com.netflix.recipes.rss.netty.NettyHandlerContainer.java Source code

Java tutorial

Introduction

Here is the source code for com.netflix.recipes.rss.netty.NettyHandlerContainer.java

Source

/**
 * The MIT License
 *
 * Copyright (c) 2009 Carl Bystrom
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 * Snagged from the following RenderShark component:
 * https://code.google.com/p/rendershark
 * /source/browse/trunk/rendershark/src/main
 * /java/com/sun/jersey/server/impl/container/netty/NettyHandlerContainer.java
 *
 */
package com.netflix.recipes.rss.netty;

import com.sun.jersey.api.core.ResourceConfig;
import com.sun.jersey.core.header.InBoundHeaders;
import com.sun.jersey.spi.container.ContainerRequest;
import com.sun.jersey.spi.container.ContainerResponse;
import com.sun.jersey.spi.container.ContainerResponseWriter;
import com.sun.jersey.spi.container.WebApplication;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufInputStream;
import io.netty.buffer.ByteBufOutputStream;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpMessage;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;

import java.io.IOException;
import java.io.OutputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Sharable
public class NettyHandlerContainer extends ChannelInboundHandlerAdapter {
    public static final String PROPERTY_BASE_URI = "com.sun.jersey.server.impl.container.netty.baseUri";

    private final WebApplication application;
    private final String baseUri;

    NettyHandlerContainer(WebApplication application, ResourceConfig resourceConfig) {
        this.application = application;
        this.baseUri = (String) resourceConfig.getProperty(PROPERTY_BASE_URI);
    }

    private final static class Writer implements ContainerResponseWriter {
        private final ChannelHandlerContext ctx;
        private DefaultFullHttpResponse response;

        private Writer(ChannelHandlerContext ctx) {
            this.ctx = ctx;
        }

        public OutputStream writeStatusAndHeaders(long contentLength, ContainerResponse cResponse)
                throws IOException {
            ByteBuf buffer = Unpooled.buffer();
            response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_0,
                    HttpResponseStatus.valueOf(cResponse.getStatus()), buffer);
            for (Map.Entry<String, List<Object>> e : cResponse.getHttpHeaders().entrySet()) {
                List<String> values = new ArrayList<String>();
                for (Object v : e.getValue())
                    values.add(ContainerResponse.getHeaderValue(v));
                response.headers().set(e.getKey(), values);
            }
            return new ByteBufOutputStream(buffer);
        }

        public void finish() throws IOException {
            // Streaming is not supported. Entire response will be written
            // downstream once finish() is called.
            final ChannelFuture f = ctx.writeAndFlush(response);
            f.addListener(ChannelFutureListener.CLOSE);
        }
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws URISyntaxException, IOException {
        if (msg instanceof FullHttpRequest) {
            FullHttpRequest httpRequest = (FullHttpRequest) msg;
            String base = getBaseUri(httpRequest);
            URI baseUri = new URI(base);
            URI requestUri = new URI(base.substring(0, base.length() - 1) + httpRequest.getUri());
            ContainerRequest cRequest = new ContainerRequest(application, httpRequest.getMethod().name(), baseUri,
                    requestUri, getHeaders(httpRequest), new ByteBufInputStream(httpRequest.content()));
            application.handleRequest(cRequest, new Writer(ctx));
        }
    }

    private String getBaseUri(HttpMessage httpMessage) {
        if (baseUri != null) {
            return baseUri;
        }
        return "http://" + HttpHeaders.getHost(httpMessage) + "/";
    }

    private InBoundHeaders getHeaders(FullHttpRequest httpRequest) {
        InBoundHeaders headers = new InBoundHeaders();
        HttpHeaders httpHeaders = httpRequest.headers();
        for (String name : httpHeaders.names()) {
            headers.put(name, httpHeaders.getAll(name));
        }
        return headers;
    }

}