KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > axis > providers > java > RPCProvider


1 /*
2  * Copyright 2001-2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.apache.axis.providers.java;
18
19 import org.apache.axis.AxisFault;
20 import org.apache.axis.Constants;
21 import org.apache.axis.MessageContext;
22 import org.apache.axis.components.logger.LogFactory;
23 import org.apache.axis.description.OperationDesc;
24 import org.apache.axis.description.ParameterDesc;
25 import org.apache.axis.description.ServiceDesc;
26 import org.apache.axis.constants.Style;
27 import org.apache.axis.handlers.soap.SOAPService;
28 import org.apache.axis.message.RPCElement;
29 import org.apache.axis.message.RPCHeaderParam;
30 import org.apache.axis.message.RPCParam;
31 import org.apache.axis.message.SOAPBodyElement;
32 import org.apache.axis.message.SOAPEnvelope;
33 import org.apache.axis.soap.SOAPConstants;
34 import org.apache.axis.utils.JavaUtils;
35 import org.apache.axis.utils.Messages;
36 import org.apache.commons.logging.Log;
37 import org.xml.sax.SAXException JavaDoc;
38
39 import javax.xml.namespace.QName JavaDoc;
40 import javax.xml.rpc.holders.Holder JavaDoc;
41 import javax.wsdl.OperationType;
42 import java.lang.reflect.Method JavaDoc;
43 import java.util.ArrayList JavaDoc;
44 import java.util.Iterator JavaDoc;
45 import java.util.Vector JavaDoc;
46
47 /**
48  * Implement message processing by walking over RPCElements of the
49  * envelope body, invoking the appropriate methods on the service object.
50  *
51  * @author Doug Davis (dug@us.ibm.com)
52  */

