KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > openlaszlo > data > SOAPDataSource


1 /* ****************************************************************************
2  * SOAPDataSource.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.data;
11
12 import org.openlaszlo.iv.flash.api.FlashFile;
13 import org.openlaszlo.iv.flash.api.Frame;
14 import org.openlaszlo.iv.flash.api.Script;
15 import org.openlaszlo.iv.flash.api.action.DoAction;
16 import org.openlaszlo.iv.flash.util.FlashOutput;
17 import org.openlaszlo.iv.flash.util.IVException;
18 import org.openlaszlo.iv.flash.api.action.Actions;
19 import org.openlaszlo.iv.flash.api.action.Program;
20 import org.openlaszlo.iv.flash.util.FlashBuffer;
21 import org.openlaszlo.server.LPS;
22 // LoadCount belongs in utils
23
import org.openlaszlo.servlets.LoadCount;
24 import org.openlaszlo.media.MimeType;
25 import org.openlaszlo.remote.soap.LZSOAPService;
26 import org.openlaszlo.remote.soap.WSDLException;
27 import org.openlaszlo.remote.soap.WSDLParser;
28 import org.openlaszlo.remote.soap.encoding.SOAPDataEncoder;
29 import org.openlaszlo.server.LPS;
30 import org.openlaszlo.xml.internal.XMLUtils;
31 import java.io.ByteArrayInputStream JavaDoc;
32 import java.io.File JavaDoc;
33 import java.io.InputStream JavaDoc;
34 import java.io.InterruptedIOException JavaDoc;
35 import java.io.IOException JavaDoc;
36 import java.io.StringReader JavaDoc;
37 import java.net.URLDecoder JavaDoc;
38 import java.net.URLEncoder JavaDoc;
39 import java.rmi.RemoteException JavaDoc;
40 import java.util.Date JavaDoc;
41 import java.util.HashMap JavaDoc;
42 import java.util.Iterator JavaDoc;
43 import java.util.Properties JavaDoc;
44 import java.util.Vector JavaDoc;
45 import javax.xml.parsers.DocumentBuilder JavaDoc;
46 import javax.xml.parsers.DocumentBuilderFactory JavaDoc;
47 import javax.xml.parsers.ParserConfigurationException JavaDoc;
48 import javax.xml.rpc.ServiceException JavaDoc;
49 import javax.servlet.http.HttpServletRequest JavaDoc;
50 import javax.servlet.http.HttpServletResponse JavaDoc;
51 import org.apache.axis.message.SOAPBodyElement;
52 import org.apache.axis.AxisFault;
53 import org.apache.log4j.Logger;
54 import org.xml.sax.InputSource JavaDoc;
55 import org.xml.sax.SAXException JavaDoc;
56 import org.w3c.dom.DOMException JavaDoc;
57 import org.w3c.dom.Element JavaDoc;
58 import org.w3c.dom.NodeList JavaDoc;
59 import org.w3c.dom.Text JavaDoc;
60 import org.apache.axis.AxisProperties;
61 import org.apache.axis.configuration.EngineConfigurationFactoryDefault;
62 import org.apache.axis.components.net.DefaultCommonsHTTPClientProperties;
63 import org.apache.axis.message.SOAPHeader;
64
65
66 /**
67  * Data source for SOAP.
68  */

