KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > axis > transport > http > AxisServlet


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.transport.http;
18
19 import java.io.File JavaDoc;
20 import java.io.IOException JavaDoc;
21 import java.io.PrintWriter JavaDoc;
22 import java.lang.reflect.Method JavaDoc;
23 import java.lang.reflect.InvocationTargetException JavaDoc;
24 import java.net.HttpURLConnection JavaDoc;
25 import java.util.ArrayList JavaDoc;
26 import java.util.Enumeration JavaDoc;
27 import java.util.Iterator JavaDoc;
28
29 import javax.servlet.ServletContext JavaDoc;
30 import javax.servlet.ServletException JavaDoc;
31 import javax.servlet.http.HttpServletRequest JavaDoc;
32 import javax.servlet.http.HttpServletResponse JavaDoc;
33 import javax.servlet.http.HttpUtils JavaDoc;
34 import javax.xml.soap.MimeHeader JavaDoc;
35 import javax.xml.soap.MimeHeaders JavaDoc;
36 import javax.xml.soap.SOAPException JavaDoc;
37 import javax.xml.soap.SOAPMessage JavaDoc;
38
39 import org.apache.axis.AxisEngine;
40 import org.apache.axis.AxisFault;
41 import org.apache.axis.ConfigurationException;
42 import org.apache.axis.Constants;
43 import org.apache.axis.Handler;
44 import org.apache.axis.Message;
45 import org.apache.axis.MessageContext;
46 import org.apache.axis.SimpleTargetedChain;
47 import org.apache.axis.client.Service;
48 import org.apache.axis.management.ServiceAdmin;
49 import org.apache.axis.components.logger.LogFactory;
50 import org.apache.axis.description.OperationDesc;
51 import org.apache.axis.description.ServiceDesc;
52 import org.apache.axis.handlers.soap.SOAPService;
53 import org.apache.axis.security.servlet.ServletSecurityProvider;
54 import org.apache.axis.utils.JavaUtils;
55 import org.apache.axis.utils.Messages;
56 import org.apache.axis.utils.XMLUtils;
57 import org.apache.commons.logging.Log;
58 import org.w3c.dom.Element JavaDoc;
59
60 /**
61  *
62  * @author Doug Davis (dug@us.ibm.com)
63  * @author Steve Loughran
64  * xdoclet tags are not active yet; keep web.xml in sync.
65  * To change the location of the services, change url-pattern in web.xml and
66  * set parameter axis.servicesPath in server-config.wsdd. For more information see
67  * <a HREF="http://ws.apache.org/axis/java/reference.html">Axis Reference Guide</a>.
68  *
69  * @web.servlet name="AxisServlet" display-name="Apache-Axis Servlet"
70  * @web.servlet-mapping url-pattern="/servlet/AxisServlet"
71  * @web.servlet-mapping url-pattern="*.jws"
72  * @web.servlet-mapping url-pattern="/services/*"
73   */

