You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tomee.apache.org by ma...@apache.org on 2007/04/19 11:15:19 UTC

svn commit: r530344 - in /incubator/openejb/trunk/openejb3/container/openejb-core/src: main/java/org/apache/openejb/core/interceptor/ main/java/org/apache/openejb/core/stateless/ test/java/org/apache/openejb/core/stateless/

Author: manugeorge
Date: Thu Apr 19 02:15:16 2007
New Revision: 530344

URL: http://svn.apache.org/viewvc?view=rev&rev=530344
Log:
OPENEJB-565
Basic support for JAX-WS invocations. Thank you Jarek

Added:
    incubator/openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/core/stateless/JaxWsWebServiceInvocationTest.java
Modified:
    incubator/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/interceptor/InterceptorStack.java
    incubator/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/interceptor/JaxWsInvocationContext.java
    incubator/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateless/StatelessContainer.java

Modified: incubator/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/interceptor/InterceptorStack.java
URL: http://svn.apache.org/viewvc/incubator/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/interceptor/InterceptorStack.java?view=diff&rev=530344&r1=530343&r2=530344
==============================================================================
--- incubator/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/interceptor/InterceptorStack.java (original)
+++ incubator/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/interceptor/InterceptorStack.java Thu Apr 19 02:15:16 2007
@@ -68,8 +68,8 @@
         return value;
     }
 
