How to make fixed-rate dynamic in XML based task schedulers? - java

<task:scheduled-tasks>
<task:scheduled ref="testBean" method="testMethod" fixed-rate="1000"/>
</task:scheduled-tasks>
In the above snippet, I want to pass fixed-rate as variable fetched from the config file. How can I do that?
P.S. I don't want to move to the annotation-based scheduler.

After going through various articles and documentation I found a way to achieve the same. So sharing the same.
I created a configuration bean of a loader class. Loader class is responsbile to fetch the configs (either from file or any configuration management tool) and set in the system properties.
<bean id="configuration" class="com.test.config.loader">
</bean>
Say one the property is like
database:mysql
It can be accessed like
<task:scheduled-tasks>
<task:scheduled ref="testBean" method="testMethod" fixed-rate="#{configuration['database']}"/>
</task:scheduled-tasks>

Related

why spring task scheduler not executing task simultaneously?

I have following configuration to run task--
<bean id="trendDataJob" class="com.ge.og.realtrack.scheduler.TrendDataJob"> </bean>
<task:scheduled-tasks>
<task:scheduled ref="trendDataJob" method="trendJob" cron="#{trendDataJob.configMap['corn_exp']}"></task:scheduled>
<task:scheduled ref="trendDataJob" method="metaDataTrendJob" cron="#{trendDataJob.configMap['metadata_corn_exp']}"></task:scheduled>
</task:scheduled-tasks>
cron expression for this is corn_exp=0 0/1 * * * ? to run every minute.
Here is problem as both method of trendDataJob schedule to run every minute but they are executing one after another first trendJob once its completed then its executing metaDataTrendJob i am not able to understand this behavior .
Also another problem is in case of method takes more than one minute to finish finish..its not triggering next call till current call finish and return.
By default the scheduler uses a ConcurrentTaskScheduler with a single thread. If you want another one configure it and pass it to the scheduled-tasks scheduler attribute.
The easiest way, in XML, is to use the scheduler element. (See this section in the reference guide).
<task:scheduler id="scheduler" pool-size="10"/>
Then simply register it on the other element.
<task:scheduled-tasks scheduler="scheduler"> ...
Have you used #EnableScheduling in your java code?
#EnableScheduling ensures that a background task executor is created. Without it, nothing gets scheduled.
For more, you can go through
Spring 3 #Scheduled – 4 Ways to Schedule Tasks
Spring Batch + Spring TaskScheduler example
Scheduling Tasks
Enable scheduling annotations
To enable support for #Scheduled and #Async annotations add #EnableScheduling and #EnableAsync to one of your #Configuration classes:
#Configuration
#EnableAsync
#EnableScheduling
public class AppConfig {
}
You are free to pick and choose the relevant annotations for your application. For example, if you only need support for #Scheduled, simply omit #EnableAsync. For more fine-grained control you can additionally implement the SchedulingConfigurer and/or AsyncConfigurer interfaces. See the javadocs for full details.
If you prefer XML configuration use the <task:annotation-driven> element.
<task:annotation-driven executor="myExecutor" scheduler="myScheduler"/>
<task:executor id="myExecutor" pool-size="5"/>
<task:scheduler id="myScheduler" pool-size="10"/>
Notice with the above XML that an executor reference is provided for
handling those tasks that correspond to methods with the #Async
annotation, and the scheduler reference is provided for managing those
methods annotated with #Scheduled.
If you're using a default task scheduler in spring, i'm pretty sure it only runs on a single thread, hence why you cannot make them run in parallel.
You need to configure some kind of BatchScheduler with a pool size, to make it run in parallel.

Dynamically create multiple CronTriggerBean beans

