edu.ucsb.eucalyptus.transport.Axis2InOutMessageReceiver.java Source code

Java tutorial

Introduction

Here is the source code for edu.ucsb.eucalyptus.transport.Axis2InOutMessageReceiver.java

Source

/*
 * Author: Chris Grzegorczyk grze@cs.ucsb.edu
 * Author: Sunil Soman sunils@cs.ucsb.edu
 */

package edu.ucsb.eucalyptus.transport;

import com.google.common.collect.Lists;
import edu.ucsb.eucalyptus.cloud.EucalyptusCloudException;
import edu.ucsb.eucalyptus.msgs.AddClusterResponseType;
import edu.ucsb.eucalyptus.msgs.DeregisterImageType;
import edu.ucsb.eucalyptus.msgs.DescribeImageAttributeType;
import edu.ucsb.eucalyptus.msgs.DescribeImagesResponseType;
import edu.ucsb.eucalyptus.msgs.DescribeImagesType;
import edu.ucsb.eucalyptus.msgs.DescribeInstancesResponseType;
import edu.ucsb.eucalyptus.msgs.EucalyptusErrorMessageType;
import edu.ucsb.eucalyptus.msgs.EucalyptusMessage;
import edu.ucsb.eucalyptus.msgs.ImageDetails;
import edu.ucsb.eucalyptus.msgs.MetaDataEntry;
import edu.ucsb.eucalyptus.msgs.ModifyImageAttributeType;
import edu.ucsb.eucalyptus.msgs.PostObjectResponseType;
import edu.ucsb.eucalyptus.msgs.ReservationInfoType;
import edu.ucsb.eucalyptus.msgs.ResetImageAttributeType;
import edu.ucsb.eucalyptus.msgs.RunInstancesType;
import edu.ucsb.eucalyptus.msgs.RunningInstancesItemType;
import edu.ucsb.eucalyptus.msgs.WalrusDataRequestType;
import edu.ucsb.eucalyptus.msgs.WalrusDataResponseType;
import edu.ucsb.eucalyptus.msgs.WalrusErrorMessageType;
import edu.ucsb.eucalyptus.transport.binding.Binding;
import edu.ucsb.eucalyptus.transport.binding.BindingManager;
import edu.ucsb.eucalyptus.transport.http.Axis2HttpWorker;
import edu.ucsb.eucalyptus.transport.query.GenericHttpDispatcher;
import edu.ucsb.eucalyptus.transport.query.HttpRequest;
import edu.ucsb.eucalyptus.util.BindingUtil;
import edu.ucsb.eucalyptus.util.WalrusProperties;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.soap.SOAPEnvelope;
import org.apache.axiom.soap.SOAPFactory;
import org.apache.axis2.AxisFault;
import org.apache.axis2.context.MessageContext;
import org.apache.axis2.description.AxisOperation;
import org.apache.axis2.receivers.AbstractInOutMessageReceiver;
import org.apache.axis2.transport.http.server.AxisHttpResponse;
import org.apache.axis2.util.JavaUtils;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.http.message.BasicHeader;
import org.apache.http.protocol.HTTP;
import org.apache.log4j.Logger;
import org.apache.neethi.Policy;
import org.apache.rampart.RampartMessageData;
import org.apache.ws.security.WSSecurityEngineResult;
import org.apache.ws.security.handler.WSHandlerConstants;
import org.apache.ws.security.handler.WSHandlerResult;
import org.jibx.runtime.JiBXException;
import org.mule.DefaultMuleMessage;
import org.mule.api.MuleException;
import org.mule.api.MuleMessage;
import org.mule.config.ExceptionHelper;

import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;

