Spring Quartz : Job does not fire - java

I am using Quartz 2 and Spring 3.0
I want to use SchedulerFactoryBean but my Job is not getting fired.
Below is my XML file
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="quartzScheduler"
class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="autoStartup" value="true"/>
<property name="schedulerName" value="PCLoaderScheduler"/>
</bean>
</beans>
My code is below:
#Component
public class PCSchedulerManager {
#Autowired
private Scheduler scheduler;
public void scheduleJob(final Map<String, Object> parameters, Class inputClass) throws PCSchedulerException {
try {
long currentTimeStamp = System.currentTimeMillis();
JobDetail job = JobBuilder
.newJob(inputClass)
.withIdentity(inputClass.getName() + currentTimeStamp)
.build();
job.getJobDataMap().putAll(parameters);
Trigger trigger = TriggerBuilder
.newTrigger()
.withIdentity(inputClass.getName() + currentTimeStamp)
.build();
//Schedule a job with JobDetail and Trigger
scheduler.scheduleJob(job, trigger);
} catch (SchedulerException e) {
throw new PCSchedulerException(e);
}
}
}
Please refer the Job I am trying to execute
public class LoaderJob implements Job {
public void execute(JobExecutionContext jec) throws JobExecutionException {
System.out.println("Do your stuff here...");
}
}
I know that the scheduler is getting started when the server starts. But It does not run my Job.
Also, If I use, the below statement instead of Autowiring the Spring Quartz scheduler, then the job is getting fired successfully
scheduler = new StdSchedulerFactory().getScheduler();
scheduler.start();
Please let me know what am I doing wrong...

Do you need to inject dependencies into the job? Then implement QuartzJobBean
and override executeInternal() method.
Also please check If you are getting any exception while job execution.

Quartz 2 and Spring 3.0 are incompatible. Updated Spring to 3.1. Now it works fine

First, go ahead and add something like this to your configuration xml file. Notice how you can change the repeatInterval and startDelay properties. Alternatively, you can use cron expressions as well. Read about them from this link.
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="cronTrgTest" />
</list>
</property>
</bean>
<bean id="cronTrgTest" class="org.springframework.scheduling.quartz.SimpleTriggerBean">
<property name="jobDetail" ref="testJob" />
<property name="repeatInterval" value="5000" />
<property name="startDelay" value="1000" />
</bean>
<bean id="testJob" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="cronTest" />
<property name="targetMethod" value="test" />
</bean>
<bean id="cronTest" class="com.mustafaergin.ws.cron.CronTest">
</bean>
Then implement the target POJO and you are done.
public class CronTest {
public void test() {
System.out.println("TEST");
}
}
You can find the original article I wrote a while ago here.

Related

Jms message failure with Retry advice send response to fail channel and again pass to successful channel

Below is the config
<jms:outbound-channel-adapter id="someId" channel="inputChannel"
connection-factory="${connection.factory}" destination="queue">
<jms:request-handler-advice-chain>
<bean class="org.springframework.integration.handler.advice.ExpressionEvaluatingRequestHandlerAdvice">
<property name="onSuccessExpression" value="T(Boolean).TRUE"/>
<property name="successChannelName" value="afterSuccessDeliveryMessageChannel"/>
<property name="onFailureExpression" value="T(Boolean).FALSE"/>
<property name="failureChannelName" value="failureChannel"/>
</bean>
<bean id="retryWithBackoffAdviceSession"
class="org.springframework.integration.handler.advice.RequestHandlerRetryAdvice">
<property name="retryTemplate">
<bean class="org.springframework.retry.support.RetryTemplate">
<property name="retryPolicy">
<bean class="org.springframework.retry.policy.SimpleRetryPolicy">
<property name="maxAttempts" value="5"/>
</bean>
</property>
</bean>
</property>
<property name="recoveryCallback">
<bean class="org.springframework.integration.handler.advice.ErrorMessageSendingRecoverer">
<constructor-arg ref="failureChannel"/>
</bean>
</property>
</bean>
</jms:request-handler-advice-chain>
</jms:outbound-channel-adapter>
I am retrying message 5 times and then using recoveryCallBack logging message to some DB.
It works fine retry 5 times and call failureChannel channel but once it calls the failureChannel then again it pass to afterSuccessDeliveryMessageChannel.
I am not sure what I am doing wrong here?
I am expecting once it failed it should go failedChannel NOT again back to afterSuccessDeliveryMessageChannel.
Your problem is like this:
Your Retry advice sends to the failureChannel from the recoveryCallback and exits, successfully.
Then when we look into the ExpressionEvaluatingRequestHandlerAdvice code, we see this logic:
try {
Object result = callback.execute();
if (this.onSuccessExpression != null) {
evaluateSuccessExpression(message);
}
return result;
}
So, since there is no exception calling callback, it goes to the successChannel configured.
To make it fail and go to the failureChannel configured, you should consider to not use that recoveryCallback. Then RequestHandlerRetryAdvice will throw an exception which is going to be caught by the ExpressionEvaluatingRequestHandlerAdvice and sent to that failureChannel. There won't be onSuccessExpression evaluation since we will end up with an exception.

