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 2017/03/01 18:01:31 UTC

tomee git commit: TOMEE-2018 connectionFactoryLookup and destinationLookup not supported for mdbs

Repository: tomee
Updated Branches:
  refs/heads/master 4983a0d45 -> 9fa28a270


TOMEE-2018 connectionFactoryLookup and destinationLookup not supported for mdbs


Project: http://git-wip-us.apache.org/repos/asf/tomee/repo
Commit: http://git-wip-us.apache.org/repos/asf/tomee/commit/9fa28a27
Tree: http://git-wip-us.apache.org/repos/asf/tomee/tree/9fa28a27
Diff: http://git-wip-us.apache.org/repos/asf/tomee/diff/9fa28a27

Branch: refs/heads/master
Commit: 9fa28a270008e8ff717cb6f750683a803f6d72dd
Parents: 4983a0d
Author: rmannibucau <rm...@apache.org>
Authored: Wed Mar 1 19:01:03 2017 +0100
Committer: rmannibucau <rm...@apache.org>
Committed: Wed Mar 1 19:01:03 2017 +0100

----------------------------------------------------------------------
 .../org/apache/openejb/config/AutoConfig.java   |  12 ++
 .../apache/openejb/core/mdb/MdbContainer.java   |   2 +
 .../activemq/ActiveMQResourceAdapter.java       |  74 ++++++++++
 .../activemq/TomEEMessageActivationSpec.java    |  31 ++++
 .../activemq/jms2/cdi/JMS2CDIExtension.java     |  28 +++-
 .../openejb/util/reflection/Reflections.java    |   9 +-
 .../META-INF/org.apache.openejb/service-jar.xml |   2 +-
 .../apache/openejb/activemq/MDBSpecTest.java    | 142 +++++++++++++++++++
 8 files changed, 292 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tomee/blob/9fa28a27/container/openejb-core/src/main/java/org/apache/openejb/config/AutoConfig.java
----------------------------------------------------------------------
diff --git a/container/openejb-core/src/main/java/org/apache/openejb/config/AutoConfig.java b/container/openejb-core/src/main/java/org/apache/openejb/config/AutoConfig.java
index 0653f4d..5639b36 100644
--- a/container/openejb-core/src/main/java/org/apache/openejb/config/AutoConfig.java
+++ b/container/openejb-core/src/main/java/org/apache/openejb/config/AutoConfig.java
@@ -427,6 +427,10 @@ public class AutoConfig implements DynamicDeployer, JndiConstants {
                     destination = properties.getProperty("destination");
                 }
 
