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 2015/04/15 21:02:37 UTC
tomee git commit: TOMEE-1548 @PostContruct/@preDestroy support in
resource attributes - with merge
Repository: tomee
Updated Branches:
refs/heads/master 02ff59e1a -> 2a29aef9f
TOMEE-1548 @PostContruct/@preDestroy support in resource attributes - with merge
Project: http://git-wip-us.apache.org/repos/asf/tomee/repo
Commit: http://git-wip-us.apache.org/repos/asf/tomee/commit/2a29aef9
Tree: http://git-wip-us.apache.org/repos/asf/tomee/tree/2a29aef9
Diff: http://git-wip-us.apache.org/repos/asf/tomee/diff/2a29aef9
Branch: refs/heads/master
Commit: 2a29aef9ffaf829fdc9e950337fea49eb1a10862
Parents: 02ff59e
Author: Romain Manni-Bucau <rm...@apache.org>
Authored: Wed Apr 15 20:14:07 2015 +0200
Committer: Romain Manni-Bucau <rm...@apache.org>
Committed: Wed Apr 15 20:14:07 2015 +0200
----------------------------------------------------------------------
.../src/test/resources/META-INF/resources.xml | 2 -
.../openejb/assembler/classic/Assembler.java | 205 ++++++++++++------
.../openejb/assembler/classic/ResourceInfo.java | 2 +
.../openejb/config/ConfigurationFactory.java | 13 +-
.../org/apache/openejb/config/sys/Resource.java | 22 ++
.../apache/openejb/config/sys/StackHandler.java | 2 +
.../ivm/naming/ContextualJndiReference.java | 4 +
.../openejb/resource/ResourceLifecycleTest.java | 208 +++++++++++++++++++
8 files changed, 394 insertions(+), 64 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/tomee/blob/2a29aef9/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
index 0249b91..3edb7dc 100644
--- 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
@@ -20,14 +20,12 @@
<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
http://git-wip-us.apache.org/repos/asf/tomee/blob/2a29aef9/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 156e6c0..0a98318 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
@@ -129,6 +129,7 @@ import org.apache.openejb.util.PropertiesHelper;
import org.apache.openejb.util.PropertyPlaceHolderHelper;
import org.apache.openejb.util.References;
import org.apache.openejb.util.SafeToolkit;
+import org.apache.openejb.util.SetAccessible;
import org.apache.openejb.util.SuperProperties;
import org.apache.openejb.util.URISupport;
import org.apache.openejb.util.URLs;
@@ -138,6 +139,7 @@ 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.container.BeanManagerImpl;
import org.apache.webbeans.inject.OWBInjector;
import org.apache.webbeans.logger.JULLoggerFactory;
import org.apache.webbeans.spi.BeanArchiveService;
@@ -150,13 +152,19 @@ import org.apache.webbeans.spi.ScannerService;
import org.apache.webbeans.spi.TransactionService;
import org.apache.webbeans.spi.adaptor.ELAdaptor;
import org.apache.webbeans.spi.api.ResourceReference;
+import org.apache.xbean.finder.AnnotationFinder;
import org.apache.xbean.finder.ClassLoaders;
import org.apache.xbean.finder.ResourceFinder;
import org.apache.xbean.finder.UrlSet;
+import org.apache.xbean.finder.archive.ClassesArchive;
import org.apache.xbean.recipe.ObjectRecipe;
import org.apache.xbean.recipe.Option;
import org.apache.xbean.recipe.UnsetPropertiesRecipe;
+import java.io.ObjectStreamException;
+import java.io.Serializable;
+import java.lang.reflect.Method;
+import java.util.Collection;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
@@ -203,7 +211,6 @@ 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;
@@ -234,6 +241,8 @@ import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.ReentrantLock;
+import static org.apache.openejb.util.Classes.ancestors;
+
@SuppressWarnings({"UnusedDeclaration", "UnqualifiedFieldAccess", "UnqualifiedMethodAccess"})
public class Assembler extends AssemblerTool implements org.apache.openejb.spi.Assembler, JndiConstants {
@@ -539,9 +548,11 @@ public class Assembler extends AssemblerTool implements org.apache.openejb.spi.A
createSecurityService(configInfo.facilities.securityService);
+ final Set<String> rIds = new HashSet<>(configInfo.facilities.resources.size());
for (final ResourceInfo resourceInfo : configInfo.facilities.resources) {
createResource(resourceInfo);
}
+ postConstructResources(rIds, ParentClassLoaderFinder.Helper.get(), systemInstance.getComponent(ContainerSystem.class).getJNDIContext(), null);
// Containers
for (final ContainerInfo serviceInfo : containerSystemInfo.containers) {
@@ -980,7 +991,7 @@ public class Assembler extends AssemblerTool implements org.apache.openejb.spi.A
}
}
- postConstructResources(appInfo, classLoader, containerSystemContext, appContext);
+ postConstructResources(appInfo.resourceIds, classLoader, containerSystemContext, appContext);
deployedApplications.put(appInfo.path, appInfo);
resumePersistentSchedulers(appContext);
@@ -1096,67 +1107,89 @@ 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();
+ private void postConstructResources(final Set<String> inResourceIds, final ClassLoader classLoader, final Context containerSystemContext, final AppContext appContext) throws NamingException, OpenEJBException {
+ final Thread thread = Thread.currentThread();
+ final ClassLoader oldCl = thread.getContextClassLoader();
try {
- Thread.currentThread().setContextClassLoader(classLoader);
+ thread.setContextClassLoader(classLoader);
- final Set<String> resourceIds = new HashSet<String>(appInfo.resourceIds);
+ final Set<String> resourceIds = new HashSet<>(inResourceIds);
final List<ResourceInfo> resourceList = config.facilities.resources;
for (final 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);
+ final Class<?> clazz = classLoader.loadClass(resourceInfo.className);
+ final AnnotationFinder finder = new AnnotationFinder(new ClassesArchive(ancestors(clazz)));
+ final List<Method> postConstructs = finder.findAnnotatedMethods(PostConstruct.class);
+ final List<Method> preDestroys = finder.findAnnotatedMethods(PreDestroy.class);
final 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();
- this.bindResource(resourceInfo.id, resource);
+ CreationalContext<?> creationalContext = null;
+ Object originalResource = null;
+ if (!postConstructs.isEmpty() || initialize) {
+ originalResource = containerSystemContext.lookup(OPENEJB_RESOURCE_JNDI_PREFIX + resourceInfo.id);
+ Object resource = originalResource;
+ if (resource instanceof Reference) {
+ resource = unwrapReference(resource);
+ this.bindResource(resourceInfo.id, resource, true);
}
try {
// wire up CDI
- OWBInjector.inject(appContext.getBeanManager(),
- resource,
- appContext.getBeanManager().createCreationalContext(null));
+ if (appContext != null) {
+ final BeanManagerImpl beanManager = appContext.getWebBeansContext().getBeanManagerImpl();
+ if (beanManager.isInUse()) {
+ creationalContext = beanManager.createCreationalContext(null);
+ OWBInjector.inject(beanManager, resource, creationalContext);
+ }
+ }
- if (postConstruct != null) {
- postConstruct.invoke(resource);
+ if (resourceInfo.postConstruct != null) {
+ final Method p = clazz.getDeclaredMethod(resourceInfo.postConstruct);
+ if (!p.isAccessible()) {
+ SetAccessible.on(p);
+ }
+ p.invoke(resource);
+ }
+
+ for (final Method m : postConstructs) {
+ if (!m.isAccessible()) {
+ SetAccessible.on(m);
+ }
+ m.invoke(resource);
}
- } catch (Exception e) {
+ } catch (final Exception e) {
logger.fatal("Error calling @PostConstruct method on " + resource.getClass().getName());
throw new OpenEJBException(e);
}
}
- } catch (Exception e) {
+
+ if (resourceInfo.preDestroy != null) {
+ final Method p = clazz.getDeclaredMethod(resourceInfo.preDestroy);
+ if (!p.isAccessible()) {
+ SetAccessible.on(p);
+ }
+ preDestroys.add(p);
+ }
+
+ if (!preDestroys.isEmpty() || creationalContext != null) {
+ final String name = OPENEJB_RESOURCE_JNDI_PREFIX + resourceInfo.id;
+ if (originalResource == null) {
+ originalResource = containerSystemContext.lookup(name);
+ }
+ this.bindResource(resourceInfo.id, new ResourceInstance(name, originalResource, preDestroys, creationalContext), true);
+ }
+ } catch (final Exception e) {
logger.fatal("Error calling @PostConstruct method on " + resourceInfo.id);
throw new OpenEJBException(e);
}
}
} finally {
- Thread.currentThread().setContextClassLoader(oldCl);
+ thread.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 {
// used lazily by JaxWsServiceObjectFactory so merge both to keep same config
// note: we could do the same for resources
@@ -1761,7 +1794,7 @@ public class Assembler extends AssemblerTool implements org.apache.openejb.spi.A
private void destroyResource(final String name, final String className, final Object object) {
- Method preDestroy = null;
+ Collection<Method> preDestroy = null;
if (object instanceof ResourceAdapterReference) {
final ResourceAdapterReference resourceAdapter = (ResourceAdapterReference) object;
@@ -1821,13 +1854,6 @@ public class Assembler extends AssemblerTool implements org.apache.openejb.spi.A
} catch (final RuntimeException e) {
logger.error(e.getMessage(), e);
}
- } else if ((preDestroy = findPreDestroy(object)) != null) {
- logger.debug("Calling @PreDestroy on: " + className);
- try {
- preDestroy.invoke(object);
- } catch (final Exception e) {
- logger.error(e.getMessage(), e);
- }
} else if (logger.isDebugEnabled() && !DataSource.class.isInstance(object)) {
logger.debug("Not processing resource on destroy: " + className);
}
@@ -1848,18 +1874,19 @@ public class Assembler extends AssemblerTool implements org.apache.openejb.spi.A
}
}
- private Method findPreDestroy(final Object object) {
- try {
- Object resource = object;
- if (LazyResource.class.isInstance(resource) && LazyResource.class.cast(resource).isInitialized()) {
- resource = LazyResource.class.cast(resource).getObject();
+ private static Object unwrapReference(final Object object) {
+ Object o = object;
+ while (o != null && Reference.class.isInstance(o)) {
+ try {
+ o = Reference.class.cast(o).getObject();
+ } catch (final NamingException e) {
+ // break
}
-
- final Class<? extends Object> cls = resource.getClass();
- return findMethodAnnotatedWith(PreDestroy.class, cls);
- } catch (Exception e) {
- return null;
}
+ if (o == null) {
+ o = object;
+ }
+ return o;
}
public void destroyApplication(final String filePath) throws UndeployException, NoSuchApplicationException {
@@ -2539,9 +2566,9 @@ public class Assembler extends AssemblerTool implements org.apache.openejb.spi.A
newLazyResource(serviceInfo) :
doCreateResource(serviceInfo);
- bindResource(serviceInfo.id, service);
+ bindResource(serviceInfo.id, service, false);
for (final String alias : serviceInfo.aliases) {
- bindResource(alias, service);
+ bindResource(alias, service, false);
}
if (serviceInfo.originAppName != null && !serviceInfo.originAppName.isEmpty() && !"/".equals(serviceInfo.originAppName)
&& !serviceInfo.id.startsWith("global")) {
@@ -2549,7 +2576,7 @@ public class Assembler extends AssemblerTool implements org.apache.openejb.spi.A
serviceInfo.aliases.add(baseJndiName);
final ContextualJndiReference ref = new ContextualJndiReference(baseJndiName);
ref.addPrefix(serviceInfo.originAppName);
- bindResource(baseJndiName, ref);
+ bindResource(baseJndiName, ref, false);
}
// Update the config tree
@@ -2812,7 +2839,7 @@ public class Assembler extends AssemblerTool implements org.apache.openejb.spi.A
return service;
}
- private void bindResource(final String id, final Object service) throws OpenEJBException {
+ private void bindResource(final String id, final Object service, final boolean canReplace) throws OpenEJBException {
final String name = OPENEJB_RESOURCE_JNDI_PREFIX + id;
final Context jndiContext = containerSystem.getJNDIContext();
Object existing = null;
@@ -2835,12 +2862,21 @@ public class Assembler extends AssemblerTool implements org.apache.openejb.spi.A
} else if (existingIsContextual && !serviceIsExisting) {
ContextualJndiReference.class.cast(existing).setDefaultValue(service);
} else if (existingIsContextual) { // && serviceIsExisting is always true here
- ContextualJndiReference.class.cast(existing).addPrefix(ContextualJndiReference.class.cast(service).lastPrefix());
+ final ContextualJndiReference contextual = ContextualJndiReference.class.cast(existing);
+ if (canReplace && contextual.prefixesSize() == 1) { // replace!
+ contextual.removePrefix(contextual.lastPrefix());
+ contextual.setDefaultValue(service);
+ } else {
+ contextual.addPrefix(ContextualJndiReference.class.cast(service).lastPrefix());
+ }
return;
}
}
try {
+ if (canReplace && existing != null) {
+ jndiContext.unbind(name);
+ }
if (rebind) {
jndiContext.rebind(name, service);
} else {
@@ -3280,4 +3316,55 @@ public class Assembler extends AssemblerTool implements org.apache.openejb.spi.A
}
}
}
+
+ public static class ResourceInstance extends Reference implements Serializable, DestroyableResource {
+ private final String name;
+ private final Object delegate;
+ private transient final Collection<Method> preDestroys;
+ private transient final CreationalContext<?> context;
+
+ public ResourceInstance(final String name, final Object delegate, final Collection<Method> preDestroys, final CreationalContext<?> context) {
+ this.name = name;
+ this.delegate = delegate;
+ this.preDestroys = preDestroys;
+ this.context = context;
+ }
+
+ @Override
+ public Object getObject() throws NamingException {
+ return delegate;
+ }
+
+ @Override
+ public void destroyResource() {
+ final Object o = unwrapReference(delegate);
+ for (final Method m : preDestroys) {
+ try {
+ if (!m.isAccessible()) {
+ SetAccessible.on(m);
+ }
+ m.invoke(o);
+ } catch (final Exception e) {
+ SystemInstance.get().getComponent(Assembler.class).logger.error(e.getMessage(), e);
+ }
+ }
+ try {
+ if (context != null) {
+ context.release();
+ }
+ } catch (final Exception e) {
+ // no-op
+ }
+ }
+
+ // we don't care unwrapping the resource here since we want to keep ResourceInstance data for destruction
+ // which is never serialized (IvmContext)
+ Object readResolve() throws ObjectStreamException {
+ try {
+ return SystemInstance.get().getComponent(ContainerSystem.class).getJNDIContext().lookup(name);
+ } catch (final NamingException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+ }
}
http://git-wip-us.apache.org/repos/asf/tomee/blob/2a29aef9/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/ResourceInfo.java
----------------------------------------------------------------------
diff --git a/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/ResourceInfo.java b/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/ResourceInfo.java
index 502947e..c24ae24 100644
--- a/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/ResourceInfo.java
+++ b/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/ResourceInfo.java
@@ -22,6 +22,8 @@ import java.util.List;
public class ResourceInfo extends ServiceInfo {
public String jndiName = "";
+ public String postConstruct;
+ public String preDestroy;
public String originAppName; // if define by an app
public List<String> aliases = new ArrayList<String>();
}
http://git-wip-us.apache.org/repos/asf/tomee/blob/2a29aef9/container/openejb-core/src/main/java/org/apache/openejb/config/ConfigurationFactory.java
----------------------------------------------------------------------
diff --git a/container/openejb-core/src/main/java/org/apache/openejb/config/ConfigurationFactory.java b/container/openejb-core/src/main/java/org/apache/openejb/config/ConfigurationFactory.java
index 075c76a..bfbbc84 100644
--- a/container/openejb-core/src/main/java/org/apache/openejb/config/ConfigurationFactory.java
+++ b/container/openejb-core/src/main/java/org/apache/openejb/config/ConfigurationFactory.java
@@ -773,10 +773,13 @@ public class ConfigurationFactory implements OpenEjbConfigurationFactory {
}
if (object instanceof Resource) {
+ final Resource resource = Resource.class.cast(object);
final String aliases = map.remove("aliases");
if (aliases != null) {
- ((Resource) object).getAliases().addAll(Arrays.asList(aliases.split(",")));
+ resource.getAliases().addAll(Arrays.asList(aliases.split(",")));
}
+ resource.setPostConstruct(map.remove("post-construct"));
+ resource.setPreDestroy(map.remove("pre-destroy"));
}
service.getProperties().putAll(map);
@@ -1230,8 +1233,12 @@ public class ConfigurationFactory implements OpenEjbConfigurationFactory {
info.properties = props;
info.constructorArgs.addAll(parseConstructorArgs(provider));
if (info instanceof ResourceInfo && service instanceof Resource) {
- ((ResourceInfo) info).jndiName = ((Resource) service).getJndi();
- ((ResourceInfo) info).aliases.addAll(((Resource) service).getAliases());
+ final ResourceInfo ri = ResourceInfo.class.cast(info);
+ final Resource resource = Resource.class.cast(service);
+ ri.jndiName = resource.getJndi();
+ ri.postConstruct = resource.getPostConstruct();
+ ri.preDestroy = resource.getPreDestroy();
+ ri.aliases.addAll(resource.getAliases());
}
if (service.getClasspath() != null && service.getClasspath().length() > 0) {
http://git-wip-us.apache.org/repos/asf/tomee/blob/2a29aef9/container/openejb-core/src/main/java/org/apache/openejb/config/sys/Resource.java
----------------------------------------------------------------------
diff --git a/container/openejb-core/src/main/java/org/apache/openejb/config/sys/Resource.java b/container/openejb-core/src/main/java/org/apache/openejb/config/sys/Resource.java
index 2e651f6..f953be7 100644
--- a/container/openejb-core/src/main/java/org/apache/openejb/config/sys/Resource.java
+++ b/container/openejb-core/src/main/java/org/apache/openejb/config/sys/Resource.java
@@ -52,6 +52,12 @@ public class Resource extends AbstractService {
@XmlAttribute
protected String jndi;
+ @XmlAttribute(name = "post-construct")
+ protected String postConstruct;
+
+ @XmlAttribute(name = "pre-destroy")
+ protected String preDestroy;
+
@XmlElement(name = "aliases")
protected List<String> aliases = new ArrayList<String>();
@@ -94,6 +100,22 @@ public class Resource extends AbstractService {
return aliases;
}
+ public String getPostConstruct() {
+ return postConstruct;
+ }
+
+ public void setPostConstruct(final String postConstruct) {
+ this.postConstruct = postConstruct;
+ }
+
+ public String getPreDestroy() {
+ return preDestroy;
+ }
+
+ public void setPreDestroy(final String preDestroy) {
+ this.preDestroy = preDestroy;
+ }
+
@Override
public boolean equals(final Object o) {
if (this == o) {
http://git-wip-us.apache.org/repos/asf/tomee/blob/2a29aef9/container/openejb-core/src/main/java/org/apache/openejb/config/sys/StackHandler.java
----------------------------------------------------------------------
diff --git a/container/openejb-core/src/main/java/org/apache/openejb/config/sys/StackHandler.java b/container/openejb-core/src/main/java/org/apache/openejb/config/sys/StackHandler.java
index 9e23128..77c0c49 100644
--- a/container/openejb-core/src/main/java/org/apache/openejb/config/sys/StackHandler.java
+++ b/container/openejb-core/src/main/java/org/apache/openejb/config/sys/StackHandler.java
@@ -222,6 +222,8 @@ public class StackHandler extends DefaultHandler {
public void startElement(final String uri, final String localName, final String qName, final Attributes attributes) throws SAXException {
super.startElement(uri, localName, qName, attributes);
service.setJndi(attributes.getValue("jndi"));
+ service.setPostConstruct(attributes.getValue("post-construct"));
+ service.setPreDestroy(attributes.getValue("pre-destroy"));
service.setPropertiesProvider(attributes.getValue("property-provider"));
final String aliases = attributes.getValue("aliases");
http://git-wip-us.apache.org/repos/asf/tomee/blob/2a29aef9/container/openejb-core/src/main/java/org/apache/openejb/core/ivm/naming/ContextualJndiReference.java
----------------------------------------------------------------------
diff --git a/container/openejb-core/src/main/java/org/apache/openejb/core/ivm/naming/ContextualJndiReference.java b/container/openejb-core/src/main/java/org/apache/openejb/core/ivm/naming/ContextualJndiReference.java
index f225b3f..cd7e947 100644
--- a/container/openejb-core/src/main/java/org/apache/openejb/core/ivm/naming/ContextualJndiReference.java
+++ b/container/openejb-core/src/main/java/org/apache/openejb/core/ivm/naming/ContextualJndiReference.java
@@ -73,6 +73,10 @@ public class ContextualJndiReference extends IntraVmJndiReference {
return prefixes.isEmpty();
}
+ public int prefixesSize() {
+ return prefixes.size();
+ }
+
@Override
public Object getObject() throws NamingException {
final Boolean rawValue = !followReference.get();
http://git-wip-us.apache.org/repos/asf/tomee/blob/2a29aef9/container/openejb-core/src/test/java/org/apache/openejb/resource/ResourceLifecycleTest.java
----------------------------------------------------------------------
diff --git a/container/openejb-core/src/test/java/org/apache/openejb/resource/ResourceLifecycleTest.java b/container/openejb-core/src/test/java/org/apache/openejb/resource/ResourceLifecycleTest.java
new file mode 100644
index 0000000..8f10ad1
--- /dev/null
+++ b/container/openejb-core/src/test/java/org/apache/openejb/resource/ResourceLifecycleTest.java
@@ -0,0 +1,208 @@
+/*
+ * 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.resource;
+
+import org.apache.openejb.junit.ApplicationComposer;
+import org.apache.openejb.testing.Classes;
+import org.apache.openejb.testing.ContainerProperties;
+import org.apache.openejb.testing.SimpleLog;
+import org.junit.AfterClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Collection;
+import java.util.LinkedList;
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import javax.annotation.Resource;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+@Classes
+@SimpleLog
+@ContainerProperties({
+ @ContainerProperties.Property(name = "postConstructAndPreDestroy", value = "new://Resource?class-name=org.apache.openejb.resource.ResourceLifecycleTest$WithBoth"),
+ @ContainerProperties.Property(name = "postConstructAndPreDestroy.myAttr", value = "done"),
+ @ContainerProperties.Property(name = "postConstructOnly", value = "new://Resource?class-name=org.apache.openejb.resource.ResourceLifecycleTest$WithPostConstruct"),
+ @ContainerProperties.Property(name = "postConstructOnly.myAttr", value = "done"),
+ @ContainerProperties.Property(name = "postConstructAnnotationAndConfigOnly", value = "new://Resource?class-name=org.apache.openejb.resource.ResourceLifecycleTest$WithPostConstruct&post-construct=init2"),
+ @ContainerProperties.Property(name = "postConstructAnnotationAndConfigOnly.myAttr", value = "done"),
+ @ContainerProperties.Property(name = "preDestroyOnly", value = "new://Resource?class-name=org.apache.openejb.resource.ResourceLifecycleTest$WithPreDestroy"),
+ @ContainerProperties.Property(name = "preDestroyOnly.myAttr", value = "done"),
+ @ContainerProperties.Property(name = "preDestroyAnnotationAndConfigOnly", value = "new://Resource?class-name=org.apache.openejb.resource.ResourceLifecycleTest$WithPreDestroy&pre-destroy=init2"),
+ @ContainerProperties.Property(name = "preDestroyAnnotationAndConfigOnly.myAttr", value = "done"),
+})
+@RunWith(ApplicationComposer.class)
+public class ResourceLifecycleTest {
+ @Resource(name = "postConstructAndPreDestroy")
+ private WithBoth both;
+
+ @Resource(name = "postConstructOnly")
+ private WithPostConstruct postConstruct;
+
+ @Resource(name = "postConstructAnnotationAndConfigOnly")
+ private WithPostConstruct postConstruct2;
+
+ @Resource(name = "preDestroyOnly")
+ private WithPreDestroy preDestroy;
+
+ @Resource(name = "preDestroyAnnotationAndConfigOnly")
+ private WithPreDestroy preDestroy2;
+
+ private static final Collection<Runnable> POST_CONTAINER_VALIDATIONS = new LinkedList<>();
+
+ @AfterClass
+ public static void lastValidations() { // late to make the test failing (ie junit report will be broken) but better than destroying eagerly the resource
+ for (final Runnable runnable : POST_CONTAINER_VALIDATIONS) {
+ runnable.run();
+ }
+ POST_CONTAINER_VALIDATIONS.clear();
+ }
+
+ @Test
+ public void postConstructOnly() {
+ assertNotNull(postConstruct);
+ assertTrue(postConstruct.isInit());
+ assertFalse(postConstruct.isInit2());
+ assertEquals("done", postConstruct.myAttr);
+ }
+
+ @Test
+ public void postConstructAnnotationAndConfigOnly() {
+ assertNotNull(postConstruct2);
+ assertTrue(postConstruct2.isInit());
+ assertTrue(postConstruct2.isInit2());
+ assertEquals("done", postConstruct2.myAttr);
+ }
+
+ @Test
+ public void preDestroyOnly() {
+ assertNotNull(preDestroy);
+ assertFalse(preDestroy.isDestroy());
+ assertFalse(preDestroy.isDestroy2());
+ assertEquals("done", preDestroy.myAttr);
+ POST_CONTAINER_VALIDATIONS.add(new Runnable() {
+ @Override
+ public void run() {
+ assertTrue(preDestroy.isDestroy());
+ }
+ });
+ }
+
+ @Test
+ public void preDestroyAnnotationAndConfigOnly() {
+ assertNotNull(preDestroy2);
+ assertFalse(preDestroy2.isDestroy());
+ assertFalse(preDestroy2.isDestroy2());
+ assertEquals("done", preDestroy2.myAttr);
+ POST_CONTAINER_VALIDATIONS.add(new Runnable() {
+ @Override
+ public void run() {
+ assertTrue(preDestroy2.isDestroy());
+ assertTrue(preDestroy2.isDestroy2());
+ }
+ });
+ }
+
+ @Test
+ public void postConstructAndPreDestroy() {
+ assertNotNull(both);
+ assertTrue(both.isInit());
+ assertFalse(both.isDestroy());
+ assertEquals("done", both.myAttr);
+ POST_CONTAINER_VALIDATIONS.add(new Runnable() {
+ @Override
+ public void run() {
+ assertTrue(both.isDestroy());
+ }
+ });
+ }
+
+ public static class TrivialConfigToCheckWarnings {
+ protected String myAttr;
+ }
+
+ public static class WithBoth extends TrivialConfigToCheckWarnings {
+ private boolean init;
+ private boolean destroy;
+
+ @PostConstruct
+ private void init() {
+ init = true;
+ }
+
+ @PreDestroy
+ private void init2() {
+ destroy = true;
+ }
+
+ public boolean isInit() {
+ return init;
+ }
+
+ public boolean isDestroy() {
+ return destroy;
+ }
+ }
+
+ public static class WithPostConstruct extends TrivialConfigToCheckWarnings {
+ private boolean init;
+ private boolean init2;
+
+ @PostConstruct
+ private void init() {
+ init = true;
+ }
+
+ private void init2() {
+ init2 = true;
+ }
+
+ public boolean isInit() {
+ return init;
+ }
+
+ public boolean isInit2() {
+ return init2;
+ }
+ }
+
+ public static class WithPreDestroy extends TrivialConfigToCheckWarnings {
+ private boolean destroy;
+ private boolean destroy2;
+
+ @PreDestroy
+ private void init() {
+ destroy = true;
+ }
+
+ private void init2() {
+ destroy2 = true;
+ }
+
+ public boolean isDestroy() {
+ return destroy;
+ }
+
+ public boolean isDestroy2() {
+ return destroy2;
+ }
+ }
+}