HttpClassExporter

import java.io.*;
import java.net.*;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.CoderResult;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class HttpClassExporter {

    public static interface Callback {

        public void report(String info, Throwable th);

    }

    private final Callback callback;
    private final ClassLoader classLoader;
    private final Pattern pattern;
    private final String codebase;
    private final int port;

    public HttpClassExporter(InetSocketAddress bindAddr, String prefix, Callback callback, ClassLoader classLoader) throws IOException {
        ServerSocket serverSocket = new ServerSocket();
        serverSocket.bind(bindAddr);

        this.port = bindAddr.getPort();
        this.pattern = getPattern(prefix);
        this.codebase = getCodebase(prefix, bindAddr.getHostString());
        this.callback = callback;
        if (classLoader == null) {
            this.classLoader = HttpClassExporter.class.getClassLoader();
        } else {
            this.classLoader = classLoader;
        }
        Thread acceptorThread = new Thread(new Acceptor(serverSocket));
        acceptorThread.setDaemon(true);
        acceptorThread.start();
    }

    public HttpClassExporter(InetAddress bindAddr, String prefix, Callback callback, ClassLoader classLoader) throws IOException {
        ServerSocket serverSocket = new ServerSocket();
        serverSocket.bind(new InetSocketAddress(bindAddr, 0));
        port = serverSocket.getLocalPort();

        this.pattern = getPattern(prefix);
        this.codebase = getCodebase(prefix, bindAddr.getHostAddress());
        this.callback = callback;
        if (classLoader == null) {
            this.classLoader = HttpClassExporter.class.getClassLoader();
        } else {
            this.classLoader = classLoader;
        }
        Thread acceptorThread = new Thread(new Acceptor(serverSocket));
        acceptorThread.setDaemon(true);
        acceptorThread.start();
    }

    private String getCodebase(String prefix, String hostString) {
        return "http://" + hostString + ":" + port + "/" + prefix + "/";
    }

    private Pattern getPattern(String prefix) {
        return Pattern.compile("GET /" + prefix + "/(.+)* HTTP/1\\.\\d\r\n");
    }

    String getCodebase() {
        return codebase;
    }

    public int getPort() {
        return port;
    }

    private class Acceptor implements Runnable {

        private final ServerSocket serverSocket;

        private Acceptor(ServerSocket serverSocket) {
            this.serverSocket = serverSocket;
        }

        @Override
        public void run() {
            while (true) {
                try {
                    Socket connectedSocket = serverSocket.accept();
                    SocketExporter exporter = new SocketExporter(connectedSocket);
                    if (callback != null) {
                        callback.report("New connection from " + connectedSocket.getRemoteSocketAddress(), null);
                    }
                } catch (IOException e) {
                    if (callback != null) {
                        callback.report("Accept error", e);
                    }
                    break;
                }
            }
        }
    }

    private class SocketExporter implements Runnable {

        private final Socket socket;

        private SocketExporter(Socket socket) {
            this.socket = socket;
            Thread exporterThread = new Thread(this);
            exporterThread.setDaemon(true);
            exporterThread.start();
        }

        @Override
        public void run() {
            try {
                // read HTTP request
                CharBuffer inputBuffer = CharBuffer.allocate(1000); // enough
                Reader socketReader = new InputStreamReader(socket.getInputStream(), "UTF-8");
                int dataRead = socketReader.read(inputBuffer);
                if (dataRead < 0) {
                    if (callback != null) {
                        callback.report("Socket was closed", null);
                    }
                } else {
                    if (callback != null) {
                        callback.report("Read " + dataRead + " bytes", null);
                    }
                }
                inputBuffer.flip();

                Matcher matcher = pattern.matcher(inputBuffer);
                if (matcher.find()) {
                    String path = matcher.group(1);
                    if (path == null) {
                        if (callback != null) {
                            callback.report("Path was empty ", null);
                        }
                        Writer socketWriter = new OutputStreamWriter(socket.getOutputStream());
                        socketWriter.write("HTTP/1.0 200 OK\r\nContent-Length:0\r\n\r\n");
                        socketWriter.close();
                        socket.close();
                    } else {
                        if (callback != null) {
                            callback.report("Requested following resource: " + path, null);
                        }

                        // write HTTP response
                        InputStream resourceStream = classLoader.getResourceAsStream(path);
                        if (resourceStream != null) {

                            WritableByteChannel socketChannel = Channels.newChannel(socket.getOutputStream());

                            CharBuffer httpResponse = CharBuffer.wrap("HTTP/1.0 200 OK\r\n\r\n");
                            CharsetEncoder encoder = Charset.forName("UTF-8").newEncoder();
                            ByteBuffer httpResponseBytes = encoder.encode(httpResponse);
                            socketChannel.write(httpResponseBytes);

                            ReadableByteChannel classChannel = Channels.newChannel(resourceStream);

                            ByteBuffer buffer = ByteBuffer.allocate(100);
                            while (classChannel.read(buffer) > 0) {
                                buffer.flip();
                                socketChannel.write(buffer);
                                buffer.compact();
                            }
                            socketChannel.close();
                            resourceStream.close();

                        } else {
                            if (callback != null) {
                                callback.report("stream for resource was not found", null);
                            }
                        }
                    }
                } else {
                    if (callback != null) {
                        callback.report("regexp doesn't match", null);
                    }
                }
            } catch (Exception e) {
                if (callback != null) {
                    callback.report("Export error", e);
                }
            } finally {
                try {
                    socket.close();
                } catch (Exception e) {
                    // ignore
                }
            }

        }
    }

}
  1. No comments yet.
  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: