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/09/20 15:22:33 UTC

tomee git commit: TOMEE-1938 @JMSDestinationConfiguration

Repository: tomee
Updated Branches:
  refs/heads/master a3e90ee23 -> 246af9a56


TOMEE-1938 @JMSDestinationConfiguration


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

Branch: refs/heads/master
Commit: 246af9a5640b53ab2c43361dc57cac2c446ecd28
Parents: a3e90ee
Author: Romain manni-Bucau <rm...@gmail.com>
Authored: Tue Sep 20 17:22:27 2016 +0200
Committer: Romain manni-Bucau <rm...@gmail.com>
Committed: Tue Sep 20 17:22:27 2016 +0200

----------------------------------------------------------------------
 .../org/apache/openejb/cdi/CdiBeanInfo.java     |  12 ++
 .../openejb/config/AnnotationDeployer.java      |  49 +++++++
 .../openejb/config/ConfigurationFactory.java    |  17 ++-
 .../ConvertJMSDestinationDefinitions.java       |  86 ++++++++++++
 .../openejb/activemq/JMSDestinationTest.java    |  74 +++++++++++
 .../org/apache/openejb/jee/Application.java     |  12 ++
 .../apache/openejb/jee/ApplicationClient.java   |  25 +++-
 .../java/org/apache/openejb/jee/EntityBean.java |  12 ++
 .../org/apache/openejb/jee/Interceptor.java     |  12 ++
 .../org/apache/openejb/jee/JMSDestination.java  | 133 +++++++++++++++++++
 .../org/apache/openejb/jee/JndiConsumer.java    |   4 +
 .../apache/openejb/jee/MessageDrivenBean.java   |  16 ++-
 .../org/apache/openejb/jee/SessionBean.java     |  12 ++
 .../java/org/apache/openejb/jee/WebApp.java     |  12 ++
 .../org/apache/openejb/jee/WebFragment.java     |  12 ++
 15 files changed, 473 insertions(+), 15 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tomee/blob/246af9a5/container/openejb-core/src/main/java/org/apache/openejb/cdi/CdiBeanInfo.java
----------------------------------------------------------------------
diff --git a/container/openejb-core/src/main/java/org/apache/openejb/cdi/CdiBeanInfo.java b/container/openejb-core/src/main/java/org/apache/openejb/cdi/CdiBeanInfo.java
index 22eac30..0927c35 100644
--- a/container/openejb-core/src/main/java/org/apache/openejb/cdi/CdiBeanInfo.java
+++ b/container/openejb-core/src/main/java/org/apache/openejb/cdi/CdiBeanInfo.java
@@ -23,6 +23,7 @@ import org.apache.openejb.jee.EjbLocalRef;
 import org.apache.openejb.jee.EjbRef;
 import org.apache.openejb.jee.EnvEntry;
 import org.apache.openejb.jee.JMSConnectionFactory;
+import org.apache.openejb.jee.JMSDestination;
 import org.apache.openejb.jee.JndiConsumer;
 import org.apache.openejb.jee.KeyedCollection;
 import org.apache.openejb.jee.LifecycleCallback;
