And one of me
Two threads so bare, you’d hardly see.
–
Two steps entwine, two ryhmes sublime
As yours are mine, your eyes divine
–
Friends, I’m sure, of which I’m certain
Cannot draw the final curtain
The Spring Application Framework ships with helper classes to make configuring OpenSymphony’s quartz scheduler a breeze. The scheduler allows (amongst other things) cron style triggers. At the time of writing, the latest version of Quartz is 1.6.3, but I’ll be using 1.6.0 as this is the latest version in the Maven central repos.
First, download the version you wish to use and add as a dependency to your project. In Maven‘s case, add this to the pom.xml:
<dependency> <groupId>opensymphony</groupId> <artifactId>quartz</artifactId> <version>1.6.0</version> </dependency>
Now, create your task which extends org.springframework.scheduling.quartz.QuartzJobBean and implement public void executeInternal(JobExecutionContext context) throws JobExecutionException. You can inject any necessary beans too (myService in this example).
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.scheduling.quartz.QuartzJobBean;
public class myTask extends QuartzJobBean {
private MyService myService;
public void setMyService(MyService myService) {
this.myService = myService;
}
public void executeInternal(JobExecutionContext context) throws JobExecutionException {
Actual Business Logic
}
}
Create a schedulingContext-timer.xml to keep the scheudling configuration seperate and place in the WEB-INF folder of your Spring webapp. These settings could also go in the applicationContext.xml if you prefer but I like to keep the configuration seperate.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<!-- Job details -->
<bean id="myTask" class="org.springframework.scheduling.quartz.JobDetailBean">
<property name="jobClass" value="com.mycompany.project.scheduling.MyTask"/>
<property name="jobDataAsMap">
<map>
<entry key="myService" value-ref="myServiceBean"/>
</map>
</property>
</bean>
<!-- Cron -->
<bean id="myTaskCronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail" ref="myTask"/>
<property name="cronExpression" value="0 0/5 * * * ?"/>
</bean>
<!-- Kicker -->
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="myTaskCronTrigger"/>
</list>
</property>
</bean>
</beans>
A couple of notes:
And that’s all… your webapp now has full Cron capabilities! Enjoy
I noticed a newer version of log4j (1.2.15) and figured I’d upgrade in our maven projects.
My advice is to avoid it… some unnecessary dependencies are forced so you end up with lots of extra jars. Hope they fix it soon.
Just a quick one. I currently have several projects which all rely on 1 project as a global library so the same jar versions are used across the board.
This was working fine until 6.5RC1 came along. NetBeans would seemingly randomly create a CopyLibs folder with a copylibtask.jar within my library project. Not accidentally committing this to SVN has been a pain.
Seems it’s all down to using the embedded ant. Since I’ve changed this to use the external ant, the problem has disappeared (so far! – will update this if it reoccurs).
Fix:
Tools -> Options -> Miscellaneous -> Ant -> Change Ant Home to point to an external ant (preferably 1.7.1)
After a good couple of days spent converting ant projects over to maven, here is what I consider the easiest method. This is using NetBeans 6.5rc1 but probably works in 6.1.
Here are the steps for converting an ant project to a maven project in NetBeans.
This presumes your ~/.m2/settings.xml is already set up (not shown here for security purposes) and you have installed the Netbeans maven2 plugin:
1. Open ant project
2. Create new maven project using the “Maven Quickstart Archetype”
3. Properties -> Sources -> Change to 1.6
4. pom.xml -> Add distribution management
<distributionManagement>
<repository>
<id>nexus</id>
<name>Internal Releases</name>
<url>YourInternalReleaseURL</url>
</repository>
</distributionManagement>
5. Files tab -> src/main -> add folder “resources”. This will create an “Other Sources/resources” entry in the project view
6. Delete existing source and test package stubs
7. Copy java sources and test sources across from ant project
8. Move all config xml files (such as applicationContext.xml) over to “Other Sources/resources”
9. If you have any hibernate .hbm.xml files, create a folder structure under “Other Sources/resources” identical to the package structure, and copy the files to there
10. Resolve dependencies. The easiest way to do this is go through red-underlined classes, copy the missing required classname, right-click the libraries node and hit “Find Dependency”
11. If a dependency is purely for a test class, add “<scope>test</scope>” to reduce the resulting jar filesize
12. mvn install or deploy
If the ant project exposes a WebService:
1. Add the following plugin to the pom.xml:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jaxws-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>wsimport</goal>
</goals>
<configuration>
<wsdlUrls>
<wsdlUrl>yourWSDLExposedUrl</wsdlUrl>
</wsdlUrls>
<packageName>yourWSClientPackageName</packageName>
<sourceDestDir>${basedir}/src/main/java</sourceDestDir>
</configuration>
</execution>
</executions>
</plugin>
2. Change the wsdl location and packageName as necessary. Without the sourceDestDir, the generated sources live under target/ and code completion won’t work. Setting the package name to the same package as the ws-client solves this. Compilation works either way.
As used by Hibernate, ehcache is a great little caching implementation which ought to be part of every Java coders arsenal. Although its complexities may seem overwhelming, it’s very easy to use as a simple caching solution.
In my situation, I needed to prevent db hits when validating codes (ie seeing if they already exist in the db). This is how easy it is to set up.
applicationContext.xml:
<bean id="myDao" class="myDaoImpl" init-method="setupCache"> <property name="cacheManager" ref="cacheManager"> </bean>
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"> <property name="configLocation" value="classpath:ehcache.xml" /> </bean>
ehcache.xml:
<ehcache> <diskStore path="java.io.tmpdir"/> <cache name="myCacheName" maxElementsInMemory="1000" eternal="true" overflowToDisk="false"/> <defaultCache maxElementsInMemory="300" maxElementsOnDisk="1000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true"/> </ehcache>
myDaoImpl.java:
import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Element;
public class {
private CacheManager cacheManager;
private Cache myCache = null;
public void setCacheManager(CacheManager cacheManager) {
this.cacheManager = cacheManager;
}
private void setupCache() {
String cacheName = "myCacheName";
logger.debug("Fetching cache [" + cacheName + "]");
myCache = cacheManager.getCache(cacheName);
}
}
ehcache.xml needs to be put alongside applicationContext.xml (especially in the case of jar packaging). If you’re packaging a war, you can place it anywhere on the classpath and don’t need to specify the configLocation (it’s the default config name).
To use the cache, do something like this:
Element cachedObject = myCache.get(key);
if (cachedObject != null) {
return cachedObject;
} else {
fetch object from db
// add to cache
myCache.put(new Element(key, object))
return object;
}
And that's it!
Now you’ll only hit the db when needed. Of course, it’s worth reading the reference material to see the many ways you can configure the cache. My example is purely for a 1000 object permanent memory cache, but TTL and overflow-to-disk (for example) is just as easy to set up.
Earlier today, we noticed one the maven war files was being bundled with the geronimo-spec-javamail.jar. Unfortunately, the other projects use the standard java mail.jar. The presence of 2 seperate mail jars under the same tomcat instance has been causing us mime-type conflicts.
Hot-deploying worked though so we figured it was something to do with bundled jars.
In NetBeans, the geronimo jar appeared greyed out in the list of libraries, indicating a transitive dependency. How to work out which jar is at the root of this dependency?
The plugin is still in beta, but it saved me lots of time so I would recommend it.
Update:
Unfortunately, this plugin was available in 6.5Beta but not in 6.5RC1. Hopefully it’ll make a comeback soon.
And first, a little something:
Two threads so bare, you’d hardly see.
–
Two steps entwine, two ryhmes sublime
As yours are mine, your eyes divine
–
Friends, I’m sure, of which I’m certain
Cannot draw the final curtain