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

org.glassfish.grizzly.samples.httpserver.nonblockinghandler.NonBlockingHttpHandlerSample Maven / Gradle / Ivy

There is a newer version: 4.0.2
Show newest version
/*
 * Copyright (c) 2010, 2020 Oracle and/or its affiliates. All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Distribution License v. 1.0, which is available at
 * http://www.eclipse.org/org/documents/edl-v10.php.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

package org.glassfish.grizzly.samples.httpserver.nonblockinghandler;

import java.io.IOException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.glassfish.grizzly.Buffer;
import org.glassfish.grizzly.Connection;
import org.glassfish.grizzly.Grizzly;
import org.glassfish.grizzly.ReadHandler;
import org.glassfish.grizzly.filterchain.BaseFilter;
import org.glassfish.grizzly.filterchain.FilterChainBuilder;
import org.glassfish.grizzly.filterchain.FilterChainContext;
import org.glassfish.grizzly.filterchain.NextAction;
import org.glassfish.grizzly.filterchain.TransportFilter;
import org.glassfish.grizzly.http.HttpClientFilter;
import org.glassfish.grizzly.http.HttpContent;
import org.glassfish.grizzly.http.HttpRequestPacket;
import org.glassfish.grizzly.http.io.NIOReader;
import org.glassfish.grizzly.http.io.NIOWriter;
import org.glassfish.grizzly.http.server.HttpHandler;
import org.glassfish.grizzly.http.server.HttpServer;
import org.glassfish.grizzly.http.server.Request;
import org.glassfish.grizzly.http.server.Response;
import org.glassfish.grizzly.http.server.ServerConfiguration;
import org.glassfish.grizzly.http.util.Header;
import org.glassfish.grizzly.http.util.HeaderValue;
import org.glassfish.grizzly.impl.FutureImpl;
import org.glassfish.grizzly.impl.SafeFutureImpl;
import org.glassfish.grizzly.memory.Buffers;
import org.glassfish.grizzly.memory.MemoryManager;
import org.glassfish.grizzly.nio.transport.TCPNIOTransport;
import org.glassfish.grizzly.nio.transport.TCPNIOTransportBuilder;

/**
 * 

* This example demonstrates the use of a {@link HttpHandler} to echo HTTP POST data sent by * the client, back to the client using non-blocking streams introduced in Grizzly 2.0. *

* *

* The is composed of two main parts (as nested classes of BlockingHttpHandlerSample) *

    *
  • Client: This is a simple HTTP based on the Grizzly * {@link org.glassfish.grizzly.http.HttpClientFilter}. The client uses a custom * {@link org.glassfish.grizzly.filterchain.Filter} on top of the {@link org.glassfish.grizzly.http.HttpClientFilter} to * send the POST and read, and ultimately display, the response from the server. To better demonstrate the * callbacks defined by {@link ReadHandler}, the client will send each data chunk two seconds apart. * *
  • *
  • NoneBlockingEchoHandler: This {@link HttpHandler} is installed to the * {@link org.glassfish.grizzly.http.server.HttpServer} instance and associated with the path /echo. The * handler uses the {@link org.glassfish.grizzly.http.io.NIOReader} returned by * {@link org.glassfish.grizzly.http.server.Request#getReader()}. As data is received asynchronously, the * {@link ReadHandler} callbacks are invoked at this time data is then written to the response.
  • *
*

* */ public class NonBlockingHttpHandlerSample { private static final Logger LOGGER = Grizzly.logger(NonBlockingHttpHandlerSample.class); public static void main(String[] args) { // create a basic server that listens on port 8080. final HttpServer server = HttpServer.createSimpleServer(); final ServerConfiguration config = server.getServerConfiguration(); // Map the path, /echo, to the NonBlockingEchoHandler config.addHttpHandler(new NonBlockingEchoHandler(), "/echo"); try { server.start(); Client client = new Client(); client.run(); } catch (IOException ioe) { LOGGER.log(Level.SEVERE, ioe.toString(), ioe); } finally { server.shutdownNow(); } } // ---------------------------------------------------------- Nested Classes private static final class Client { private static final String HOST = "localhost"; private static final int PORT = 8080; public void run() throws IOException { final FutureImpl completeFuture = SafeFutureImpl.create(); // Build HTTP client filter chain FilterChainBuilder clientFilterChainBuilder = FilterChainBuilder.stateless(); // Add transport filter clientFilterChainBuilder.add(new TransportFilter()); // Add HttpClientFilter, which transforms Buffer <-> HttpContent clientFilterChainBuilder.add(new HttpClientFilter()); // Add ClientFilter clientFilterChainBuilder.add(new ClientFilter(completeFuture)); // Initialize Transport final TCPNIOTransport transport = TCPNIOTransportBuilder.newInstance().build(); // Set filterchain as a Transport Processor transport.setProcessor(clientFilterChainBuilder.build()); try { // start the transport transport.start(); Connection connection = null; // Connecting to a remote Web server Future connectFuture = transport.connect(HOST, PORT); try { // Wait until the client connect operation will be completed // Once connection has been established, the POST will // be sent to the server. connection = connectFuture.get(10, TimeUnit.SECONDS); // Wait no longer than 30 seconds for the response from the // server to be complete. String result = completeFuture.get(30, TimeUnit.SECONDS); // Display the echoed content System.out.println("\nEchoed POST Data: " + result + '\n'); } catch (Exception e) { if (connection == null) { LOGGER.log(Level.WARNING, "Connection failed. Server is not listening."); } else { LOGGER.log(Level.WARNING, "Unexpected error communicating with the server."); } } finally { // Close the client connection if (connection != null) { connection.closeSilently(); } } } finally { // stop the transport transport.shutdownNow(); } } // ------------------------------------------------------ Nested Classes private static final class ClientFilter extends BaseFilter { private static final HeaderValue HOST_HEADER_VALUE = HeaderValue.newHeaderValue(HOST + ':' + PORT).prepare(); private static final String[] CONTENT = { "contentA-", "contentB-", "contentC-", "contentD" }; private final FutureImpl future; private final StringBuilder sb = new StringBuilder(); // ---------------------------------------------------- Constructors private ClientFilter(FutureImpl future) { this.future = future; } // ----------------------------------------- Methods from BaseFilter @SuppressWarnings({ "unchecked" }) @Override public NextAction handleConnect(FilterChainContext ctx) throws IOException { System.out.println("\nClient connected!\n"); HttpRequestPacket request = createRequest(); System.out.println("Writing request:\n"); System.out.println(request.toString()); ctx.write(request); // write the request // for each of the content parts in CONTENT, wrap in a Buffer, // create the HttpContent to wrap the buffer and write the // content. MemoryManager mm = ctx.getConnection().getTransport().getMemoryManager(); for (int i = 0, len = CONTENT.length; i < len; i++) { HttpContent.Builder contentBuilder = request.httpContentBuilder(); Buffer b = Buffers.wrap(mm, CONTENT[i]); contentBuilder.content(b); HttpContent content = contentBuilder.build(); System.out.printf("(Client writing: %s)\n", b.toStringContent()); ctx.write(content); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } // since the request created by createRequest() is chunked, // we need to write the trailer to signify the end of the // POST data ctx.write(request.httpTrailerBuilder().build()); System.out.println("\n"); return ctx.getStopAction(); // discontinue filter chain execution } @Override public NextAction handleRead(FilterChainContext ctx) throws IOException { HttpContent c = ctx.getMessage(); Buffer b = c.getContent(); if (b.hasRemaining()) { sb.append(b.toStringContent()); } // Last content from the server, set the future result so // the client can display the result and gracefully exit. if (c.isLast()) { future.result(sb.toString()); } return ctx.getStopAction(); // discontinue filter chain execution } // ------------------------------------------------- Private Methods private HttpRequestPacket createRequest() { HttpRequestPacket.Builder builder = HttpRequestPacket.builder(); builder.method("POST"); builder.protocol("HTTP/1.1"); builder.uri("/echo"); builder.chunked(true); HttpRequestPacket packet = builder.build(); packet.addHeader(Header.Host, HOST_HEADER_VALUE); return packet; } } } // END Client /** * This handler using non-blocking streams to read POST data and echo it back to the client. */ private static class NonBlockingEchoHandler extends HttpHandler { // -------------------------------------------- Methods from HttpHandler @Override public void service(final Request request, final Response response) throws Exception { final char[] buf = new char[128]; final NIOReader in = request.getNIOReader(); // return the non-blocking InputStream final NIOWriter out = response.getNIOWriter(); response.suspend(); // If we don't have more data to read - onAllDataRead() will be called in.notifyAvailable(new ReadHandler() { @Override public void onDataAvailable() throws Exception { System.out.printf("[onDataAvailable] echoing %d bytes\n", in.readyData()); echoAvailableData(in, out, buf); in.notifyAvailable(this); } @Override public void onError(Throwable t) { System.out.println("[onError]" + t); response.resume(); } @Override public void onAllDataRead() throws Exception { System.out.printf("[onAllDataRead] length: %d\n", in.readyData()); try { echoAvailableData(in, out, buf); } finally { try { in.close(); } catch (IOException ignored) { } try { out.close(); } catch (IOException ignored) { } response.resume(); } } }); } private void echoAvailableData(NIOReader in, NIOWriter out, char[] buf) throws IOException { while (in.isReady()) { int len = in.read(buf); out.write(buf, 0, len); } } } // END NonBlockingEchoHandler }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy