Java tutorial
/* KIARA - Middleware for efficient and QoS/Security-aware invocation of services and exchange of messages * * Copyright (C) 2014 German Research Center for Artificial Intelligence (DFKI) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see <http://www.gnu.org/licenses/>. */ /* * Copyright 2012 The Netty Project * * The Netty Project 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 de.dfki.kiara.util; import io.netty.bootstrap.Bootstrap; import io.netty.buffer.ByteBuf; import io.netty.channel.Channel; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.EventLoopGroup; import io.netty.channel.SimpleChannelInboundHandler; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.codec.http.DefaultFullHttpRequest; import io.netty.handler.codec.http.HttpClientCodec; import io.netty.handler.codec.http.HttpContent; import io.netty.handler.codec.http.HttpContentDecompressor; import io.netty.handler.codec.http.HttpHeaders; import io.netty.handler.codec.http.HttpMethod; import io.netty.handler.codec.http.HttpObject; 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.LastHttpContent; import io.netty.handler.ssl.SslContext; import io.netty.handler.ssl.util.InsecureTrustManagerFactory; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.nio.ByteBuffer; /** * * @author Dmitri Rubinstein <dmitri.rubinstein@dfki.de> */ public class URILoader { static class HttpClientHandler extends SimpleChannelInboundHandler<HttpObject> { private Throwable error = null; private HttpResponseStatus status = null; private String contentType = null; private final NoCopyByteArrayOutputStream bout = new NoCopyByteArrayOutputStream(1024); public Throwable getError() { return error; } public byte[] getContent() { return bout.toByteArray(); } public int getContentSize() { return bout.size(); } public HttpResponseStatus getStatus() { return status; } public String getContentType() { return contentType; } @Override public void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception { if (msg instanceof HttpResponse) { HttpResponse response = (HttpResponse) msg; status = response.getStatus(); if (!response.headers().isEmpty()) { contentType = response.headers().get("Content-Type"); } } if (msg instanceof HttpContent) { HttpContent content = (HttpContent) msg; ByteBuf buf = content.content(); if (buf.isReadable()) { if (buf.hasArray()) { bout.write(buf.array(), buf.readerIndex(), buf.readableBytes()); } else { byte[] bytes = new byte[buf.readableBytes()]; buf.getBytes(buf.readerIndex(), bytes); bout.write(bytes); } } if (content instanceof LastHttpContent) { ctx.close(); bout.flush(); } } } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { error = cause; ctx.close(); } } static class HttpClientInitializer extends ChannelInitializer<SocketChannel> { private final SslContext sslCtx; private final HttpClientHandler handler; public HttpClientInitializer(SslContext sslCtx, HttpClientHandler handler) { this.sslCtx = sslCtx; this.handler = handler; } @Override public void initChannel(SocketChannel ch) { ChannelPipeline p = ch.pipeline(); // Enable HTTPS if necessary. if (sslCtx != null) { p.addLast(sslCtx.newHandler(ch.alloc())); } p.addLast(new HttpClientCodec()); // Remove the following line if you don't want automatic content decompression. p.addLast(new HttpContentDecompressor()); // Uncomment the following line if you don't want to handle HttpContents. //p.addLast(new HttpObjectAggregator(1048576)); p.addLast(handler); } } public static String load(String uriStr, String charsetName) throws URISyntaxException, IOException { ByteBuffer buf = load(new URI(uriStr)); return new String(buf.array(), buf.arrayOffset(), buf.remaining(), charsetName); } public static String load(URI uri, String charsetName) throws IOException { ByteBuffer buf = load(uri); return new String(buf.array(), buf.arrayOffset(), buf.remaining(), charsetName); } public static byte[] load(String uriStr) throws URISyntaxException, IOException { ByteBuffer buf = load(new URI(uriStr)); byte[] bytes = new byte[buf.remaining()]; buf.get(bytes, 0, bytes.length); return bytes; } public static ByteBuffer load(URI uri) throws IOException { String scheme = uri.getScheme() == null ? "http" : uri.getScheme(); String host = uri.getHost() == null ? "127.0.0.1" : uri.getHost(); int port = uri.getPort(); if (port == -1) { if ("http".equalsIgnoreCase(scheme)) { port = 80; } else if ("https".equalsIgnoreCase(scheme)) { port = 443; } } if (!"http".equalsIgnoreCase(scheme) && !"https".equalsIgnoreCase(scheme)) { throw new IOException("Only HTTP(S) is supported."); } // Configure SSL context if necessary. final boolean ssl = "https".equalsIgnoreCase(scheme); final SslContext sslCtx; if (ssl) { sslCtx = SslContext.newClientContext(InsecureTrustManagerFactory.INSTANCE); } else { sslCtx = null; } // Configure the client. EventLoopGroup group = new NioEventLoopGroup(); HttpClientHandler handler = new HttpClientHandler(); try { Bootstrap b = new Bootstrap(); b.group(group).channel(NioSocketChannel.class).handler(new HttpClientInitializer(sslCtx, handler)); // Make the connection attempt. Channel ch = b.connect(host, port).sync().channel(); // Prepare the HTTP request. HttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, uri.getRawPath()); request.headers().set(HttpHeaders.Names.HOST, host); request.headers().set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.CLOSE); request.headers().set(HttpHeaders.Names.ACCEPT_ENCODING, HttpHeaders.Values.GZIP); // Send the HTTP request. ch.writeAndFlush(request); // Wait for the server to close the connection. ch.closeFuture().sync(); } catch (InterruptedException ex) { throw new IOException("Loading interrupted", ex); } finally { // Shut down executor threads to exit. group.shutdownGracefully(); } Throwable error = handler.getError(); if (error != null) throw new IOException("Could not load content", error); if (!HttpResponseStatus.OK.equals(handler.getStatus())) throw new IOException("HTTP response error: " + handler.getStatus()); return ByteBuffer.wrap(handler.getContent(), 0, handler.getContentSize()); } }