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

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

/*
* Copyright 2004-2014 SmartBear Software
*
* Licensed under the EUPL, Version 1.1 or - as soon as they will be approved by the European Commission - subsequent
* versions of the EUPL (the "Licence");
* You may not use this work except in compliance with the Licence.
* You may obtain a copy of the Licence at:
*
* http://ec.europa.eu/idabc/eupl
*
* Unless required by applicable law or agreed to in writing, software distributed under the Licence is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the Licence for the specific language governing permissions and limitations
* under the Licence.
*/

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.http.entity.ByteArrayEntity;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;

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 HttpContext httpState = new BasicHttpContext();
    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.
        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 = 0;
            if (postMethod.hasHttpResponse()) {
                responseCode = postMethod.getHttpResponse().getStatusLine().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.setEntity(new ByteArrayEntity(outBuffer.toByteArray()));

        HttpClientSupport.execute(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.setHeader(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.