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 2016/06/09 08:13:23 UTC
tomee git commit: TOMEE-1836 resource lifecycle events
Repository: tomee
Updated Branches:
refs/heads/master ed862e9b0 -> f9da4b38d
TOMEE-1836 resource lifecycle events
Project: http://git-wip-us.apache.org/repos/asf/tomee/repo
Commit: http://git-wip-us.apache.org/repos/asf/tomee/commit/f9da4b38
Tree: http://git-wip-us.apache.org/repos/asf/tomee/tree/f9da4b38
Diff: http://git-wip-us.apache.org/repos/asf/tomee/diff/f9da4b38
Branch: refs/heads/master
Commit: f9da4b38da7349fcd5123b293e01ef95c02927ad
Parents: ed862e9
Author: Romain manni-Bucau <rm...@gmail.com>
Authored: Thu Jun 9 10:13:01 2016 +0200
Committer: Romain manni-Bucau <rm...@gmail.com>
Committed: Thu Jun 9 10:13:01 2016 +0200
----------------------------------------------------------------------
.../openejb/assembler/classic/Assembler.java | 21 ++-
.../classic/event/ResourceBeforeDestroyed.java | 35 +++++
.../classic/event/ResourceCreated.java | 26 ++++
.../assembler/classic/event/ResourceEvent.java | 71 ++++++++++
.../classic/event/ResourceEventsTest.java | 136 +++++++++++++++++++
5 files changed, 285 insertions(+), 4 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/tomee/blob/f9da4b38/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 6d33d0b..d316dac 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
@@ -48,6 +48,8 @@ import org.apache.openejb.assembler.classic.event.AssemblerDestroyed;
import org.apache.openejb.assembler.classic.event.BeforeStartEjbs;
import org.apache.openejb.assembler.classic.event.ContainerSystemPostCreate;
import org.apache.openejb.assembler.classic.event.ContainerSystemPreDestroy;
+import org.apache.openejb.assembler.classic.event.ResourceCreated;
+import org.apache.openejb.assembler.classic.event.ResourceBeforeDestroyed;
import org.apache.openejb.assembler.classic.util.ServiceInfos;
import org.apache.openejb.assembler.monitoring.JMXContainer;
import org.apache.openejb.async.AsynchronousPool;
@@ -1965,7 +1967,10 @@ public class Assembler extends AssemblerTool implements org.apache.openejb.spi.A
removeResourceInfo(name);
}
- private void doResourceDestruction(final String name, final String className, final Object object) {
+ private void doResourceDestruction(final String name, final String className, final Object jndiObject) {
+ final ResourceBeforeDestroyed event = new ResourceBeforeDestroyed(jndiObject, name);
+ SystemInstance.get().fireEvent(event);
+ final Object object = event.getReplacement() == null ? jndiObject : event.getReplacement();
if (object instanceof ResourceAdapterReference) {
final ResourceAdapterReference resourceAdapter = (ResourceAdapterReference) object;
try {
@@ -2955,7 +2960,7 @@ public class Assembler extends AssemblerTool implements org.apache.openejb.spi.A
Object service = serviceRecipe.create(loader);
if (customLoader) {
- final Collection<Class<?>> apis = new ArrayList<>(Arrays.asList(service.getClass().getInterfaces()));
+ final Collection<Class<?>> apis = new ArrayList<Class<?>>(Arrays.asList(service.getClass().getInterfaces()));
if (apis.size() - (apis.contains(Serializable.class) ? 1 : 0) - (apis.contains(Externalizable.class) ? 1 : 0) > 0) {
service = Proxy.newProxyInstance(loader, apis.toArray(new Class<?>[apis.size()]), new ClassLoaderAwareHandler(null, service, loader));
@@ -3129,7 +3134,10 @@ public class Assembler extends AssemblerTool implements org.apache.openejb.spi.A
logUnusedProperties(serviceRecipe, serviceInfo);
} // else wait post construct
}
- return service;
+
+ final ResourceCreated event = new ResourceCreated(service, serviceInfo.id);
+ SystemInstance.get().fireEvent(event);
+ return event.getReplacement() == null ? service : event.getReplacement();
}
private void bindResource(final String id, final Object service, final boolean canReplace) throws OpenEJBException {
@@ -3672,6 +3680,7 @@ public class Assembler extends AssemblerTool implements org.apache.openejb.spi.A
private final Object delegate;
private final transient Collection<Method> preDestroys;
private final transient CreationalContext<?> context;
+ private volatile boolean destroyed = false;
public ResourceInstance(final String name, final Object delegate, final Collection<Method> preDestroys, final CreationalContext<?> context) {
this.name = name;
@@ -3686,7 +3695,10 @@ public class Assembler extends AssemblerTool implements org.apache.openejb.spi.A
}
@Override
- public void destroyResource() {
+ public synchronized void destroyResource() {
+ if (destroyed) {
+ return;
+ }
final Object o = unwrapReference(delegate);
for (final Method m : preDestroys) {
try {
@@ -3710,6 +3722,7 @@ public class Assembler extends AssemblerTool implements org.apache.openejb.spi.A
} catch (final Exception e) {
// no-op
}
+ destroyed = true;
}
// we don't care unwrapping the resource here since we want to keep ResourceInstance data for destruction
http://git-wip-us.apache.org/repos/asf/tomee/blob/f9da4b38/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/event/ResourceBeforeDestroyed.java
----------------------------------------------------------------------
diff --git a/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/event/ResourceBeforeDestroyed.java b/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/event/ResourceBeforeDestroyed.java
new file mode 100644
index 0000000..a15748a
--- /dev/null
+++ b/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/event/ResourceBeforeDestroyed.java
@@ -0,0 +1,35 @@
+/*
+ * 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.event;
+
+import org.apache.openejb.assembler.classic.Assembler;
+import org.apache.openejb.observer.Event;
+
+@Event
+public class ResourceBeforeDestroyed extends ResourceEvent {
+ public ResourceBeforeDestroyed(final Object resource, final String name) {
+ super(name, resource);
+ }
+
+ @Override
+ public void replaceBy(final Object newResource) {
+ if (Assembler.ResourceInstance.class.isInstance(resource)) {
+ Assembler.ResourceInstance.class.cast(resource).destroyResource();
+ }
+ super.replaceBy(newResource);
+ }
+}
http://git-wip-us.apache.org/repos/asf/tomee/blob/f9da4b38/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/event/ResourceCreated.java
----------------------------------------------------------------------
diff --git a/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/event/ResourceCreated.java b/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/event/ResourceCreated.java
new file mode 100644
index 0000000..17b7c05
--- /dev/null
+++ b/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/event/ResourceCreated.java
@@ -0,0 +1,26 @@
+/*
+ * 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.event;
+
+import org.apache.openejb.observer.Event;
+
+@Event
+public class ResourceCreated extends ResourceEvent{
+ public ResourceCreated(final Object resource, final String name) {
+ super(name, resource);
+ }
+}
http://git-wip-us.apache.org/repos/asf/tomee/blob/f9da4b38/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/event/ResourceEvent.java
----------------------------------------------------------------------
diff --git a/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/event/ResourceEvent.java b/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/event/ResourceEvent.java
new file mode 100644
index 0000000..12f851b
--- /dev/null
+++ b/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/event/ResourceEvent.java
@@ -0,0 +1,71 @@
+/*
+ * 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.event;
+
+import org.apache.openejb.assembler.classic.Assembler;
+
+import javax.naming.NamingException;
+
+public abstract class ResourceEvent {
+ protected final String name;
+ protected final Object resource;
+ protected Object replacement;
+
+ protected ResourceEvent(final String name, final Object resource) {
+ this.name = name;
+ this.resource = resource;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public Object getRawResource() {
+ return resource;
+ }
+
+ public Object getResource() {
+ try {
+ return !Assembler.ResourceInstance.class.isInstance(resource) ? resource : Assembler.ResourceInstance.class.cast(resource).getObject();
+ } catch (final NamingException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ public boolean is(final Class<?> type) {
+ try {
+ return type.isInstance(resource) ||
+ (Assembler.ResourceInstance.class.isInstance(resource) &&
+ type.isInstance(Assembler.ResourceInstance.class.cast(resource).getObject()));
+ } catch (final NamingException e) {
+ return false;
+ }
+ }
+
+ public void replaceBy(final Object newResource) {
+ this.replacement = newResource;
+ }
+
+ public Object getReplacement() {
+ return replacement;
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() + "{" + name + "}";
+ }
+}
http://git-wip-us.apache.org/repos/asf/tomee/blob/f9da4b38/container/openejb-core/src/test/java/org/apache/openejb/assembler/classic/event/ResourceEventsTest.java
----------------------------------------------------------------------
diff --git a/container/openejb-core/src/test/java/org/apache/openejb/assembler/classic/event/ResourceEventsTest.java b/container/openejb-core/src/test/java/org/apache/openejb/assembler/classic/event/ResourceEventsTest.java
new file mode 100644
index 0000000..34a6f36
--- /dev/null
+++ b/container/openejb-core/src/test/java/org/apache/openejb/assembler/classic/event/ResourceEventsTest.java
@@ -0,0 +1,136 @@
+/*
+ * 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.event;
+
+import org.apache.openejb.assembler.classic.Assembler;
+import org.apache.openejb.observer.Observes;
+import org.apache.openejb.testing.ApplicationComposers;
+import org.apache.openejb.testing.Classes;
+import org.apache.openejb.testing.ContainerProperties;
+import org.apache.openejb.testing.SimpleLog;
+import org.junit.Test;
+
+import javax.annotation.PreDestroy;
+import javax.annotation.Resource;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Callable;
+
+import static java.util.Collections.singleton;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+@Classes
+@SimpleLog
+@ContainerProperties({
+ @ContainerProperties.Property(name = "test", value = "new://Service?class-name=org.apache.openejb.assembler.classic.event.ResourceEventsTest$Listener"),
+ @ContainerProperties.Property(name = "base", value = "new://Resource?class-name=org.apache.openejb.assembler.classic.event.ResourceEventsTest$Base"),
+ @ContainerProperties.Property(name = "base2", value = "new://Resource?class-name=org.apache.openejb.assembler.classic.event.ResourceEventsTest$Base"),
+})
+public class ResourceEventsTest {
+ @Resource(name = "base")
+ private Base base;
+
+ @Resource(name = "base2")
+ private Base base2;
+
+ @Test
+ public void run() throws Exception {
+ Listener.EVENTS.clear();
+ new ApplicationComposers(this).evaluate(this, new Callable<Object>() {
+ @Override
+ public Object call() throws Exception {
+ assertEquals(2, Listener.EVENTS.size());
+ for (final ResourceEvent re : Listener.EVENTS) {
+ assertTrue(ResourceCreated.class.isInstance(re));
+ assertNotNull(re.getResource());
+ assertTrue("base".equals(re.getName()) || "base2".equals(re.getName()));
+ }
+ Listener.EVENTS.clear();
+ assertTrue(Child.class.isInstance(base));
+ assertFalse(Child.class.isInstance(base2));
+ assertNotNull(Child.class.cast(base).parent);
+ return null;
+ }
+ });
+ assertEquals(2, Listener.EVENTS.size());
+ for (final ResourceEvent re : Listener.EVENTS) {
+ assertTrue(ResourceBeforeDestroyed.class.isInstance(re));
+
+ Object resource = re.getResource();
+ if (Assembler.ResourceInstance.class.isInstance(resource)) {
+ resource = Assembler.ResourceInstance.class.cast(resource).getObject();
+ }
+
+ assertNotNull(resource);
+ assertTrue("base".equals(re.getName()) || "base2".equals(re.getName()));
+ if ("base".equals(re.getName())) {
+ assertTrue(Child.class.isInstance(resource));
+ } else {
+ assertFalse(Child.class.isInstance(resource));
+ assertTrue(Base.class.isInstance(resource));
+ }
+ }
+ Listener.EVENTS.clear();
+ assertTrue(base2.stopped);
+ assertTrue(base.stopped);
+ assertTrue(Base.class.cast(Child.class.cast(base).parent).stopped);
+ }
+
+ public static class Base {
+ private boolean stopped = false;
+
+ @PreDestroy
+ public void stop() {
+ stopped = true;
+ }
+ }
+
+ public static class Child extends Base {
+ private final Object parent;
+
+ Child(final Object resource) {
+ parent = resource;
+ }
+ }
+
+ public static class Listener {
+ private static final List<ResourceEvent> EVENTS = new ArrayList<>();
+
+ public void onCreated(@Observes final ResourceCreated created) {
+ EVENTS.add(created);
+ if (created.is(Base.class) && "base".equals(created.getName())) {
+ created.replaceBy(new Child(created.getResource()));
+ }
+ }
+
+ public void onDestroyed(@Observes final ResourceBeforeDestroyed destroyed) {
+ EVENTS.add(destroyed);
+ if (destroyed.is(Base.class) && destroyed.is(Child.class) && "base".equals(destroyed.getName())) {
+ final Object parent = Child.class.cast(destroyed.getResource()).parent;
+ try {
+ destroyed.replaceBy(new Assembler.ResourceInstance("base", parent, singleton(Base.class.getMethod("stop")), null));
+ } catch (final NoSuchMethodException e) {
+ fail(e.getMessage());
+ }
+ }
+ }
+ }
+}