问:
spring batch read jobParameters from command line and use it in job config
EDITS BASED ON SUGGESTION:
For brevity, I will remove older code and long part and re-phrase the issue.

I am trying to build the app (Spring boot + Spring Batch) taking the date and config information from command line. Based on suggestions, I can use the application properties?
The main aim is to use the same job (task of the job) to download different files form different host/time etc. So, properties file can give the information to use for download and compiled jar should read the info and do its tasks.

Main Entry point.

```<code>@SpringBootApplication
public class CoreApplication implements ApplicationRunner {

    @Autowired
    JobLauncher jobLauncher;

    @Autowired
    Job processJob;

    @Value("${rundate}")
    private String run_date;

    private static final Logger logger = LoggerFactory.getLogger(CoreApplication.class);

    public static void main(String[] args) {
        SpringApplication.run(CoreApplication.class, args);
    }

    @Override
    public void run(ApplicationArguments args) throws Exception {

        JobParameters jobParameters = new JobParametersBuilder()
                .addLong("JobID", System.currentTimeMillis())
                .addString("RunDate", run_date)
                .toJobParameters();

        try {
            jobLauncher.run(processJob, jobParameters);
        } catch (Exception e) {
            logger.error("Exception while running a batch job {}", e.getMessage());
        }

    }

}
</code>```

I rearranged the code, to use the values of server, user, etc from application.properties file. Please let me know if it is wrong way to inject the properties.

application.properties file:

```<code>spring.datasource.url=jdbc:postgresql://dbhost:1000/db
spring.datasource.username=username
spring.datasource.password=password
spring.datasource.platform=postgresql
spring.batch.job.enabled=false
local.directory="/my/local/path/"
file.name="file_name_20200601.csv"
remote.directory="/remote/ftp/location"
remote.host="remotehost"
remote.port=22
remote.user="remoteuser"
private.key.location="/key/file/location"
</code>```

My Batch Configuration:

```<code>@Configuration
@EnableBatchProcessing
@EnableIntegration
@EnableAutoConfiguration
public class BatchConfiguration {
    private Logger logger = LoggerFactory.getLogger(BatchConfiguration.class);

    @Autowired
    public JobBuilderFactory jobBuilderFactory;

    @Autowired
    public StepBuilderFactory stepBuilderFactory;

    @Bean
    public Job ftpJob() {
        return jobBuilderFactory.get("FTP Job")
                .incrementer(new RunIdIncrementer())
                .start(getFilesFromFTPServer())
                .build();
    }

    @Bean
    public Step getFilesFromFTPServer() {
        return stepBuilderFactory.get("Get file from server")
                .tasklet(new RemoteFileInboundTasklet())
                .build();

    }
}
</code>```

My Tasklet:

public class RemoteFileInboundTasklet implements Tasklet {

```<code>private Logger logger = LoggerFactory.getLogger(RemoteFileInboundTasklet.class);

@Value("${file.name}")
private String fileNamePattern;

private String clientName;
private boolean deleteLocalFiles = true;
private boolean retryIfNotFound = false;

@Value("${local.directory}")
private String local_directory_value;

private File localDirectory;
private int downloadFileAttempts = 12;
private long retryIntervalMilliseconds = 300000;

@Value("${remote.directory}")
private String remoteDirectory;

@Value("${remote.host}")
private String remoteHost;

@Value("${remote.user}")
private String remoteUser;

@Value("${remote.port}")
private int remotePort;

@Value("${private.key.location}")
private String private_key_file;

public SessionFactory<ChannelSftp.LsEntry> clientSessionFactory() {
    DefaultSftpSessionFactory ftpSessionFactory = new DefaultSftpSessionFactory();
    ftpSessionFactory.setHost(remoteHost);
    ftpSessionFactory.setPort(remotePort);
    ftpSessionFactory.setUser(remoteUser);
    ftpSessionFactory.setPrivateKey(new FileSystemResource(private_key_file));
    ftpSessionFactory.setAllowUnknownKeys(true);
    return ftpSessionFactory;
}

private SessionFactory sessionFactory = clientSessionFactory();

public SftpInboundFileSynchronizer sftpInboundFileSynchronizer() {
    SftpInboundFileSynchronizer sftpInboundFileSynchronizer = new SftpInboundFileSynchronizer(sessionFactory);
    sftpInboundFileSynchronizer.setDeleteRemoteFiles(false);
    sftpInboundFileSynchronizer.setRemoteDirectory(remoteDirectory);
    return sftpInboundFileSynchronizer;
}

private SftpInboundFileSynchronizer ftpInboundFileSynchronizer = sftpInboundFileSynchronizer();

private SftpInboundFileSynchronizingMessageSource sftpInboundFileSynchronizingMessageSource;

public boolean isDeleteLocalFiles() {
    return deleteLocalFiles;
}

public void setDeleteLocalFiles(boolean deleteLocalFiles) {
    this.deleteLocalFiles = deleteLocalFiles;
}

public SftpInboundFileSynchronizer getFtpInboundFileSynchronizer() {
    return ftpInboundFileSynchronizer;
}

public void setFtpInboundFileSynchronizer(SftpInboundFileSynchronizer ftpInboundFileSynchronizer) {
    this.ftpInboundFileSynchronizer = ftpInboundFileSynchronizer;
}

public SessionFactory getSessionFactory() {
    return sessionFactory;
}

public void setSessionFactory(SessionFactory sessionFactory) {
    this.sessionFactory = sessionFactory;
}

public SftpInboundFileSynchronizingMessageSource getSftpInboundFileSynchronizingMessageSource() {
    return sftpInboundFileSynchronizingMessageSource;
}

public void setSftpInboundFileSynchronizingMessageSource(SftpInboundFileSynchronizingMessageSource sftpInboundFileSynchronizingMessageSource) {
    this.sftpInboundFileSynchronizingMessageSource = sftpInboundFileSynchronizingMessageSource;
}

public String getRemoteDirectory() {
    return remoteDirectory;
}

public void setRemoteDirectory(String remoteDirectory) {
    this.remoteDirectory = remoteDirectory;
}

private SFTPGateway sftpGateway;

@ServiceActivator(inputChannel = "sftpChannel")
public MessageHandler clientMessageHandler() {
    SftpOutboundGateway sftpOutboundGateway = new SftpOutboundGateway(clientSessionFactory(), "mget", "payload");
    sftpOutboundGateway.setAutoCreateLocalDirectory(true);
    sftpOutboundGateway.setLocalDirectory(new File(local_directory_value));
    sftpOutboundGateway.setFileExistsMode(FileExistsMode.REPLACE_IF_MODIFIED);
    sftpOutboundGateway.setFilter(new AcceptOnceFileListFilter<>());
    return sftpOutboundGateway;
}

private void deleteLocalFiles()
{
    if (deleteLocalFiles)
    {
        localDirectory = new File(local_directory_value);
        SimplePatternFileListFilter filter = new SimplePatternFileListFilter(fileNamePattern);
        List<File> matchingFiles = filter.filterFiles(localDirectory.listFiles());
        if (CollectionUtils.isNotEmpty(matchingFiles))
        {
            for (File file : matchingFiles)
            {
                FileUtils.deleteQuietly(file);
            }
        }
    }
}

@Override
public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception {

    deleteLocalFiles();
    ftpInboundFileSynchronizer.synchronizeToLocalDirectory(localDirectory);
    if (retryIfNotFound) {

        SimplePatternFileListFilter filter = new SimplePatternFileListFilter(fileNamePattern);
        int attemptCount = 1;
        while (filter.filterFiles(localDirectory.listFiles()).size() == 0 && attemptCount <= downloadFileAttempts) {

            logger.info("File(s) matching " + fileNamePattern + " not found on remote site. Attempt " + attemptCount + " out of " + downloadFileAttempts);
            Thread.sleep(retryIntervalMilliseconds);
            ftpInboundFileSynchronizer.synchronizeToLocalDirectory(localDirectory);
            attemptCount++;
        }

        if (attemptCount >= downloadFileAttempts && filter.filterFiles(localDirectory.listFiles()).size() == 0) {
            throw new FileNotFoundException("Could not find remote file(s) matching " + fileNamePattern + " after " + downloadFileAttempts + " attempts.");
        }
    }
    return RepeatStatus.FINISHED;
}

public String getFileNamePattern() {
    return fileNamePattern;
}

public void setFileNamePattern(String fileNamePattern) {
    this.fileNamePattern = fileNamePattern;
}

public String getClientName() {
    return clientName;
}

public void setClientName(String clientName) {
    this.clientName = clientName;
}

public boolean isRetryIfNotFound() {
    return retryIfNotFound;
}

public void setRetryIfNotFound(boolean retryIfNotFound) {
    this.retryIfNotFound = retryIfNotFound;
}

public File getLocalDirectory() {
    return localDirectory;
}

public void setLocalDirectory(File localDirectory) {
    this.localDirectory = localDirectory;
}

public int getDownloadFileAttempts() {
    return downloadFileAttempts;
}

public void setDownloadFileAttempts(int downloadFileAttempts) {
    this.downloadFileAttempts = downloadFileAttempts;
}

public long getRetryIntervalMilliseconds() {
    return retryIntervalMilliseconds;
}

public void setRetryIntervalMilliseconds(long retryIntervalMilliseconds) {
    this.retryIntervalMilliseconds = retryIntervalMilliseconds;
}
</code>```

}

My understanding (please correct here if wrong) that the application.properties file properties can be injected in the tasklet (as above).
Then I try to build the package.

```<code>mvn clean package
</code>```

I get the following error:

```<code>Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.batch.core.Step]: Factory method 'getFilesFromFTPServer' threw exception; nested exception is java.lang.IllegalArgumentException: Path must not be null
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:185) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
    at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
    ... 122 common frames omitted
Caused by: java.lang.IllegalArgumentException: Path must not be null
    at org.springframework.util.Assert.notNull(Assert.java:198) ~[spring-core-5.2.6.RELEASE.jar:5.2.6.RELEASE]
    at org.springframework.core.io.FileSystemResource.<init>(FileSystemResource.java:80) ~[spring-core-5.2.6.RELEASE.jar:5.2.6.RELEASE]
    at com.my.batch.core.tasklet.RemoteFileInboundTasklet.clientSessionFactory(RemoteFileInboundTasklet.java:78) ~[classes/:na]
    at com.my.batch.core.tasklet.RemoteFileInboundTasklet.<init>(RemoteFileInboundTasklet.java:83) ~[classes/:na]
    at com.my.batch.core.BatchConfiguration.getFilesFromFTPServer(BatchConfiguration.java:71) ~[classes/:na]
    at com.my.batch.core.BatchConfiguration$$EnhancerBySpringCGLIB$$17d8a6d9.CGLIB$getFilesFromFTPServer$1(<generated>) ~[classes/:na]
</code>```

The line in the code is:

```<code>ftpSessionFactory.setPrivateKey(new FileSystemResource(private_key_file));
</code>```

called via BatchConfiguration.java -> getFilesFromFTPServer.

This means my values from applcation.properties is not passed?
What changes I need to do?

And, while compiling or building the jar, why is it checking the value of variable?

NEW EDITS:

I tried to declare my tasklet as a bean in Configuration and build the package again. However, it is giving the same error.

My application.properties file after change:

