com.stremebase.examples.todomvc.HttpRouter.java Source code

Java tutorial

Introduction

Here is the source code for com.stremebase.examples.todomvc.HttpRouter.java

Source

/*
 * This file includes source code developed at
 * The Netty Project (http://netty.io/).
 * 
 * Copyright 2015 Olli Niinivaara
 *
 * Olli Niinivaara licenses this file to you under the Apache License,
 * version 2.0 (the "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at:
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */

package com.stremebase.examples.todomvc;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Locale;
import java.util.TimeZone;

import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandler;
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.HttpHeaders;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.handler.codec.http.multipart.Attribute;
import io.netty.handler.codec.http.multipart.DefaultHttpDataFactory;
import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder;
import io.netty.handler.codec.http.multipart.InterfaceHttpData;
import io.netty.handler.codec.http.router.RouteResult;
import io.netty.handler.codec.http.router.Router;
import io.netty.util.CharsetUtil;

import static com.stremebase.examples.todomvc.Todo.*;

@ChannelHandler.Sharable
public class HttpRouter extends SimpleChannelInboundHandler<HttpRequest> {
    public static final String HTTP_DATE_FORMAT = "EEE, dd MMM yyyy HH:mm:ss zzz";
    public static final String HTTP_DATE_GMT_TIMEZONE = "GMT";
    public static final int HTTP_CACHE_SECONDS = 3600;

    public static final SimpleDateFormat dateFormatter = new SimpleDateFormat(HTTP_DATE_FORMAT, Locale.US);
    public static final Calendar time = new GregorianCalendar();

    private final Router<Integer> router;

    public HttpRouter(Router<Integer> router) {
        this.router = router;
        dateFormatter.setTimeZone(TimeZone.getTimeZone(HTTP_DATE_GMT_TIMEZONE));
    }

    @Override
    public void channelRead0(ChannelHandlerContext ctx, HttpRequest req) {
        if (HttpHeaders.is100ContinueExpected(req)) {
            ctx.writeAndFlush(new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.CONTINUE));
            return;
        }

        HttpResponse res = createResponse(req, router);
        flushResponse(ctx, req, res);
    }

    private static HttpResponse createResponse(HttpRequest req, Router<Integer> router) {
        RouteResult<Integer> routeResult = router.route(req.getMethod(), req.getUri());

        Integer request = routeResult.target();

        String data = "";
        String mimeType = "";

        if (request == CSS) {
            data = Todo.getCss();
            mimeType = "text/css";
        } else if (request == ICON) {
            mimeType = "image/x-icon";
        } else if (request == GET) {
            data = Todo.get();
            mimeType = "text/html";
        } else if (request == FILTER) {
            data = Todo.filter(routeResult.pathParams().get("filtertype"));
            mimeType = "text/html";
        } else if (req.getMethod().equals(HttpMethod.POST)) {
            HttpPostRequestDecoder decoder = new HttpPostRequestDecoder(new DefaultHttpDataFactory(false), req);

            Attribute attribute;

            String item_text = null;
            InterfaceHttpData httpData = decoder.getBodyHttpData("item-text");
            if (httpData != null) {
                attribute = (Attribute) httpData;
                try {
                    item_text = attribute.getValue();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            String item_id = null;
            httpData = decoder.getBodyHttpData("item-id");
            if (httpData != null) {
                attribute = (Attribute) httpData;
                try {
                    item_id = attribute.getValue();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (request == POST) {
                if (item_id == null)
                    data = Todo.create(item_text);
                else
                    data = Todo.save(Long.valueOf(item_id), item_text);
            } else if (request == DELETE) {
                data = Todo.delete(Long.valueOf(item_id));
            } else if (request == DELETECOMPLETED) {
                data = Todo.clearCompleted();
            } else if (request == TOGGLESTATUS)
                data = Todo.toggleStatus(Long.valueOf(item_id));

            mimeType = "text/html";
            decoder.destroy();
        }

        FullHttpResponse res;

        if (request == NOTFOUND) {
            res = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.TEMPORARY_REDIRECT);
            res.headers().add(HttpHeaders.Names.LOCATION, "/");
            return res;
        }

        if (request == ICON)
            res = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK,
                    Unpooled.copiedBuffer(Todo.favicon));
        else
            res = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK,
                    Unpooled.copiedBuffer(data, CharsetUtil.UTF_8));

        res.headers().set(HttpHeaders.Names.CONTENT_TYPE, mimeType);
        res.headers().set(HttpHeaders.Names.CONTENT_LENGTH, res.content().readableBytes());
        if (request == CSS || request == ICON)
            setDateAndCacheHeaders(res);

        return res;
    }

    private static ChannelFuture flushResponse(ChannelHandlerContext ctx, HttpRequest req, HttpResponse res) {
        if (!HttpHeaders.isKeepAlive(req)) {
            return ctx.writeAndFlush(res).addListener(ChannelFutureListener.CLOSE);
        } else {
            res.headers().set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.KEEP_ALIVE);
            return ctx.writeAndFlush(res);
        }
    }

    private static void setDateAndCacheHeaders(HttpResponse response) {
        response.headers().set(HttpHeaders.Names.DATE, dateFormatter.format(time.getTime()));
        time.add(Calendar.SECOND, HTTP_CACHE_SECONDS);
        response.headers().set(HttpHeaders.Names.EXPIRES, dateFormatter.format(time.getTime()));
        response.headers().set(HttpHeaders.Names.CACHE_CONTROL, "private, max-age=" + HTTP_CACHE_SECONDS);
    }
}