-    public Object invoke(javax.xml.ws.handler.MessageContext messageContext) throws Exception {
-        InvocationContext invocationContext = new JaxWsInvocationContext(operation, interceptors, beanInstance, targetMethod, messageContext);
+    public Object invoke(javax.xml.ws.handler.MessageContext messageContext, Object... parameters) throws Exception {
+        InvocationContext invocationContext = new JaxWsInvocationContext(operation, interceptors, beanInstance, targetMethod, messageContext, parameters);
         Object value = invocationContext.proceed();
         return value;
     }

Modified: incubator/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/interceptor/JaxWsInvocationContext.java
URL: http://svn.apache.org/viewvc/incubator/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/interceptor/JaxWsInvocationContext.java?view=diff&rev=530344&r1=530343&r2=530344
==============================================================================
--- incubator/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/interceptor/JaxWsInvocationContext.java (original)
+++ incubator/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/interceptor/JaxWsInvocationContext.java Thu Apr 19 02:15:16 2007
@@ -29,8 +29,8 @@
 public class JaxWsInvocationContext extends ReflectionInvocationContext {
     private final javax.xml.ws.handler.MessageContext messageContext;
 
-    public JaxWsInvocationContext(Operation operation, List<Interceptor> interceptors, Object target, Method method, MessageContext messageContext) {
-        super(operation, interceptors, target, method);
+    public JaxWsInvocationContext(Operation operation, List<Interceptor> interceptors, Object target, Method method, MessageContext messageContext, Object... parameters) {
+        super(operation, interceptors, target, method, parameters);
         this.messageContext = messageContext;
     }
 

Modified: incubator/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateless/StatelessContainer.java
URL: http://svn.apache.org/viewvc/incubator/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateless/StatelessContainer.java?view=diff&rev=530344&r1=530343&r2=530344
==============================================================================
--- incubator/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateless/StatelessContainer.java (original)
+++ incubator/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateless/StatelessContainer.java Thu Apr 19 02:15:16 2007
@@ -194,13 +194,6 @@
         try {
             if (isWebServiceCall(deploymentInfo, callMethod, args)){
                 callContext.setCurrentOperation(Operation.BUSINESS_WS);                                   
-                Class cls = null;                    
-                try {
-                     cls = Class.forName("javax.xml.rpc.handler.MessageContext");
-                } catch (ClassNotFoundException e) {
-                    throw new OpenEJBException("Cannot find class javax.xml.rpc.handler.MessageContext",e);
-                }
-                ThreadContext.getThreadContext().set(cls,args[0]);                                    
                 returnValue = invokeWebService(args, deploymentInfo, runMethod, instance, returnValue);                
             } else {
                 List<InterceptorData> interceptors = deploymentInfo.getMethodInterceptors(runMethod);
@@ -261,9 +254,10 @@
         InterceptorStack interceptorStack = new InterceptorStack(instance.bean, runMethod, Operation.BUSINESS_WS, interceptorDatas, interceptors);
         Object[] params = new Object[runMethod.getParameterTypes().length];
         if (messageContext instanceof javax.xml.rpc.handler.MessageContext) {
+            ThreadContext.getThreadContext().set(javax.xml.rpc.handler.MessageContext.class, (javax.xml.rpc.handler.MessageContext) messageContext);
             returnValue = interceptorStack.invoke((javax.xml.rpc.handler.MessageContext) messageContext, params);
         } else if (messageContext instanceof javax.xml.ws.handler.MessageContext) {
-            returnValue = interceptorStack.invoke((javax.xml.ws.handler.MessageContext) messageContext);
+            returnValue = interceptorStack.invoke((javax.xml.ws.handler.MessageContext) messageContext, params);
         }
         return returnValue;
     }

Added: incubator/openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/core/stateless/JaxWsWebServiceInvocationTest.java
URL: http://svn.apache.org/viewvc/incubator/openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/core/stateless/JaxWsWebServiceInvocationTest.java?view=auto&rev=530344
==============================================================================
--- incubator/openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/core/stateless/JaxWsWebServiceInvocationTest.java (added)
+++ incubator/openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/core/stateless/JaxWsWebServiceInvocationTest.java Thu Apr 19 02:15:16 2007
@@ -0,0 +1,376 @@
+/**
+ * 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.stateless;
+
+import junit.framework.TestCase;
+import org.apache.openejb.core.ivm.naming.InitContextFactory;
+import org.apache.openejb.config.ConfigurationFactory;
+import org.apache.openejb.config.EjbModule;
+import org.apache.openejb.assembler.classic.Assembler;
+import org.apache.openejb.assembler.classic.ProxyFactoryInfo;
+import org.apache.openejb.assembler.classic.TransactionServiceInfo;
+import org.apache.openejb.assembler.classic.SecurityServiceInfo;
+import org.apache.openejb.assembler.classic.ConnectionManagerInfo;
+import org.apache.openejb.assembler.classic.StatelessSessionContainerInfo;
+import org.apache.openejb.assembler.classic.EjbJarInfo;
+import org.apache.openejb.jee.EjbJar;
+import org.apache.openejb.jee.StatelessBean;
+import org.apache.openejb.loader.SystemInstance;
+import org.apache.openejb.spi.ContainerSystem;
+import org.apache.openejb.DeploymentInfo;
+import org.apache.openejb.RpcContainer;
+
+import javax.interceptor.AroundInvoke;
+import javax.interceptor.InvocationContext;
+import javax.interceptor.Interceptors;
+import javax.jws.WebService;
+import javax.xml.ws.handler.MessageContext;
+import javax.xml.ws.WebServiceContext;
+import javax.annotation.Resource;
+import javax.ejb.SessionContext;
+import java.util.ArrayList;
+import java.util.Set;
+import java.util.Collection;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.lang.reflect.Method;
+
+/**
+ * The point of this test case is to verify that OpenEJB is accurately performing
+ * it's part of a WebServiceProvider to OpenEJB invocation as it relates to JAX-RPC.
+ *
+ * In the agreement between OpenEJB and the Web Service Provider, the Web Service Provider
+ * must supply the MessageContext and an Interceptor as the arguments of the standard
+ * container.invoke method call.
+ *
+ * OpenEJB must ensure the MessageContext is exposed via the SessionContext.getMessageContext
+ * and ensure that the interceptor is added to the chain just after the other interceptors and
+ * before the bean method itself is invoked.
+ *
+ * @version $Rev$ $Date$
+ */
+public class JaxWsWebServiceInvocationTest extends TestCase {
+
+    public void testWebServiceInvocations() throws Exception {
+        System.setProperty(javax.naming.Context.INITIAL_CONTEXT_FACTORY, InitContextFactory.class.getName());
+
+        ConfigurationFactory config = new ConfigurationFactory();
+        Assembler assembler = new Assembler();
+
+        assembler.createProxyFactory(config.configureService(ProxyFactoryInfo.class));
+        assembler.createTransactionManager(config.configureService(TransactionServiceInfo.class));
+        assembler.createSecurityService(config.configureService(SecurityServiceInfo.class,"PseudoSecurityService",null,"PseudoSecurityService",null));
+
+        assembler.createConnectionManager(config.configureService(ConnectionManagerInfo.class));
+
+        assembler.createContainer(config.configureService(StatelessSessionContainerInfo.class));
+
+
+        EjbJarInfo ejbJar = config.configureApplication(buildTestApp());
+
+        assembler.createApplication(ejbJar);
+
+        ContainerSystem containerSystem = SystemInstance.get().getComponent(ContainerSystem.class);
+
+        DeploymentInfo deploymentInfo = containerSystem.getDeploymentInfo("EchoBean");
+
+        assertNotNull(deploymentInfo);
+
+        assertEquals("ServiceEndpointInterface", EchoServiceEndpoint.class, deploymentInfo.getServiceEndpointInterface());
+
+
+        // OK, Now let's fake a web serivce invocation coming from any random
+        // web service provider.  The web serivce provider needs supply
+        // the MessageContext and an interceptor to do the marshalling as
+        // the arguments of the standard container.invoke signature.
+
+        // So let's create a fake message context.
+        MessageContext messageContext = new FakeMessageContext();
+
+        // Now let's create a fake interceptor as would be supplied by the
+        // web service provider.  Instead of writing "fake" marshalling
+        // code that would pull the arguments from the soap message, we'll
+        // just give it the argument values directly.
+        Object webServiceProviderInterceptor = new FakeWebServiceProviderInterceptor("Hello world");
+
+        // Ok, now we have the two arguments expected on a JAX-RPC Web Service
+        // invocation as per the OpenEJB-specific agreement between OpenEJB
+        // and the Web Service Provider
+        Object[] args = new Object[]{messageContext, webServiceProviderInterceptor};
+
+        // Let's grab the container as the Web Service Provider would do and
+        // perform an invocation
+        RpcContainer container = (RpcContainer) deploymentInfo.getContainer();
+
+        Method echoMethod = EchoServiceEndpoint.class.getMethod("echo", String.class);
+
+        String value = (String)container.invoke("EchoBean", echoMethod, args, null);
+
+        assertCalls(Call.values());
+        calls.clear();
+        assertEquals("Hello world" , value);
+        
+    }
+
+    private void assertCalls(Call... expectedCalls) {
+        List expected = Arrays.asList(expectedCalls);
+        assertEquals(join("\n", expected) , join("\n", calls));
+    }
+
+    public static enum Call {
+        EjbInterceptor_Invoke_BEFORE,
+        Bean_Invoke_BEFORE,
+        WebServiceProvider_Invoke_BEFORE,
+        Bean_Invoke,
+        WebServiceProvider_Invoke_AFTER,
+        Bean_Invoke_AFTER,
+        EjbInterceptor_Invoke_AFTER,
+    }
+
+    public static List<Call> calls = new ArrayList<Call>();
+
+    public EjbModule buildTestApp() {
+        EjbJar ejbJar = new EjbJar();
+
+        StatelessBean bean = ejbJar.addEnterpriseBean(new StatelessBean(EchoBean.class));
+        bean.setServiceEndpoint(EchoServiceEndpoint.class.getName());
+
+        return new EjbModule(this.getClass().getClassLoader(), this.getClass().getSimpleName(), "test", ejbJar, null);
+    }
+
+    @Interceptors({PlainEjbInterceptor.class})
+    public static class EchoBean {
+
+        @Resource
+        private SessionContext ctx;
+
+        @Resource
+        private WebServiceContext wsContext;
+
+        @AroundInvoke
+        public Object invoke(InvocationContext context) throws Exception {
+
+            /**
+             * For JAX-WS invocations context.getContextData() must return the 
+             * JAX-WS MessageContex. As per the agreement between OpenEJB and the Web Service Provider
+             * the MessageContex should have been passed into the container.invoke method
+             * and the container should then ensure it's available via getContextData()
+             * for the duration of this call.
+             */
+            MessageContext messageContext = (MessageContext)context.getContextData();
+            
+            junit.framework.Assert.assertNotNull("message context should not be null", messageContext);
+            junit.framework.Assert.assertTrue("the Web Service Provider's message context should be used", messageContext instanceof FakeMessageContext);
+
+            // Try to get JAX-RPC context, should throw an exception since it's JAX-WS
+            try {
+                ctx.getMessageContext();
+                junit.framework.Assert.fail("Did not throw exception");
+            } catch (IllegalStateException e) {
+                // that's expected since it's JAX-WS
+            }
+            
+            // TODO: this is not implemented yet
+            /*
+            junit.framework.Assert.assertNotNull("web service context should not be null", wsContext);
+            */
+
+            calls.add(Call.Bean_Invoke_BEFORE);
+            Object o = context.proceed();
+            calls.add(Call.Bean_Invoke_AFTER);
+            return o;
+        }
+        
+        public String echo(String data){
+            calls.add(Call.Bean_Invoke);
+            return data;
+        }
+    }
+
+    @WebService
+    public static interface EchoServiceEndpoint { 
+        String echo(String data);
+    }
+
+    /**
+     * This interceptor is here to ensure that the container
+     * still invokes interceptors normally for web serivce
+     * invocations and to also guarantee that the Web Service
+     * Provider's interceptor (which is a special OpenEJB concept)
+     * is invoked *after* all the normal ejb interceptors.
+     */
+    public static class PlainEjbInterceptor {
+
+        @AroundInvoke
+        public Object invoke(InvocationContext context) throws Exception {
+            // Track this call so we can assert proper interceptor order
+            calls.add(Call.EjbInterceptor_Invoke_BEFORE);
+            Object o = context.proceed();
+            calls.add(Call.EjbInterceptor_Invoke_AFTER);
+            return o;
+        }
+    }
+
+
+    private static String join(String delimeter, List items) {
+        StringBuffer sb = new StringBuffer();
+        for (Object item : items) {
+            sb.append(item.toString()).append(delimeter);
+        }
+        return sb.toString();
+    }
+
+
+    /**
+     * This object would be implemented by the Web Service Provider per
+     * the JAX-WS spec and supplied to us in the container.invoke method
+     * per the OpenEJB-WebServiceProvider agreement
+     */
+    public static class FakeMessageContext implements MessageContext {
+
+        private Map map = new HashMap();
+
+        public void clear() {
+            map.clear();      
+        }
+
+        public boolean containsKey(Object key) {
+            return map.containsKey(key);
+        }
+
+        public boolean containsValue(Object value) {
+            return map.containsValue(value);
+        }
+
+        public Set<Entry<String, Object>> entrySet() {
+            return map.entrySet();
+        }
+
+        public Object get(Object key) {
+            return map.get(key);
+        }
+
+        public boolean isEmpty() {
+            return map.isEmpty();
+        }
+
+        public Set<String> keySet() {
+            return map.keySet();
+        }
+
+        public Object put(String key, Object value) {
+            return map.put(key, value);
+        }
+
+        public void putAll(Map<? extends String, ? extends Object> t) {
+            map.putAll(t);
+        }
+
+        public Object remove(Object key) {
+            return map.remove(key);
+        }
+
+        public int size() {
+            return map.size();
+        }
+
+        public Collection<Object> values() {
+            return map.values();
+        }
+
+        public Scope getScope(String arg0) {
+            return null;
+        }
+
+        public void setScope(String arg0, Scope arg1) {
+        }
+
+    }
+
+    /**
+     * This object would be supplied by the Web Service Provider
+     * as per the OpenEJB-WebServiceProvider agreement and serves
+     * two purposes:
+     *
+     * 1. Executing the Handler Chain (as required by
+     * the JAX-RPC specification) in the context of the EJB Container
+     * (as required by the EJB and J2EE WebServices specifications)
+     *
+     * 2. Unmarshalling the method arguments from the SOAP message
+     * after the handlers in the Handler Chain have had a chance
+     * to modify the argument values via the SAAJ tree.
+     *
+     * The Interceptor instance given to OpenEJB is constructed
+     * and created by the Web Service Provider and should contain
+     * all the data it requires to complete it's part of the agreement.
+     *
+     * OpenEJB will not perform any injection on this object and
+     * the interceptor will be discarded so that the Web Service
+     * Provider may pass in a new Interceptor instance on every
+     * web service invocation.
+     *
+     * The Web Service Provider may pass in any object to serve
+     * the roll of the Interceptor as long as it has an @AroundInvoke
+     * method using the method signature:
+     *
+     * public Object <METHOD-NAME> (InvocationContext ctx) throws Exception
+     *
+     * Unlike typical EJB Interceptor around invoke methods, the @AroundInvoke
+     * annotation must be used and is not optional, and the method must be public.
+     */
+    public static class FakeWebServiceProviderInterceptor {
+
+        /**
+         * These would normally come from the soap message
+         */
+        private final Object[] args;
+
+        public FakeWebServiceProviderInterceptor(Object... args) {
+            this.args = args;
+        }
+
+        @AroundInvoke
+        public Object invoke(InvocationContext invocationContext) throws Exception {
+            // The interceptor of the web serivce must set the
+            // arguments it marshalls from the soap message into
+            // the InvocationContext so we can invoke the bean.
+            invocationContext.setParameters(args);
+
+            Object returnValue;
+            try {
+
+                // Track this call so we can assert proper interceptor order
+                calls.add(Call.WebServiceProvider_Invoke_BEFORE);
+
+                // handler chain "before advice" would happen here
+                returnValue = invocationContext.proceed();
+                // handler chain "after advice" would happen here
+
+                // Track this call so we can assert proper interceptor order
+                calls.add(Call.WebServiceProvider_Invoke_AFTER);
+
+            } catch (Exception e) {
+                // handler chain fault processing would happen here
+                throw e;
+            }
+            return returnValue;
+        }
+    }
+}