```<code>spring.datasource.url=jdbc:postgresql://dbhost:1000/db
spring.datasource.username=username
spring.datasource.password=password
spring.datasource.platform=postgresql
spring.batch.job.enabled=false
local.directory=/my/local/path/
file.name=file_name_20200601.csv
remote.directory=/remote/ftp/location
remote.host=remotehost
remote.port=22
remote.user=remoteuser
private.key.location=/key/file/location
</code>```

No change in tasklet.

Changed Configuration:

```<code>@Configuration
@EnableBatchProcessing
@EnableIntegration
@EnableAutoConfiguration
public class BatchConfiguration {
    private Logger logger = LoggerFactory.getLogger(BatchConfiguration.class);

    @Autowired
    public JobBuilderFactory jobBuilderFactory;

    @Autowired
    public StepBuilderFactory stepBuilderFactory;

    @Bean
    public RemoteFileInboundTasklet remoteFileInboundTasklet() {
        return new RemoteFileInboundTasklet();
    }

    @Bean
    public Job ftpJob() {
        return jobBuilderFactory.get("FTP Job")
                .incrementer(new RunIdIncrementer())
                .start(getFilesFromFTPServer())
                .build();
    }

    @Bean
    public Step getFilesFromFTPServer() {
        return stepBuilderFactory.get("Get file from server")
                .tasklet(remoteFileInboundTasklet())
                .build();

    }
}
</code>```

When I tried to build the package(mvn clean package), I still get the same error.

Path must not be null.

It is not able to read the properties. Any idea what is wrong?

EDITS BASED ON DIFFERENT APPROACH:

I tried to further see how to use configuration and found the following approach to use the @ConfigurationProperties annotation (How to access a value defined in the application.properties file in Spring Boot)

I created a new ftp config class:

```<code>import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;

@ConfigurationProperties(prefix = "ftp")
@Configuration("coreFtpProperties")
public class CoreFtp {
    private String host;
    private String port;
    private String user;
    private String passwordKey;
    private String localDirectory;
    private String remoteDirectory;
    private String fileName;

    public String getHost() {
        return host;
    }

    public void setHost(String host) {
        this.host = host;
    }

    public String getPort() {
        return port;
    }

    public void setPort(String port) {
        this.port = port;
    }

    public String getUser() {
        return user;
    }

    public void setUser(String user) {
        this.user = user;
    }

    public String getPasswordKey() {
        return passwordKey;
    }

    public void setPasswordKey(String passwordKey) {
        this.passwordKey = passwordKey;
    }

    public String getLocalDirectory() {
        return localDirectory;
    }

    public void setLocalDirectory(String localDirectory) {
        this.localDirectory = localDirectory;
    }

    public String getRemoteDirectory() {
        return remoteDirectory;
    }

    public void setRemoteDirectory(String remoteDirectory) {
        this.remoteDirectory = remoteDirectory;
    }

    public String getFileName() {
        return fileName;
    }

    public void setFileName(String fileName) {
        this.fileName = fileName;
    }
}
</code>```

Minor change to application.properties file:

```<code>spring.datasource.url=jdbc:postgresql://dbhost:1000/db
spring.datasource.username=username
spring.datasource.password=password
spring.datasource.platform=postgresql
spring.batch.job.enabled=false
local.directory="/my/local/path/"
file.name="file_name_20200601.csv"
remote.directory="/remote/ftp/location"
remote.host="remotehost"
remote.port=22
remote.user="remoteuser"
private.key.location="/key/file/location"
</code>```0

In my batch configuration I made this changes:

```<code>spring.datasource.url=jdbc:postgresql://dbhost:1000/db
spring.datasource.username=username
spring.datasource.password=password
spring.datasource.platform=postgresql
spring.batch.job.enabled=false
local.directory="/my/local/path/"
file.name="file_name_20200601.csv"
remote.directory="/remote/ftp/location"
remote.host="remotehost"
remote.port=22
remote.user="remoteuser"
private.key.location="/key/file/location"
</code>```1

So, accordingly my Tasklet is changed as:

```<code>spring.datasource.url=jdbc:postgresql://dbhost:1000/db
spring.datasource.username=username
spring.datasource.password=password
spring.datasource.platform=postgresql
spring.batch.job.enabled=false
local.directory="/my/local/path/"
file.name="file_name_20200601.csv"
remote.directory="/remote/ftp/location"
remote.host="remotehost"
remote.port=22
remote.user="remoteuser"
private.key.location="/key/file/location"
</code>```2

Based on above changes, I am able to compile the code and create the necessary Jar, and run the code using the jar.

答:
You are declaring a bean jobExecutionListener() in which you create new FileSystemResource(config_file_path);. The config_file_path is injected from job parameters @Value("#{jobParameters['ConfigFilePath']}") which are not available at configuration time but only when a job/step is run. This is called late binding.

So in your case, when Spring tries to create the bean jobExecutionListener(), it tries to inject config_file_path but it is null at that time (at this point Spring is only creating beans to configure the application context) and the job is not run yet hence the method beforeJob is not executed yet. This is the reason you have a NullPointerException. Adding @JobScope on the jobExecutionListener() bean should fix the issue but I do not recommend that. The reason is that you are trying to configure some properties in the wrong way and in the wrong place, so I would fix that design instead of working around the issue by adding an annotation.

Job parameters are used for business parameters and not technical details. In your case, runDate is a good choice for a job parameter but not ConfigFilePath. Moreover, since you use Spring, why do you inject the file path then do properties = PropertiesLoaderUtils.loadProperties(resource); and Integer.parseInt(properties.getProperty("remote.port"));? Spring will do that for you if tell it to inject properties where needed.

I would remove this config_file_path job parameter as well as the job listener and inject the properties in the remoteFileInboundTasklet directly, that is, as close as possible to where these properties are needed.

Edit: Add code example

Can you help to understand where can I declare the tasklet as a bean?

In your step getFilesFromFTPServer , you are creating the tasklet manually, so dependency injection is not performed. You need to declare the tasklet as a Spring bean for this to work, something like:

```<code>@Bean
public Tasklet myTasklet() {
   return new RemoteFileInboundTasklet()
}

@Bean
public Step getFilesFromFTPServer() {
    return stepBuilderFactory.get("Get file from server")
            .tasklet(myTasklet())
            .build();

}
</code>```

Body:
EDITS BASED ON SUGGESTION:
For brevity, I will remove older code and long part and re-phrase the issue.

I am trying to build the app (Spring boot + Spring Batch) taking the date and config information from command line. Based on suggestions, I can use the application properties?
The main aim is to use the same job (task of the job) to download different files form different host/time etc. So, properties file can give the information to use for download and compiled jar should read the info and do its tasks.

Main Entry point.

@SpringBootApplication
public class CoreApplication implements ApplicationRunner {

    @Autowired
    JobLauncher jobLauncher;

    @Autowired
    Job processJob;

    @Value("${rundate}")
    private String run_date;

    private static final Logger logger = LoggerFactory.getLogger(CoreApplication.class);

    public static void main(String[] args) {
        SpringApplication.run(CoreApplication.class, args);
    }

    @Override
    public void run(ApplicationArguments args) throws Exception {

        JobParameters jobParameters = new JobParametersBuilder()
                .addLong("JobID", System.currentTimeMillis())
                .addString("RunDate", run_date)
                .toJobParameters();

        try {
            jobLauncher.run(processJob, jobParameters);
        } catch (Exception e) {
            logger.error("Exception while running a batch job {}", e.getMessage());
        }

    }

}

I rearranged the code, to use the values of server, user, etc from application.properties file. Please let me know if it is wrong way to inject the properties.

application.properties file:

spring.datasource.url=jdbc:postgresql://dbhost:1000/db
spring.datasource.username=username
spring.datasource.password=password
spring.datasource.platform=postgresql
spring.batch.job.enabled=false
local.directory="/my/local/path/"
file.name="file_name_20200601.csv"
remote.directory="/remote/ftp/location"
remote.host="remotehost"
remote.port=22
remote.user="remoteuser"
private.key.location="/key/file/location"

My Batch Configuration:

@Configuration
@EnableBatchProcessing
@EnableIntegration
@EnableAutoConfiguration
public class BatchConfiguration {
    private Logger logger = LoggerFactory.getLogger(BatchConfiguration.class);

    @Autowired
    public JobBuilderFactory jobBuilderFactory;

    @Autowired
    public StepBuilderFactory stepBuilderFactory;

    @Bean
    public Job ftpJob() {
        return jobBuilderFactory.get("FTP Job")
                .incrementer(new RunIdIncrementer())
                .start(getFilesFromFTPServer())
                .build();
    }

    @Bean
    public Step getFilesFromFTPServer() {
        return stepBuilderFactory.get("Get file from server")
                .tasklet(new RemoteFileInboundTasklet())
                .build();

    }
}

My Tasklet:

public class RemoteFileInboundTasklet implements Tasklet {

private Logger logger = LoggerFactory.getLogger(RemoteFileInboundTasklet.class);

@Value("${file.name}")
private String fileNamePattern;

private String clientName;
private boolean deleteLocalFiles = true;
private boolean retryIfNotFound = false;

@Value("${local.directory}")
private String local_directory_value;

private File localDirectory;
private int downloadFileAttempts = 12;
private long retryIntervalMilliseconds = 300000;

@Value("${remote.directory}")
private String remoteDirectory;

@Value("${remote.host}")
private String remoteHost;

@Value("${remote.user}")
private String remoteUser;

@Value("${remote.port}")
private int remotePort;

@Value("${private.key.location}")
private String private_key_file;

public SessionFactory<ChannelSftp.LsEntry> clientSessionFactory() {
    DefaultSftpSessionFactory ftpSessionFactory = new DefaultSftpSessionFactory();
    ftpSessionFactory.setHost(remoteHost);
    ftpSessionFactory.setPort(remotePort);
    ftpSessionFactory.setUser(remoteUser);
    ftpSessionFactory.setPrivateKey(new FileSystemResource(private_key_file));
    ftpSessionFactory.setAllowUnknownKeys(true);
    return ftpSessionFactory;
}

private SessionFactory sessionFactory = clientSessionFactory();

public SftpInboundFileSynchronizer sftpInboundFileSynchronizer() {
    SftpInboundFileSynchronizer sftpInboundFileSynchronizer = new SftpInboundFileSynchronizer(sessionFactory);
    sftpInboundFileSynchronizer.setDeleteRemoteFiles(false);
    sftpInboundFileSynchronizer.setRemoteDirectory(remoteDirectory);
    return sftpInboundFileSynchronizer;
}

private SftpInboundFileSynchronizer ftpInboundFileSynchronizer = sftpInboundFileSynchronizer();

private SftpInboundFileSynchronizingMessageSource sftpInboundFileSynchronizingMessageSource;

public boolean isDeleteLocalFiles() {
    return deleteLocalFiles;
}

public void setDeleteLocalFiles(boolean deleteLocalFiles) {
    this.deleteLocalFiles = deleteLocalFiles;
}

public SftpInboundFileSynchronizer getFtpInboundFileSynchronizer() {
    return ftpInboundFileSynchronizer;
}

public void setFtpInboundFileSynchronizer(SftpInboundFileSynchronizer ftpInboundFileSynchronizer) {
    this.ftpInboundFileSynchronizer = ftpInboundFileSynchronizer;
}

public SessionFactory getSessionFactory() {
    return sessionFactory;
}

public void setSessionFactory(SessionFactory sessionFactory) {
    this.sessionFactory = sessionFactory;
}

public SftpInboundFileSynchronizingMessageSource getSftpInboundFileSynchronizingMessageSource() {
    return sftpInboundFileSynchronizingMessageSource;
}

public void setSftpInboundFileSynchronizingMessageSource(SftpInboundFileSynchronizingMessageSource sftpInboundFileSynchronizingMessageSource) {
    this.sftpInboundFileSynchronizingMessageSource = sftpInboundFileSynchronizingMessageSource;
}

public String getRemoteDirectory() {
    return remoteDirectory;
}

public void setRemoteDirectory(String remoteDirectory) {
    this.remoteDirectory = remoteDirectory;
}

private SFTPGateway sftpGateway;

@ServiceActivator(inputChannel = "sftpChannel")
public MessageHandler clientMessageHandler() {
    SftpOutboundGateway sftpOutboundGateway = new SftpOutboundGateway(clientSessionFactory(), "mget", "payload");
    sftpOutboundGateway.setAutoCreateLocalDirectory(true);
    sftpOutboundGateway.setLocalDirectory(new File(local_directory_value));
    sftpOutboundGateway.setFileExistsMode(FileExistsMode.REPLACE_IF_MODIFIED);
    sftpOutboundGateway.setFilter(new AcceptOnceFileListFilter<>());
    return sftpOutboundGateway;
}

private void deleteLocalFiles()
{
    if (deleteLocalFiles)
    {
        localDirectory = new File(local_directory_value);
        SimplePatternFileListFilter filter = new SimplePatternFileListFilter(fileNamePattern);
        List<File> matchingFiles = filter.filterFiles(localDirectory.listFiles());
        if (CollectionUtils.isNotEmpty(matchingFiles))
        {
            for (File file : matchingFiles)
            {
                FileUtils.deleteQuietly(file);
            }
        }
    }
}

@Override
public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception {

    deleteLocalFiles();
    ftpInboundFileSynchronizer.synchronizeToLocalDirectory(localDirectory);
    if (retryIfNotFound) {

        SimplePatternFileListFilter filter = new SimplePatternFileListFilter(fileNamePattern);
        int attemptCount = 1;
        while (filter.filterFiles(localDirectory.listFiles()).size() == 0 && attemptCount <= downloadFileAttempts) {

            logger.info("File(s) matching " + fileNamePattern + " not found on remote site. Attempt " + attemptCount + " out of " + downloadFileAttempts);
            Thread.sleep(retryIntervalMilliseconds);
            ftpInboundFileSynchronizer.synchronizeToLocalDirectory(localDirectory);
            attemptCount++;
        }

        if (attemptCount >= downloadFileAttempts && filter.filterFiles(localDirectory.listFiles()).size() == 0) {
            throw new FileNotFoundException("Could not find remote file(s) matching " + fileNamePattern + " after " + downloadFileAttempts + " attempts.");
        }
    }
    return RepeatStatus.FINISHED;
}

public String getFileNamePattern() {
    return fileNamePattern;
}

public void setFileNamePattern(String fileNamePattern) {
    this.fileNamePattern = fileNamePattern;
}

public String getClientName() {
    return clientName;
}

public void setClientName(String clientName) {
    this.clientName = clientName;
}

public boolean isRetryIfNotFound() {
    return retryIfNotFound;
}

public void setRetryIfNotFound(boolean retryIfNotFound) {
    this.retryIfNotFound = retryIfNotFound;
}

public File getLocalDirectory() {
    return localDirectory;
}

public void setLocalDirectory(File localDirectory) {
    this.localDirectory = localDirectory;
}

public int getDownloadFileAttempts() {
    return downloadFileAttempts;
}

public void setDownloadFileAttempts(int downloadFileAttempts) {
    this.downloadFileAttempts = downloadFileAttempts;
}

public long getRetryIntervalMilliseconds() {
    return retryIntervalMilliseconds;
}

public void setRetryIntervalMilliseconds(long retryIntervalMilliseconds) {
    this.retryIntervalMilliseconds = retryIntervalMilliseconds;
}

}

My understanding (please correct here if wrong) that the application.properties file properties can be injected in the tasklet (as above).
Then I try to build the package.

mvn clean package

I get the following error:

Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.batch.core.Step]: Factory method 'getFilesFromFTPServer' threw exception; nested exception is java.lang.IllegalArgumentException: Path must not be null
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:185) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
    at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
    ... 122 common frames omitted
Caused by: java.lang.IllegalArgumentException: Path must not be null
    at org.springframework.util.Assert.notNull(Assert.java:198) ~[spring-core-5.2.6.RELEASE.jar:5.2.6.RELEASE]
    at org.springframework.core.io.FileSystemResource.<init>(FileSystemResource.java:80) ~[spring-core-5.2.6.RELEASE.jar:5.2.6.RELEASE]
    at com.my.batch.core.tasklet.RemoteFileInboundTasklet.clientSessionFactory(RemoteFileInboundTasklet.java:78) ~[classes/:na]
    at com.my.batch.core.tasklet.RemoteFileInboundTasklet.<init>(RemoteFileInboundTasklet.java:83) ~[classes/:na]
    at com.my.batch.core.BatchConfiguration.getFilesFromFTPServer(BatchConfiguration.java:71) ~[classes/:na]
    at com.my.batch.core.BatchConfiguration$$EnhancerBySpringCGLIB$$17d8a6d9.CGLIB$getFilesFromFTPServer$1(<generated>) ~[classes/:na]

The line in the code is:

ftpSessionFactory.setPrivateKey(new FileSystemResource(private_key_file));

called via BatchConfiguration.java -> getFilesFromFTPServer.

This means my values from applcation.properties is not passed?
What changes I need to do?

And, while compiling or building the jar, why is it checking the value of variable?

NEW EDITS:

I tried to declare my tasklet as a bean in Configuration and build the package again. However, it is giving the same error.

My application.properties file after change:

spring.datasource.url=jdbc:postgresql://dbhost:1000/db
spring.datasource.username=username
spring.datasource.password=password
spring.datasource.platform=postgresql
spring.batch.job.enabled=false
local.directory=/my/local/path/
file.name=file_name_20200601.csv
remote.directory=/remote/ftp/location
remote.host=remotehost
remote.port=22
remote.user=remoteuser
private.key.location=/key/file/location

No change in tasklet.

Changed Configuration:

@Configuration
@EnableBatchProcessing
@EnableIntegration
@EnableAutoConfiguration
public class BatchConfiguration {
    private Logger logger = LoggerFactory.getLogger(BatchConfiguration.class);

    @Autowired
    public JobBuilderFactory jobBuilderFactory;

    @Autowired
    public StepBuilderFactory stepBuilderFactory;

    @Bean
    public RemoteFileInboundTasklet remoteFileInboundTasklet() {
        return new RemoteFileInboundTasklet();
    }

    @Bean
    public Job ftpJob() {
        return jobBuilderFactory.get("FTP Job")
                .incrementer(new RunIdIncrementer())
                .start(getFilesFromFTPServer())
                .build();
    }

    @Bean
    public Step getFilesFromFTPServer() {
        return stepBuilderFactory.get("Get file from server")
                .tasklet(remoteFileInboundTasklet())
                .build();

    }
}

When I tried to build the package(mvn clean package), I still get the same error.

Path must not be null.

It is not able to read the properties. Any idea what is wrong?

EDITS BASED ON DIFFERENT APPROACH:

I tried to further see how to use configuration and found the following approach to use the @ConfigurationProperties annotation (How to access a value defined in the application.properties file in Spring Boot)

I created a new ftp config class:

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;

@ConfigurationProperties(prefix = "ftp")
@Configuration("coreFtpProperties")
public class CoreFtp {
    private String host;
    private String port;
    private String user;
    private String passwordKey;
    private String localDirectory;
    private String remoteDirectory;
    private String fileName;

    public String getHost() {
        return host;
    }

    public void setHost(String host) {
        this.host = host;
    }

    public String getPort() {
        return port;
    }

    public void setPort(String port) {
        this.port = port;
    }

    public String getUser() {
        return user;
    }

    public void setUser(String user) {
        this.user = user;
    }

    public String getPasswordKey() {
        return passwordKey;
    }

    public void setPasswordKey(String passwordKey) {
        this.passwordKey = passwordKey;
    }

    public String getLocalDirectory() {
        return localDirectory;
    }

    public void setLocalDirectory(String localDirectory) {
        this.localDirectory = localDirectory;
    }

    public String getRemoteDirectory() {
        return remoteDirectory;
    }

    public void setRemoteDirectory(String remoteDirectory) {
        this.remoteDirectory = remoteDirectory;
    }

    public String getFileName() {
        return fileName;
    }

    public void setFileName(String fileName) {
        this.fileName = fileName;
    }
}

Minor change to application.properties file:

spring.datasource.url=jdbc:postgresql://dbhost:1000/db
spring.datasource.username=username
spring.datasource.password=password
spring.datasource.platform=postgresql
spring.batch.job.enabled=false
ftp.local_directory=/my/local/path/
ftp.file_name=file_name_20200601.csv
ftp.remote_directory=/remote/ftp/location
ftp.host=remotehost
ftp.port=22
ftp.user=remoteuser
ftp.password_key=/key/file/location

In my batch configuration I made this changes:

@Configuration
@EnableBatchProcessing
@EnableIntegration
public class BatchConfiguration {
    private Logger logger = LoggerFactory.getLogger(BatchConfiguration.class);

    @Autowired
    public JobBuilderFactory jobBuilderFactory;

    @Autowired
    public StepBuilderFactory stepBuilderFactory;

    @Autowired
    private CoreFtp coreFtpProperties;

    @Bean
    public RemoteFileInboundTasklet remoteFileInboundTasklet() {
        RemoteFileInboundTasklet ftpTasklet = new RemoteFileInboundTasklet();
        ftpTasklet.setRetryIfNotFound(true);
        ftpTasklet.setDownloadFileAttempts(3);
        ftpTasklet.setRetryIntervalMilliseconds(10000);
        ftpTasklet.setFileNamePattern(coreFtpProperties.getFileName());
        ftpTasklet.setRemoteDirectory(coreFtpProperties.getRemoteDirectory());
        ftpTasklet.setLocalDirectory(new File(coreFtpProperties.getLocalDirectory()));
        ftpTasklet.setSessionFactory(clientSessionFactory());
        ftpTasklet.setFtpInboundFileSynchronizer(sftpInboundFileSynchronizer());
        ftpTasklet.setSftpInboundFileSynchronizingMessageSource(new SftpInboundFileSynchronizingMessageSource(sftpInboundFileSynchronizer()));

        return ftpTasklet;
    }

    @Bean
    public SftpInboundFileSynchronizer sftpInboundFileSynchronizer() {
        SftpInboundFileSynchronizer sftpInboundFileSynchronizer = new SftpInboundFileSynchronizer(clientSessionFactory());
        sftpInboundFileSynchronizer.setDeleteRemoteFiles(false);
        sftpInboundFileSynchronizer.setRemoteDirectory(coreFtpProperties.getRemoteDirectory());
        return sftpInboundFileSynchronizer;
    }

    @Bean(name = "clientSessionFactory")
    public SessionFactory<LsEntry> clientSessionFactory() {
        DefaultSftpSessionFactory ftpSessionFactory = new DefaultSftpSessionFactory();
        ftpSessionFactory.setHost(coreFtpProperties.getHost());
        ftpSessionFactory.setPort(Integer.parseInt(coreFtpProperties.getPort()));
        ftpSessionFactory.setUser(coreFtpProperties.getUser());
        ftpSessionFactory.setPrivateKey(new FileSystemResource(coreFtpProperties.getPasswordKey()));
        ftpSessionFactory.setPassword("");
        ftpSessionFactory.setAllowUnknownKeys(true);
        return ftpSessionFactory;
    }