+                if (destination == null) { // EE 7/EJB 3.2
+                    destination = properties.getProperty("destinationLookup");
+                }
+
                 // destination
                 //                String destination = properties.getProperty("destination", properties.getProperty("destinationName"));
                 if (destination == null) {
@@ -2007,6 +2011,14 @@ public class AutoConfig implements DynamicDeployer, JndiConstants {
             return id;
         }
 
+        // app resources
+        if (appResources.appId != null && !appResources.appId.isEmpty() && resourceId.startsWith(appResources.appId + '/')) {
+            id = findResourceId(resourceId.substring(appResources.appId.length() + 1), type, required, appResources);
+            if (id != null) {
+                return id;
+            }
+        }
+
         // throw an exception or log an error
         final String shortName = toShortName(resourceId);
         final String message = "No existing resource found while attempting to Auto-link unmapped resource-ref '" +

http://git-wip-us.apache.org/repos/asf/tomee/blob/9fa28a27/container/openejb-core/src/main/java/org/apache/openejb/core/mdb/MdbContainer.java
----------------------------------------------------------------------
diff --git a/container/openejb-core/src/main/java/org/apache/openejb/core/mdb/MdbContainer.java b/container/openejb-core/src/main/java/org/apache/openejb/core/mdb/MdbContainer.java
index 5223db2..389d228 100644
--- a/container/openejb-core/src/main/java/org/apache/openejb/core/mdb/MdbContainer.java
+++ b/container/openejb-core/src/main/java/org/apache/openejb/core/mdb/MdbContainer.java
@@ -216,6 +216,8 @@ public class MdbContainer implements RpcContainer {
             final Set<String> unusedProperties = new TreeSet<String>(objectRecipe.getUnsetProperties().keySet());
             unusedProperties.remove("destination");
             unusedProperties.remove("destinationType");
+            unusedProperties.remove("destinationLookup");
+            unusedProperties.remove("connectionFactoryLookup");
             unusedProperties.remove("beanClass");
             if (!unusedProperties.isEmpty()) {
                 final String text = "No setter found for the activation spec properties: " + unusedProperties;

http://git-wip-us.apache.org/repos/asf/tomee/blob/9fa28a27/container/openejb-core/src/main/java/org/apache/openejb/resource/activemq/ActiveMQResourceAdapter.java
----------------------------------------------------------------------
diff --git a/container/openejb-core/src/main/java/org/apache/openejb/resource/activemq/ActiveMQResourceAdapter.java b/container/openejb-core/src/main/java/org/apache/openejb/resource/activemq/ActiveMQResourceAdapter.java
index 6955035..dde1e2b 100644
--- a/container/openejb-core/src/main/java/org/apache/openejb/resource/activemq/ActiveMQResourceAdapter.java
+++ b/container/openejb-core/src/main/java/org/apache/openejb/resource/activemq/ActiveMQResourceAdapter.java
@@ -17,20 +17,33 @@
 
 package org.apache.openejb.resource.activemq;
 
+import org.apache.activemq.ActiveMQConnection;
 import org.apache.activemq.ActiveMQConnectionFactory;
+import org.apache.activemq.RedeliveryPolicy;
 import org.apache.activemq.broker.BrokerService;
 import org.apache.activemq.ra.ActiveMQConnectionRequestInfo;
+import org.apache.activemq.ra.ActiveMQManagedConnection;
 import org.apache.activemq.ra.MessageActivationSpec;
+import org.apache.openejb.loader.SystemInstance;
+import org.apache.openejb.resource.AutoConnectionTracker;
 import org.apache.openejb.resource.activemq.jms2.TomEEConnectionFactory;
+import org.apache.openejb.resource.activemq.jms2.TomEEManagedConnectionProxy;
+import org.apache.openejb.spi.ContainerSystem;
 import org.apache.openejb.util.Duration;
 import org.apache.openejb.util.LogCategory;
 import org.apache.openejb.util.Logger;
 import org.apache.openejb.util.URISupport;
 import org.apache.openejb.util.URLs;
+import org.apache.openejb.util.reflection.Reflections;
 
+import javax.jms.Connection;
+import javax.jms.JMSException;
+import javax.naming.NamingException;
 import javax.resource.spi.BootstrapContext;
 import javax.resource.spi.ResourceAdapterInternalException;
+import java.lang.reflect.InvocationHandler;
 import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
 import java.net.URISyntaxException;
 import java.util.Collection;
 import java.util.Iterator;
@@ -189,7 +202,68 @@ public class ActiveMQResourceAdapter extends org.apache.activemq.ra.ActiveMQReso
     }
 
     @Override
+    public ActiveMQConnection makeConnection(final MessageActivationSpec activationSpec) throws JMSException {
+        if (TomEEMessageActivationSpec.class.isInstance(activationSpec)) {
+            final TomEEMessageActivationSpec s = TomEEMessageActivationSpec.class.cast(activationSpec);
+            if (s.getConnectionFactoryLookup() != null) {
+                try {
+                    final Object lookup = SystemInstance.get().getComponent(ContainerSystem.class).getJNDIContext()
+                            .lookup("openejb:Resource/" + s.getConnectionFactoryLookup());
+                    if (!ActiveMQConnectionFactory.class.isInstance(lookup)) {
+                        final org.apache.activemq.ra.ActiveMQConnectionFactory connectionFactory = org.apache.activemq.ra.ActiveMQConnectionFactory.class.cast(lookup);
+                        Connection connection = connectionFactory.createConnection();
+                        if (Proxy.isProxyClass(connection.getClass())) { // not great, we should find a better want without bypassing ra layer
+                            final InvocationHandler invocationHandler = Proxy.getInvocationHandler(connection);
+                            if (AutoConnectionTracker.ConnectionInvocationHandler.class.isInstance(invocationHandler)) {
+                                final Object handle = Reflections.get(invocationHandler, "handle");
+                                if (TomEEManagedConnectionProxy.class.isInstance(handle)) {
+                                    final ActiveMQManagedConnection c = ActiveMQManagedConnection.class.cast(Reflections.get(handle, "connection"));
+                                    final ActiveMQConnection physicalConnection = ActiveMQConnection.class.cast(Reflections.get(c, "physicalConnection"));
+                                    final RedeliveryPolicy redeliveryPolicy = activationSpec.redeliveryPolicy();
+                                    if (redeliveryPolicy != null) {
+                                        physicalConnection.setRedeliveryPolicy(redeliveryPolicy);
+                                    }
+                                    return physicalConnection;
+                                }
+                            }
+                        }
+
+                        /*
+                        final RedeliveryPolicy redeliveryPolicy = activationSpec.redeliveryPolicy();
+                        if (redeliveryPolicy != null) {
+                            physicalConnection.setRedeliveryPolicy(redeliveryPolicy);
+                        }
+                        */
+                        return null;
+                    }
+                } catch (final ClassCastException cce) {
+                    throw new java.lang.IllegalStateException(cce);
+                } catch (final NamingException e) {
+                    throw new IllegalArgumentException(e);
+                }
+            }
+        }
+        return super.makeConnection(activationSpec);
+    }
+
+    @Override
     protected ActiveMQConnectionFactory createConnectionFactory(final ActiveMQConnectionRequestInfo connectionRequestInfo, final MessageActivationSpec activationSpec) {
+        if (TomEEMessageActivationSpec.class.isInstance(activationSpec)) {
+            final TomEEMessageActivationSpec s = TomEEMessageActivationSpec.class.cast(activationSpec);
+            if (s.getConnectionFactoryLookup() != null) {
+                try {
+                    final Object lookup = SystemInstance.get().getComponent(ContainerSystem.class).getJNDIContext()
+                            .lookup("openejb:Resource/" + s.getConnectionFactoryLookup());
+                    if (ActiveMQConnectionFactory.class.isInstance(lookup)) {
+                        return ActiveMQConnectionFactory.class.cast(lookup);
+                    }
+                    return ActiveMQConnectionFactory.class.cast(lookup); // already handled
+                } catch (final NamingException e) {
+                    throw new IllegalArgumentException("");
+                }
+            }
+        }
+
         final ActiveMQConnectionFactory factory = new TomEEConnectionFactory();
         connectionRequestInfo.configure(factory, activationSpec);
         return factory;

http://git-wip-us.apache.org/repos/asf/tomee/blob/9fa28a27/container/openejb-core/src/main/java/org/apache/openejb/resource/activemq/TomEEMessageActivationSpec.java
----------------------------------------------------------------------
diff --git a/container/openejb-core/src/main/java/org/apache/openejb/resource/activemq/TomEEMessageActivationSpec.java b/container/openejb-core/src/main/java/org/apache/openejb/resource/activemq/TomEEMessageActivationSpec.java
new file mode 100644
index 0000000..9f30911
--- /dev/null
+++ b/container/openejb-core/src/main/java/org/apache/openejb/resource/activemq/TomEEMessageActivationSpec.java
@@ -0,0 +1,31 @@
+/*
+ * 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.activemq;
+
+import org.apache.activemq.ra.ActiveMQActivationSpec;
+
+public class TomEEMessageActivationSpec extends ActiveMQActivationSpec {
+    private String connectionFactoryLookup;
+
+    public String getConnectionFactoryLookup() {
+        return connectionFactoryLookup;
+    }
+
+    public void setConnectionFactoryLookup(final String connectionFactoryLookup) {
+        this.connectionFactoryLookup = connectionFactoryLookup;
+    }
+}

http://git-wip-us.apache.org/repos/asf/tomee/blob/9fa28a27/container/openejb-core/src/main/java/org/apache/openejb/resource/activemq/jms2/cdi/JMS2CDIExtension.java
----------------------------------------------------------------------
diff --git a/container/openejb-core/src/main/java/org/apache/openejb/resource/activemq/jms2/cdi/JMS2CDIExtension.java b/container/openejb-core/src/main/java/org/apache/openejb/resource/activemq/jms2/cdi/JMS2CDIExtension.java
index a8aef08..98ef326 100644
--- a/container/openejb-core/src/main/java/org/apache/openejb/resource/activemq/jms2/cdi/JMS2CDIExtension.java
+++ b/container/openejb-core/src/main/java/org/apache/openejb/resource/activemq/jms2/cdi/JMS2CDIExtension.java
@@ -86,7 +86,7 @@ public class JMS2CDIExtension implements Extension {
             final JMSPasswordCredential credential = annotated.getAnnotation(JMSPasswordCredential.class);
 
             final String jndi = "openejb:Resource/" +
-                (jmsConnectionFactory == null ? findAnyConnectionFactory() : jmsConnectionFactory.value());
+                (jmsConnectionFactory == null ? findAnyConnectionFactory() : findMatchingConnectionFactory(jmsConnectionFactory.value()));
             return new Key(
                 jndi,
                 credential != null ? credential.userName() : null,
@@ -94,6 +94,32 @@ public class JMS2CDIExtension implements Extension {
                 sessionMode != null ? sessionMode.value() : null);
         }
 
+        private String findMatchingConnectionFactory(final String value) {
+            final OpenEjbConfiguration component = SystemInstance.get().getComponent(OpenEjbConfiguration.class);
+            if (component != null && component.facilities != null) {
+                for (final ResourceInfo ri : component.facilities.resources) {
+                    if (!ri.types.contains("javax.jms.ConnectionFactory")) {
+                        continue;
+                    }
+                    if (ri.id.equals(value)) {
+                        return ri.id;
+                    }
+                }
+                // try application ones
+                for (final ResourceInfo ri : component.facilities.resources) {
+                    if (!ri.types.contains("javax.jms.ConnectionFactory")) {
+                        continue;
+                    }
+                    if (ri.id.endsWith(value)) {
+                        return ri.id;
+                    }
+                }
+            }
+            // something is wrong, just fail
+            throw new IllegalArgumentException(
+                    "No connection factory found, either use @JMSConnectionFactory JMSContext or define a connection factory");
+        }
+
         private String findAnyConnectionFactory() {
             final OpenEjbConfiguration component = SystemInstance.get().getComponent(OpenEjbConfiguration.class);
             if (component != null && component.facilities != null) {

http://git-wip-us.apache.org/repos/asf/tomee/blob/9fa28a27/container/openejb-core/src/main/java/org/apache/openejb/util/reflection/Reflections.java
----------------------------------------------------------------------
diff --git a/container/openejb-core/src/main/java/org/apache/openejb/util/reflection/Reflections.java b/container/openejb-core/src/main/java/org/apache/openejb/util/reflection/Reflections.java
index 250749b..1d0d065 100644
--- a/container/openejb-core/src/main/java/org/apache/openejb/util/reflection/Reflections.java
+++ b/container/openejb-core/src/main/java/org/apache/openejb/util/reflection/Reflections.java
@@ -108,13 +108,10 @@ public final class Reflections {
         while (clazz != null) {
             try {
                 final Field f = clazz.getDeclaredField(field);
-                final boolean acc = f.isAccessible();
-                f.setAccessible(true);
-                try {
-                    return f.get(instance);
-                } finally {
-                    f.setAccessible(acc);
+                if (!f.isAccessible()) {
+                    f.setAccessible(true);
                 }
+                return f.get(instance);
             } catch (final NoSuchFieldException nsfe) {
                 // no-op
             } catch (final Exception e) {

http://git-wip-us.apache.org/repos/asf/tomee/blob/9fa28a27/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 1df40e3..36eb8e0 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
@@ -482,7 +482,7 @@
 
     # Specifies the activation spec class
 
-    ActivationSpecClass org.apache.activemq.ra.ActiveMQActivationSpec
+    ActivationSpecClass org.apache.openejb.resource.activemq.TomEEMessageActivationSpec
 
     # Specifies the maximum number of bean instances that are
     # allowed to exist for each MDB deployment.

http://git-wip-us.apache.org/repos/asf/tomee/blob/9fa28a27/container/openejb-core/src/test/java/org/apache/openejb/activemq/MDBSpecTest.java
----------------------------------------------------------------------
diff --git a/container/openejb-core/src/test/java/org/apache/openejb/activemq/MDBSpecTest.java b/container/openejb-core/src/test/java/org/apache/openejb/activemq/MDBSpecTest.java
new file mode 100644
index 0000000..c0d7876
--- /dev/null
+++ b/container/openejb-core/src/test/java/org/apache/openejb/activemq/MDBSpecTest.java
@@ -0,0 +1,142 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.activemq;
+
+import org.apache.activemq.ra.ActiveMQConnectionRequestInfo;
+import org.apache.activemq.ra.MessageActivationSpec;
+import org.apache.openejb.junit.ApplicationComposer;
+import org.apache.openejb.resource.activemq.ActiveMQResourceAdapter;
+import org.apache.openejb.resource.activemq.TomEEMessageActivationSpec;
+import org.apache.openejb.testing.Classes;
+import org.apache.openejb.testing.Configuration;
+import org.apache.openejb.testing.SimpleLog;
+import org.apache.openejb.testng.PropertiesBuilder;
+import org.apache.openejb.util.reflection.Reflections;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import javax.annotation.Resource;
+import javax.ejb.ActivationConfigProperty;
+import javax.ejb.MessageDriven;
+import javax.inject.Inject;
+import javax.jms.JMSConnectionFactory;
+import javax.jms.JMSConnectionFactoryDefinition;
+import javax.jms.JMSContext;
+import javax.jms.JMSDestinationDefinition;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageListener;
+import javax.jms.Queue;
+import java.util.Properties;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import static org.junit.Assert.assertTrue;
+
+@SimpleLog
+@RunWith(ApplicationComposer.class)
+@Classes(cdi = true, innerClassesAsBean = true)
+public class MDBSpecTest {
+    @Configuration
+    public Properties config() {
+        return new PropertiesBuilder()
+                // .p("openejb.offline", "true") // helpful in dev but not working cause of dynamic resources
+
+                .p("amq", "new://Resource?type=ActiveMQResourceAdapter")
+                .p("amq.DataSource", "")
+                .p("amq.BrokerXmlConfig", "broker:(vm://localhost)")
+
+                .p("mdbs", "new://Container?type=MESSAGE")
+                .p("mdbs.ResourceAdapter", "amq")
+
+                .p("testcontainer", "new://Container?type=MANAGED")
+
+                .build();
+    }
+
+    @Resource(name = "amq")
+    private ActiveMQResourceAdapter amq;
+
+    @Resource(name = "jms/input")
+    private Queue destination;
+
+    @Inject
+    @JMSConnectionFactory("jms/ConnectionFactory")
+    private JMSContext context;
+
+    @Before
+    public void resetLatch() {
+        Listener.reset();
+    }
+
+    @Test
+    public void checkConfig() throws InterruptedException {
+        // first it works in term of communication
+        context.createProducer().send(destination, "hello");
+        assertTrue(Listener.sync());
+
+        // then we should check we don't create a connection factory but use the config one
+        // Note: if you have time use a custom connection factory to have a better tracking, for now it should be good enough otherwise
+    }
+
+    private Object createFactory(final ActiveMQResourceAdapter amq) {
+        return Reflections.invokeByReflection(
+                amq,
+                "createConnectionFactory",
+                new Class<?>[]{ActiveMQConnectionRequestInfo.class, MessageActivationSpec.class},
+                new Object[]{null, new TomEEMessageActivationSpec() {{
+                    setConnectionFactoryLookup("jms/XAConnectionFactory");
+                }}});
+    }
+
+    @JMSDestinationDefinition(name = "jms/input", destinationName = "jms/input", interfaceName = "javax.jms.Queue")
+    @JMSConnectionFactoryDefinition(name = "jms/ConnectionFactory", transactional = false)
+    @MessageDriven(activationConfig = {
+            @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
+            @ActivationConfigProperty(propertyName = "destinationLookup", propertyValue = "jms/input"),
+            @ActivationConfigProperty(propertyName = "connectionFactoryLookup", propertyValue = "jms/ConnectionFactory")
+    })
+    public static class Listener implements MessageListener {
+        public static volatile CountDownLatch latch;
+        public static volatile boolean ok = false;
+
+        @Override
+        public void onMessage(final Message message) {
+            try {
+                try {
+                    final String body = message.getBody(String.class);
+                    ok = "hello".equals(body);
+                } catch (final JMSException e) {
+                    // no-op
+                }
+            } finally {
+                latch.countDown();
+            }
+        }
+
+        public static void reset() {
+            latch = new CountDownLatch(1);
+            ok = false;
+        }
+
+        public static boolean sync() throws InterruptedException {
+            latch.await(1, TimeUnit.MINUTES);
+            return ok;
+        }
+    }
+}