com.eucalyptus.ws.handlers.IoSoapHandler.java Source code

Java tutorial

Introduction

Here is the source code for com.eucalyptus.ws.handlers.IoSoapHandler.java

Source

/*************************************************************************
 * (c) Copyright 2016 Hewlett Packard Enterprise Development Company LP
 *
 * 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; version 3 of the License.
 *
 * This program 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/.
 ************************************************************************/
package com.eucalyptus.ws.handlers;

import java.util.Iterator;
import java.util.List;
import java.util.function.Supplier;
import javax.annotation.Nullable;
import javax.xml.soap.SOAPConstants;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.soap.SOAPEnvelope;
import org.apache.axiom.soap.SOAPFactory;
import org.apache.axiom.soap.SOAPFault;
import org.apache.axiom.soap.SOAPHeader;
import org.apache.axiom.soap.SOAPHeaderBlock;
import com.eucalyptus.binding.Binding;
import com.eucalyptus.binding.HoldMe;
import com.eucalyptus.records.Logs;
import com.eucalyptus.util.Exceptions;
import com.eucalyptus.util.Pair;
import com.eucalyptus.ws.EucalyptusRemoteFault;
import com.eucalyptus.ws.IoMessage;
import com.google.common.collect.Lists;
import edu.ucsb.eucalyptus.msgs.EucalyptusErrorMessageType;
import edu.ucsb.eucalyptus.msgs.ExceptionResponseType;
import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.handler.codec.http.HttpMessage;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.HttpResponseStatus;
import javaslang.control.Option;

/**
 * SOAP object model handler
 */
@SuppressWarnings("ThrowableResultOfMethodCallIgnored")
@ChannelHandler.Sharable
public class IoSoapHandler extends ChannelDuplexHandler {

    /**
     * Handle incoming soap model
     */
    @Override
    public void channelRead(final ChannelHandlerContext ctx, final Object msg) throws Exception {
        if (msg instanceof IoMessage) {
            final IoMessage ioMessage = IoMessage.class.cast(msg);
            final SOAPEnvelope env = ioMessage.getSoapEnvelope();
            if (env != null && !env.hasFault()) {
                ioMessage.setOmMessage(env.getBody().getFirstElement());
            } else {
                final Supplier<Integer> statusCodeSupplier = () -> getStatus(ioMessage);
                perhapsFault(env, statusCodeSupplier);
            }
        }
        super.channelRead(ctx, msg);
    }

    /**
     * Create outbound soap model
     */
    @Override
    public void write(final ChannelHandlerContext ctx, final Object msg, final ChannelPromise promise)
            throws Exception {
        if (msg instanceof IoMessage) {
            final IoMessage ioMessage = IoMessage.class.cast(msg);
            final HttpMessage httpMessage = ioMessage.getHttpMessage();
            final Option<Pair<SOAPEnvelope, Integer>> soapEnvelopeOption = IoSoapHandler
                    .perhapsBuildFault(ioMessage.getMessage());

            if (soapEnvelopeOption.isDefined()) {
                ioMessage.setSoapEnvelope(soapEnvelopeOption.get().getLeft());
                if (httpMessage instanceof HttpResponse) {
                    ((HttpResponse) httpMessage)
                            .setStatus(HttpResponseStatus.valueOf(soapEnvelopeOption.get().getRight()));
                }
            } else {
                ioMessage.setSoapEnvelope(buildSoapEnvelope(ioMessage.getOmMessage()));
            }
        }
        super.write(ctx, msg, promise);
    }

    @Nullable
    private static Integer getStatus(final IoMessage message) {
        return message.getHttpMessage() instanceof HttpResponse
                ? ((HttpResponse) message.getHttpMessage()).getStatus().code()
                : null;
    }

    static SOAPEnvelope buildSoapEnvelope(final OMElement body) {
        final SOAPFactory factory = HoldMe.getOMSOAP11Factory();
        final SOAPEnvelope soapEnvelope = factory
                .createSOAPEnvelope(factory.createOMNamespace(SOAPConstants.URI_NS_SOAP_1_1_ENVELOPE, ""));
        factory.createSOAPHeader(soapEnvelope);
        factory.createSOAPBody(soapEnvelope).addChild(body);
        return soapEnvelope;
    }

    static Option<Pair<SOAPEnvelope, Integer>> perhapsBuildFault(final Object msg) {
        Option<Pair<SOAPEnvelope, Integer>> soapEnvelopeOption = Option.none();
        if (msg instanceof EucalyptusErrorMessageType) {
            EucalyptusErrorMessageType errMsg = (EucalyptusErrorMessageType) msg;
            soapEnvelopeOption = Option.some(
                    Pair.of(Binding.createFault(errMsg.getSource(), errMsg.getMessage(), errMsg.getStatusMessage()),
                            org.jboss.netty.handler.codec.http.HttpResponseStatus.BAD_REQUEST.getCode()));
        } else if (msg instanceof ExceptionResponseType) {
            ExceptionResponseType errMsg = (ExceptionResponseType) msg;
            String createFaultDetails = Logs.isExtrrreeeme() ? Exceptions.string(errMsg.getException())
                    : errMsg.getException().getMessage();
            soapEnvelopeOption = Option.some(
                    Pair.of(Binding.createFault(errMsg.getRequestType(), errMsg.getMessage(), createFaultDetails),
                            errMsg.getHttpStatus().getCode()));
        }
        return soapEnvelopeOption;
    }

    static void perhapsFault(final SOAPEnvelope env, final Supplier<Integer> statusCodeSupplier)
            throws EucalyptusRemoteFault {
        final SOAPHeader header = env.getHeader();
        String action = "ProblemAction";
        String relatesTo = "RelatesTo";
        if (header != null) {
            final List<SOAPHeaderBlock> headers = Lists.newArrayList(header.examineAllHeaderBlocks());
            // :: try to get the fault info from the soap header -- hello there? :://
            for (final SOAPHeaderBlock headerBlock : headers) {
                if (action.equals(headerBlock.getLocalName())) {
                    action = headerBlock.getText();
                } else if (relatesTo.equals(headerBlock.getLocalName())) {
                    relatesTo = headerBlock.getText();
                }
            }
        }
        //faults don't need to have a header.
        // :: process the real fault :://
        final SOAPFault fault = env.getBody().getFault();
        if (fault != null) {
            String faultReason = "";
            final Iterator children = fault.getChildElements();
            while (children.hasNext()) {
                final OMElement child = (OMElement) children.next();
                faultReason += child.getText();
            }
            final String faultCode = fault.getCode().getText();
            faultReason = faultReason.replaceAll(faultCode, "");
            final String faultDetail = fault.getDetail().getText();
            throw new EucalyptusRemoteFault(action, relatesTo, faultCode, faultReason, faultDetail,
                    statusCodeSupplier.get());
        }
    }
}