Repository: tomee Updated Branches: refs/heads/master 283373f36 -> e20d46165
TOMEE-2149 Allow beforeDelivery/afterDelivery calls with message delivery in between, as per JSR-322 section 13.5.6 Project: http://git-wip-us.apache.org/repos/asf/tomee/repo Commit: http://git-wip-us.apache.org/repos/asf/tomee/commit/e20d4616 Tree: http://git-wip-us.apache.org/repos/asf/tomee/tree/e20d4616 Diff: http://git-wip-us.apache.org/repos/asf/tomee/diff/e20d4616 Branch: refs/heads/master Commit: e20d461659476923b5d19fd3bc2a6b991f1ea498 Parents: 283373f Author: Jonathan Gallimore <j...@jrg.me.uk> Authored: Thu Nov 23 11:55:05 2017 +0000 Committer: Jonathan Gallimore <j...@jrg.me.uk> Committed: Thu Nov 23 15:36:54 2017 +0000 ---------------------------------------------------------------------- .../openejb/core/mdb/EndpointHandler.java | 2 - .../openejb/core/mdb/NoMessageDeliveryTest.java | 229 +++++++++++++++++++ 2 files changed, 229 insertions(+), 2 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/tomee/blob/e20d4616/container/openejb-core/src/main/java/org/apache/openejb/core/mdb/EndpointHandler.java ---------------------------------------------------------------------- diff --git a/container/openejb-core/src/main/java/org/apache/openejb/core/mdb/EndpointHandler.java b/container/openejb-core/src/main/java/org/apache/openejb/core/mdb/EndpointHandler.java index 3e6dc76..4e21949 100644 --- a/container/openejb-core/src/main/java/org/apache/openejb/core/mdb/EndpointHandler.java +++ b/container/openejb-core/src/main/java/org/apache/openejb/core/mdb/EndpointHandler.java @@ -284,8 +284,6 @@ public class EndpointHandler implements InvocationHandler, MessageEndpoint { switch (state) { case RELEASED: throw new IllegalStateException("Message endpoint factory has been released"); - case BEFORE_CALLED: - throw new IllegalStateException("Exactally one message must be delivered between beforeDelivery and afterDelivery"); case NONE: throw new IllegalStateException("afterDelivery may only be called if message delivery began with a beforeDelivery call"); } http://git-wip-us.apache.org/repos/asf/tomee/blob/e20d4616/container/openejb-core/src/test/java/org/apache/openejb/core/mdb/NoMessageDeliveryTest.java ---------------------------------------------------------------------- diff --git a/container/openejb-core/src/test/java/org/apache/openejb/core/mdb/NoMessageDeliveryTest.java b/container/openejb-core/src/test/java/org/apache/openejb/core/mdb/NoMessageDeliveryTest.java new file mode 100644 index 0000000..104d775 --- /dev/null +++ b/container/openejb-core/src/test/java/org/apache/openejb/core/mdb/NoMessageDeliveryTest.java @@ -0,0 +1,229 @@ +/** + * 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.core.mdb; + +import junit.framework.TestCase; +import org.apache.openejb.OpenEJB; +import org.apache.openejb.assembler.classic.AppInfo; +import org.apache.openejb.assembler.classic.Assembler; +import org.apache.openejb.assembler.classic.SecurityServiceInfo; +import org.apache.openejb.assembler.classic.TransactionServiceInfo; +import org.apache.openejb.config.AppModule; +import org.apache.openejb.config.ConfigurationFactory; +import org.apache.openejb.config.ConnectorModule; +import org.apache.openejb.config.EjbModule; +import org.apache.openejb.core.ivm.naming.InitContextFactory; +import org.apache.openejb.jee.Connector; +import org.apache.openejb.jee.EjbJar; +import org.apache.openejb.jee.InboundResourceadapter; +import org.apache.openejb.jee.MessageAdapter; +import org.apache.openejb.jee.MessageDrivenBean; +import org.apache.openejb.jee.MessageListener; +import org.apache.openejb.jee.ResourceAdapter; +import org.apache.openejb.util.Join; +import org.junit.Assert; + +import javax.annotation.PostConstruct; +import javax.annotation.Resource; +import javax.ejb.ActivationConfigProperty; +import javax.ejb.MessageDriven; +import javax.ejb.MessageDrivenContext; +import javax.naming.InitialContext; +import javax.resource.ResourceException; +import javax.resource.spi.ActivationSpec; +import javax.resource.spi.BootstrapContext; +import javax.resource.spi.InvalidPropertyException; +import javax.resource.spi.ResourceAdapterInternalException; +import javax.resource.spi.endpoint.MessageEndpoint; +import javax.resource.spi.endpoint.MessageEndpointFactory; +import javax.transaction.xa.XAResource; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Stack; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +/** + * @version $Rev$ $Date$ + */ +public class NoMessageDeliveryTest extends TestCase { + + @Override + public void tearDown() throws Exception { + super.tearDown(); + OpenEJB.destroy(); + } + + public void test() throws Exception { + System.setProperty(javax.naming.Context.INITIAL_CONTEXT_FACTORY, InitContextFactory.class.getName()); + + final ConfigurationFactory config = new ConfigurationFactory(); + final Assembler assembler = new Assembler(); + + assembler.createTransactionManager(config.configureService(TransactionServiceInfo.class)); + assembler.createSecurityService(config.configureService(SecurityServiceInfo.class)); + + // Setup the descriptor information + + EmailBean.lifecycle.clear(); + + + final AppModule app = new AppModule(this.getClass().getClassLoader(), "testapp"); + + final Connector connector = new Connector("email-ra"); + final ResourceAdapter adapter = new ResourceAdapter(EmailResourceAdapter.class); + connector.setResourceAdapter(adapter); + final InboundResourceadapter inbound = adapter.setInboundResourceAdapter(new InboundResourceadapter()); + final MessageAdapter messageAdapter = inbound.setMessageAdapter(new MessageAdapter()); + final MessageListener listener = messageAdapter.addMessageListener(new MessageListener(EmailConsumer.class, EmailAccountInfo.class)); + listener.getActivationSpec().addRequiredConfigProperty("address"); + app.getConnectorModules().add(new ConnectorModule(connector)); + + final EjbJar ejbJar = new EjbJar(); + ejbJar.addEnterpriseBean(new MessageDrivenBean(EmailBean.class)); + app.getEjbModules().add(new EjbModule(ejbJar)); + + final AppInfo appInfo = config.configureApplication(app); + assembler.createApplication(appInfo); + + final InitialContext initialContext = new InitialContext(); + + final EmailResourceAdapter ra = (EmailResourceAdapter) initialContext.lookup("java:openejb/Resource/email-raRA"); + + final Properties headers = new Properties(); + headers.put("To", "dblev...@apache.org"); + headers.put("From", "dblev...@visi.com"); + headers.put("Subject", "Hello"); + + ra.deliverEmail(headers, "How's it going?"); + + final Stack<Lifecycle> lifecycle = EmailBean.lifecycle; + + final List expected = Arrays.asList(Lifecycle.CONSTRUCTOR, Lifecycle.INJECTION, Lifecycle.POST_CONSTRUCT); + + Assert.assertEquals(Join.join("\n", expected), Join.join("\n", lifecycle)); + } + + public enum Lifecycle { + CONSTRUCTOR, INJECTION, POST_CONSTRUCT, ON_MESSAGE + } + + @MessageDriven(activationConfig = {@ActivationConfigProperty(propertyName = "address", propertyValue = "dblev...@apache.org")}) + public static class EmailBean implements EmailConsumer { + + public static Lock lock = new ReentrantLock(); + public static Condition messageRecieved = lock.newCondition(); + + private static final Stack<Lifecycle> lifecycle = new Stack<Lifecycle>(); + + public EmailBean() { + lifecycle.push(Lifecycle.CONSTRUCTOR); + } + + @Resource + public void setMessageDrivenContext(final MessageDrivenContext messageDrivenContext) { + lifecycle.push(Lifecycle.INJECTION); + } + + @PostConstruct + public void init() { + lifecycle.push(Lifecycle.POST_CONSTRUCT); + } + + public void receiveEmail(final Properties headers, final String body) { + lifecycle.push(Lifecycle.ON_MESSAGE); + } + } + + public static interface EmailConsumer { + public void receiveEmail(Properties headers, String body); + } + + public static class EmailResourceAdapter implements javax.resource.spi.ResourceAdapter { + public boolean started; + + private final Map<String, EmailConsumer> consumers = new HashMap<String, EmailConsumer>(); + + public void start(final BootstrapContext bootstrapContext) throws ResourceAdapterInternalException { + } + + public void stop() { + } + + public void endpointActivation(final MessageEndpointFactory messageEndpointFactory, final ActivationSpec activationSpec) throws ResourceException { + final EmailAccountInfo accountInfo = (EmailAccountInfo) activationSpec; + + final EmailConsumer emailConsumer = (EmailConsumer) messageEndpointFactory.createEndpoint(null); + consumers.put(accountInfo.getAddress(), emailConsumer); + } + + public void endpointDeactivation(final MessageEndpointFactory messageEndpointFactory, final ActivationSpec activationSpec) { + final EmailAccountInfo accountInfo = (EmailAccountInfo) activationSpec; + + final EmailConsumer emailConsumer = consumers.remove(accountInfo.getAddress()); + final MessageEndpoint endpoint = (MessageEndpoint) emailConsumer; + endpoint.release(); + } + + public XAResource[] getXAResources(final ActivationSpec[] activationSpecs) throws ResourceException { + return new XAResource[0]; + } + + public void deliverEmail(final Properties headers, final String body) throws Exception { + final String to = headers.getProperty("To"); + + final EmailConsumer emailConsumer = consumers.get(to); + + if (emailConsumer == null) throw new Exception("No such account"); + + final MessageEndpoint endpoint = (MessageEndpoint) emailConsumer; + + endpoint.beforeDelivery(EmailConsumer.class.getMethod("receiveEmail", Properties.class, String.class)); + endpoint.afterDelivery(); + } + } + + public static class EmailAccountInfo implements ActivationSpec { + private EmailResourceAdapter emailResourceAdapter; + + private String address; + + public void validate() throws InvalidPropertyException { + } + + public String getAddress() { + return address; + } + + public void setAddress(final String address) { + this.address = address; + } + + public EmailResourceAdapter getResourceAdapter() { + return emailResourceAdapter; + } + + public void setResourceAdapter(final javax.resource.spi.ResourceAdapter resourceAdapter) { + this.emailResourceAdapter = (EmailResourceAdapter) resourceAdapter; + } + } + +}