KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > axis > message > RPCElement


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.message;
18
19 import org.apache.axis.AxisFault;
20 import org.apache.axis.Constants;
21 import org.apache.axis.Message;
22 import org.apache.axis.MessageContext;
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.encoding.DeserializationContext;
27 import org.apache.axis.encoding.SerializationContext;
28 import org.apache.axis.constants.Style;
29 import org.apache.axis.constants.Use;
30 import org.apache.axis.handlers.soap.SOAPService;
31 import org.apache.axis.soap.SOAPConstants;
32 import org.apache.axis.utils.JavaUtils;
33 import org.apache.axis.utils.Messages;
34 import org.apache.axis.wsdl.toJava.Utils;
35 import org.xml.sax.Attributes JavaDoc;
36 import org.xml.sax.SAXException JavaDoc;
37
38 import javax.xml.namespace.QName JavaDoc;
39 import javax.xml.soap.SOAPElement JavaDoc;
40 import java.util.ArrayList JavaDoc;
41 import java.util.Enumeration JavaDoc;
42 import java.util.Vector JavaDoc;
43 import java.util.Iterator JavaDoc;
44 import java.util.List JavaDoc;
45 import java.util.Collection JavaDoc;
46
47 public class RPCElement extends SOAPBodyElement
48 {
49     //protected Vector params2 = new Vector();
50
protected boolean needDeser = false;
51     OperationDesc [] operations = null;
52
53     public RPCElement(String JavaDoc namespace,
54                       String JavaDoc localName,
55                       String JavaDoc prefix,
56                       Attributes JavaDoc attributes,
57                       DeserializationContext context,
58                       OperationDesc [] operations) throws AxisFault
59     {
60         super(namespace, localName, prefix, attributes, context);
61
62         // This came from parsing XML, so we need to deserialize it sometime
63
needDeser = true;
64
65         // Obtain our possible operations
66
if (operations == null) {
67             updateOperationsByName();
68         } else {
69             this.operations = operations;
70         }
71     }
72
73     public RPCElement(String JavaDoc namespace, String JavaDoc methodName, Object JavaDoc [] args)
74     {
75         this.setNamespaceURI(namespace);
76         this.name = methodName;
77
78         for (int i = 0; args != null && i < args.length; i++) {
79             if (args[i] instanceof RPCParam) {
80                 addParam((RPCParam)args[i]);
81             } else {
82                 String JavaDoc name = null;
83                 if (name == null) name = "arg" + i;
84                 addParam(new RPCParam(namespace, name, args[i]));
85             }
86         }
87     }
88
89     public RPCElement(String JavaDoc methodName)
90     {
91         this.name = methodName;
92     }
93
94     public void updateOperationsByName() throws AxisFault
95     {
96         if (context == null) {
97             return;
98         }
99
100         MessageContext msgContext = context.getMessageContext();
101
102         if (msgContext == null) {
103             return;
104         }
105
106         // Obtain our possible operations
107
SOAPService service = msgContext.getService();
108         if (service == null) {
109             return;
110         }
111
112         ServiceDesc serviceDesc =
113             service.getInitializedServiceDesc(msgContext);
114
115         String JavaDoc lc = Utils.xmlNameToJava(name);
116         if (serviceDesc == null) {
117             throw AxisFault.makeFault(
118                    new ClassNotFoundException JavaDoc(
119                            Messages.getMessage("noClassForService00",
120                                                lc)));
121         }
122
123         this.operations = serviceDesc.getOperationsByName(lc);
124     }
125
126     public void updateOperationsByQName() throws AxisFault
127     {
128         if (context == null) {
129             return;
130         }
131
132         MessageContext msgContext = context.getMessageContext();
133
134         if (msgContext == null) {
135             return;
136         }
137
138         this.operations = msgContext.getPossibleOperationsByQName(getQName());
139     }
140
141     public OperationDesc[] getOperations()
142     {
143         return this.operations;
144     }
145
146     public String JavaDoc getMethodName()
147     {
148         return name;
149     }
150
151     public void setNeedDeser(boolean needDeser) {
152         this.needDeser = needDeser;
153     }
154
155     public void deserialize() throws SAXException JavaDoc
156     {
157         needDeser = false;
158
159         MessageContext msgContext = context.getMessageContext();
160
161         // Figure out if we should be looking for out params or in params
162
// (i.e. is this message a response?)
163
Message msg = msgContext.getCurrentMessage();
164         SOAPConstants soapConstants = msgContext.getSOAPConstants();
165
166         boolean isResponse = ((msg != null) &&
167                               Message.RESPONSE.equals(msg.getMessageType()));
168
169         // We're going to need this below, so create one.
170
RPCHandler rpcHandler = new RPCHandler(this, isResponse);
171
172         if (operations != null) {
173             int numParams = (getChildren() == null) ? 0 : getChildren().size();
174
175             SAXException JavaDoc savedException = null;
176
177             // By default, accept missing parameters as nulls, and
178
// allow the message context to override.
179
boolean acceptMissingParams = msgContext.isPropertyTrue(
180                     MessageContext.ACCEPTMISSINGPARAMS,
181                     true);
182
183             // We now have an array of all operations by this name. Try to
184
// find the right one. For each matching operation which has an
185
// equal number of "in" parameters, try deserializing. If we
186
// don't succeed for any of the candidates, punt.
187

188             for (int i = 0; i < operations.length; i++) {
189                 OperationDesc operation = operations[i];
190
191                 // See if any information is coming from a header
192
boolean needHeaderProcessing =
193                     needHeaderProcessing(operation, isResponse);
194
195                 // Make a quick check to determine if the operation
196
// could be a match.
197
// 1) The element is the first param, DOCUMENT, (i.e.
198
// don't know the operation name or the number
199
// of params, so try all operations).
200
// or (2) Style is literal
201
// If the Style is LITERAL, the numParams may be inflated
202
// as in the following case:
203
// <getAttractions xmlns="urn:CityBBB">
204
// <attname>Christmas</attname>
205
// <attname>Xmas</attname>
206
// </getAttractions>
207
// for getAttractions(String[] attName)
208
// numParams will be 2 and and operation.getNumInParams=1
209
// or (3) Number of expected params is
210
// >= num params in message
211
if (operation.getStyle() == Style.DOCUMENT ||
212                     operation.getStyle() == Style.WRAPPED ||
213                     operation.getUse() == Use.LITERAL ||
214                     (acceptMissingParams ?
215                         (operation.getNumInParams() >= numParams) :
216                         (operation.getNumInParams() == numParams))) {
217
218                     boolean isEncoded = operation.getUse() == Use.ENCODED;
219                     rpcHandler.setOperation(operation);
220                     try {
221                         // If no operation name and more than one
222
// parameter is expected, don't
223
// wrap the rpcHandler in an EnvelopeHandler.
224
if ( ( msgContext.isClient() &&
225                                operation.getStyle() == Style.DOCUMENT ) ||
226                             ( !msgContext.isClient() &&
227                                operation.getStyle() == Style.DOCUMENT &&
228                                operation.getNumInParams() > 0 ) ) { context.pushElementHandler(rpcHandler);
229                             context.setCurElement(null);
230                         } else {
231                             context.pushElementHandler(
232                                     new EnvelopeHandler(rpcHandler));
233                             context.setCurElement(this);
234                         }
235
236                         publishToHandler((org.xml.sax.ContentHandler JavaDoc) context);
237
238                         // If parameter values are located in headers,
239
// get the information and publish the header
240
// elements to the rpc handler.
241
if (needHeaderProcessing) {
242                             processHeaders(operation, isResponse,
243                                            context, rpcHandler);
244                         }
245
246                         // Check if the RPCParam's value match the signature of the
247
// param in the operation.
248
boolean match = true;
249                         List JavaDoc params = getParams2();
250                         for ( int j = 0 ; j < params.size() && match ; j++ ) {
251                             RPCParam rpcParam = (RPCParam)params.get(j);
252                             Object JavaDoc value = rpcParam.getObjectValue();
253
254                             // first check the type on the paramter
255
ParameterDesc paramDesc = rpcParam.getParamDesc();
256
257                             // if we found some type info try to make sure the value type is
258
// correct. For instance, if we deserialized a xsd:dateTime in
259
// to a Calendar and the service takes a Date, we need to convert
260
if (paramDesc != null && paramDesc.getJavaType() != null) {
261
262                                 // Get the type in the signature (java type or its holder)
263
Class JavaDoc sigType = paramDesc.getJavaType();
264
265                                 // if the type is an array but the value is not
266
// an array or Collection, put it into an
267
// ArrayList so that we correctly recognize it
268
// as convertible
269
if (sigType.isArray()) {
270                                     if (value != null &&
271                                             JavaUtils.isConvertable(value,
272                                                sigType.getComponentType()) &&
273                                           !(value.getClass().isArray()) &&
274                                           !(value instanceof Collection JavaDoc)) {
275                                         ArrayList JavaDoc list = new ArrayList JavaDoc();
276                                         list.add(value);
277                                         value = list;
278                                         rpcParam.setObjectValue(value);
279                                     }
280                                 }
281
282                                 if(!JavaUtils.isConvertable(value, sigType, isEncoded))
283                                     match = false;
284                             }
285                         }
286                         // This is not the right operation, try the next one.
287
if(!match) {
288                             children = new ArrayList JavaDoc();
289                             continue;
290                         }
291
292                         // Success!! This is the right one...
293
msgContext.setOperation(operation);
294                         return;
295                     } catch (SAXException JavaDoc e) {
296                         // If there was a problem, try the next one.
297
savedException = e;
298                         children = new ArrayList JavaDoc();
299                         continue;
300                     } catch (AxisFault e) {
301                         // Thrown by getHeadersByName...
302
// If there was a problem, try the next one.
303
savedException = new SAXException JavaDoc(e);
304                         children = new ArrayList JavaDoc();
305                         continue;
306                     }
307                 }
308             }
309
310             // If we're SOAP 1.2, getting to this point means bad arguments.
311
if (!msgContext.isClient() && soapConstants == SOAPConstants.SOAP12_CONSTANTS) {
312                 AxisFault fault = new AxisFault(Constants.FAULT_SOAP12_SENDER, "string", null, null);
313                 fault.addFaultSubCode(Constants.FAULT_SUBCODE_BADARGS);
314                 throw new SAXException JavaDoc(fault);
315             }
316
317             if (savedException != null) {
318                 throw savedException;
319             } else if (!msgContext.isClient()) {
320                 QName JavaDoc faultCode = new QName JavaDoc(Constants.FAULT_SERVER_USER);
321                 if (soapConstants == SOAPConstants.SOAP12_CONSTANTS)
322                     faultCode = Constants.FAULT_SOAP12_SENDER;
323                 AxisFault fault = new AxisFault(faultCode,
324                     null, Messages.getMessage("noSuchOperation", name), null, null, null);
325
326                 throw new SAXException JavaDoc(fault);
327             }
328         }
329
330         if (operations != null) {
331             rpcHandler.setOperation(operations[0]);
332         }
333
334         // Same logic as above. Don't wrap rpcHandler
335
// if there is no operation wrapper in the message
336
if (operations != null && operations.length > 0 &&
337             (operations[0].getStyle() == Style.DOCUMENT)) {
338             context.pushElementHandler(rpcHandler);
339             context.setCurElement(null);
340         } else {
341             context.pushElementHandler(new EnvelopeHandler(rpcHandler));
342             context.setCurElement(this);
343         }
344
345         publishToHandler((org.xml.sax.ContentHandler JavaDoc)context);
346     }
347
348     private List JavaDoc getParams2() {
349         return getParams(new ArrayList JavaDoc());
350     }
351
352     private List JavaDoc getParams(List JavaDoc list) {
353         for (int i = 0; children != null && i < children.size(); i++) {
354             Object JavaDoc child = children.get(i);
355             if (child instanceof RPCParam) {
356                 list.add(child);
357             }
358         }
359         return list;
360     }
361     
362     /** This gets the FIRST param whose name matches.
363      * !!! Should it return more in the case of duplicates?
364      */

365     public RPCParam getParam(String JavaDoc name) throws SAXException JavaDoc
366     {
367         if (needDeser) {
368             deserialize();
369         }
370
371         List JavaDoc params = getParams2();
372         for (int i = 0; i < params.size(); i++) {
373             RPCParam param = (RPCParam)params.get(i);
374             if (param.getName().equals(name))
375                 return param;
376         }
377
378         return null;
379     }
380
381     public Vector JavaDoc getParams() throws SAXException JavaDoc
382     {
383         if (needDeser) {
384             deserialize();
385         }
386         
387         return (Vector JavaDoc)getParams(new Vector JavaDoc());
388     }
389
390     public void addParam(RPCParam param)
391     {
392         param.setRPCCall(this);
393         initializeChildren();
394         children.add(param);
395     }
396
397     protected void outputImpl(SerializationContext context) throws Exception JavaDoc
398     {
399         MessageContext msgContext = context.getMessageContext();
400         boolean hasOperationElement =
401             (msgContext == null ||
402              msgContext.getOperationStyle() == Style.RPC ||
403              msgContext.getOperationStyle() == Style.WRAPPED);
404
405         // When I have MIME and a no-param document WSDL, if I don't check
406
// for no params here, the server chokes with "can't find Body".
407
// because it will be looking for the enclosing element always
408
// found in an RPC-style (and wrapped) request
409
boolean noParams = getParams2().size() == 0;
410
411         if (hasOperationElement || noParams) {
412             // Set default namespace if appropriate (to avoid prefix mappings
413
// in literal style). Do this only if there is no encodingStyle.
414
if (encodingStyle != null && encodingStyle.equals("")) {
415                 context.registerPrefixForURI("", getNamespaceURI());
416             }
417             context.startElement(new QName JavaDoc(getNamespaceURI(), name), attributes);
418         }
419
420         if(noParams) {
421             if (children != null) {
422                 for (Iterator JavaDoc it = children.iterator(); it.hasNext();) {
423                     ((NodeImpl)it.next()).output(context);
424                 }
425             }
426         } else {
427             List JavaDoc params = getParams2();
428             for (int i = 0; i < params.size(); i++) {
429                 RPCParam param = (RPCParam)params.get(i);
430                 if (!hasOperationElement && encodingStyle != null && encodingStyle.equals("")) {
431                     context.registerPrefixForURI("", param.getQName().getNamespaceURI());
432                 }
433                 param.serialize(context);
434             }
435         }
436
437         if (hasOperationElement || noParams) {
438             context.endElement();
439         }
440     }
441
442     /**
443      * needHeaderProcessing
444      * @param operation OperationDesc
445      * @param isResponse boolean indicates if request or response message
446      * @return true if the operation description indicates parameters/results
447      * are located in the soap header.
448      */

449     private boolean needHeaderProcessing(OperationDesc operation,
450                                          boolean isResponse) {
451
452         // Search parameters/return to see if any indicate
453
// that instance data is contained in the header.
454
ArrayList JavaDoc paramDescs = operation.getParameters();
455         if (paramDescs != null) {
456             for (int j=0; j<paramDescs.size(); j++) {
457                 ParameterDesc paramDesc =
458                     (ParameterDesc) paramDescs.get(j);
459                 if ((!isResponse && paramDesc.isInHeader()) ||
460                     (isResponse && paramDesc.isOutHeader())) {
461                     return true;
462                 }
463             }
464         }
465         if (isResponse &&
466             operation.getReturnParamDesc() != null &&
467             operation.getReturnParamDesc().isOutHeader()) {
468             return true;
469         }
470         return false;
471     }
472
473     /**
474      * needHeaderProcessing
475      * @param operation OperationDesc
476      * @param isResponse boolean indicates if request or response message
477      * @param context DeserializationContext
478      * @param handler RPCHandler used to deserialize parameters
479      * are located in the soap header.
480      */

481     private void processHeaders(OperationDesc operation,
482                                 boolean isResponse,
483                                 DeserializationContext context,
484                                 RPCHandler handler)
485         throws AxisFault, SAXException JavaDoc
486     {
487         // Inform handler that subsequent elements come from
488
// the header
489
try {
490             handler.setHeaderElement(true);
491             // Get the soap envelope
492
SOAPElement JavaDoc envelope = getParentElement();
493             while (envelope != null &&
494                    !(envelope instanceof SOAPEnvelope)) {
495                 envelope = envelope.getParentElement();
496             }
497             if (envelope == null)
498                 return;
499
500             // Find parameters that have instance
501
// data in the header.
502
ArrayList JavaDoc paramDescs = operation.getParameters();
503             if (paramDescs != null) {
504                 for (int j=0; j<paramDescs.size(); j++) {
505                     ParameterDesc paramDesc =
506                         (ParameterDesc) paramDescs.get(j);
507                     if ((!isResponse && paramDesc.isInHeader()) ||
508                         (isResponse && paramDesc.isOutHeader())) {
509                         // Get the headers that match the parameter's
510
// QName
511
Enumeration JavaDoc headers = ((SOAPEnvelope) envelope).
512                             getHeadersByName(
513                                  paramDesc.getQName().getNamespaceURI(),
514                                  paramDesc.getQName().getLocalPart(),
515                                  true);
516                         // Publish each of the found elements to the
517
// handler. The pushElementHandler and
518
// setCurElement calls are necessary to
519
// have the message element recognized as a
520
// child of the RPCElement.
521
while(headers != null &&
522                               headers.hasMoreElements()) {
523                             context.pushElementHandler(handler);
524                             context.setCurElement(null);
525                             ((MessageElement) headers.nextElement()).
526                                 publishToHandler(
527                                    (org.xml.sax.ContentHandler JavaDoc)context);
528                         }
529                     }
530                 }
531             }
532
533             // Now do the same processing for the return parameter.
534
if (isResponse &&
535                 operation.getReturnParamDesc() != null &&
536                 operation.getReturnParamDesc().isOutHeader()) {
537                 ParameterDesc paramDesc = operation.getReturnParamDesc();
538                 Enumeration JavaDoc headers =
539                     ((SOAPEnvelope) envelope).
540                     getHeadersByName(
541                         paramDesc.getQName().getNamespaceURI(),
542                         paramDesc.getQName().getLocalPart(),
543                         true);
544                 while(headers != null &&
545                       headers.hasMoreElements()) {
546                     context.pushElementHandler(handler);
547                     context.setCurElement(null);
548
549                     ((MessageElement) headers.nextElement()).
550                         publishToHandler((org.xml.sax.ContentHandler JavaDoc)context);
551                 }
552             }
553         } finally {
554             handler.setHeaderElement(false);
555         }
556     }
557 }
558
Popular Tags