dblevins 2005/06/17 18:59:56
Modified: modules/core/src/java/org/openejb/server/axis
EJBContainerProvider.java
Log:
Completely rewritten EJBContainerProvider leveraging the refactored
RPCProvider. The focus of this class is to have the demarshalling of
SAAJ->Java to occur whenever getArguments is called on the Invocation
instance (AxisRpcInvocation) allowing the EjbContainer to process the
handler chain in a non-axis specific way. Further benefits are that
any Interceptor in the EjbContainer stack could modify the MessageContext.
Currently there is a bug in Axis that prevents us from being able to
call getArguments more than once. The code works now despite this
bug, but any call to getArguments before the Invocation has gone
through the HandlerChain will trigger the bug.
http://issues.apache.org/jira/browse/AXIS-2062
Also, I temporarily removed OUT and INOUT param and Holder support to
get things working. I'll be putting those back asap.
Revision Changes Path
1.5 +200 -22
openejb/modules/core/src/java/org/openejb/server/axis/EJBContainerProvider.java
Index: EJBContainerProvider.java
===================================================================
RCS file:
/scm/openejb/openejb/modules/core/src/java/org/openejb/server/axis/EJBContainerProvider.java,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- EJBContainerProvider.java 3 May 2005 15:34:40 -0000 1.4
+++ EJBContainerProvider.java 17 Jun 2005 22:59:56 -0000 1.5
@@ -1,25 +1,79 @@
-/*
- * Copyright (c) 2005 Your Corporation. All Rights Reserved.
+/**
+ * Redistribution and use of this software and associated documentation
+ * ("Software"), with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain copyright
+ * statements and notices. Redistributions must also contain a
+ * copy of this document.
+ *
+ * 2. Redistributions in binary form must reproduce the
+ * above copyright notice, this list of conditions and the
+ * following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. The name "OpenEJB" must not be used to endorse or promote
+ * products derived from this Software without prior written
+ * permission of The OpenEJB Group. For written permission,
+ * please contact [EMAIL PROTECTED]
+ *
+ * 4. Products derived from this Software may not be called "OpenEJB"
+ * nor may "OpenEJB" appear in their names without prior written
+ * permission of The OpenEJB Group. OpenEJB is a registered
+ * trademark of The OpenEJB Group.
+ *
+ * 5. Due credit should be given to the OpenEJB Project
+ * (http://openejb.org/).
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OPENEJB GROUP AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE OPENEJB GROUP OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Copyright 2005 (C) The OpenEJB Group. All Rights Reserved.
+ *
+ * $Id$
*/
package org.openejb.server.axis;
-import java.lang.reflect.Method;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
-import java.util.Iterator;
+import java.util.Vector;
+import javax.xml.rpc.handler.soap.SOAPMessageContext;
import javax.xml.rpc.holders.IntHolder;
+import javax.xml.soap.SOAPMessage;
-import org.apache.axis.providers.java.RPCProvider;
-import org.apache.axis.MessageContext;
-import org.apache.axis.Handler;
import org.apache.axis.AxisFault;
+import org.apache.axis.Handler;
+import org.apache.axis.Message;
+import org.apache.axis.MessageContext;
+import org.apache.axis.description.OperationDesc;
+import org.apache.axis.description.ParameterDesc;
+import org.apache.axis.description.ServiceDesc;
import org.apache.axis.handlers.soap.SOAPService;
-import org.apache.geronimo.webservices.MessageContextInvocationKey;
+import org.apache.axis.message.RPCElement;
+import org.apache.axis.message.RPCParam;
+import org.apache.axis.message.SOAPEnvelope;
+import org.apache.axis.providers.java.RPCProvider;
+import org.apache.axis.utils.JavaUtils;
+import org.apache.geronimo.core.service.InvocationKey;
import org.apache.geronimo.core.service.InvocationResult;
+import org.apache.geronimo.transaction.context.TransactionContext;
+import org.apache.geronimo.webservices.MessageContextInvocationKey;
import org.openejb.EJBContainer;
-import org.openejb.EJBInvocation;
-import org.openejb.EJBInvocationImpl;
+import org.openejb.EJBInstanceContext;
import org.openejb.EJBInterfaceType;
+import org.openejb.EJBInvocation;
+import org.xml.sax.SAXException;
public class EJBContainerProvider extends RPCProvider {
private final EJBContainer ejbContainer;
@@ -28,28 +82,152 @@
this.ejbContainer = ejbContainer;
}
- public Object getServiceObject(MessageContext msgContext, Handler
service, String clsName, IntHolder scopeHolder) throws Exception {
- return ejbContainer;
- }
+ public void processMessage(MessageContext msgContext, SOAPEnvelope
reqEnv, SOAPEnvelope resEnv, Object obj) throws Exception {
- protected Object invokeMethod(MessageContext msgContext, Method method,
Object obj, Object[] params) throws Exception {
- int index = ejbContainer.getMethodIndex(method);
- EJBInvocation invocation = new
EJBInvocationImpl(EJBInterfaceType.WEB_SERVICE, null, index, params);
+ RPCElement body = getBody(reqEnv, msgContext);
+ OperationDesc operation = getOperationDesc(msgContext, body);
+
+ int index = ejbContainer.getMethodIndex(operation.getMethod());
+ AxisRpcInvocation invocation = new AxisRpcInvocation(operation,
msgContext, index);
invocation.put(MessageContextInvocationKey.INSTANCE, msgContext);
+ SOAPMessage message = ((SOAPMessageContext) msgContext).getMessage();
+ Object objRes = null;
try {
+ message.getSOAPPart().getEnvelope();
+
msgContext.setProperty(org.apache.axis.SOAPPart.ALLOW_FORM_OPTIMIZATION,
Boolean.FALSE);
+
InvocationResult invocationResult =
ejbContainer.invoke(invocation);
if (invocationResult.isException()) {
throw (Throwable) invocationResult.getException();
}
- return invocationResult.getResult();
+ objRes = invocationResult.getResult();
} catch (Throwable throwable) {
- if (throwable instanceof Exception){
- throw (Exception) throwable;
- } else {
- throw (Error) throwable;
- }
+ throw new AxisFault("Web Service EJB Invocation failed: method "
+ operation.getMethod(), throwable);
}
+
+ SOAPService service = msgContext.getService();
+ ServiceDesc serviceDescription = service.getServiceDescription();
+ ArrayList inoutParams = invocation.getInOutParams();
+ RPCElement resBody = createResponseBody(body, msgContext, operation,
serviceDescription, objRes, resEnv, inoutParams);
+ resEnv.addBodyElement(resBody);
+ }
+
+ public Object getServiceObject(MessageContext msgContext, Handler
service, String clsName, IntHolder scopeHolder) throws Exception {
+ return ejbContainer;
}
+ /**
+ * This class is intentionally not static or top level class
+ * as it leverages logic in RPCProvider
+ *
+ * @see org.apache.axis.providers.java.RPCProvider
+ */
+ private class AxisRpcInvocation implements EJBInvocation {
+ private int index;
+
+ // Valid in server-side interceptor stack once an instance has been
identified
+ private transient EJBInstanceContext instanceContext;
+
+ // Valid in server-side interceptor stack once a TransactionContext
has been created
+ private transient TransactionContext transactionContext;
+
+ private Map attributes = new HashMap();
+ private OperationDesc operation;
+ private MessageContext messageContext;
+
+ public AxisRpcInvocation(OperationDesc operation, MessageContext
msgContext, int index) throws Exception {
+ this.messageContext = msgContext;
+ this.index = index;
+ this.operation = operation;
+ }
+
+ public int getMethodIndex() {
+ return index;
+ }
+
+ public EJBInterfaceType getType() {
+ return EJBInterfaceType.WEB_SERVICE;
+ }
+
+ public Object[] getArguments() {
+ try {
+ return demarshallArguments();
+ } catch (Exception e) {
+ throw (IllegalStateException) new
IllegalStateException("Cannot demarshal the soap parts into
arguments").initCause(e);
+ }
+ }
+
+ private Object[] demarshallArguments() throws Exception {
+ SOAPMessage message = ((SOAPMessageContext)
messageContext).getMessage();
+
messageContext.setProperty(org.apache.axis.SOAPPart.ALLOW_FORM_OPTIMIZATION,
Boolean.TRUE);
+ if (message != null) {
+ message.saveChanges();
+ }
+ try {
+ Message reqMsg = messageContext.getRequestMessage();
+ SOAPEnvelope requestEnvelope = reqMsg.getSOAPEnvelope();
+ RPCElement body = getBody(requestEnvelope, messageContext);
+ body.setNeedDeser(true);
+ Vector args = null;
+ try {
+ args = body.getParams();
+ } catch (SAXException e) {
+ if (e.getException() != null) throw e.getException();
+ throw e;
+ }
+
+ Object[] argValues = new Object[operation.getNumParams()];
+
+ for (int i = 0; i < args.size(); i++) {
+ RPCParam rpcParam = (RPCParam) args.get(i);
+ Object value = rpcParam.getObjectValue();
+
+ ParameterDesc paramDesc = rpcParam.getParamDesc();
+
+ if (paramDesc != null && paramDesc.getJavaType() !=
null) {
+ value = JavaUtils.convert(value,
paramDesc.getJavaType());
+ rpcParam.setObjectValue(value);
+ }
+ int order = (paramDesc == null || paramDesc.getOrder()
== -1) ? i : paramDesc.getOrder();
+ argValues[order] = value;
+ }
+ return argValues;
+ } finally {
+
messageContext.setProperty(org.apache.axis.SOAPPart.ALLOW_FORM_OPTIMIZATION,
Boolean.FALSE);
+ }
+ }
+
+ public Object getId() {
+ return null;
+ }
+
+ public EJBInstanceContext getEJBInstanceContext() {
+ return instanceContext;
+ }
+
+ public void setEJBInstanceContext(EJBInstanceContext
instanceContext) {
+ this.instanceContext = instanceContext;
+ }
+
+ public TransactionContext getTransactionContext() {
+ return transactionContext;
+ }
+
+ public void setTransactionContext(TransactionContext
transactionContext) {
+ this.transactionContext = transactionContext;
+ }
+
+ public Object get(InvocationKey key) {
+ return attributes.get(key);
+ }
+
+ public void put(InvocationKey key, Object value) {
+ attributes.put(key, value);
+ }
+
+ public ArrayList getInOutParams() {
+ return new ArrayList(); //TODO collect out an inout params in
demarshalArguments
+ }
+ }
}