JMS CachingConnectionFactory onException method is never called on JMSException

I am using Apache Camel with Spring to send messages from my Java service. I need to reset JMS connection in case of any error occurred at exchange. I am using below code to achieve my objective.
try
{
producerTemplate.sendBody(endPoint, bytes);
}
catch (final RuntimeCamelException exception)
{
LOGGER.error("Exception occured in sendBody", exception.getMessage(), exception);
handleError(); // handle error here.
}
In camel context, I have defined CachingConnectionFactory with exception listener and made reconnectOnException=true
<bean id="testConnectionFactory" class="org.apache.qpid.jms.JmsConnectionFactory">
<property name="username" value="${user.name}" />
<property name="password" value="${user.password}" />
<property name="clientID" value="${host.address}" />
<property name="remoteURI"
value="amqp://${host.address}:${host.port}?jms.clientID=${host.address}?jms.username=${user.name}&jms.password=${user.password}&jms.redeliveryPolicy.maxRedeliveries=${message.retry.count}&amqp.saslMechanisms=PLAIN" />
</bean>
<bean id="testCachingConnectionFactory"
class="org.springframework.jms.connection.CachingConnectionFactory">
<property name="exceptionListener" ref="testCachingConnectionFactory" />
<property name="targetConnectionFactory" ref="testConnectionFactory" />
<property name="reconnectOnException" value="true" />
</bean>
In my case, JMSSecurityException is thrown from try block at below line
producerTemplate.sendBody(endPoint, bytes)
execution goes inside catch block but OnException() of SingleConnectionFactory is never called even though exceptionListener is defined. The idea is to call ultimately resetConnection() (inside OnException) to reset JMS connection.
Implement ExceptionListenerand add the exception listener definition as a property to your spring connection factory testCachingConnectionFactory.
For example create an exception listener class (component) JmsExceptionListener:
public class JmsExceptionListener implements ExceptionListener {
#Override
public void onException(JMSException exception) {
// what ever you wanna do here!
}
}
Then add a bean definition for JmsExceptionListener:
<bean id="jmsExceptionListener" class="JmsExceptionListener"></bean>
And then add the definition as an exception-listener property:
<property name="exceptionListener" ref="jmsExceptionListener"/>
instead of what you are using in your configuration:
<property name="exceptionListener" ref="testCachingConnectionFactory" />

JMX with spring without XML configuration, 100% annotation based?