@@ -55,6 +56,7 @@ public class CdiBeanInfo implements JndiConsumer {
     protected List<LifecycleCallback> preDestroy;
     protected KeyedCollection<String, DataSource> dataSource;
     protected KeyedCollection<String, JMSConnectionFactory> jmsConnectionFactories;
+    protected KeyedCollection<String, JMSDestination> jmsDestinations;
     protected List<LifecycleCallback> postActivate;
     protected List<LifecycleCallback> prePassivate;
     protected List<SecurityRoleRef> securityRoleRef;
@@ -294,6 +296,16 @@ public class CdiBeanInfo implements JndiConsumer {
         return KeyedCollection.class.cast(getJMSConnectionFactories()).toMap();
     }
 
+    @Override
+    public Collection<JMSDestination> getJMSDestination() {
+        return jmsDestinations == null ? (jmsDestinations = new KeyedCollection<>()) : jmsDestinations;
+    }
+
+    @Override
+    public Map<String, JMSDestination> getJMSDestinationMap() {
+        return KeyedCollection.class.cast(getJMSDestination()).toMap();
+    }
+
     public String getJndiConsumerName() {
         return beanName;
     }

http://git-wip-us.apache.org/repos/asf/tomee/blob/246af9a5/container/openejb-core/src/main/java/org/apache/openejb/config/AnnotationDeployer.java
----------------------------------------------------------------------
diff --git a/container/openejb-core/src/main/java/org/apache/openejb/config/AnnotationDeployer.java b/container/openejb-core/src/main/java/org/apache/openejb/config/AnnotationDeployer.java
index 2302579..1b4bb8b 100644
--- a/container/openejb-core/src/main/java/org/apache/openejb/config/AnnotationDeployer.java
+++ b/container/openejb-core/src/main/java/org/apache/openejb/config/AnnotationDeployer.java
@@ -69,6 +69,7 @@ import org.apache.openejb.jee.InterceptorBinding;
 import org.apache.openejb.jee.Invokable;
 import org.apache.openejb.jee.IsolationLevel;
 import org.apache.openejb.jee.JMSConnectionFactory;
+import org.apache.openejb.jee.JMSDestination;
 import org.apache.openejb.jee.JndiConsumer;
 import org.apache.openejb.jee.JndiReference;
 import org.apache.openejb.jee.License;
@@ -206,6 +207,8 @@ import javax.interceptor.ExcludeDefaultInterceptors;
 import javax.interceptor.Interceptors;
 import javax.jms.JMSConnectionFactoryDefinition;
 import javax.jms.JMSConnectionFactoryDefinitions;
+import javax.jms.JMSDestinationDefinition;
+import javax.jms.JMSDestinationDefinitions;
 import javax.jms.Queue;
 import javax.jws.HandlerChain;
 import javax.jws.WebService;
@@ -4065,6 +4068,20 @@ public class AnnotationDeployer implements DynamicDeployer {
                 final JMSConnectionFactoryDefinition definition = annotated.getAnnotation(JMSConnectionFactoryDefinition.class);
                 buildConnectionFactoryDefinition(consumer, definition);
             }
+
+            //
+            // @JMSDestinationDefinition
+            //
+            for (final Annotated<Class<?>> annotated : annotationFinder.findMetaAnnotatedClasses(JMSDestinationDefinitions.class)) {
+                final JMSDestinationDefinitions defs = annotated.getAnnotation(JMSDestinationDefinitions.class);
+                for (final JMSDestinationDefinition definition : defs.value()) {
+                    buildDestinationDefinition(consumer, definition);
+                }
+            }
+
+            for (final Annotated<Class<?>> annotated : annotationFinder.findMetaAnnotatedClasses(JMSDestinationDefinition.class)) {
+                buildDestinationDefinition(consumer, annotated.getAnnotation(JMSDestinationDefinition.class));
+            }
         }
 
         private void buildContext(final JndiConsumer consumer, final Member member) {
@@ -4716,6 +4733,38 @@ public class AnnotationDeployer implements DynamicDeployer {
             }
         }
 
