KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > soap > server > http > RPCRouterServlet


1 /*
2  * The Apache Software License, Version 1.1
3  *
4  *
5  * Copyright (c) 2000 The Apache Software Foundation. All rights
6  * reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in
17  * the documentation and/or other materials provided with the
18  * distribution.
19  *
20  * 3. The end-user documentation included with the redistribution,
21  * if any, must include the following acknowledgment:
22  * "This product includes software developed by the
23  * Apache Software Foundation (http://www.apache.org/)."
24  * Alternately, this acknowledgment may appear in the software itself,
25  * if and wherever such third-party acknowledgments normally appear.
26  *
27  * 4. The names "SOAP" and "Apache Software Foundation" must
28  * not be used to endorse or promote products derived from this
29  * software without prior written permission. For written
30  * permission, please contact apache@apache.org.
31  *
32  * 5. Products derived from this software may not be called "Apache",
33  * nor may "Apache" appear in their name, without prior written
34  * permission of the Apache Software Foundation.
35  *
36  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39  * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
40  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
43  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
44  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
45  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
46  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47  * SUCH DAMAGE.
48  * ====================================================================
49  *
50  * This software consists of voluntary contributions made by many
51  * individuals on behalf of the Apache Software Foundation and was
52  * originally based on software copyright (c) 2000, International
53  * Business Machines, Inc., http://www.apache.org. For more
54  * information on the Apache Software Foundation, please see
55  * <http://www.apache.org/>.
56  */

57
58 package org.apache.soap.server.http;
59
60 import java.io.*;
61 import java.util.*;
62 import java.lang.reflect.*;
63 import javax.servlet.*;
64 import javax.servlet.http.*;
65 import javax.xml.parsers.*;
66 import org.w3c.dom.* ;
67 import org.apache.soap.*;
68 import org.apache.soap.rpc.*;
69 import org.apache.soap.server.*;
70 import org.apache.soap.encoding.*;
71 import org.apache.soap.transport.*;
72 import org.apache.soap.util.*;
73 import org.apache.soap.util.xml.*;
74 import org.apache.soap.transport.EnvelopeEditor;
75 import org.apache.soap.transport.EnvelopeEditorFactory;
76
77 /**
78  * This servlet routes RPC requests to the intended method of
79  * the intended object.
80  *
81  * @author Sanjiva Weerawarana (sanjiva@watson.ibm.com)
82  * @author Matthew J. Duftler (duftler@us.ibm.com)
83  * @author Steven McDowall (sjm@aptest.com)
84  * @author Eric M. Dashofy (edashofy@ics.uci.edu)
85  * @author Kevin J. Mitchell (kevin.mitchell@xmls.com)
86  * @author Wouter Cloetens (wcloeten@raleigh.ibm.com)
87  * @author Bill Nagy (nagy@watson.ibm.com)
88  */