How to dynamically create multiple CronTriggerBean beans.
My system currently uses a property file to get the times for running the job
For example:
SCHEDULE_TIME=09:30,10:55,17:35
Now, I will get these values and create cron expressions for them.
Now I want to create multiple CronTriggerBean beans with the cron expressions that I have with me.
How can I do it ?
<bean id="crontestJobTriggerTradeCheck"
class="frameworkx.springframework.scheduling.quartz.InitializingCronTrigger">
<property name="jobDetail">
<ref bean="tradeCheck" />
</property>
</bean>
try to create class like InitializingCronTrigger extends CronTriggerFactoryBean .Set CronExpression in InitializingCronTrigger .

Is there a way to start the file:inbound-channel-adapter through code?

I have a situation where a particular file is to be copied from a location to another. The polling is not required as the action will be deliberately triggered. Also the directory from which the file is to be picked up is decided at run time.
I can have a configuration as follows:
<int-file:inbound-channel-adapter id="filesIn" directory="#outPathBean.getPath()" channel="abc" filter="compositeFilter" >
<int:poller id="poller" fixed-delay="5000" />
</int-file:inbound-channel-adapter>
<int:channel id="abc"/>
<int-file:outbound-channel-adapter channel="abc" id="filesOut"
directory-expression="file:${paths.root}"
delete-source-files="true" filename-generator="fileNameGenerator" />
filenamegenerator and composite filter classes are configured as well.
I am new to spring. Please point me in the right direction!!
You can use a FireOnceTrigger as discussed in this answer and start/stop the adapter as needed.
To get a reference to the adapter (a SourcePollingChannelAdapter), inject (or #Autowire etc.) it as a Lifecycle bean (start()/stop() etc).
Or you can do the whole thing programmatically using a FileReadingMessageSource, and discussed in this answer.
Sample for start/stop Adapter.incase its useful.
SourcePollingChannelAdapter sourcePollingChannelAdapter = (SourcePollingChannelAdapter) context
.getBean("filesIn"); //adapter id in the bean configuration
// Stop
if (sourcePollingChannelAdapter.isRunning()) {
sourcePollingChannelAdapter.stop();
}
// Set Cron Expression if required when start or use any triggers
CronTrigger cronTrigger = new CronTrigger("* * * * * ?");
sourcePollingChannelAdapter.setTrigger(cronTrigger);
// Start
if (!sourcePollingChannelAdapter.isRunning()) {
sourcePollingChannelAdapter.start();
}

ternary operator in spring configuration file

I have a situation where I need to check the profile maven is running on and then according to that I need to configure task scheduler. There are two profiles one is 'global' and the other one is 'nonglobal', what I did is:
<task:scheduler id="customerPortalTaskScheduler" pool-size="1" />
<task:scheduled-tasks scheduler="customerPortalTaskScheduler">
<task:scheduled ref="SubscriptionService" method="updateNextDistributionDateForAllCurrentUsers" cron="${nhst.ncp.instance} == 'global' ? #{customerportal['globalUpdateDistributionDateServiceTuesday.CronTrigger']} : #{customerportal['updateDistributionDateServiceMondayThursday.CronTrigger']}" />
<task:scheduled ref="SubscriptionService" method="updateNextDistributionDateForAllCurrentUsers" cron="${nhst.ncp.instance} == 'global' ? #{customerportal['globalUpdateDistributionDateServiceWednesday.CronTrigger']} : #{customerportal['updateDistributionDateServiceFriday.CronTrigger']}" />
<task:scheduled ref="SubscriptionService" method="updateNextDistributionDateForAllCurrentUsers" cron="${nhst.ncp.instance} == 'global' ? #{customerportal['globalUpdateDistributionDateServiceThursday.CronTrigger']} : #{customerportal['updateDistributionDateServiceWeekend.CronTrigger']}" />
</task:scheduled-tasks>
${nhst.ncp.instance} is instance of maven profile. It would say whether its global or nonglobal profile. It does work fine, because properties file are being loaded properly.
With the above configuration, I am getting an error which is there in screenshot.
Any ideas how to solve this?
Do not depend on profile activated. Depend on local configuration file:
<context:property-placeholder ignore-resource-not-found="true" location="file:/etc/mumbojumbo/app.config.properties"/>
in /etc/mumbojumbo/app.config.properties
cron.schedule = blabla
You can always provide a sensible default value. So you only have to override it where you want.
<task:scheduled ref="SubscriptionService" method="updateNextDistributionDateForAllCurrentUsers" cron="${cron.schedule:defaultvalue}" />
Something like that?

How to register handler interceptors with spring mvc 3.0?

It should be easy:
<bean id="handlerMapping"
class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="interceptors">
<list>
<ref bean="myInterceptor" />
</list>
</property>
</bean>
but this way the interceptor isn't called.
By default, Spring will register a BeanNameUrlHandlerMapping, and a DefaultAnnotationHandlerMapping, without any explicit config required.
If you define your own HandlerMapping beans, then the default ones will not be registered, and you'll just get the explicitly declared ones.
So far, so good.
The problem comes when you add <mvc:annotation-driven/> to the mix. This also declares its own DefaultAnnotationHandlerMapping, which replaces the defaults. However, if you also declare your own one, then you end up with two. Since they are consulted in order of declaration, this usually means the one registered by <mvc:annotation-driven/> gets called first, and your own one gets ignored.
It would be better if the DefaultAnnotationHandlerMapping registered by <mvc:annotation-driven/> acted like the default one, i.e. if explicitly declared ones took precedence, but that's not the way they wrote it.
My current preference is to not use <mvc:annotation-driven/> at all, it's too confusing, and too unpredictable when mixed with other config options. It doesn't really do anything especially complex, it's not difficult or verbose to explicitly add the stuff that it does for you, and the end result is easier to follow.
Problem I faced: Spring MVC tag doesn't go well with custom definition of DefaultAnnotationHandlerMapping.
Why..? the reason is very well explained in the answers above.
Why i wanted to use DefaultAnnotationHandlerMapping? I want to define an interceptor for my every request. a Spring-Mobile interceptor to determine the USER AGENT..mobile or a browser?
Now Due to this clash of mvc-annotation and DefaultAnnotationHandlerMapping, I cant use DefaultAnnotationHandlerMapping anymore.
The problem comes down to how can i register my interceptors with tag.
The solution was simple...but hard to find. Posting it so it can be helpful to the other solution seekers..
Use tag and register the interceptor bean in your dispathcer-servlet.xml
example :
<mvc:interceptors>
<!-- This runs for all mappings -->
<bean class="main.com.XXX.MobileDeviceResolverHanlderInterceptor"/>
</mvc:interceptors>
The reason for this behaviour is that two beans of type org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping exist in the application context. Spring resolves the two, but asks only the first for interceptors. To fix this, the following init parameter should be set to the DispatcherServlet
<init-param>
<param-name>detectAllHandlerMappings</param-name>
<param-value>false</param-value>
</init-param>
This makes the dispatcher servlet use only the handlerMapping defined in the x-servlet.xml
It is beyond me why this is the default behaviour. I'm expecting an answer from the spring community.
In my case I can NOT get rid of <mvc:annotation-driven/> as I am using jackson for json support using annotation.
What I tried, moved my all interceptors <mvc:interceptors> in separate "xml" file (interceptor-config.xml) and imported it from my x-dispatcher-servlet.xml
<import resource="interceptor-config.xml"/>
It solve my issue and avoid default 'DefaultAnnotationHandlerMapping' beans my application context.
Rather than creating separate 'xml', you can copy/paste interceptor contents directly in 'x-dispatcher-servlet.xml'.
Following is my interceptor:
<mvc:interceptors>
<mvc:interceptor>
<!-- Intercepting specific URL -->
<mvc:mapping path="/abc/**" />
<bean id= "myInterceptor"
class="xx.xxx.xxx.MyInterceptor" />
</mvc:interceptor>
<mvc:interceptors>
In Spring MVC 3.0 you can use <mvc:interceptors> instead of manual defining the handler mapping.

Categories