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;


Reply via email to