Package com.eviware.soapui.impl.wsdl.panels.teststeps.amf

Source Code of com.eviware.soapui.impl.wsdl.panels.teststeps.amf.SoapUIAMFConnection

/*
*  soapUI, copyright (C) 2004-2011 eviware.com
*
*  soapUI is free software; you can redistribute it and/or modify it under the
*  terms of version 2.1 of the GNU Lesser General Public License as published by
*  the Free Software Foundation.
*
*  soapUI 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 Lesser General Public License for more details at gnu.org.
*/

package com.eviware.soapui.impl.wsdl.panels.teststeps.amf;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.commons.httpclient.HostConfiguration;
import org.apache.commons.httpclient.HttpState;
import org.apache.commons.httpclient.methods.ByteArrayRequestEntity;

import com.eviware.soapui.SoapUI;
import com.eviware.soapui.impl.wsdl.submit.transports.http.support.methods.ExtendedPostMethod;
import com.eviware.soapui.impl.wsdl.support.http.HttpClientSupport;
import com.eviware.soapui.impl.wsdl.support.http.ProxyUtils;
import com.eviware.soapui.model.propertyexpansion.PropertyExpansionContext;

import flex.messaging.io.ClassAliasRegistry;
import flex.messaging.io.MessageDeserializer;
import flex.messaging.io.MessageIOConstants;
import flex.messaging.io.SerializationContext;
import flex.messaging.io.amf.ActionContext;
import flex.messaging.io.amf.ActionMessage;
import flex.messaging.io.amf.AmfMessageDeserializer;
import flex.messaging.io.amf.AmfMessageSerializer;
import flex.messaging.io.amf.MessageBody;
import flex.messaging.io.amf.MessageHeader;
import flex.messaging.io.amf.client.AMFHeaderProcessor;
import flex.messaging.io.amf.client.exceptions.ClientStatusException;
import flex.messaging.io.amf.client.exceptions.ServerStatusException;
import flex.messaging.io.amf.client.exceptions.ServerStatusException.HttpResponseInfo;

/**
* AMFConnection derivate using HttpClient instead of UrlConnection
*
* @author Ole
*/

public class SoapUIAMFConnection
{
  private static int DEFAULT_OBJECT_ENCODING = MessageIOConstants.AMF3;

  /**
   * Creates a default AMF connection instance.
   */
  public SoapUIAMFConnection()
  {
  }

  private ActionContext actionContext;
  private boolean connected;
  private int objectEncoding;
  private boolean objectEncodingSet = false;
  private SerializationContext serializationContext;
  private String url;

  private List<MessageHeader> amfHeaders;
  private AMFHeaderProcessor amfHeaderProcessor;
  private Map<String, String> httpRequestHeaders;
  private int responseCounter;

  private ExtendedPostMethod postMethod;
  private HttpState httpState = new HttpState();
  private PropertyExpansionContext context;

  public int getObjectEncoding()
  {
    if( !objectEncodingSet )
      return DEFAULT_OBJECT_ENCODING;

    return objectEncoding;
  }

  public void setObjectEncoding( int objectEncoding )
  {
    this.objectEncoding = objectEncoding;
    objectEncodingSet = true;
  }

  public String getUrl()
  {
    return url;
  }

  /**
   * Adds an AMF packet-level header which is sent with every request for the
   * life of this AMF connection.
   *
   * @param name
   *           The name of the header.
   * @param mustUnderstand
   *           Whether the header must be processed or not.
   * @param data
   *           The value of the header.
   */
  public void addAmfHeader( String name, boolean mustUnderstand, Object data )
  {
    if( amfHeaders == null )
      amfHeaders = new ArrayList<MessageHeader>();

    MessageHeader header = new MessageHeader( name, mustUnderstand, data );
    amfHeaders.add( header );
  }

  /**
   * Add an AMF packet-level header with mustUnderstand=false, which is sent
   * with every request for the life of this AMF connection.
   *
   * @param name
   *           The name of the header.
   * @param data
   *           The value of the header.
   */
  public void addAmfHeader( String name, Object data )
  {
    addAmfHeader( name, false, data );
  }

  /**
   * Removes any AMF headers found with the name given.
   *
   * @param name
   *           The name of the header(s) to remove.
   *
   * @return true if a header existed with the given name.
   */
  public boolean removeAmfHeader( String name )
  {
    boolean exists = false;
    if( amfHeaders != null )
    {
      for( Iterator<MessageHeader> iterator = amfHeaders.iterator(); iterator.hasNext(); )
      {
        MessageHeader header = iterator.next();
        if( name.equals( header.getName() ) )
        {
          iterator.remove();
          exists = true;
        }
      }
    }
    return exists;
  }

  /**
   * Removes all AMF headers.
   */
  public void removeAllAmfHeaders()
  {
    if( amfHeaders != null )
      amfHeaders = null;
  }