89 public class RPCRouterServlet extends HttpServlet {
90   /*
91     EnvelopeEditorFactory, XMLParser, and ConfigFile are
92     all server-side parameters which can be set using Servlet
93     init-parameters or WebApp context-parameters.
94     For example, you may add the following
95     description to web.xml when using Tomcat:
96
97     <context-param>
98         <param-name>EnvelopeEditorFactory</param-name>
99         <param-value>MyEnvelopeEditorFactory</param-value>
100     </context-param>
101     <context-param>
102         <param-name>XMLParser</param-name>
103         <param-value>SampleXMLDocumentBuilderFactory</param-value>
104     </context-param>
105     <context-param>
106         <param-name>ConfigFile</param-name>
107         <param-value>myconfig.xml</param-value>
108     </context-param>
109     <servlet>
110       <servlet-name>RPCRouterServlet</servlet-name>
111       <servlet-class>org.apache.soap.server.http.RPCRouterServlet</servlet-class>
112       <init-param>
113         <param-name>EnvelopeEditorFactory</param-name>
114         <param-value>MyEnvelopeEditorFactory</param-value>
115       </init-param>
116       <init-param>
117         <param-name>XMLParser</param-name>
118         <param-value>SampleXMLDocumentBuilderFactory</param-value>
119       </init-param>
120       <init-param>
121         <param-name>ConfigFile</param-name>
122         <param-value>myconfig.xml</param-value>
123       </init-param>
124     </servlet>
125
126     The servlet init-parameter values will override those of the
127     context-parameters.
128   */

129   private EnvelopeEditor editor = null;
130   private String configFilename = null;
131
132   public void init() throws ServletException {
133     ClassLoader servletClassLoader =
134       Thread.currentThread().getContextClassLoader();
135     
136     try
137     {
138       /*Make sure that we got a useful classloader; if we can not
139     even load ourselves, then at least use the classloader that
140     loaded us.*/

141       servletClassLoader.loadClass(this.getClass().getName());
142     }
143     catch(ClassNotFoundException e)
144     {
145       servletClassLoader = getClass().getClassLoader();
146     }
147     
148     if (servletClassLoader == null)
149     {
150       /*This is needed because some containers use hashtable to store
151     servlet attributes and therefore they can't be null.
152     If Class.forName is passed in null as the classloader, then it
153     seems to default to the system class loader, so this should be ok.*/

154       servletClassLoader = ClassLoader.getSystemClassLoader();
155     }
156     ServletConfig servletConfig = getServletConfig();
157     ServletContext servletContext = servletConfig.getServletContext();
158     /*We're going to check for init parameters in the servletContext first
159       and then allow people to override them in the servletConfig. This
160       will allow for backwards compatability with the old way of setting
161       config parameters.*/

162     String envelopeEditorFactoryClassName =
163       servletConfig.getInitParameter(Constants.ENVELOPE_EDITOR_FACTORY);
164     if (envelopeEditorFactoryClassName == null)
165       envelopeEditorFactoryClassName
166     = servletContext.getInitParameter(Constants.ENVELOPE_EDITOR_FACTORY);
167
168
169     // Is there an envelope editory factory?
170
if (envelopeEditorFactoryClassName != null) {
171       EnvelopeEditorFactory factory =
172         (EnvelopeEditorFactory)createObject(envelopeEditorFactoryClassName,
173                                             servletClassLoader);
174
175       if (factory != null) {
176         try {
177           Properties props = new Properties();
178       /*First we put in the servletContext parameters, and then
179         overwrite them with the servletConfig parameters if
180         they are present.*/

181           Enumeration enum = servletContext.getInitParameterNames();
182       
183           while (enum.hasMoreElements()) {
184             String name = (String)enum.nextElement();
185
186             if (!Constants.ENVELOPE_EDITOR_FACTORY.equals(name)
187                 && !Constants.XML_PARSER.equals(name)) {
188               props.put(name, servletContext.getInitParameter(name));
189             }
190           }
191
192           enum = servletConfig.getInitParameterNames();
193
194           while (enum.hasMoreElements()) {
195             String name = (String)enum.nextElement();
196
197             if (!Constants.ENVELOPE_EDITOR_FACTORY.equals(name)
198                 && !Constants.XML_PARSER.equals(name)) {
199               props.put(name, servletConfig.getInitParameter(name));
200             }
201           }
202
203           // Put the real path into the properties, if it can be found.
204
String servletContextPath = servletContext.getRealPath("");
205
206           if (servletContextPath != null) {
207             props.put("SOAPServerContextPath", servletContextPath);
208           }
209
210           // Create an editor by calling the factory.
211
editor = factory.create(props);
212         } catch (SOAPException e) {
213           throw new ServletException("Can't create editor", e);
214         }
215       }
216     }
217
218
219     String tempStr = servletConfig.getInitParameter(Constants.CONFIGFILENAME);
220     if (tempStr == null)
221       tempStr = servletContext.getInitParameter(Constants.CONFIGFILENAME);
222
223     // Is there a user-specified config filename?
224
if (tempStr != null) {
225       configFilename = tempStr;
226     }
227
228     tempStr = servletConfig.getInitParameter(Constants.XML_PARSER);
229     if (tempStr == null)
230       tempStr = servletContext.getInitParameter(Constants.XML_PARSER);
231
232     // Is there a user-specified JAXP implementation?
233
if (tempStr != null) {
234       XMLParserUtils.refreshDocumentBuilderFactory(tempStr,
235                                                    true, // namespaceAware
236
false);// validating
237
}
238
239     ServerHTTPUtils.setServletClassLoaderIntoContext(servletContext,
240                                                      servletClassLoader);
241   }
242
243   private Object createObject(String className, ClassLoader classLoader)
244     throws ServletException
245   {
246     try {
247       return classLoader.loadClass(className).newInstance();
248     } catch (ClassNotFoundException e) {
249       throw new ServletException("Can't find class named '" + className +
250                                  "'.");
251     } catch (InstantiationException e) {
252       throw new ServletException("Can't instantiate class '" + className +
253                                  "'.");
254     } catch (IllegalAccessException e) {
255       throw new ServletException("WARNING: Can't access the constructor " +
256                                  "of the class '" + className + "'.");
257     }
258   }
259
260   public void doGet (HttpServletRequest req, HttpServletResponse res)
261     throws ServletException, IOException {
262     res.setContentType("text/html");
263
264     PrintWriter out = res.getWriter ();
265
266     out.println("<html><head><title>SOAP RPC Router</title></head>");
267     out.println ("<body><h1>SOAP RPC Router</h1>");
268     out.println ("<p>Sorry, I don't speak via HTTP GET- you have to use");
269     out.println ("HTTP POST to talk to me.</p></body></html>");
270   }
271
272   public void doPost (HttpServletRequest req, HttpServletResponse res)
273     throws ServletException, IOException {
274     ServletConfig config = getServletConfig();
275     ServletContext context = config.getServletContext ();
276     HttpSession session = req.getSession ();
277     ServiceManager serviceManager =
278       ServerHTTPUtils.getServiceManagerFromContext (context, configFilename);
279     Call call = null;
280     Response resp = null;
281     String targetID = null;
282     String fullTargetID = null;
283     int status = res.SC_OK;
284     DeploymentDescriptor dd = null;
285
286     SOAPContext reqCtx = new SOAPContext();
287     SOAPContext resCtx = new SOAPContext();
288     Envelope callEnv = null ;
289
290     reqCtx.setClassLoader( ServerHTTPUtils.
291                              getServletClassLoaderFromContext(context) );
292
293     try { // unrecoverable error
294
try { // SOAPException
295
// extract the call
296
try {// Exception extracting the call
297
reqCtx.setProperty( Constants.BAG_HTTPSERVLET, this );
298           reqCtx.setProperty( Constants.BAG_HTTPSESSION, session );
299           reqCtx.setProperty( Constants.BAG_HTTPSERVLETREQUEST, req );
300           reqCtx.setProperty( Constants.BAG_HTTPSERVLETRESPONSE, res );
301   
302           // Carry the request context from the read to the creation of
303
// the Call object.
304

305           // Generate Envelope after the incoming message is translated by
306
// EnvelopeEditor
307
// Note: XMLParser that is specified by init-param isused in
308
// this process.
309
DocumentBuilder xdb = XMLParserUtils.getXMLDocBuilder();
310
311           callEnv =
312             ServerHTTPUtils.readEnvelopeFromRequest(xdb,
313                                                     req.getContentType(),
314                                                     req.getContentLength(),
315                                                     req.getInputStream(),
316                                                     editor,
317                                                     res,
318                                                     reqCtx);
319           if (callEnv == null)
320             return;
321           call = RPCRouter.extractCallFromEnvelope(serviceManager, callEnv,
322                                                    reqCtx);
323           targetID = call.getTargetObjectURI ();
324           fullTargetID = call.getFullTargetObjectURI ();
325         } catch (IllegalArgumentException e) {
326           String msg = e.getMessage ();
327           String faultCode =
328             (msg != null && msg.equals (Constants.ERR_MSG_VERSION_MISMATCH))
329             ? Constants.FAULT_CODE_VERSION_MISMATCH
330             : Constants.FAULT_CODE_CLIENT;
331           throw new SOAPException (faultCode, msg, e);
332         }
333   
334         // get the deployment descriptor for this service (will except if
335
// not known)
336
dd = serviceManager.query (targetID);
337         reqCtx.setProperty( Constants.BAG_DEPLOYMENTDESCRIPTOR, dd );
338   
339         Provider provider;
340         if ( dd.getProviderType() == DeploymentDescriptor.PROVIDER_JAVA ) {
341           // Handle Java based services
342
provider = new org.apache.soap.providers.RPCJavaProvider();
343         } else if (dd.getProviderType() ==
344                    DeploymentDescriptor.PROVIDER_USER_DEFINED) {
345           // Handle user-defined providers
346
provider = ServerUtils.loadProvider(dd, reqCtx);
347         } else {
348           // Handle scripts
349
provider = new org.apache.soap.providers.RPCJavaProvider();
350         }
351         
352         provider.locate( dd, callEnv, call, call.getMethodName(), fullTargetID,
353                          reqCtx );
354         provider.invoke( reqCtx, resCtx );
355
356       } catch (Throwable t) {
357         // note that we catch runtime errors too with the above .. the
358
// idea is to do a SOAP fault for everything that goes out so
359
// that if the recepient is expecting to read some XML they'll
360
// get it. If not, it doesn't hurt.
361
SOAPException e = null;
362         if (t instanceof SOAPException)
363           e = (SOAPException) t;
364         else
365           e = new SOAPException(Constants.FAULT_CODE_SERVER +
366                                 ".Exception:", "", t);
367   
368         Fault fault = new Fault (e);
369         fault.setFaultActorURI (req.getRequestURI ());
370         if (dd != null)
371           dd.buildFaultRouter(reqCtx).notifyListeners(fault, e);
372   
373         // the status code for faults should always be the internal
374
// server error status code (per soap spec)
375
status = res.SC_INTERNAL_SERVER_ERROR;
376   
377         String respEncStyle = null;
378         if(call != null)
379             respEncStyle = call.getEncodingStyleURI();
380         if(respEncStyle == null)
381           respEncStyle = Constants.NS_URI_SOAP_ENC;
382   
383         resCtx = new SOAPContext(); // get rid of old one
384
resp = new Response (null, null, fault, null, null, respEncStyle,
385                              resCtx);
386         SOAPMappingRegistry smr =
387       (call != null) ? call.getSOAPMappingRegistry ()
388                      : ServerHTTPUtils.getSMRFromContext (context);
389         Envelope env = resp.buildEnvelope();
390         StringWriter sw = new StringWriter();
391         env.marshall(sw, smr, resp.getSOAPContext());
392         resp.getSOAPContext().setRootPart( sw.toString(),
393                                            Constants.HEADERVAL_CONTENT_TYPE_UTF8);
394       }
395
396       // Generate response.
397
TransportMessage sres = new TransportMessage(null, resCtx, null );
398       sres.editOutgoing(editor);
399
400       // Generate response byte array.
401
sres.save();
402
403       // Write.
404
res.setStatus(status);
405       res.setContentType(sres.getContentType());
406       for (Enumeration headers = sres.getHeaderNames();
407            headers.hasMoreElements(); ) {
408           String name = (String)headers.nextElement();
409           res.setHeader(name, sres.getHeader(name));
410       }
411
412       res.setContentLength(sres.getContentLength());
413       OutputStream outStream = res.getOutputStream();
414       sres.writeTo(outStream);
415     }
416     catch (Exception e)
417     {
418         throw new ServletException ("Error building response envelope: " + e);
419     }
420   }
421 }
422
Popular Tags