/*******************************************************************************
 * 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 Axis2InOutMessageReceiver extends AbstractInOutMessageReceiver {

    private static Logger LOG = Logger.getLogger(Axis2InOutMessageReceiver.class);
    private Class serviceClass;
    private Axis2MessageReceiver msgReceiver;

    public Axis2InOutMessageReceiver(Axis2MessageReceiver msgReceiver, Class serviceClass) throws AxisFault {
        this.serviceClass = serviceClass;
        this.msgReceiver = msgReceiver;
    }

    public void invokeBusinessLogic(MessageContext msgContext, MessageContext newMsgContext) throws AxisFault {
        String methodName = this.findOperation(msgContext);
        Class serviceMethodArgType = this.findArgumentClass(methodName);

        SOAPFactory factory = this.getSOAPFactory(msgContext);
        OMElement msgBodyOm = msgContext.getEnvelope().getBody().getFirstElement();

        String bindingName = this.findBindingName(msgBodyOm);
        EucalyptusMessage wrappedParam = this.bindMessage(methodName, serviceMethodArgType, msgBodyOm, bindingName);

        HttpRequest httprequest = (HttpRequest) msgContext.getProperty(GenericHttpDispatcher.HTTP_REQUEST);
        if (httprequest == null) {
            this.verifyUser(msgContext, wrappedParam);
        } else {
            bindingName = httprequest.getBindingName();
            Policy p = new Policy();
            newMsgContext.setProperty(RampartMessageData.KEY_RAMPART_POLICY, p);
            //:: fixes the handling of certain kinds of client brain damage :://
            if (httprequest.isPureClient()) {
                if (wrappedParam instanceof ModifyImageAttributeType) {
                    ModifyImageAttributeType pure = ((ModifyImageAttributeType) wrappedParam);
                    pure.setImageId(purifyImageIn(pure.getImageId()));
                } else if (wrappedParam instanceof DescribeImageAttributeType) {
                    DescribeImageAttributeType pure = ((DescribeImageAttributeType) wrappedParam);
                    pure.setImageId(purifyImageIn(pure.getImageId()));
                } else if (wrappedParam instanceof ResetImageAttributeType) {
                    ResetImageAttributeType pure = ((ResetImageAttributeType) wrappedParam);
                    pure.setImageId(purifyImageIn(pure.getImageId()));
                } else if (wrappedParam instanceof DescribeImagesType) {
                    ArrayList<String> strs = Lists.newArrayList();
                    for (String imgId : ((DescribeImagesType) wrappedParam).getImagesSet()) {
                        strs.add(purifyImageIn(imgId));
                    }
                    ((DescribeImagesType) wrappedParam).setImagesSet(strs);
                } else if (wrappedParam instanceof DeregisterImageType) {
                    DeregisterImageType pure = ((DeregisterImageType) wrappedParam);
                    pure.setImageId(purifyImageIn(pure.getImageId()));
                } else if (wrappedParam instanceof RunInstancesType) {
                    RunInstancesType pure = ((RunInstancesType) wrappedParam);
                    pure.setImageId(purifyImageIn(pure.getImageId()));
                    pure.setKernelId(purifyImageIn(pure.getKernelId()));
                    pure.setRamdiskId(purifyImageIn(pure.getRamdiskId()));
                }
            }

        }

        MuleMessage message = this.invokeService(methodName, wrappedParam);

        if (message == null)
            throw new AxisFault("Received a NULL response. This is a bug -- it should NEVER happen.");

        this.checkException(message);

        if (httprequest != null) {
            //:: fixes the handling of certain kinds of client brain damage :://
            if (httprequest.isPureClient()) {
                if (message.getPayload() instanceof DescribeImagesResponseType) {
                    DescribeImagesResponseType purify = (DescribeImagesResponseType) message.getPayload();
                    for (ImageDetails img : purify.getImagesSet()) {
                        img.setImageId(img.getImageId().replaceFirst("^e", "a").toLowerCase());
                        if (img.getKernelId() != null)
                            img.setKernelId(img.getKernelId().replaceFirst("^e", "a").toLowerCase());
                        if (img.getRamdiskId() != null)
                            img.setRamdiskId(img.getRamdiskId().replaceFirst("^e", "a").toLowerCase());
                    }
                } else if (message.getPayload() instanceof DescribeInstancesResponseType) {
                    DescribeInstancesResponseType purify = (DescribeInstancesResponseType) message.getPayload();
                    for (ReservationInfoType rsvInfo : purify.getReservationSet()) {
                        for (RunningInstancesItemType r : rsvInfo.getInstancesSet()) {
                            r.setImageId(r.getImageId().replaceFirst("^e", "a").toLowerCase());
                            if (r.getKernel() != null)
                                r.setKernel(r.getKernel().replaceFirst("^e", "a").toLowerCase());
                            if (r.getRamdisk() != null)
                                r.setRamdisk(r.getRamdisk().replaceFirst("^e", "a").toLowerCase());
                        }
                    }
                }

            }
        }

        if (newMsgContext != null) {
            SOAPEnvelope envelope = generateMessage(methodName, factory, bindingName, message.getPayload(),
                    httprequest == null ? null : httprequest.getOriginalNamespace());
            newMsgContext.setEnvelope(envelope);
        }

        newMsgContext.setProperty(Axis2HttpWorker.REAL_HTTP_REQUEST,
                msgContext.getProperty(Axis2HttpWorker.REAL_HTTP_REQUEST));
        newMsgContext.setProperty(Axis2HttpWorker.REAL_HTTP_RESPONSE,
                msgContext.getProperty(Axis2HttpWorker.REAL_HTTP_RESPONSE));

        LOG.info("Returning reply: " + message.getPayload());

        if (message.getPayload() instanceof WalrusErrorMessageType) {
            WalrusErrorMessageType errorMessage = (WalrusErrorMessageType) message.getPayload();
            msgContext.setProperty(Axis2HttpWorker.HTTP_STATUS, errorMessage.getHttpCode());
            newMsgContext.setProperty(Axis2HttpWorker.HTTP_STATUS, errorMessage.getHttpCode());
            //This selects the data formatter
            newMsgContext.setProperty("messageType", "application/walrus");
            return;
        }

        Boolean putType = (Boolean) msgContext.getProperty(WalrusProperties.STREAMING_HTTP_PUT);
        Boolean getType = (Boolean) msgContext.getProperty(WalrusProperties.STREAMING_HTTP_GET);

        if (getType != null || putType != null) {
            WalrusDataResponseType reply = (WalrusDataResponseType) message.getPayload();
            AxisHttpResponse response = (AxisHttpResponse) msgContext
                    .getProperty(Axis2HttpWorker.REAL_HTTP_RESPONSE);
            response.addHeader(new BasicHeader("Last-Modified", reply.getLastModified()));
            response.addHeader(new BasicHeader("ETag", '\"' + reply.getEtag() + '\"'));
            if (getType != null) {
                newMsgContext.setProperty(WalrusProperties.STREAMING_HTTP_GET, getType);
                WalrusDataRequestType request = (WalrusDataRequestType) wrappedParam;
                Boolean isCompressed = request.getIsCompressed();
                if (isCompressed == null)
                    isCompressed = false;
                if (isCompressed) {
                    newMsgContext.setProperty("GET_COMPRESSED", isCompressed);
                } else {
                    Long contentLength = reply.getSize();
                    response.addHeader(new BasicHeader(HTTP.CONTENT_LEN, String.valueOf(contentLength)));
                }
                List<MetaDataEntry> metaData = reply.getMetaData();
                for (MetaDataEntry metaDataEntry : metaData) {
                    response.addHeader(
                            new BasicHeader(WalrusProperties.AMZ_META_HEADER_PREFIX + metaDataEntry.getName(),
                                    metaDataEntry.getValue()));
                }
                if (getType.equals(Boolean.TRUE)) {
                    newMsgContext.setProperty("GET_KEY", request.getBucket() + "." + request.getKey());
                    newMsgContext.setProperty("GET_RANDOM_KEY", request.getRandomKey());
                }
                //This selects the data formatter
                newMsgContext.setProperty("messageType", "application/walrus");
            } else if (putType != null) {
                if (reply instanceof PostObjectResponseType) {
                    PostObjectResponseType postReply = (PostObjectResponseType) reply;
                    String redirectUrl = postReply.getRedirectUrl();
                    if (redirectUrl != null) {
                        response.addHeader(new BasicHeader("Location", redirectUrl));
                        msgContext.setProperty(Axis2HttpWorker.HTTP_STATUS, HttpStatus.SC_SEE_OTHER);
                        newMsgContext.setProperty(Axis2HttpWorker.HTTP_STATUS, HttpStatus.SC_SEE_OTHER);
                        newMsgContext.setProperty("messageType", "application/walrus");
                    } else {
                        Integer successCode = postReply.getSuccessCode();
                        if (successCode != null) {
                            newMsgContext.setProperty(Axis2HttpWorker.HTTP_STATUS, successCode);
                            if (successCode == 201) {
                                return;
                            } else {
                                newMsgContext.setProperty("messageType", "application/walrus");
                                return;
                            }

                        }
                    }
                }
                response.addHeader(new BasicHeader(HTTP.CONTENT_LEN, String.valueOf(0)));
            }
        }

    }

    private String purifyImageIn(String id) {
        id = "e" + id.substring(1, 4) + id.substring(4).toUpperCase();
        return id;
    }

    private void checkException(final MuleMessage message) throws AxisFault {
        if (message.getPayload() instanceof EucalyptusErrorMessageType)
            throw new AxisFault(message.getPayload().toString());
        else if (message.getExceptionPayload() != null) {
            MuleException umoException = ExceptionHelper
                    .getRootMuleException(message.getExceptionPayload().getException());
            if (umoException.getCause() != null)
                throw AxisFault.makeFault(umoException.getCause());
            else
                throw AxisFault.makeFault(umoException);
        }
    }

    private SOAPEnvelope generateMessage(final String methodName, final SOAPFactory factory, String bindingName,
            final Object response, final String altNs) {
        SOAPEnvelope envelope = null;
        LOG.info("[" + serviceClass.getSimpleName() + ":" + methodName + "] Got return type "
                + response.getClass().getSimpleName());
        if (response instanceof AddClusterResponseType)
            bindingName = "msgs_eucalyptus_ucsb_edu";
        try {
            /** construct the response **/
            envelope = factory.getDefaultEnvelope();
            Binding binding = BindingManager.getBinding(bindingName, this.serviceClass);
            OMElement msgElement = binding.toOM(response, altNs);
            envelope.getBody().addChild(msgElement);
        } catch (JiBXException e) {
            LOG.error(e, e);
        }
        LOG.info("[" + serviceClass.getSimpleName() + ":" + methodName + "] Returning message of type "
                + response.getClass().getSimpleName());
        return envelope;
    }

    private MuleMessage invokeService(final String methodName, final EucalyptusMessage wrappedParam)
            throws AxisFault {
        LOG.info("[" + serviceClass.getSimpleName() + ":" + methodName + "] Invoking method " + methodName);
        MuleMessage message = null;
        try {
            message = this.msgReceiver.routeMessage(
                    new DefaultMuleMessage(this.msgReceiver.getConnector().getMessageAdapter(wrappedParam)), true);
        } catch (MuleException wsException) {
            MuleException umoException = ExceptionHelper.getRootMuleException(wsException);
            if (umoException.getCause() != null)
                throw AxisFault.makeFault(umoException.getCause());
            else
                throw AxisFault.makeFault(umoException);
        }
        return message;
    }

    private EucalyptusMessage bindMessage(final String methodName, final Class serviceMethodArgType,
            final OMElement msgBodyOm, final String bindingName) throws AxisFault {
        EucalyptusMessage wrappedParam = null;
        try {
            /** unmarshall the incoming message **/
            Binding msgBinding = BindingManager.getBinding(bindingName, this.serviceClass);
            wrappedParam = (EucalyptusMessage) msgBinding.fromOM(msgBodyOm, serviceMethodArgType);
            LOG.info("[" + serviceClass.getSimpleName() + ":" + methodName + "] Unmarshalled parameter type "
                    + wrappedParam.getClass());
        } catch (JiBXException e) {
            LOG.error(e, e);
            throw AxisFault.makeFault(e);
        }
        return wrappedParam;
    }

    private String findBindingName(final OMElement msgBodyOm) {
        String bindingName = null;
        String nsUri = msgBodyOm.getNamespace().getNamespaceURI();
        bindingName = BindingUtil.sanitizeNamespace(nsUri);
        return bindingName;
    }

    private Class findArgumentClass(final String methodName) throws AxisFault {
        Class serviceMethodArgType = null;
        try {
            serviceMethodArgType = Class.forName("edu.ucsb.eucalyptus.msgs." + methodName + "Type");
        } catch (ClassNotFoundException e) {
            throw new AxisFault("Argument type not found: edu.ucsb.eucalyptus.msgs." + methodName + "Type");
        }
        return serviceMethodArgType;
    }

    private String findOperation(final MessageContext msgContext)
            throws AxisFault { /**Find the axisOperation that has been set by the Dispatch phase.**/
        AxisOperation op = msgContext.getOperationContext().getAxisOperation();
        String methodName = null;
        if (op == null || (op.getName() == null)
                || ((methodName = JavaUtils.xmlNameToJava(op.getName().getLocalPart())) == null))
            throw new AxisFault("Operation not found: " + op.getName());
        return methodName;
    }

    private void verifyUser(MessageContext msgContext, EucalyptusMessage msg) throws EucalyptusCloudException {
        Vector<WSHandlerResult> wsResults = (Vector<WSHandlerResult>) msgContext
                .getProperty(WSHandlerConstants.RECV_RESULTS);
        for (WSHandlerResult wsResult : wsResults)
            if (wsResult.getResults() != null)
                for (WSSecurityEngineResult engResult : (Vector<WSSecurityEngineResult>) wsResult.getResults())
                    if (engResult.containsKey(WSSecurityEngineResult.TAG_X509_CERTIFICATE)) {
                        X509Certificate cert = (X509Certificate) engResult
                                .get(WSSecurityEngineResult.TAG_X509_CERTIFICATE);
                        msg = this.msgReceiver.getProperties().getAuthenticator().authenticate(cert, msg);
                    }
    }
}