You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tomee.apache.org by rm...@apache.org on 2012/11/14 18:38:12 UTC
svn commit: r1409270 - in /openejb/trunk/openejb/container/openejb-core/src:
main/java/org/apache/openejb/core/timer/EjbTimerServiceImpl.java
test/java/org/apache/openejb/timer/EjbTimerImplSerializableTest.java
Author: rmannibucau
Date: Wed Nov 14 17:38:11 2012
New Revision: 1409270
URL: http://svn.apache.org/viewvc?rev=1409270&view=rev
Log:
when deserializing a quartz scheduler trying to do it lazily to avoid dead lock
Modified:
openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/core/timer/EjbTimerServiceImpl.java
openejb/trunk/openejb/container/openejb-core/src/test/java/org/apache/openejb/timer/EjbTimerImplSerializableTest.java
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=1409270&r1=1409269&r2=1409270&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 Wed Nov 14 17:38:11 2012
@@ -52,7 +52,9 @@ import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
+import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
@@ -115,114 +117,123 @@ public class EjbTimerServiceImpl impleme
deployment = SystemInstance.get().getComponent(ContainerSystem.class).getBeanContext(dId);
transactionManager = getDefaultTransactionManager();
timerStore = new MemoryTimerStore(transactionManager); // TODO: check it should be serialized or not
- scheduler = getDefaultScheduler(deployment);
+ scheduler = (Scheduler) Proxy.newProxyInstance(deployment.getClassLoader(), new Class<?>[] { Scheduler.class }, new LazyScheduler(deployment));
}
- public static synchronized Scheduler getDefaultScheduler(BeanContext deployment) {
+ public static synchronized Scheduler getDefaultScheduler(final BeanContext deployment) {
Scheduler scheduler = deployment.get(Scheduler.class);
- boolean valid;
- try {
- valid = !scheduler.isShutdown();
- } catch (Exception ignored) {
- valid = false;
- }
- if (scheduler != null && valid) {
- return scheduler;
- }
-
- final Properties properties = new Properties();
- putAll(properties, SystemInstance.get().getProperties());
- putAll(properties, deployment.getModuleContext().getAppContext().getProperties());
- putAll(properties, deployment.getModuleContext().getProperties());
- putAll(properties, deployment.getProperties());
-
- // custom config -> don't use default scheduler
- boolean newInstance = false;
- for (String key : properties.stringPropertyNames()) {
- if (key.startsWith("org.quartz.")) {
- newInstance = true;
- break;
+ if (scheduler != null) {
+ boolean valid;
+ try {
+ valid = !scheduler.isShutdown();
+ } catch (Exception ignored) {
+ valid = false;
+ }
+ if (valid) {
+ return scheduler;
}
}
- final SystemInstance systemInstance = SystemInstance.get();
+ Scheduler thisScheduler;
+ synchronized (deployment) { // should be done only once so no perf issues
+ scheduler = deployment.get(Scheduler.class);
+ if (scheduler != null) {
+ return scheduler;
+ }
+
+ final Properties properties = new Properties();
+ putAll(properties, SystemInstance.get().getProperties());
+ putAll(properties, deployment.getModuleContext().getAppContext().getProperties());
+ putAll(properties, deployment.getModuleContext().getProperties());
+ putAll(properties, deployment.getProperties());
+
+ // custom config -> don't use default scheduler
+ boolean newInstance = false;
+ for (String key : properties.stringPropertyNames()) {
+ if (key.startsWith("org.quartz.")) {
+ newInstance = true;
+ break;
+ }
+ }
- final String defaultThreadPool = DefaultTimerThreadPoolAdapter.class.getName();
- if (!properties.containsKey(StdSchedulerFactory.PROP_THREAD_POOL_CLASS)) {
- properties.put(StdSchedulerFactory.PROP_THREAD_POOL_CLASS, defaultThreadPool);
- }
- if (!properties.containsKey(StdSchedulerFactory.PROP_SCHED_INSTANCE_NAME)) {
- properties.put(StdSchedulerFactory.PROP_SCHED_INSTANCE_NAME, "OpenEJB-TimerService-Scheduler");
- }
- if (!properties.containsKey(QUARTZ_MAKE_SCHEDULER_THREAD_DAEMON)) {
- properties.put(QUARTZ_MAKE_SCHEDULER_THREAD_DAEMON, "true");
- }
- if (!properties.containsKey(QUARTZ_JMX) && LocalMBeanServer.isJMXActive()) {
- properties.put(QUARTZ_JMX, "true");
- }
- if (!properties.containsKey(StdSchedulerFactory.PROP_SCHED_INSTANCE_ID)) {
- if (!newInstance) {
- properties.setProperty(StdSchedulerFactory.PROP_SCHED_INSTANCE_ID, "OpenEJB");
- } else {
- properties.setProperty(StdSchedulerFactory.PROP_SCHED_INSTANCE_ID, deployment.getDeploymentID().toString());
+ final SystemInstance systemInstance = SystemInstance.get();
+
+ final String defaultThreadPool = DefaultTimerThreadPoolAdapter.class.getName();
+ if (!properties.containsKey(StdSchedulerFactory.PROP_THREAD_POOL_CLASS)) {
+ properties.put(StdSchedulerFactory.PROP_THREAD_POOL_CLASS, defaultThreadPool);
+ }
+ if (!properties.containsKey(StdSchedulerFactory.PROP_SCHED_INSTANCE_NAME)) {
+ properties.put(StdSchedulerFactory.PROP_SCHED_INSTANCE_NAME, "OpenEJB-TimerService-Scheduler");
+ }
+ if (!properties.containsKey(QUARTZ_MAKE_SCHEDULER_THREAD_DAEMON)) {
+ properties.put(QUARTZ_MAKE_SCHEDULER_THREAD_DAEMON, "true");
+ }
+ if (!properties.containsKey(QUARTZ_JMX) && LocalMBeanServer.isJMXActive()) {
+ properties.put(QUARTZ_JMX, "true");
+ }
+ if (!properties.containsKey(StdSchedulerFactory.PROP_SCHED_INSTANCE_ID)) {
+ if (!newInstance) {
+ properties.setProperty(StdSchedulerFactory.PROP_SCHED_INSTANCE_ID, "OpenEJB");
+ } else {
+ properties.setProperty(StdSchedulerFactory.PROP_SCHED_INSTANCE_ID, deployment.getDeploymentID().toString());
+ }
}
- }
- // 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());
- }
+ // 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(DefaultTimerThreadPoolAdapter.OPENEJB_TIMER_POOL_SIZE)) {
- log.info("Found property 'org.quartz.threadPool.threadCount' for default thread pool, please use '"
- + DefaultTimerThreadPoolAdapter.OPENEJB_TIMER_POOL_SIZE + "' instead");
- }
+ if (defaultThreadPool.equals(properties.get(StdSchedulerFactory.PROP_THREAD_POOL_CLASS))
+ && properties.containsKey("org.quartz.threadPool.threadCount")
+ && !properties.containsKey(DefaultTimerThreadPoolAdapter.OPENEJB_TIMER_POOL_SIZE)) {
+ log.info("Found property 'org.quartz.threadPool.threadCount' for default thread pool, please use '"
+ + DefaultTimerThreadPoolAdapter.OPENEJB_TIMER_POOL_SIZE + "' instead");
+ }
- // to ensure we can shutdown correctly, default doesn't support such a configuration
- if (!properties.getProperty(StdSchedulerFactory.PROP_JOB_STORE_CLASS, RAMJobStore.class.getName()).equals(RAMJobStore.class.getName())) {
- properties.put("org.quartz.jobStore.makeThreadsDaemons", properties.getProperty("org.quartz.jobStore.makeThreadsDaemon", "true"));
- }
+ // to ensure we can shutdown correctly, default doesn't support such a configuration
+ if (!properties.getProperty(StdSchedulerFactory.PROP_JOB_STORE_CLASS, RAMJobStore.class.getName()).equals(RAMJobStore.class.getName())) {
+ properties.put("org.quartz.jobStore.makeThreadsDaemons", properties.getProperty("org.quartz.jobStore.makeThreadsDaemon", "true"));
+ }
- scheduler = systemInstance.getComponent(Scheduler.class);
- Scheduler thisScheduler;
- if (scheduler == null || newInstance) {
- try {
- // start in container context to avoid thread leaks
- final ClassLoader oldCl = Thread.currentThread().getContextClassLoader();
- if (!"true".equals(deployment.getProperties().getProperty(OPENEJB_QUARTZ_USE_TCCL, "false"))) {
- Thread.currentThread().setContextClassLoader(EjbTimerServiceImpl.class.getClassLoader());
- }
+ scheduler = systemInstance.getComponent(Scheduler.class);
+ if (scheduler == null || newInstance) {
try {
- thisScheduler = new StdSchedulerFactory(properties).getScheduler();
- thisScheduler.start();
- } finally {
- Thread.currentThread().setContextClassLoader(oldCl);
+ // start in container context to avoid thread leaks
+ final ClassLoader oldCl = Thread.currentThread().getContextClassLoader();
+ if (!"true".equals(deployment.getProperties().getProperty(OPENEJB_QUARTZ_USE_TCCL, "false"))) {
+ Thread.currentThread().setContextClassLoader(EjbTimerServiceImpl.class.getClassLoader());
+ }
+ try {
+ thisScheduler = new StdSchedulerFactory(properties).getScheduler();
+ thisScheduler.start();
+ } finally {
+ Thread.currentThread().setContextClassLoader(oldCl);
+ }
+
+ //durability is configured with true, which means that the job will be kept in the store even if no trigger is attached to it.
+ //Currently, all the EJB beans share with the same job instance
+ JobDetail job = JobBuilder.newJob(EjbTimeoutJob.class)
+ .withIdentity(OPENEJB_TIMEOUT_JOB_NAME, OPENEJB_TIMEOUT_JOB_GROUP_NAME)
+ .storeDurably(true)
+ .requestRecovery(false)
+ .build();
+ thisScheduler.addJob(job, true);
+ } catch (SchedulerException e) {
+ throw new OpenEJBRuntimeException("Fail to initialize the default scheduler", e);
}
- //durability is configured with true, which means that the job will be kept in the store even if no trigger is attached to it.
- //Currently, all the EJB beans share with the same job instance
- JobDetail job = JobBuilder.newJob(EjbTimeoutJob.class)
- .withIdentity(OPENEJB_TIMEOUT_JOB_NAME, OPENEJB_TIMEOUT_JOB_GROUP_NAME)
- .storeDurably(true)
- .requestRecovery(false)
- .build();
- thisScheduler.addJob(job, true);
- } catch (SchedulerException e) {
- throw new OpenEJBRuntimeException("Fail to initialize the default scheduler", e);
+ if (!newInstance) {
+ systemInstance.setComponent(Scheduler.class, thisScheduler);
+ }
+ } else {
+ thisScheduler = scheduler;
}
- if (!newInstance) {
- systemInstance.setComponent(Scheduler.class, thisScheduler);
- }
- } else {
- thisScheduler = scheduler;
+ deployment.set(Scheduler.class, thisScheduler);
}
- deployment.set(Scheduler.class, thisScheduler);
-
return thisScheduler;
}
@@ -266,6 +277,10 @@ public class EjbTimerServiceImpl impleme
}
private void shutdownMyScheduler() {
+ if (scheduler == null) {
+ return;
+ }
+
boolean defaultScheduler = false;
final Scheduler ds = SystemInstance.get().getComponent(Scheduler.class);
try { // == is the faster way to test, we rely on name (key in quartz registry) only for serialization
@@ -275,7 +290,7 @@ public class EjbTimerServiceImpl impleme
}
// if specific instance
- if (scheduler != null && !defaultScheduler) {
+ if (!defaultScheduler) {
try {
scheduler.shutdown();
} catch (SchedulerException e) {
@@ -285,12 +300,13 @@ public class EjbTimerServiceImpl impleme
}
public static void shutdown() {
-
- Scheduler scheduler = SystemInstance.get().getComponent(Scheduler.class);
- if (scheduler != null) try {
- scheduler.shutdown();
- } catch (SchedulerException e) {
- throw new OpenEJBRuntimeException("Unable to shutdown scheduler", e);
+ final Scheduler scheduler = SystemInstance.get().getComponent(Scheduler.class);
+ if (scheduler != null) {
+ try {
+ scheduler.shutdown();
+ } catch (SchedulerException e) {
+ throw new OpenEJBRuntimeException("Unable to shutdown scheduler", e);
+ }
}
}
@@ -633,4 +649,17 @@ public class EjbTimerServiceImpl impleme
});
}
}*/
+
+ private static class LazyScheduler implements InvocationHandler {
+ private final BeanContext ejb;
+
+ public LazyScheduler(final BeanContext deployment) {
+ ejb = deployment;
+ }
+
+ @Override
+ public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
+ return method.invoke(getDefaultScheduler(ejb), args);
+ }
+ }
}
\ No newline at end of file
Modified: openejb/trunk/openejb/container/openejb-core/src/test/java/org/apache/openejb/timer/EjbTimerImplSerializableTest.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/container/openejb-core/src/test/java/org/apache/openejb/timer/EjbTimerImplSerializableTest.java?rev=1409270&r1=1409269&r2=1409270&view=diff
==============================================================================
--- openejb/trunk/openejb/container/openejb-core/src/test/java/org/apache/openejb/timer/EjbTimerImplSerializableTest.java (original)
+++ openejb/trunk/openejb/container/openejb-core/src/test/java/org/apache/openejb/timer/EjbTimerImplSerializableTest.java Wed Nov 14 17:38:11 2012
@@ -44,6 +44,7 @@ import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import static org.hamcrest.core.IsInstanceOf.instanceOf;
+import static org.hamcrest.core.IsNull.notNullValue;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
@@ -62,6 +63,7 @@ public class EjbTimerImplSerializableTes
final EjbTimerService timerDeserialized = (EjbTimerService) deserialize(serial);
assertThat(timerDeserialized, instanceOf(EjbTimerServiceImpl.class));
+ assertThat(((EjbTimerServiceImpl) timerDeserialized).getScheduler(), notNullValue());
assertEqualsByReflection(timer, timerDeserialized, "deployment");
assertEqualsByReflection(timer, timerDeserialized, "transacted");