All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.barchart.http.server.HttpRequestChannelHandler Maven / Gradle / Ivy

There is a newer version: 1.1.6
Show newest version
/**
 * Copyright (C) 2011-2013 Barchart, Inc. 
 *
 * All rights reserved. Licensed under the OSI BSD License.
 *
 * http://www.opensource.org/licenses/bsd-license.php
 */
package com.barchart.http.server;

import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundMessageHandlerAdapter;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.util.AttributeKey;

import com.barchart.http.request.RequestHandler;
import com.barchart.http.request.RequestHandlerMapping;

/**
 * Netty channel handler for routing inbound requests to the proper
 * RequestHandler.
 */
@Sharable
public class HttpRequestChannelHandler extends
		ChannelInboundMessageHandlerAdapter {

	public static final AttributeKey ATTR_RESPONSE =
			new AttributeKey("response");

	private final HttpServerConfig config;
	private final ServerMessagePool messagePool;

	public HttpRequestChannelHandler(final HttpServerConfig config_) {
		super();
		config = config_;
		messagePool = new ServerMessagePool(config.maxConnections());
	}

	@Override
	public void messageReceived(final ChannelHandlerContext ctx,
			final FullHttpRequest msg) throws Exception {

		// Create request handler
		final RequestHandlerMapping mapping =
				config.getRequestMapping(msg.getUri());

		if (mapping == null) {
			sendNotFound(ctx, msg);
			return;
		}

		final String relativePath =
				msg.getUri().substring(mapping.path().length());

		// Create request/response
		final PooledServerRequest request = messagePool.getRequest();
		request.init(ctx.channel(), msg, relativePath);

		final RequestHandler handler = mapping.handler(request);

		final PooledServerResponse response = messagePool.getResponse();
		response.init(ctx, this, handler, request, config.logger());

		// Store in ChannelHandlerContext for future reference
		ctx.attr(ATTR_RESPONSE).set(response);

		try {

			// Process request
			handler.onRequest(request, response);

		} catch (final Throwable t) {

			// Catch server errors
			response.setStatus(HttpResponseStatus.INTERNAL_SERVER_ERROR);

			try {
				config.errorHandler().onError(request, response, t);
			} catch (final Throwable t2) {
				response.write(t.getClass()
						+ " was thrown while processing this request.  Additionally, "
						+ t2.getClass()
						+ " was thrown while handling this exception.");
			}

			config.logger().error(request, response, t);

		} finally {

			// If handler did not request async response, finish request
			if (!response.isFinished() && !response.isSuspended()) {
				response.finish();
			}

		}

	}

	private void sendNotFound(final ChannelHandlerContext ctx,
			final FullHttpRequest msg) throws Exception {

		// Create request/response
		final PooledServerRequest request = messagePool.getRequest();
		request.init(ctx.channel(), msg, msg.getUri());

		final PooledServerResponse response = messagePool.getResponse();
		response.init(ctx, this, null, request, config.logger());
		response.setStatus(HttpResponseStatus.NOT_FOUND);

		// Store in ChannelHandlerContext for future reference
		ctx.attr(ATTR_RESPONSE).set(response);

		try {

			// Process request
			config.errorHandler().onError(request, response, null);

		} catch (final Throwable e) {

			response.write("The requested URL was not found.  Additionally, "
					+ e.getClass() + " was thrown while handling this error.");

		} finally {

			// If handler did not request async response, finish request
			if (!response.isFinished() && !response.isSuspended()) {
				response.finish();
			}

		}

	}

	@Override
	public void channelInactive(final ChannelHandlerContext ctx) {

		final PooledServerResponse response = ctx.attr(ATTR_RESPONSE).get();

		if (response != null) {

			try {

				if (!response.isFinished()) {

					response.close();

					final RequestHandler handler = response.handler();

					if (handler != null) {
						handler.onAbort(response.request(), response);
					}

				}

			} finally {

				freeHandlers(ctx);

			}

		}

	}

	@Override
	public void exceptionCaught(final ChannelHandlerContext ctx,
			final Throwable exception) throws Exception {

		final PooledServerResponse response = ctx.attr(ATTR_RESPONSE).get();

		if (response != null) {

			try {

				try {

					if (!response.isFinished()) {

						response.setStatus(HttpResponseStatus.INTERNAL_SERVER_ERROR);

						config.errorHandler().onError(response.request(),
								response, exception);

						response.close();

						final RequestHandler handler = response.handler();

						if (handler != null) {
							handler.onException(response.request(), response,
									exception);
						}

					}

				} finally {

					config.logger().error(response.request(), response,
							exception);

				}

			} finally {

				freeHandlers(ctx);

			}

		}

	}

	/**
	 * Free any request/response handlers related to the current channel handler
	 * context.
	 */
	public void freeHandlers(final ChannelHandlerContext ctx) {

		final PooledServerResponse response =
				ctx.attr(ATTR_RESPONSE).getAndRemove();

		if (response != null) {

			try {

				final RequestHandler handler = response.handler();

				if (handler != null) {
					handler.onComplete(response.request(), response);
				}

			} finally {

				messagePool.makeAvailable(response.request());

				response.close();

				messagePool.makeAvailable(response);

			}

		}

	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy