KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > openlaszlo > remote > soap > LZSOAPService


1 /* *****************************************************************************
2  * LZSOAPService.java
3  * ****************************************************************************/

4
5 /* J_LZ_COPYRIGHT_BEGIN *******************************************************
6 * Copyright 2001-2004 Laszlo Systems, Inc. All Rights Reserved. *
7 * Use is subject to license terms. *
8 * J_LZ_COPYRIGHT_END *********************************************************/

9
10 package org.openlaszlo.remote.soap;
11
12 import org.openlaszlo.iv.flash.api.action.Program;
13 import org.openlaszlo.remote.soap.encoding.SWFSimpleDeserializerFactory;
14 import org.openlaszlo.remote.soap.encoding.SWFObjectDeserializerFactory;
15 import org.openlaszlo.remote.soap.encoding.LZObjectSerializerFactory;
16 import org.openlaszlo.server.LPS;
17 import java.io.IOException JavaDoc;
18 import java.net.URLDecoder JavaDoc;
19 import java.rmi.RemoteException JavaDoc;
20 import java.util.Iterator JavaDoc;
21 import java.util.List JavaDoc;
22 import java.util.ArrayList JavaDoc;
23 import java.util.Hashtable JavaDoc;
24 import java.util.Map JavaDoc;
25 import javax.xml.namespace.QName JavaDoc;
26 import javax.xml.rpc.JAXRPCException JavaDoc;
27 import javax.xml.soap.SOAPHeader JavaDoc;
28 import org.apache.axis.AxisFault;
29 import org.apache.axis.client.Service;
30 import org.apache.axis.client.Call;
31 import javax.xml.rpc.ServiceException JavaDoc;
32 import javax.xml.rpc.encoding.DeserializerFactory JavaDoc;
33 import javax.xml.rpc.encoding.SerializerFactory JavaDoc;
34 import javax.xml.rpc.encoding.TypeMappingRegistry JavaDoc;
35 import javax.xml.rpc.encoding.TypeMapping JavaDoc;
36 import javax.xml.rpc.handler.HandlerInfo JavaDoc;
37 import javax.xml.rpc.handler.HandlerRegistry JavaDoc;
38 import javax.xml.soap.SOAPException JavaDoc;
39 import org.apache.axis.Constants;
40 import org.apache.axis.message.SOAPBodyElement;
41 import org.apache.axis.message.SOAPHeaderElement;
42 import org.apache.log4j.Logger;
43 import org.w3c.dom.DOMException JavaDoc;
44 import org.w3c.dom.Element JavaDoc;
45 import org.w3c.dom.Node JavaDoc;
46 import org.w3c.dom.NodeList JavaDoc;
47 import org.w3c.dom.Text JavaDoc;
48 import org.xml.sax.SAXException JavaDoc;
49
50 public class LZSOAPService
51 {
52     private static Logger mLogger = Logger.getLogger(LZSOAPService.class);
53
54     String JavaDoc mServiceName;
55     String JavaDoc mPort;
56     String JavaDoc mEndpointAddress;
57     String JavaDoc mTransport;
58     String JavaDoc mTargetNS;
59     String JavaDoc mXMLSchemaNS;
60     String JavaDoc mSOAPEncodingNS;
61     Service mService;
62     TypeMappingRegistry JavaDoc mTypeMappingRegistry;
63     HandlerRegistry JavaDoc mHandlerRegistry;
64     TypeMapping JavaDoc mDefaultTypeMapping;
65     TypeMapping JavaDoc mDefaultSOAPEncodingTypeMapping;
66
67     /** URL for wsdl. This gets set in SOAPDataSource. */
68     String JavaDoc mWSDL;
69
70     /** Map of SWF of services (synchronized) (key is version string like swf6,
71      * swf7, etc.) */

72     Hashtable JavaDoc mClientSOAPServiceMap = new Hashtable JavaDoc();
73
74     /** Map of LZSOAPOperations. */
75     Map JavaDoc mOperations = null;
76
77     /** Map of schema complex types. */
78     Map JavaDoc mSchemaComplexTypes = null;
79
80
81
82     /** Keep one DeserializerFactory around. */
83     DeserializerFactory mSWFObjectDeserializerFactory =
84         new SWFObjectDeserializerFactory();
85     SerializerFactory mObjectSerializerFactory = new LZObjectSerializerFactory();
86
87     public LZSOAPService(String JavaDoc wsdl, String JavaDoc serviceName, String JavaDoc port,
88                          String JavaDoc endpointAddress, String JavaDoc transport,
89                          String JavaDoc targetNS, String JavaDoc xmlSchemaNS,
90                          String JavaDoc soapEncodingNS)
91         throws ServiceException JavaDoc {
92
93         mWSDL = wsdl;
94         mServiceName = serviceName;
95         mPort = port;
96         mEndpointAddress = endpointAddress;
97         mTransport = transport;
98         mTargetNS = targetNS;
99         mXMLSchemaNS = xmlSchemaNS;
100         mSOAPEncodingNS = soapEncodingNS;
101
102         mService = new Service(new QName JavaDoc(mTargetNS, mServiceName));
103
104         mTypeMappingRegistry = mService.getTypeMappingRegistry();
105         mHandlerRegistry = mService.getHandlerRegistry();
106
107         getHandlerChain().add(new HandlerInfo JavaDoc(LZSOAPHandler.class, null, null));
108
109         // Register default type mapping and default soap encoding type mapping.
110
mDefaultTypeMapping = LZDefaultTypeMapping.getSingleton();
111         mDefaultSOAPEncodingTypeMapping = new LZDefaultSOAPEncodingTypeMapping();
112         mTypeMappingRegistry.registerDefault(mDefaultTypeMapping);
113         mTypeMappingRegistry.register(Constants.URI_SOAP11_ENC, mDefaultSOAPEncodingTypeMapping);
114     }
115
116
117     public synchronized byte[] createClientSOAPService(String JavaDoc swfversion, int swfnum)
118         throws ServiceException JavaDoc {
119         byte[] swfobj = (byte[])mClientSOAPServiceMap.get(swfversion);
120         if (swfobj == null) {
121             try {
122                 swfobj = ClientSOAPService.createObject(this, swfnum);
123                 mClientSOAPServiceMap.put(swfversion, swfobj);
124             } catch (IOException JavaDoc e) {
125                 throw new ServiceException JavaDoc("could not create client SOAP service object");
126             }
127         }
128         return swfobj;
129     }
130
131     /**
132      * Get client SWF representation of service.
133      */

134     public byte[] getClientSOAPService(int swfnum)
135         throws ServiceException JavaDoc {
136         String JavaDoc swfversion = LPS.getSWFVersion(swfnum);
137         byte[] swfobj = (byte[])mClientSOAPServiceMap.get(swfversion);
138         if (swfobj == null) swfobj = createClientSOAPService(swfversion, swfnum);
139         return swfobj;
140     }
141
142     /**
143      * Invoke operation with parameters. Parameters are represented in XML like:
144      *
145      * <params>
146      * <param>param1</param>
147      * <param>param2</param>
148      * <param>param3</param>
149      * <params>
150      *
151      * In document style, the string in the <param> element should be an
152      * XML-escaped string. For example, suppose you were trying to send two
153      * documents that looked like:
154      *
155      * doc1: <a>1</a>
156      * doc2: <b>2</b>
157      *
158      * The XML parameter string should look as follows:
159      *
160      * <params>
161      * <param>%3Ca%3E1%3C/a%3E</param>
162      * <param>%3Cb%3E2%3C/b%3E</param>
163      * </params>
164      *
165      * @param operation operation to invoke
166      * @param xml XML from client that includes header and body. The format looks like:
167      *
168      * <e><h>XML_HEADER</h><b>XML_BODY</b></e>
169      *
170      * where XML_BODY is
171      *
172      * <params>
173      * <param>PARAM1</param>
174      * <param>PARAM2</param>
175      * <param>...</param>
176      * </params>
177      *
178      * @return object array where the first parameter is a string indicating the
179      * style used to invoke the function (rpc|document) and the second is the
180      * return value. For document styles, an array of SOAPBody message items are
181      * returned.
182      */

183     public Object JavaDoc[] invoke(String JavaDoc operation, String JavaDoc xml)
184         throws AxisFault, ServiceException JavaDoc, RemoteException JavaDoc {
185
186         mLogger.debug("invoke()");
187
188         try {
189             Element envelope = LZSOAPUtils.xmlStringToElement(xml);
190
191             Element body = LZSOAPUtils.getFirstElementByTagName(envelope, "b");
192             Element paramsEl = LZSOAPUtils.getFirstElementByTagName(body, "params");
193
194             Object JavaDoc[] callArr = createCall(operation, paramsEl);
195             Call call = (Call)callArr[0];
196             Object JavaDoc[] params = (Object JavaDoc[])callArr[1];
197
198             Element header = LZSOAPUtils.getFirstElementByTagName(envelope, "h");
199             NodeList JavaDoc headerNodes = header.getChildNodes();
200             for (int i=0; i < headerNodes.getLength(); i++) {
201                 Node JavaDoc headerNode = (Node JavaDoc)headerNodes.item(i);
202                 if (headerNode.getNodeType() != Node.ELEMENT_NODE) continue;
203                 call.addHeader(new SOAPHeaderElement((Element)headerNode));
204             }
205
206             // Pass back style and return value from call
207
Object JavaDoc returnValue = call.invoke(params);
208
209             // Return header, if any
210
SOAPHeader JavaDoc responseHeader =
211                 call.getResponseMessage().getSOAPEnvelope().getHeader();
212
213             LZSOAPOperation op = (LZSOAPOperation)mOperations.get(operation);
214             return new Object JavaDoc[]{ op.getStyle(), returnValue, responseHeader };
215
216         } catch (AxisFault e) {
217             mLogger.error("AxisFault");
218             throw e;
219         } catch (IOException JavaDoc e) {
220             mLogger.error("IOException", e);
221             throw new ServiceException JavaDoc(e.getMessage());
222         } catch (org.xml.sax.SAXException JavaDoc e) {
223             mLogger.error("SAXException:", e);
224             throw new ServiceException JavaDoc(e.getMessage());
225         } catch (SOAPException JavaDoc e) {
226             mLogger.error("SOAPException", e);
227             throw new ServiceException JavaDoc(e.getMessage());
228         }
229
230     }
231
232     Node JavaDoc getParamValue(Element param) {
233         NodeList JavaDoc list = param.getChildNodes();
234         int len = list.getLength();
235         if (len == 0) {
236             return null;
237         }
238
239         // if a subelement exists, the param must be an array or object.
240
for (int i=0; i < list.getLength(); i++) {
241             Node JavaDoc node = list.item(i);
242             if (node.getNodeType() == Node.ELEMENT_NODE) {
243                 return param;
244             }
245         }
246
247         return list.item(0);
248     }
249
250
251     /**
252      * @return true if paramNode is text node, else false.
253      */

254     public boolean isTextNode(Node JavaDoc paramNode) {
255         return (paramNode == null || paramNode.getNodeType() == Node.TEXT_NODE);
256     }
257
258     /**
259      * @return true if paramNode is an element node, else false.
260      */

261     public boolean isElementNode(Node JavaDoc paramNode) {
262         return (paramNode.getNodeType() == Node.ELEMENT_NODE);
263     }
264
265     /**
266      * @return list of rpc parameters
267      */

268     public List JavaDoc setRPCParams(Call call, NodeList JavaDoc paramsList, List JavaDoc parts,
269                              LZSOAPOperation op)
270         throws ServiceException JavaDoc, IOException JavaDoc, SAXException JavaDoc, DOMException JavaDoc {
271
272         if (mLogger.isDebugEnabled()) {
273             mLogger.debug("setRPCParams");
274         }
275
276         int pos = 0; // parameter position
277
List JavaDoc params = new ArrayList JavaDoc();
278         for (int i=0; i < paramsList.getLength(); i++) {
279
280             Node JavaDoc node = (Node JavaDoc)paramsList.item(i);
281             if (node.getNodeType() != Node.ELEMENT_NODE) continue;
282
283             Element p = (Element)node;
284             Node JavaDoc paramNode = getParamValue(p);
285
286             LZSOAPPart part = (LZSOAPPart)parts.get(pos);
287             ComplexType type = part.getType();
288
289             if (type.isArray()) {
290
291                 if (! isElementNode(paramNode)) {
292                     throw new ServiceException JavaDoc("parameter " + (pos+1) +
293                                                " should an array");
294                 }
295
296                 call.addParameter(part.getName(), type.getBase().getName(),
297                                   ArrayList JavaDoc.class, part.getParameterMode());
298
299                 ArrayWrapper aw = new ArrayWrapper((Element)paramNode, type);
300                 ArrayList JavaDoc list = new ArrayList JavaDoc();
301                 list.add(aw);
302                 params.add(list);
303                 if (mLogger.isDebugEnabled()) {
304                     mLogger.debug("array param: " + aw);
305                 }
306
307             } else {
308
309                 call.addParameter(part.getName(), type.getName(),
310                                   part.getParameterMode());
311
312                 if (isTextNode(paramNode)) { // primitive param
313
Text JavaDoc text = (Text JavaDoc)paramNode;
314                     String JavaDoc strValue = (text != null ? text.getData() : "");
315                     params.add(((LZSOAPPart)parts.get(pos)).valueOf(strValue));
316                     if (mLogger.isDebugEnabled()) {
317                         mLogger.debug("primitive param: " + strValue);
318                     }
319
320                 } else if (isElementNode(paramNode)) { // object param
321
ObjectWrapper ow = new ObjectWrapper((Element)paramNode);
322                     params.add(ow);
323                     if (mLogger.isDebugEnabled()) {
324                         mLogger.debug("object param: " + ow);
325                     }
326
327                 } else {
328                     throw new ServiceException JavaDoc("bad parameter " + (pos+1) +
329                                                ": " + paramNode);
330                 }
331
332             }
333
334             ++pos;
335         }
336
337         if (params.size() != parts.size()) {
338             throw new ServiceException JavaDoc("wrong number of params");
339         }
340
341         // Set return type
342
parts = op.getOutputMessage().getParts();
343         if (parts.size() != 1) {
344             throw new ServiceException JavaDoc("no support more than one return value");
345         }
346
347         LZSOAPPart part = (LZSOAPPart)parts.get(0);
348         ComplexType type = part.getType();
349         if (type != null) {
350             call.setReturnType(type.getName());
351         } else {
352             mLogger.warn("type of return unspecified");
353         }
354
355         return params;
356     }
357
358     /**
359      * @return list of document style parameters
360      */

361     public List JavaDoc setDocumentParams(Call call, NodeList JavaDoc paramsList, List JavaDoc parts,
362                                   LZSOAPOperation op)
363         throws ServiceException JavaDoc, IOException JavaDoc, SAXException JavaDoc, DOMException JavaDoc {
364
365         if (mLogger.isDebugEnabled()) {
366             mLogger.debug("setDocumentParams");
367         }
368
369         call.setProperty(Call.OPERATION_STYLE_PROPERTY, "document");
370         call.setProperty(Call.SOAPACTION_USE_PROPERTY, new Boolean JavaDoc(true));
371         call.setProperty(Call.SOAPACTION_URI_PROPERTY, op.getSoapAction());
372
373         List JavaDoc params = new ArrayList JavaDoc();
374         for (int i=0; i < paramsList.getLength(); i++) {
375
376             Node JavaDoc node = (Node JavaDoc)paramsList.item(i);
377             if (node.getNodeType() != Node.ELEMENT_NODE) continue;
378
379             Element p = (Element)node;
380
381             // get the XML string and convert to an element
382
Text JavaDoc text = (Text JavaDoc)p.getFirstChild();
383             String JavaDoc data = URLDecoder.decode(text.getData());
384             Element docElement = LZSOAPUtils.xmlStringToElement(data);
385             params.add(new SOAPBodyElement(docElement));
386
387         }
388
389         return params;
390     }
391
392     /**
393      * @param operation name of operation.
394      * @param paramsEl parameter element nodes.
395      * @return array with Call object as first value and a parameter array to invoke call with.
396      */

397     public Object JavaDoc[] createCall(String JavaDoc operation, Element paramsEl) throws ServiceException JavaDoc {
398         LZSOAPOperation op = (LZSOAPOperation)mOperations.get(operation);
399         if (op == null) {
400             throw new ServiceException JavaDoc("could not find operation named " +
401                                        operation);
402         }
403
404         try {
405             Call call = (org.apache.axis.client.Call)
406                 mService.createCall(new QName JavaDoc(mTargetNS, mPort));
407             call.setOperationName(new QName JavaDoc(mTargetNS, op.getName()));
408             call.setTargetEndpointAddress(mEndpointAddress);
409
410             NodeList JavaDoc paramsList = paramsEl.getChildNodes();
411             List JavaDoc parts = op.getInputMessage().getParts();
412
413             List JavaDoc params = null;
414             if (op.getStyle().equals("document"))
415                 params = setDocumentParams(call, paramsList, parts, op);
416             else /* rpc */
417                 params = setRPCParams(call, paramsList, parts, op);
418
419             return new Object JavaDoc[]{ call, params.toArray() };
420         } catch (IOException JavaDoc e) {
421             mLogger.error("IOException", e);
422             throw new ServiceException JavaDoc("IOException: " + e.getMessage());
423         } catch (SAXException JavaDoc e) {
424             mLogger.error("SAXException", e);
425             throw new ServiceException JavaDoc("SAXException: " + e.getMessage());
426         } catch (DOMException JavaDoc e) {
427             mLogger.error("DOMException", e);
428             throw new ServiceException JavaDoc("DOMException: " + e.getMessage());
429         }
430     }
431
432     public TypeMappingRegistry JavaDoc getTypeMappingRegistry() {
433         return mTypeMappingRegistry;
434     }
435
436     public HandlerRegistry JavaDoc getHandlerRegistry() {
437         return mHandlerRegistry;
438     }
439
440     public List JavaDoc getHandlerChain() {
441         return mHandlerRegistry.getHandlerChain(new QName JavaDoc(mTargetNS, mPort));
442     }
443
444     public Service getService() {
445         return mService;
446     }
447
448     /** Set map of LZSOAPOperations. */
449     public void setOperations(Map JavaDoc operations) {
450         mOperations = operations;
451     }
452
453     /** @return map of LZSOAPOperations. */
454     public Map JavaDoc getOperations() {
455         return mOperations;
456     }
457
458     public String JavaDoc getTargetNS() {
459         return mTargetNS;
460     }
461
462     public String JavaDoc getSOAPEncodingNS() {
463         return mSOAPEncodingNS;
464     }
465
466     public String JavaDoc getServiceName() {
467         return mServiceName;
468     }
469
470     public String JavaDoc getPort() {
471         return mPort;
472     }
473
474     public String JavaDoc getEndpointAddress() {
475         return mEndpointAddress;
476     }
477
478     public String JavaDoc getTransport() {
479         return mTransport;
480     }
481
482     /** WSDL URL for this SOAP service. */
483     public String JavaDoc getWSDL() {
484         return mWSDL;
485     }
486
487     /** Set WSDL URL for this SOAP service. */
488     public void setWSDL(String JavaDoc wsdl) {
489         mWSDL = wsdl;
490     }
491
492     /**
493      * This gets called by WSDLParser after WSDL schema is read.
494      */

495     public void setSchemaComplexTypes(Map JavaDoc schemaComplexTypes) {
496         mSchemaComplexTypes = schemaComplexTypes;
497
498         // now register these complex types with type mapper.
499
if (mSchemaComplexTypes != null) {
500             Iterator JavaDoc iter = mSchemaComplexTypes.values().iterator();
501             while (iter.hasNext()) {
502                 ComplexType value = (ComplexType)iter.next();
503                 if ( value.getType() == ComplexType.TYPE_STRUCT ) {
504                     QName JavaDoc structQName = value.getName();
505                     // Just to be safe, registering in both default type mapping
506
// and SOAP type mapping.
507
mDefaultTypeMapping.register(ObjectWrapper.class, structQName,
508                                                  mObjectSerializerFactory,
509                                                  mSWFObjectDeserializerFactory);
510                     mDefaultSOAPEncodingTypeMapping.register(ObjectWrapper.class, structQName,
511                                                              mObjectSerializerFactory,
512                                                              mSWFObjectDeserializerFactory);
513                     if (mLogger.isDebugEnabled()) {
514                         mLogger.debug("registered type mapping for object: " + structQName);
515                     }
516                 }
517                 // NOTE: arrays/collections are handled by default type mapping
518
// in LZDefaultTypeMapping. -pk
519
}
520         }
521     }
522
523     /**
524      * @return map of ComplexType.
525      */

526     public Map JavaDoc getSchemaComplexTypes() {
527         return mSchemaComplexTypes;
528     }
529
530     public void toComplexTypesXML(StringBuffer JavaDoc sb) {
531         sb.append("<complex-types>");
532         if (mSchemaComplexTypes != null) {
533             Iterator JavaDoc iter = mSchemaComplexTypes.entrySet().iterator();
534             while (iter.hasNext()) {
535                 Map.Entry JavaDoc entry = (Map.Entry JavaDoc)iter.next();
536                 ComplexType ct =(ComplexType)entry.getValue();
537                 ct.toXML(sb);
538             }
539         }
540         sb.append("</complex-types>");
541     }
542
543     public void toOperationXML(StringBuffer JavaDoc sb) {
544         sb.append("<operations>");
545         Iterator JavaDoc iter = mOperations.keySet().iterator();
546         while (iter.hasNext()) {
547             String JavaDoc key = (String JavaDoc)iter.next();
548             LZSOAPOperation op = (LZSOAPOperation)mOperations.get(key);
549             op.toXML(sb);
550         }
551         sb.append("</operations>");
552     }
553
554     public void toXML(StringBuffer JavaDoc sb) {
555         sb.append("<service")
556             .append(" name=\"").append(mServiceName).append("\"")
557             .append(" port=\"").append(mPort).append("\"")
558             .append(" endpoint=\"").append(mEndpointAddress).append("\"")
559             .append(" transport=\"").append(mTransport).append("\"")
560             .append(" target-namespace=\"").append(mTargetNS).append("\">");
561         toOperationXML(sb);
562         toComplexTypesXML(sb);
563         sb.append("</service>");
564     }
565
566 // public String toString() {
567
// return "-- SOAPService ------------------------------\n"
568
// + "service=" + mServiceName + "\n"
569
// + "port=" + mPort + "\n"
570
// + "endpoint=" + mEndpointAddress + "\n"
571
// + "transport=" + mTransport + "\n"
572
// + "target namespace=" + mTargetNS + "\n\n"
573
// + " ==== OPERATIONS ====\n\n"
574
// + toOperationString()
575
// + " ==== SCHEMA COMPLEX TYPES ====\n\n"
576
// + stringComplexTypes()
577
// + "---------------------------------------------";
578
// }
579

580 // public String toOperationString() {
581
// StringBuffer buf = new StringBuffer();
582
// Iterator iter = mOperations.keySet().iterator();
583
// while (iter.hasNext()) {
584
// String key = (String)iter.next();
585
// LZSOAPOperation op = (LZSOAPOperation)mOperations.get(key);
586
// buf.append(op).append("\n");
587
// }
588
// return buf.toString();
589
// }
590

591 }
592
Popular Tags