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.DeploymentInfo;
040    import org.apache.openejb.RpcContainer;
041    
042    public class EJBMessageReceiver implements MessageReceiver {
043    
044        private static final Log LOG = LogFactory.getLog(EJBMessageReceiver.class);
045        
046        private DeploymentInfo deploymentInfo;
047        private Class serviceImplClass;
048        private EJBWebServiceContainer container;
049    
050        public EJBMessageReceiver(EJBWebServiceContainer container, Class serviceImplClass, DeploymentInfo deploymentInfo) {
051            this.container = container;
052            this.serviceImplClass = serviceImplClass;
053            this.deploymentInfo = deploymentInfo;
054        }
055        
056        public void receive(org.apache.axis2.context.MessageContext axisMsgCtx) throws AxisFault {         
057            MessageContext requestMsgCtx = new MessageContext(axisMsgCtx);
058            
059            // init some bits
060            requestMsgCtx.setOperationName(requestMsgCtx.getAxisMessageContext().getAxisOperation().getName());
061            requestMsgCtx.setEndpointDescription(getEndpointDescription(requestMsgCtx));
062            
063            Method method = null;
064            if (Provider.class.isAssignableFrom(this.serviceImplClass)) {
065                method = getProviderMethod();
066            } else {
067                requestMsgCtx.setOperationDescription(getOperationDescription(requestMsgCtx));
068                method = getServiceMethod(requestMsgCtx);
069            }
070            
071            if (LOG.isDebugEnabled()) {
072                LOG.debug("Invoking '" + method.getName() + "' method.");
073            }
074            
075            EJBInterceptor interceptor = new EJBInterceptor(this.container, requestMsgCtx);
076    
077            SoapMessageContext jaxwsContext = new SoapMessageContext(requestMsgCtx);
078            Object[] arguments = { jaxwsContext, interceptor };
079            
080            RpcContainer container = (RpcContainer) this.deploymentInfo.getContainer();
081    
082            Class callInterface = this.deploymentInfo.getServiceEndpointInterface();
083            
084            method = getMostSpecificMethod(method, callInterface);
085            
086            try {
087                Object res = container.invoke(this.deploymentInfo.getDeploymentID(), callInterface, method, arguments, null);
088                // TODO: update response message with new response value?
089            } catch (Exception e) {
090                throw AxisFault.makeFault(e);
091            }
092        }
093        
094        private static Method getMostSpecificMethod(Method method, Class<?> targetClass) {
095            if (method != null && targetClass != null) {
096                try {
097                    method = targetClass.getMethod(method.getName(), method.getParameterTypes());
098                } catch (NoSuchMethodException ex) {
099                    // Perhaps the target class doesn't implement this method:
100                    // that's fine, just use the original method
101                }
102            }
103            return method;
104        }
105        
106        private Method getServiceMethod(MessageContext mc) {
107            OperationDescription opDesc = mc.getOperationDescription();
108            if (opDesc == null) {
109                throw ExceptionFactory.makeWebServiceException("Operation Description was not set");
110            }
111    
112            Method returnMethod = opDesc.getMethodFromServiceImpl(this.serviceImplClass);
113            if (returnMethod == null) {
114                throw ExceptionFactory
115                        .makeWebServiceException(Messages.getMessage("JavaBeanDispatcherErr1"));
116            }
117    
118            return returnMethod;
119        }
120        
121        private OperationDescription getOperationDescription(MessageContext mc) {
122            EndpointDescription ed = mc.getEndpointDescription();
123            EndpointInterfaceDescription eid = ed.getEndpointInterfaceDescription();
124            
125            OperationDescription[] ops = eid.getDispatchableOperation(mc.getOperationName());
126            if (ops == null || ops.length == 0) {
127                throw ExceptionFactory.makeWebServiceException(
128                        "No operation found.  WSDL Operation name: " + mc.getOperationName());
129            }
130            if (ops.length > 1) {
131                throw ExceptionFactory.makeWebServiceException(
132                        "More than one operation found. Overloaded WSDL operations are not supported.  WSDL Operation name: " +
133                                mc.getOperationName());
134            }
135            OperationDescription op = ops[0];
136            return op;
137        }
138        
139        private EndpointDescription getEndpointDescription(MessageContext mc) {
140            AxisService axisSvc = mc.getAxisMessageContext().getAxisService();
141    
142            Parameter param = axisSvc.getParameter(EndpointDescription.AXIS_SERVICE_PARAMETER);
143    
144            EndpointDescription ed = (EndpointDescription) param.getValue();
145            return ed;
146        }
147        
148        private Method getProviderMethod() {
149            try {
150                return this.serviceImplClass.getMethod("invoke", getProviderType());
151            } catch (NoSuchMethodException e) {
152                throw ExceptionFactory.makeWebServiceException("Could not get Provider.invoke() method");
153            }
154        }
155        
156        private Class<?> getProviderType() {
157            Class providerType = null;
158    
159            Type[] giTypes = this.serviceImplClass.getGenericInterfaces();
160            for (Type giType : giTypes) {
161                ParameterizedType paramType = null;
162                try {
163                    paramType = (ParameterizedType)giType;
164                } catch (ClassCastException e) {
165                    throw ExceptionFactory.makeWebServiceException(
166                            "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>");
167                }
168                Class interfaceName = (Class)paramType.getRawType();
169    
170                if (interfaceName == javax.xml.ws.Provider.class) {
171                    if (paramType.getActualTypeArguments().length > 1) {
172                        throw ExceptionFactory.makeWebServiceException(
173                                "Provider cannot have more than one Generic Types defined as Per JAX-WS Specification");
174                    }
175                    providerType = (Class)paramType.getActualTypeArguments()[0];
176                }
177            }
178            return providerType;
179        }
180        
181    }