com.seagate.kinetic.simulator.io.provider.nio.http.HttpMessageServiceHandler.java Source code

Java tutorial

Introduction

Here is the source code for com.seagate.kinetic.simulator.io.provider.nio.http.HttpMessageServiceHandler.java

Source

/**
 * Copyright 2013-2015 Seagate Technology LLC.
 *
 * This Source Code Form is subject to the terms of the Mozilla
 * Public License, v. 2.0. If a copy of the MPL was not
 * distributed with this file, You can obtain one at
 * https://mozilla.org/MP:/2.0/.
 * 
 * This program is distributed in the hope that it will be useful,
 * but is provided AS-IS, WITHOUT ANY WARRANTY; including without 
 * the implied warranty of MERCHANTABILITY, NON-INFRINGEMENT or 
 * FITNESS FOR A PARTICULAR PURPOSE. See the Mozilla Public 
 * License for more details.
 *
 * See www.openkinetic.org for more project information
 */
package com.seagate.kinetic.simulator.io.provider.nio.http;

import static io.netty.handler.codec.http.HttpHeaders.getHost;
import static io.netty.handler.codec.http.HttpHeaders.Names.CONNECTION;
import static io.netty.handler.codec.http.HttpHeaders.Names.CONTENT_LENGTH;
import static io.netty.handler.codec.http.HttpHeaders.Names.CONTENT_TYPE;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpContent;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.handler.codec.http.QueryStringDecoder;

import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.google.protobuf.ByteString;
import com.google.protobuf.InvalidProtocolBufferException;
import com.seagate.kinetic.common.lib.KineticMessage;
import com.seagate.kinetic.proto.Kinetic.Command;
import com.seagate.kinetic.proto.Kinetic.Message;
import com.seagate.kinetic.proto.KineticIo.ExtendedMessage;
import com.seagate.kinetic.simulator.io.provider.spi.MessageService;

/**
 *
 * Please note: This class is for evaluation only and in prototype state.
 *
 * @author chiaming
 *
 */
public class HttpMessageServiceHandler extends SimpleChannelInboundHandler<Object> {

    private static final Logger logger = Logger.getLogger(HttpMessageServiceHandler.class.getName());

    private MessageService lcservice = null;

    public HttpMessageServiceHandler(MessageService lcservice2) {
        this.lcservice = lcservice2;
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {

        int contentLength = 0;

        if (msg instanceof HttpRequest) {
            HttpRequest request = (HttpRequest) msg;

            logger.finest("protocol version: " + request.getProtocolVersion());

            logger.finest("host: " + getHost(request, "unknown"));

            logger.finest("REQUEST_URI: " + request.getUri());

            List<Map.Entry<String, String>> headers = request.headers().entries();

            String lenstr = request.headers().get(HttpHeaders.Names.CONTENT_LENGTH);
            contentLength = Integer.parseInt(lenstr);

            logger.finest("content length=" + contentLength);

            if (!headers.isEmpty()) {
                for (Map.Entry<String, String> h : request.headers().entries()) {
                    String key = h.getKey();
                    String value = h.getValue();
                    logger.finest("HEADER: " + key + " = " + value);
                }
            }

            QueryStringDecoder queryStringDecoder = new QueryStringDecoder(request.getUri());
            Map<String, List<String>> params = queryStringDecoder.parameters();
            if (!params.isEmpty()) {
                for (Entry<String, List<String>> p : params.entrySet()) {
                    String key = p.getKey();
                    List<String> vals = p.getValue();
                    for (String val : vals) {
                        logger.finest("PARAM: " + key + " = " + val);
                    }
                }

            }

        }

        // create extended builder
        ExtendedMessage.Builder extendedMessage = ExtendedMessage.newBuilder();

        if (msg instanceof HttpContent) {

            HttpContent httpContent = (HttpContent) msg;

            ByteBuf content = httpContent.content();
            if (content.isReadable()) {

                byte[] body = new byte[contentLength];
                content.getBytes(0, body);

                // read from serialized bytes
                extendedMessage.mergeFrom(body);
            }

            // build message
            ExtendedMessage extended = extendedMessage.build();

            if (logger.isLoggable(Level.FINEST)) {
                logger.finest("received request: " + extended);
            }

            // create kinetic message for processing
            KineticMessage km = new KineticMessage();

            // set interface message
            km.setMessage(extended.getInterfaceMessage());

            // get command bytes
            ByteString commandBytes = extendedMessage.getInterfaceMessage().getCommandBytes();

            // build command
            Command.Builder commandBuilder = Command.newBuilder();

            try {
                commandBuilder.mergeFrom(commandBytes);
                km.setCommand(commandBuilder.build());
            } catch (InvalidProtocolBufferException e) {
                logger.log(Level.WARNING, e.getMessage(), e);
            }

            // set value
            if (extended.hasValue()) {
                km.setValue(extended.getValue().toByteArray());
            }

            // process request
            KineticMessage kmresp = this.lcservice.processRequest(km);

            // construct response message
            ExtendedMessage.Builder extendedResponse = ExtendedMessage.newBuilder();

            // set interface message
            extendedResponse.setInterfaceMessage((Message.Builder) kmresp.getMessage());

            // set value
            if (kmresp.getValue() != null) {
                extendedResponse.setValue(ByteString.copyFrom(kmresp.getValue()));
            }

            // get serialized value
            ByteBuf data = Unpooled.copiedBuffer(extendedResponse.build().toByteArray());

            FullHttpResponse httpResponse = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK,
                    data);

            httpResponse.headers().set(CONTENT_TYPE, "application/octet-stream");

            httpResponse.headers().set(HttpHeaders.Names.CONTENT_ENCODING, HttpHeaders.Values.BINARY);

            httpResponse.headers().set(CONTENT_LENGTH, httpResponse.content().readableBytes());

            httpResponse.headers().set(CONNECTION, HttpHeaders.Values.KEEP_ALIVE);

            // send response message
            ctx.writeAndFlush(httpResponse);

            if (logger.isLoggable(Level.FINEST)) {
                logger.finest("wrote and flushed response: " + kmresp);
            }
        }
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        ctx.flush();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        logger.log(Level.WARNING, "Unexpected exception from downstream.", cause);
        ctx.close();
    }

}