  /**
   * Adds a Http request header to the underlying connection.
   *
   * @param name
   *           The name of the Http header.
   * @param value
   *           The value of the Http header.
   */
  public void addHttpRequestHeader( String name, String value )
  {
    if( httpRequestHeaders == null )
      httpRequestHeaders = new HashMap<String, String>();

    httpRequestHeaders.put( name, value );
  }

  /**
   * Removes the Http header found with the name given.
   *
   * @param name
   *           The name of the Http header.
   *
   * @return true if a header existed with the given name.
   */
  public boolean removeHttpRequestHeader( String name )
  {
    boolean exists = false;
    if( httpRequestHeaders != null )
    {
      Object previousValue = httpRequestHeaders.remove( name );
      exists = ( previousValue != null );
    }
    return exists;
  }

  /**
   * Removes all Http request headers.
   */
  public void removeAllHttpRequestHeaders()
  {
    if( httpRequestHeaders != null )
      httpRequestHeaders = null;
  }

  /**
   * Makes an AMF request to the server. A connection must have been made prior
   * to making a call.
   *
   * @param command
   *           The method to call on the server.
   * @param arguments
   *           Arguments for the method.
   *
   * @return The result of the call.
   *
   * @throws ClientStatusException
   *            If there is a client side exception.
   * @throws ServerStatusException
   *            If there is a server side exception.
   */

  public Object call( PropertyExpansionContext context, String command, Object... arguments )
      throws ClientStatusException, ServerStatusException
  {
    this.context = context;

    if( !connected )
    {
      String message = "AMF connection is not connected";
      ClientStatusException cse = new ClientStatusException( message, ClientStatusException.AMF_CALL_FAILED_CODE );
      throw cse;
    }

    String responseURI = getResponseURI();

    ActionMessage requestMessage = new ActionMessage( getObjectEncoding() );

    if( amfHeaders != null )
    {
      for( MessageHeader header : amfHeaders )
        requestMessage.addHeader( header );
    }

    MessageBody amfMessage = new MessageBody( command, responseURI, arguments );
    requestMessage.addBody( amfMessage );

    // Setup for AMF message serializer
    actionContext.setRequestMessage( requestMessage );
    ByteArrayOutputStream outBuffer = new ByteArrayOutputStream();
    AmfMessageSerializer amfMessageSerializer = new AmfMessageSerializer();
    amfMessageSerializer.initialize( serializationContext, outBuffer, null/* debugTrace */);

    try
    {
      amfMessageSerializer.writeMessage( requestMessage );
      Object result = send( outBuffer );
      return result;
    }
    catch( Exception e )
    {
      if( e instanceof ClientStatusException )
        throw ( ClientStatusException )e;
      else if( e instanceof ServerStatusException )
        throw ( ServerStatusException )e;
      // Otherwise, wrap into a ClientStatusException.
      ClientStatusException exception = new ClientStatusException( e, ClientStatusException.AMF_CALL_FAILED_CODE );
      throw exception;
    }
    finally
    {
      try
      {
        outBuffer.close();
      }
      catch( IOException ignore )
      {
      }
    }
  }

  /**
   * Closes the underlying URL connection, sets the url to null, and clears the
   * cookies.
   */
  public void close()
  {
    // Clear the URL connection and URL.
    if( postMethod != null )
    {
      postMethod.releaseConnection();
      postMethod = null;
    }
    url = null;

    serializationContext = null;
    connected = false;
  }

  /**
   * Connects to the URL provided. Any previous connections are closed.
   *
   * @param url
   *           The url to connect to.
   *
   * @throws ClientStatusException
   *            If there is a client side exception.
   */
  public void connect( String url ) throws ClientStatusException
  {
    if( connected )
      close();

    this.url = url;
    try
    {
      serializationContext = new SerializationContext();
      serializationContext.createASObjectForMissingType = true;
      internalConnect();
    }
    catch( IOException e )
    {
      ClientStatusException exception = new ClientStatusException( e, ClientStatusException.AMF_CONNECT_FAILED_CODE );
      throw exception;
    }
  }

  // --------------------------------------------------------------------------
  //
  // Protected Methods
  //
  // --------------------------------------------------------------------------

  /**
   * Generates the HTTP response info for the server status exception.
   *
   * @return The HTTP response info for the server status exception.
   */
  protected HttpResponseInfo generateHttpResponseInfo()
  {
    HttpResponseInfo httpResponseInfo = null;
    try
    {
      int responseCode = postMethod.getStatusCode();
      String responseMessage = postMethod.getResponseBodyAsString();
      httpResponseInfo = new HttpResponseInfo( responseCode, responseMessage );
    }
    catch( IOException ignore )
    {
    }
    return httpResponseInfo;
  }

  /**
   * Generates and returns the response URI.
   *
   * @return The response URI.
   */
  protected String getResponseURI()
  {
    String responseURI = "/" + responseCounter;
    responseCounter++ ;
    return responseURI;
  }

  /**
   * An internal method that sets up the underlying URL connection.
   *
   * @throws IOException
   *            If an exception is encountered during URL connection setup.
   */
  protected void internalConnect() throws IOException
  {
    serializationContext.instantiateTypes = false;
    postMethod = new ExtendedPostMethod( url );
    setHttpRequestHeaders();
    actionContext = new ActionContext();
    connected = true;
  }

  /**
   * Processes the HTTP response headers and body.
   */
  protected Object processHttpResponse( InputStream inputStream ) throws ClassNotFoundException, IOException,
      ClientStatusException, ServerStatusException
  {
    return processHttpResponseBody( inputStream );
  }

  /**
   * Processes the HTTP response body.
   */
  protected Object processHttpResponseBody( InputStream inputStream ) throws ClassNotFoundException, IOException,
      ClientStatusException, ServerStatusException
  {
    DataInputStream din = new DataInputStream( inputStream );
    ActionMessage message = new ActionMessage();
    actionContext.setRequestMessage( message );
    MessageDeserializer deserializer = new AmfMessageDeserializer();
    deserializer.initialize( serializationContext, din, null/* trace */);
    deserializer.readMessage( message, actionContext );
    din.close();
    context.setProperty( AMFResponse.AMF_RESPONSE_ACTION_MESSAGE, message );
    return processAmfPacket( message );
  }

  /**
   * Processes the AMF packet.
   */
  @SuppressWarnings( "unchecked" )
  protected Object processAmfPacket( ActionMessage packet ) throws ClientStatusException, ServerStatusException
  {
    processAmfHeaders( packet.getHeaders() );
    return processAmfBody( packet.getBodies() );
  }

  /**
   * Processes the AMF headers by dispatching them to an AMF header processor,
   * if one exists.
   */
  protected void processAmfHeaders( ArrayList<MessageHeader> headers ) throws ClientStatusException
  {
    // No need to process headers if there's no AMF header processor.
    if( amfHeaderProcessor == null )
      return;

    for( MessageHeader header : headers )
      amfHeaderProcessor.processHeader( header );
  }

  /**
   * Processes the AMF body. Note that this method won't work if batching of
   * AMF messages is supported at some point but for now we are guaranteed to
   * have a single message.
   */
  protected Object processAmfBody( ArrayList<MessageBody> messages ) throws ServerStatusException
  {
    for( MessageBody message : messages )
    {
      String targetURI = message.getTargetURI();

      if( targetURI.endsWith( MessageIOConstants.RESULT_METHOD ) )
      {
        return message.getData();
      }
      else if( targetURI.endsWith( MessageIOConstants.STATUS_METHOD ) )
      {
        // String exMessage = "Server error";
        // HttpResponseInfo responseInfo = generateHttpResponseInfo();
        // ServerStatusException exception = new ServerStatusException(
        // exMessage, message.getData(), responseInfo );

        return message.getData();
        // throw exception;
      }
    }
    return null; // Should not happen.
  }

  /**
   * Writes the output buffer and processes the HTTP response.
   */
  protected Object send( ByteArrayOutputStream outBuffer ) throws ClassNotFoundException, IOException,
      ClientStatusException, ServerStatusException
  {
    // internalConnect.
    internalConnect();

    postMethod.setRequestEntity( new ByteArrayRequestEntity( outBuffer.toByteArray() ) );
    HostConfiguration hostConfiguration = new HostConfiguration();

    ProxyUtils.initProxySettings( context.getModelItem() == null ? SoapUI.getSettings() : context.getModelItem()
        .getSettings(), httpState, hostConfiguration, url, context );

    HttpClientSupport.getHttpClient().executeMethod( hostConfiguration, postMethod, httpState );

    context.setProperty( AMFResponse.AMF_POST_METHOD, postMethod );

    return processHttpResponse( responseBodyInputStream() );
  }

  private ByteArrayInputStream responseBodyInputStream() throws IOException
  {
    byte[] responseBody = postMethod.getResponseBody();
    ByteArrayInputStream bais = new ByteArrayInputStream( responseBody );
    context.setProperty( AMFResponse.AMF_RAW_RESPONSE_BODY, responseBody );
    return bais;
  }

  /**
   * Sets the Http request headers, including the cookie headers.
   */
  protected void setHttpRequestHeaders()
  {
    if( httpRequestHeaders != null )
    {
      for( Map.Entry<String, String> element : httpRequestHeaders.entrySet() )
      {
        String key = element.getKey();
        String value = element.getValue();
        postMethod.setRequestHeader( key, value );
      }
    }
  }

  /**
   * Registers a custom alias for a class name bidirectionally.
   *
   * @param alias
   *           The alias for the class name.
   * @param className
   *           The concrete class name.
   */
  public static void registerAlias( String alias, String className )
  {
    ClassAliasRegistry registry = ClassAliasRegistry.getRegistry();
    registry.registerAlias( alias, className );
    registry.registerAlias( className, alias );
  }
}
TOP

Related Classes of com.eviware.soapui.impl.wsdl.panels.teststeps.amf.SoapUIAMFConnection

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.