Author: rmannibucau
Date: Sat Aug 11 12:33:43 2012
New Revision: 1371929
URL: http://svn.apache.org/viewvc?rev=1371929&view=rev
Log:
better management of quartz related object serialization + custom persister for
our ejbcrontrigger
Added:
openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/core/timer/EJBCronTriggerPersistenceDelegate.java
Modified:
openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/core/timer/EJBCronTrigger.java
openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/core/timer/EjbTimerServiceImpl.java
Modified:
openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/core/timer/EJBCronTrigger.java
URL:
http://svn.apache.org/viewvc/openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/core/timer/EJBCronTrigger.java?rev=1371929&r1=1371928&r2=1371929&view=diff
==============================================================================
---
openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/core/timer/EJBCronTrigger.java
(original)
+++
openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/core/timer/EJBCronTrigger.java
Sat Aug 11 12:33:43 2012
@@ -58,15 +58,17 @@ public class EJBCronTrigger extends Cron
private static final Pattern VALID_HOUR =
Pattern.compile("(([0-1]?[0-9])|([2][0-3]))|\\*");
private static final Pattern VALID_MINUTE =
Pattern.compile("([0-5]?[0-9])|\\*");
private static final Pattern VALID_SECOND =
Pattern.compile("([0-5]?[0-9])|\\*");
-
+
private static final Pattern RANGE =
Pattern.compile("(-?[A-Za-z0-9]+)-(-?[A-Za-z0-9]+)");
+ public static final String DELIMITER = ";";
private static final String LAST_IDENTIFIER = "LAST";
-
- private static final Map<String, Integer> MONTHS_MAP = new HashMap<String,
Integer>();
+
private static final Map<String, Integer> WEEKDAYS_MAP = new
HashMap<String, Integer>();
+ private static final Map<String, Integer> MONTHS_MAP = new HashMap<String,
Integer>();
+
static {
int i = 0;
// Jan -> 0
@@ -79,7 +81,7 @@ public class EJBCronTrigger extends Cron
WEEKDAYS_MAP.put(weekday.toUpperCase(Locale.US), i++);
}
}
-
+
private static final int[] ORDERED_CALENDAR_FIELDS = { Calendar.YEAR,
Calendar.MONTH, Calendar.DAY_OF_MONTH, Calendar.HOUR_OF_DAY, Calendar.MINUTE,
Calendar.SECOND };
private static final Map<Integer, Integer>
CALENDAR_FIELD_TYPE_ORDERED_INDEX_MAP = new LinkedHashMap<Integer, Integer>();
@@ -98,8 +100,9 @@ public class EJBCronTrigger extends Cron
private final FieldExpression[] expressions = new FieldExpression[7];
private TimeZone timezone;
+ private String rawValue;
- public EJBCronTrigger(ScheduleExpression expr) throws ParseException {
+ public EJBCronTrigger(ScheduleExpression expr) throws ParseException {
Map<Integer, String> fieldValues = new LinkedHashMap<Integer,
String>();
fieldValues.put(Calendar.YEAR, expr.getYear());
@@ -132,9 +135,12 @@ public class EJBCronTrigger extends Cron
if (!errors.isEmpty()) {
throw new ParseException(errors);
}
- }
- /**
+ rawValue = expr.getYear() + DELIMITER + expr.getMonth() + DELIMITER +
expr.getDayOfMonth() + DELIMITER + expr.getDayOfWeek()
+ + DELIMITER + expr.getHour() + DELIMITER +
expr.getMinute() + DELIMITER + expr.getSecond();
+ }
+
+ /**
* Computes a set of allowed values for the given field of a calendar
based
* time expression.
*
@@ -498,6 +504,10 @@ public class EJBCronTrigger extends Cron
return -1;
}
+ public String getRawValue() {
+ return rawValue;
+ }
+
/**
* reset those sub field values, we need to configure from the end to
begin, as getActualMaximun consider other fields' values
* @param calendar
@@ -516,7 +526,12 @@ public class EJBCronTrigger extends Cron
}
}
- public static class ParseException extends Exception {
+ @Override // we don't want to be a CronTrigger for persistence
+ public boolean hasAdditionalProperties() {
+ return true;
+ }
+
+ public static class ParseException extends Exception {
private final Map<Integer, ParseException> children;
private final Integer field;
Added:
openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/core/timer/EJBCronTriggerPersistenceDelegate.java
URL:
http://svn.apache.org/viewvc/openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/core/timer/EJBCronTriggerPersistenceDelegate.java?rev=1371929&view=auto
==============================================================================
---
openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/core/timer/EJBCronTriggerPersistenceDelegate.java
(added)
+++
openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/core/timer/EJBCronTriggerPersistenceDelegate.java
Sat Aug 11 12:33:43 2012
@@ -0,0 +1,113 @@
+package org.apache.openejb.core.timer;
+
+import org.quartz.JobDetail;
+import org.quartz.ScheduleBuilder;
+import org.quartz.TriggerKey;
+import org.quartz.impl.jdbcjobstore.CronTriggerPersistenceDelegate;
+import org.quartz.impl.jdbcjobstore.Util;
+import org.quartz.spi.MutableTrigger;
+import org.quartz.spi.OperableTrigger;
+
+import javax.ejb.ScheduleExpression;
+import java.io.IOException;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+public class EJBCronTriggerPersistenceDelegate extends
CronTriggerPersistenceDelegate {
+ @Override
+ public String getHandledTriggerTypeDiscriminator() {
+ return "EJB_CRON";
+ }
+
+ @Override
+ public boolean canHandleTriggerType(OperableTrigger trigger) {
+ return trigger instanceof EJBCronTrigger;
+ }
+
+ @Override
+ public TriggerPropertyBundle loadExtendedTriggerProperties(final
Connection conn, final TriggerKey triggerKey) throws SQLException {
+ PreparedStatement ps = null;
+ ResultSet rs = null;
+ try {
+ ps = conn.prepareStatement(Util.rtp(SELECT_CRON_TRIGGER,
tablePrefix, schedNameLiteral));
+ ps.setString(1, triggerKey.getName());
+ ps.setString(2, triggerKey.getGroup());
+ rs = ps.executeQuery();
+
+ if (rs.next()) {
+ String cronExpr = rs.getString(COL_CRON_EXPRESSION);
+ String timeZoneId = rs.getString(COL_TIME_ZONE_ID);
+
+ final String[] parts =
cronExpr.split(EJBCronTrigger.DELIMITER);
+ try {
+ final EJBCronTrigger cb = new EJBCronTrigger(new
ScheduleExpression()
+ .year(parts[0])
+ .month(parts[1])
+ .dayOfMonth(parts[2])
+ .dayOfWeek(parts[3])
+ .hour(parts[4])
+ .minute(parts[5])
+ .second(parts[6])
+ .timezone(timeZoneId));
+ return new TriggerPropertyBundle(new
EJBCronTriggerSceduleBuilder(cb), null, null);
+ } catch (EJBCronTrigger.ParseException e) {
+ throw new IllegalStateException("Can't build the Trigger
with key: '" + triggerKey + "' and statement: " + Util.rtp(SELECT_CRON_TRIGGER,
tablePrefix, schedNameLiteral));
+ }
+ }
+
+ throw new IllegalStateException("No record found for selection of
Trigger with key: '" + triggerKey + "' and statement: " +
Util.rtp(SELECT_CRON_TRIGGER, tablePrefix, schedNameLiteral));
+ } finally {
+ Util.closeResultSet(rs);
+ Util.closeStatement(ps);
+ }
+ }
+
+ @Override
+ public int insertExtendedTriggerProperties(final Connection conn, final
OperableTrigger trigger,
+ final String state, final
JobDetail jobDetail) throws SQLException, IOException {
+ final EJBCronTrigger cronTrigger = (EJBCronTrigger) trigger;
+ PreparedStatement ps = null;
+ try {
+ ps = conn.prepareStatement(Util.rtp(INSERT_CRON_TRIGGER,
tablePrefix, schedNameLiteral));
+ ps.setString(1, trigger.getKey().getName());
+ ps.setString(2, trigger.getKey().getGroup());
+ ps.setString(3, cronTrigger.getRawValue());
+ ps.setString(4, cronTrigger.getTimeZone().getID());
+ return ps.executeUpdate();
+ } finally {
+ Util.closeStatement(ps);
+ }
+ }
+
+ @Override
+ public int updateExtendedTriggerProperties(final Connection conn, final
OperableTrigger trigger,
+ final String state, final
JobDetail jobDetail) throws SQLException, IOException {
+ final EJBCronTrigger cronTrigger = (EJBCronTrigger) trigger;
+ PreparedStatement ps = null;
+ try {
+ ps = conn.prepareStatement(Util.rtp(UPDATE_CRON_TRIGGER,
tablePrefix, schedNameLiteral));
+ ps.setString(1, cronTrigger.getRawValue());
+ ps.setString(2, cronTrigger.getTimeZone().getID());
+ ps.setString(3, trigger.getKey().getName());
+ ps.setString(4, trigger.getKey().getGroup());
+ return ps.executeUpdate();
+ } finally {
+ Util.closeStatement(ps);
+ }
+ }
+
+ private static class EJBCronTriggerSceduleBuilder extends
ScheduleBuilder<EJBCronTrigger> {
+ private final EJBCronTrigger trigger;
+
+ public EJBCronTriggerSceduleBuilder(final EJBCronTrigger trig) {
+ trigger = trig;
+ }
+
+ @Override
+ protected MutableTrigger build() {
+ return trigger;
+ }
+ }
+}
Modified:
openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/core/timer/EjbTimerServiceImpl.java
URL:
http://svn.apache.org/viewvc/openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/core/timer/EjbTimerServiceImpl.java?rev=1371929&r1=1371928&r2=1371929&view=diff
==============================================================================
---
openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/core/timer/EjbTimerServiceImpl.java
(original)
+++
openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/core/timer/EjbTimerServiceImpl.java
Sat Aug 11 12:33:43 2012
@@ -54,7 +54,9 @@ import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
+import java.util.Map;
import java.util.Properties;
+import java.util.concurrent.ConcurrentHashMap;
public class EjbTimerServiceImpl implements EjbTimerService, Serializable {
@@ -65,6 +67,8 @@ public class EjbTimerServiceImpl impleme
public static final String OPENEJB_TIMEOUT_JOB_NAME =
"OPENEJB_TIMEOUT_JOB";
public static final String OPENEJB_TIMEOUT_JOB_GROUP_NAME =
"OPENEJB_TIMEOUT_GROUP";
+ private static final Map<Object, Scheduler> SCHEDULER_BY_BEANCONTEXT = new
ConcurrentHashMap<Object, Scheduler>();
+
private boolean transacted;
private int retryAttempts;
@@ -109,6 +113,11 @@ public class EjbTimerServiceImpl impleme
}
public static synchronized Scheduler getDefaultScheduler(BeanContext
deployment) {
+ Scheduler scheduler =
SCHEDULER_BY_BEANCONTEXT.get(deployment.getDeploymentID());
+ if (scheduler != null) {
+ return scheduler;
+ }
+
final Properties properties = new Properties();
final SystemInstance systemInstance = SystemInstance.get();
final String defaultThreadPool =
DefaultTimerThreadPoolAdapter.class.getName();
@@ -120,13 +129,18 @@ public class EjbTimerServiceImpl impleme
boolean newInstance = updateProperties(properties,
deployment.getEjbName() + ".")
|| updateProperties(properties, deployment.getModuleName() +
"." + deployment.getEjbName() + ".");
+ // adding our custom persister
+ if (properties.containsKey("org.quartz.jobStore.class") &&
!properties.containsKey("org.quartz.jobStore.driverDelegateInitString")) {
+ properties.put("org.quartz.jobStore.driverDelegateInitString",
"triggerPersistenceDelegateClasses=" +
EJBCronTriggerPersistenceDelegate.class.getName());
+ }
+
if
(defaultThreadPool.equals(properties.get(StdSchedulerFactory.PROP_THREAD_POOL_CLASS))
&& properties.containsKey("org.quartz.threadPool.threadCount")
& !properties.containsKey("openejb.timer.pool.size")) {
log.info("Found property 'org.quartz.threadPool.threadCount' for
default thread pool, please use 'openejb.timer.pool.size' instead");
}
- final Scheduler scheduler =
systemInstance.getComponent(Scheduler.class);
+ scheduler = systemInstance.getComponent(Scheduler.class);
Scheduler thisScheduler;
if (scheduler == null || newInstance) {
try {
@@ -150,6 +164,9 @@ public class EjbTimerServiceImpl impleme
} else {
thisScheduler = scheduler;
}
+
+ SCHEDULER_BY_BEANCONTEXT.put(deployment.getDeploymentID(),
thisScheduler);
+
return thisScheduler;
}
@@ -182,6 +199,7 @@ public class EjbTimerServiceImpl impleme
throw new OpenEJBRuntimeException("Unable to shutdown
scheduler", e);
}
}
+ SCHEDULER_BY_BEANCONTEXT.remove(deployment);
}
public static void shutdown() {
@@ -419,8 +437,15 @@ public class EjbTimerServiceImpl impleme
public void ejbTimeout(TimerData timerData) {
try {
Timer timer = getTimer(timerData.getId());
- if (timer == null) {
- return;
+ // quartz can be backed by some advanced config (jdbc for instance)
+ if (timer == null && timerStore instanceof MemoryTimerStore &&
timerData.getTimer() != null) {
+ try {
+ timerStore.addTimerData(timerData);
+ timer = timerData.getTimer(); // TODO: replace
memoryjobstore by the db one?
+ } catch (TimerStoreException e) {
+ // shouldn't occur
+ }
+ // return;
}
for (int tries = 0; tries < (1 + retryAttempts); tries++) {
boolean retry = false;