-
hello World batch
Is there something wrong with this configuration?
Code:
<bean id="hello" class="org.springframework.batch.sample.tasklet.PrintTasklet">
<property name="message" value="Hello"/>
</bean>
<bean id="space" class="org.springframework.batch.sample.tasklet.PrintTasklet">
<property name="message" value=" ## "/>
</bean>
<bean id="world" class="org.springframework.batch.sample.tasklet.PrintTasklet">
<property name="message" value="World!!!"/>
</bean>
<bean id="taskletStep" abstract="true"
class="org.springframework.batch.core.step.tasklet.TaskletStep">
<property name="jobRepository" ref="jobRepository"/>
</bean>
<bean id="simpleJob" class="org.springframework.batch.core.job.SimpleJob">
<property name="name" value="simpleJob" />
<property name="steps">
<list>
<bean parent="taskletStep">
<property name="tasklet" ref="hello"/>
</bean>
<bean parent="taskletStep">
<property name="tasklet" ref="space"/>
</bean>
<bean parent="taskletStep">;
<property name="tasklet" ref="world"/>
</bean>
</list>
</property>
<property name="jobRepository" ref="jobRepository"/>
</bean>
I am getting this exception:
Code:
org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Failed to import bean definitions from URL location [classpath:/jobs/helloWorld.xml]
Offending resource: class path resource [org/springframework/batch/sample/HelloWorldFunctionalTests-context.xml]; nested exception is org.springframework.beans.factory.xml.XmlBeanDefinitionStoreException: Line 49 in XML document from class path resource [jobs/helloWorld.xml] is invalid; nested exception is org.xml.sax.SAXParseException: cvc-complex-type.2.3: Element 'bean' cannot have character [children], because the type's content type is element-only. at org.springframework.beans.factory.parsing.FailFastProblemReporter.error(FailFastProblemReporter.java:68)
at org.springframework.beans.factory.parsing.ReaderContext.error(ReaderContext.java:85)
at org.springframework.beans.factory.parsing.ReaderContext.error(ReaderContext.java:76)
at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.importBeanDefinitionResource(DefaultBeanDefinitionDocumentReader.java:182)
at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.parseDefaultElement(DefaultBeanDefinitionDocumentReader.java:147)
at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.parseBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:132)
at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.registerBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:92)
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.registerBeanDefinitions(XmlBeanDefinitionReader.java:507)
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:398)
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:342)
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:310)
at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:143)
at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:178)
at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:149)
at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:212)
at org.springframework.test.AbstractSingleSpringContextTests.createApplicationContext(AbstractSingleSpringContextTests.java:242)
at org.springframework.test.AbstractSingleSpringContextTests.loadContextLocations(AbstractSingleSpringContextTests.java:212)
at org.springframework.test.AbstractSingleSpringContextTests.loadContext(AbstractSingleSpringContextTests.java:187)
at org.springframework.test.AbstractSpringContextTests.getContext(AbstractSpringContextTests.java:140)
at org.springframework.test.AbstractSingleSpringContextTests.setUp(AbstractSingleSpringContextTests.java:100)
at junit.framework.TestCase.runBare(TestCase.java:132)
at org.springframework.test.ConditionalTestCase.runBare(ConditionalTestCase.java:76)
at junit.framework.TestResult$1.protect(TestResult.java:110)
at junit.framework.TestResult.runProtected(TestResult.java:128)
at junit.framework.TestResult.run(TestResult.java:113)
at junit.framework.TestCase.run(TestCase.java:124)
at junit.framework.TestSuite.runTest(TestSuite.java:232)
at junit.framework.TestSuite.run(TestSuite.java:227)
at org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:81)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:38)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)
[B]Caused by: org.springframework.beans.factory.xml.XmlBeanDefinitionStoreException: Line 49 in XML document from class path resource [jobs/helloWorld.xml] is invalid; nested exception is org.xml.sax.SAXParseException: cvc-complex-type.2.3: Element 'bean' cannot have character [children], because the type's content type is element-only. at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:404)
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:342)
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:310)
at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:143)
at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:178)
at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.importBeanDefinitionResource(DefaultBeanDefinitionDocumentReader.java:174)
... 31 more
Caused by: org.xml.sax.SAXParseException: cvc-complex-type.2.3: Element 'bean' cannot have character [children], because the type's content type is element-only.
at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(Unknown Source)
at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.error(Unknown Source)
at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(Unknown Source)
at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(Unknown Source)
at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator$XSIErrorReporter.reportError(Unknown Source)
at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.reportSchemaError(Unknown Source)
at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.elementLocallyValidComplexType(Unknown Source)
at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.elementLocallyValidType(Unknown Source)
at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.processElementContent(Unknown Source)
at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.handleEndElement(Unknown Source)
at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.endElement(Unknown Source)
at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.scanEndElement(Unknown Source)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDispatcher.dispatch(Unknown Source)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(Unknown Source)
at com.sun.org.apache.xerces.internal.parsers.DOMParser.parse(Unknown Source)
at com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.parse(Unknown Source)
at org.springframework.beans.factory.xml.DefaultDocumentLoader.loadDocument(DefaultDocumentLoader.java:75)
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:396)
... 36 more
-
Go to line 49 as the stacktrace guides you and watch for special characters that need to be escaped in the enclosing bean definition (not really batch related btw).
UPDATE: even better look for trailing semicolon :)
-
Well how stupid can i get! ;)
I was thinking there is an issue with simpleJob Bean because if I use a single step, it works. was thinking its not able to take a <List>
Sorry abt that...
-
Don't worry, it's no stupider than the author of the
"Hello World" Spring Batch article on dzone, Tareq Abed Rabbo,
who had those typos in the original article and on his blog.
-Paul
p.s. For those who find this post before his article, I haven't been posting long enough to link externally so just search for the second line of this post and you'll find his article.
-
The blog link is http://java.dzone.com/news/spring-batch-hello-world-1. It's a useful contribution (despite using only TaskletStep, which is not the majority use case).
-
Corrections
Thanks Dave. I also thought to mention that a few other coding typos are listed by me on a reply to the DZone article. I don't know about others but I'm sometimes ready to bite someone (not necessarily the author mind you*) when I can't get through a "Hello World" program without finding code typos in things I don't yet understand, so I spend too long figuring out where the problem is.
-P
*I'm sure the author is wondering how how the heck those typos got in his article.
-
spring batch
Hi,
I'm beginner with spring quartz and i have a problem for my project.
I'would whan my job is failed or sleep, the scheduler relance it and the job can retake
where it has stopped.
This is a differents steps how i was did :
In the first i have m y class scheduler:
Code:
@DisallowConcurrentExecution
public class JobLauncherDetails extends QuartzJobBean /*implements JobExecutionListener*/ {
private static final String JOB_DATA_MAP_MAX_RETRY = "maxRetry";
//private static final String JOB_DATA_MAP_NB_RETRIES = "nbRetries";
private final static String JOB_LOCATOR_CONTEXT_KEY = "jobLocator";
private final static String JOB_LAUNCHER_CONTEXT_KEY = "jobLauncher";
private static final String JOB_DATA_MAP_START_DATE = "startDate";
private static final String JOB_PARAM_LISTENER_DELAY_KEY = "listenerDelay";
private static final long JOB_PARAM_DEFAULT_LISTENER_DELAY = 1000;
private static Logger log = LoggerFactory.getLogger(JobLauncherDetails.class);
/**
* Special key in job data map for the name of a job to run.
*/
private static final String JOB_NAME = "jobName";
private JobLocator jobLocator;
private JobLauncher jobLauncher;
private String jobName;
private JobListener MyjobListener;
/**
* Method called by Quartz trigger. The given {@link JobExecutionContext}
* gives info on the Job to run.
*/
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
try {
jobLocator = (JobLocator) context.getScheduler().getContext().get(JOB_LOCATOR_CONTEXT_KEY);
jobLauncher = (JobLauncher) context.getScheduler().getContext().get(JOB_LAUNCHER_CONTEXT_KEY);
MyjobListener=(JobListener)context.getScheduler().getContext().get(MyjobListener);
} catch (SchedulerException se) {
log.error("Unable to get jobLocator and jobLauncher from scheduler context.", se);
}
if (jobLocator == null || jobLauncher == null) {
log.error("Unable to run a job without valids jobLocator and jobLauncher.");
} else {
JobDetail jobDetail = context.getJobDetail();
Map<String, Object> jobDataMap = context.getMergedJobDataMap();
if (jobDataMap == null || jobDataMap.size() == 0) {
log.error("Unable to run a job without a valid jobDataMap (no job name provided...).");
} else {
jobName = (String) jobDataMap.get(JOB_NAME);
if (jobName == null || jobName.isEmpty()) {
log.error("Unable to run a job: no job name provided...");
} else {
if(context.getRefireCount()==0) {
// Add a date to the jobDataMap so that the job is unique.
// It is useful to distinguish 2 instances of the same trigger.
// Otherwise, a JobExecutionAlreadyRunningException will be launched
// (no need to modify this parameter for a refired job)
jobDataMap.put(JOB_DATA_MAP_START_DATE, new Date());
}
JobParameters jobParameters = getJobParametersFromJobMap(jobDataMap);
Scheduler sched= context.getScheduler();
try {
sched.getListenerManager().addJobListener(new NcaJobListener());
} catch (SchedulerException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (log.isInfoEnabled())
log.info("\n**********************************************************************\n"
+ "* Quartz trigger - start job: {}. Key: {}\n"
+ "* Firing unique ID: {}\n"
+ "* Refire count: {}\n"
+ "* Job parameters: {}\n"
+ "* isConcurrentExectionDisallowed: {}\n"
+ "**********************************************************************\n",
new Object[] { jobName, jobDetail==null?"":jobDetail.getKey(), context.getFireInstanceId(),
context.getRefireCount(), jobParameters==null?"":jobParameters.toString(),
context.getJobDetail().isConcurrentExectionDisallowed() });
JobExecution jobExec = null;
BatchStatus jobStatus = BatchStatus.UNKNOWN;
try {
jobExec = jobLauncher.run(jobLocator.getJob(jobName), jobParameters);
log.info("Job Id: {}", jobExec.getId());
}
} catch (Exception ex) {
if(!(ex instanceof JobExecutionException)) {
log.error("Error while running Job [{}]. Rescheduling if possible.\nError: {}\n******************************", jobName, ex.toString());
// TODO: retirer ce log...
log.error("Error full stack:", ex);
} else {
throw (JobExecutionException) ex;
}
}
if (log.isInfoEnabled())
log.info("\n**********************************************************************\n"
+ "* Quartz trigger - end job: {}\n"
+ "* Firing unique ID: {}\n"
+ "* Refire count: {}\n"
+ "* Job parameters: {}\n"
+ "* Start date: {}\n"
+ "* End date: {}\n"
+ "* Status: {}\n"
+ "**********************************************************************\n",
new Object[] { jobName, context.getFireInstanceId(), context.getRefireCount(),
jobParameters==null?"":jobParameters.toString(),
jobExec==null?"":jobExec.getStartTime(),
jobExec==null?"":jobExec.getEndTime(),
jobStatus });
}
}
}
}
/**
* Copy parameters that are of the correct type over to
* {@link JobParameters}, ignoring jobName.
*
* @return a {@link JobParameters} instance
*/
private JobParameters getJobParametersFromJobMap(Map<String, Object> jobDataMap) {
JobParametersBuilder builder = new JobParametersBuilder();
for (Entry<String, Object> entry : jobDataMap.entrySet()) {
String key = entry.getKey();
Object value = entry.getValue();
if (value instanceof String && !key.equals(JOB_NAME)) {
builder.addString(key, (String) value);
} else if (value instanceof Float || value instanceof Double) {
builder.addDouble(key, ((Number) value).doubleValue());
} else if (value instanceof Integer || value instanceof Long) {
builder.addLong(key, ((Number) value).longValue());
} else if (value instanceof Date) {
builder.addDate(key, (Date) value);
} else {
log.debug("JobDataMap contains values which are not job parameters (ignoring).");
}
}
return builder.toJobParameters();
}
/*@Override
public void afterJob(JobExecution jobExecution) {
// TODO Auto-generated method stub
log.info("*************************** Job ended with status: {} ********************", jobExecution.getExitStatus());
if (ExitStatus.FAILED.equals(jobExecution.getExitStatus())) {
log.error("******************************\nJob [{}] failed. Reschedule if possible.\n******************************", jobName);
// rescheduleJob(jobExecution);
}
}
@Override
public void beforeJob(JobExecution jobExecution) {
log.info("************** Before running job {} **************", jobName);
}*/
}
-
In the second i have a class jobfaileur:
Code:
public class JobFailureListener implements JobExecutionListener {
private static Logger log = LoggerFactory.getLogger(JobFailureListener.class);
private static final String JOB_DATA_MAP_MAX_RETRY = "maxRetry";
private static final String JOB_NAME = "jobName";
private String jobName;
public void beforeJob(JobExecution jobExecution) {
// nothing to do
log.info("*************************** Job ended with status: {} ********************", jobExecution.getExitStatus());
}
public void afterJob(JobExecution jobExecution, JobExecutionContext context) throws JobExecutionException {
if( jobExecution.getStatus() == BatchStatus.COMPLETED ){
System.out.println("!!!!!!!!!!!!!!!!! sa marche !!!!!!!!!!!!!!!!");
}
else
if (!jobExecution.getAllFailureExceptions().isEmpty()) {
ExitStatus exitStatus = ExitStatus.FAILED;
log.error("******************************\nJob [{}] failed. Reschedule if possible.\n******************************");
//rescheduler if possible
rescheduleJob(jobExecution, context);
for (Throwable e : jobExecution.getAllFailureExceptions()) {
exitStatus = exitStatus.addExitDescription(e);
}
jobExecution.setExitStatus(exitStatus);
}
}
private void rescheduleJob(JobExecution jobExec, JobExecutionContext context) throws JobExecutionException {
rescheduleJob(jobExec, context, null);
}
private void rescheduleJob(JobExecution jobExec, JobExecutionContext context, Throwable excep) throws JobExecutionException {
// TODO: Gérer la politique de réessai, ex :
// http://stackoverflow.com/questions/4408858/quartz-retry-when-failure
if(jobExec == null)
throw new IllegalArgumentException("jobExec cannot be null.");
if(context == null)
throw new IllegalArgumentException("context cannot be null.");
String fireInstanceId = context.getFireInstanceId();
int refireCount = context.getRefireCount();
if (log.isInfoEnabled())
log.info("\n**********************************************************************\n"
+ "* Quartz trigger - rescheduling job: {}\n"
+ "* Firing unique ID: {}\n"
+ "* Refire count: {}\n"
+ "**********************************************************************\n",
new Object[] { jobName, fireInstanceId, refireCount});
JobDataMap dataMap = context.getJobDetail().getJobDataMap();
int maxRetry = dataMap.getIntValue(JOB_DATA_MAP_MAX_RETRY);
JobExecutionException jobExecutionException = null;
if(maxRetry>0 && refireCount<maxRetry) {
jobExecutionException = new JobExecutionException("Error: the job [" + jobName + "] didn't end properly, refire it immediately.", excep);
jobExecutionException.setRefireImmediately(true);
//boolean refireImmediatelyResult = jobExecutionException.refireImmediately();
log.info("************** Job Id: {} - rescheduled. ", jobExec.getId());
throw jobExecutionException;
} else {
//jobExecutionException = new JobExecutionException("Error: the job [" + jobName + "] didn't end properly. No more retry possible, sending alarm.", excep);
log.error("\n**********************************************************************\n"
+ "* Quartz trigger - No more retry possible for job: {}\n"
+ "* Firing unique ID: {}\n"
+ "* UNSCHEDULING TRIGGER + SENDING EXPLOIT ALARM...\n"
+ "**********************************************************************\n",
jobName, fireInstanceId);
AlarmDef alarmDef = AlarmExploit.searchBatchFailedAlarmDefByBatchName(jobName);
AlarmExploit.generateAlarmWithoutTemplate(alarmDef, "Batch failed", "The following batch failed (no more retry possible): " + jobName, Locale.ENGLISH.toString(), null);
}
}
@Override
public void afterJob(JobExecution jobExecution) {
// TODO Auto-generated method stub
}
}
I also add an sleep for my job and when i run i have a message who said that my job is finished or it's nnot there but juste sleep.
Please can i have a response, exemple or others suggestions , i need some one to help me please
Thanks a lot