Project: eucalyptus
/*
 * Author: Chris Grzegorczyk [email protected] 
 * Author: Sunil Soman [email protected] 
 */
 
package edu.ucsb.eucalyptus.transport.http; 
 
import edu.ucsb.eucalyptus.util.Messaging; 
import org.apache.axiom.soap.SOAPEnvelope; 
import org.apache.axiom.soap.SOAPFactory; 
import org.apache.axiom.soap.impl.llom.soap11.SOAP11Factory; 
import org.apache.axis2.AxisFault; 
import org.apache.axis2.Constants; 
import org.apache.axis2.builder.BuilderUtil; 
import org.apache.axis2.context.ConfigurationContext; 
import org.apache.axis2.context.MessageContext; 
import org.apache.axis2.engine.AxisEngine; 
import org.apache.axis2.engine.Handler; 
import org.apache.axis2.transport.RequestResponseTransport; 
import org.apache.axis2.transport.TransportUtils; 
import org.apache.axis2.transport.http.HTTPConstants; 
import org.apache.axis2.transport.http.HTTPTransportReceiver; 
import org.apache.axis2.transport.http.HTTPTransportUtils; 
import org.apache.axis2.transport.http.server.AxisHttpRequest; 
import org.apache.axis2.transport.http.server.AxisHttpResponse; 
import org.apache.axis2.transport.http.server.HttpUtils; 
import org.apache.axis2.transport.http.server.Worker; 
import org.apache.http.Header; 
import org.apache.http.HttpException; 
import org.apache.http.HttpStatus; 
import org.apache.http.MethodNotSupportedException; 
import org.apache.http.message.BasicHeader; 
import org.apache.http.protocol.HTTP; 
import org.apache.http.util.EncodingUtils; 
import org.apache.log4j.Logger; 
import org.mule.transport.NullPayload; 
 
import java.io.IOException; 
import java.io.InputStream; 
import java.io.OutputStream; 
 
/*******************************************************************************
 * Copyright (c) 2009  Eucalyptus Systems, Inc. 
 * 
 * This program is free software: you can redistribute it and/or modify 
 * it under the terms of the GNU General Public License as published by 
 * the Free Software Foundation, only version 3 of the License. 
 * 
 * 
 * This file is distributed in the hope that it will be useful, but WITHOUT 
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License 
 * for more details. 
 * 
 * You should have received a copy of the GNU General Public License along 
 * with this program.  If not, see <http://www.gnu.org/licenses/>. 
 * 
 * Please contact Eucalyptus Systems, Inc., 130 Castilian 
 * Dr., Goleta, CA 93101 USA or visit <http://www.eucalyptus.com/licenses/> 
 * if you need additional information or have any questions. 
 * 
 * This file may incorporate work covered under the following copyright and 
 * permission notice: 
 * 
 *   Software License Agreement (BSD License) 
 * 
 *   Copyright (c) 2008, Regents of the University of California 
 *   All rights reserved. 
 * 
 *   Redistribution and use of this software in source and binary forms, with 
 *   or without modification, are permitted provided that the following 
 *   conditions are met: 
 * 
 *     Redistributions of source code must retain the above copyright notice, 
 *     this list of conditions and the following disclaimer. 
 * 
 *     Redistributions in binary form must reproduce the above copyright 
 *     notice, this list of conditions and the following disclaimer in the 
 *     documentation and/or other materials provided with the distribution. 
 * 
 *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 
 *   IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 
 *   TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 
 *   PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 
 *   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
 *   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
 *   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
 *   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
 *   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
 *   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
 *   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. USERS OF 
 *   THIS SOFTWARE ACKNOWLEDGE THE POSSIBLE PRESENCE OF OTHER OPEN SOURCE 
 *   LICENSED MATERIAL, COPYRIGHTED MATERIAL OR PATENTED MATERIAL IN THIS 
 *   SOFTWARE, AND IF ANY SUCH MATERIAL IS DISCOVERED THE PARTY DISCOVERING 
 *   IT MAY INFORM DR. RICH WOLSKI AT THE UNIVERSITY OF CALIFORNIA, SANTA 
 *   BARBARA WHO WILL THEN ASCERTAIN THE MOST APPROPRIATE REMEDY, WHICH IN 
 *   THE REGENTS? DISCRETION MAY INCLUDE, WITHOUT LIMITATION, REPLACEMENT 
 *   OF THE CODE SO IDENTIFIED, LICENSING OF THE CODE SO IDENTIFIED, OR 
 *   WITHDRAWAL OF THE CODE CAPABILITY TO THE EXTENT NEEDED TO COMPLY WITH 
 *   ANY SUCH LICENSES OR RIGHTS. 
 ******************************************************************************/
 
 
public class Axis2HttpWorker implements Worker { 
 
  private static Logger LOG = Logger.getLogger( Axis2HttpWorker.class ); 
 
  public static String REAL_HTTP_REQUEST = "HAI_IS_REAL_HTTP_REQUEST"
  public static String REAL_HTTP_RESPONSE = "YHALO_I_ARE_TEH_HTTP_RESPONSE"
  public static String HTTP_STATUS = "IS_IT_CAN_BE_HTTP_STATUS"
 
  public Axis2HttpWorker() {} 
 
  public void servicefinal AxisHttpRequest request, final AxisHttpResponse response, final MessageContext msgContext ) throws HttpException, IOException { 
 
    ConfigurationContext configurationContext = msgContext.getConfigurationContext(); 
    final String servicePath = configurationContext.getServiceContextPath(); 
    final String contextPath = ( servicePath.startsWith( "/" ) ? servicePath : "/" + servicePath ) + "/"
 
    String uri = request.getRequestURI(); 
    String method = request.getMethod(); 
    String soapAction = HttpUtils.getSoapAction( request ); 
    Handler.InvocationResponse pi = null
    msgContext.setProperty( REAL_HTTP_REQUEST, request ); 
    msgContext.setProperty( REAL_HTTP_RESPONSE, response ); 
 
    Header[] headers = request.getHeaders(HTTP.CONTENT_LEN); 
    if(headers != null && headers.length > 0) { 
        String contentLength = headers[0].getValue(); 
        msgContext.setProperty(HTTP.CONTENT_LEN, contentLength); 
    } 
 
    if ( method.equals( HTTPConstants.HEADER_GET ) ) { 
      if ( ( uri.startsWith( "/latest/" ) || uri.matches("/\\d\\d\\d\\d-\\d\\d-\\d\\d/.*") ) && handleMetaData( response, msgContext, uri ) ) 
        return
      if ( !uri.startsWith( contextPath ) ) { 
        response.setStatus( HttpStatus.SC_MOVED_PERMANENTLY ); 
        response.addHeader( new BasicHeader( "Location", ( contextPath + uri ).replaceAll( "//""/" ) ) ); 
        return
      } 
      if ( uri.endsWith( "services/" ) ) { 
        handleServicesList( response, configurationContext ); 
        return
      } 
      if ( uri.endsWith( "?wsdl" ) ) { 
        handleWSDL( response ); 
        return
      } 
      pi = handleGet( request, response, msgContext ); 
    } 
    else if ( method.equals( HTTPConstants.HEADER_POST ) ) { 
      String contentType = request.getContentType(); 
      if ( HTTPTransportUtils.isRESTRequest( contentType ) ) 
        pi = Axis2HttpWorker.processXMLRequest( msgContext, request.getInputStream(), response.getOutputStream(), contentType ); 
      else { 
        String ip = ( String ) msgContext.getProperty( MessageContext.TRANSPORT_ADDR ); 
        if ( ip != null ) 
          uri = ip + uri; 
        pi = HTTPTransportUtils.processHTTPPostRequest( msgContext, request.getInputStream(), response.getOutputStream(), contentType, soapAction, uri ); 
      } 
    } 
    else if ( method.equals( HTTPConstants.HEADER_PUT ) ) { 
      String contentType = request.getContentType(); 
      msgContext.setProperty( Constants.Configuration.CONTENT_TYPE, contentType ); 
 
      pi = Axis2HttpWorker.processXMLRequest( msgContext, request.getInputStream(), response.getOutputStream(), contentType ); 
    } 
    else if ( method.equals( HTTPConstants.HEADER_DELETE ) ) 
      pi = Axis2HttpWorker.processURLRequest( msgContext, response.getOutputStream(), null ); 
    else if ( method.equals( "HEAD" ) ) 
      pi = Axis2HttpWorker.processURLRequest( msgContext, response.getOutputStream(), null ); 
    else 
      throw new MethodNotSupportedException( method + " method not supported" ); 
 
    Boolean holdResponse = ( Boolean ) msgContext.getProperty( RequestResponseTransport.HOLD_RESPONSE ); 
    if ( pi.equals( Handler.InvocationResponse.SUSPEND ) || ( holdResponse != null && Boolean.TRUE.equals( holdResponse ) ) ) 
      try { 
        ( ( RequestResponseTransport ) msgContext.getProperty( RequestResponseTransport.TRANSPORT_CONTROL ) ).awaitResponse(); 
      } 
      catch ( InterruptedException e ) { 
        throw new IOException( "We were interrupted, so this may not function correctly:" + e.getMessage() ); 
      } 
    RequestResponseTransport requestResponseTransportControl = ( RequestResponseTransport ) msgContext.getProperty( RequestResponseTransport.TRANSPORT_CONTROL ); 
    if ( TransportUtils.isResponseWritten( msgContext )  || ( ( requestResponseTransportControl != null ) && requestResponseTransportControl.getStatus().equals( RequestResponseTransport.RequestResponseTransportStatus.SIGNALLED ) ) ); 
    else 
      response.setStatus( HttpStatus.SC_ACCEPTED ); 
    Integer status = ( Integer ) msgContext.getProperty( HTTP_STATUS ); 
    if ( status != null ) response.setStatus( status ); 
  } 
 
  private void handleServicesListfinal AxisHttpResponse response, final ConfigurationContext configurationContext ) throws IOException { 
    String s = HTTPTransportReceiver.getServicesHTML( configurationContext ); 
    response.setStatus( HttpStatus.SC_OK ); 
    response.setContentType( "text/html" ); 
    OutputStream out = response.getOutputStream(); 
    out.write( EncodingUtils.getBytes( s, HTTP.ISO_8859_1 ) ); 
  } 
 
  private void handleWSDLfinal AxisHttpResponse response ) throws IOException { 
    String s = "A sensible response."
    response.setStatus( HttpStatus.SC_OK ); 
    response.setContentType( "text/html" ); 
    OutputStream out = response.getOutputStream(); 
    out.write( EncodingUtils.getBytes( s, HTTP.ISO_8859_1 ) ); 
  } 
 
  private boolean handleMetaDatafinal AxisHttpResponse response, final MessageContext msgContext, final String uri ) { 
    try { 
      String newUri = null
      if( uri.startsWith( "/latest/" ) ) 
        newUri = uri.replaceAll( "/latest/", msgContext.getProperty( MessageContext.REMOTE_ADDR ) + ":" ); 
      else 
        newUri = uri.replaceAll( "/\\d\\d\\d\\d-\\d\\d-\\d\\d/", msgContext.getProperty( MessageContext.REMOTE_ADDR ) + ":" ); 
      LOG.debug( "Metadata request: " + newUri ); 
      Object reply = Messaging.send( "vm://VmMetadata", newUri ); 
      if ( !( reply instanceof NullPayload ) ) { 
        response.setStatus( HttpStatus.SC_OK ); 
        response.setContentType( "text/html" ); 
        OutputStream out = response.getOutputStream(); 
        out.write( EncodingUtils.getBytes( ( ( String ) reply ), HTTP.ISO_8859_1 ) ); 
      } 
      else 
        response.setStatus( HttpStatus.SC_NOT_FOUND ); 
      return true
    } 
    catch ( Exception e ) { 
      LOG.error( e, e ); 
    } 
    return false
  } 
 
  private Handler.InvocationResponse handleGetfinal AxisHttpRequest request, final AxisHttpResponse response, final MessageContext msgContext ) throws AxisFault { 
    Handler.InvocationResponse pi; 
    String contentType = null
    Header[] headers = request.getHeaders( HTTPConstants.HEADER_CONTENT_TYPE ); 
    if ( headers != null && headers.length > 0 ) { 
      contentType = headers[ 0 ].getValue(); 
      int index = contentType.indexOf( ';' ); 
      if ( index > 0 ) { 
        contentType = contentType.substring( 0, index ); 
      } 
    } 
    pi = Axis2HttpWorker.processURLRequest( msgContext, response.getOutputStream(), contentType ); 
    return pi; 
  } 
 
  public static Handler.InvocationResponse processURLRequest( MessageContext msgContext, OutputStream out, String contentType ) throws AxisFault { 
    try { 
      if ( contentType == null || "".equals( contentType ) ) { 
        contentType = HTTPConstants.MEDIA_TYPE_X_WWW_FORM; 
      } 
      msgContext.setDoingREST( true ); 
      msgContext.setProperty( MessageContext.TRANSPORT_OUT, out ); 
      String charSetEncoding = BuilderUtil.getCharSetEncoding( contentType ); 
      msgContext.setProperty( Constants.Configuration.CHARACTER_SET_ENCODING, charSetEncoding ); 
      SOAPEnvelope soapEnvelope = TransportUtils.createSOAPMessage( msgContext, null, contentType ); 
      msgContext.setEnvelope( soapEnvelope ); 
    } 
    catch ( Exception e ) { 
      throw e instanceof AxisFault ? ( AxisFault ) e : AxisFault.makeFault( e ); 
    } 
    finally { 
      String messageType = ( String ) msgContext.getProperty( Constants.Configuration.MESSAGE_TYPE ); 
      if ( HTTPConstants.MEDIA_TYPE_X_WWW_FORM.equals( messageType ) || HTTPConstants.MEDIA_TYPE_MULTIPART_FORM_DATA.equals( messageType ) ) 
        msgContext.setProperty( Constants.Configuration.MESSAGE_TYPE, HTTPConstants.MEDIA_TYPE_APPLICATION_XML ); 
    } 
    AxisEngine axisEngine = new AxisEngine( msgContext.getConfigurationContext() ); 
    return axisEngine.receive( msgContext ); 
  } 
 
  public static Handler.InvocationResponse processXMLRequest( MessageContext msgContext, InputStream in, OutputStream out, String contentType ) throws AxisFault { 
    try { 
      msgContext.setDoingREST( true ); 
      String charSetEncoding = BuilderUtil.getCharSetEncoding( contentType ); 
      msgContext.setProperty( Constants.Configuration.CHARACTER_SET_ENCODING, charSetEncoding ); 
      SOAPFactory soapFactory = new SOAP11Factory(); 
      SOAPEnvelope soapEnvelope = soapFactory.getDefaultEnvelope(); 
      msgContext.setEnvelope( soapEnvelope ); 
      in = HTTPTransportUtils.handleGZip( msgContext, in ); 
      msgContext.setProperty( Constants.Configuration.CONTENT_TYPE, contentType ); 
      msgContext.setProperty( MessageContext.TRANSPORT_OUT, out ); 
      msgContext.setProperty( MessageContext.TRANSPORT_IN, in ); 
    } 
    catch ( Exception e ) { 
      throw e instanceof AxisFault ? ( AxisFault ) e : AxisFault.makeFault( e ); 
    } 
    finally { 
      String messageType = ( String ) msgContext.getProperty( Constants.Configuration.MESSAGE_TYPE ); 
      if ( HTTPConstants.MEDIA_TYPE_X_WWW_FORM.equals( messageType ) || HTTPConstants.MEDIA_TYPE_MULTIPART_FORM_DATA.equals( messageType ) ) 
        msgContext.setProperty( Constants.Configuration.MESSAGE_TYPE, HTTPConstants.MEDIA_TYPE_APPLICATION_XML ); 
    } 
    AxisEngine axisEngine = new AxisEngine( msgContext.getConfigurationContext() ); 
    return axisEngine.receive( msgContext ); 
  } 
 
}