I am using JMX in Spring application with XML configuration:
<bean id="jmxExporter" class="org.springframework.jmx.export.MBeanExporter">
<property name="beans">
<map>
<entry key="bean:name=bean1" value-ref="bean1"/>
<entry key="bean:name=bean2" value-ref="bean2"/>
<entry key="bean:name=bean3" value-ref="bean3"/>
</map>
</property>
<property name="notificationListenerMappings">
<map>
<entry key="*">
<bean class="com.test.listener"/>
</entry>
</map>
</property>
</bean>
<bean id="registry" class="org.springframework.remoting.rmi.RmiRegistryFactoryBean">
<property name="port" value="1099" />
</bean>
<bean id="serverConnector"
class="org.springframework.jmx.support.ConnectorServerFactoryBean">
<property name="objectName" value="connector:name=rmi" />
<property name="serviceUrl"
value="service:jmx:rmi://localhost/jndi/rmi://localhost:1099/jmxrmi" />
</bean>
I understand from various documents like instead of this XML configuration we could annotate it with #EnableMBeanExport and with #ManagedResource for the beans.
But i doubt how ConnectorServerFactoryBean gets configured with these annotations. Or is there any annotation available to configure RMI and connectorServerFactoryBean?
Also i need to know how to annotate, notificationListenerMappings configured?
P.S:
I have the code working for publisher and listener under XML configuration. I am planning to move it completely on annotation based as i do not want to disturb XML configuration already in PROD.
Edited
Found the following piece of code: planning to try it:
#Bean
public RmiRegistryFactoryBean registry() {
return new RmiRegistryFactoryBean();
}
#Bean
#DependsOn("registry")
public ConnectorServerFactoryBean connectorServer() throws MalformedObjectNameException {
ConnectorServerFactoryBean connectorServerFactoryBean = new ConnectorServerFactoryBean();
connectorServerFactoryBean.setObjectName("connector:name=rmi");
connectorServerFactoryBean.setServiceUrl("service:jmx:rmi://localhost/jndi/rmi://localhost:1099/connector");
return connectorServerFactoryBean;
}
Edit 2:
I am proceeding on above mentioned approach and I am able to configure MBeans and able to publish notifications. But unfortunately I am stuck up with configuring NotificationListener through Annotation.
I tried adding the following:
#Bean
#DependsOn("registry")
public ConnectorServerFactoryBean connectorServer() throws MalformedObjectNameException {
ConnectorServerFactoryBean connectorServerFactoryBean = new ConnectorServerFactoryBean();
connectorServerFactoryBean.setObjectName("connector:name=rmi");
connectorServerFactoryBean.setServiceUrl("service:jmx:rmi://localhost/jndi/rmi://localhost:1099/connector");
//TestListener is my NotificationListener class
ObjectName objectName = new ObjectName("bean:name=bean1");
connectorServerFactoryBean.getServer().addNotificationListener(objectName,
new TestListener(), null,null);
return connectorServerFactoryBean;
}
I am getting instanceNotFoundException stating bean:name=bean1 is not found. But I have configured like, #ManagedResource(objectName="bean:name=bean1") on my bean1.
Any help please on what i am missing?
#EnableMBeanExport has a server property, which reference the bean name of a server object.
see for example the test of this component, which use this server property : https://github.com/spring-projects/spring-framework/blob/master/spring-context/src/test/java/org/springframework/jmx/export/annotation/EnableMBeanExportConfigurationTests.java

Spring Batch : Job only to fire service

I currently have multiple Quartz pollers that check a multiple flags in the database and fire a service if flags are true and I also have one spring batch project reading files, then calling a service to update the information accordingly.
What i am wondering is if it is possible to get the spring batch application to only call a service very 5 minutes (dont check for any information just call a service which will handle all the business logic) so that i can remove the Quartz jobs from my application all my jobs are in one place (spring batch project)?
If so can any point me in the right direction on how to do this as i cannot find anything online to just set up a spring batch job just to fire a service?
You can simply schedule a Quartz job and call your service from executeInternal method of your schedular class. You will not be able to autowire your service directly in schedular class, so you need to set it using jobDataas Map.
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<bean id="cronTriggerCache"
class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail" ref="exampleJob" />
<property name="cronExpression" value="your cron expression" />
</bean>
</list>
</bean>
<bean name="exampleJob" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
<property name="jobClass" value="example.ExampleJob"/>
<property name="jobDataAsMap">
<map>
<entry key="myService" ref="myService"/>
</map>
</property>
</bean>
package example;
public class ExampleJob extends QuartzJobBean {
private myService myService;
/**
* have getter setter for you service
*
*/
protected void executeInternal(JobExecutionContext ctx) throws JobExecutionException {
// do the actual work
//call your service method here
}
}

