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

Java tutorial

Introduction

Here is the source code for com.eucalyptus.ws.handlers.IoBindingHandler.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.regex.Pattern;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMNamespace;
import org.apache.log4j.Logger;
import com.eucalyptus.binding.Binding;
import com.eucalyptus.binding.BindingException;
import com.eucalyptus.binding.BindingManager;
import com.eucalyptus.component.ComponentId;
import com.eucalyptus.context.Context;
import com.eucalyptus.context.Contexts;
import com.eucalyptus.records.Logs;
import com.eucalyptus.util.Exceptions;
import com.eucalyptus.ws.IoMessage;
import com.eucalyptus.ws.WebServicesException;
import edu.ucsb.eucalyptus.msgs.BaseMessage;
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.FullHttpMessage;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.HttpResponseStatus;

/**
 *
 */
@ChannelHandler.Sharable
public class IoBindingHandler extends ChannelDuplexHandler {

    private static Logger LOG = Logger.getLogger(BindingHandler.class);

    private final IoBindingHandler.BindingHandlerContext context;

    public static abstract class BindingHandlerContext {
        public boolean namespaceMismatch(final String namespace) {
            return false;
        }

        public void updateBindingForNamespace(final String namespace) {
        }

        public boolean updateForDefaultBinding(final String namespace) {
            return false;
        }

        public String getNamespace() {
            return null;
        }

        public abstract Binding getBinding();
    }

    public static class StaticBindingHandlerContext extends IoBindingHandler.BindingHandlerContext {
        private final Binding binding;

        public StaticBindingHandlerContext(final Binding binding) {
            this.binding = binding;
        }

        @Override
        public Binding getBinding() {
            return binding;
        }
    }

    public static class DynamicBindingHandlerContext extends IoBindingHandler.BindingHandlerContext {
        private Binding binding;
        private String namespace;
        private final Binding defaultBinding;
        private final Pattern namespacePattern;
        private final Class<? extends ComponentId> component;

        public DynamicBindingHandlerContext(final Binding binding, final Pattern namespacePattern,
                final Class<? extends ComponentId> component) {
            this.binding = binding;
            this.defaultBinding = binding;
            this.namespacePattern = namespacePattern;
            this.component = component;
        }

        @Override
        public boolean namespaceMismatch(final String namespace) {
            return namespacePattern != null && !namespacePattern.matcher(namespace).matches();
        }

        @Override
        public void updateBindingForNamespace(final String namespace) {
            this.binding = BindingManager.getBinding(namespace, component);
        }

        @Override
        public boolean updateForDefaultBinding(final String namespace) {
            if (this.defaultBinding != null) {
                this.namespace = namespace;
                this.binding = this.defaultBinding;
                return true;
            }
            return false;
        }

        @Override
        public String getNamespace() {
            return namespace;
        }

        @Override
        public Binding getBinding() {
            return binding;
        }
    }

    /**
     * Create a static context which will always use the given binding.
     *
     * <p>A BindingHandler created with such a context can safely be cached</p>
     */
    public static IoBindingHandler.BindingHandlerContext context(final Binding binding) {
        return new IoBindingHandler.StaticBindingHandlerContext(binding);

    }

    /**
     * Create a dynamic context which will always use the given binding.
     *
     * <p>A BindingHandler created with such a context should only be used once
     * and should not be cached.</p>
     */
    public static IoBindingHandler.BindingHandlerContext context(final Binding binding,
            final Pattern namespacePattern, final Class<? extends ComponentId> component) {
        return new IoBindingHandler.DynamicBindingHandlerContext(binding, namespacePattern, component);

    }

    public IoBindingHandler(final IoBindingHandler.BindingHandlerContext context) {
        this.context = context;
    }

    @Override
    public void channelRead(final ChannelHandlerContext ctx, final Object msgObj) throws Exception {
        if (msgObj instanceof IoMessage) {
            IoMessage ioMessage = (IoMessage) msgObj;
            BaseMessage msg = null;
            Class msgType = null;
            String namespace = null;
            try {
                OMElement elem = ioMessage.getOmMessage();
                OMNamespace omNs = elem.getNamespace();
                namespace = omNs.getNamespaceURI();
                if (context.namespaceMismatch(namespace)) {
                    throw new WebServicesException("Invalid request");
                }
                context.updateBindingForNamespace(namespace);
                msgType = this.context.getBinding().getElementClass(ioMessage.getOmMessage().getLocalName());
            } catch (BindingException ex) {
                if (this.context.updateForDefaultBinding(namespace)) {
                    try {
                        msgType = this.context.getBinding()
                                .getElementClass(ioMessage.getOmMessage().getLocalName());
                    } catch (Exception ex1) {
                        throw new WebServicesException("Failed to find binding for namespace: " + namespace
                                + " due to: " + ex.getMessage(), ex);
                    }
                }
            } catch (Exception e1) {
                LOG.error(e1.getMessage() + " while attempting to bind: " + ioMessage.getOmMessage());
                Logs.extreme().error(ioMessage.getSoapEnvelope().toString(), e1);
                if (this.context.getBinding() == null) {
                    throw new WebServicesException(e1);
                } else {
                    throw new WebServicesException(
                            "Failed to find binding for namespace: " + namespace + " due to: " + e1.getMessage(),
                            e1);
                }
            }
            try {
                if (ioMessage.isRequest()) {
                    if (msgType != null) {
                        msg = (BaseMessage) this.context.getBinding().fromOM(ioMessage.getOmMessage(), msgType);
                    } else {
                        msg = (BaseMessage) this.context.getBinding().fromOM(ioMessage.getOmMessage());
                    }
                } else {
                    msg = (BaseMessage) this.context.getBinding().fromOM(ioMessage.getOmMessage());
                }
            } catch (Exception e1) {
                try {
                    msg = (BaseMessage) this.context.getBinding().fromOM(ioMessage.getOmMessage(),
                            this.context.getNamespace());
                } catch (Exception ex) {
                    throw new WebServicesException(e1);
                }
            }

            // in case the base message has request ID in its correlation ID prefix,
            // we should reset the correlation ID using the request ID
            if (ioMessage.getCorrelationId() != null && msg.getCorrelationId() != null && msg.hasRequestId()) {
                try {
                    final Context context = Contexts.lookup(ioMessage.getCorrelationId());
                    // reset correlation ID
                    msg.regardingRequestId(msg.getCorrelationId());
                    ioMessage.setCorrelationId(msg.getCorrelationId());
                    Contexts.update(context, ioMessage.getCorrelationId());
                } catch (final Exception ex) {
                    ;
                }
            }
            msg.setCorrelationId(ioMessage.getCorrelationId());
            ioMessage.setMessage(msg);
        }
        super.channelRead(ctx, msgObj);
    }

    @Override
    public void write(final ChannelHandlerContext ctx, final Object msgObj, final ChannelPromise promise)
            throws Exception {
        if (msgObj instanceof IoMessage) {
            IoMessage ioMessage = (IoMessage) msgObj;
            OMElement omElem;
            if (ioMessage.getMessage() instanceof EucalyptusErrorMessageType || ioMessage.getMessage() == null) {
                return;
            } else if (ioMessage.getMessage() instanceof ExceptionResponseType) {
                final FullHttpMessage httpMessage = ioMessage.getHttpMessage();
                ExceptionResponseType msg = (ExceptionResponseType) ioMessage.getMessage();
                String createFaultDetails = Logs.isExtrrreeeme() ? Exceptions.string(msg.getException())
                        : msg.getException().getMessage();
                omElem = Binding.createFault(msg.getRequestType(), msg.getMessage(), createFaultDetails);
                if (httpMessage instanceof HttpResponse) {
                    ((HttpResponse) httpMessage).setStatus(HttpResponseStatus.valueOf(msg.getHttpStatusCode()));
                }
            } else {
                try {
                    omElem = this.context.getBinding().toOM(ioMessage.getMessage(), this.context.getNamespace());
                } catch (BindingException ex) {
                    omElem = BindingManager.getDefaultBinding().toOM(ioMessage.getMessage());
                } catch (Exception ex) {
                    Logs.exhaust().debug(ex, ex);
                    throw ex;
                }
            }
            ioMessage.setOmMessage(omElem);
        }
        super.write(ctx, msgObj, promise);
    }
}