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());
+                }
+            }
+        }
+    }
+}