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: */package org.apache.openejb.server.axis;
017:
018: import org.apache.axis.AxisFault;
019: import org.apache.axis.Constants;
020: import org.apache.axis.Handler;
021: import org.apache.axis.Message;
022: import org.apache.axis.MessageContext;
023: import org.apache.axis.description.OperationDesc;
024: import org.apache.axis.description.ParameterDesc;
025: import org.apache.axis.description.ServiceDesc;
026: import org.apache.axis.encoding.XMLType;
027: import org.apache.axis.encoding.DeserializationContext;
028: import org.apache.axis.message.RPCElement;
029: import org.apache.axis.message.RPCParam;
030: import org.apache.axis.message.SOAPEnvelope;
031: import org.apache.axis.message.SOAPBodyElement;
032: import org.apache.axis.message.SOAPFault;
033: import org.apache.axis.providers.java.RPCProvider;
034: import org.apache.axis.utils.JavaUtils;
035: import org.apache.openejb.ApplicationException;
036: import org.apache.openejb.DeploymentInfo;
037: import org.apache.openejb.InvalidateReferenceException;
038: import org.apache.openejb.RpcContainer;
039: import org.xml.sax.SAXException;
040: import org.xml.sax.InputSource;
041:
042: import javax.interceptor.AroundInvoke;
043: import javax.interceptor.InvocationContext;
044: import javax.xml.rpc.handler.HandlerChain;
045: import javax.xml.rpc.handler.HandlerInfo;
046: import javax.xml.rpc.holders.IntHolder;
047: import javax.xml.rpc.soap.SOAPFaultException;
048: import javax.xml.soap.SOAPMessage;
049: import javax.xml.namespace.QName;
050: import java.io.ByteArrayOutputStream;
051: import java.io.ByteArrayInputStream;
052: import java.util.ArrayList;
053: import java.util.List;
054: import java.util.Vector;
055:
056: public class EjbContainerProvider extends RPCProvider {
057:
058: private final DeploymentInfo ejbDeployment;
059: private final List<HandlerInfo> handlerInfos;
060:
061: public EjbContainerProvider(DeploymentInfo ejbDeployment) {
062: this .ejbDeployment = ejbDeployment;
063: this .handlerInfos = new ArrayList<HandlerInfo>();
064: }
065:
066: public EjbContainerProvider(DeploymentInfo ejbDeployment,
067: List<HandlerInfo> handlerInfos) {
068: this .ejbDeployment = ejbDeployment;
069: this .handlerInfos = handlerInfos;
070: }
071:
072: public void processMessage(MessageContext msgContext,
073: SOAPEnvelope reqEnv, SOAPEnvelope resEnv, Object obj)
074: throws Exception {
075:
076: RPCElement body = getBody(reqEnv, msgContext);
077: OperationDesc operation = getOperationDesc(msgContext, body);
078:
079: AxisRpcInterceptor interceptor = new AxisRpcInterceptor(
080: operation, msgContext);
081: SOAPMessage message = msgContext.getMessage();
082:
083: try {
084: message.getSOAPPart().getEnvelope();
085: msgContext.setProperty(
086: org.apache.axis.SOAPPart.ALLOW_FORM_OPTIMIZATION,
087: Boolean.FALSE);
088:
089: RpcContainer container = (RpcContainer) ejbDeployment
090: .getContainer();
091:
092: Object[] arguments = { msgContext, interceptor };
093:
094: Class callInterface = ejbDeployment
095: .getServiceEndpointInterface();
096: Object result = container.invoke(ejbDeployment
097: .getDeploymentID(), callInterface, operation
098: .getMethod(), arguments, null);
099:
100: interceptor.createResult(result);
101: } catch (InvalidateReferenceException e) {
102: interceptor.createExceptionResult(e.getCause());
103: } catch (ApplicationException e) {
104: interceptor.createExceptionResult(e.getCause());
105: } catch (Throwable throwable) {
106: throw new AxisFault(
107: "Web Service EJB Invocation failed: method "
108: + operation.getMethod(), throwable);
109: }
110: }
111:
112: public Object getServiceObject(MessageContext msgContext,
113: Handler service, String clsName, IntHolder scopeHolder)
114: throws Exception {
115: return ejbDeployment;
116: }
117:
118: /**
119: * This class is intentionally not static or top level class
120: * as it leverages logic in RPCProvider
121: *
122: * @see org.apache.axis.providers.java.RPCProvider
123: */
124: public class AxisRpcInterceptor {
125:
126: private OperationDesc operation;
127: private MessageContext messageContext;
128:
129: public AxisRpcInterceptor(OperationDesc operation,
130: MessageContext msgContext) throws Exception {
131: this .messageContext = msgContext;
132: this .operation = operation;
133: }
134:
135: @AroundInvoke
136: public Object intercept(InvocationContext context)
137: throws Exception {
138: HandlerChain handlerChain = new HandlerChainImpl(
139: handlerInfos);
140: try {
141: Object invocationResult = null;
142:
143: try {
144: if (handlerChain.handleRequest(messageContext)) {
145: // update arguments as handlers could change the soap msg
146: context.setParameters(getArguments());
147:
148: invocationResult = context.proceed();
149:
150: // update the soap msg so that handlers see invocation result
151: if (!handlerChain.isEmpty()) {
152: createResult(invocationResult);
153: }
154:
155: } else {
156: /* The Handler implementation class has the responsibility of setting
157: * the response SOAP message in the handleRequest method and perform
158: * additional processing in the handleResponse method.
159: */
160: invocationResult = null;
161: }
162: } catch (SOAPFaultException e) {
163: handlerChain.handleFault(messageContext);
164: throw e;
165: }
166:
167: handlerChain.handleResponse(messageContext);
168:
169: if (!handlerChain.isEmpty()) {
170: /*
171: * Deserialize the result value from soap msg as handers could have
172: * changed it.
173: */
174: try {
175: invocationResult = demarshallResult();
176: } catch (Exception e) {
177: // if this fails, return invocationResult from above
178: }
179: }
180:
181: return invocationResult;
182: } finally {
183: handlerChain.destroy();
184: }
185: }
186:
187: public Object[] getArguments() {
188: try {
189: return demarshallArguments();
190: } catch (Exception e) {
191: throw (IllegalStateException) new IllegalStateException(
192: "Cannot demarshal the soap parts into arguments")
193: .initCause(e);
194: }
195: }
196:
197: private Object[] demarshallArguments() throws Exception {
198: SOAPMessage message = messageContext.getMessage();
199: messageContext.setProperty(
200: org.apache.axis.SOAPPart.ALLOW_FORM_OPTIMIZATION,
201: Boolean.TRUE);
202: if (message != null) {
203: message.saveChanges();
204: }
205:
206: try {
207: Message reqMsg = messageContext.getRequestMessage();
208: SOAPEnvelope requestEnvelope = reqMsg.getSOAPEnvelope();
209: RPCElement body = getBody(requestEnvelope,
210: messageContext);
211: body.setNeedDeser(true);
212: Vector args = null;
213: try {
214: args = body.getParams();
215: } catch (SAXException e) {
216: if (e.getException() != null) {
217: throw e.getException();
218: }
219: throw e;
220: }
221:
222: Object[] argValues = new Object[operation
223: .getNumParams()];
224:
225: for (int i = 0; i < args.size(); i++) {
226: RPCParam rpcParam = (RPCParam) args.get(i);
227: Object value = rpcParam.getObjectValue();
228:
229: ParameterDesc paramDesc = rpcParam.getParamDesc();
230:
231: if (paramDesc != null
232: && paramDesc.getJavaType() != null) {
233: value = JavaUtils.convert(value, paramDesc
234: .getJavaType());
235: rpcParam.setObjectValue(value);
236: }
237: int order = (paramDesc == null || paramDesc
238: .getOrder() == -1) ? i : paramDesc
239: .getOrder();
240: argValues[order] = value;
241: }
242: return argValues;
243: } finally {
244: messageContext
245: .setProperty(
246: org.apache.axis.SOAPPart.ALLOW_FORM_OPTIMIZATION,
247: Boolean.FALSE);
248: }
249: }
250:
251: private Object demarshallResult() throws Exception {
252: Message resMsg = messageContext.getResponseMessage();
253:
254: /*
255: * This is not the most efficient way to deserialize the result
256: * but could not find better or more reliable way to do this.
257: */
258: ByteArrayOutputStream out = new ByteArrayOutputStream();
259: resMsg.writeTo(out);
260: ByteArrayInputStream in = new ByteArrayInputStream(out
261: .toByteArray());
262:
263: DeserializationContext dser = new DeserializationContext(
264: new InputSource(in), resMsg.getMessageContext(),
265: null);
266: dser.parse();
267: SOAPEnvelope responseEnvelope = dser.getEnvelope();
268:
269: SOAPBodyElement bodyEl = responseEnvelope.getFirstBody();
270: if (bodyEl == null) {
271: return null;
272: }
273:
274: QName returnType = operation.getReturnType();
275: if (XMLType.AXIS_VOID.equals(returnType)) {
276: return null;
277: }
278:
279: Object result = null;
280:
281: if (bodyEl instanceof RPCElement) {
282: RPCElement body = (RPCElement) bodyEl;
283: body.setNeedDeser(true);
284: Vector args = null;
285: try {
286: args = body.getParams();
287: } catch (SAXException e) {
288: if (e.getException() != null) {
289: throw e.getException();
290: }
291: throw e;
292: }
293:
294: QName returnParamQName = operation.getReturnQName();
295: if (args != null && args.size() > 0) {
296:
297: if (returnParamQName == null) {
298: RPCParam param = (RPCParam) args.get(0);
299: result = param.getObjectValue();
300: } else {
301: for (int i = 0; i < args.size(); i++) {
302: RPCParam param = (RPCParam) args.get(i);
303: if (returnParamQName.equals(param
304: .getQName())) {
305: result = param.getObjectValue();
306: break;
307: }
308: }
309: }
310:
311: }
312: } else {
313: try {
314: result = bodyEl.getValueAsType(returnType);
315: } catch (Exception e) {
316: result = bodyEl;
317: }
318: }
319:
320: if (operation.getReturnClass() != null) {
321: result = JavaUtils.convert(result, operation
322: .getReturnClass());
323: }
324:
325: return result;
326: }
327:
328: public void createResult(Object object) {
329: messageContext.setPastPivot(true);
330: try {
331: Message requestMessage = messageContext
332: .getRequestMessage();
333: SOAPEnvelope requestEnvelope = requestMessage
334: .getSOAPEnvelope();
335: RPCElement requestBody = getBody(requestEnvelope,
336: messageContext);
337:
338: Message responseMessage = messageContext
339: .getResponseMessage();
340: SOAPEnvelope responseEnvelope = responseMessage
341: .getSOAPEnvelope();
342: ServiceDesc serviceDescription = messageContext
343: .getService().getServiceDescription();
344: RPCElement responseBody = createResponseBody(
345: requestBody, messageContext, operation,
346: serviceDescription, object, responseEnvelope,
347: getInOutParams());
348:
349: responseEnvelope.removeBody();
350: responseEnvelope.addBodyElement(responseBody);
351: } catch (Exception e) {
352: throw new RuntimeException(
353: "Failed while creating response message body",
354: e);
355: }
356: }
357:
358: public void createExceptionResult(Throwable exception) {
359: messageContext.setPastPivot(true);
360:
361: AxisFault axisFault = null;
362: if (exception instanceof Exception) {
363: axisFault = AxisFault.makeFault((Exception) exception);
364: axisFault
365: .setFaultCodeAsString(Constants.FAULT_SERVER_GENERAL);
366: } else {
367: axisFault = new AxisFault("Server", "Server Error",
368: null, null);
369: }
370:
371: SOAPFault fault = new SOAPFault(axisFault);
372: SOAPEnvelope envelope = new SOAPEnvelope();
373: envelope.addBodyElement(fault);
374: Message message = new Message(envelope);
375: message.setMessageType(Message.RESPONSE);
376: messageContext.setResponseMessage(message);
377: }
378:
379: public ArrayList getInOutParams() {
380: return new ArrayList(); //TODO collect out an inout params in demarshalArguments
381: }
382: }
383:
384: }
|