74 public class AxisServlet extends AxisServletBase {
75     protected static Log log =
76             LogFactory.getLog(AxisServlet.class.getName());
77
78     /**
79      * this log is for timing
80      */

81     private static Log tlog =
82             LogFactory.getLog(Constants.TIME_LOG_CATEGORY);
83
84     /**
85      * a separate log for exceptions lets users route them
86      * differently from general low level debug info
87      */

88     private static Log exceptionLog =
89             LogFactory.getLog(Constants.EXCEPTION_LOG_CATEGORY);
90
91     public static final String JavaDoc INIT_PROPERTY_TRANSPORT_NAME =
92             "transport.name";
93
94     public static final String JavaDoc INIT_PROPERTY_USE_SECURITY =
95             "use-servlet-security";
96     public static final String JavaDoc INIT_PROPERTY_ENABLE_LIST =
97             "axis.enableListQuery";
98
99     public static final String JavaDoc INIT_PROPERTY_JWS_CLASS_DIR =
100             "axis.jws.servletClassDir";
101
102     // This will turn off the list of available services
103
public static final String JavaDoc INIT_PROPERTY_DISABLE_SERVICES_LIST =
104             "axis.disableServiceList";
105
106     // Location of the services as defined by the servlet-mapping in web.xml
107
public static final String JavaDoc INIT_PROPERTY_SERVICES_PATH =
108             "axis.servicesPath";
109
110     // These have default values.
111
private String JavaDoc transportName;
112
113     private Handler transport;
114
115     private ServletSecurityProvider securityProvider = null;
116
117     private String JavaDoc servicesPath;
118
119     /**
120      * cache of logging debug option; only evaluated at init time.
121      * So no dynamic switching of logging options with this servlet.
122      */

123     private static boolean isDebug = false;
124
125     /**
126      * Should we enable the "?list" functionality on GETs? (off by
127      * default because deployment information is a potential security
128      * hole)
129      */

130     private boolean enableList = false;
131
132     /**
133      * Should we turn off the list of services when we receive a GET
134      * at the servlet root?
135      */

136     private boolean disableServicesList = false;
137
138     /**
139      * Cached path to JWS output directory
140      */

141     private String JavaDoc jwsClassDir = null;
142     protected String JavaDoc getJWSClassDir() {return jwsClassDir;
143     }
144
145
146     /**
147      * create a new servlet instance
148      */

149     public AxisServlet() {
150     }
151
152     /**
153      * Initialization method.
154      */

155     public void init() throws javax.servlet.ServletException JavaDoc {
156         super.init();
157         ServletContext JavaDoc context = getServletConfig().getServletContext();
158
159         isDebug = log.isDebugEnabled();
160         if (isDebug) {
161             log.debug("In servlet init");
162         }
163         transportName = getOption(context,
164                                   INIT_PROPERTY_TRANSPORT_NAME,
165                                   HTTPTransport.DEFAULT_TRANSPORT_NAME);
166
167         if (JavaUtils.isTrueExplicitly(getOption(context,
168                                                  INIT_PROPERTY_USE_SECURITY, null))) {
169             securityProvider = new ServletSecurityProvider();
170         }
171
172         enableList =
173                 JavaUtils.isTrueExplicitly(getOption(context,
174                 INIT_PROPERTY_ENABLE_LIST, null));
175
176         jwsClassDir = getOption(context, INIT_PROPERTY_JWS_CLASS_DIR, null);
177
178         // Should we list services?
179
disableServicesList = JavaUtils.isTrue(getOption(context,
180                 INIT_PROPERTY_DISABLE_SERVICES_LIST, "false"));
181
182         servicesPath = getOption(context, INIT_PROPERTY_SERVICES_PATH,
183                                  "/services/");
184
185         /**
186          * There are DEFINATE problems here if
187          * getHomeDir and/or getDefaultJWSClassDir return null
188          * (as they could with WebLogic).
189          * This needs to be reexamined in the future, but this
190          * should fix any NPE's in the mean time.
191          */

192         if (jwsClassDir != null) {
193             if (getHomeDir() != null) {
194                 jwsClassDir = getHomeDir() + jwsClassDir;
195             }
196         } else {
197             jwsClassDir = getDefaultJWSClassDir();
198         }
199
200         initQueryStringHandlers();
201
202         // Setup the service admin
203
try {
204             ServiceAdmin.setEngine(this.getEngine(), context.getServerInfo());
205         } catch (AxisFault af) {
206             exceptionLog.info("Exception setting AxisEngine on ServiceAdmin " +
207                               af);
208         }
209     }
210
211
212     /**
213      * Process GET requests. This includes handoff of pseudo-SOAP requests
214      *
215      * @param request request in
216      * @param response request out
217      * @throws ServletException
218      * @throws IOException
219      */

220     public void doGet(HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response) throws
221             ServletException JavaDoc, IOException JavaDoc {
222         if (isDebug) {
223             log.debug("Enter: doGet()");
224
225         }
226         PrintWriter JavaDoc writer = new FilterPrintWriter(response);
227
228         try {
229             AxisEngine engine = getEngine();
230             ServletContext JavaDoc servletContext =
231                     getServletConfig().getServletContext();
232
233             String JavaDoc pathInfo = request.getPathInfo();
234             String JavaDoc realpath = servletContext.getRealPath(request.getServletPath());
235             if (realpath == null) {
236                 realpath = request.getServletPath();
237             }
238
239             //JWS pages are special; they are the servlet path and there
240
//is no pathinfo...we map the pathinfo to the servlet path to keep
241
//it happy
242
boolean isJWSPage = request.getRequestURI().endsWith(".jws");
243             if (isJWSPage) {
244                 pathInfo = request.getServletPath();
245             }
246
247             // Try to execute a query string plugin and return upon success.
248

249             if (processQuery(request, response, writer) == true) {
250                 return;
251             }
252
253             boolean hasNoPath = (pathInfo == null || pathInfo.equals(""));
254             if (!disableServicesList) {
255                 if(hasNoPath) {
256                     // If the user requested the servlet (i.e. /axis/servlet/AxisServlet)
257
// with no service name, present the user with a list of deployed
258
// services to be helpful
259
// Don't do this if has been turned off
260
reportAvailableServices(response, writer, request);
261                 } else if (realpath != null) {
262                     // We have a pathname, so now we perform WSDL or list operations
263

264                     // get message context w/ various properties set
265
MessageContext msgContext = createMessageContext(engine,
266                             request, response);
267
268                     // NOTE: HttpUtils.getRequestURL has been deprecated.
269
// This line SHOULD be:
270
// String url = req.getRequestURL().toString()
271
// HOWEVER!!!! DON'T REPLACE IT! There's a bug in
272
// req.getRequestURL that is not in HttpUtils.getRequestURL
273
// req.getRequestURL returns "localhost" in the remote
274
// scenario rather than the actual host name.
275
//
276
// But more importantly, getRequestURL() is a servlet 2.3
277
// API and to support servlet 2.2 (aka WebSphere 4)
278
// we need to leave this in for a while longer. tomj 10/14/2004
279
//
280
String JavaDoc url = HttpUtils.getRequestURL(request).toString();
281
282                     msgContext.setProperty(MessageContext.TRANS_URL, url);
283
284                     // See if we can locate the desired service. If we
285
// can't, return a 404 Not Found. Otherwise, just
286
// print the placeholder message.
287

288                     String JavaDoc serviceName;
289                     if (pathInfo.startsWith("/")) {
290                         serviceName = pathInfo.substring(1);
291                     } else {
292                         serviceName = pathInfo;
293                     }
294
295                     SOAPService s = engine.getService(serviceName);
296                     if (s == null) {
297                         //no service: report it
298
if (isJWSPage) {
299                             reportCantGetJWSService(request, response, writer);
300                         } else {
301                             reportCantGetAxisService(request, response, writer);
302                         }
303
304                     } else {
305                         //print a snippet of service info.
306
reportServiceInfo(response, writer, s, serviceName);
307                     }
308                 }
309             } else {
310                 // We didn't have a real path in the request, so just
311
// print a message informing the user that they reached
312
// the servlet.
313

314                 response.setContentType("text/html; charset=utf-8");
315                 writer.println("<html><h1>Axis HTTP Servlet</h1>");
316                 writer.println(Messages.getMessage("reachedServlet00"));
317
318                 writer.println("<p>" +
319                                Messages.getMessage("transportName00",
320                         "<b>" + transportName + "</b>"));
321                 writer.println("</html>");
322             }
323         } catch (AxisFault fault) {
324             reportTroubleInGet(fault, response, writer);
325         } catch (Exception JavaDoc e) {
326             reportTroubleInGet(e, response, writer);
327         } finally {
328             writer.close();
329             if (isDebug) {
330                 log.debug("Exit: doGet()");
331             }
332         }
333     }
334
335     /**
336      * when we get an exception or an axis fault in a GET, we handle
337      * it almost identically: we go 'something went wrong', set the response
338      * code to 500 and then dump info. But we dump different info for an axis fault
339      * or subclass thereof.
340      * @param exception what went wrong
341      * @param response current response
342      * @param writer open writer to response
343      */

344     private void reportTroubleInGet(Throwable JavaDoc exception,
345                                     HttpServletResponse JavaDoc response,
346                                     PrintWriter JavaDoc writer) {
347         response.setContentType("text/html; charset=utf-8");
348         response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
349         writer.println("<h2>" +
350                        Messages.getMessage("error00") +
351                        "</h2>");
352         writer.println("<p>" +
353                        Messages.getMessage("somethingWrong00") +
354                        "</p>");
355         if (exception instanceof AxisFault) {
356             AxisFault fault = (AxisFault) exception;
357             processAxisFault(fault);
358             writeFault(writer, fault);
359         } else {
360             logException(exception);
361             writer.println("<pre>Exception - " + exception + "<br>");
362             //dev systems only give fault dumps
363
if (isDevelopment()) {
364                 writer.println(JavaUtils.stackToString(exception));
365             }
366             writer.println("</pre>");
367         }
368     }
369
370     /**
371      * routine called whenever an axis fault is caught; where they
372      * are logged and any other business. The method may modify the fault
373      * in the process
374      * @param fault what went wrong.
375      */

376     protected void processAxisFault(AxisFault fault) {
377         //log the fault
378
Element JavaDoc runtimeException = fault.lookupFaultDetail(
379                 Constants.QNAME_FAULTDETAIL_RUNTIMEEXCEPTION);
380         if (runtimeException != null) {
381             exceptionLog.info(Messages.getMessage("axisFault00"), fault);
382             //strip runtime details
383
fault.removeFaultDetail(Constants.
384                                     QNAME_FAULTDETAIL_RUNTIMEEXCEPTION);
385         } else if (exceptionLog.isDebugEnabled()) {
386             exceptionLog.debug(Messages.getMessage("axisFault00"), fault);
387         }
388         //dev systems only give fault dumps
389
if (!isDevelopment()) {
390             //strip out the stack trace
391
fault.removeFaultDetail(Constants.QNAME_FAULTDETAIL_STACKTRACE);
392         }
393     }
394
395     /**
396      * log any exception to our output log, at our chosen level
397      * @param e what went wrong
398      */

399     protected void logException(Throwable JavaDoc e) {
400         exceptionLog.info(Messages.getMessage("exception00"), e);
401     }
402
403     /**
404      * this method writes a fault out to an HTML stream. This includes
405      * escaping the strings to defend against cross-site scripting attacks
406      * @param writer
407      * @param axisFault
408      */

409     private void writeFault(PrintWriter JavaDoc writer, AxisFault axisFault) {
410         String JavaDoc localizedMessage = XMLUtils.xmlEncodeString(axisFault.
411                 getLocalizedMessage());
412         writer.println("<pre>Fault - " + localizedMessage + "<br>");
413         writer.println(axisFault.dumpToString());
414         writer.println("</pre>");
415     }
416
417     /**
418      * print a snippet of service info.
419      * @param service service
420      * @param writer output channel
421      * @param serviceName where to put stuff
422      */

423
424     protected void reportServiceInfo(HttpServletResponse JavaDoc response,
425                                      PrintWriter JavaDoc writer, SOAPService service,
426                                      String JavaDoc serviceName) {
427         response.setContentType("text/html; charset=utf-8");
428
429         writer.println("<h1>"
430                        + service.getName()
431                        + "</h1>");
432         writer.println(
433                 "<p>" +
434                 Messages.getMessage("axisService00") +
435                 "</p>");
436         writer.println(
437                 "<i>" +
438                 Messages.getMessage("perhaps00") +
439                 "</i>");
440     }
441
442     /**
443      * report that we have no WSDL
444      *
445      * This method was moved to the querystring handler QSWSDLHandler. The
446      * method reportNoWSDL in AxisServlet is never called. Perhaps the method
447      * is overwritten in subclasses of AxisServlet so the method wasn't
448      * removed. See the discussion in
449      *
450      * http://nagoya.apache.org/bugzilla/show_bug.cgi?id=23845
451      *
452      * @param res
453      * @param writer
454      * @param moreDetailCode optional name of a message to provide more detail
455      * @param axisFault optional fault string, for extra info at debug time only
456      */

457     protected void reportNoWSDL(HttpServletResponse JavaDoc res, PrintWriter JavaDoc writer,
458                                 String JavaDoc moreDetailCode, AxisFault axisFault) {
459     }
460
461
462     /**
463      * This method lists the available services; it is called when there is
464      * nothing to execute on a GET
465      * @param response
466      * @param writer
467      * @param request
468      * @throws ConfigurationException
469      * @throws AxisFault
470      */

471     protected void reportAvailableServices(HttpServletResponse JavaDoc response,
472                                            PrintWriter JavaDoc writer,
473                                            HttpServletRequest JavaDoc request) throws
474             ConfigurationException, AxisFault {
475         AxisEngine engine = getEngine();
476
477         response.setContentType("text/html; charset=utf-8");
478         writer.println("<h2>And now... Some Services</h2>");
479
480         Iterator JavaDoc i;
481         try {
482             i = engine.getConfig().getDeployedServices();
483         } catch (ConfigurationException configException) {
484             //turn any internal configuration exceptions back into axis faults
485
//if that is what they are
486
if (configException.getContainedException() instanceof AxisFault) {
487                 throw (AxisFault) configException.getContainedException();
488             } else {
489                 throw configException;
490             }
491         }
492         // baseURL may change if <endpointURL> tag is used for
493
// custom deployment at a different location
494
String JavaDoc defaultBaseURL = getWebappBase(request) + servicesPath;
495         writer.println("<ul>");
496         while (i.hasNext()) {
497             ServiceDesc sd = (ServiceDesc) i.next();
498             StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
499             sb.append("<li>");
500             String JavaDoc name = sd.getName();
501             sb.append(name);
502             sb.append(" <a HREF=\"");
503             String JavaDoc endpointURL = sd.getEndpointURL();
504             String JavaDoc baseURL = (endpointURL == null) ? defaultBaseURL :
505                              endpointURL;
506             sb.append(baseURL);
507             sb.append(name);
508             sb.append("?wsdl\"><i>(wsdl)</i></a></li>");
509             writer.println(sb.toString());
510             ArrayList JavaDoc operations = sd.getOperations();
511             if (!operations.isEmpty()) {
512                 writer.println("<ul>");
513                 for (Iterator JavaDoc it = operations.iterator(); it.hasNext(); ) {
514                     OperationDesc desc = (OperationDesc) it.next();
515                     writer.println("<li>" + desc.getName());
516                 }
517                 writer.println("</ul>");
518             }
519         }
520         writer.println("</ul>");
521     }
522
523     /**
524      * generate the error response to indicate that there is apparently no endpoint there
525      * @param request the request that didnt have an edpoint
526      * @param response response we are generating
527      * @param writer open writer for the request
528      */

529     protected void reportCantGetAxisService(HttpServletRequest JavaDoc request,
530                                             HttpServletResponse JavaDoc response,
531                                             PrintWriter JavaDoc writer) {
532         // no such service....
533
response.setStatus(HttpURLConnection.HTTP_NOT_FOUND);
534         response.setContentType("text/html; charset=utf-8");
535         writer.println("<h2>" +
536                        Messages.getMessage("error00") + "</h2>");
537         writer.println("<p>" +
538                        Messages.getMessage("noService06") +
539                        "</p>");
540     }
541
542     /**
543      * probe for a JWS page and report 'no service' if one is not found there
544      * @param request the request that didnt have an edpoint
545      * @param response response we are generating
546      * @param writer open writer for the request
547      */

548     protected void reportCantGetJWSService(HttpServletRequest JavaDoc request,
549                                            HttpServletResponse JavaDoc response,
550                                            PrintWriter JavaDoc writer) {
551         // first look to see if there is a service
552
// requestPath is a work around to support serving .jws web services
553
// from services URL - see AXIS-843 for more information
554
String JavaDoc requestPath = request.getServletPath() + ((request.getPathInfo() != null) ?
555                 request.getPathInfo() : "");
556         String JavaDoc realpath = getServletConfig().getServletContext()
557                           .getRealPath(requestPath);
558         log.debug("JWS real path: " + realpath);
559         boolean foundJWSFile = (new File JavaDoc(realpath).exists()) &&
560                                (realpath.endsWith(Constants.
561                                                   JWS_DEFAULT_FILE_EXTENSION));
562         response.setContentType("text/html; charset=utf-8");
563         if (foundJWSFile) {
564             response.setStatus(HttpURLConnection.HTTP_OK);
565             writer.println(Messages.getMessage("foundJWS00") + "<p>");
566             String JavaDoc url = request.getRequestURI();
567             String JavaDoc urltext = Messages.getMessage("foundJWS01");
568             writer.println("<a HREF='" + url + "?wsdl'>" + urltext + "</a>");
569         } else {
570             response.setStatus(HttpURLConnection.HTTP_NOT_FOUND);
571             writer.println(Messages.getMessage("noService06"));
572         }
573     }
574
575
576     /**
577      * Process a POST to the servlet by handing it off to the Axis Engine.
578      * Here is where SOAP messages are received
579      * @param req posted request
580      * @param res respose
581      * @throws ServletException trouble
582      * @throws IOException different trouble
583      */

584     public void doPost(HttpServletRequest JavaDoc req, HttpServletResponse JavaDoc res) throws
585             ServletException JavaDoc, IOException JavaDoc {
586         long t0 = 0, t1 = 0, t2 = 0, t3 = 0, t4 = 0;
587         String JavaDoc soapAction = null;
588         MessageContext msgContext = null;
589         if (isDebug) {
590             log.debug("Enter: doPost()");
591         }
592         if (tlog.isDebugEnabled()) {
593             t0 = System.currentTimeMillis();
594         }
595
596         Message JavaDoc responseMsg = null;
597         String JavaDoc contentType = null;
598
599         try {
600             AxisEngine engine = getEngine();
601
602             if (engine == null) {
603                 // !!! should return a SOAP fault...
604
ServletException JavaDoc se =
605                         new ServletException JavaDoc(Messages.getMessage("noEngine00"));
606                 log.debug("No Engine!", se);
607                 throw se;
608             }
609
610             res.setBufferSize(1024 * 8); // provide performance boost.
611

612             /** get message context w/ various properties set
613              */

614             msgContext = createMessageContext(engine, req, res);
615
616             // ? OK to move this to 'getMessageContext',
617
// ? where it would also be picked up for 'doGet()' ?
618
if (securityProvider != null) {
619                 if (isDebug) {
620                     log.debug("securityProvider:" + securityProvider);
621                 }
622                 msgContext.setProperty(MessageContext.SECURITY_PROVIDER,
623                                        securityProvider);
624             }
625
626             /* Get request message
627              */

628             Message JavaDoc requestMsg =
629                     new Message JavaDoc(req.getInputStream(),
630                                 false,
631                                 req.getHeader(HTTPConstants.HEADER_CONTENT_TYPE),
632                                 req.getHeader(HTTPConstants.
633                                               HEADER_CONTENT_LOCATION));
634             // Transfer HTTP headers to MIME headers for request message.
635
MimeHeaders JavaDoc requestMimeHeaders = requestMsg.getMimeHeaders();
636             for (Enumeration JavaDoc e = req.getHeaderNames(); e.hasMoreElements(); ) {
637                 String JavaDoc headerName = (String JavaDoc) e.nextElement();
638                 for (Enumeration JavaDoc f = req.getHeaders(headerName);
639                                      f.hasMoreElements(); ) {
640                     String JavaDoc headerValue = (String JavaDoc) f.nextElement();
641                     requestMimeHeaders.addHeader(headerName, headerValue);
642                 }
643             }
644
645             if (isDebug) {
646                 log.debug("Request Message:" + requestMsg);
647
648                 /* Set the request(incoming) message field in the context */
649                 /**********************************************************/
650             }
651             msgContext.setRequestMessage(requestMsg);
652             String JavaDoc url = HttpUtils.getRequestURL(req).toString();
653             msgContext.setProperty(MessageContext.TRANS_URL, url);
654             // put character encoding of request to message context
655
// in order to reuse it during the whole process.
656
String JavaDoc requestEncoding;
657             try {
658                 requestEncoding = (String JavaDoc) requestMsg.getProperty(SOAPMessage.
659                         CHARACTER_SET_ENCODING);
660                 if (requestEncoding != null) {
661                     msgContext.setProperty(SOAPMessage.CHARACTER_SET_ENCODING,
662                                            requestEncoding);
663                 }
664             } catch (SOAPException JavaDoc e1) {
665             }
666
667             try {
668                 /**
669                  * Save the SOAPAction header in the MessageContext bag.
670                  * This will be used to tell the Axis Engine which service
671                  * is being invoked. This will save us the trouble of
672                  * having to parse the Request message - although we will
673                  * need to double-check later on that the SOAPAction header
674                  * does in fact match the URI in the body.
675                  */

676                 // (is this last stmt true??? (I don't think so - Glen))
677
/********************************************************/
678                 soapAction = getSoapAction(req);
679
680                 if (soapAction != null) {
681                     msgContext.setUseSOAPAction(true);
682                     msgContext.setSOAPActionURI(soapAction);
683                 }
684
685                 // Create a Session wrapper for the HTTP session.
686
// These can/should be pooled at some point.
687
// (Sam is Watching! :-)
688
msgContext.setSession(new AxisHttpSession(req));
689
690                 if (tlog.isDebugEnabled()) {
691                     t1 = System.currentTimeMillis();
692                 }
693                 /* Invoke the Axis engine... */
694                 /*****************************/
695                 if (isDebug) {
696                     log.debug("Invoking Axis Engine.");
697                     //here we run the message by the engine
698
}
699                 engine.invoke(msgContext);
700                 if (isDebug) {
701                     log.debug("Return from Axis Engine.");
702                 }
703                 if (tlog.isDebugEnabled()) {
704                     t2 = System.currentTimeMillis();
705                 }
706                 responseMsg = msgContext.getResponseMessage();
707
708                 // We used to throw exceptions on null response messages.
709
// They are actually OK in certain situations (asynchronous
710
// services), so fall through here and return an ACCEPTED
711
// status code below. Might want to install a configurable
712
// error check for this later.
713
} catch (AxisFault fault) {
714                 //log and sanitize
715
processAxisFault(fault);
716                 configureResponseFromAxisFault(res, fault);
717                 responseMsg = msgContext.getResponseMessage();
718                 if (responseMsg == null) {
719                     responseMsg = new Message JavaDoc(fault);
720                     ((org.apache.axis.SOAPPart) responseMsg.getSOAPPart()).
721                             getMessage().setMessageContext(msgContext);
722                 }
723             } catch (Exception JavaDoc e) {
724                 //other exceptions are internal trouble
725
responseMsg = msgContext.getResponseMessage();
726                 res.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
727                 responseMsg = convertExceptionToAxisFault(e, responseMsg);
728                 ((org.apache.axis.SOAPPart) responseMsg.getSOAPPart()).
729                         getMessage().setMessageContext(msgContext);
730             } catch (Throwable JavaDoc t) {
731                 logException(t);
732                 //other exceptions are internal trouble
733
responseMsg = msgContext.getResponseMessage();
734                 res.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
735                 responseMsg = new Message JavaDoc(new AxisFault(t.toString(),t));
736                 ((org.apache.axis.SOAPPart) responseMsg.getSOAPPart()).
737                         getMessage().setMessageContext(msgContext);
738             }
739         } catch (AxisFault fault) {
740             processAxisFault(fault);
741             configureResponseFromAxisFault(res, fault);
742             responseMsg = msgContext.getResponseMessage();
743             if (responseMsg == null) {
744                 responseMsg = new Message JavaDoc(fault);
745                 ((org.apache.axis.SOAPPart) responseMsg.getSOAPPart()).
746                         getMessage().setMessageContext(msgContext);
747             }
748         }
749
750         if (tlog.isDebugEnabled()) {
751             t3 = System.currentTimeMillis();
752         }
753
754         /* Send response back along the wire... */
755         /***********************************/
756         if (responseMsg != null) {
757             // Transfer MIME headers to HTTP headers for response message.
758
MimeHeaders JavaDoc responseMimeHeaders = responseMsg.getMimeHeaders();
759             for (Iterator JavaDoc i = responseMimeHeaders.getAllHeaders(); i.hasNext(); ) {
760                 MimeHeader JavaDoc responseMimeHeader = (MimeHeader JavaDoc) i.next();
761                 res.addHeader(responseMimeHeader.getName(),
762                               responseMimeHeader.getValue());
763             }
764             // synchronize the character encoding of request and response
765
String JavaDoc responseEncoding = (String JavaDoc) msgContext.getProperty(
766                     SOAPMessage.CHARACTER_SET_ENCODING);
767             if (responseEncoding != null) {
768                 try {
769                     responseMsg.setProperty(SOAPMessage.CHARACTER_SET_ENCODING,
770                                             responseEncoding);
771                 } catch (SOAPException JavaDoc e) {
772                 }
773             }
774             //determine content type from message response
775
contentType = responseMsg.getContentType(msgContext.
776                     getSOAPConstants());
777             sendResponse(contentType, res, responseMsg);
778         } else {
779             // No content, so just indicate accepted
780
res.setStatus(202);
781         }
782         
783         if (isDebug) {
784             log.debug("Response sent.");
785             log.debug("Exit: doPost()");
786         }
787         if (tlog.isDebugEnabled()) {
788             t4 = System.currentTimeMillis();
789             tlog.debug("axisServlet.doPost: " + soapAction +
790                        " pre=" + (t1 - t0) +
791                        " invoke=" + (t2 - t1) +
792                        " post=" + (t3 - t2) +
793                        " send=" + (t4 - t3) +
794                        " " + msgContext.getTargetService() + "." +
795                        ((msgContext.getOperation() == null) ?
796                         "" : msgContext.getOperation().getName()));
797         }
798
799     }
800
801     /**
802      * Configure the servlet response status code and maybe other headers
803      * from the fault info.
804      * @param response response to configure
805      * @param fault what went wrong
806      */

807     private void configureResponseFromAxisFault(HttpServletResponse JavaDoc response,
808                                                 AxisFault fault) {
809         // then get the status code
810
// It's been suggested that a lack of SOAPAction
811
// should produce some other error code (in the 400s)...
812
int status = getHttpServletResponseStatus(fault);
813         if (status == HttpServletResponse.SC_UNAUTHORIZED) {
814             // unauth access results in authentication request
815
// TODO: less generic realm choice?
816
response.setHeader("WWW-Authenticate", "Basic realm=\"AXIS\"");
817         }
818         response.setStatus(status);
819     }
820
821     /**
822      * turn any Exception into an AxisFault, log it, set the response
823      * status code according to what the specifications say and
824      * return a response message for posting. This will be the response
825      * message passed in if non-null; one generated from the fault otherwise.
826      *
827      * @param exception what went wrong
828      * @param responseMsg what response we have (if any)
829      * @return a response message to send to the user
830      */

831     private Message JavaDoc convertExceptionToAxisFault(Exception JavaDoc exception,
832                                                 Message JavaDoc responseMsg) {
833         logException(exception);
834         if (responseMsg == null) {
835             AxisFault fault = AxisFault.makeFault(exception);
836             processAxisFault(fault);
837             responseMsg = new Message JavaDoc(fault);
838         }
839         return responseMsg;
840     }
841
842     /**
843      * Extract information from AxisFault and map it to a HTTP Status code.
844      *
845      * @param af Axis Fault
846      * @return HTTP Status code.
847      */

848     protected int getHttpServletResponseStatus(AxisFault af) {
849         // TODO: Should really be doing this with explicit AxisFault
850
// subclasses... --Glen
851
return af.getFaultCode().getLocalPart().startsWith("Server.Unauth")
852                 ? HttpServletResponse.SC_UNAUTHORIZED
853                 : HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
854         // This will raise a 401 for both
855
// "Unauthenticated" & "Unauthorized"...
856
}
857
858     /**
859      * write a message to the response, set appropriate headers for content
860      * type..etc.
861      * @param res response
862      * @param responseMsg message to write
863      * @throws AxisFault
864      * @throws IOException if the response stream can not be written to
865      */

866     private void sendResponse(String JavaDoc contentType,
867                               HttpServletResponse JavaDoc res,
868                               Message JavaDoc responseMsg) throws AxisFault,
869             IOException JavaDoc {
870         if (responseMsg == null) {
871             res.setStatus(HttpServletResponse.SC_NO_CONTENT);
872             if (isDebug) {
873                 log.debug("NO AXIS MESSAGE TO RETURN!");
874                 //String resp = Messages.getMessage("noData00");
875
//res.setContentLength((int) resp.getBytes().length);
876
//res.getWriter().print(resp);
877
}
878         } else {
879             if (isDebug) {
880                 log.debug("Returned Content-Type:" +
881                           contentType);
882                 // log.debug("Returned Content-Length:" +
883
// responseMsg.getContentLength());
884
}
885
886             try {
887                 res.setContentType(contentType);
888
889                 /* My understand of Content-Length
890                  * HTTP 1.0
891                  * -Required for requests, but optional for responses.
892                  * HTTP 1.1
893                  * - Either Content-Length or HTTP Chunking is required.
894                  * Most servlet engines will do chunking if content-length is not specified.
895                  *
896                  *
897                  */

898
899                 //if(clientVersion == HTTPConstants.HEADER_PROTOCOL_V10) //do chunking if necessary.
900
// res.setContentLength(responseMsg.getContentLength());
901

902                 responseMsg.writeTo(res.getOutputStream());
903             } catch (SOAPException JavaDoc e) {
904                 logException(e);
905             }
906         }
907
908         if (!res.isCommitted()) {
909             res.flushBuffer(); // Force it right now.
910
}
911     }
912
913     /**
914      * Place the Request message in the MessagContext object - notice
915      * that we just leave it as a 'ServletRequest' object and let the
916      * Message processing routine convert it - we don't do it since we
917      * don't know how it's going to be used - perhaps it might not
918      * even need to be parsed.
919      * @return a message context
920      */

921     private MessageContext createMessageContext(AxisEngine engine,
922                                                 HttpServletRequest JavaDoc req,
923                                                 HttpServletResponse JavaDoc res) {
924         MessageContext msgContext = new MessageContext(engine);
925
926         String JavaDoc requestPath = getRequestPath(req);
927
928         if (isDebug) {
929             log.debug("MessageContext:" + msgContext);
930             log.debug("HEADER_CONTENT_TYPE:" +
931                       req.getHeader(HTTPConstants.HEADER_CONTENT_TYPE));
932             log.debug("HEADER_CONTENT_LOCATION:" +
933                       req.getHeader(HTTPConstants.HEADER_CONTENT_LOCATION));
934             log.debug("Constants.MC_HOME_DIR:" + String.valueOf(getHomeDir()));
935             log.debug("Constants.MC_RELATIVE_PATH:" + requestPath);
936             log.debug("HTTPConstants.MC_HTTP_SERVLETLOCATION:" +
937                       String.valueOf(getWebInfPath()));
938             log.debug("HTTPConstants.MC_HTTP_SERVLETPATHINFO:" +
939                       req.getPathInfo());
940             log.debug("HTTPConstants.HEADER_AUTHORIZATION:" +
941                       req.getHeader(HTTPConstants.HEADER_AUTHORIZATION));
942             log.debug("Constants.MC_REMOTE_ADDR:" + req.getRemoteAddr());
943             log.debug("configPath:" + String.valueOf(getWebInfPath()));
944         }
945
946         /* Set the Transport */
947         /*********************/
948         msgContext.setTransportName(transportName);
949
950         /* Save some HTTP specific info in the bag in case someone needs it */
951         /********************************************************************/
952         msgContext.setProperty(Constants.MC_JWS_CLASSDIR, jwsClassDir);
953         msgContext.setProperty(Constants.MC_HOME_DIR, getHomeDir());
954         msgContext.setProperty(Constants.MC_RELATIVE_PATH, requestPath);
955         msgContext.setProperty(HTTPConstants.MC_HTTP_SERVLET, this);
956         msgContext.setProperty(HTTPConstants.MC_HTTP_SERVLETREQUEST, req);
957         msgContext.setProperty(HTTPConstants.MC_HTTP_SERVLETRESPONSE, res);
958         msgContext.setProperty(HTTPConstants.MC_HTTP_SERVLETLOCATION,
959                                getWebInfPath());
960         msgContext.setProperty(HTTPConstants.MC_HTTP_SERVLETPATHINFO,
961                                req.getPathInfo());
962         msgContext.setProperty(HTTPConstants.HEADER_AUTHORIZATION,
963                                req.getHeader(HTTPConstants.HEADER_AUTHORIZATION));
964         msgContext.setProperty(Constants.MC_REMOTE_ADDR, req.getRemoteAddr());
965
966         // Set up a javax.xml.rpc.server.ServletEndpointContext
967
ServletEndpointContextImpl sec = new ServletEndpointContextImpl();
968
969         msgContext.setProperty(Constants.MC_SERVLET_ENDPOINT_CONTEXT, sec);
970         /* Save the real path */
971         /**********************/
972         String JavaDoc realpath = getServletConfig().getServletContext()
973                           .getRealPath(requestPath);
974
975         if (realpath != null) {
976             msgContext.setProperty(Constants.MC_REALPATH, realpath);
977         }
978
979         msgContext.setProperty(Constants.MC_CONFIGPATH, getWebInfPath());
980
981         return msgContext;
982     }
983
984     /**
985      * Extract the SOAPAction header.
986      * if SOAPAction is null then we'll we be forced to scan the body for it.
987      * if SOAPAction is "" then use the URL
988      * @param req incoming request
989      * @return the action
990      * @throws AxisFault
991      */

992     private String JavaDoc getSoapAction(HttpServletRequest JavaDoc req) throws AxisFault {
993         String JavaDoc soapAction = req.getHeader(HTTPConstants.HEADER_SOAP_ACTION);
994
995         if (isDebug) {
996             log.debug("HEADER_SOAP_ACTION:" + soapAction);
997
998             /**
999              * Technically, if we don't find this header, we should probably fault.
1000             * It's required in the SOAP HTTP binding.
1001             */

1002        }
1003        if (soapAction == null) {
1004            AxisFault af = new AxisFault("Client.NoSOAPAction",
1005                                         Messages.getMessage("noHeader00",
1006                    "SOAPAction"),
1007                                         null, null);
1008
1009            exceptionLog.error(Messages.getMessage("genFault00"), af);
1010
1011            throw af;
1012        }
1013        // the SOAP 1.1 spec & WS-I 1.0 says:
1014
// soapaction = "SOAPAction" ":" [ <"> URI-reference <"> ]
1015
// some implementations leave off the quotes
1016
// we strip them if they are present
1017
if (soapAction.startsWith("\"") && soapAction.endsWith("\"")
1018            && soapAction.length() >= 2) {
1019            int end = soapAction.length() - 1;
1020            soapAction = soapAction.substring(1, end);
1021        }
1022
1023        if (soapAction.length() == 0) {
1024            soapAction = req.getContextPath(); // Is this right?
1025

1026        }
1027        return soapAction;
1028    }
1029
1030    /**
1031     * Provided to allow overload of default JWSClassDir
1032     * by derived class.
1033     * @return directory for JWS files
1034     */

1035    protected String JavaDoc getDefaultJWSClassDir() {
1036        return (getWebInfPath() == null)
1037                ? null // ??? what is a good FINAL default for WebLogic?
1038
: getWebInfPath() + File.separator + "jwsClasses";
1039    }
1040
1041    /**
1042     * Initialize a Handler for the transport defined in the Axis server config.
1043     * This includes optionally filling in query string handlers.
1044     */

1045
1046    public void initQueryStringHandlers() {
1047        try {
1048            this.transport = getEngine().getTransport(this.transportName);
1049
1050            if (this.transport == null) {
1051                // No transport by this name is defined. Therefore, fill in default
1052
// query string handlers.
1053

1054                this.transport = new SimpleTargetedChain();
1055
1056                this.transport.setOption("qs.list",
1057                                         "org.apache.axis.transport.http.QSListHandler");
1058                this.transport.setOption("qs.method",
1059                                         "org.apache.axis.transport.http.QSMethodHandler");
1060                this.transport.setOption("qs.wsdl",
1061                                         "org.apache.axis.transport.http.QSWSDLHandler");
1062
1063                return;
1064            }
1065
1066            else {
1067                // See if we should use the default query string handlers.
1068
// By default, set this to true (for backwards compatibility).
1069

1070                boolean defaultQueryStrings = true;
1071                String JavaDoc useDefaults = (String JavaDoc)this.transport.getOption(
1072                        "useDefaultQueryStrings");
1073
1074                if ((useDefaults != null) &&
1075                    useDefaults.toLowerCase().equals("false")) {
1076                    defaultQueryStrings = false;
1077                }
1078
1079                if (defaultQueryStrings == true) {
1080                    // We should use defaults, so fill them in.
1081

1082                    this.transport.setOption("qs.list",
1083                                             "org.apache.axis.transport.http.QSListHandler");
1084                    this.transport.setOption("qs.method",
1085                                             "org.apache.axis.transport.http.QSMethodHandler");
1086                    this.transport.setOption("qs.wsdl",
1087                                             "org.apache.axis.transport.http.QSWSDLHandler");
1088                }
1089            }
1090        }
1091
1092        catch (AxisFault e) {
1093            // Some sort of problem occurred, let's just make a default transport.
1094

1095            this.transport = new SimpleTargetedChain();
1096
1097            this.transport.setOption("qs.list",
1098                                     "org.apache.axis.transport.http.QSListHandler");
1099            this.transport.setOption("qs.method",
1100                                     "org.apache.axis.transport.http.QSMethodHandler");
1101            this.transport.setOption("qs.wsdl",
1102                                     "org.apache.axis.transport.http.QSWSDLHandler");
1103
1104            return;
1105        }
1106    }
1107
1108    /**
1109     * Attempts to invoke a plugin for the query string supplied in the URL.
1110     *
1111     * @param request the servlet's HttpServletRequest object.
1112     * @param response the servlet's HttpServletResponse object.
1113     * @param writer the servlet's PrintWriter object.
1114     */

1115
1116    private boolean processQuery(HttpServletRequest JavaDoc request,
1117                                 HttpServletResponse JavaDoc response,
1118                                 PrintWriter JavaDoc writer) throws AxisFault {
1119        // Attempt to instantiate a plug-in handler class for the query string
1120
// handler classes defined in the HTTP transport.
1121

1122        String JavaDoc path = request.getServletPath();
1123        String JavaDoc queryString = request.getQueryString();
1124        String JavaDoc serviceName;
1125        AxisEngine engine = getEngine();
1126        Iterator JavaDoc i = this.transport.getOptions().keySet().iterator();
1127
1128        if (queryString == null) {
1129            return false;
1130        }
1131
1132        String JavaDoc servletURI = request.getContextPath() + path;
1133        String JavaDoc reqURI = request.getRequestURI();
1134        // chop off '/'.
1135
if (servletURI.length() + 1 < reqURI.length()) {
1136            serviceName = reqURI.substring(servletURI.length() + 1);
1137        } else {
1138            serviceName = "";
1139        } while (i.hasNext() == true) {
1140            String JavaDoc queryHandler = (String JavaDoc) i.next();
1141
1142            if (queryHandler.startsWith("qs.") == true) {
1143                // Only attempt to match the query string with transport
1144
// parameters prefixed with "qs:".
1145

1146                String JavaDoc handlerName = queryHandler.substring
1147                                     (queryHandler.indexOf(".") + 1).
1148                                     toLowerCase();
1149
1150                // Determine the name of the plugin to invoke by using all text
1151
// in the query string up to the first occurence of &, =, or the
1152
// whole string if neither is present.
1153

1154                int length = 0;
1155                boolean firstParamFound = false;
1156
1157                while (firstParamFound == false && length < queryString.length()) {
1158                    char ch = queryString.charAt(length++);
1159
1160                    if (ch == '&' || ch == '=') {
1161                        firstParamFound = true;
1162
1163                        --length;
1164                    }
1165                }
1166
1167                if (length < queryString.length()) {
1168                    queryString = queryString.substring(0, length);
1169                }
1170
1171                if (queryString.toLowerCase().equals(handlerName) == true) {
1172                    // Query string matches a defined query string handler name.
1173

1174                    // If the defined class name for this query string handler is blank,
1175
// just return (the handler is "turned off" in effect).
1176

1177                    if (this.transport.getOption(queryHandler).equals("")) {
1178                        return false;
1179                    }
1180
1181                    try {
1182                        // Attempt to dynamically load the query string handler
1183
// and its "invoke" method.
1184

1185                        MessageContext msgContext = createMessageContext(engine,
1186                                request, response);
1187                        Class JavaDoc plugin = Class.forName((String JavaDoc)this.transport.
1188                                getOption(queryHandler));
1189                        Method JavaDoc pluginMethod = plugin.getDeclaredMethod("invoke",
1190                                new Class JavaDoc[] {msgContext.getClass()});
1191                        String JavaDoc url = HttpUtils.getRequestURL(request).toString();
1192
1193                        // Place various useful servlet-related objects in
1194
// the MessageContext object being delivered to the
1195
// plugin.
1196
msgContext.setProperty(MessageContext.TRANS_URL, url);
1197                        msgContext.setProperty(HTTPConstants.
1198                                               PLUGIN_SERVICE_NAME, serviceName);
1199                        msgContext.setProperty(HTTPConstants.PLUGIN_NAME,
1200                                               handlerName);
1201                        msgContext.setProperty(HTTPConstants.
1202                                               PLUGIN_IS_DEVELOPMENT,
1203                                               new Boolean JavaDoc(isDevelopment()));
1204                        msgContext.setProperty(HTTPConstants.PLUGIN_ENABLE_LIST,
1205                                               new Boolean JavaDoc(enableList));
1206                        msgContext.setProperty(HTTPConstants.PLUGIN_ENGINE,
1207                                               engine);
1208                        msgContext.setProperty(HTTPConstants.PLUGIN_WRITER,
1209                                               writer);
1210                        msgContext.setProperty(HTTPConstants.PLUGIN_LOG, log);
1211                        msgContext.setProperty(HTTPConstants.
1212                                               PLUGIN_EXCEPTION_LOG,
1213                                               exceptionLog);
1214
1215                        // Invoke the plugin.
1216

1217                        pluginMethod.invoke(plugin.newInstance(),
1218                                            new Object JavaDoc[] {msgContext});
1219
1220                        writer.close();
1221
1222                        return true;
1223                    } catch (InvocationTargetException JavaDoc ie) {
1224                        reportTroubleInGet(ie.getTargetException(), response,
1225                                           writer);
1226                        // return true to prevent any further processing
1227
return true;
1228                    } catch (Exception JavaDoc e) {
1229                        reportTroubleInGet(e, response, writer);
1230                        // return true to prevent any further processing
1231
return true;
1232                    }
1233                }
1234            }
1235        }
1236
1237        return false;
1238    }
1239
1240    /**
1241     * getRequestPath a returns request path for web service padded with
1242     * request.getPathInfo for web services served from /services directory.
1243     * This is a required to support serving .jws web services from /services
1244     * URL. See AXIS-843 for more information.
1245     *
1246     * @param request HttpServletRequest
1247     * @return String
1248     */

1249    private static String JavaDoc getRequestPath(HttpServletRequest JavaDoc request) {
1250        return request.getServletPath() + ((request.getPathInfo() != null) ?
1251                                           request.getPathInfo() : "");
1252    }
1253}
1254
Popular Tags