You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tomee.apache.org by jg...@apache.org on 2015/04/15 11:00:36 UTC
tomee git commit: TOMEE-1547 allow resources to be loaded more lazily,
support @PostConstruct and @PreDestroy in resources
Repository: tomee
Updated Branches:
refs/heads/tomee-1.7.x 9da3b458e -> d4aec8fae
TOMEE-1547 allow resources to be loaded more lazily, support @PostConstruct and @PreDestroy in resources
Project: http://git-wip-us.apache.org/repos/asf/tomee/repo
Commit: http://git-wip-us.apache.org/repos/asf/tomee/commit/d4aec8fa
Tree: http://git-wip-us.apache.org/repos/asf/tomee/tree/d4aec8fa
Diff: http://git-wip-us.apache.org/repos/asf/tomee/diff/d4aec8fa
Branch: refs/heads/tomee-1.7.x
Commit: d4aec8fae0d1e618e23e1f3e19a5151a15fcce0d
Parents: 9da3b45
Author: Jonathan Gallimore <jo...@jrg.me.uk>
Authored: Wed Apr 15 09:59:19 2015 +0100
Committer: Jonathan Gallimore <jo...@jrg.me.uk>
Committed: Wed Apr 15 09:59:19 2015 +0100
----------------------------------------------------------------------
.../arquillian/tests/resource/ResourceTest.java | 117 +++++++++++
.../src/test/resources/META-INF/resources.xml | 37 ++++
.../openejb/assembler/classic/Assembler.java | 204 ++++++++++++++++---
.../apache/openejb/config/DeploymentLoader.java | 2 +
.../apache/openejb/config/ReadDescriptors.java | 39 +++-
.../META-INF/org.apache.openejb/service-jar.xml | 1 -
.../assembler/classic/LazyResourceTest.java | 82 ++++++++
.../openejb/config/ReadDescriptorsTest.java | 115 +++++++++++
8 files changed, 567 insertions(+), 30 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/tomee/blob/d4aec8fa/arquillian/arquillian-tomee-tests/arquillian-tomee-config-tests/src/test/java/org/apache/openejb/arquillian/tests/resource/ResourceTest.java
----------------------------------------------------------------------
diff --git a/arquillian/arquillian-tomee-tests/arquillian-tomee-config-tests/src/test/java/org/apache/openejb/arquillian/tests/resource/ResourceTest.java b/arquillian/arquillian-tomee-tests/arquillian-tomee-config-tests/src/test/java/org/apache/openejb/arquillian/tests/resource/ResourceTest.java
new file mode 100644
index 0000000..dabc13b
--- /dev/null
+++ b/arquillian/arquillian-tomee-tests/arquillian-tomee-config-tests/src/test/java/org/apache/openejb/arquillian/tests/resource/ResourceTest.java
@@ -0,0 +1,117 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.openejb.arquillian.tests.resource;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import javax.annotation.Resource;
+import javax.ejb.EJB;
+import javax.ejb.Lock;
+import javax.ejb.LockType;
+import javax.ejb.Singleton;
+
+import org.apache.openejb.api.resource.DestroyableResource;
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.arquillian.junit.Arquillian;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.spec.EnterpriseArchive;
+import org.jboss.shrinkwrap.api.spec.JavaArchive;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(Arquillian.class)
+public class ResourceTest {
+
+ @EJB
+ private TestEjb ejb;
+
+ @Deployment
+ public static EnterpriseArchive createDeployment() {
+
+ final JavaArchive ejbJar = ShrinkWrap.create(JavaArchive.class, "test-ejb.jar")
+ .addAsResource("META-INF/resources.xml", "META-INF/resources.xml")
+ .addClass(ResourceTest.class)
+ .addClass(Destroyable.class)
+ .addClass(Hello.class)
+ .addClass(TestEjb.class);
+
+ final EnterpriseArchive ear = ShrinkWrap.create(EnterpriseArchive.class, "test.ear")
+ .addAsModule(ejbJar);
+
+ return ear;
+ }
+
+ @Test
+ public void test() throws Exception {
+ Assert.assertTrue(ejb.isPostConstructCalled());
+ }
+
+ @Singleton
+ @Lock(LockType.READ)
+ public static class TestEjb {
+
+ @Resource(name = "test/Hello")
+ private Hello hello;
+
+ public boolean isPostConstructCalled() {
+ return hello.isPostConstructCalled();
+ }
+ }
+
+ public static class Hello {
+
+ private boolean postConstructCalled = false;
+ private boolean preDestroyCalled = false;
+
+ @PostConstruct
+ public void postConstruct() {
+ postConstructCalled = true;
+ }
+
+ @PreDestroy
+ public void preDestroy() {
+ preDestroyCalled = true;
+ }
+
+ public boolean isPostConstructCalled() {
+ return postConstructCalled;
+ }
+
+ public boolean isPreDestroyCalled() {
+ return preDestroyCalled;
+ }
+ }
+
+ public static class Destroyable implements DestroyableResource {
+
+ private boolean destroyCalled = false;
+
+ @Override
+ public void destroyResource() {
+ destroyCalled = true;
+ }
+
+ public boolean isDestroyCalled() {
+ return destroyCalled;
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/tomee/blob/d4aec8fa/arquillian/arquillian-tomee-tests/arquillian-tomee-config-tests/src/test/resources/META-INF/resources.xml
----------------------------------------------------------------------
diff --git a/arquillian/arquillian-tomee-tests/arquillian-tomee-config-tests/src/test/resources/META-INF/resources.xml b/arquillian/arquillian-tomee-tests/arquillian-tomee-config-tests/src/test/resources/META-INF/resources.xml
new file mode 100644
index 0000000..0249b91
--- /dev/null
+++ b/arquillian/arquillian-tomee-tests/arquillian-tomee-config-tests/src/test/resources/META-INF/resources.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0"?>
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you under the Apache License, Version 2.0 (the
+ ~ "License"); you may not use this file except in compliance
+ ~ with the License. You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing,
+ ~ software distributed under the License is distributed on an
+ ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ ~ KIND, either express or implied. See the License for the
+ ~ specific language governing permissions and limitations
+ ~ under the License.
+ -->
+
+<Resources>
+ <Resource id="Hello" class-name="org.apache.openejb.arquillian.tests.resource.ResourceTest$Hello">
+ code org.apache.openejb.arquillian.tests.resource.ResourceTest.Hello
+ Lazy true
+ UseAppClassLoader true
+ InitializeAfterDeployment true
+ </Resource>
+
+ <Resource id="Destroyable" class-name="org.apache.openejb.arquillian.tests.resource.ResourceTest$Destroyable">
+ code org.apache.openejb.arquillian.tests.resource.ResourceTest.Destroyable
+ Lazy true
+ UseAppClassLoader true
+ InitializeAfterDeployment true
+ </Resource>
+
+</Resources>
+
http://git-wip-us.apache.org/repos/asf/tomee/blob/d4aec8fa/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java
----------------------------------------------------------------------
diff --git a/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java b/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java
index 9791e3b..0667bd3 100644
--- a/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java
+++ b/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java
@@ -39,6 +39,7 @@ import org.apache.openejb.NoSuchApplicationException;
import org.apache.openejb.OpenEJBException;
import org.apache.openejb.OpenEJBRuntimeException;
import org.apache.openejb.UndeployException;
+import org.apache.openejb.api.DestroyableResource;
import org.apache.openejb.assembler.classic.event.AssemblerAfterApplicationCreated;
import org.apache.openejb.assembler.classic.event.AssemblerBeforeApplicationDestroyed;
import org.apache.openejb.assembler.classic.event.AssemblerCreated;
@@ -64,6 +65,7 @@ import org.apache.openejb.config.ConfigurationFactory;
import org.apache.openejb.config.NewLoaderLogic;
import org.apache.openejb.config.QuickJarsTxtParser;
import org.apache.openejb.config.TldScanner;
+import org.apache.openejb.config.sys.Resource;
import org.apache.openejb.core.ConnectorReference;
import org.apache.openejb.core.CoreContainerSystem;
import org.apache.openejb.core.CoreUserTransaction;
@@ -77,6 +79,8 @@ import org.apache.openejb.core.ivm.IntraVmProxy;
import org.apache.openejb.core.ivm.naming.ContextualJndiReference;
import org.apache.openejb.core.ivm.naming.IvmContext;
import org.apache.openejb.core.ivm.naming.IvmJndiFactory;
+import org.apache.openejb.core.ivm.naming.JndiUrlReference;
+import org.apache.openejb.core.ivm.naming.LazyObjectReference;
import org.apache.openejb.core.ivm.naming.Reference;
import org.apache.openejb.core.security.SecurityContextHandler;
import org.apache.openejb.core.timer.EjbTimerServiceImpl;
@@ -130,7 +134,9 @@ import org.apache.openejb.util.classloader.ClassLoaderAwareHandler;
import org.apache.openejb.util.classloader.URLClassLoaderFirst;
import org.apache.openejb.util.proxy.ProxyFactory;
import org.apache.openejb.util.proxy.ProxyManager;
+import org.apache.webbeans.component.ResourceBean;
import org.apache.webbeans.config.WebBeansContext;
+import org.apache.webbeans.inject.OWBInjector;
import org.apache.webbeans.logger.JULLoggerFactory;
import org.apache.webbeans.spi.ContainerLifecycle;
import org.apache.webbeans.spi.ContextsService;
@@ -147,6 +153,8 @@ import org.apache.xbean.recipe.ObjectRecipe;
import org.apache.xbean.recipe.Option;
import org.apache.xbean.recipe.UnsetPropertiesRecipe;
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
import javax.enterprise.context.Dependent;
import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.inject.spi.Bean;
@@ -177,6 +185,7 @@ import javax.transaction.TransactionSynchronizationRegistry;
import javax.validation.ValidationException;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
+
import java.io.ByteArrayInputStream;
import java.io.Externalizable;
import java.io.File;
@@ -185,9 +194,11 @@ import java.io.InputStream;
import java.io.InvalidObjectException;
import java.io.ObjectStreamException;
import java.io.Serializable;
+import java.lang.annotation.Annotation;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.Instrumentation;
import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.MalformedURLException;
@@ -208,6 +219,7 @@ import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;
import java.util.TreeMap;
+import java.util.concurrent.Callable;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@@ -644,9 +656,9 @@ public class Assembler extends AssemblerTool implements org.apache.openejb.spi.A
}
Extensions.addExtensions(classLoader, appInfo.eventClassesNeedingAppClassloader);
-
logger.info("createApplication.start", appInfo.path);
-
+ final Context containerSystemContext = containerSystem.getJNDIContext();
+
// To start out, ensure we don't already have any beans deployed with duplicate IDs. This
// is a conflict we can't handle.
final List<String> used = new ArrayList<String>();
@@ -700,8 +712,6 @@ public class Assembler extends AssemblerTool implements org.apache.openejb.spi.A
appContext.set(AsynchronousPool.class, AsynchronousPool.create(appContext));
- final Context containerSystemContext = containerSystem.getJNDIContext();
-
final Map<String, LazyValidatorFactory> lazyValidatorFactories = new HashMap<String, LazyValidatorFactory>();
final Map<String, LazyValidator> lazyValidators = new HashMap<String, LazyValidator>();
final boolean isGeronimo = SystemInstance.get().hasProperty("openejb.geronimo");
@@ -928,6 +938,8 @@ public class Assembler extends AssemblerTool implements org.apache.openejb.spi.A
}
}
+ postConstructResources(appInfo, classLoader, containerSystemContext, appContext);
+
deployedApplications.put(appInfo.path, appInfo);
resumePersistentSchedulers(appContext);
@@ -947,6 +959,66 @@ public class Assembler extends AssemblerTool implements org.apache.openejb.spi.A
}
}
+ private void postConstructResources(final AppInfo appInfo, final ClassLoader classLoader, final Context containerSystemContext, final AppContext appContext) throws NamingException, OpenEJBException {
+ final ClassLoader oldCl = Thread.currentThread().getContextClassLoader();
+
+ try {
+ Thread.currentThread().setContextClassLoader(classLoader);
+
+ final Set<String> resourceIds = new HashSet<String>(appInfo.resourceIds);
+ final List<ResourceInfo> resourceList = config.facilities.resources;
+
+ for (ResourceInfo resourceInfo : resourceList) {
+ if (!resourceIds.contains(resourceInfo.id)) {
+ continue;
+ }
+
+ try {
+ final Class<?> cls = Class.forName(resourceInfo.className, true, classLoader);
+ final Method postConstruct = findMethodAnnotatedWith(PostConstruct.class, cls);
+ boolean initialize = "true".equalsIgnoreCase(String.valueOf(resourceInfo.properties.remove("InitializeAfterDeployment")));
+ if (postConstruct != null || initialize) {
+
+ Object resource = containerSystemContext.lookup(OPENEJB_RESOURCE_JNDI_PREFIX + resourceInfo.id);
+ if (resource instanceof LazyResource) {
+ resource = LazyResource.class.cast(resource).getObject();
+ }
+
+ try {
+ // wire up CDI
+ OWBInjector.inject(appContext.getBeanManager(),
+ resource,
+ appContext.getBeanManager().createCreationalContext(null));
+
+ if (postConstruct != null) {
+ postConstruct.invoke(resource);
+ }
+ } catch (Exception e) {
+ logger.fatal("Error calling @PostConstruct method on " + resource.getClass().getName());
+ throw new OpenEJBException(e);
+ }
+ }
+ } catch (Exception e) {
+ logger.fatal("Error calling @PostConstruct method on " + resourceInfo.id);
+ throw new OpenEJBException(e);
+ }
+ }
+ } finally {
+ Thread.currentThread().setContextClassLoader(oldCl);
+ }
+ }
+
+ private Method findMethodAnnotatedWith(final Class<? extends Annotation> annotation, final Class<?> cls) {
+ final Method[] methods = cls.getDeclaredMethods();
+ for (final Method method : methods) {
+ if (method.getAnnotation(annotation) != null) {
+ return method;
+ }
+ }
+
+ return null;
+ }
+
public static void mergeServices(final AppInfo appInfo) throws URISyntaxException {
for (final ServiceInfo si : appInfo.services) { // used lazily by JaxWsServiceObjectFactory, we could do the same for resources
if (!appInfo.properties.containsKey(si.id)) {
@@ -1588,6 +1660,15 @@ public class Assembler extends AssemblerTool implements org.apache.openejb.spi.A
} catch (final Exception e) {
logger.debug("Not processing resource on destroy: " + className, e);
}
+ } else if (DestroyableResource.class.isInstance(object)) {
+ try {
+ DestroyableResource.class.cast(object).destroyResource();
+ } catch (final RuntimeException e) {
+ logger.error(e.getMessage(), e);
+ }
+ } else if (hasPreDestroy(object)) {
+ logger.debug("Calling @PreDestroy on: " + className);
+ preDestroy(object);
} else if (logger.isDebugEnabled() && !DataSource.class.isInstance(object)) {
logger.debug("Not processing resource on destroy: " + className);
}
@@ -1608,6 +1689,31 @@ public class Assembler extends AssemblerTool implements org.apache.openejb.spi.A
}
}
+ private void preDestroy(Object object) {
+ final Method preDestroy = findMethodAnnotatedWith(PreDestroy.class, object.getClass());
+ if (preDestroy != null) {
+ try {
+ preDestroy.invoke(object);
+ } catch (Exception e) {
+ logger.error("Error when calling @PreDestroy", e);
+ }
+ }
+ }
+
+ private boolean hasPreDestroy(final Object object) {
+ try {
+ Object resource = object;
+ if (resource instanceof LazyResource) {
+ resource = LazyResource.class.cast(resource).getObject();
+ }
+
+ Class<? extends Object> cls = resource.getClass();
+ return findMethodAnnotatedWith(PreDestroy.class, cls) != null;
+ } catch (Exception e) {
+ return false;
+ }
+ }
+
public void destroyApplication(final String filePath) throws UndeployException, NoSuchApplicationException {
final ReentrantLock l = lock;
@@ -2281,6 +2387,57 @@ public class Assembler extends AssemblerTool implements org.apache.openejb.spi.A
}
public void createResource(final ResourceInfo serviceInfo) throws OpenEJBException {
+ Object service = "true".equalsIgnoreCase(String.valueOf(serviceInfo.properties.remove("Lazy"))) ?
+ newLazyResource(serviceInfo) :
+ doCreateResource(serviceInfo);
+
+ bindResource(serviceInfo.id, service);
+ for (final String alias : serviceInfo.aliases) {
+ bindResource(alias, service);
+ }
+ if (serviceInfo.originAppName != null && !serviceInfo.originAppName.isEmpty() && !"/".equals(serviceInfo.originAppName)
+ && !serviceInfo.id.startsWith("global")) {
+ final String baseJndiName = serviceInfo.id.substring(serviceInfo.originAppName.length() + 1);
+ serviceInfo.aliases.add(baseJndiName);
+ final ContextualJndiReference ref = new ContextualJndiReference(baseJndiName);
+ ref.addPrefix(serviceInfo.originAppName);
+ bindResource(baseJndiName, ref);
+ }
+
+ // Update the config tree
+ config.facilities.resources.add(serviceInfo);
+
+ if (logger.isDebugEnabled()) { // weird to check parent logger but save time and it is almost never activated
+ logger.getChildLogger("service").debug("createService.success", serviceInfo.service, serviceInfo.id, serviceInfo.className);
+ }
+ }
+
+ private LazyResource newLazyResource(final ResourceInfo serviceInfo) {
+ final ClassLoader loader = Thread.currentThread().getContextClassLoader();
+ return new LazyResource(new Callable<Object>() {
+ @Override
+ public Object call() throws Exception {
+ final boolean appClassLoader = "true".equals(serviceInfo.properties.remove("UseAppClassLoader"));
+
+ ClassLoader old = null;
+
+ if (!appClassLoader) {
+ old = Thread.currentThread().getContextClassLoader();
+ Thread.currentThread().setContextClassLoader(loader);
+ }
+
+ try {
+ return doCreateResource(serviceInfo);
+ } finally {
+ if (old != null) {
+ Thread.currentThread().setContextClassLoader(old);
+ }
+ }
+ }
+ });
+ }
+
+ private Object doCreateResource(final ResourceInfo serviceInfo) throws OpenEJBException {
final ObjectRecipe serviceRecipe = createRecipe(serviceInfo);
final boolean properties = PropertiesFactory.class.getName().equals(serviceInfo.className);
if ("false".equalsIgnoreCase(serviceInfo.properties.getProperty("SkipImplicitAttributes", "false")) && !properties) {
@@ -2297,7 +2454,7 @@ public class Assembler extends AssemblerTool implements org.apache.openejb.spi.A
final InputStream is = new ByteArrayInputStream(serviceInfo.properties.getProperty("Definition").getBytes());
final Properties p = new SuperProperties();
IO.readProperties(is, p);
- for (final Map.Entry<Object, Object> entry : p.entrySet()) {
+ for (final Entry<Object, Object> entry : p.entrySet()) {
final String key = entry.getKey().toString();
if (!props.containsKey(key)
// never override from Definition, just use it to complete the properties set
@@ -2440,7 +2597,7 @@ public class Assembler extends AssemblerTool implements org.apache.openejb.spi.A
final Map<String, Object> unsetA = serviceRecipe.getUnsetProperties();
final Map<String, Object> unsetB = connectionManagerRecipe.getUnsetProperties();
final Map<String, Object> unset = new HashMap<String, Object>();
- for (final Map.Entry<String, Object> entry : unsetA.entrySet()) {
+ for (final Entry<String, Object> entry : unsetA.entrySet()) {
if (unsetB.containsKey(entry.getKey())) {
unset.put(entry.getKey(), entry.getValue());
}
@@ -2504,26 +2661,7 @@ public class Assembler extends AssemblerTool implements org.apache.openejb.spi.A
} else if (!Properties.class.isInstance(service)) {
logUnusedProperties(serviceRecipe, serviceInfo);
}
-
- bindResource(serviceInfo.id, service);
- for (final String alias : serviceInfo.aliases) {
- bindResource(alias, service);
- }
- if (serviceInfo.originAppName != null && !serviceInfo.originAppName.isEmpty() && !"/".equals(serviceInfo.originAppName)
- && !serviceInfo.id.startsWith("global")) {
- final String baseJndiName = serviceInfo.id.substring(serviceInfo.originAppName.length() + 1);
- serviceInfo.aliases.add(baseJndiName);
- final ContextualJndiReference ref = new ContextualJndiReference(baseJndiName);
- ref.addPrefix(serviceInfo.originAppName);
- bindResource(baseJndiName, ref);
- }
-
- // Update the config tree
- config.facilities.resources.add(serviceInfo);
-
- if (logger.isDebugEnabled()) { // weird to check parent logger but save time and it is almost never activated
- logger.getChildLogger("service").debug("createService.success", serviceInfo.service, serviceInfo.id, serviceInfo.className);
- }
+ return service;
}
private void bindResource(final String id, final Object service) throws OpenEJBException {
@@ -2977,4 +3115,18 @@ public class Assembler extends AssemblerTool implements org.apache.openejb.spi.A
}
}
}
+
+ public static class LazyResource extends LazyObjectReference<Object> {
+ public LazyResource(final Callable<Object> creator) {
+ super(creator);
+ }
+
+ Object writeReplace() throws ObjectStreamException {
+ try {
+ return getObject();
+ } catch (final NamingException e) {
+ return null;
+ }
+ }
+ }
}
http://git-wip-us.apache.org/repos/asf/tomee/blob/d4aec8fa/container/openejb-core/src/main/java/org/apache/openejb/config/DeploymentLoader.java
----------------------------------------------------------------------
diff --git a/container/openejb-core/src/main/java/org/apache/openejb/config/DeploymentLoader.java b/container/openejb-core/src/main/java/org/apache/openejb/config/DeploymentLoader.java
index 0a7514b..21c41bc 100644
--- a/container/openejb-core/src/main/java/org/apache/openejb/config/DeploymentLoader.java
+++ b/container/openejb-core/src/main/java/org/apache/openejb/config/DeploymentLoader.java
@@ -25,6 +25,8 @@ import org.apache.openejb.api.RemoteClient;
import org.apache.openejb.classloader.ClassLoaderConfigurer;
import org.apache.openejb.classloader.WebAppEnricher;
import org.apache.openejb.config.event.BeforeDeploymentEvent;
+import org.apache.openejb.config.sys.Resource;
+import org.apache.openejb.config.sys.Resources;
import org.apache.openejb.core.EmptyResourcesClassLoader;
import org.apache.openejb.core.ParentClassLoaderFinder;
import org.apache.openejb.jee.Application;
http://git-wip-us.apache.org/repos/asf/tomee/blob/d4aec8fa/container/openejb-core/src/main/java/org/apache/openejb/config/ReadDescriptors.java
----------------------------------------------------------------------
diff --git a/container/openejb-core/src/main/java/org/apache/openejb/config/ReadDescriptors.java b/container/openejb-core/src/main/java/org/apache/openejb/config/ReadDescriptors.java
index 0c1f835..5faeb6f 100644
--- a/container/openejb-core/src/main/java/org/apache/openejb/config/ReadDescriptors.java
+++ b/container/openejb-core/src/main/java/org/apache/openejb/config/ReadDescriptors.java
@@ -20,7 +20,9 @@ package org.apache.openejb.config;
import org.apache.openejb.OpenEJBException;
import org.apache.openejb.config.sys.JSonConfigReader;
import org.apache.openejb.config.sys.JaxbOpenejb;
+import org.apache.openejb.config.sys.Resource;
import org.apache.openejb.config.sys.Resources;
+import org.apache.openejb.core.ParentClassLoaderFinder;
import org.apache.openejb.jee.ApplicationClient;
import org.apache.openejb.jee.Beans;
import org.apache.openejb.jee.Connector;
@@ -72,6 +74,7 @@ import javax.xml.bind.JAXBException;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
+
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
@@ -241,7 +244,6 @@ public class ReadDescriptors implements DynamicDeployer {
}
return appModule;
-
}
public static void readResourcesXml(final Module module) {
@@ -250,7 +252,7 @@ public class ReadDescriptors implements DynamicDeployer {
if (url != null) {
try {
final Resources openejb = JaxbOpenejb.unmarshal(Resources.class, url.get());
- module.initResources(openejb);
+ module.initResources(check(openejb));
} catch (final Exception e) {
logger.warning("can't read " + url.toString() + " to load resources for module " + module.toString(), e);
}
@@ -261,7 +263,7 @@ public class ReadDescriptors implements DynamicDeployer {
if (url != null) {
try {
final Resources openejb = JSonConfigReader.read(Resources.class, url.get());
- module.initResources(openejb);
+ module.initResources(check(openejb));
} catch (final Exception e) {
logger.warning("can't read " + url.toString() + " to load resources for module " + module.toString(), e);
}
@@ -269,6 +271,37 @@ public class ReadDescriptors implements DynamicDeployer {
}
}
+ public static Resources check(final Resources resources) {
+ final List<Resource> resourceList = resources.getResource();
+ for (final Resource resource : resourceList) {
+ if (resource.getClassName() != null) {
+ try {
+ ParentClassLoaderFinder.Helper.get().loadClass(resource.getClassName());
+ if (resource.getType() != null) {
+ ParentClassLoaderFinder.Helper.get().loadClass(resource.getType());
+ }
+ continue;
+ } catch (Exception e) {
+ }
+
+ // if the resource class cannot be loaded,
+ // set the lazy property to true
+ // and the app classloader property to true
+
+ final Boolean lazySpecified = Boolean.valueOf(resource.getProperties().getProperty("Lazy", "false"));
+
+ resource.getProperties().setProperty("Lazy", "true");
+ resource.getProperties().setProperty("UseAppClassLoader", "true");
+
+ if (!lazySpecified) {
+ resource.getProperties().setProperty("InitializeAfterDeployment", "true");
+ }
+ }
+ }
+
+ return resources;
+ }
+
private void readValidationConfigType(final Module module) throws OpenEJBException {
if (module.getValidationConfig() != null) {
return;
http://git-wip-us.apache.org/repos/asf/tomee/blob/d4aec8fa/container/openejb-core/src/main/resources/META-INF/org.apache.openejb/service-jar.xml
----------------------------------------------------------------------
diff --git a/container/openejb-core/src/main/resources/META-INF/org.apache.openejb/service-jar.xml b/container/openejb-core/src/main/resources/META-INF/org.apache.openejb/service-jar.xml
index 89669ba..e366823 100644
--- a/container/openejb-core/src/main/resources/META-INF/org.apache.openejb/service-jar.xml
+++ b/container/openejb-core/src/main/resources/META-INF/org.apache.openejb/service-jar.xml
@@ -1142,5 +1142,4 @@
service="Resource"
types="ContextService, javax.enterprise.concurrent.ContextService"
class-name="org.apache.openejb.concurrencyutilities.ee.impl.ContextServiceImpl"/>
-
</ServiceJar>
http://git-wip-us.apache.org/repos/asf/tomee/blob/d4aec8fa/container/openejb-core/src/test/java/org/apache/openejb/assembler/classic/LazyResourceTest.java
----------------------------------------------------------------------
diff --git a/container/openejb-core/src/test/java/org/apache/openejb/assembler/classic/LazyResourceTest.java b/container/openejb-core/src/test/java/org/apache/openejb/assembler/classic/LazyResourceTest.java
new file mode 100644
index 0000000..1b19f1c
--- /dev/null
+++ b/container/openejb-core/src/test/java/org/apache/openejb/assembler/classic/LazyResourceTest.java
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.openejb.assembler.classic;
+
+import org.apache.openejb.config.AppModule;
+import org.apache.openejb.config.EjbModule;
+import org.apache.openejb.jee.EjbJar;
+import org.apache.openejb.junit.ApplicationComposer;
+import org.apache.openejb.loader.SystemInstance;
+import org.apache.openejb.spi.ContainerSystem;
+import org.apache.openejb.testing.Configuration;
+import org.apache.openejb.testing.Module;
+import org.apache.openejb.testng.PropertiesBuilder;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import javax.naming.NamingException;
+import java.util.Properties;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+@RunWith(ApplicationComposer.class)
+public class LazyResourceTest {
+ @Test
+ public void lazy() throws NamingException {
+ assertEquals(1, MyResource1.count);
+ assertEquals(0, MyResource2.count);
+ assertTrue(MyResource2.class.isInstance(
+ SystemInstance.get().getComponent(ContainerSystem.class).getJNDIContext().lookup("openejb/Resource/r2")));
+ assertEquals(1, MyResource2.count);
+ }
+
+ @Module
+ public AppModule application() {
+ final EjbModule ejbModule = new EjbModule(new EjbJar());
+
+ final AppModule appModule = new AppModule(Thread.currentThread().getContextClassLoader(), null);
+ appModule.getEjbModules().add(ejbModule);
+
+ return appModule;
+ }
+
+ @Configuration
+ public Properties config() {
+ return new PropertiesBuilder()
+ .p("r1", "new://Resource?class-name=org.apache.openejb.assembler.classic.LazyResourceTest$MyResource1")
+ .p("r2", "new://Resource?class-name=org.apache.openejb.assembler.classic.LazyResourceTest$MyResource2")
+ .p("r2.Lazy", "true")
+ .build();
+ }
+
+ public static class MyResource1 {
+ public static volatile int count = 0;
+
+ public MyResource1() {
+ count++;
+ }
+ }
+
+ public static class MyResource2 {
+ public static volatile int count = 0;
+
+ public MyResource2() {
+ count++;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/tomee/blob/d4aec8fa/container/openejb-core/src/test/java/org/apache/openejb/config/ReadDescriptorsTest.java
----------------------------------------------------------------------
diff --git a/container/openejb-core/src/test/java/org/apache/openejb/config/ReadDescriptorsTest.java b/container/openejb-core/src/test/java/org/apache/openejb/config/ReadDescriptorsTest.java
new file mode 100644
index 0000000..7413109
--- /dev/null
+++ b/container/openejb-core/src/test/java/org/apache/openejb/config/ReadDescriptorsTest.java
@@ -0,0 +1,115 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.openejb.config;
+
+
+import org.apache.openejb.config.sys.Resource;
+import org.apache.openejb.config.sys.Resources;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class ReadDescriptorsTest {
+
+ @Test
+ public void testClassNotAvailable() {
+
+ final Resource resource = new Resource();
+ resource.setClassName("not.a.real.Class");
+
+ final Resources resources = new Resources();
+ resources.add(resource);
+
+ final Resources checkedResources = ReadDescriptors.check(resources);
+ final Resource res = checkedResources.getResource().get(0);
+
+ Assert.assertEquals("true", res.getProperties().getProperty("Lazy"));
+ Assert.assertEquals("true", res.getProperties().getProperty("UseAppClassLoader"));
+ Assert.assertEquals("true", res.getProperties().getProperty("InitializeAfterDeployment"));
+ }
+
+ @Test
+ public void testTypeNotAvailable() {
+
+ final Resource resource = new Resource();
+ resource.setClassName("org.apache.openejb.config.ReadDescriptorsTest");
+ resource.setType("not.a.real.Class");
+
+ final Resources resources = new Resources();
+ resources.add(resource);
+
+ final Resources checkedResources = ReadDescriptors.check(resources);
+ final Resource res = checkedResources.getResource().get(0);
+
+ Assert.assertEquals("true", res.getProperties().getProperty("Lazy"));
+ Assert.assertEquals("true", res.getProperties().getProperty("UseAppClassLoader"));
+ Assert.assertEquals("true", res.getProperties().getProperty("InitializeAfterDeployment"));
+ }
+
+ @Test
+ public void testClassAndTypeAvailable() {
+
+ final Resource resource = new Resource();
+ resource.setClassName("org.apache.openejb.config.ReadDescriptorsTest");
+ resource.setType("org.apache.openejb.config.ReadDescriptorsTest");
+
+ final Resources resources = new Resources();
+ resources.add(resource);
+
+ final Resources checkedResources = ReadDescriptors.check(resources);
+ final Resource res = checkedResources.getResource().get(0);
+
+ Assert.assertNull(res.getProperties().getProperty("Lazy"));
+ Assert.assertNull(res.getProperties().getProperty("UseAppClassLoader"));
+ Assert.assertNull(res.getProperties().getProperty("InitializeAfterDeployment"));
+ }
+
+ @Test
+ public void testClassAvailable() {
+
+ final Resource resource = new Resource();
+ resource.setClassName("org.apache.openejb.config.ReadDescriptorsTest");
+
+ final Resources resources = new Resources();
+ resources.add(resource);
+
+ final Resources checkedResources = ReadDescriptors.check(resources);
+ final Resource res = checkedResources.getResource().get(0);
+
+ Assert.assertNull(res.getProperties().getProperty("Lazy"));
+ Assert.assertNull(res.getProperties().getProperty("UseAppClassLoader"));
+ Assert.assertNull(res.getProperties().getProperty("InitializeAfterDeployment"));
+ }
+
+ @Test
+ public void testLazyResource() {
+ final Resource resource = new Resource();
+ resource.setClassName("not.a.real.Class");
+ resource.setType("not.a.real.Class");
+ resource.getProperties().setProperty("Lazy", "true");
+
+ final Resources resources = new Resources();
+ resources.add(resource);
+
+ final Resources checkedResources = ReadDescriptors.check(resources);
+ final Resource res = checkedResources.getResource().get(0);
+
+ Assert.assertEquals("true", res.getProperties().getProperty("Lazy"));
+ Assert.assertEquals("true", res.getProperties().getProperty("UseAppClassLoader"));
+ Assert.assertNull(res.getProperties().getProperty("InitializeAfterDeployment"));
+ }
+
+}