53 public class RPCProvider extends JavaProvider {
54     protected static Log log =
55             LogFactory.getLog(RPCProvider.class.getName());
56
57     /**
58      * Process the current message.
59      * Result in resEnv.
60      *
61      * @param msgContext self-explanatory
62      * @param reqEnv the request envelope
63      * @param resEnv the response envelope
64      * @param obj the service object itself
65      */

66     public void processMessage(MessageContext msgContext,
67                                SOAPEnvelope reqEnv,
68                                SOAPEnvelope resEnv,
69                                Object JavaDoc obj)
70             throws Exception JavaDoc {
71         if (log.isDebugEnabled()) {
72             log.debug("Enter: RPCProvider.processMessage()");
73         }
74
75         SOAPService service = msgContext.getService();
76         ServiceDesc serviceDesc = service.getServiceDescription();
77         OperationDesc operation = msgContext.getOperation();
78
79         Vector JavaDoc bodies = reqEnv.getBodyElements();
80         if (log.isDebugEnabled()) {
81             log.debug(Messages.getMessage("bodyElems00", "" + bodies.size()));
82             if(bodies.size()>0){
83                 log.debug(Messages.getMessage("bodyIs00", "" + bodies.get(0)));
84             }
85         }
86
87         RPCElement body = null;
88
89         // Find the first "root" body element, which is the RPC call.
90
for (int bNum = 0; body == null && bNum < bodies.size(); bNum++) {
91             // If this is a regular old SOAPBodyElement, and it's a root,
92
// we're probably a non-wrapped doc/lit service. In this case,
93
// we deserialize the element, and create an RPCElement "wrapper"
94
// around it which points to the correct method.
95
// FIXME : There should be a cleaner way to do this...
96
if (!(bodies.get(bNum) instanceof RPCElement)) {
97                 SOAPBodyElement bodyEl = (SOAPBodyElement) bodies.get(bNum);
98                 // igors: better check if bodyEl.getID() != null
99
// to make sure this loop does not step on SOAP-ENC objects
100
// that follow the parameters! FIXME?
101
if (bodyEl.isRoot() && operation != null && bodyEl.getID() == null) {
102                     ParameterDesc param = operation.getParameter(bNum);
103                     // at least do not step on non-existent parameters!
104
if (param != null) {
105                         Object JavaDoc val = bodyEl.getValueAsType(param.getTypeQName());
106                         body = new RPCElement("",
107                                               operation.getName(),
108                                               new Object JavaDoc[]{val});
109                     }
110                 }
111             } else {
112                 body = (RPCElement) bodies.get(bNum);
113             }
114         }
115
116         // special case code for a document style operation with no
117
// arguments (which is a strange thing to have, but whatever)
118
if (body == null) {
119             // throw an error if this isn't a document style service
120
if (!(serviceDesc.getStyle().equals(Style.DOCUMENT))) {
121                 throw new Exception JavaDoc(Messages.getMessage("noBody00"));
122             }
123             
124             // look for a method in the service that has no arguments,
125
// use the first one we find.
126
ArrayList JavaDoc ops = serviceDesc.getOperations();
127             for (Iterator JavaDoc iterator = ops.iterator(); iterator.hasNext();) {
128                 OperationDesc desc = (OperationDesc) iterator.next();
129                 if (desc.getNumInParams() == 0) {
130                     // found one with no parameters, use it
131
msgContext.setOperation(desc);
132                     // create an empty element
133
body = new RPCElement(desc.getName());
134                     // stop looking
135
break;
136                 }
137             }
138             
139             // If we still didn't find anything, report no body error.
140
if (body == null) {
141                 throw new Exception JavaDoc(Messages.getMessage("noBody00"));
142             }
143         }
144
145         String JavaDoc methodName = body.getMethodName();
146         Vector JavaDoc args = null;
147         try {
148             args = body.getParams();
149         } catch (SAXException JavaDoc e) {
150             if(e.getException() != null)
151                 throw e.getException();
152             throw e;
153         }
154         int numArgs = args.size();
155         
156         // This may have changed, so get it again...
157
// FIXME (there should be a cleaner way to do this)
158
operation = msgContext.getOperation();
159
160         if (operation == null) {
161             QName JavaDoc qname = new QName JavaDoc(body.getNamespaceURI(),
162                     body.getName());
163             operation = serviceDesc.getOperationByElementQName(qname);
164
165         if (operation == null) {
166             SOAPConstants soapConstants = msgContext == null ?
167                     SOAPConstants.SOAP11_CONSTANTS :
168                     msgContext.getSOAPConstants();
169             if (soapConstants == SOAPConstants.SOAP12_CONSTANTS) {
170                 AxisFault fault =
171                         new AxisFault(Constants.FAULT_SOAP12_SENDER,
172                                       Messages.getMessage("noSuchOperation",
173                                                           methodName),
174                                       null,
175                                       null);
176                 fault.addFaultSubCode(Constants.FAULT_SUBCODE_PROC_NOT_PRESENT);
177                 throw new SAXException JavaDoc(fault);
178             } else {
179                 throw new AxisFault(Constants.FAULT_CLIENT, Messages.getMessage("noSuchOperation", methodName),
180                         null, null);
181             }
182             } else {
183                  msgContext.setOperation(operation);
184             }
185         }
186         
187         // Create the array we'll use to hold the actual parameter
188
// values. We know how big to make it from the metadata.
189
Object JavaDoc[] argValues = new Object JavaDoc[operation.getNumParams()];
190
191         // A place to keep track of the out params (INOUTs and OUTs)
192
ArrayList JavaDoc outs = new ArrayList JavaDoc();
193         
194         // Put the values contained in the RPCParams into an array
195
// suitable for passing to java.lang.reflect.Method.invoke()
196
// Make sure we respect parameter ordering if we know about it
197
// from metadata, and handle whatever conversions are necessary
198
// (values -> Holders, etc)
199
for (int i = 0; i < numArgs; i++) {
200             RPCParam rpcParam = (RPCParam) args.get(i);
201             Object JavaDoc value = rpcParam.getObjectValue();
202             
203             // first check the type on the paramter
204
ParameterDesc paramDesc = rpcParam.getParamDesc();
205             
206             // if we found some type info try to make sure the value type is
207
// correct. For instance, if we deserialized a xsd:dateTime in
208
// to a Calendar and the service takes a Date, we need to convert
209
if (paramDesc != null && paramDesc.getJavaType() != null) {
210
211                 // Get the type in the signature (java type or its holder)
212
Class JavaDoc sigType = paramDesc.getJavaType();
213                 
214                 // Convert the value into the expected type in the signature
215
value = JavaUtils.convert(value, sigType);
216
217                 rpcParam.setObjectValue(value);
218                 if (paramDesc.getMode() == ParameterDesc.INOUT) {
219                     outs.add(rpcParam);
220                 }
221             }
222             
223             // Put the value (possibly converted) in the argument array
224
// make sure to use the parameter order if we have it
225
if (paramDesc == null || paramDesc.getOrder() == -1) {
226                 argValues[i] = value;
227             } else {
228                 argValues[paramDesc.getOrder()] = value;
229             }
230
231             if (log.isDebugEnabled()) {
232                 log.debug(" " + Messages.getMessage("value00",
233                         "" + argValues[i]));
234             }
235         }
236         
237         // See if any subclasses want a crack at faulting on a bad operation
238
// FIXME : Does this make sense here???
239
String JavaDoc allowedMethods = (String JavaDoc) service.getOption("allowedMethods");
240         checkMethodName(msgContext, allowedMethods, operation.getName());
241
242         // Now create any out holders we need to pass in
243
int count = numArgs;
244         for (int i = 0; i < argValues.length; i++) {
245             
246             // We are interested only in OUT/INOUT
247
ParameterDesc param = operation.getParameter(i);
248             if(param.getMode() == ParameterDesc.IN)
249                 continue;
250
251             Class JavaDoc holderClass = param.getJavaType();
252             if (holderClass != null &&
253                     Holder JavaDoc.class.isAssignableFrom(holderClass)) {
254                 int index = count;
255                 // Use the parameter order if specified or just stick them to the end.
256
if (param.getOrder() != -1) {
257                     index = param.getOrder();
258                 } else {
259                     count++;
260                 }
261                 // If it's already filled, don't muck with it
262
if (argValues[index] != null) {
263                     continue;
264                 }
265                 argValues[index] = holderClass.newInstance();
266                 // Store an RPCParam in the outs collection so we
267
// have an easy and consistent way to write these
268
// back to the client below
269
RPCParam p = new RPCParam(param.getQName(),
270                         argValues[index]);
271                 p.setParamDesc(param);
272                 outs.add(p);
273             } else {
274                 throw new AxisFault(Messages.getMessage("badOutParameter00",
275                         "" + param.getQName(),
276                         operation.getName()));
277             }
278         }
279         
280         // OK! Now we can invoke the method
281
Object JavaDoc objRes = null;
282         try {
283             objRes = invokeMethod(msgContext,
284                                   operation.getMethod(),
285                                   obj, argValues);
286         } catch (IllegalArgumentException JavaDoc e) {
287             String JavaDoc methodSig = operation.getMethod().toString();
288             String JavaDoc argClasses = "";
289             for (int i = 0; i < argValues.length; i++) {
290                 if (argValues[i] == null) {
291                     argClasses += "null";
292                 } else {
293                     argClasses += argValues[i].getClass().getName();
294                 }
295                 if (i + 1 < argValues.length) {
296                     argClasses += ",";
297                 }
298             }
299             log.info(Messages.getMessage("dispatchIAE00",
300                     new String JavaDoc[]{methodSig, argClasses}),
301                     e);
302             throw new AxisFault(Messages.getMessage("dispatchIAE00",
303                     new String JavaDoc[]{methodSig, argClasses}),
304                     e);
305         }
306         
307         /** If this is a one-way operation, there is nothing more to do.
308          */

309         if (OperationType.ONE_WAY.equals(operation.getMep()))
310
311             return;
312         
313         /* Now put the result in the result SOAPEnvelope */
314         /*************************************************/
315         RPCElement resBody = new RPCElement(methodName + "Response");
316         resBody.setPrefix(body.getPrefix());
317         resBody.setNamespaceURI(body.getNamespaceURI());
318         resBody.setEncodingStyle(msgContext.getEncodingStyle());
319
320         try {
321             // Return first
322
if (operation.getMethod().getReturnType() != Void.TYPE) {
323                 QName JavaDoc returnQName = operation.getReturnQName();
324                 if (returnQName == null) {
325                     String JavaDoc nsp = body.getNamespaceURI();
326                     if(nsp == null || nsp.length()==0) {
327                         nsp = serviceDesc.getDefaultNamespace();
328                     }
329                     returnQName = new QName JavaDoc(msgContext.isEncoded() ? "" :
330                                                 nsp,
331                                             methodName + "Return");
332                 }
333                 
334                 RPCParam param = new RPCParam(returnQName, objRes);
335                 param.setParamDesc(operation.getReturnParamDesc());
336
337                 if (!operation.isReturnHeader()) {
338                     // For SOAP 1.2 rpc style, add a result
339
if (msgContext.getSOAPConstants() == SOAPConstants.SOAP12_CONSTANTS &&
340                             (serviceDesc.getStyle().equals(Style.RPC))) {
341                         RPCParam resultParam = new RPCParam(Constants.QNAME_RPC_RESULT, returnQName);
342                         resultParam.setXSITypeGeneration(Boolean.FALSE);
343                         resBody.addParam(resultParam);
344                     }
345                     resBody.addParam(param);
346                 } else {
347                     resEnv.addHeader(new RPCHeaderParam(param));
348                 }
349
350             }
351             
352             // Then any other out params
353
if (!outs.isEmpty()) {
354                 for (Iterator JavaDoc i = outs.iterator(); i.hasNext();) {
355                     // We know this has a holder, so just unwrap the value
356
RPCParam param = (RPCParam) i.next();
357                     Holder JavaDoc holder = (Holder JavaDoc) param.getObjectValue();
358                     Object JavaDoc value = JavaUtils.getHolderValue(holder);
359                     ParameterDesc paramDesc = param.getParamDesc();
360
361                     param.setObjectValue(value);
362                     if (paramDesc != null && paramDesc.isOutHeader()) {
363                         resEnv.addHeader(new RPCHeaderParam(param));
364                     } else {
365                         resBody.addParam(param);
366                     }
367                 }
368             }
369         } catch (Exception JavaDoc e) {
370             throw e;
371         }
372
373         resEnv.addBodyElement(resBody);
374     }
375
376     /**
377      * This method encapsulates the method invocation.
378      *
379      * @param msgContext MessageContext
380      * @param method the target method.
381      * @param obj the target object
382      * @param argValues the method arguments
383      */

384     protected Object JavaDoc invokeMethod(MessageContext msgContext,
385                                   Method JavaDoc method, Object JavaDoc obj,
386                                   Object JavaDoc[] argValues)
387             throws Exception JavaDoc {
388         return (method.invoke(obj, argValues));
389     }
390
391     /**
392      * Throw an AxisFault if the requested method is not allowed.
393      *
394      * @param msgContext MessageContext
395      * @param allowedMethods list of allowed methods
396      * @param methodName name of target method
397      */

398     protected void checkMethodName(MessageContext msgContext,
399                                    String JavaDoc allowedMethods,
400                                    String JavaDoc methodName)
401             throws Exception JavaDoc {
402         // Our version doesn't need to do anything, though inherited
403
// ones might.
404
}
405 }
406
Popular Tags