001    /**
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *     http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    
018    package org.apache.geronimo.axis2.ejb;
019    
020    import java.lang.reflect.Method;
021    import java.lang.reflect.ParameterizedType;
022    import java.lang.reflect.Type;
023    
024    import javax.xml.ws.Provider;
025    
026    import org.apache.axis2.AxisFault;
027    import org.apache.axis2.description.AxisService;
028    import org.apache.axis2.description.Parameter;
029    import org.apache.axis2.engine.MessageReceiver;
030    import org.apache.axis2.jaxws.ExceptionFactory;
031    import org.apache.axis2.jaxws.core.MessageContext;
032    import org.apache.axis2.jaxws.description.EndpointDescription;
033    import org.apache.axis2.jaxws.description.EndpointInterfaceDescription;
034    import org.apache.axis2.jaxws.description.OperationDescription;
035    import org.apache.axis2.jaxws.handler.SoapMessageContext;
036    import org.apache.axis2.jaxws.i18n.Messages;
037    import org.apache.commons.logging.Log;
038    import org.apache.commons.logging.LogFactory;
039    import org.apache.openejb.ApplicationException;
040    import org.apache.openejb.DeploymentInfo;
041    import org.apache.openejb.RpcContainer;
042    
043    public class EJBMessageReceiver implements MessageReceiver {
044    
045        private static final Log LOG = LogFactory.getLog(EJBMessageReceiver.class);
046        
047        private DeploymentInfo deploymentInfo;
048        private Class serviceImplClass;
049        private EJBWebServiceContainer container;
050    
051        public EJBMessageReceiver(EJBWebServiceContainer container, Class serviceImplClass, DeploymentInfo deploymentInfo) {
052            this.container = container;
053            this.serviceImplClass = serviceImplClass;
054            this.deploymentInfo = deploymentInfo;
055        }
056        
057        public void receive(org.apache.axis2.context.MessageContext axisMsgCtx) throws AxisFault {         
058            MessageContext requestMsgCtx = new MessageContext(axisMsgCtx);
059            
060            // init some bits
061            requestMsgCtx.setOperationName(requestMsgCtx.getAxisMessageContext().getAxisOperation().getName());
062            requestMsgCtx.setEndpointDescription(getEndpointDescription(requestMsgCtx));
063            
064            Method method = null;
065            if (Provider.class.isAssignableFrom(this.serviceImplClass)) {
066                method = getProviderMethod();
067            } else {
068                requestMsgCtx.setOperationDescription(getOperationDescription(requestMsgCtx));
069                method = getServiceMethod(requestMsgCtx);
070            }
071            
072            if (LOG.isDebugEnabled()) {
073                LOG.debug("Invoking '" + method.getName() + "' method.");
074            }
075            
076            EJBInterceptor interceptor = new EJBInterceptor(this.container, requestMsgCtx);
077    
078            SoapMessageContext jaxwsContext = new SoapMessageContext(requestMsgCtx);
079            Object[] arguments = { jaxwsContext, interceptor };
080            
081            RpcContainer container = (RpcContainer) this.deploymentInfo.getContainer();
082    
083            Class callInterface = this.deploymentInfo.getServiceEndpointInterface();
084            
085            method = getMostSpecificMethod(method, callInterface);
086            
087            try {
088                Object res = container.invoke(this.deploymentInfo.getDeploymentID(), callInterface, method, arguments, null);
089                // TODO: update response message with new response value?
090            } catch (ApplicationException e) {
091                if (e.getCause() instanceof AxisFault) {
092                    throw (AxisFault)e.getCause();
093                } else {
094                    throw AxisFault.makeFault(e);
095                }
096            } catch (Exception e) {
097                throw AxisFault.makeFault(e);
098            }
099        }
100        
101        private static Method getMostSpecificMethod(Method method, Class<?> targetClass) {
102            if (method != null && targetClass != null) {
103                try {
104                    method = targetClass.getMethod(method.getName(), method.getParameterTypes());
105                } catch (NoSuchMethodException ex) {
106                    // Perhaps the target class doesn't implement this method:
107                    // that's fine, just use the original method
108                }
109            }
110            return method;
111        }
112        
113        private Method getServiceMethod(MessageContext mc) {
114            OperationDescription opDesc = mc.getOperationDescription();
115            if (opDesc == null) {
116                throw ExceptionFactory.makeWebServiceException("Operation Description was not set");
117            }
118    
119            Method returnMethod = opDesc.getMethodFromServiceImpl(this.serviceImplClass);
120            if (returnMethod == null) {
121                throw ExceptionFactory
122                        .makeWebServiceException(Messages.getMessage("JavaBeanDispatcherErr1"));
123            }
124    
125            return returnMethod;
126        }
127        
128        private OperationDescription getOperationDescription(MessageContext mc) {
129            EndpointDescription ed = mc.getEndpointDescription();
130            EndpointInterfaceDescription eid = ed.getEndpointInterfaceDescription();
131            
132            OperationDescription[] ops = eid.getDispatchableOperation(mc.getOperationName());
133            if (ops == null || ops.length == 0) {
134                throw ExceptionFactory.makeWebServiceException(
135                        "No operation found.  WSDL Operation name: " + mc.getOperationName());
136            }
137            if (ops.length > 1) {
138                throw ExceptionFactory.makeWebServiceException(
139                        "More than one operation found. Overloaded WSDL operations are not supported.  WSDL Operation name: " +
140                                mc.getOperationName());
141            }
142            OperationDescription op = ops[0];
143            return op;
144        }
145        
146        private EndpointDescription getEndpointDescription(MessageContext mc) {
147            AxisService axisSvc = mc.getAxisMessageContext().getAxisService();
148    
149            Parameter param = axisSvc.getParameter(EndpointDescription.AXIS_SERVICE_PARAMETER);
150    
151            EndpointDescription ed = (EndpointDescription) param.getValue();
152            return ed;
153        }
154        
155        private Method getProviderMethod() {
156            try {
157                return this.serviceImplClass.getMethod("invoke", getProviderType());
158            } catch (NoSuchMethodException e) {
159                throw ExceptionFactory.makeWebServiceException("Could not get Provider.invoke() method");
160            }
161        }
162        
163        private Class<?> getProviderType() {
164            Class providerType = null;
165    
166            Type[] giTypes = this.serviceImplClass.getGenericInterfaces();
167            for (Type giType : giTypes) {
168                ParameterizedType paramType = null;
169                try {
170                    paramType = (ParameterizedType)giType;
171                } catch (ClassCastException e) {
172                    throw ExceptionFactory.makeWebServiceException(
173                            "Provider based SEI Class has to implement javax.xml.ws.Provider as javax.xml.ws.Provider<String>, javax.xml.ws.Provider<SOAPMessage>, javax.xml.ws.Provider<Source> or javax.xml.ws.Provider<JAXBContext>");
174                }
175                Class interfaceName = (Class)paramType.getRawType();
176    
177                if (interfaceName == javax.xml.ws.Provider.class) {
178                    if (paramType.getActualTypeArguments().length > 1) {
179                        throw ExceptionFactory.makeWebServiceException(
180                                "Provider cannot have more than one Generic Types defined as Per JAX-WS Specification");
181                    }
182                    providerType = (Class)paramType.getActualTypeArguments()[0];
183                }
184            }
185            return providerType;
186        }
187        
188    }