    @Bean
    @ServiceActivator(inputChannel = "sftpChannel")
    public MessageHandler clientMessageHandler() {
        SftpOutboundGateway sftpOutboundGateway = new SftpOutboundGateway(clientSessionFactory(), "mget", "payload");
        sftpOutboundGateway.setAutoCreateLocalDirectory(true);
        sftpOutboundGateway.setLocalDirectory(new File(coreFtpProperties.getLocalDirectory()));
        sftpOutboundGateway.setFileExistsMode(FileExistsMode.REPLACE_IF_MODIFIED);
        sftpOutboundGateway.setFilter(new AcceptOnceFileListFilter<>());
        return sftpOutboundGateway;
    }

    @Bean
    public Job ftpJob() {
        return jobBuilderFactory.get("FTP Job")
                .incrementer(new RunIdIncrementer())
                .start(getFilesFromFTPServer())
                .build();
    }

    @Bean
    public Step getFilesFromFTPServer() {
        return stepBuilderFactory.get("Get file from server")
                .tasklet(remoteFileInboundTasklet())
                .build();

    }

}

So, accordingly my Tasklet is changed as:

public class RemoteFileInboundTasklet implements Tasklet {

    private Logger logger = LoggerFactory.getLogger(RemoteFileInboundTasklet.class);

    private String fileNamePattern;

    private String clientName;
    private boolean deleteLocalFiles = true;
    private boolean retryIfNotFound = false;

    private File localDirectory;

    private int downloadFileAttempts = 12;
    private long retryIntervalMilliseconds = 300000;

    private String remoteDirectory;

    private SessionFactory sessionFactory;
    private SftpInboundFileSynchronizer ftpInboundFileSynchronizer;

    private SftpInboundFileSynchronizingMessageSource sftpInboundFileSynchronizingMessageSource;

    public boolean isDeleteLocalFiles() {
        return deleteLocalFiles;
    }

    public void setDeleteLocalFiles(boolean deleteLocalFiles) {
        this.deleteLocalFiles = deleteLocalFiles;
    }

    public SftpInboundFileSynchronizer getFtpInboundFileSynchronizer() {
        return ftpInboundFileSynchronizer;
    }

    public void setFtpInboundFileSynchronizer(SftpInboundFileSynchronizer ftpInboundFileSynchronizer) {
        this.ftpInboundFileSynchronizer = ftpInboundFileSynchronizer;
    }

    public SessionFactory getSessionFactory() {
        return sessionFactory;
    }

    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    public SftpInboundFileSynchronizingMessageSource getSftpInboundFileSynchronizingMessageSource() {
        return sftpInboundFileSynchronizingMessageSource;
    }

    public void setSftpInboundFileSynchronizingMessageSource(SftpInboundFileSynchronizingMessageSource sftpInboundFileSynchronizingMessageSource) {
        this.sftpInboundFileSynchronizingMessageSource = sftpInboundFileSynchronizingMessageSource;
    }

    public String getRemoteDirectory() {
        return remoteDirectory;
    }

    public void setRemoteDirectory(String remoteDirectory) {
        this.remoteDirectory = remoteDirectory;
    }

    private SFTPGateway sftpGateway;

    private void deleteLocalFiles()
    {
        if (deleteLocalFiles)
        {
            SimplePatternFileListFilter filter = new SimplePatternFileListFilter(fileNamePattern);
            List<File> matchingFiles = filter.filterFiles(localDirectory.listFiles());
            if (CollectionUtils.isNotEmpty(matchingFiles))
            {
                for (File file : matchingFiles)
                {
                    FileUtils.deleteQuietly(file);
                }
            }
        }
    }

    @Override
    public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception {

        deleteLocalFiles();

        ftpInboundFileSynchronizer.synchronizeToLocalDirectory(localDirectory);

        if (retryIfNotFound) {

            SimplePatternFileListFilter filter = new SimplePatternFileListFilter(fileNamePattern);
            int attemptCount = 1;
            while (filter.filterFiles(localDirectory.listFiles()).size() == 0 && attemptCount <= downloadFileAttempts) {

                logger.info("File(s) matching " + fileNamePattern + " not found on remote site. Attempt " + attemptCount + " out of " + downloadFileAttempts);
                Thread.sleep(retryIntervalMilliseconds);
                ftpInboundFileSynchronizer.synchronizeToLocalDirectory(localDirectory);
                attemptCount++;
            }

            if (attemptCount >= downloadFileAttempts && filter.filterFiles(localDirectory.listFiles()).size() == 0) {
                throw new FileNotFoundException("Could not find remote file(s) matching " + fileNamePattern + " after " + downloadFileAttempts + " attempts.");
            }
        }
        return RepeatStatus.FINISHED;
    }
}

Based on above changes, I am able to compile the code and create the necessary Jar, and run the code using the jar.

Body:
You are declaring a bean jobExecutionListener() in which you create new FileSystemResource(config_file_path);. The config_file_path is injected from job parameters @Value("#{jobParameters['ConfigFilePath']}") which are not available at configuration time but only when a job/step is run. This is called late binding.

So in your case, when Spring tries to create the bean jobExecutionListener(), it tries to inject config_file_path but it is null at that time (at this point Spring is only creating beans to configure the application context) and the job is not run yet hence the method beforeJob is not executed yet. This is the reason you have a NullPointerException. Adding @JobScope on the jobExecutionListener() bean should fix the issue but I do not recommend that. The reason is that you are trying to configure some properties in the wrong way and in the wrong place, so I would fix that design instead of working around the issue by adding an annotation.

Job parameters are used for business parameters and not technical details. In your case, runDate is a good choice for a job parameter but not ConfigFilePath. Moreover, since you use Spring, why do you inject the file path then do properties = PropertiesLoaderUtils.loadProperties(resource); and Integer.parseInt(properties.getProperty("remote.port"));? Spring will do that for you if tell it to inject properties where needed.

I would remove this config_file_path job parameter as well as the job listener and inject the properties in the remoteFileInboundTasklet directly, that is, as close as possible to where these properties are needed.

Edit: Add code example

Can you help to understand where can I declare the tasklet as a bean?

In your step getFilesFromFTPServer , you are creating the tasklet manually, so dependency injection is not performed. You need to declare the tasklet as a Spring bean for this to work, something like:

@Bean
public Tasklet myTasklet() {
   return new RemoteFileInboundTasklet()
}

@Bean
public Step getFilesFromFTPServer() {
    return stepBuilderFactory.get("Get file from server")
            .tasklet(myTasklet())
            .build();

}


来源: stackexchange

问:
Enable the button when the user has reached end of the page by scrolling
I am trying to create a terms and conditions page where I have 'I Agree' button which should be disabled when the user is at the top/middle of the page. When the user reaches the end of the page the button should be enabled. For that I want to have Hostlistner/Directive/event binding which will listen to scroll and get the position of the scroll and inform when it reaches at bottom and enable I agree button. Is there any other way of doing it? I am new to angular. Thanks in advance

my html

```<code><div class="modal-body" #agreement>
           <h6 class="inittext">You must scroll to the end of the terms and conditions And press "Agree"
            to continue with your request.</h6>
            <p style="font-weight:bold">Lorem ipsum dolor sit amet<br></p>
            <p> consectetur adipiscing elit, sed do eiusmod tempor incididunt
              ut labore et dolore magna aliqua. Ac ut consequat semper viverra nam libero justo laoreet.
              Amet massa vitae tortor condimentum. Aliquam sem et tortor consequat id porta nibh venenatis
               cras. Sed id semper risus in hendrerit gravida rutrum quisque.<br></p>
               <p style="font-weight:bold"> Fermentum posuere urna <br></p>
                <p>nec tincidunt praesent semper feugiat. Ullamcorper malesuada proin libero nunc consequat
               interdum varius. Habitasse platea dictumst quisque sagittis purus sit amet. Dictum non
               consectetur a erat nam. Duis tristique sollicitudin nibh sit amet commodo.
               Tincidunt tortor aliquam nulla facilisi cras fermentum. Massa sapien faucibus
               et molestie ac.</p>
               <p style="font-weight:bold">Mi bibendum <br></p>
               <p> neque egestas congue quisque egestas diam in. Aliquet porttitor lacus luctus
                 accumsan tortor posuere ac ut. Odio tempor orci dapibus ultrices in iaculis nunc. Sit amet
                  venenatis urna cursus eget.<br></p>
                  <p>Eget magna fermentum iaculis eu non diam. Enim praesent
                  elementum facilisis leo vel. Quam nulla porttitor massa id neque aliquam vestibulum. Arcu
                  cursus vitae congue mauris. Tempus quam pellentesque nec nam aliquam sem et tortor. Rhoncus
                  est pellentesque elit ullamcorper dignissim cras tincidunt lobortis.<br></p> <p> Tristique senectus et
                   netus et malesuada. Fermentum et sollicitudin ac orci phasellus egestas tellus rutrum.
                   Sed risus ultricies tristique nulla aliquet enim tortor. Nunc non blandit massa enim nec
                   dui nunc. Purus gravida quis blandit turpis cursus in hac habitasse platea.</p>
                   <h6 class="inittext">You must press "Agree" to continue with your request.</h6>
         </div>
        <div class="modal-footer">
          <button type="button" class="btn btn-outline-primary" style="float: left">Save as PDF</button>
          <button type="button" class="btn btn-outline-primary">Disagree</button>
          <button type="button" class="btn btn-primary" disabled>Agree</button>
        </div>
</code>```

My ts file

```<code>import { Component,ElementRef, ViewChild, HostListener, AfterViewInit } from '@angular/core';

@Component({
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent implements AfterViewInit {
  @ViewChild('agreement') agreement : ElementRef;
</code>```

}

答:
You can use the scrollTop and height information in connection with the current position.

```<code>document.documentElement.scrollTop + document.documentElement.offsetHeight
document.documentElement.scrollHeight
</code>```

For more details, have a closer look at this answer:

https://stackoverflow.com/a/42547136/9293934

ContentLicense: CC BY-SA 4.0

Body:
I am trying to create a terms and conditions page where I have 'I Agree' button which should be disabled when the user is at the top/middle of the page. When the user reaches the end of the page the button should be enabled. For that I want to have Hostlistner/Directive/event binding which will listen to scroll and get the position of the scroll and inform when it reaches at bottom and enable I agree button. Is there any other way of doing it? I am new to angular. Thanks in advance

my html

You must scroll to the end of the terms and conditions And press "Agree"
            to continue with your request.

Lorem ipsum dolor sit amet

 consectetur adipiscing elit, sed do eiusmod tempor incididunt
              ut labore et dolore magna aliqua. Ac ut consequat semper viverra nam libero justo laoreet.
              Amet massa vitae tortor condimentum. Aliquam sem et tortor consequat id porta nibh venenatis
               cras. Sed id semper risus in hendrerit gravida rutrum quisque.

 Fermentum posuere urna

nec tincidunt praesent semper feugiat. Ullamcorper malesuada proin libero nunc consequat
               interdum varius. Habitasse platea dictumst quisque sagittis purus sit amet. Dictum non
               consectetur a erat nam. Duis tristique sollicitudin nibh sit amet commodo.
               Tincidunt tortor aliquam nulla facilisi cras fermentum. Massa sapien faucibus
               et molestie ac.

