Java tutorial
/** * This file is part of BungeeJSON. * * BungeeJSON 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, either version 3 of the License, or * (at your option) any later version. * * BungeeJSON 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 BungeeJSON. If not, see <http://www.gnu.org/licenses/>. */ package com.imaginarycode.minecraft.bungeejson.impl.httpserver; import com.google.common.base.Charsets; import com.google.common.collect.HashMultimap; import com.google.common.collect.Multimap; import com.imaginarycode.minecraft.bungeejson.BungeeJSONPlugin; import com.imaginarycode.minecraft.bungeejson.BungeeJSONUtilities; import com.imaginarycode.minecraft.bungeejson.api.ApiRequest; import com.imaginarycode.minecraft.bungeejson.api.RequestHandler; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; import io.netty.handler.codec.http.*; import io.netty.util.CharsetUtil; import java.net.InetSocketAddress; import java.util.List; import java.util.Map; import java.util.logging.Level; public class HttpServerHandler extends SimpleChannelInboundHandler<Object> { private HttpResponse resp; private HttpRequest request; private StringBuilder bodyBuilder = new StringBuilder(); @Override protected void channelRead0(ChannelHandlerContext channelHandlerContext, Object o) throws Exception { if (channelHandlerContext.channel().remoteAddress() instanceof InetSocketAddress) { if (o instanceof HttpRequest) { request = (HttpRequest) o; } if (o instanceof HttpContent) { bodyBuilder.append(((HttpContent) o).content().toString(Charsets.UTF_8)); if (o instanceof LastHttpContent) { channelHandlerContext.channel().writeAndFlush(getResponse(channelHandlerContext, request)); bodyBuilder.delete(0, bodyBuilder.length()); } } } } private HttpResponse getResponse(ChannelHandlerContext channelHandlerContext, HttpRequest hr) { QueryStringDecoder query = new QueryStringDecoder(hr.getUri()); Multimap<String, String> params = createMultimapFromMap(query.parameters()); Object reply; HttpResponseStatus hrs; final RequestHandler handler = BungeeJSONPlugin.getRequestManager().getHandlerForEndpoint(query.path()); if (handler == null) { reply = BungeeJSONUtilities.error("No such endpoint exists."); hrs = HttpResponseStatus.NOT_FOUND; } else { final ApiRequest ar = new HttpServerApiRequest( ((InetSocketAddress) channelHandlerContext.channel().remoteAddress()).getAddress(), params, bodyBuilder.toString()); try { reply = handler.handle(ar); hrs = HttpResponseStatus.OK; } catch (Throwable throwable) { hrs = HttpResponseStatus.INTERNAL_SERVER_ERROR; reply = BungeeJSONUtilities .error("An internal error has occurred. Information has been logged to the console."); BungeeJSONPlugin.getPlugin().getLogger().log(Level.WARNING, "Error while handling " + hr.getUri() + " from " + ar.getRemoteIp(), throwable); } } String json = BungeeJSONPlugin.getPlugin().getGson().toJson(reply); DefaultFullHttpResponse hreply = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, hrs, Unpooled.wrappedBuffer(json.getBytes(CharsetUtil.UTF_8))); // Add a reminder that we're still running the show. hreply.headers().set("Content-Type", "application/json; charset=UTF-8"); hreply.headers().set("Access-Control-Allow-Origin", "*"); hreply.headers().set("Server", "BungeeJSON/0.1"); hreply.headers().set("Content-Length", json.length()); return hreply; } private <K, V> Multimap<K, V> createMultimapFromMap(Map<K, List<V>> map) { Multimap<K, V> multimap = HashMultimap.create(); for (Map.Entry<K, List<V>> entry : map.entrySet()) { multimap.putAll(entry.getKey(), entry.getValue()); } return multimap; } }