69 public class SOAPDataSource extends DataSource
70 {
71     private static Logger mLogger = Logger.getLogger(SOAPDataSource.class);
72
73     /** Static document builder. */
74     static DocumentBuilder JavaDoc mBuilder = null;
75
76     static String JavaDoc mLoadOption;
77
78     static HashMap JavaDoc mServiceMap = new HashMap JavaDoc();
79
80     //------------------------------------------------------------
81
// Begin soap info variables
82
//------------------------------------------------------------
83

84     static long mLastCleared = -1;
85
86     static LoadCount mInvokeLoad = new LoadCount(10);
87     static LoadCount mGetServiceLoad = new LoadCount(10);
88
89     //------------------------------------------------------------
90
// End soap info variables
91
//------------------------------------------------------------
92

93
94     {
95         DocumentBuilderFactory JavaDoc factory = DocumentBuilderFactory.newInstance();
96         try {
97             mBuilder = factory.newDocumentBuilder();
98         } catch (ParserConfigurationException JavaDoc e) {
99             System.err.println("Can't create DocumentBuilder");
100         }
101
102         mLoadOption = LPS.getProperty("rpc.soap.wsdlLoadOption", "always");
103         if (mLogger.isDebugEnabled()) {
104             mLogger.debug("WSDL load option is set to \"" + mLoadOption + "\"");
105         }
106     }
107
108     public SOAPDataSource() {
109         clearLoadInfo();
110
111         //------------------------------------------------------------
112
// AXIS CommonsHTTPClient properties
113
//------------------------------------------------------------
114
String JavaDoc clientConfigFile =
115             LPS.getProperties().getProperty("axis.clientConfigFile", LPS.getConfigDirectory() +
116                                             File.separatorChar + "client-config.wsdd");
117
118         AxisProperties.setProperty(EngineConfigurationFactoryDefault.OPTION_CLIENT_CONFIG_FILE,
119                                    clientConfigFile);
120
121         // Reuse HTTPDataSource HttpClient properties.
122
AxisProperties.setProperty(DefaultCommonsHTTPClientProperties.MAXIMUM_TOTAL_CONNECTIONS_PROPERTY_KEY,
123                                    "" + HTTPDataSource.getMaxTotalConnections());
124         AxisProperties.setProperty(DefaultCommonsHTTPClientProperties.MAXIMUM_CONNECTIONS_PER_HOST_PROPERTY_KEY,
125                                    "" + HTTPDataSource.getMaxConnectionsPerHost());
126         AxisProperties.setProperty(DefaultCommonsHTTPClientProperties.CONNECTION_POOL_TIMEOUT_KEY,
127                                    "" + HTTPDataSource.getConnectionPoolTimeout());
128     }
129
130     /**
131      * @return unique name of this data source
132      */

133     public String JavaDoc name()
134     {
135         return "soap";
136     }
137
138     /**
139      * Sends system information to client.
140      *
141      * @throws DataSourceException if there was a problem retrieving or sending
142      * the data.
143      */

144     public Data getData(String JavaDoc app, HttpServletRequest JavaDoc req,
145                         HttpServletResponse JavaDoc res, long lastModifiedTime)
146         throws InterruptedIOException JavaDoc, IOException JavaDoc, DataSourceException {
147         if (mLogger.isDebugEnabled()) {
148             mLogger.debug("getData");
149         }
150
151         String JavaDoc request = req.getParameter("request");
152         if (request == null || request.equals(""))
153             request = "invoke";
154
155         int swfnum = LPS.getSWFVersionNum(req);
156
157         long t0, t1;
158         t0 = System.currentTimeMillis();
159         if (request.equals("invoke")) {
160             mInvokeLoad.increment();
161             try {
162                 return invoke(app, req, res, swfnum);
163             } finally {
164                 t1 = System.currentTimeMillis();
165                 mInvokeLoad.decrement((int)(t1-t0));
166             }
167         } else if (request.equals("load")) {
168             mGetServiceLoad.increment();
169             try {
170                 LZSOAPService service = getService(app, req, res, true);
171                 return new SOAPData( service.getClientSOAPService(swfnum) );
172             } catch (ServiceException JavaDoc e) {
173                 return exceptionToSOAPData
174                     ( swfnum, new DataSourceException(e.getMessage()) );
175             } finally {
176                 t1 = System.currentTimeMillis();
177                 mGetServiceLoad.decrement((int)(t1-t0));
178             }
179         }
180
181         return exceptionToSOAPData
182             ( swfnum, new DataSourceException("unknown SOAP datasource request") );
183     }
184
185     public Data invoke(String JavaDoc app, HttpServletRequest JavaDoc req,
186                        HttpServletResponse JavaDoc res, int swfnum) {
187
188         if (! req.getMethod().equals("POST")) {
189             mLogger.error("request must be POST");
190             return exceptionToSOAPData
191                 ( swfnum, new DataSourceException("request must be POST") );
192         }
193
194         String JavaDoc xml = req.getParameter("lzpostbody");
195         if (xml == null || xml.equals("")) {
196             mLogger.error("no post body");
197             return exceptionToSOAPData
198                 ( swfnum, new DataSourceException("no post body") );
199         }
200
201         if (mLogger.isDebugEnabled()) {
202             mLogger.debug("lzpostbody: " + xml);
203         }
204
205         try {
206
207             LZSOAPService service = getService(app, req, res, false);
208             if (service == null) {
209                 return exceptionToSOAPData
210                     ( swfnum, new DataSourceException("could not find service") );
211             }
212
213
214             try {
215                 String JavaDoc operation = req.getParameter("operation");
216                 Object JavaDoc[] value = service.invoke(operation, xml);
217
218                 if ( value[0].equals("rpc") ) {
219                     return programToSOAPData(swfnum,
220                                              (Program)value[1],
221                                              (SOAPHeader)value[2] );
222                 } else {
223                     return documentsToSOAPData(swfnum,
224                                                (Vector JavaDoc)value[1],
225                                                (SOAPHeader)value[2]);
226                 }
227             } catch (AxisFault fault) {
228                 // Axis throws exceptions for faults
229
return new SOAPData
230                     ( new SOAPDataEncoder(swfnum).buildFromFault(fault) );
231             }
232
233         } catch (RemoteException JavaDoc e) {
234             mLogger.error("RemoteException: " + e.getMessage(), e);
235             return exceptionToSOAPData(swfnum, e);
236         } catch (DataSourceException e) {
237             mLogger.error("DataSourceException: " + e.getMessage(), e);
238             return exceptionToSOAPData(swfnum, e);
239         } catch (IOException JavaDoc e) {
240             mLogger.error("IOException: " + e.getMessage(), e);
241             return exceptionToSOAPData(swfnum, e);
242         } catch (ServiceException JavaDoc e) {
243             mLogger.error("ServiceException: " + e.getMessage(), e);
244             return exceptionToSOAPData(swfnum, e);
245         } catch (Exception JavaDoc e) {
246             mLogger.error("Exception: " + e.getMessage(), e);
247             return exceptionToSOAPData(swfnum, e);
248         }
249
250     }
251
252     SOAPData exceptionToSOAPData(int swfnum, Exception JavaDoc e) {
253         mLogger.error("Exception", e);
254         return new SOAPData( new SOAPDataEncoder(swfnum).buildFromException(e) );
255     }
256
257
258     SOAPData documentsToSOAPData(int swfnum, Vector JavaDoc docs, SOAPHeader header)
259         throws DataSourceException {
260
261         if (mLogger.isDebugEnabled()) {
262             mLogger.debug("documentsToSOAPData");
263         }
264
265         if (docs.size() == 0) {
266             mLogger.error("no document return");
267             throw new DataSourceException("no document return");
268         }
269
270         try {
271             return new SOAPData( new SOAPDataEncoder(swfnum, docs, header) );
272         } catch (Exception JavaDoc e) {
273             mLogger.error("problems getting SOAP document element", e);
274             throw new DataSourceException("problems getting SOAP document element");
275         }
276     }
277
278
279
280
281     /**
282      * Creates key for services map.
283      *
284      * @param wsdl WSDL URL.
285      * @param service SOAP service name.
286      * @param port SOAP port name.
287      * @return key to use for services map.
288      */

289     public String JavaDoc key(String JavaDoc wsdl, String JavaDoc service, String JavaDoc port) {
290         return wsdl + " " + service + " " + port;
291     }
292
293
294     /**
295      * Get SOAP service.
296      *
297      * @param req
298      * @param res
299      * @exception DataSourceException
300      */

301     synchronized public LZSOAPService getService(String JavaDoc app,
302                                                  HttpServletRequest JavaDoc req,
303                                                  HttpServletResponse JavaDoc res,
304                                                  boolean checkLoadOption)
305         throws DataSourceException {
306
307         String JavaDoc wsdl = req.getParameter("wsdl");
308         String JavaDoc service = req.getParameter("service");
309         String JavaDoc port = req.getParameter("port");
310
311         if (wsdl == null || wsdl.equals("")) {
312             throw new DataSourceException("no wsdl specified");
313         }
314
315         LZSOAPService soapService = null;
316         if (checkLoadOption) {
317             if ( "never" == mLoadOption.intern() ) {
318                 soapService = (LZSOAPService)mServiceMap.get( key(wsdl,service,port) );
319             }
320         } else {
321             soapService = (LZSOAPService)mServiceMap.get( key(wsdl,service,port) );
322         }
323         if (soapService != null)
324             return soapService;
325
326         return fetchService(app, req, res);
327     }
328
329     /**
330      * Fetch SOAP service over HTTP.
331      */

332     synchronized public LZSOAPService fetchService(String JavaDoc app,
333                                                    HttpServletRequest JavaDoc req,
334                                                    HttpServletResponse JavaDoc res)
335         throws DataSourceException {
336
337         String JavaDoc wsdl = req.getParameter("wsdl");
338         String JavaDoc service = req.getParameter("service");
339         String JavaDoc port = req.getParameter("port");
340
341         // TODO: [2004-06-24 pkang] cache WSDLs.
342
try {
343             Data data;
344             if (wsdl.startsWith("file:")) {
345                 data = FileDataSource.getFileData(app, req, res, wsdl, -1);
346             } else if (wsdl.startsWith("http://") || wsdl.startsWith("https://")) {
347                 data = HTTPDataSource.getHTTPData(req, res, wsdl, -1);
348             } else {
349                 throw new DataSourceException("unsupported WSDL protocol: " +
350                                               wsdl);
351             }
352
353             String JavaDoc _wsdl = data.getAsString();
354             LZSOAPService soapService =
355                 WSDLParser.parse(wsdl, new InputSource JavaDoc(new StringReader JavaDoc(_wsdl)),
356                                  service, port);
357
358             if (soapService == null) {
359                 throw new DataSourceException("could not find SOAP service (" +
360                                               wsdl + ", " + service + ", " +
361                                               port + ")");
362             }
363
364             mServiceMap.put( key(wsdl,soapService.getServiceName(),soapService.getPort()),
365                              soapService);
366
367             // secondary mapping to the same service
368
if (service == null || port == null) {
369                 mServiceMap.put( key(wsdl,service,port), soapService);
370             }
371
372             return soapService;
373
374         } catch (IOException JavaDoc e) {
375             mLogger.error("Exception", e);
376             throw new DataSourceException(e.getMessage());
377         } catch (WSDLException e) {
378             mLogger.error("Exception", e);
379             throw new DataSourceException(e.getMessage());
380         } catch (ServiceException JavaDoc e) {
381             mLogger.error("Exception", e);
382             throw new DataSourceException(e.getMessage());
383         } catch (Exception JavaDoc e) {
384             mLogger.error("Exception", e);
385             throw new DataSourceException(e.getMessage());
386         }
387     }
388
389
390     SOAPData programToSOAPData(int swfnum, Program program, SOAPHeader header)
391         throws DataSourceException {
392
393         if (mLogger.isDebugEnabled()) {
394             mLogger.debug("programToSOAPData");
395         }
396
397         try {
398             return new SOAPData( new SOAPDataEncoder(swfnum, program, header) );
399         } catch (Exception JavaDoc e) {
400             mLogger.error("problems creating RPC program", e);
401             throw new DataSourceException("problems creating RPC program");
402         }
403     }
404
405     /**
406      * @param serviceKey the key name to the LZSOAPService
407      */

408     synchronized public static void serviceXML(StringBuffer JavaDoc sb, String JavaDoc serviceKey) {
409         LZSOAPService service = (LZSOAPService)mServiceMap.get(serviceKey);
410         if (service != null) {
411             service.toXML(sb);
412         } else {
413             sb.append("<error>").append(serviceKey).append(" service not found.")
414                 .append("</error>");
415         }
416     }
417
418     synchronized public static void listServicesXML(StringBuffer JavaDoc sb) {
419         sb.append("<services count=\"").append(mServiceMap.size()).append("\">");
420         Iterator JavaDoc iter = mServiceMap.keySet().iterator();
421         while (iter.hasNext()) {
422             String JavaDoc k = (String JavaDoc)iter.next();
423             sb.append("<service")
424                 .append(" name=\"").append(XMLUtils.escapeXml(k)).append("\"")
425                 .append(" urlname=\"").append(URLEncoder.encode(k)).append("\"")
426                 .append("/>");
427         }
428         sb.append("</services>");
429     }
430
431     synchronized static public void toXML(StringBuffer JavaDoc sb) {
432         Date JavaDoc lc = new Date JavaDoc(mLastCleared);
433         sb.append("<soapinfo ")
434             .append(" last-cleared=\"").append(lc).append("\"")
435             .append(">");
436         {
437             sb.append(mInvokeLoad.toXML("invoke_load"));
438             sb.append(mGetServiceLoad.toXML("get_service_load"));
439             listServicesXML(sb);
440         }
441         sb.append("</soapinfo>");
442     }
443
444     public static void clearLoadInfo() {
445         mInvokeLoad.reset();
446         mGetServiceLoad.reset();
447         mLastCleared = System.currentTimeMillis();
448     }
449
450     /**
451      * A data object to hold session object.
452      */

453     public class SOAPData extends Data
454     {
455         byte[] mObject = null;
456         SOAPDataEncoder mSOAPDataEncoder = null;
457         public SOAPData(byte[] object) {
458             mObject = object;
459         }
460
461         public SOAPData(SOAPDataEncoder de) {
462             mSOAPDataEncoder = de;
463         }
464
465         public String JavaDoc getMimeType() {
466             return MimeType.SWF;
467         }
468
469         public InputStream JavaDoc getInputStream()
470             throws IOException JavaDoc {
471             if (mObject != null) {
472                 return new ByteArrayInputStream JavaDoc(mObject);
473             } else if (mSOAPDataEncoder != null) {
474                 return mSOAPDataEncoder.getInputStream();
475             }
476
477             throw new IOException JavaDoc("no input stream");
478         }
479
480         public long size() {
481             if (mObject != null) {
482                 return mObject.length;
483             } else if (mSOAPDataEncoder != null) {
484                 try {
485                     return mSOAPDataEncoder.getSize();
486                 } catch (IOException JavaDoc e) {
487                     mLogger.warn("ioexception getting size soap data encoder");
488                 }
489             }
490
491             return 0;
492         }
493     }
494 }
495
Popular Tags