View Javadoc

1   /* 
2    * Copyright (c) 2007, Fraunhofer-Gesellschaft
3    * All rights reserved.
4    * 
5    * Redistribution and use in source and binary forms, with or without
6    * modification, are permitted provided that the following conditions are
7    * met:
8    * 
9    * (1) Redistributions of source code must retain the above copyright
10   *     notice, this list of conditions and the disclaimer at the end.
11   *     Redistributions in binary form must reproduce the above copyright
12   *     notice, this list of conditions and the following disclaimer in
13   *     the documentation and/or other materials provided with the
14   *     distribution.
15   * 
16   * (2) Neither the name of Fraunhofer nor the names of its
17   *     contributors may be used to endorse or promote products derived
18   *     from this software without specific prior written permission.
19   * 
20   * DISCLAIMER
21   * 
22   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23   * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24   * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25   * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26   * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30   * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33   *  
34   */
35  package org.ogf.graap.wsag.wsrf.bootstrap;
36  
37  import java.io.BufferedInputStream;
38  import java.io.BufferedOutputStream;
39  import java.io.IOException;
40  import java.io.OutputStream;
41  import java.io.PrintWriter;
42  import java.util.Arrays;
43  import java.util.HashSet;
44  import java.util.Map;
45  import java.util.Set;
46  import java.util.concurrent.CountDownLatch;
47  
48  import javax.servlet.ServletConfig;
49  import javax.servlet.ServletContext;
50  import javax.servlet.ServletException;
51  import javax.servlet.http.HttpServlet;
52  import javax.servlet.http.HttpServletRequest;
53  import javax.servlet.http.HttpServletResponse;
54  import javax.xml.namespace.QName;
55  
56  import org.apache.axiom.om.OMElement;
57  import org.apache.axiom.om.impl.builder.StAXBuilder;
58  import org.apache.axiom.soap.SOAP12Constants;
59  import org.apache.axiom.soap.SOAPEnvelope;
60  import org.apache.axiom.soap.SOAPFaultCode;
61  import org.apache.axis2.AxisFault;
62  import org.apache.axis2.Constants;
63  import org.apache.axis2.addressing.AddressingHelper;
64  import org.apache.axis2.addressing.EndpointReference;
65  import org.apache.axis2.context.ConfigurationContext;
66  import org.apache.axis2.context.ConfigurationContextFactory;
67  import org.apache.axis2.context.MessageContext;
68  import org.apache.axis2.deployment.WarBasedAxisConfigurator;
69  import org.apache.axis2.description.AxisBindingMessage;
70  import org.apache.axis2.description.AxisBindingOperation;
71  import org.apache.axis2.description.Parameter;
72  import org.apache.axis2.description.TransportInDescription;
73  import org.apache.axis2.description.TransportOutDescription;
74  import org.apache.axis2.description.WSDL2Constants;
75  import org.apache.axis2.engine.AxisConfiguration;
76  import org.apache.axis2.engine.AxisEngine;
77  import org.apache.axis2.engine.Handler.InvocationResponse;
78  import org.apache.axis2.engine.ListenerManager;
79  import org.apache.axis2.transport.RequestResponseTransport;
80  import org.apache.axis2.transport.TransportListener;
81  import org.apache.axis2.transport.TransportUtils;
82  import org.apache.axis2.transport.http.AxisServletListener;
83  import org.apache.axis2.transport.http.HTTPConstants;
84  import org.apache.axis2.transport.http.HTTPTransportUtils;
85  import org.apache.axis2.transport.http.ListingAgent;
86  import org.apache.axis2.transport.http.ServletBasedOutTransportInfo;
87  import org.apache.axis2.transport.http.TransportHeaders;
88  import org.apache.axis2.transport.http.util.QueryStringParser;
89  import org.apache.axis2.transport.http.util.RESTUtil;
90  import org.apache.axis2.util.JavaUtils;
91  import org.apache.axis2.util.MessageContextBuilder;
92  import org.apache.log4j.Logger;
93  
94  /**
95   * This is essentially a copy of the Axis2 Servlet. It includes a patch in the initialization method to
96   * prevent the registration of a shutdown hook by the ListenerManager ({@link #init(ServletConfig)}), which
97   * causes a memory leak when re-deploying in tomcat.
98   * 
99   * When upgrading to a new version, this file MUST be upgraded too. (probably the shutdown hook can be
100  * prevented in future by configuration)
101  * 
102  * @author Oliver Waeldrich
103  * 
104  */
105 // CHECKSTYLE:OFF
106 @SuppressWarnings( "serial" )
107 public class Bootstrap extends HttpServlet
108 {
109 
110     private static final Logger LOG = Logger.getLogger( Bootstrap.class );
111 
112     /**
113      * Configuration Context
114      */
115     public static final String CONFIGURATION_CONTEXT = "CONFIGURATION_CONTEXT";
116 
117     /**
118      * Session ID
119      */
120     public static final String SESSION_ID = "SessionId";
121 
122     private static final Set<String> METADATA_QUERY_PARAM_NAMES =
123         new HashSet<String>( Arrays.asList( "wsdl2", "wsdl", "xsd", "policy" ) );
124 
125     /**
126      * Configuration Context
127      */
128     protected transient ConfigurationContext configContext;
129 
130     /**
131      * Axis Configuration
132      */
133     protected transient AxisConfiguration axisConfiguration;
134 
135     /**
136      * Servlet Configuration
137      */
138     protected transient ServletConfig servletConfig;
139 
140     /**
141      * The Listing Agent.
142      */
143     protected transient ListingAgent agent;
144 
145     /**
146      * Context Root.
147      */
148     protected transient String contextRoot = null;
149 
150     /**
151      * disable REST
152      */
153     protected boolean disableREST = false;
154 
155     private static final String LIST_SERVICES_SUFFIX = "/services/listServices";
156 
157     private static final String LIST_FAULTY_SERVICES_SUFFIX = "/services/ListFaultyServices";
158 
159     private boolean closeReader = true;
160 
161     private static final int BUFFER_SIZE = 1024 * 8;
162 
163     private boolean initCalled = false;
164 
165     private transient AxisServletListener httpListener;
166 
167     private transient AxisServletListener httpsListener;
168 
169     /**
170      * Implementation of POST interface
171      * 
172      * @param request
173      *            the request
174      * @param response
175      *            the response
176      * @throws ServletException
177      *             an servlet error
178      * @throws IOException
179      *             an i/o error
180      */
181     @SuppressWarnings( "unused" )
182     protected void doPost( HttpServletRequest request, HttpServletResponse response )
183         throws ServletException, IOException
184     {
185 
186         LOG.trace( "entering axis servlet post call" );
187 
188         // set the initial buffer for a larger value
189         response.setBufferSize( BUFFER_SIZE );
190 
191         preprocessRequest( request );
192 
193         MessageContext msgContext;
194         OutputStream out = response.getOutputStream();
195         String contentType = request.getContentType();
196         if ( !HTTPTransportUtils.isRESTRequest( contentType ) )
197         {
198             msgContext = createMessageContext( request, response );
199             msgContext.setProperty( Constants.Configuration.CONTENT_TYPE, contentType );
200             try
201             {
202                 // adding ServletContext into msgContext;
203                 String url = request.getRequestURL().toString();
204 
205                 OutputStream bufferedOut = new BufferedOutputStream( out );
206 
207                 InvocationResponse pi =
208                     HTTPTransportUtils.processHTTPPostRequest( msgContext,
209                                                                new BufferedInputStream(
210                                                                                         request.getInputStream() ),
211                                                                bufferedOut,
212                                                                contentType,
213                                                                request.getHeader( HTTPConstants.HEADER_SOAP_ACTION ),
214                                                                url );
215 
216                 Boolean holdResponse =
217                     (Boolean) msgContext.getProperty( RequestResponseTransport.HOLD_RESPONSE );
218 
219                 RequestResponseTransport transport =
220                     (RequestResponseTransport) msgContext.getProperty( RequestResponseTransport.TRANSPORT_CONTROL );
221 
222                 if ( pi.equals( InvocationResponse.SUSPEND )
223                     || ( holdResponse != null && Boolean.TRUE.equals( holdResponse ) ) )
224                 {
225                     transport.awaitResponse();
226                 }
227                 response.setContentType( "text/xml; charset="
228                     + msgContext.getProperty( Constants.Configuration.CHARACTER_SET_ENCODING ) );
229                 // if data has not been sent back and this is not a signal response
230                 if ( !TransportUtils.isResponseWritten( msgContext )
231                     && ( transport.getStatus() != RequestResponseTransport.RequestResponseTransportStatus.SIGNALLED ) )
232                 {
233                     response.setStatus( HttpServletResponse.SC_ACCEPTED );
234                 }
235 
236                 // Make sure that no data remains in the BufferedOutputStream even if the message
237                 // formatter doesn't call flush
238                 bufferedOut.flush();
239 
240             }
241             catch ( AxisFault e )
242             {
243                 setResponseState( msgContext, response );
244                 LOG.debug( "catch axis fault", e );
245                 if ( msgContext != null )
246                 {
247                     processAxisFault( msgContext, response, out, e );
248                 }
249                 else
250                 {
251                     throw new ServletException( e );
252                 }
253             }
254             catch ( Throwable t )
255             {
256                 LOG.error( t.getMessage(), t );
257                 try
258                 {
259                     // If the fault is not going along the back channel we should be 202ing
260                     if ( AddressingHelper.isFaultRedirected( msgContext ) )
261                     {
262                         response.setStatus( HttpServletResponse.SC_ACCEPTED );
263                     }
264                     else
265                     {
266                         response.setStatus( HttpServletResponse.SC_INTERNAL_SERVER_ERROR );
267 
268                         AxisBindingOperation axisBindingOperation =
269                             (AxisBindingOperation) msgContext.getProperty( Constants.AXIS_BINDING_OPERATION );
270                         if ( axisBindingOperation != null )
271                         {
272                             String faultName = (String) msgContext.getProperty( Constants.FAULT_NAME );
273                             AxisBindingMessage axisBindingMessage = axisBindingOperation.getFault( faultName );
274                             if ( axisBindingMessage != null )
275                             {
276                                 Integer code =
277                                     (Integer) axisBindingMessage.getProperty( WSDL2Constants.ATTR_WHTTP_CODE );
278                                 if ( code != null )
279                                 {
280                                     response.setStatus( code.intValue() );
281                                 }
282                             }
283                         }
284                     }
285                     handleFault( msgContext, out, new AxisFault( t.toString(), t ) );
286                 }
287                 catch ( AxisFault e2 )
288                 {
289                     LOG.info( e2 );
290                     throw new ServletException( e2 );
291                 }
292             }
293             finally
294             {
295                 LOG.trace( "leaving axis servlet post call" );
296 
297                 closeStaxBuilder( msgContext );
298                 TransportUtils.deleteAttachments( msgContext );
299             }
300         }
301         else
302         {
303             if ( !disableREST )
304             {
305                 RestRequestProcessor processor =
306                     new RestRequestProcessor( Constants.Configuration.HTTP_METHOD_POST, request, response );
307                 processor.processXMLRequest();
308             }
309             else
310             {
311                 showRestDisabledErrorMessage( response );
312             }
313         }
314     }
315 
316     /**
317      * Implementation for GET interface
318      * 
319      * @param request
320      *            the request
321      * @param response
322      *            the response
323      * @throws ServletException
324      *             an servlet error
325      * @throws IOException
326      *             an i/o error
327      */
328 
329     protected void doGet( HttpServletRequest request, HttpServletResponse response )
330         throws ServletException, IOException
331     {
332 
333         preprocessRequest( request );
334 
335         // this method is also used to serve for the listServices request.
336 
337         String requestURI = request.getRequestURI();
338         String query = request.getQueryString();
339 
340         // There can be three different request coming to this.
341         // 1. wsdl, wsdl2 and xsd requests
342         // 2. list services requests
343         // 3. REST requests.
344         if ( ( query != null ) && new QueryStringParser( query ).search( METADATA_QUERY_PARAM_NAMES ) )
345         {
346             // handling meta data exchange stuff
347             agent.processListService( request, response );
348         }
349         else if ( requestURI.endsWith( ".xsd" ) || requestURI.endsWith( ".wsdl" ) )
350         {
351             agent.processExplicitSchemaAndWSDL( request, response );
352         }
353         else if ( requestURI.endsWith( LIST_SERVICES_SUFFIX )
354             || requestURI.endsWith( LIST_FAULTY_SERVICES_SUFFIX ) )
355         {
356             // handling list services request
357             try
358             {
359                 agent.handle( request, response );
360             }
361             catch ( Exception e )
362             {
363                 throw new ServletException( e );
364             }
365         }
366         else if ( !disableREST )
367         {
368             new RestRequestProcessor( Constants.Configuration.HTTP_METHOD_GET, request, response ).processURLRequest();
369         }
370         else
371         {
372             showRestDisabledErrorMessage( response );
373         }
374     }
375 
376     /**
377      * Implementation of DELETE interface
378      * 
379      * @param request
380      *            the request
381      * @param response
382      *            the response
383      * @throws ServletException
384      *             servlet error
385      * @throws IOException
386      *             I/O error
387      */
388 
389     protected void doDelete( HttpServletRequest request, HttpServletResponse response )
390         throws ServletException, IOException
391     {
392 
393         preprocessRequest( request );
394         // this method is also used to serve for the listServices request.
395         if ( !disableREST )
396         {
397             RestRequestProcessor processor =
398                 new RestRequestProcessor( Constants.Configuration.HTTP_METHOD_DELETE, request, response );
399             processor.processURLRequest();
400         }
401         else
402         {
403             showRestDisabledErrorMessage( response );
404         }
405     }
406 
407     /**
408      * Implementation of PUT interface
409      * 
410      * @param request
411      *            the request
412      * @param response
413      *            the response
414      * @throws ServletException
415      *             an servlet error
416      * @throws IOException
417      *             an i/o error
418      */
419     protected void doPut( HttpServletRequest request, HttpServletResponse response )
420         throws ServletException, IOException
421     {
422 
423         preprocessRequest( request );
424         // this method is also used to serve for the listServices request.
425         if ( !disableREST )
426         {
427             new RestRequestProcessor( Constants.Configuration.HTTP_METHOD_PUT, request, response ).processXMLRequest();
428         }
429         else
430         {
431             showRestDisabledErrorMessage( response );
432         }
433     }
434 
435     /**
436      * Private method that deals with disabling of REST support.
437      * 
438      * @param response
439      *            the response
440      * @throws IOException
441      *             i/o exception
442      */
443     protected void showRestDisabledErrorMessage( HttpServletResponse response ) throws IOException
444     {
445         PrintWriter writer = new PrintWriter( response.getOutputStream() );
446         writer.println( "<html><body><h2>Please enable REST support in WEB-INF/conf/axis2.xml "
447             + "and WEB-INF/web.xml</h2></body></html>" );
448         writer.flush();
449         response.setStatus( HttpServletResponse.SC_ACCEPTED );
450     }
451 
452     /**
453      * Close the builders.
454      * 
455      * @param messageContext
456      * @throws ServletException
457      */
458     private void closeStaxBuilder( MessageContext messageContext ) throws ServletException
459     {
460         if ( closeReader && messageContext != null )
461         {
462             try
463             {
464                 SOAPEnvelope envelope = messageContext.getEnvelope();
465                 if ( envelope != null )
466                 {
467                     StAXBuilder builder = (StAXBuilder) envelope.getBuilder();
468                     if ( builder != null )
469                     {
470                         builder.close();
471                     }
472                 }
473             }
474             catch ( Exception e )
475             {
476                 LOG.debug( e.toString(), e );
477             }
478         }
479     }
480 
481     /**
482      * Processing for faults
483      * 
484      * @param msgContext
485      * @param res
486      * @param out
487      * @param e
488      */
489     private void processAxisFault( MessageContext msgContext, HttpServletResponse res, OutputStream out,
490                                    AxisFault e )
491     {
492         try
493         {
494             // If the fault is not going along the back channel we should be 202ing
495             if ( AddressingHelper.isFaultRedirected( msgContext ) )
496             {
497                 res.setStatus( HttpServletResponse.SC_ACCEPTED );
498             }
499             else
500             {
501 
502                 String status = (String) msgContext.getProperty( Constants.HTTP_RESPONSE_STATE );
503                 if ( status == null )
504                 {
505                     res.setStatus( HttpServletResponse.SC_INTERNAL_SERVER_ERROR );
506                 }
507                 else
508                 {
509                     res.setStatus( Integer.parseInt( status ) );
510                 }
511 
512                 AxisBindingOperation axisBindingOperation =
513                     (AxisBindingOperation) msgContext.getProperty( Constants.AXIS_BINDING_OPERATION );
514                 if ( axisBindingOperation != null )
515                 {
516                     AxisBindingMessage fault =
517                         axisBindingOperation.getFault( (String) msgContext.getProperty( Constants.FAULT_NAME ) );
518                     if ( fault != null )
519                     {
520                         Integer code = (Integer) fault.getProperty( WSDL2Constants.ATTR_WHTTP_CODE );
521                         if ( code != null )
522                         {
523                             res.setStatus( code.intValue() );
524                         }
525                     }
526                 }
527             }
528             handleFault( msgContext, out, e );
529         }
530         catch ( AxisFault e2 )
531         {
532             LOG.info( e2 );
533         }
534     }
535 
536     /**
537      * 
538      * @param msgContext
539      *            the message context
540      * @param out
541      *            the response output stream
542      * @param e
543      *            the fault
544      * @throws AxisFault
545      *             AXIS fault
546      */
547     protected void handleFault( MessageContext msgContext, OutputStream out, AxisFault e ) throws AxisFault
548     {
549         msgContext.setProperty( MessageContext.TRANSPORT_OUT, out );
550 
551         MessageContext faultContext = MessageContextBuilder.createFaultMessageContext( msgContext, e );
552         // SOAP 1.2 specification mentions that we should send HTTP code 400 in a fault if the
553         // fault code Sender
554         HttpServletResponse response =
555             (HttpServletResponse) msgContext.getProperty( HTTPConstants.MC_HTTP_SERVLETRESPONSE );
556         if ( response != null )
557         {
558 
559             // TODO : Check for SOAP 1.2!
560             SOAPFaultCode code = faultContext.getEnvelope().getBody().getFault().getCode();
561 
562             OMElement valueElement = null;
563             if ( code != null )
564             {
565                 valueElement =
566                     code.getFirstChildWithName( new QName( SOAP12Constants.SOAP_ENVELOPE_NAMESPACE_URI,
567                                                            SOAP12Constants.SOAP_FAULT_VALUE_LOCAL_NAME ) );
568             }
569 
570             if ( valueElement != null )
571             {
572                 if ( SOAP12Constants.FAULT_CODE_SENDER.equals( valueElement.getTextAsQName().getLocalPart() )
573                     && !msgContext.isDoingREST() )
574                 {
575                     response.setStatus( HttpServletResponse.SC_BAD_REQUEST );
576                 }
577             }
578         }
579 
580         AxisEngine.sendFault( faultContext );
581     }
582 
583     /**
584      * Main init method
585      * 
586      * @param config
587      *            the servlet config
588      * @throws ServletException
589      *             servlet exception
590      */
591     public void init( ServletConfig config ) throws ServletException
592     {
593 
594         // prevent this method from being called more than once per instance
595         initCalled = true;
596         super.init( config );
597         try
598         {
599             this.servletConfig = config;
600             ServletContext servletContext = servletConfig.getServletContext();
601             this.configContext = (ConfigurationContext) servletContext.getAttribute( CONFIGURATION_CONTEXT );
602             if ( configContext == null )
603             {
604                 configContext = initConfigContext( config );
605                 config.getServletContext().setAttribute( CONFIGURATION_CONTEXT, configContext );
606             }
607             axisConfiguration = configContext.getAxisConfiguration();
608 
609             httpListener = getAxisServletListener( Constants.TRANSPORT_HTTP );
610             httpsListener = getAxisServletListener( Constants.TRANSPORT_HTTPS );
611 
612             if ( httpListener == null && httpsListener == null )
613             {
614                 LOG.warn( "No transportReceiver for " + AxisServletListener.class.getName()
615                     + " found. An instance for HTTP will be configured automatically. "
616                     + "Please update your axis2.xml file!" );
617                 httpListener = new AxisServletListener();
618                 TransportInDescription transportInDescription =
619                     new TransportInDescription( Constants.TRANSPORT_HTTP );
620                 transportInDescription.setReceiver( httpListener );
621                 axisConfiguration.addTransportIn( transportInDescription );
622             }
623             else if ( httpListener != null && httpsListener != null && httpListener.getPort() == -1
624                 && httpsListener.getPort() == -1 )
625             {
626                 LOG.warn( "If more than one transportReceiver for " + AxisServletListener.class.getName()
627                     + " exists, then all instances "
628                     + "must be configured with a port number. WSDL generation will be " + "unreliable." );
629             }
630 
631             ListenerManager listenerManager = new ListenerManager();
632             listenerManager.init( configContext );
633             //
634             // wsag4j fix
635             //
636             listenerManager.setShutdownHookRequired( false );
637             listenerManager.start();
638             ListenerManager.defaultConfigurationContext = configContext;
639             agent = new ListingAgent( configContext );
640 
641             initParams();
642 
643         }
644         catch ( Exception e )
645         {
646             throw new ServletException( e );
647         }
648     }
649 
650     private AxisServletListener getAxisServletListener( String name )
651     {
652         TransportInDescription desc = axisConfiguration.getTransportIn( name );
653         if ( desc == null )
654         {
655             return null;
656         }
657         TransportListener receiver = desc.getReceiver();
658         if ( receiver instanceof AxisServletListener )
659         {
660             return (AxisServletListener) receiver;
661         }
662         else
663         {
664             return null;
665         }
666     }
667 
668     /**
669      * distroy the ConfigurationContext
670      */
671     public void destroy()
672     {
673         // stoping listner manager
674         try
675         {
676             if ( configContext != null )
677             {
678                 configContext.terminate();
679             }
680         }
681         catch ( AxisFault axisFault )
682         {
683             LOG.info( axisFault.getMessage() );
684         }
685         try
686         {
687             super.destroy();
688         }
689         catch ( Exception e )
690         {
691             LOG.info( e.getMessage() );
692         }
693 
694         axisConfiguration = null;
695     }
696 
697     /**
698      * Initializes the Axis2 parameters.
699      */
700     protected void initParams()
701     {
702         Parameter parameter;
703         // do we need to completely disable REST support
704         parameter = axisConfiguration.getParameter( Constants.Configuration.DISABLE_REST );
705         if ( parameter != null )
706         {
707             disableREST = !JavaUtils.isFalseExplicitly( parameter.getValue() );
708         }
709 
710         // Should we close the reader(s)
711         parameter = axisConfiguration.getParameter( "axis2.close.reader" );
712         if ( parameter != null )
713         {
714             closeReader = JavaUtils.isTrueExplicitly( parameter.getValue() );
715         }
716 
717     }
718 
719     /**
720      * Convenient method to re-initialize the ConfigurationContext
721      * 
722      * @throws ServletException
723      *             the error
724      */
725     public void init() throws ServletException
726     {
727         if ( this.servletConfig != null && !initCalled )
728         {
729             init( this.servletConfig );
730         }
731     }
732 
733     /**
734      * Initialize the Axis configuration context
735      * 
736      * @param config
737      *            Servlet configuration
738      * @return ConfigurationContext the configuration context
739      * 
740      * @throws ServletException
741      *             a servlet exception
742      */
743     protected ConfigurationContext initConfigContext( ServletConfig config ) throws ServletException
744     {
745         try
746         {
747             ConfigurationContext configCtx =
748                 ConfigurationContextFactory.createConfigurationContext( new WarBasedAxisConfigurator( config ) );
749             configCtx.setProperty( Constants.CONTAINER_MANAGED, Constants.VALUE_TRUE );
750             return configCtx;
751         }
752         catch ( Exception e )
753         {
754             LOG.info( e );
755             throw new ServletException( e );
756         }
757     }
758 
759     /**
760      * Set the context root if it is not set already.
761      * 
762      * @param req
763      *            the request
764      */
765     public void initContextRoot( HttpServletRequest req )
766     {
767         if ( contextRoot != null && contextRoot.trim().length() != 0 )
768         {
769             return;
770         }
771         String contextPath = req.getContextPath();
772         // handling ROOT scenario, for servlets in the default (root) context, this method returns ""
773         if ( contextPath != null && contextPath.length() == 0 )
774         {
775             contextPath = "/";
776         }
777         this.contextRoot = contextPath;
778 
779         configContext.setContextRoot( contextRoot );
780     }
781 
782     /**
783      * Preprocess the request. This will:
784      * <ul>
785      * <li>Set the context root if it is not set already (by calling
786      * {@link #initContextRoot(HttpServletRequest)}).
787      * <li>Remember the port number if port autodetection is enabled.
788      * <li>Reject the request if no {@link AxisServletListener} has been registered for the protocol.
789      * </ul>
790      * 
791      * @param req
792      *            the request to preprocess
793      */
794     // This method should not be part of the public API. In particular we must not allow subclasses
795     // to override this method because we don't make any guarantees as to when exactly this method
796     // is called.
797     private void preprocessRequest( HttpServletRequest req ) throws ServletException
798     {
799         initContextRoot( req );
800 
801         TransportInDescription transportInDescription =
802             req.isSecure() ? this.axisConfiguration.getTransportIn( Constants.TRANSPORT_HTTPS )
803                             : this.axisConfiguration.getTransportIn( Constants.TRANSPORT_HTTP );
804 
805         if ( transportInDescription == null )
806         {
807             throw new ServletException( req.getScheme() + " is forbidden" );
808         }
809         else
810         {
811             if ( transportInDescription.getReceiver() instanceof AxisServletListener )
812             {
813                 AxisServletListener listner = (AxisServletListener) transportInDescription.getReceiver();
814                 // Autodetect the port number if necessary
815                 if ( listner.getPort() == -1 )
816                 {
817                     listner.setPort( req.getServerPort() );
818                 }
819             }
820         }
821 
822     }
823 
824     /**
825      * Get all transport headers.
826      * 
827      * @param req
828      *            the request
829      * @return Map the transport headers
830      */
831     protected Map<?, ?> getTransportHeaders( HttpServletRequest req )
832     {
833         return new TransportHeaders( req );
834     }
835 
836     /**
837      * @param request
838      *            the request
839      * @param response
840      *            the response
841      * @param invocationType
842      *            If invocationType=true; then this will be used in SOAP message invocation. If
843      *            invocationType=false; then this will be used in REST message invocation.
844      * @return MessageContext the message context
845      * 
846      * @throws IOException
847      *             IO error
848      */
849     protected MessageContext createMessageContext( HttpServletRequest request, HttpServletResponse response,
850                                                    boolean invocationType ) throws IOException
851     {
852         MessageContext msgContext = configContext.createMessageContext();
853         String requestURI = request.getRequestURI();
854 
855         String trsPrefix = request.getRequestURL().toString();
856         int sepindex = trsPrefix.indexOf( ':' );
857         if ( sepindex > -1 )
858         {
859             trsPrefix = trsPrefix.substring( 0, sepindex );
860             msgContext.setIncomingTransportName( trsPrefix );
861         }
862         else
863         {
864             msgContext.setIncomingTransportName( Constants.TRANSPORT_HTTP );
865             trsPrefix = Constants.TRANSPORT_HTTP;
866         }
867         TransportInDescription transportIn =
868             axisConfiguration.getTransportIn( msgContext.getIncomingTransportName() );
869         // set the default output description. This will be http
870 
871         TransportOutDescription transportOut = axisConfiguration.getTransportOut( trsPrefix );
872         if ( transportOut == null )
873         {
874             // if the req coming via https but we do not have a https sender
875             transportOut = axisConfiguration.getTransportOut( Constants.TRANSPORT_HTTP );
876         }
877 
878         msgContext.setTransportIn( transportIn );
879         msgContext.setTransportOut( transportOut );
880         msgContext.setServerSide( true );
881 
882         if ( !invocationType )
883         {
884             String query = request.getQueryString();
885             if ( query != null )
886             {
887                 requestURI = requestURI + "?" + query;
888             }
889         }
890 
891         msgContext.setTo( new EndpointReference( requestURI ) );
892         msgContext.setFrom( new EndpointReference( request.getRemoteAddr() ) );
893         msgContext.setProperty( MessageContext.REMOTE_ADDR, request.getRemoteAddr() );
894         msgContext.setProperty( Constants.OUT_TRANSPORT_INFO, new ServletBasedOutTransportInfo( response ) );
895         // set the transport Headers
896         msgContext.setProperty( MessageContext.TRANSPORT_HEADERS, getTransportHeaders( request ) );
897         msgContext.setProperty( HTTPConstants.MC_HTTP_SERVLETREQUEST, request );
898         msgContext.setProperty( HTTPConstants.MC_HTTP_SERVLETRESPONSE, response );
899         try
900         {
901             ServletContext context = getServletContext();
902             if ( context != null )
903             {
904                 msgContext.setProperty( HTTPConstants.MC_HTTP_SERVLETCONTEXT, context );
905             }
906         }
907         catch ( Exception e )
908         {
909             LOG.debug( e.getMessage(), e );
910         }
911 
912         // setting the RequestResponseTransport object
913         msgContext.setProperty( RequestResponseTransport.TRANSPORT_CONTROL,
914                                 new ServletRequestResponseTransport( response ) );
915 
916         return msgContext;
917     }
918 
919     /**
920      * This method assumes, that the created MessageContext will be used in only SOAP invocation.
921      * 
922      * @param req
923      *            the request
924      * @param resp
925      *            the response
926      * @return MessageContext the message context
927      * 
928      * @throws IOException
929      *             an IO error
930      */
931 
932     protected MessageContext createMessageContext( HttpServletRequest req, HttpServletResponse resp )
933         throws IOException
934     {
935         return createMessageContext( req, resp, true );
936     }
937 
938     /**
939      * 
940      * 
941      */
942     protected class ServletRequestResponseTransport implements RequestResponseTransport
943     {
944         @SuppressWarnings( "unused" )
945         private HttpServletResponse response;
946 
947         private boolean responseWritten = false;
948 
949         private CountDownLatch responseReadySignal = new CountDownLatch( 1 );
950 
951         // The initial status must be WAITING, as the main servlet will do some other
952         // work after setting this RequestResponseTransport up, and we don't want to miss
953         // signals that come in before this thread gets to the awaitResponse call.
954         private RequestResponseTransportStatus status = RequestResponseTransportStatus.WAITING;
955 
956         AxisFault faultToBeThrownOut = null;
957 
958         ServletRequestResponseTransport( HttpServletResponse response )
959         {
960             this.response = response;
961         }
962 
963         /**
964          * {@inheritDoc}
965          */
966         public void acknowledgeMessage( MessageContext msgContext ) throws AxisFault
967         {
968             status = RequestResponseTransportStatus.ACKED;
969             responseReadySignal.countDown();
970         }
971 
972         /**
973          * {@inheritDoc}
974          */
975         public void awaitResponse() throws InterruptedException, AxisFault
976         {
977             LOG.debug( "Blocking servlet thread -- awaiting response" );
978             responseReadySignal.await();
979 
980             if ( faultToBeThrownOut != null )
981             {
982                 throw faultToBeThrownOut;
983             }
984         }
985 
986         /**
987          * 
988          */
989         public void signalResponseReady()
990         {
991             LOG.debug( "Signalling response available" );
992             status = RequestResponseTransportStatus.SIGNALLED;
993             responseReadySignal.countDown();
994         }
995 
996         /**
997          * @return the status
998          */
999         public RequestResponseTransportStatus getStatus()
1000         {
1001             return status;
1002         }
1003 
1004         /**
1005          * @param fault
1006          *            the Axis fault
1007          */
1008         public void signalFaultReady( AxisFault fault )
1009         {
1010             faultToBeThrownOut = fault;
1011             signalResponseReady();
1012         }
1013 
1014         /**
1015          * @return response written
1016          */
1017         public boolean isResponseWritten()
1018         {
1019             return responseWritten;
1020         }
1021 
1022         /**
1023          * @param responseWritten
1024          *            the response written to set
1025          */
1026         public void setResponseWritten( boolean responseWritten )
1027         {
1028             this.responseWritten = responseWritten;
1029         }
1030 
1031     }
1032 
1033     private void setResponseState( MessageContext messageContext, HttpServletResponse response )
1034     {
1035         String state = (String) messageContext.getProperty( Constants.HTTP_RESPONSE_STATE );
1036         if ( state != null )
1037         {
1038             int stateInt = Integer.parseInt( state );
1039             if ( stateInt == HttpServletResponse.SC_UNAUTHORIZED )
1040             { // Unauthorized
1041                 String realm = (String) messageContext.getProperty( Constants.HTTP_BASIC_AUTH_REALM );
1042                 response.addHeader( "WWW-Authenticate", "basic realm=\"" + realm + "\"" );
1043             }
1044         }
1045     }
1046 
1047     /**
1048      * Ues in processing REST related Requests. This is the helper Class use in processing of doGet, doPut ,
1049      * doDelete and doPost.
1050      */
1051     protected class RestRequestProcessor
1052     { 
1053         /**
1054          * Message Context 
1055          */
1056         protected MessageContext messageContext;
1057 
1058         private HttpServletRequest request;
1059 
1060         private HttpServletResponse response;
1061 
1062         /**
1063          * 
1064          * @param httpMethodString
1065          *            the HTTP method
1066          * @param request
1067          *            the request
1068          * @param response
1069          *            the response
1070          * 
1071          * @throws IOException
1072          *             IOException
1073          */
1074         public RestRequestProcessor( String httpMethodString, HttpServletRequest request,
1075                                      HttpServletResponse response )
1076             throws IOException
1077         {
1078             this.request = request;
1079             this.response = response;
1080             messageContext = createMessageContext( this.request, this.response, false );
1081             messageContext.setProperty( org.apache.axis2.transport.http.HTTPConstants.HTTP_METHOD,
1082                                         httpMethodString );
1083         }
1084 
1085         /**
1086          * 
1087          * @throws IOException
1088          *             IOException
1089          * @throws ServletException
1090          *             ServletException
1091          */
1092         public void processXMLRequest() throws IOException, ServletException
1093         {
1094             try
1095             {
1096                 RESTUtil.processXMLRequest( messageContext, request.getInputStream(),
1097                                             response.getOutputStream(), request.getContentType() );
1098                 this.checkResponseWritten();
1099             }
1100             catch ( AxisFault axisFault )
1101             {
1102                 processFault( axisFault );
1103             }
1104             closeStaxBuilder( messageContext );
1105         }
1106 
1107         /**
1108          * 
1109          * @throws IOException
1110          *             IOException
1111          * @throws ServletException
1112          *             ServletException
1113          */
1114         public void processURLRequest() throws IOException, ServletException
1115         {
1116             try
1117             {
1118                 RESTUtil.processURLRequest( messageContext, response.getOutputStream(),
1119                                             request.getContentType() );
1120                 this.checkResponseWritten();
1121             }
1122             catch ( AxisFault e )
1123             {
1124                 setResponseState( messageContext, response );
1125                 processFault( e );
1126             }
1127             closeStaxBuilder( messageContext );
1128 
1129         }
1130 
1131         private void checkResponseWritten()
1132         {
1133             if ( !TransportUtils.isResponseWritten( messageContext ) )
1134             {
1135                 response.setStatus( HttpServletResponse.SC_ACCEPTED );
1136             }
1137         }
1138 
1139         private void processFault( AxisFault e ) throws ServletException, IOException
1140         {
1141             LOG.debug( e );
1142             if ( messageContext != null )
1143             {
1144                 processAxisFault( messageContext, response, response.getOutputStream(), e );
1145             }
1146             else
1147             {
1148                 throw new ServletException( e );
1149             }
1150 
1151         }
1152 
1153     }
1154 
1155     // private static final Logger log = Logger.getLogger(Bootstrap.class);
1156     //
1157     // private static final long serialVersionUID = 1L;
1158     //
1159     // private BootstrapIsolationLayer isolationLayer;
1160     //
1161     // /* (non-Javadoc)
1162     // * @see org.apache.axis2.transport.http.AxisServlet#init()
1163     // */
1164     // public void init(ServletConfig config) throws ServletException {
1165     // super.init(config);
1166     // // try {
1167     // // //
1168     // // // get the real path for bootstraping configuration files, etc.
1169     // // //
1170     // // ServletContext context = config.getServletContext();
1171     // // String path = context.getRealPath("/");
1172     // // String defaultGatewayURI = getDefaultGatewayURI(context);
1173     // // String datapath = path + "/WEB-INF/wsag4j-data";
1174     // //
1175     // // if (!System.getProperties().containsKey(EmfRegistry.WSAG4J_DATAPATH)) {
1176     // // System.getProperties().setProperty(EmfRegistry.WSAG4J_DATAPATH, datapath);
1177     // // }
1178     // //
1179     // // //
1180     // // // create and initialize the isolation layer
1181     // // //
1182     // // isolationLayer = new BootstrapIsolationLayer(path, defaultGatewayURI);
1183     // // isolationLayer.initialize();
1184     // //
1185     // // }
1186     // // catch (Exception e) {
1187     // // String message = "WSAG4J initialization process failed. Error: " + e.getMessage();
1188     // // log.error(message);
1189     // //
1190     // // throw new ServletException(message, e);
1191     // // }
1192     // }
1193     //
1194     // public void destroy() {
1195     // // log.info("shutdown WSAG4J service");
1196     // //
1197     // // try {
1198     // // isolationLayer.shutdown();
1199     // // isolationLayer = null;
1200     // // }
1201     // // catch(Exception e) {
1202     // // String message = "WSAG4J shutdown process failed. Error: " + e.getMessage();
1203     // // log.error(message);
1204     // // }
1205     // //
1206     // // BootstrapRegistry.finalizeBootstrapRegistry();
1207     // //
1208     // // DatabaseManager.getTimer().shutDown();
1209     // //
1210     // // Introspector.flushCaches();
1211     // // for (Enumeration<Driver> e = DriverManager.getDrivers(); e.hasMoreElements();) {
1212     // // Driver driver = e.nextElement();
1213     // // if (driver.getClass().getClassLoader() == getClass().getClassLoader()) {
1214     // // try {
1215     // // DriverManager.deregisterDriver(driver);
1216     // // }
1217     // // catch (Exception ex) {
1218     // // log.warn("failed to deregister driver.", ex);
1219     // // }
1220     // // }
1221     // // }
1222     // //
1223     // // delegate destroy call
1224     // super.destroy();
1225     //
1226     // axisConfiguration = null;
1227     // //
1228     // // log.info("shutdown of WSAG4J service completed");
1229     // }
1230     //
1231     // // protected String getDefaultGatewayURI(ServletContext context) throws Exception {
1232     // // String contextPath = context.getResource("/").getPath();
1233     // // contextPath = contextPath.substring(0, contextPath.lastIndexOf("/"));
1234     // // contextPath = contextPath.substring(contextPath.lastIndexOf("/") + 1);
1235     // //
1236     // // String host = InetAddress.getLocalHost().getHostAddress();
1237     // // ConfigurationContext axisContext =
1238     // (ConfigurationContext)context.getAttribute(CONFIGURATION_CONTEXT);
1239     // //
1240     // // // Try to resolve the running port via the Axis2 configuration.
1241     // // // We use 8080 as default port.
1242     // // String port = (String)axisContext.getProperty(ListingAgent.RUNNING_PORT);
1243     // // port = (port == null) ? "8080" : port;
1244     // //
1245     // // String generatedGatewayURL = "http://" + host + ":" + port + "/" + contextPath;
1246     // //
1247     // // return generatedGatewayURL;
1248     // // }
1249     //
1250     // /* (non-Javadoc)
1251     // * @see org.apache.axis2.transport.http.AxisServlet#doGet(javax.servlet.http.HttpServletRequest,
1252     // javax.servlet.http.HttpServletResponse)
1253     // */
1254     // protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException,
1255     // IOException {
1256     // //response.getOutputStream().println("<!-- Invokation of Bootstrap Service -->");
1257     // super.doGet(request, response);
1258     // }
1259     // CHECKSTYLE:ON
1260 }