Mi bibendum

 neque egestas congue quisque egestas diam in. Aliquet porttitor lacus luctus
                 accumsan tortor posuere ac ut. Odio tempor orci dapibus ultrices in iaculis nunc. Sit amet
                  venenatis urna cursus eget.

Eget magna fermentum iaculis eu non diam. Enim praesent
                  elementum facilisis leo vel. Quam nulla porttitor massa id neque aliquam vestibulum. Arcu
                  cursus vitae congue mauris. Tempus quam pellentesque nec nam aliquam sem et tortor. Rhoncus
                  est pellentesque elit ullamcorper dignissim cras tincidunt lobortis.

 Tristique senectus et
                   netus et malesuada. Fermentum et sollicitudin ac orci phasellus egestas tellus rutrum.
                   Sed risus ultricies tristique nulla aliquet enim tortor. Nunc non blandit massa enim nec
                   dui nunc. Purus gravida quis blandit turpis cursus in hac habitasse platea.

You must press "Agree" to continue with your request.

          <button type="button" class="btn btn-outline-primary" style="float: left">Save as PDF</button>
          <button type="button" class="btn btn-outline-primary">Disagree</button>
          <button type="button" class="btn btn-primary" disabled>Agree</button>

My ts file

import { Component,ElementRef, ViewChild, HostListener, AfterViewInit } from '@angular/core';