Spring beans loaded multiple times

I am writing Apache CXF web services and use Spring for loading my beans. My only bean is calling external process (MATLAB) from Java. My beans definition looks as below:
<bean id="matlabEngine" class="org.burch.pca.matlab.MatlabEngine"
init-method="start" scope="singleton">
<constructor-arg value="${matlab.engine.path}"></constructor-arg>
</bean>
<bean
class="org.springframework.web.context.support.ServletContextPropertyPlaceholderConfigurer">
<property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
<property name="searchContextAttributes" value="true" />
<property name="contextOverride" value="true" />
<property name="ignoreResourceNotFound" value="true" />
<property name="locations">
<list>
<value>classpath:/pca-engine.properties</value>
</list>
</property>
</bean>
Piece of my MatlabEngine bean is as below:
/**
* Path to MATLAB engine.
*/
private String pathToEngine;
public MatlabEngine(String pathToEngine) throws MatlabConnectionException, MatlabInvocationException{
super();
setPathToEngine(pathToEngine);
}
/**
* Starts engine and goes to path defined by argument
* #param pathToEngine
* #throws MatlabConnectionException
* #throws MatlabInvocationException
*/
public void start() throws MatlabConnectionException, MatlabInvocationException{
//Create a factory
RemoteMatlabProxyFactory factory = new RemoteMatlabProxyFactory();
//Get a proxy, launching MATLAB in the process
proxy = factory.getProxy();
//Display welcoming messages in MATLAB Command Window
proxy.eval(MatlabCommandsRegistry.disp(MATLAB_ENGINE_WELCOME_1));
proxy.eval(MatlabCommandsRegistry.disp(MATLAB_ENGINE_WELCOME_2));
if(pathToEngine!= null && !"".equals(pathToEngine)){
logM("Switching to engine directory...");
String goToEngineRootDir = MatlabCommandsRegistry.cd(pathToEngine);
proxy.eval(goToEngineRootDir);
logM("Sucessfully changed engine dir to "+pathToEngine);
}
}
When I deploy web services in Tomcat, it brings up MATLAB process nicely (bean gets loaded).
However, when I create client request to web service endpoint with this code:
public static void main(String args[]) throws Exception {
JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
factory.getInInterceptors().add(new LoggingInInterceptor());
factory.getOutInterceptors().add(new LoggingOutInterceptor());
factory.setServiceClass(UploadService.class);
factory.setAddress("http://localhost:8080/auth-ws-1.0.0/services/upload");
UploadService client = (UploadService) factory.create();
UploadEntity resume=new UploadEntity();
resume.setFileName("Image490");
resume.setFileType("jpg");
//Work arround data handler....
DataSource source = new FileDataSource(new File("C:\\Users\\Pictures\\thumb.png"));
DataHandler dataHandle = new DataHandler(source);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
dataHandle.writeTo(stream);
resume.setPayload(stream.toByteArray());
client.uploadFile(resume);
System.exit(0);
}
my server brings out new instance of MATLAB process (bean gets loaded again - very heavy and undesirable). What could I do to have only one bean which will be used to serve all processing and all requests? I am new to Spring, and I am thinking that my problem is that I am dealing with multiple contexts here. I want them to share a single instance of a singleton bean but don't know how to manage this.
Thank you for your time!
You should enable singleton mode for you bean.
Look at this: http://static.springsource.org/spring/docs/1.2.x/reference/beans.html#beans-factory-modes
Bean defenition may looks like this:
<!-- Spring property loading bean -->
<bean
class="org.springframework.web.context.support.ServletContextPropertyPlaceholderConfigurer" singleton="true">
<property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
<property name="searchContextAttributes" value="true" />
<property name="contextOverride" value="true" />
<property name="ignoreResourceNotFound" value="true" />
<property name="locations">
<list>
<value>classpath:/pca-engine.properties</value>
</list>
</property>
</bean>
I think you should manage MATLAB process lifecircle wisely to decrease resource loading.

Categories

Resources