Okt
13
2009
Frank
Yesterday I wrote how to define Quartz-Jobs in JBoss AS. Generally such jobs try to use business logic, which is injected via @EJB. Currently in Version 5.1.0.GA this is not possible if you use the classloader-isolation. You will get the following (or similar) exception:
1
2
3
4
5
6
7
8
9
| Caused by: java.lang.RuntimeException: Can not find interface declared by Proxy in our CL + BaseClassLoader@92c904{vfsfile:...}
at org.jboss.ejb3.proxy.impl.objectfactory.ProxyObjectFactory.redefineProxyInTcl(ProxyObjectFactory.java:343)
at org.jboss.ejb3.proxy.impl.objectfactory.session.SessionProxyObjectFactory.createProxy(SessionProxyObjectFactory.java:134)
at org.jboss.ejb3.proxy.impl.objectfactory.session.stateless.StatelessSessionProxyObjectFactory.getProxy(StatelessSessionProxyObjectFactory.java:79)
at org.jboss.ejb3.proxy.impl.objectfactory.ProxyObjectFactory.getObjectInstance(ProxyObjectFactory.java:158)
at javax.naming.spi.NamingManager.getObjectInstance(NamingManager.java:304)
at org.jnp.interfaces.NamingContext.getObjectInstance(NamingContext.java:1479)
at org.jnp.interfaces.NamingContext.getObjectInstanceWrapFailure(NamingContext.java:1496)
... 39 more |
The reason for this ist that the Quartz-Service has another classloader as your application and the started job contains to the classloader of the Quartz-Service. There is also a bug posted. Maybe this will be possible in the near future.
One solution is to call a MBean from the job and this MBean injects the business logic via @EJB. The advantage of this solution is that you also can control and monitor the cronjob itselfs and can run the logic on demand via JMX-Console.
An example job would look like:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| @MessageDriven(messageListenerInterface = StatefulJob.class, activationConfig = { @ActivationConfigProperty(propertyName = "cronTrigger", propertyValue = "0 0 0 ? * MON-SAT") })
@ResourceAdapter("quartz-ra.rar")
@Depends(ImportDataManagement.ID)
public class DailyUpdateJob implements StatefulJob {
private static final Logger log = Logger
.getLogger(DailyUpdateJob.class);
public void execute(JobExecutionContext context)
throws JobExecutionException {
try {
MBeanServer server = MBeanServerLocator.locate();
ImportDataManagement bp = (ImportDataManagement) MBeanProxyExt
.create(ImportDataManagement.class,
ImportDataManagement.ID, server);
bp.importDaily();
} catch (Exception e) {
log.error("run", e);
}
}
} |
Helpful links:
no comments | tags: classloader, cronjobs, ejb, Java, JBoss, quartz | posted in JBoss
Okt
12
2009
Frank
With the introduction of EJB3 a new method for implementing cronjobs was added. These jobs uses quartz as framework and there are two ways to setup:
1. Variant: Defining a MDB-Consumer
The preferred way is the definition of an MDB-Consumer. The only thing you need is to implement the Job-Interface (org.quartz.Job) and add some Annotations to it:
1
2
3
4
5
6
7
8
9
| @MessageDriven(activationConfig = { @ActivationConfigProperty(propertyName = "cronTrigger", propertyValue = "0/2 * * * * ?") })
@ResourceAdapter("quartz-ra.rar")
public class MySampleCronJob implements Job {
public void execute(JobExecutionContext context) throws JobExecutionException {
System.out.println("job is called");
}
} |
If this job should only be called once at a specific time, you can use the interface StatefulJob. When the job is called is defined in the property cronTrigger. A full documentation can be found at the Quartz-API-Documentation.
Pay attention that the Component only implements one interface or you have to define the property “messageListenerInterface” at @MessageDriven. Otherwise the deployer cannot find the using type. Especially if you use AspectJ this is important.
2. Variant: Using a Quartz-Service
This is the old version. You can define a managed-bean via an XML which instantiate a Quartz-Service.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| < ?xml version="1.0" encoding="UTF-8"?>
<server>
<mbean code="org.quartz.ee.jmx.jboss.QuartzService" name="user:service=QuartzService,name=QuartzService">
<attribute name="Properties">
org.quartz.scheduler.instanceName = DefaultQuartzScheduler
org.quartz.scheduler.rmi.export = false
org.quartz.scheduler.rmi.proxy = false
org.quartz.scheduler.xaTransacted = false
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 5
org.quartz.threadPool.threadPriority = 4
</attribute>
</mbean>
</server> |
Then you can use this managed bean to add a new trigger and to assign a job to this trigger. This code can be used in an own managed bean, which setups the application.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
| public class CronManagementBean {
@Resource(mappedName = "/Quartz")
private Scheduler scheduler;
public void start() {
try {
Trigger trigger = new CronTrigger("myTrigger",
"mygroup",
"0 0 4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23 ? * *");
JobDetail jobDetail = new JobDetail("myJob",
"myjobgroup", StatusJob.class);
scheduler.scheduleJob(jobDetail, trigger);
} catch (SchedulerException e) {
throw new RuntimeException(e);
} catch (ParseException e) {
throw new RuntimeException(e);
}
}
public void stop() {
try {
scheduler.deleteJob("myJob", "myjobgroup");
} catch (SchedulerException e) {
log.warn("shutdown fails", e);
}
}
} |
1 comment | tags: cronjobs, Java, JBoss, quartz | posted in JBoss