+        private void buildDestinationDefinition(final JndiConsumer consumer, final JMSDestinationDefinition definition) {
+            final JMSDestination destination = new JMSDestination();
+            destination.setName(definition.name());
+            destination.setClassName(definition.className());
+            destination.setInterfaceName(definition.interfaceName());
+            destination.setResourceAdapter(definition.resourceAdapter());
+            destination.setDestinationName(definition.destinationName());
+
+            for (final String s : definition.properties()) {
+                final int equal = s.indexOf('=');
+                if (equal < s.length() - 1) {
+                    final SuperProperties props = new SuperProperties();
+                    try {
+                        props.load(new ByteArrayInputStream(s.getBytes()));
+                        for (final String key : props.stringPropertyNames()) {
+                            if (!key.isEmpty()) {
+                                destination.property(key, props.getProperty(key));
+                            }
+                        }
+                    } catch (final IOException e) {
+                        final String key = s.substring(0, equal).trim();
+                        final String value = s.substring(equal + 1).trim();
+                        destination.property(key, value);
+                    }
+                } else {
+                    destination.property(s.trim(), "");
+                }
+            }
+
+            consumer.getJMSDestination().add(destination);
+        }
+
         private void buildConnectionFactoryDefinition(final JndiConsumer consumer, final JMSConnectionFactoryDefinition definition) {
             final JMSConnectionFactory connectionFactory = new JMSConnectionFactory();
             connectionFactory.setName(definition.name());

http://git-wip-us.apache.org/repos/asf/tomee/blob/246af9a5/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 873a092..f5dd8ba 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
@@ -288,6 +288,7 @@ public class ConfigurationFactory implements OpenEjbConfigurationFactory {
 
         chain.add(new ConvertDataSourceDefinitions());
         chain.add(new ConvertJMSConnectionFactoryDefinitions());
+        chain.add(new ConvertJMSDestinationDefinitions());
         chain.add(new CleanEnvEntries());
         chain.add(new LinkBuiltInTypes());
 
@@ -455,12 +456,16 @@ public class ConfigurationFactory implements OpenEjbConfigurationFactory {
         if (sys != null) {
             sys.facilities.resources.add(serviceInfo);
         } else if (!offline) {
-            final Assembler assembler = SystemInstance.get().getComponent(Assembler.class);
-            if (assembler != null) {
-                assembler.createResource(null, serviceInfo);
-            }else{
-                throw new OpenEJBException("ResourceInfo: Assembler has not been defined");
-            }
+            doInstall(serviceInfo);
+        }
+    }
+
+    void doInstall(final ResourceInfo serviceInfo) throws OpenEJBException {
+        final Assembler assembler = SystemInstance.get().getComponent(Assembler.class);
+        if (assembler != null) {
+            assembler.createResource(null, serviceInfo);
+        } else {
+            throw new OpenEJBException("ResourceInfo: Assembler has not been defined");
         }
     }
 

http://git-wip-us.apache.org/repos/asf/tomee/blob/246af9a5/container/openejb-core/src/main/java/org/apache/openejb/config/ConvertJMSDestinationDefinitions.java
----------------------------------------------------------------------
diff --git a/container/openejb-core/src/main/java/org/apache/openejb/config/ConvertJMSDestinationDefinitions.java b/container/openejb-core/src/main/java/org/apache/openejb/config/ConvertJMSDestinationDefinitions.java
new file mode 100644
index 0000000..3cd9b46
--- /dev/null
+++ b/container/openejb-core/src/main/java/org/apache/openejb/config/ConvertJMSDestinationDefinitions.java
@@ -0,0 +1,86 @@
+/*
+ * 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.OpenEJBException;
+import org.apache.openejb.config.sys.Resource;
+import org.apache.openejb.jee.JMSDestination;
+import org.apache.openejb.jee.JndiConsumer;
+import org.apache.openejb.jee.KeyedCollection;
+import org.apache.openejb.jee.Property;
+import org.apache.openejb.util.PropertyPlaceHolderHelper;
+
+import java.util.List;
+import java.util.Properties;
+
+public class ConvertJMSDestinationDefinitions extends BaseConvertDefinitions {
+    @Override
+    public AppModule deploy(final AppModule appModule) throws OpenEJBException {
+        final List<JndiConsumer> jndiConsumers = collectConsumers(appModule);
+        final KeyedCollection<String, JMSDestination> destinations = new KeyedCollection<>();
+        for (final JndiConsumer consumer : jndiConsumers) {
+            if (consumer != null) {
+                destinations.addAll(consumer.getJMSDestination());
+            }
+        }
+        for (final JMSDestination destination : destinations) {
+            appModule.getResources().add(toResource(destination));
+        }
+        return appModule;
+    }
+
+
+    private Resource toResource(final JMSDestination factory) {
+        final String name = cleanUpName(factory.getName());
+
+        final Resource factoryResource = new Resource(name, javax.jms.ConnectionFactory.class.getName());
+
+        factoryResource.setJndi(factory.getName().replaceFirst("java:", ""));
+        factoryResource.setType(
+            factory.getInterfaceName() != null && !factory.getInterfaceName().isEmpty() ?
+                factory.getInterfaceName() : "javax.jms.Queue");
+        if (factory.getClassName() != null && !factory.getClassName().isEmpty()) {
+            factoryResource.setClassName(factory.getClassName());
+        }
+
+        final Properties p = factoryResource.getProperties();
+        put(p, AutoConfig.ORIGIN_FLAG, AutoConfig.ORIGIN_ANNOTATION);
+        put(p, "JndiName", factoryResource.getJndi());
+        put(p, "Destination", factory.getDestinationName());
+        if (factory.getResourceAdapter() != null && !factory.getResourceAdapter().isEmpty()) {
+            put(p, "ResourceAdapter", factory.getResourceAdapter());
+        }
+
+        setProperties(factory, p);
+        return factoryResource;
+    }
+
+    private void setProperties(final JMSDestination d, final Properties p) {
+        for (final Property property : d.getProperty()) {
+            final String key = property.getName();
+            final String value = property.getValue();
+            put(p, key, value);
+        }
+    }
+
+    private static void put(final Properties properties, final String key, final Object value) {
+        if (key != null && value != null) {
+            properties.put(key, PropertyPlaceHolderHelper.value(String.valueOf(value)));
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/tomee/blob/246af9a5/container/openejb-core/src/test/java/org/apache/openejb/activemq/JMSDestinationTest.java
----------------------------------------------------------------------
diff --git a/container/openejb-core/src/test/java/org/apache/openejb/activemq/JMSDestinationTest.java b/container/openejb-core/src/test/java/org/apache/openejb/activemq/JMSDestinationTest.java
new file mode 100644
index 0000000..6e70482
--- /dev/null
+++ b/container/openejb-core/src/test/java/org/apache/openejb/activemq/JMSDestinationTest.java
@@ -0,0 +1,74 @@
+/**
+ * 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.command.ActiveMQQueue;
+import org.apache.activemq.command.ActiveMQTopic;
+import org.apache.openejb.junit.ApplicationComposer;
+import org.apache.openejb.testing.Classes;
+import org.apache.openejb.testing.SimpleLog;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import javax.annotation.Resource;
+import javax.jms.JMSConnectionFactoryDefinition;
+import javax.jms.JMSConnectionFactoryDefinitions;
+import javax.jms.JMSDestinationDefinition;
+import javax.jms.JMSDestinationDefinitions;
+import javax.jms.JMSException;
+import javax.jms.Queue;
+import javax.jms.Topic;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+@SimpleLog
+@RunWith(ApplicationComposer.class)
+@Classes(innerClassesAsBean = true, cdi = true)
+public class JMSDestinationTest {
+    @Resource(name = "q")
+    private Queue queue;
+
+    @Resource(name = "t")
+    private Topic topic;
+
+    @Test
+    public void created() throws JMSException {
+        assertNotNull(queue);
+        assertNotNull(topic);
+        assertTrue(ActiveMQQueue.class.isInstance(queue));
+        assertTrue(ActiveMQTopic.class.isInstance(topic));
+        assertEquals("queuetest", ActiveMQQueue.class.cast(queue).getQueueName());
+        assertEquals("topictest", ActiveMQTopic.class.cast(topic).getTopicName());
+    }
+
+    @JMSDestinationDefinitions({
+            @JMSDestinationDefinition(name = "q", interfaceName = "javax.jms.Queue", resourceAdapter = "Default JMS Resource Adapter", properties = {"PhysicalName=queuetest"}),
+            @JMSDestinationDefinition(name = "t", interfaceName = "javax.jms.Topic", resourceAdapter = "Default JMS Resource Adapter", properties = {"PhysicalName=topictest"})
+    })
+    @JMSConnectionFactoryDefinitions({
+            @JMSConnectionFactoryDefinition(
+                    name = "cf",
+                    className = "org.apache.openejb.resource.activemq.ActiveMQResourceAdapter",
+                    resourceAdapter = "Default JMS Resource Adapter",
+                    interfaceName = "javax.jms.MessageListener"
+            )
+    })
+    public static class Define {
+    }
+}

http://git-wip-us.apache.org/repos/asf/tomee/blob/246af9a5/container/openejb-jee/src/main/java/org/apache/openejb/jee/Application.java
----------------------------------------------------------------------
diff --git a/container/openejb-jee/src/main/java/org/apache/openejb/jee/Application.java b/container/openejb-jee/src/main/java/org/apache/openejb/jee/Application.java
index da3c49b..920bae0 100644
--- a/container/openejb-jee/src/main/java/org/apache/openejb/jee/Application.java
+++ b/container/openejb-jee/src/main/java/org/apache/openejb/jee/Application.java
@@ -139,6 +139,8 @@ public class Application implements JndiConsumer, NamedModule {
     protected KeyedCollection<String, DataSource> dataSource;
     @XmlElement(name = "jms-connection-factory", required = true)
     protected KeyedCollection<String, JMSConnectionFactory> jmsConnectionFactories;
+    @XmlElement(name = "jms-destination")
+    protected KeyedCollection<String, JMSDestination> jmsDestinations;
     @XmlAttribute(required = true)
     @XmlJavaTypeAdapter(CollapsedStringAdapter.class)
     protected java.lang.String version;
@@ -428,4 +430,14 @@ public class Application implements JndiConsumer, NamedModule {
     public Map<String, JMSConnectionFactory> getJMSConnectionFactoriesMap() {
         return KeyedCollection.class.cast(getJMSConnectionFactories()).toMap();
     }
+
+    @Override
+    public Collection<JMSDestination> getJMSDestination() {
+        return jmsDestinations == null ? (jmsDestinations = new KeyedCollection<>()) : jmsDestinations;
+    }
+
+    @Override
+    public Map<String, JMSDestination> getJMSDestinationMap() {
+        return KeyedCollection.class.cast(getJMSDestination()).toMap();
+    }
 }

http://git-wip-us.apache.org/repos/asf/tomee/blob/246af9a5/container/openejb-jee/src/main/java/org/apache/openejb/jee/ApplicationClient.java
----------------------------------------------------------------------
diff --git a/container/openejb-jee/src/main/java/org/apache/openejb/jee/ApplicationClient.java b/container/openejb-jee/src/main/java/org/apache/openejb/jee/ApplicationClient.java
index 578ea32..d031edb 100644
--- a/container/openejb-jee/src/main/java/org/apache/openejb/jee/ApplicationClient.java
+++ b/container/openejb-jee/src/main/java/org/apache/openejb/jee/ApplicationClient.java
@@ -16,20 +16,19 @@
  */
 package org.apache.openejb.jee;
 
-import javax.xml.bind.annotation.XmlAccessorType;
 import javax.xml.bind.annotation.XmlAccessType;
-import javax.xml.bind.annotation.XmlType;
-import javax.xml.bind.annotation.XmlTransient;
-import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlAccessorType;
 import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlID;
 import javax.xml.bind.annotation.XmlRootElement;
-import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
+import javax.xml.bind.annotation.XmlTransient;
+import javax.xml.bind.annotation.XmlType;
 import javax.xml.bind.annotation.adapters.CollapsedStringAdapter;
-import java.util.List;
+import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.Collection;
+import java.util.List;
 import java.util.Map;
 
 
@@ -133,6 +132,8 @@ public class ApplicationClient implements JndiConsumer, Lifecycle, NamedModule {
     protected KeyedCollection<String, DataSource> dataSource;
     @XmlElement(name = "jms-connection-factory", required = true)
     protected KeyedCollection<String, JMSConnectionFactory> jmsConnectionFactories;
+    @XmlElement(name = "jms-destination")
+    protected KeyedCollection<String, JMSDestination> jmsDestinations;
 
 
     @XmlAttribute
@@ -435,4 +436,14 @@ public class ApplicationClient implements JndiConsumer, Lifecycle, NamedModule {
     public Map<String, JMSConnectionFactory> getJMSConnectionFactoriesMap() {
         return KeyedCollection.class.cast(getJMSConnectionFactories()).toMap();
     }
+
+    @Override
+    public Collection<JMSDestination> getJMSDestination() {
+        return jmsDestinations == null ? (jmsDestinations = new KeyedCollection<>()) : jmsDestinations;
+    }
+
+    @Override
+    public Map<String, JMSDestination> getJMSDestinationMap() {
+        return KeyedCollection.class.cast(getJMSDestination()).toMap();
+    }
 }

http://git-wip-us.apache.org/repos/asf/tomee/blob/246af9a5/container/openejb-jee/src/main/java/org/apache/openejb/jee/EntityBean.java
----------------------------------------------------------------------
diff --git a/container/openejb-jee/src/main/java/org/apache/openejb/jee/EntityBean.java b/container/openejb-jee/src/main/java/org/apache/openejb/jee/EntityBean.java
index 29b307d..67c32d9 100644
--- a/container/openejb-jee/src/main/java/org/apache/openejb/jee/EntityBean.java
+++ b/container/openejb-jee/src/main/java/org/apache/openejb/jee/EntityBean.java
@@ -170,6 +170,8 @@ public class EntityBean implements RemoteBean {
     protected KeyedCollection<String, DataSource> dataSource;
     @XmlElement(name = "jms-connection-factory", required = true)
     protected KeyedCollection<String, JMSConnectionFactory> jmsConnectionFactories;
+    @XmlElement(name = "jms-destination")
+    protected KeyedCollection<String, JMSDestination> jmsDestinations;
     @XmlElement(name = "security-role-ref", required = true)
     protected List<SecurityRoleRef> securityRoleRef;
     @XmlElement(name = "security-identity")
@@ -613,4 +615,14 @@ public class EntityBean implements RemoteBean {
     public Map<String, JMSConnectionFactory> getJMSConnectionFactoriesMap() {
         return KeyedCollection.class.cast(getJMSConnectionFactories()).toMap();
     }
+
+    @Override
+    public Collection<JMSDestination> getJMSDestination() {
+        return jmsDestinations == null ? (jmsDestinations = new KeyedCollection<>()) : jmsDestinations;
+    }
+
+    @Override
+    public Map<String, JMSDestination> getJMSDestinationMap() {
+        return KeyedCollection.class.cast(getJMSDestination()).toMap();
+    }
 }

http://git-wip-us.apache.org/repos/asf/tomee/blob/246af9a5/container/openejb-jee/src/main/java/org/apache/openejb/jee/Interceptor.java
----------------------------------------------------------------------
diff --git a/container/openejb-jee/src/main/java/org/apache/openejb/jee/Interceptor.java b/container/openejb-jee/src/main/java/org/apache/openejb/jee/Interceptor.java
index 47c0c35..cb5bc56 100644
--- a/container/openejb-jee/src/main/java/org/apache/openejb/jee/Interceptor.java
+++ b/container/openejb-jee/src/main/java/org/apache/openejb/jee/Interceptor.java
@@ -115,6 +115,8 @@ public class Interceptor implements JndiConsumer, Session {
     protected KeyedCollection<String, DataSource> dataSource;
     @XmlElement(name = "jms-connection-factory", required = true)
     protected KeyedCollection<String, JMSConnectionFactory> jmsConnectionFactories;
+    @XmlElement(name = "jms-destination")
+    protected KeyedCollection<String, JMSDestination> jmsDestinations;
     @XmlElement(name = "post-construct", required = true)
     protected List<LifecycleCallback> postConstruct;
     @XmlElement(name = "pre-destroy", required = true)
@@ -448,4 +450,14 @@ public class Interceptor implements JndiConsumer, Session {
     public Map<String, JMSConnectionFactory> getJMSConnectionFactoriesMap() {
         return KeyedCollection.class.cast(getJMSConnectionFactories()).toMap();
     }
+
+    @Override
+    public Collection<JMSDestination> getJMSDestination() {
+        return jmsDestinations == null ? (jmsDestinations = new KeyedCollection<>()) : jmsDestinations;
+    }
+
+    @Override
+    public Map<String, JMSDestination> getJMSDestinationMap() {
+        return KeyedCollection.class.cast(getJMSDestination()).toMap();
+    }
 }

http://git-wip-us.apache.org/repos/asf/tomee/blob/246af9a5/container/openejb-jee/src/main/java/org/apache/openejb/jee/JMSDestination.java
----------------------------------------------------------------------
diff --git a/container/openejb-jee/src/main/java/org/apache/openejb/jee/JMSDestination.java b/container/openejb-jee/src/main/java/org/apache/openejb/jee/JMSDestination.java
new file mode 100644
index 0000000..c4d2097
--- /dev/null
+++ b/container/openejb-jee/src/main/java/org/apache/openejb/jee/JMSDestination.java
@@ -0,0 +1,133 @@
+/**
+ * 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.jee;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlID;
+import javax.xml.bind.annotation.XmlSchemaType;
+import javax.xml.bind.annotation.XmlTransient;
+import javax.xml.bind.annotation.XmlType;
+import javax.xml.bind.annotation.adapters.CollapsedStringAdapter;
+import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
+import java.util.ArrayList;
+import java.util.List;
+
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "jms-destination-factoryType", propOrder = {
+        "name",
+        "descriptions",
+        "className",
+        "interfaceName",
+        "resourceAdapter",
+        "destinationName",
+        "property"
+})
+public class JMSDestination implements Keyable<String> {
+    @XmlTransient
+    protected TextMap description = new TextMap();
+    @XmlElement(required = true)
+    protected String name;
+    @XmlElement(name = "class-name")
+    protected String className;
+    @XmlElement(name = "interface-name")
+    protected String interfaceName;
+    @XmlElement(name = "interface-name")
+    protected String destinationName;
+    @XmlElement(name = "resource-adapter-name")
+    protected String resourceAdapter;
+    protected List<Property> property;
+    @XmlAttribute
+    @XmlJavaTypeAdapter(CollapsedStringAdapter.class)
+    @XmlID
+    @XmlSchemaType(name = "ID")
+    protected String id;
+
+    @XmlElement(name = "description")
+    public Text[] getDescriptions() {
+        return description.toArray();
+    }
+
+    public JMSDestination property(final String name, final String value) {
+        getProperty().add(new Property(name, value));
+        return this;
+    }
+
+    public String getResourceAdapter() {
+        return resourceAdapter;
+    }
+
+    public void setResourceAdapter(String resourceAdapter) {
+        this.resourceAdapter = resourceAdapter;
+    }
+
+    public String getDestinationName() {
+        return destinationName;
+    }
+
+    public void setDestinationName(String destinationName) {
+        this.destinationName = destinationName;
+    }
+
+    public String getClassName() {
+        return className;
+    }
+
+    public void setClassName(String className) {
+        this.className = className;
+    }
+
+    public String getInterfaceName() {
+        return interfaceName;
+    }
+
+    public void setInterfaceName(String interfaceName) {
+        this.interfaceName = interfaceName;
+    }
+
+    public List<Property> getProperty() {
+        if (property == null) {
+            property = new ArrayList<>();
+        }
+        return this.property;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(final String value) {
+        this.id = value;
+    }
+
+    @Override
+    public String getKey() {
+        final String name = getName();
+        if (name == null || name.startsWith("java:")) return name;
+        return "java:comp/env/" + name;
+    }
+}

http://git-wip-us.apache.org/repos/asf/tomee/blob/246af9a5/container/openejb-jee/src/main/java/org/apache/openejb/jee/JndiConsumer.java
----------------------------------------------------------------------
diff --git a/container/openejb-jee/src/main/java/org/apache/openejb/jee/JndiConsumer.java b/container/openejb-jee/src/main/java/org/apache/openejb/jee/JndiConsumer.java
index 2d8e68c..ce11cfe 100644
--- a/container/openejb-jee/src/main/java/org/apache/openejb/jee/JndiConsumer.java
+++ b/container/openejb-jee/src/main/java/org/apache/openejb/jee/JndiConsumer.java
@@ -74,4 +74,8 @@ public interface JndiConsumer {
     Collection<JMSConnectionFactory> getJMSConnectionFactories();
 
     Map<String, JMSConnectionFactory> getJMSConnectionFactoriesMap();
+
+    Collection<JMSDestination> getJMSDestination();
+
+    Map<String, JMSDestination> getJMSDestinationMap();
 }

http://git-wip-us.apache.org/repos/asf/tomee/blob/246af9a5/container/openejb-jee/src/main/java/org/apache/openejb/jee/MessageDrivenBean.java
----------------------------------------------------------------------
diff --git a/container/openejb-jee/src/main/java/org/apache/openejb/jee/MessageDrivenBean.java b/container/openejb-jee/src/main/java/org/apache/openejb/jee/MessageDrivenBean.java
index b9b1d88..3385dcf 100644
--- a/container/openejb-jee/src/main/java/org/apache/openejb/jee/MessageDrivenBean.java
+++ b/container/openejb-jee/src/main/java/org/apache/openejb/jee/MessageDrivenBean.java
@@ -23,13 +23,13 @@ import javax.xml.bind.annotation.XmlAccessorType;
 import javax.xml.bind.annotation.XmlAttribute;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlID;
-import javax.xml.bind.annotation.XmlType;
 import javax.xml.bind.annotation.XmlTransient;
+import javax.xml.bind.annotation.XmlType;
 import javax.xml.bind.annotation.adapters.CollapsedStringAdapter;
 import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
 import java.util.ArrayList;
-import java.util.List;
 import java.util.Collection;
+import java.util.List;
 import java.util.Map;
 
 
@@ -158,6 +158,8 @@ public class MessageDrivenBean implements EnterpriseBean, TimerConsumer, Invokab
     protected KeyedCollection<String, DataSource> dataSource;
     @XmlElement(name = "jms-connection-factory", required = true)
     protected KeyedCollection<String, JMSConnectionFactory> jmsConnectionFactories;
+    @XmlElement(name = "jms-destination")
+    protected KeyedCollection<String, JMSDestination> jmsDestinations;
     @XmlElement(name = "post-construct", required = true)
     protected List<LifecycleCallback> postConstruct;
     @XmlElement(name = "pre-destroy", required = true)
@@ -573,6 +575,16 @@ public class MessageDrivenBean implements EnterpriseBean, TimerConsumer, Invokab
         return KeyedCollection.class.cast(getJMSConnectionFactories()).toMap();
     }
 
+    @Override
+    public Collection<JMSDestination> getJMSDestination() {
+        return jmsDestinations == null ? (jmsDestinations = new KeyedCollection<>()) : jmsDestinations;
+    }
+
+    @Override
+    public Map<String, JMSDestination> getJMSDestinationMap() {
+        return KeyedCollection.class.cast(getJMSDestination()).toMap();
+    }
+
 
     public List<LifecycleCallback> getPostConstruct() {
         if (postConstruct == null) {

http://git-wip-us.apache.org/repos/asf/tomee/blob/246af9a5/container/openejb-jee/src/main/java/org/apache/openejb/jee/SessionBean.java
----------------------------------------------------------------------
diff --git a/container/openejb-jee/src/main/java/org/apache/openejb/jee/SessionBean.java b/container/openejb-jee/src/main/java/org/apache/openejb/jee/SessionBean.java
index 5091b8a..f79ece3 100644
--- a/container/openejb-jee/src/main/java/org/apache/openejb/jee/SessionBean.java
+++ b/container/openejb-jee/src/main/java/org/apache/openejb/jee/SessionBean.java
@@ -236,6 +236,8 @@ public class SessionBean implements RemoteBean, Session, TimerConsumer {
     protected KeyedCollection<String, DataSource> dataSource;
     @XmlElement(name = "jms-connection-factory", required = true)
     protected KeyedCollection<String, JMSConnectionFactory> jmsConnectionFactories;
+    @XmlElement(name = "jms-destination")
+    protected KeyedCollection<String, JMSDestination> jmsDestinations;
     @XmlElement(name = "post-activate", required = true)
     protected List<LifecycleCallback> postActivate;
     @XmlElement(name = "pre-passivate", required = true)
@@ -940,4 +942,14 @@ public class SessionBean implements RemoteBean, Session, TimerConsumer {
     public Map<String, JMSConnectionFactory> getJMSConnectionFactoriesMap() {
         return KeyedCollection.class.cast(getJMSConnectionFactories()).toMap();
     }
+
+    @Override
+    public Collection<JMSDestination> getJMSDestination() {
+        return jmsDestinations == null ? (jmsDestinations = new KeyedCollection<>()) : jmsDestinations;
+    }
+
+    @Override
+    public Map<String, JMSDestination> getJMSDestinationMap() {
+        return KeyedCollection.class.cast(getJMSDestination()).toMap();
+    }
 }

http://git-wip-us.apache.org/repos/asf/tomee/blob/246af9a5/container/openejb-jee/src/main/java/org/apache/openejb/jee/WebApp.java
----------------------------------------------------------------------
diff --git a/container/openejb-jee/src/main/java/org/apache/openejb/jee/WebApp.java b/container/openejb-jee/src/main/java/org/apache/openejb/jee/WebApp.java
index 82c78c7..f2aff30 100644
--- a/container/openejb-jee/src/main/java/org/apache/openejb/jee/WebApp.java
+++ b/container/openejb-jee/src/main/java/org/apache/openejb/jee/WebApp.java
@@ -164,6 +164,8 @@ public class WebApp implements WebCommon, Lifecycle, NamedModule {
     protected KeyedCollection<String, DataSource> dataSource;
     @XmlElement(name = "jms-connection-factory", required = true)
     protected KeyedCollection<String, JMSConnectionFactory> jmsConnectionFactories;
+    @XmlElement(name = "jms-destination")
+    protected KeyedCollection<String, JMSDestination> jmsDestinations;
     @XmlElement(name = "post-construct", required = true)
     protected List<LifecycleCallback> postConstruct;
     @XmlElement(name = "pre-destroy", required = true)
@@ -787,4 +789,14 @@ public class WebApp implements WebCommon, Lifecycle, NamedModule {
     public Map<String, JMSConnectionFactory> getJMSConnectionFactoriesMap() {
         return KeyedCollection.class.cast(getJMSConnectionFactories()).toMap();
     }
+
+    @Override
+    public Collection<JMSDestination> getJMSDestination() {
+        return jmsDestinations == null ? (jmsDestinations = new KeyedCollection<>()) : jmsDestinations;
+    }
+
+    @Override
+    public Map<String, JMSDestination> getJMSDestinationMap() {
+        return KeyedCollection.class.cast(getJMSDestination()).toMap();
+    }
 }

http://git-wip-us.apache.org/repos/asf/tomee/blob/246af9a5/container/openejb-jee/src/main/java/org/apache/openejb/jee/WebFragment.java
----------------------------------------------------------------------
diff --git a/container/openejb-jee/src/main/java/org/apache/openejb/jee/WebFragment.java b/container/openejb-jee/src/main/java/org/apache/openejb/jee/WebFragment.java
index 5ff0687..6ccd07d 100644
--- a/container/openejb-jee/src/main/java/org/apache/openejb/jee/WebFragment.java
+++ b/container/openejb-jee/src/main/java/org/apache/openejb/jee/WebFragment.java
@@ -162,6 +162,8 @@ public class WebFragment implements WebCommon {
     protected KeyedCollection<String, DataSource> dataSource;
     @XmlElement(name = "jms-connection-factory", required = true)
     protected KeyedCollection<String, JMSConnectionFactory> jmsConnectionFactories;
+    @XmlElement(name = "jms-destination")
+    protected KeyedCollection<String, JMSDestination> jmsDestinations;
     @XmlElement(name = "post-construct", required = true)
     protected List<LifecycleCallback> postConstruct;
     @XmlElement(name = "pre-destroy", required = true)
@@ -622,4 +624,14 @@ public class WebFragment implements WebCommon {
     public Map<String, JMSConnectionFactory> getJMSConnectionFactoriesMap() {
         return KeyedCollection.class.cast(getJMSConnectionFactories()).toMap();
     }
+
+    @Override
+    public Collection<JMSDestination> getJMSDestination() {
+        return jmsDestinations == null ? (jmsDestinations = new KeyedCollection<>()) : jmsDestinations;
+    }
+
+    @Override
+    public Map<String, JMSDestination> getJMSDestinationMap() {
+        return KeyedCollection.class.cast(getJMSDestination()).toMap();
+    }
 }
\ No newline at end of file