Spring Batch : Job only to fire service - java

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
}
}

Related

Switch LDAP connection at runtime in Spring

I am new to spring. Admins of my spring based web app want to configure settings from the web interface, so users can authenticate against LDAP server with their company username and password.
Change in LDAP settings should be possible without restarting the application. This might happen during a 'migration' or whatever reason. I have a couple beans, which need to be refreshed after the admin saves new settings for the LDAP server:
<bean id="ldapServer" class="org.springframework.security.ldap.DefaultSpringSecurityContextSource">
<constructor-arg>
<list>
<value>${ldap.url1}</value>
...
</list>
</constructor-arg>
<constructor-arg value="${ldap.basedn}"</constructor-arg>
<property name="referral" value="${ldap.referral}" />
<property name="baseEnvironmentProperties">...</property>
<property name="userDn" value="${ldap.username}" />
<property name="password" value="${ldap.password}" />
</bean>
I am using Springframework 3.1.2. The problem is, there are constructor arguments, which I want to change and not affect other running jobs. I tried playing with Scoped proxy, but not to much success yet:
<bean id="ldapServer" scope="prototype" ...>
<aop:scoped-proxy/>
I was successful though to get ldapServer to reinstantiate, when using prototype scope by running this piece of code:
#Controller
public class LDAPSettingsController implements ApplicationContextAware {
public ModelAndView handleRequest(...) {
DefaultSpringSecurityContextSource ldap;
ldap = context.getParentBeanFactor().getBean("ldapServer");
System.out.println(ldap.hashCode());
return new ModelAndView(new RedirectView('login.jsp'));
}
...
}
Are scopes and proxies here the way to go, or is the another mechanism in Spring to reflect configuration changes into a running program instance?
UPDATE: Clear up the question.
UPDATE: The root problem with the AOP proxies was following root exception:
java.lang.IllegalArgumentException: Superclass has no null constructors but no arguments were given
What worked was adding proxy-target-class="false" attribute to the <aop:scoped-proxy/> tag. I created a new scope, which works better than prototype - It destroys beans on settings update. Now I have this in my beans.xml:
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
<property name="scopes">
<map>
<entry key="ldap">
<ref bean="ldapScope" />
</entry>
</map>
</property>
</bean>
<bean id="ldapScope" class="com.myapp.SettingsScope" />
<bean id="ldapServer" scope="ldap" ...>
<aop:scoped-proxy proxy-target-class="false"/>
<constructor-args>
<list><value>${ldap.url1}</value> .. </list>
</constructor-args>
...
</bean>
I also have a controller for LDAP settings into which I inject ldapScope and I call a method which destroys current life-cycle objects and starts a new life-cycle every time, user presses the apply button.
PS: Not sure if I handle the life-cycle "re-start" in the right way - people my way to look for auto-start beans and start them after such event happens (i.e.: Setting -> Apply)

Spring Quartz : Job does not fire

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.

Spring HTTP invoker waits one second before processing next request

I have set up an spring http invoker example as described here http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/remoting.html in section 20.4
If i do several service calls in a row (see my for-loop), between the single calls is one second though the server processes the method in less than 4ms.
Any ideas.
Stefan
Here the config and call:
<!-- server side -->
<bean name="configurationServiceExporter"
class="org.springframework.remoting.httpinvoker.SimpleHttpInvokerServiceExporter">
<property name="service" ref="configurationService" />
<property name="serviceInterface"
value="remote.service.ConfigurationService" />
</bean>
<bean id="httpServer"
class="org.springframework.remoting.support.SimpleHttpServerFactoryBean">
<property name="contexts">
<util:map>
<entry key="/remoting/ConfigurationService" value-ref="configurationServiceExporter" />
</util:map>
</property>
<property name="port" value="${port.httpinvoker}" />
</bean>
<!-- client side -->
<bean id="configurationServiceProxy" class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean">
<property name="serviceUrl"
value="http://localhost:7777/remoting/ConfigurationService" />
<property name="serviceInterface"
value="remote.service.ConfigurationService" />
</bean>
/** here the service call*/
#Component
public class ServiceConsumer {
private ConfigurationService configurationService;
public void do(){
for (int i = 0; i < 10; i++)
this.configurationService.getConfigurationValue(SMTP_HOST);
}
I just encountered the very same problem:
Spring Remoting
Delays of "exactly" 1 second
Java 7
Unfortunately, I was unable to find a reason for this odd behavior, but there exists a workaround: use jetty instead of the SimpleHttpServerFactoryBean.
This boils down to changing the xml configuration a little, how exactly is described here.
The delays disappeared; firing requests even seems to have sped up compared to using SimpleHttpServerFactoryBean in Java 6.
Found the Problem. It was not connected to Spring HTTP Invoker. I updated to Java 7. When i ran my app with Java 6 it works as before the update (without waiting one second between the requests. If i knew anything more, i come back.

Can we create multiple instances of a same java(spring) batch job?

I am using quartz to schedule a spring batch job.
The job reads a file from a folder( which has multiple files ) does some processing and copies it to another folder.
is it possible to create multiple instances of the job, that will run concurrenty,reading multiple files ?
My question is :
In spring batch, is it possible to spawn multiple instances of the same job? I am using quartz schedular ?
In Spring Batch it is possible to start several jobs, provided you have supplied different JobParameters for each jobLauncher.run() call. jobLauncher in your Spring configuration will spawn each job in a separate thread, if it is configured with appropriate task executor:
<bean id="jobLauncher" class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
<property name="jobRepository" ref="jobRepository" />
<property name="taskExecutor" ref="taskExecutor" />
</bean>
<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor"
p:corePoolSize="5"
p:maxPoolSize="30" />
It is possible with Quartz, using a MethodInvokingJobDetailFactoryBean, for instance:
<bean id="myjob"
class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject">
<ref bean="someBean" />
</property>
<property name="targetMethod" value="someMethod" />
<!-- The concurrent property is already true by default
<property name="concurrent" value="true" />
-->
</bean>
Citing the Spring documentation
By default, Quartz Jobs are stateless, resulting in the possibility of jobs interfering with each other. If you specify two triggers for the same JobDetail, it might be possible that before the first job has finished, the second one will start. If JobDetail classes implement the Stateful interface, this won't happen. The second job will not start before the first one has finished. To make jobs resulting from the MethodInvokingJobDetailFactoryBean non-concurrent, set the concurrent flag to false.

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