I have scheduled task in JBoss:
<?xml version="1.0" encoding="UTF-8"?>
<server>
<mbean code="org.jboss.varia.scheduler.Scheduler" name="acme:service=Scheduler">
<attribute name="…">…</attribute>
…
</mbean>
</server>
How to write this task, that will execute at 1:00 AM on the first day of every month?
Thank You!
How about using EJB Scheduler?
Otherwise, check here:
<mbean code="org.jboss.varia.scheduler.Scheduler" name="jboss.test:service=MyScheduler">
<attribute name="StartAtStartup">true</attribute>
<attribute name="SchedulableClass">test.MySchedulable</attribute>
<attribute name="SchedulableArguments">MySchedulable,100</attribute>
<attribute name="SchedulableArgumentTypes">java.lang.String,long</attribute>
<attribute name="InitialStartDate">NOW</attribute>
<attribute name="SchedulePeriod">5000</attribute>
<attribute name="InitialRepetitions">10</attribute>
</mbean>
Schedulable:
package test;
import java.util.Date;
import org.jboss.varia.scheduler.Schedulable;
import org.apache.log4j.Logger;
public class MySchedulable implements Schedulable
{
private static final Logger log = Logger.getLogger(MySchedulable.class);
private String name;
private long value;
public MySchedulable(String name, long value)
{
this.name = name;
this.value = value;
log.info("nt name: " + name + ", value: " + value);
}
public void perform(Date now, long repetitions)
{
log.info("perform(), time: " + now +", repetitions: " + repetitions +", name: " + name + ", value: " + value);
}
}
How about this
In jboss-service.xml
<!-- Put a real date here -->
<attribute name="InitialStartDate">01-01-01 01:00</attribute>
<attribute name="SchedulePeriod">86400000</attribute>
Then in Java
package com.example.scheduler.job;
import java.util.Date;
import org.jboss.varia.scheduler.Schedulable;
import org.apache.log4j.Logger;
public class MyJobScheduler implements Schedulable {
public MyJobScheduler() {}
public void perform(Date now, long repetitions) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(now);
int day = calendar.get(Calendar.DAY_OF_MONTH);
if(day == 1) {
// Do stuff
}
}
}
I know this question is old, but what do you think?
Related
Ideas on why the MultiResourceItemReader is leaving the last file locked and I cannot move it with the Move Tasklet? The moves completes all the other files, but the last one read.
IO Exception has:
java.nio.file.FileSystemException: C:\Users\UGDW\MyProjects\ngsa2\oab-outside-assets-batchlauncher\input\EQ_AcctData_4321_03292020.csv -> C:\Users\UGDW\MyProjects\ngsa2\oab-outside-assets-batchlauncher\output\EQ_AcctData_4321_03292020.csv_processed: The process cannot access the file because it is being used by another process.
Batch config (stripped down):
<batch:job id="stockPlanAccountDataJob">
<batch:step id="getFilesInInputDirectory" next="fileProcessing">
<tasklet ref="getFilesInInputDirectoryTasklet"/>
</batch:step>
<batch:step id="fileProcessing" next="moveFilesToOuputDirectory">
<tasklet>
<chunk reader="stockPlanAccountDataFileReader" processor="stockPlanAccountDataProcessor" writer="stockPlanConsoleItemWriter"
commit-interval="20" skip-limit="20">
<batch:skippable-exception-classes>
<batch:include class="java.lang.Exception"/>
<batch:exclude class="org.springframework.batch.item.file.FlatFileParseException"/>
</batch:skippable-exception-classes>
</chunk>
</tasklet>
</batch:step>
<batch:step id="moveFilesToOuputDirectory">
<tasklet ref="stockPlanMoveFilesTasklet"/>
</batch:step>
</batch:job>
<bean id="getFilesInInputDirectoryTasklet" class="simplepeekandmulti.GetFilesInInputDirectoryTasklet" scope="step"/>
<bean id="stockPlanAccountDataFileReader" class="simplepeekandmulti.StockPlanAccountDataFileReader" scope="step">
<property name="delegate" ref="preprocessorUsingPeekable"/>
</bean>
<bean id="preprocessorUsingPeekable" class="org.springframework.batch.item.support.SingleItemPeekableItemReader" scope="step">
<property name="delegate" ref="multiFileResourceReader"/>
</bean>
<bean name="multiFileResourceReader" class="org.springframework.batch.item.file.MultiResourceItemReader" scope="step">
<property name="resources" value="file:#{jobExecutionContext[filepattern]}" />
<property name="delegate" ref="genericFlatFileReader" />
<property name="strict" value="true" />
</bean>
<bean id="genericFlatFileReader" class="org.springframework.batch.item.file.FlatFileItemReader" scope="step">
<property name="lineMapper" ref="genericFileLineMapper"/>
</bean>
<bean name="genericFileLineMapper" class="org.springframework.batch.item.file.mapping.PassThroughLineMapper" scope="step" />
<bean id="stockPlanAccountDataProcessor" class="simplepeekandmulti.StockPlanAccountDataProcessor" scope="step"/>
<bean id="stockPlanMoveFilesTasklet" class="simplepeekandmulti.StockPlanMoveFilesTasklet" scope="step"/>
Reader (with dumb logic):
package simplepeekandmulti;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.PeekableItemReader;
import simplepeekandmulti.StockPlanAccountData;
import simplepeekandmulti.StockPlanFileInputAccountData;
public class StockPlanAccountDataFileReader implements ItemReader<StockPlanFileInputAccountData> {
private PeekableItemReader<String> delegate;
private AtomicLong itemsRead = new AtomicLong(0L);
private static final String PIPE = "|";
private static final String PIPE_SPLIT = "\\|";
private static final int NUM_RECORDS_PER_LINE = 6;
public PeekableItemReader<String> getDelegate() {
return delegate;
}
public void setDelegate(PeekableItemReader<String> delegate) {
this.delegate = delegate;
}
#Override
public StockPlanFileInputAccountData read() throws Exception {
String currentLine = delegate.read();
StockPlanFileInputAccountData inputData = new StockPlanFileInputAccountData();
int recs = 0;
List<String> errorList = new ArrayList<>();
while (currentLine != null) {
if (currentLine.contains(PIPE)) {
recs++;
setDetailLine(currentLine, inputData, recs, errorList);
} else {
errorList.add(currentLine);
}
if ((errorList.size() % 2) == 0) {
return inputData;
}
itemsRead.incrementAndGet();
currentLine = delegate.read();
}
return null;
}
private void setDetailLine(String inputLine, StockPlanFileInputAccountData inputData,
int numRecs, List<String> errorList) {
String[] entry = inputLine.split(PIPE_SPLIT);
if (entry.length == NUM_RECORDS_PER_LINE) {
inputData.setDataRecordsPerFile(numRecs);
StockPlanAccountData data = new StockPlanAccountData();
data.setExternalClientId(entry[0]);
data.setSSN(entry[1]);
data.setExternalParticipantId(entry[2]);
data.setFirstName(entry[3]);
data.setLastName(entry[4]);
data.setDateOfBitrth(entry[5]);
inputData.addToDataList(data);
} else {
errorList.add("Detail Line Is Invalid, Does NOT have 6 columns, 5 pipes: " + inputLine);
}
}
}
Processor:
package simplepeekandmulti;
import java.util.ArrayList;
import java.util.List;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.annotation.BeforeStep;
import org.springframework.batch.item.ItemProcessor;
import com.vanguard.inst.batch.oab.springboot.data.StockPlanFileInputAccountData;
public class StockPlanAccountDataProcessor implements ItemProcessor<StockPlanFileInputAccountData, StockPlanFileInputAccountData> {
private StepExecution stepExecution;
#BeforeStep
public void beforeStep(StepExecution stepExecution) {
this.stepExecution = stepExecution;
}
public StockPlanFileInputAccountData process(StockPlanFileInputAccountData item) throws Exception {
List<String> errorList = new ArrayList<>(0);
if (errorList.isEmpty()) {
return item;
} else {
//exchangeEmailService.sendEmail(fileName, errorList);
return null;
}
}
}
Writer:
package simplepeekandmulti;
import java.util.List;
import org.springframework.batch.item.ItemWriter;
import org.springframework.stereotype.Component;
import com.vanguard.inst.batch.oab.springboot.data.StockPlanFileInputAccountData;
#Component
public class StockConsoleOutputItemWriter implements ItemWriter<StockPlanFileInputAccountData> {
#Override
public void write(List<? extends StockPlanFileInputAccountData> arg0) throws Exception {
// TODO Auto-generated method stub
}
}
Move Files Tasklet (with file name hardcoded): Last file in the loop always fails.
package simplepeekandmulti;
import java.io.IOException;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.List;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
#Component
public class StockPlanMoveFilesTasklet implements Tasklet {
private static final String CLASS_NAME = StockPlanMoveFilesTasklet.class.getSimpleName();
#Value("$simplepeekandmulti-{INPUT_DIR}")
private String inputDir;
#Value("$simplepeekandmulti-{OUTPUT_DIR}")
private String outputDir;
private static final String PROCESSED = "_processed";
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) {
String[] fileList = {"EQ_AcctData_3210_03302020.csv", "EQ_AcctData_4321_03302020.csv"};
try {
for (String fileName : fileList) {
Path pathFrom = FileSystems.getDefault().getPath(inputDir, fileName);
Path pathTo = FileSystems.getDefault().getPath(outputDir, fileName + PROCESSED);
Files.move(pathFrom, pathTo, StandardCopyOption.REPLACE_EXISTING);
}
} catch (IOException io) {
System.out.println(io.toString());
}
return RepeatStatus.FINISHED;
}
}
CSV Files simply have; header date, records pipe delimited, footer total record count
03/30/2020
3210|59658625|12000|AADFBCJGH|LLOQMNURS|1962-03-08
3210|10124602|12001|AADFBCJGH|LLOQMNURS|1962-03-08
2
03/30/2020
4321|5690154|13000|AADFBCJGH|LLOQMNURS|1988-10-23
4321|745701|13001|AADFBCJGH|LLOQMNURS|1988-10-23
2
I tried make a simple implementation of using Kura DataService
Here is the java class I made LampuPintar.java
package org.eclipse.kura.smarthome.lampupintar;
import org.eclipse.kura.data.DataService;
import org.osgi.service.component.ComponentContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class LampuPintar {
private DataService m_dataservice;
private static final Logger s_logger = LoggerFactory.getLogger(LampuPintar.class);
private static final String APP_ID = "lampupintar";
public void setDataService(DataService dataService){
m_dataservice = dataService;
}
public void unsetDataService(DataService dataService){
m_dataservice = null;
}
protected void activate(ComponentContext componentContext) {
s_logger.info("Bundle " + APP_ID + " has started!");
s_logger.debug(APP_ID + ": This is a debug message.");
}
protected void deactivate(ComponentContext componentContext) {
s_logger.info("Bundle " + APP_ID + " has stopped!");
}
public void publish() {
String topic = "smarthome/lampupintar";
String payload = "Hello";
int qos = 2;
boolean retain = false;
for (int i=0; i<20;i++){
try {
m_dataservice.publish(topic, payload.getBytes(), qos, retain, 2);
s_logger.info("Publish ok");
} catch (Exception e) {
s_logger.error("Error while publishing", e);
}
}
}
}
and this is the component definition file, component.xml
<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0"
activate="activate" deactivate="deactivate"
name="org.eclipse.kura.smarthome.lampupintar">
<implementation class="org.eclipse.kura.smarthome.lampupintar.LampuPintar"/>
<reference bind="setDataService"
cardinality="1..1"
interface="org.eclipse.kura.data.DataService"
name="DataService"
policy="static"
unbind="unsetDataService"/>
</scr:component>
I tried make a project with those files, I successfully created the .dp file and installed it to Kura Web UI, but it seems showed nothing and not send anything to the broker (I checked in the mosquitto broker console).
What's wrong with those codes ?? or something miss from those code to make it complete and work properly ??
Thanks.
Have you checked the log files (/var/log/kura.log and /var/log/kura-console.log)? Are you seeing your "Publish ok" message in the log? You can also check your bundle with the OSGi console (telnet localhost 5002) using the 'ss' and 'ls' commands. This will show if the bundle and resolved correctly.
I would also add the DataServiceListener [1]. This will help track events with the DataService.
[1] http://download.eclipse.org/kura/docs/api/3.0.0/apidocs/org/eclipse/kura/data/listener/DataServiceListener.html
I am new to spring batch and having a feed file with key param values in .txt format. I need to load the file into Mysql DB using spring batch. Is there any way to read a text file with key value message. Two rows are separated by an empty line and the delimiter is '='.
Sample File:
Name=Jack
Id=ADC12345
ClassId=7018
Rank=-326
Name=Gile
Id=FED12345
ClassId=7018
Rank=-32
Name, ID, ClassId and Rank are the column values.
Here's a working solution (you just need a blank line after the last record or it won't be read) :
1) Declare your business object :
public class Student {
private String name;
private String id;
private Integer classId;
private Integer rank;
// Getter + Setters
}
2) Declare a custom itemstreamreader to which you will delegate the actual FlatFileItemReader :
public class CustomMultiLineItemReader implements ItemStreamReader<Student> {
private FlatFileItemReader<FieldSet> delegate;
#Override
public void open(ExecutionContext executionContext) throws ItemStreamException {
delegate.open(executionContext);
}
#Override
public void update(ExecutionContext executionContext) throws ItemStreamException {
delegate.update(executionContext);
}
#Override
public void close() throws ItemStreamException {
delegate.close();
}
// Getter + Setters
}
3) Override its read method to manually map your multiline records :
public Student read() throws Exception {
Student s = null;
for (FieldSet line = null; (line = this.delegate.read()) != null;) {
if (line.getFieldCount() == 0) {
return s; // Record must end with footer
} else {
String prefix = line.readString(0);
if (prefix.equals("Name")) {
s = new Student(); // Record must start with header
s.setName(line.readString(1));
}
else if (prefix.equals("Id")) {
s.setId(line.readString(1));
}
else if (prefix.equals("ClassId")) {
s.setClassId(line.readInt(1));
}
else if (prefix.equals("Rank")) {
s.setRank(line.readInt(1));
}
}
}
return null;
}
4) Declare the reader in the step and configure it :
<bean class="xx.xx.xx.CustomMultiLineItemReader">
<property name="delegate">
<bean class="org.springframework.batch.item.file.FlatFileItemReader">
<property name="resource" value="file:${YOUR_FILE}"></property>
<property name="linesToSkip" value="0"></property>
<property name="lineMapper">
<bean class="org.springframework.batch.item.file.mapping.PatternMatchingCompositeLineMapper">
<property name="tokenizers">
<map>
<entry key="*">
<bean class="org.springframework.batch.item.file.transform.DelimitedLineTokenizer">
<property name="delimiter" value="="></property>
</bean>
</entry>
</map>
</property>
<property name="fieldSetMappers">
<map>
<entry key="*">
<bean class="org.springframework.batch.item.file.mapping.PassThroughFieldSetMapper" />
</entry>
</map>
</property>
</bean>
</property>
</bean>
</property>
</bean>
I used a PatternMatchingCompositeLineMapper to associate line content (here : *) with the corresponding lineTokenizer and lineMapper (even though it's useless in this case).
Then, the PassThroughFieldSetMapper lets the reader do the mapping, and the DelimitedLineTokenizer splits the line on the "=" character.
there are 2 challenges with this input format
start/end for a complete item
splitting the item in key/value pairs
one solution could be to use a custom RecordSeparatorPolicy and custom LineMapper, like
import java.util.HashMap;
import java.util.Map;
import org.junit.Test;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.item.file.FlatFileItemReader;
import org.springframework.batch.item.file.mapping.DefaultLineMapper;
import org.springframework.batch.item.file.mapping.FieldSetMapper;
import org.springframework.batch.item.file.separator.RecordSeparatorPolicy;
import org.springframework.batch.item.file.transform.DelimitedLineTokenizer;
import org.springframework.batch.item.file.transform.FieldSet;
import org.springframework.core.io.ClassPathResource;
import org.springframework.validation.BindException;
public class ReaderKeyValueTest {
#Test
public void test() throws Exception {
FlatFileItemReader<Map<String, String>> reader = new FlatFileItemReader<Map<String, String>>();
reader.setResource(new ClassPathResource("keyvalue.txt"));
// custom RecordSeparatorPolicy
reader.setRecordSeparatorPolicy(new RecordSeparatorPolicy() {
#Override
public String preProcess(final String record) {
// empty line is added to the previous 'item'
if (record.isEmpty()) {
return record;
} else {
// line with content means it is part of an 'item', lets enhance it with adding a separator
return record + ",";
}
}
#Override
public String postProcess(final String record) {
return record;
}
#Override
public boolean isEndOfRecord(final String record) {
// the end of a record is marked with the last key/value pair for "Rank"
if (record.contains("Rank=")) {
return true;
} else {
return false;
}
}
});
DefaultLineMapper<Map<String, String>> lineMapper = new DefaultLineMapper<Map<String, String>>();
// the key/value pairs are separated with ',', so we can use the standard DelimitedLineTokenizer here
lineMapper.setLineTokenizer(new DelimitedLineTokenizer());
lineMapper.setFieldSetMapper(new FieldSetMapper<Map<String, String>>() {
#Override
public Map<String, String> mapFieldSet(final FieldSet fieldSet) throws BindException {
Map<String, String> item = new HashMap<String, String>();
// split each "Key=Value" and add to the Map
for (int i = 0; i < fieldSet.getValues().length; i++) {
String[] entry = fieldSet.getValues()[i].split("=");
item.put(entry[0], entry[1]);
}
return item;
}
});
reader.setLineMapper(lineMapper);
reader.open(new ExecutionContext());
Map<String, String> item;
while ((item = reader.read()) != null) {
System.out.println(item.toString());
}
reader.read();
reader.close();
}
}
the sysout produces
{ClassId=7018, Id=ADC12345, Name=Jack, Rank=-326}
{ClassId=7018, Id=FED12345, Name=Gile, Rank=-32}
The Spring Batch JdbcCursorItemReader can accept a preparedStatementSetter:
<bean id="reader" class="org.springframework.batch.item.database.JdbcCursorItemReader">
<property name="dataSource" ref="..." />
<property name="sql" value="SELECT * FROM test WHERE col1 = ?">
<property name="rowMapper" ref="..." />
<property name="preparedStatementSetter" ref="..." />
</bean>
This works well if the sql uses ? as placeholder(s), as in the above example. However, our pre-existing sql uses named parameters, e.g. SELECT * FROM test WHERE col1 = :param
.
Is there a way to get a JdbcCursorItemReader to work with a NamedPreparedStatementSetter rather than a simple PreparedStatementSetter?
Thanks
You can try with jobParameters. In this case you don't need any PreparedStatementSetter.
<bean id="reader" class="org.springframework.batch.item.database.JdbcCursorItemReader">
<property name="dataSource" ref="..." />
<property name="sql" value="SELECT * FROM test WHERE col1 = #{jobParameters['col1']">
<property name="rowMapper" ref="..." />
<property name="preparedStatementSetter" ref="..." />
</bean>
pass the value when running the job
JobParameters param = new JobParametersBuilder().addString("col1", "value1").toJobParameters();
JobExecution execution = jobLauncher.run(job, param);
Once we don't have an official solution from spring, we can fix this problem using a simple approach:
Define one interface to provide the SqlParameters:
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
public interface SqlParameterSourceProvider {
SqlParameterSource getSqlParameterSource();
}
Extending the JdbcCursorItemReader and adding the namedParameter features.
import org.springframework.batch.item.database.JdbcCursorItemReader;
import org.springframework.jdbc.core.SqlTypeValue;
import org.springframework.jdbc.core.StatementCreatorUtils;
import org.springframework.jdbc.core.namedparam.*;
import org.springframework.util.Assert;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.*;
public class NamedParameterJdbcCursorItemReader<T> extends JdbcCursorItemReader<T> {
private SqlParameterSourceProvider parameterSourceProvider;
private String paramedSql;
public NamedParameterJdbcCursorItemReader(SqlParameterSourceProvider parameterSourceProvider) {
this.parameterSourceProvider = parameterSourceProvider;
}
#Override
public void setSql(String sql) {
Assert.notNull(parameterSourceProvider, "You have to set parameterSourceProvider before the SQL statement");
Assert.notNull(sql, "sql must not be null");
paramedSql = sql;
super.setSql(NamedParameterUtils.substituteNamedParameters(sql, parameterSourceProvider.getSqlParameterSource()));
}
#Override
protected void applyStatementSettings(PreparedStatement stmt) throws SQLException {
final ParsedSql parsedSql = NamedParameterUtils.parseSqlStatement(paramedSql);
final List<?> parameters = Arrays.asList(NamedParameterUtils.buildValueArray(parsedSql, parameterSourceProvider.getSqlParameterSource(), null));
for (int i = 0; i < parameters.size(); i++) {
StatementCreatorUtils.setParameterValue(stmt, i + 1, SqlTypeValue.TYPE_UNKNOWN, parameters.get(i));
}
}
}
Creating the concrete class that implements the interface SqlParameterSourceProvider and has the state with the updated value of the parameters to be used in your query.
public class MyCustomSqlParameterSourceProvider implements SqlParameterSourceProvider {
private Map<String, Object> params;
public void updateParams(Map<String, Object> params) {
this.params = params;
}
#Override
public SqlParameterSource getSqlParameterSource() {
final MapSqlParameterSource paramSource = new MapSqlParameterSource();
paramSource.addValues(params);
return paramSource;
}
}
Finally, update the spring configuration.
<bean id="reader" class="org.wisecoding.stackoverflow.NamedParameterJdbcCursorItemReader">
<constructor-arg ref="sqlParameterSourceProvider"/>
<property name="dataSource" ref="..." />
<property name="sql" value=SELECT * FROM test WHERE col1 = :param" />
<property name="rowMapper" ref="..." />
<property name="preparedStatementSetter" ref="..." />
</bean>
<bean id="sqlParameterSourceProvider" class="org.wisecoding.stackoverflow.MyCustomSqlParameterSourceProvider">
</bean>
Currently, there is not a way to do this. The JdbcCursorItemReader uses raw JDBC (PreparedStatement) instead of the Spring JdbcTemplate under the hood (since there is no way to get the underlying ResultSet when using JdbcTemplate). If you'd like to contribute this as a new feature, or request it as a new feature, feel free to do so at jira.spring.io
original solution in https://jira.spring.io/browse/BATCH-2521, but which does not support id in (:ids) clause.
here is an enhancement.
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.springframework.batch.item.database.JdbcCursorItemReader;
import org.springframework.jdbc.core.PreparedStatementCreatorFactory;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterUtils;
import java.util.Map;
#Slf4j
public class NamedParameterJdbcCursorItemReader<T> extends JdbcCursorItemReader<T> {
protected void setNamedParametersSql(String sql, Map<String, Object> parameters) {
val parsedSql = NamedParameterUtils.parseSqlStatement(sql);
val paramSource = new MapSqlParameterSource(parameters);
val sqlToUse = NamedParameterUtils.substituteNamedParameters(parsedSql, paramSource);
val declaredParams = NamedParameterUtils.buildSqlParameterList(parsedSql, paramSource);
val params = NamedParameterUtils.buildValueArray(parsedSql, paramSource, null);
val pscf = new PreparedStatementCreatorFactory(sql, declaredParams);
val pss = pscf.newPreparedStatementSetter(params);
log.info("sql: {}", sqlToUse);
log.info("parameters: {}", parameters);
setSql(sqlToUse);
setPreparedStatementSetter(pss);
}
}
Usage:
#Slf4j
public class UserItemJdbcReader extends NamedParameterJdbcCursorItemReader<UserEntity> {
#PostConstruct
public void init() {
val sql = "SELECT * FROM users WHERE id IN (:ids)";
val parameters = new HashMap<String, Object>(4);
parameters.put("ids", Arrays.asList(1,2,3));
setDataSource(dataSource);
setRowMapper(new UserRowMapper());
setNamedParametersSql(sql, parameters);
}
}
in my case I reuse ArgumentPreparedStatementSetter from spring-jdbc
private static final String SQL = "SELECT * FROM payments.transactions WHERE time_stamp >= ? AND time_stamp <= ?";
...
Object[] args = new Object[2];
args[0] = new Date(Instant.now().minus(7, ChronoUnit.DAYS).toEpochMilli());
args[1] = new Date();
ArgumentPreparedStatementSetter argumentPreparedStatementSetter =
new ArgumentPreparedStatementSetter(args);
return new JdbcCursorItemReaderBuilder<>()
.name("dbReader")
.sql(SQL)
.preparedStatementSetter(argumentPreparedStatementSetter)
...
I am running jboss5 and jboss 7 in same machine, so I changed port nos(jboss5-4040 and jboss7-8080). I need to send a message from jboss 5 to jboss 7. I read an article, state that, have to use JMS bridge.
https://community.jboss.org/wiki/BridgeJMSMessagesFromAS5ToAS7
I created a queue in jboss 5 and sent messages to the queue by standalone program.
import java.io.Console;
import java.util.Properties;
import javax.jms.*;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
public class sender {
String url_;
String name_;
Connection conn = null;
Session session = null;
Queue queue = null;
public sender(String url, String name) throws JMSException,
NamingException {
url_ = url;
name_ = name;
this.initializeSender();
}
private void initializeSender() throws JMSException, NamingException {
Properties props = new Properties();
props.setProperty("java.naming.factory.initial",
"org.jnp.interfaces.NamingContextFactory");
props.setProperty("java.naming.factory.url.pkgs", "org.jboss.naming");
props.setProperty("java.naming.provider.url", "jnp://localhost:1099");
Context context = new InitialContext(props);
ConnectionFactory cf = (ConnectionFactory) context
.lookup("java:/ConnectionFactory");
conn = cf.createConnection();
session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
queue = (Queue) context.lookup(name_);
conn.start();
}
public void send(String text) throws JMSException, NamingException {
// Send a text msg
MessageProducer producer = session.createProducer(queue);
TextMessage tm = session.createTextMessage(text);
producer.send(tm);
producer.close();
}
public void disconnect() throws JMSException {
if (conn != null) {
conn.stop();
}
if (session != null) {
session.close();
}
if (conn != null) {
conn.close();
}
}
public String getTopicName() {
return name_;
}
public String getTopicURL() {
return url_;
}
public static void main(String args[]) throws Exception {
sender sender = new sender("remote://localhost:4447", "BalaQueue");
sender.send("My Message");
sender.disconnect();
}
}
and I created a queue in jboss 7 and sent messages to the queue by standalone program.
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Properties;
import javax.jms.Queue;
import javax.jms.QueueConnection;
import javax.jms.QueueConnectionFactory;
import javax.jms.QueueSender;
import javax.jms.QueueSession;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.naming.Context;
import javax.naming.InitialContext;
public class QSender {
public static void main(String[] args) {
new QSender().send();
}
public void send() {
BufferedReader reader = new BufferedReader(new InputStreamReader(
System.in));
try {
// Strings for JNDI names
String factoryName = "jms/RemoteConnectionFactory";
String queueName = "jms/queue/ram";
// Create an initial context.
Properties props = new Properties();
props.put(Context.INITIAL_CONTEXT_FACTORY,
"org.jboss.naming.remote.client.InitialContextFactory");
props.put(Context.PROVIDER_URL, "remote://localhost:4447");
props.put(Context.SECURITY_PRINCIPAL, "ramguest");
props.put(Context.SECURITY_CREDENTIALS, "password");
InitialContext context = new InitialContext(props);
QueueConnectionFactory factory = (QueueConnectionFactory) context
.lookup(factoryName);
Queue queue = (Queue) context.lookup(queueName);
context.close();
// Create JMS objects
QueueConnection connection = factory.createQueueConnection(
"ramguest", "password");
QueueSession session = connection.createQueueSession(false,
Session.AUTO_ACKNOWLEDGE);
QueueSender sender = session.createSender(queue);
System.out.println("Enter message to send or 'quit' to quit.");
String messageText = null;
while (true) {
messageText = reader.readLine();
if ("quit".equalsIgnoreCase(messageText)) {
break;
}
TextMessage message = session.createTextMessage(messageText);
sender.send(message);
}
// Exit
reader.close();
System.out.println("Exiting...");
connection.close();
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
}
}
and my bridge file(jboss-service.xml)
<server>
<loader-repository>com.example:archive=unique-archive-name
<loader-repository-config>java2ParentDelegation=false</loader-repository-config>
</loader-repository> <!-- AS7 JMS Provider -->
<mbean code="org.jboss.jms.jndi.JMSProviderLoader" name="jboss.messaging:service=JMSProviderLoader,name=RemoteJBossMQProvider"> <attribute name="ProviderName">RemoteXAConnectionFactory</attribute>
<attribute name="ProviderAdapterClass">org.jboss.jms.jndi.JNDIProviderAdapter</attribute>
<attribute name="FactoryRef">jms/RemoteConnectionFactory</attribute>
<attribute name="QueueFactoryRef">jms/RemoteConnectionFactory</attribute>
<attribute name="TopicFactoryRef">jms/RemoteConnectionFactory</attribute>
<attribute name="Properties"> java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.provider.url=remote://localhost:4447
java.naming.security.principal=ramguest
java.naming.security.credentials=password
</attribute>
</mbean>
<mbean code="org.jboss.jms.server.bridge.BridgeService" name="jboss.jms:service=Bridge,name=LegayBridgeSend" xmbean-dd="xmdesc/Bridge-xmbean.xml">
<depends optional-attribute-name="SourceProviderLoader">jboss.messaging:service=JMSProviderLoader,name=JMSProvider</depends>
<depends optional-attribute-name="TargetProviderLoader">jboss.messaging:service=JMSProviderLoader,name=RemoteJBossMQProvider</depends>
<attribute name="SourceDestinationLookup">BalaQueue</attribute>
<attribute name="TargetDestinationLookup">java:jboss/exported/jms/queue/ram</attribute>
<attribute name="QualityOfServiceMode">1</attribute>
<attribute name="MaxBatchSize">1</attribute>
<attribute name="MaxBatchTime">-1</attribute>
<attribute name="FailureRetryInterval">10000</attribute>
<attribute name="MaxRetries">-1</attribute>
<attribute name="AddMessageIDInHeader">false</attribute>
<attribute name="TargetUsername">ramguest</attribute>
<attribute name="TargetPassword">password</attribute>
</mbean>
</server>
When I start jboss5 I am getting exception
WARN [Bridge] jboss.jms:name=LegayBridgeSend,service=Bridge Failed to set up connections
javax.naming.CommunicationException: Receive timed out [Root exception is java.net.SocketTimeoutException: Receive timed out]
at org.jnp.interfaces.NamingContext.discoverServer(NamingContext.java:1678)
at org.jnp.interfaces.NamingContext.checkRef(NamingContext.java:1795)
at org.jnp.interfaces.NamingContext.lookup(NamingContext.java:693)
at org.jnp.interfaces.NamingContext.lookup(NamingContext.java:686)
at javax.naming.InitialContext.lookup(InitialContext.java:392)
at org.jboss.jms.server.bridge.JNDIFactorySupport.createObject(JNDIFactorySupport.java:66)
at org.jboss.jms.server.bridge.JNDIDestinationFactory.createDestination(JNDIDestinationFactory.java:45)
at org.jboss.jms.server.bridge.Bridge.setupJMSObjects(Bridge.java:953)
at org.jboss.jms.server.bridge.Bridge.setupJMSObjectsWithRetry(Bridge.java:1223)
at org.jboss.jms.server.bridge.Bridge.access$1600(Bridge.java:68)
at org.jboss.jms.server.bridge.Bridge$FailureHandler.run(Bridge.java:1569)
at java.lang.Thread.run(Thread.java:662)
Caused by: java.net.SocketTimeoutException: Receive timed out
at java.net.PlainDatagramSocketImpl.receive0(Native Method)
at java.net.PlainDatagramSocketImpl.receive(PlainDatagramSocketImpl.java:145)
at java.net.DatagramSocket.receive(DatagramSocket.java:725)
at org.jnp.interfaces.NamingContext.discoverServer(NamingContext.java:1647)
Can anybody guide me please...
JBOSS AS 7 doesn't support JNP , Use jboss remoting
<attribute name="Properties">
java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.provider.url=remote://localhost:4447
java.naming.security.principal=ramguest
java.naming.security.credentials=password
</attribute>
Change
org.jnp.interfaces.NamingContextFactory
to
org.jboss.naming.remote.client.InitialContextFactory