@Component({
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent implements AfterViewInit {
  @ViewChild('agreement') agreement : ElementRef;

}

Body:
You can use the scrollTop and height information in connection with the current position.

document.documentElement.scrollTop + document.documentElement.offsetHeight
document.documentElement.scrollHeight

For more details, have a closer look at this answer:

https://stackoverflow.com/a/42547136/9293934


问:
Firebase update or add value when item has a key
I didnt find anything clever to get the solution yet.

This is my database:

```<code>var songKey = firebase.database().ref('songs').push().key;

                var songData = {
                  artist: finalSongTitle,
                  songTitle: songTitle,
                  genre: genre,
                  songImage: dlUrl,
                  user: user.uid,
                  isApproved: false,
                  songUrl: 'url'
                };

var updates = {};
    updates['songs/' + songKey] = songData;
    firebase.database().ref().update(updates);
</code>```

Now i want to update or set the songUrl but I'm not able to pass the key I set before. So how can I change the value?

This is when I set the data first time. Now like you guys said if I have to save the key, I saved it in a var and when I want to add the songUrl im using this:

```<code>    var secretKey = updates;

var songData2 = {
                  songUrl: songUrl
                };

var updates2 = {};
updates2[secretKey] = songData2;
firebase.database().ref().update(updates2);
</code>```

But then I get the following error:

```<code>Uncaught Error: Reference.update failed: First argument contains an invalid key ([object Object]) in path /[object Object]. Keys must be non-empty strings and can't contain ".", "#", "$", "/", "[", or "]"
</code>```

答:
Okay I figured out the solution. For everyone who is interested, I saved the key in a var and updated the single value with this line of code:

```<code>firebase.database().ref('songs/' + secretKey).update({ songUrl: songUrl });
</code>```

For anybody who is asking why I can't do it in one step: in my use case I'm uploading files step by step and I have to insert the data in a queue.

Body:
I didnt find anything clever to get the solution yet.

This is my database:

var songKey = firebase.database().ref('songs').push().key;

                var songData = {
                  artist: finalSongTitle,
                  songTitle: songTitle,
                  genre: genre,
                  songImage: dlUrl,
                  user: user.uid,
                  isApproved: false,
                  songUrl: 'url'
                };

var updates = {};
    updates['songs/' + songKey] = songData;
    firebase.database().ref().update(updates);

Now i want to update or set the songUrl but I'm not able to pass the key I set before. So how can I change the value?

This is when I set the data first time. Now like you guys said if I have to save the key, I saved it in a var and when I want to add the songUrl im using this:

    var secretKey = updates;

var songData2 = {
                  songUrl: songUrl
                };

var updates2 = {};
updates2[secretKey] = songData2;
firebase.database().ref().update(updates2);

But then I get the following error:

Uncaught Error: Reference.update failed: First argument contains an invalid key ([object Object]) in path /[object Object]. Keys must be non-empty strings and can't contain ".", "#", "$", "/", "[", or "]"

Body:
Okay I figured out the solution. For everyone who is interested, I saved the key in a var and updated the single value with this line of code:

firebase.database().ref('songs/' + secretKey).update({ songUrl: songUrl });

For anybody who is asking why I can't do it in one step: in my use case I'm uploading files step by step and I have to insert the data in a queue.


问:
Click a element which is the last element in a row of a grid, and the number of the row is dynamic, in cypress
The page has a grid. The grid has rows and columns. What I want to do is:
Each row has:
name email ready? date1 date2 togglebutton
I want to find a name on the page, and click on the togglebutton for that name. There could be 200 rows in a page.
Also, the name that I want to find could be in any row. Say, I am searching for janedoe@gmail.com
Based on the number of users signedup, janedoe could be in row 1 or row 97 or row 66. Once I locate janedoe@gmail.com on the page, how can I click the togglebutton?

I also want to paste the html here, but I dont know how to without it appearing in a single line?

答:
HTML code could be of great help, but assuming that each cell in the grid is td and the td with email is a sibling of td with togglebutton, and the button has class togglebutton, something like this should work:

```<code>cy.get('td:contains("janedoe@gmail.com") ~ td.togglebutton')
</code>```

It finds the cell td that contains text janedoe@gmail.com and then looks for a sibling of that cell: another cell td with class togglebutton.

Depending on your HTML structure it could look differently, but you should be able to adjust the code so it works for you.

PS to paste code, you may click CTRL+K or simply put your code between those characters: ``

Body:
HTML code could be of great help, but assuming that each cell in the grid is td and the td with email is a sibling of td with togglebutton, and the button has class togglebutton, something like this should work:

cy.get('td:contains("janedoe@gmail.com") ~ td.togglebutton')

It finds the cell td that contains text janedoe@gmail.com and then looks for a sibling of that cell: another cell td with class togglebutton.

Depending on your HTML structure it could look differently, but you should be able to adjust the code so it works for you.

PS to paste code, you may click CTRL+K or simply put your code between those characters: ``


问:
How can you make an image display in full resolution on a mobile browser?
The browser view-port size on a mobile device is often much lower than the screen resolution of that device. For example: on the iPhone X, the screen resolution is 1125 x 2436 whereas the view-port size is 375 x 812.

Given this, how can you make an image display with full resolution on a device such as the iPhone X? If you render an  whose src has a width of 375px, it will fill the width of the iPhoneX's screen. How can you alter this so that it only fills a third of the screen as per the device's true resolution, and displays in full quality? That is, how can you make the image display in terms of the true screen resolution and not the view-port size.

答:
```<code>width: 33%;
</code>```

or

```<code>width: 33vh;
</code>```

will have it be one third the width.

Body:
width: 33%;

or

width: 33vh;

will have it be one third the width.


问:
How to get matched array object based on their values in javascript
I would like to know how to get the array object based on values in javascript.
I have array object obj1, obj2 , how to get the object if name of obj1 matches with obj2 values in javascript

```<code>var obj1=[
  {name: "country", value: "countries"},
  {name: "city", value: "cities"}
]
var obj2=[
  {countries:"countries"},
  {sample: "sample"}
]
var result = this.getMatchedObj(obj1, obj2);

function getMatchedObj(obj){
    const newlist = obj1.map((elem) => obj2.find(e=>Object.values(e)===elem.value));
    return newlist;
}

</code>```

Expected Output:

```<code>[
 {name: "country", value: "countries"}
]
</code>```

答:
Use filter, find and includes methods.
If you just need one object, Then change filter call to find.

const getMatchedObj = (obj1, obj2) =>
  obj1.filter(({ value }) =>
    obj2.find((obj) => Object.values(obj).includes(value))
  );

var obj1 = [
  { name: "country", value: "countries" },
  { name: "city", value: "cities" },
];
var obj2 = [{ countries: "countries" }, { sample: "sample" }];

console.log(getMatchedObj(obj1, obj2));```

Body:
I would like to know how to get the array object based on values in javascript.
I have array object obj1, obj2 , how to get the object if name of obj1 matches with obj2 values in javascript

var obj1=[
  {name: "country", value: "countries"},
  {name: "city", value: "cities"}
]
var obj2=[
  {countries:"countries"},
  {sample: "sample"}
]
var result = this.getMatchedObj(obj1, obj2);

function getMatchedObj(obj){
    const newlist = obj1.map((elem) => obj2.find(e=>Object.values(e)===elem.value));
    return newlist;
}

Expected Output:

[
 {name: "country", value: "countries"}
]


问:
Can my docker image connect with a database running on same machine without network configuration?
I have created a docker image of my web application. I have a cassandra database running on my laptop and I am starting the container of my web application from the same laptop. The uri to connect to database is localhost:9042. However, the image is not able to connect with the database. Do I need to do some network configuration for the container to connect to the database?

```<code>[trace] CassandraRepositoryComponents - database will connect using parameters uri: cassandra://localhost:9042/, cluster name: myCluster
[trace] s.d.c.CassandraConnectionUri - created logger Logger[services.db.cassandra.CassandraConnectionUri]
[trace] s.d.c.CassandraConnectionManagementService - creating session with uri CassandraConnectionUri(cassandra://localhost:9042/) and cluster name myCluster
[trace] s.d.c.CassandraConnectionManagementService - exception in connecting with database com.datastax.driver.core.exceptions.NoHostAvailableException: All host(s) tried for query failed (tried: localhost/127.0.0.1:9042 (com.datastax.driver.core.exceptions.TransportException: [localhost/127.0.0.1:9042] Cannot connect))
Oops, cannot start the server.
</code>```

docker file

```<code>FROM openjdk:8
RUN mkdir deploy
WORKDIR deploy
COPY target/universal/myapp-1.0.zip .

COPY conf/logback_dev.xml ./logback.xml
COPY conf/application_dev.conf ./application.conf
RUN unzip myapp-1.0.zip
RUN chmod +x myapp-1.0/bin/myapp
EXPOSE 9000
ENTRYPOINT myapp-1.0/bin/myapp -Dplay.http.secret.key=changemeplease -Dlogger.file=/deploy/logback.xml -Dconfig.file=/deploy/application.conf
</code>```

Cassandra is running as a standalone application

答:
You can not access port opened on the host machine using 127.0.0.1. You need to find the IP assigned to the network interface of your VM (in Mac and Linux you may use ifconfig command ). Access the Cassandra using the same IP from your docker container.

Also, check if Cassandra accepts connection from any ip. Setting this to 0.0.0.0 will listen on all network interfaces. Make these changes in the cassandra.yaml config file:

```<code>rpc_address: 0.0.0.0
</code>```

Body:
I have created a docker image of my web application. I have a cassandra database running on my laptop and I am starting the container of my web application from the same laptop. The uri to connect to database is localhost:9042. However, the image is not able to connect with the database. Do I need to do some network configuration for the container to connect to the database?

[trace] CassandraRepositoryComponents - database will connect using parameters uri: cassandra://localhost:9042/, cluster name: myCluster
[trace] s.d.c.CassandraConnectionUri - created logger Logger[services.db.cassandra.CassandraConnectionUri]
[trace] s.d.c.CassandraConnectionManagementService - creating session with uri CassandraConnectionUri(cassandra://localhost:9042/) and cluster name myCluster
[trace] s.d.c.CassandraConnectionManagementService - exception in connecting with database com.datastax.driver.core.exceptions.NoHostAvailableException: All host(s) tried for query failed (tried: localhost/127.0.0.1:9042 (com.datastax.driver.core.exceptions.TransportException: [localhost/127.0.0.1:9042] Cannot connect))
Oops, cannot start the server.

docker file

FROM openjdk:8
RUN mkdir deploy
WORKDIR deploy
COPY target/universal/myapp-1.0.zip .

COPY conf/logback_dev.xml ./logback.xml
COPY conf/application_dev.conf ./application.conf
RUN unzip myapp-1.0.zip
RUN chmod +x myapp-1.0/bin/myapp
EXPOSE 9000
ENTRYPOINT myapp-1.0/bin/myapp -Dplay.http.secret.key=changemeplease -Dlogger.file=/deploy/logback.xml -Dconfig.file=/deploy/application.conf

Cassandra is running as a standalone application

Body:
You can not access port opened on the host machine using 127.0.0.1. You need to find the IP assigned to the network interface of your VM (in Mac and Linux you may use ifconfig command ). Access the Cassandra using the same IP from your docker container.

Also, check if Cassandra accepts connection from any ip. Setting this to 0.0.0.0 will listen on all network interfaces. Make these changes in the cassandra.yaml config file:

rpc_address: 0.0.0.0


问:
startActivity for external app needs <activity> declared?
I want to be able to open Android's stock Wifi Settings screen from my app, got this code:

```<code>Intent settings = new Intent(Settings.ACTION_WIFI_SETTINGS);
settings.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(settings);
</code>```

I get "Window already focused, ignoring focus gain of: com.android.internal.view.IInputMethodClient$Stub$Proxy@45a3df40"

If I'm correct I need to declare the activity in my manifest.. but HOW? I've tried this:

```<code><activity android:name="android.settings.WIFI_SETTINGS" />
</code>```

Or am I doing something else wrong??

UPDATE: I was trying to access the Wifi Settings Activity from an PreferenceActivity's onOptionsItemSelected method. This DOES NOT WORK for either startActivity, startService OR sendBroadcast.

The answer below DOES work in pretty much every other scenario.. :)

答:
You only have to declare your activities in your manifest. Not the one that belong to external programs.

And remove the flags in your intent, I can't see the point for them.

```<code>startActivity( new Intent(android.provider.settings.Settings.ACTION_WIFI_SETTINGS) );
</code>```

ContentLicense: CC BY-SA 3.0

Body:
I want to be able to open Android's stock Wifi Settings screen from my app, got this code:

Intent settings = new Intent(Settings.ACTION_WIFI_SETTINGS);
settings.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(settings);

I get "Window already focused, ignoring focus gain of: com.android.internal.view.IInputMethodClient$Stub$Proxy@45a3df40"

If I'm correct I need to declare the activity in my manifest.. but HOW? I've tried this:

<activity android:name="android.settings.WIFI_SETTINGS" />

Or am I doing something else wrong??

UPDATE: I was trying to access the Wifi Settings Activity from an PreferenceActivity's onOptionsItemSelected method. This DOES NOT WORK for either startActivity, startService OR sendBroadcast.

The answer below DOES work in pretty much every other scenario.. :)

Body:
You only have to declare your activities in your manifest. Not the one that belong to external programs.

And remove the flags in your intent, I can't see the point for them.

startActivity( new Intent(android.provider.settings.Settings.ACTION_WIFI_SETTINGS) );


问:
Source maps (for browser extension) don't work for me in Chrome 75, Edge 77
I created an example browser extension written in .html and typescript
that is working fine in Chrome, Firefox and Edge (canary). Typescript compiler generated .js and .js.map files from the .ts files.

I want to debug the source code where I can place breakpoints to the typescript code. I can do it in Firefox, but not in Chrome or Edge.
Chrome and Edge notice that the .map  and .ts files are to be added, I can can load them only from the sources and breakpoints don't work for me.

I read past articles.

Do source maps work for Chrome extensions?

Chrome Extension: Not loading source-maps

https://developers.google.com/web/tools/chrome-devtools/javascript/source-maps

https://bugs.chromium.org/p/chromium/issues/detail?id=212374

https://developer.chrome.com/extensions/manifest/web_accessible_resources

I tried different settings in manifest.json.

I can attach the whole zip with example extension, if I find a way. The whole  list of files in extension is: background.html, background.js, background.js.map, background.ts, base.js, base.js.map, base.ts, content.js, content.js.map, content.ts, manifest.json, popup.html, popup.js, popup.js.map, popup.ts, readme.md, tsconfig.json, tsext16.PNG, tsext19.PNG,

The complete manifest.json is

```<code>{
    "manifest_version": 2,

    "name": "Typescript Sourcemaps in Browser Extensions",
    "version": "1",
    "description": "Sourcemaps with Extensions",

    "icons": {
        "16": "tsext16.png"
    },
    "permissions": [
        "activeTab"
    ],
    "browser_action": {
        "default_icon": {
            "16": "tsext16.png",
            "19": "tsext19.png"
        },
        "default_popup": "popup.html",
        "default_title": "Typescript example popup"
    },
    "background": {
        "scripts": [
            "base.js",
            "background.js"
        ]
    },
    "content_scripts": [{
        "matches": ["http://*/*", "https://*/*"],
        "js": [
            "base.js",
            "content.js"
            ]
    }],
    "web_accessible_resources": [
        "background.js.map",
        "background.ts",
        "*"
    ]
}
</code>```

When looking at the Source pane, only .js files are shown.
A the top of the .js file, there is a message "Source map detected".
However, I don't know how to load .ts file (e.g. popup.ts) in a way that I
can make breakpoints working. I can mark the breakpoints in any .ts file
if I load it from "filesystem", but the execution doesn't stop and the file
name as shown in the tab has an additional icon (what probably means
"just for viewing, not connected to the debugger") similar to "new document".

I can debug this example extension in current Firefox 67.
I can get source maps for web pages into Chrome.
I tried at Windows 10 and Windows 7, both x64.

答:
For Chrome extension, mapped files are allocated under "Content scripts" tab within "Sources" tab under Developer Tools. Not under default "Page" tab.

There is a source code of all enabled extensions, plus webpack:// files (if source maps are created with Webpack).

It's also possible to find mapped files using Cmd + P.

Body:
I created an example browser extension written in .html and typescript
that is working fine in Chrome, Firefox and Edge (canary). Typescript compiler generated .js and .js.map files from the .ts files.

I want to debug the source code where I can place breakpoints to the typescript code. I can do it in Firefox, but not in Chrome or Edge.
Chrome and Edge notice that the .map  and .ts files are to be added, I can can load them only from the sources and breakpoints don't work for me.

I read past articles.

Do source maps work for Chrome extensions?

Chrome Extension: Not loading source-maps

https://developers.google.com/web/tools/chrome-devtools/javascript/source-maps

https://bugs.chromium.org/p/chromium/issues/detail?id=212374

https://developer.chrome.com/extensions/manifest/web_accessible_resources

I tried different settings in manifest.json.

I can attach the whole zip with example extension, if I find a way. The whole  list of files in extension is: background.html, background.js, background.js.map, background.ts, base.js, base.js.map, base.ts, content.js, content.js.map, content.ts, manifest.json, popup.html, popup.js, popup.js.map, popup.ts, readme.md, tsconfig.json, tsext16.PNG, tsext19.PNG,

The complete manifest.json is

{
    "manifest_version": 2,

    "name": "Typescript Sourcemaps in Browser Extensions",
    "version": "1",
    "description": "Sourcemaps with Extensions",

    "icons": {
        "16": "tsext16.png"
    },
    "permissions": [
        "activeTab"
    ],
    "browser_action": {
        "default_icon": {
            "16": "tsext16.png",
            "19": "tsext19.png"
        },
        "default_popup": "popup.html",
        "default_title": "Typescript example popup"
    },
    "background": {
        "scripts": [
            "base.js",
            "background.js"
        ]
    },
    "content_scripts": [{
        "matches": ["http://*/*", "https://*/*"],
        "js": [
            "base.js",
            "content.js"
            ]
    }],
    "web_accessible_resources": [
        "background.js.map",
        "background.ts",
        "*"
    ]
}

When looking at the Source pane, only .js files are shown.
A the top of the .js file, there is a message "Source map detected".
However, I don't know how to load .ts file (e.g. popup.ts) in a way that I
can make breakpoints working. I can mark the breakpoints in any .ts file
if I load it from "filesystem", but the execution doesn't stop and the file
name as shown in the tab has an additional icon (what probably means
"just for viewing, not connected to the debugger") similar to "new document".

I can debug this example extension in current Firefox 67.
I can get source maps for web pages into Chrome.
I tried at Windows 10 and Windows 7, both x64.


问:
Why is my copy constructor not working? (C++)
I'm studying C++ and created this simple code to practice copy constructors.

```<code>class Cube{
    private:
        double length;
    public:
        Cube(){
            length = 1;
            cout << "default constructor called" << endl;
        };
        Cube(const Cube& obj){
            length = obj.length;
            cout << "copy constructor called" << endl;
        };
};

Cube foo(){
    Cube c;
    return c;
}

int main(){
    Cube c2 = foo();
    return 0;
}
</code>```

I expected this to print

"default constructor called"

"copy constructor called"

"copy constructor called"

as default constructor is called in "Cube C", and copy constructor is called in "return c" and "Cube c2 = foo()".

However my console only shows "default constructor called"

Am I misunderstanding on how copy constructor works?

答:
However my console only shows "default constructor called"

Because of copy elision.

Your expectations are right. There're two copy constructions in concept, the 1st one is for return c;, copy-initialize the return value from c; the 2nd one is for Cube c2 = foo();, copy-initialize c2 from the return value of foo(). They're both omitted because of copy elision then the copy constructor is not called at all.

For the 1st one,

In a return statement, when the operand is the name of a non-volatile object with automatic storage duration, which isn't a function parameter or a catch clause parameter, and which is of the same class type (ignoring cv-qualification) as the function return type. This variant of copy elision is known as NRVO, "named return value optimization".

For the 2nd one,

In the initialization of an object, when the initializer expression is a prvalue of the same class type (ignoring cv-qualification) as the variable type:

```<code>   T x = T(T(f())); // only one call to default constructor of T, to initialize x
</code>```

Note that the 2nd one is mandatory since C++17.

BTW: Compiling in pre-C++17 mode (to avoid mandatory copy elision) with -fno-elide-constructors option (to avoid potential copy elision) gives the result you expected. LIVE with gcc

Body:
I'm studying C++ and created this simple code to practice copy constructors.

class Cube{
    private:
        double length;
    public:
        Cube(){
            length = 1;
            cout << "default constructor called" << endl;
        };
        Cube(const Cube& obj){
            length = obj.length;
            cout << "copy constructor called" << endl;
        };
};

Cube foo(){
    Cube c;
    return c;
}

int main(){
    Cube c2 = foo();
    return 0;
}

I expected this to print

"default constructor called"

"copy constructor called"

"copy constructor called"

as default constructor is called in "Cube C", and copy constructor is called in "return c" and "Cube c2 = foo()".

However my console only shows "default constructor called"

Am I misunderstanding on how copy constructor works?

Body:
However my console only shows "default constructor called"

Because of copy elision.

Your expectations are right. There're two copy constructions in concept, the 1st one is for return c;, copy-initialize the return value from c; the 2nd one is for Cube c2 = foo();, copy-initialize c2 from the return value of foo(). They're both omitted because of copy elision then the copy constructor is not called at all.

For the 1st one,

In a return statement, when the operand is the name of a non-volatile object with automatic storage duration, which isn't a function parameter or a catch clause parameter, and which is of the same class type (ignoring cv-qualification) as the function return type. This variant of copy elision is known as NRVO, "named return value optimization".

For the 2nd one,

In the initialization of an object, when the initializer expression is a prvalue of the same class type (ignoring cv-qualification) as the variable type:

   T x = T(T(f())); // only one call to default constructor of T, to initialize x

Note that the 2nd one is mandatory since C++17.

BTW: Compiling in pre-C++17 mode (to avoid mandatory copy elision) with -fno-elide-constructors option (to avoid potential copy elision) gives the result you expected. LIVE with gcc


问:
Automatically export a worksheet from SAP GUI
I use vbscript to run SAP GUI via Excel VBA, the following is my actions:

Login

select Tcode

give data and execute

export as worksheets.
My question is that the last action (export as worksheets) will show a file dialog that I need to choose path and press. But I want to export automatically by my set path and filename without the "save as" dialog.

Is there any method to do that?

Here is my VBA code:

```<code>Dim SAPconn As Object
Dim SAPsession As Object
Dim SapGuiAuto As Object
Dim WshShell As Object

Shell "C:\Program Files\SAP\FrontEnd\SAPgui\saplogon.exe", 4
Set WshShell = CreateObject("WScript.Shell")

Do Until WshShell.AppActivate("SAP Logon ")
    Application.Wait Now + TimeValue("0:00:01")
Loop

Set WshShell = Nothing

Set SapGuiAuto = GetObject("SAPGUI")
Set SAPapp = SapGuiAuto.GetScriptingEngine

Set SAPconn = SAPapp.Openconnection("ConnectionsName", True)
Set SAPsession = SAPconn.Children(0)

'LOGON
SAPsession.findById("wnd[0]").maximize
SAPsession.findById("wnd[0]/usr/txtRSYST-MANDT").Text = "100"
SAPsession.findById("wnd[0]/usr/txtRSYST-BNAME").Text = "userid"
SAPsession.findById("wnd[0]/usr/pwdRSYST-BCODE").Text = "password"
SAPsession.findById("wnd[0]").sendVKey 0
SAPsession.findById("wnd[0]/tbar[0]/okcd").Text = "tcode"
SAPsession.findById("wnd[0]").sendVKey 0
'run the script(skip)
SAPsession.findById("wnd[0]/usr/ctxtWERKS-LOW").Text = Cells(1, 2)......
'execute
SAPsession.findById("wnd[0]/tbar[1]/btn[8]").press
'show list
SAPsession.findById("wnd[0]/tbar[1]/btn[48]").press
'export
SAPsession.findById("wnd[0]/mbar/menu[0]/menu[1]/menu[1]").Select
'↑ just select export>as worksheet and open the file dailog....
</code>```

答:
This is the code I use to save from SAP - the exact path to the elements

(e.g "wnd[1]/usr/ctxtDY_PATH") will be different to your case as it depends on what tables you are working with:

```<code>SAPsession.findById("wnd[1]/tbar[0]/btn[0]").press
SAPsession.findById("wnd[1]/usr/ctxtDY_PATH").Text = "C:\Downloads\"
SAPsession.findById("wnd[1]/usr/ctxtDY_FILENAME").Text = "Downloaded_file_name"
SAPsession.findById("wnd[1]/usr/ctxtDY_FILENAME").caretPosition = 13
SAPsession.findById("wnd[1]/tbar[0]/btn[11]").press
</code>```

This does the following:

Clicks the save button

specifies the desired file path where the file is to be saved

specifies the desired file name

positions the cursor and presses save

As far as I'm aware, it is not possible to entirely bypass the save dialog.

Body:
I use vbscript to run SAP GUI via Excel VBA, the following is my actions:

Login

select Tcode

give data and execute

export as worksheets.
My question is that the last action (export as worksheets) will show a file dialog that I need to choose path and press. But I want to export automatically by my set path and filename without the "save as" dialog.

Is there any method to do that?

Here is my VBA code:

Dim SAPconn As Object
Dim SAPsession As Object
Dim SapGuiAuto As Object
Dim WshShell As Object

Shell "C:\Program Files\SAP\FrontEnd\SAPgui\saplogon.exe", 4
Set WshShell = CreateObject("WScript.Shell")

Do Until WshShell.AppActivate("SAP Logon ")
    Application.Wait Now + TimeValue("0:00:01")
Loop

Set WshShell = Nothing

Set SapGuiAuto = GetObject("SAPGUI")
Set SAPapp = SapGuiAuto.GetScriptingEngine

Set SAPconn = SAPapp.Openconnection("ConnectionsName", True)
Set SAPsession = SAPconn.Children(0)

'LOGON
SAPsession.findById("wnd[0]").maximize
SAPsession.findById("wnd[0]/usr/txtRSYST-MANDT").Text = "100"
SAPsession.findById("wnd[0]/usr/txtRSYST-BNAME").Text = "userid"
SAPsession.findById("wnd[0]/usr/pwdRSYST-BCODE").Text = "password"
SAPsession.findById("wnd[0]").sendVKey 0
SAPsession.findById("wnd[0]/tbar[0]/okcd").Text = "tcode"
SAPsession.findById("wnd[0]").sendVKey 0
'run the script(skip)
SAPsession.findById("wnd[0]/usr/ctxtWERKS-LOW").Text = Cells(1, 2)......
'execute
SAPsession.findById("wnd[0]/tbar[1]/btn[8]").press
'show list
SAPsession.findById("wnd[0]/tbar[1]/btn[48]").press
'export
SAPsession.findById("wnd[0]/mbar/menu[0]/menu[1]/menu[1]").Select
'↑ just select export>as worksheet and open the file dailog....

Body:
This is the code I use to save from SAP - the exact path to the elements

(e.g "wnd[1]/usr/ctxtDY_PATH") will be different to your case as it depends on what tables you are working with:

SAPsession.findById("wnd[1]/tbar[0]/btn[0]").press
SAPsession.findById("wnd[1]/usr/ctxtDY_PATH").Text = "C:\Downloads\"
SAPsession.findById("wnd[1]/usr/ctxtDY_FILENAME").Text = "Downloaded_file_name"
SAPsession.findById("wnd[1]/usr/ctxtDY_FILENAME").caretPosition = 13
SAPsession.findById("wnd[1]/tbar[0]/btn[11]").press

This does the following:

Clicks the save button

specifies the desired file path where the file is to be saved

specifies the desired file name

positions the cursor and presses save

As far as I'm aware, it is not possible to entirely bypass the save dialog.


问:
C++ MFC Integer Textfields Always Set to 0?
I'm creating a preferences form in VC++ MFC, and I have several textfields that only accept integers. I'm new to MFC, so this is how I found to initialize them in some tutorial:

```<code>CProgramDlg::CProgramDlg(CWnd* pParent /*=NULL*/)
: CDialog(CProgramDlg::IDD, pParent)
, m_nSampleValue1()
, m_nSampleValue2() ... m_nSampleValueN {}
</code>```

This is grand and all, but when I run it, all of the textboxes are filled with zeros. I know with strings that you can just send it "" and it will clear the textbox, but I tried NULL for my ints and did not have any luck.

Is there a trick to getting the textboxes to just be empty without showing zeros? Thank you for your help!

答:
m_nSampleValue1() and m_nSampleValue2() are value-initialized. If its primitive types, then that means they will be zero-initialized.

Is there a trick to getting the textboxes to just be empty without showing a 0?

If its integral type, then I think that isn't possible without changing other part of the code (which part? you've not posted it here).  If you don't want to do that, or if that is hard to do, then you can change the type of the members to string, then they will be empty strings automatically.

However, if you want to see non-zero values, then do this:

```<code>CProgramDlg::CProgramDlg(CWnd* pParent /*=NULL*/)
: CDialog(CProgramDlg::IDD, pParent)
, m_nSampleValue1(100)
, m_nSampleValue2(200) ... m_nSampleValueN(1000) {}
</code>```

Body:
I'm creating a preferences form in VC++ MFC, and I have several textfields that only accept integers. I'm new to MFC, so this is how I found to initialize them in some tutorial:

CProgramDlg::CProgramDlg(CWnd* pParent /*=NULL*/)
: CDialog(CProgramDlg::IDD, pParent)
, m_nSampleValue1()
, m_nSampleValue2() ... m_nSampleValueN {}

This is grand and all, but when I run it, all of the textboxes are filled with zeros. I know with strings that you can just send it "" and it will clear the textbox, but I tried NULL for my ints and did not have any luck.

Is there a trick to getting the textboxes to just be empty without showing zeros? Thank you for your help!

Body:
m_nSampleValue1() and m_nSampleValue2() are value-initialized. If its primitive types, then that means they will be zero-initialized.

Is there a trick to getting the textboxes to just be empty without showing a 0?

If its integral type, then I think that isn't possible without changing other part of the code (which part? you've not posted it here).  If you don't want to do that, or if that is hard to do, then you can change the type of the members to string, then they will be empty strings automatically.

However, if you want to see non-zero values, then do this:

CProgramDlg::CProgramDlg(CWnd* pParent /*=NULL*/)
: CDialog(CProgramDlg::IDD, pParent)
, m_nSampleValue1(100)
, m_nSampleValue2(200) ... m_nSampleValueN(1000) {}


问:
Extracting #define statements from another .c file to retain reverse-compatibility
I find myself with a "face-palm" type issue, and need advice to solve it

I am working on rolling out a new embedded C project that has been built around a logic engine that was originally written in Dynamic C (DC). The logic engine is written entirely in 1 file, there is no header file. The crux of my problem is that the senior developer wants this logic engine to compile In DC AND in the new C project so that only one copy of the logic, defines, etc needs to be maintained. One of the properties of DC is the includes files are very complicated for many reasons that I don't want to get into here. Long story short, extracting the variables, structure definitions, and define statements to a .h file compromises the DC project, it will not compile. Below is a summary of the two files of interest:

Dynamic C (DC) logic engine, 'DClogicEngine.c'

.#include 'newProject.h'

~ 1000 lines of structs and variables needed in new project.

~ 1500 #define statements needed in new C project

~ 20k lines of logic

New Project (C code) 'newProject.c'

~some code.

~dozens of neccesary references to the #define statements in 'DClogicEngine.c'

To re-iterate my problem, I am perfectly able to use #ifdefs and other compiler options to tie into the logic, and because this is a program I have control over, I was able to include a .h file, allowing me to include the necessary logic in the DC file. The problem is accessing the thousands of #define statements in 'DClogicEngine.c' from 'newProject.c'.

The issue I have is the notorious, face-palm, and age-old problem of "I want to include a .c file in another." I've tried countless ways of placing #include xx.c in different places and then getting clever with include guards, but no luck (and no surprises). I found an old thread and thought I might share the answer because it is humorous:

The bottom line is extracting these statements to a .h file will cause a great deal of pain in retaining reverse compatibility with the DC build. Perhaps a burden that will have to be beared?

No doubt I have myself a stupid problem. My question in three parts is:

1.) has anybody encountered a problem like this and how did you solve it?

2.) Is there anything creative I can do to make this work? Does anybody know any compiler wizardry that may help?

2.) general advice, what is the least painful way to solve this?

答:
Long story short, extracting the variables, structure definitions, and define statements to a .h file compromises the DC project, it will not compile.

This cannot be. You are saying that you have a single DC source file. There should be no systemic reason why you wouldn't be able to extract the part of that source file which contains structure definitions and other declarations in a header file which can be used by both the DC implementation and the the C re-implementation. (I don't know DC; it's possible that there are incompatibilities with C, but the refactoring should not affect the DC side — the compiler still sees a single translation unit like before. That it now consists of a source file with an included header is irrelevant to the compiler.)

The problems your were encountering were likely not of a general nature. They were likely specific to the project and circumstances (order of declarations etc.). Try to isolate them and post specific problems here.


问:
Modularity in Caliburn micro
I have main project(wpf app) and "child" project(user control class library). I am trying to use user control from child project inside MainView of my main project:

MainView.xaml:

```<code>        <ContentControl  x:Name="ActiveItem" Grid.Column="1">

        </ContentControl>
</code>```

MainViewModel:

```<code>        public void LoadAgenda()
        {
            ActivateItem(new InstanceOfViewModelFromChildProject());
        }
</code>```

And I get error

"Cannot find view for InstanceOfViewModelFromChildProject".

I think I get this error because it tries to find view inside my main project and not in child project where this viewmodel and view are located. Is there anyway to fix this or another way to do it?

答:
Override this methods in class that inherited bootstrapper class</p>

```<code>
        static Func<Type, DependencyObject, object, UIElement> _func;
        protected override void Configure()
        {
            var assembly = System.Reflection.Assembly.Load("YourAssemblyName"); //
            AssemblySource.Instance.Add(assembly);

            _func = ViewLocator.LocateForModelType;
            ViewLocator.LocateForModelType = LocateForModelType;

        }

        private static Func<Type, DependencyObject, object, UIElement> LocateForModelType = (modelType, displayLocation, context) => {

            //use the default method first:
            UIElement view = _func(modelType, displayLocation, context);
            if (!(view is TextBlock))
                return view;

            var viewTypeName = modelType.Name.Replace("Model", string.Empty);
            var viewType = (from assmebly in AssemblySource.Instance
                            from type in assmebly.GetExportedTypes()
                            where type.Name == viewTypeName
                            select type).FirstOrDefault();

            return viewType == null ? new TextBlock { Text = string.Format("{0} not found.", viewTypeName) }
                : Activator.CreateInstance(viewType) as UIElement;
        };

</code>```

Title: Modularity in Caliburn micro

Body:
I have main project(wpf app) and "child" project(user control class library). I am trying to use user control from child project inside MainView of my main project:

MainView.xaml:

        <ContentControl  x:Name="ActiveItem" Grid.Column="1">

        </ContentControl>

MainViewModel:

        public void LoadAgenda()
        {
            ActivateItem(new InstanceOfViewModelFromChildProject());
        }

And I get error

"Cannot find view for InstanceOfViewModelFromChildProject".

I think I get this error because it tries to find view inside my main project and not in child project where this viewmodel and view are located. Is there anyway to fix this or another way to do it?

Body:
Override this methods in class that inherited bootstrapper class

        static Func<Type, DependencyObject, object, UIElement> _func;
        protected override void Configure()
        {
            var assembly = System.Reflection.Assembly.Load("YourAssemblyName"); //
            AssemblySource.Instance.Add(assembly);

            _func = ViewLocator.LocateForModelType;
            ViewLocator.LocateForModelType = LocateForModelType;

        }

        private static Func<Type, DependencyObject, object, UIElement> LocateForModelType = (modelType, displayLocation, context) => {

            //use the default method first:
            UIElement view = _func(modelType, displayLocation, context);
            if (!(view is TextBlock))
                return view;

            var viewTypeName = modelType.Name.Replace("Model", string.Empty);
            var viewType = (from assmebly in AssemblySource.Instance
                            from type in assmebly.GetExportedTypes()
                            where type.Name == viewTypeName
                            select type).FirstOrDefault();

            return viewType == null ? new TextBlock { Text = string.Format("{0} not found.", viewTypeName) }
                : Activator.CreateInstance(viewType) as UIElement;
        };


问:
Dynamic query in LINQ
How do I write a dynamic query for Linq, if I have say Customer class which holds the fields:

```<code>string name
string address
int phoneno
</code>```

I have to query based on information given similar to

```<code>query = string.Empty;

if(!string.IsNullorEmpty(name))
{
   query += "@name = name";
}

if(!string.IsNullorEmpty(address))
{
   query += "@address = address";
}

if(!string.IsNullorEmpty(phoneno))
{
   query += "@phoneno = phoneno";
}

var result = from condition in customer
    where(query)
    select condition;
</code>```

Edit #1:

the items are changeable at run time like

```<code>private Customer[] GetCustomers(Dictionary<string,string> attributes)
{
   here the attribute may be, name alone, or name and address, or name address and phoneno

      foreach(string field in attributes.key)
      {
           query += field == attributes[key];

      }

         Customers[] =ExecuteQuery(query);

}
</code>```

Is this kind of query supported by LINQ?

Edit #2:

Hi Mouk,

As I am new to C#, I am still struggling, this is not working for me.

```<code>var query = _ConfigFile.ConnectionMasterSection;

for(int i = 0; i < filter.count; i++)
{
    query = result.Where(p => typeof(ConnectionMaster).GetProperty(filter[i].Attribute).Name == filter[i].Value);
}
</code>```

This yeilds Empty, where as i used this

```<code>var query = _ConfigFile.ConnectionMasterSection;

//Hard coded
res.Where(q => q.category == filter[0].Value);
</code>```

And it worked as I expected.

Hi Bryan Watts,

I tried your code also and I getting this error: "Lambda Parameter not in scope".

```<code>for(int i = 0; i < filter.count; i++)
{
    Field item = filter[i];

    MemberExpression param = Expression.MakeMemberAccess(Expression.Parameter(typeof(Connection), "p"), typeof(Connection).GetProperty(item.Attribute));

    MemberExpression constant = Expression.MakeMemberAccess(Expression.Constant(item), typeof(Field).GetProperty("Value"));
}

try
{
    var myquery = Queryable.Where(coll, Expression.Lambda<Func<Connection, bool>>(
    Expression.Equal(param, constant), Expression.Parameter(typeof(Connection),"p")));
}
</code>```

What is the mistake here?

答:
Check out this http://www.albahari.com/nutshell/predicatebuilder.aspx, it allows for strongly typed predicate building, it can be really nice.  If you want actually dynamic string built predicates than you can use the LINQ Dynamic Query Library provided by ScottGu.

Both will accomplish what you want although I would recommend the first option before the second.

Allowing you to do:

```<code>var predicate = PredicateBuilder.True<MyLinqType>();

if(!string.IsNullOrEmpty(name))
    predicate = predicate.And(p => p.name == name);

...

var myResults = Context.MyLinTypeQueryTable.Where(predicate);
</code>```

And more.

OwnerDisplayName: Mohanavel

LastEditorDisplayName: Quintin Robinson

ContentLicense: CC BY-SA 2.5

Title: Dynamic query in LINQ

Body:
How do I write a dynamic query for Linq, if I have say Customer class which holds the fields:

string name
string address
int phoneno

I have to query based on information given similar to

query = string.Empty;

if(!string.IsNullorEmpty(name))
{
   query += "@name = name";
}

if(!string.IsNullorEmpty(address))
{
   query += "@address = address";
}

if(!string.IsNullorEmpty(phoneno))
{
   query += "@phoneno = phoneno";
}

var result = from condition in customer
    where(query)
    select condition;

Edit #1:

the items are changeable at run time like

private Customer[] GetCustomers(Dictionary<string,string> attributes)
{
   here the attribute may be, name alone, or name and address, or name address and phoneno

      foreach(string field in attributes.key)
      {
           query += field == attributes[key];

      }

         Customers[] =ExecuteQuery(query);

}

Is this kind of query supported by LINQ?

Edit #2:

Hi Mouk,

As I am new to C#, I am still struggling, this is not working for me.

var query = _ConfigFile.ConnectionMasterSection;

for(int i = 0; i < filter.count; i++)
{
    query = result.Where(p => typeof(ConnectionMaster).GetProperty(filter[i].Attribute).Name == filter[i].Value);
}

This yeilds Empty, where as i used this

var query = _ConfigFile.ConnectionMasterSection;

//Hard coded
res.Where(q => q.category == filter[0].Value);

And it worked as I expected.

Hi Bryan Watts,

I tried your code also and I getting this error: "Lambda Parameter not in scope".

for(int i = 0; i < filter.count; i++)
{
    Field item = filter[i];

    MemberExpression param = Expression.MakeMemberAccess(Expression.Parameter(typeof(Connection), "p"), typeof(Connection).GetProperty(item.Attribute));

    MemberExpression constant = Expression.MakeMemberAccess(Expression.Constant(item), typeof(Field).GetProperty("Value"));
}

try
{
    var myquery = Queryable.Where(coll, Expression.Lambda<Func<Connection, bool>>(
    Expression.Equal(param, constant), Expression.Parameter(typeof(Connection),"p")));
}

What is the mistake here?

Body:
Check out this http://www.albahari.com/nutshell/predicatebuilder.aspx, it allows for strongly typed predicate building, it can be really nice.  If you want actually dynamic string built predicates than you can use the LINQ Dynamic Query Library provided by ScottGu.

Both will accomplish what you want although I would recommend the first option before the second.

Allowing you to do:

var predicate = PredicateBuilder.True<MyLinqType>();

if(!string.IsNullOrEmpty(name))
    predicate = predicate.And(p => p.name == name);

...

var myResults = Context.MyLinTypeQueryTable.Where(predicate);

And more.

OwnerDisplayName: Quintin Robinson


问:
Check if all child components are rendered
Is there any way I know whether all child components in blazor page are rendered or not?
I need to call JSInterop when all HTML are ready.</p>

答:
You can capture a reference to each child component using the ref attribute and add each one into some collection.

It may be helpful for you -> Blazor get nested components by Reflection

Thanks


问:
Typescript ts-nocheck seems to be ignored
I set // @ts-nocheck But I still get the typescript errors

```<code>OS: Catalina
</code>```

答:
ts-nocheck to only have meaning in JS files

This is implemented in TypeScript 3.7 beta: https://devblogs.microsoft.com/typescript/announcing-typescript-3-7-beta/

Body:
I set // @ts-nocheck But I still get the typescript errors

OS: Catalina


问:
DynamicAllocation enabled with Spark on Kubernetes?
Latest documentation for spark 2.4.5 suggests "Dynamic Resource Allocation and External Shuffle Service" in Future work, however, I have also found some older documentation for spark 2.2.0 suggesting it is supported after setting up external shuffle service.

Have you successfully enabled Spark dynamic allocation on Kubernetes? If so, what challenges did you face and which documentation did you reference?

We are currently using AWS EMR service for Spark, and would like to try out Spark on Kubernetes with Dynamic Allocation enabled.

Thanks!

答: the older docs do belong to the older Spark fork repo, which has been used as a basement and POC for the main Apache Spark repository work related to K8s. If you want to have this feature enabled your you - you are restricted to use only this older Spark 2.2.0 fork. Note that it is not recommended for PROD.</p>