users@grizzly.java.net

Portunification ProtocolHandler - expireKey Question

From: John ROM <snake-john_at_gmx.de>
Date: Mon, 26 May 2008 10:16:23 +0200

Hello,
I have to share on server a single port with an
tomcat webserver providing a webstart service
and my custom application providing a custom service.

So I set up Portunification.

I looked at the Griizly mailing Thread "Tunnel implementation" and
"Proxy implementation"
and came up with
the ProtocolHandler (see underneath code) which
is supposed to forward http requests to the webstart server.

The code works but I am affraid of Memmory and Resources leaks .

My Questions are:
1) If the calling client doesn't close its connection I would like to put a timeout on the key.
   I tried putting a System.currentTimemillis()+ 10 secs see (underneath) on the selectionKey
   (Could be that my test right and the client really closes all conenctions very fast!)
   I am asumeing that after 15 seconds the expireKey method will be called.
Am I right?
   
2) Maybe somebody could have a quick look and tell me if there are more dangers in the code
   underneath?

    

Many Greetings
John

----------------------- Code -----------------------------------------

package test.net

import com.sun.grizzly.*;
import com.sun.grizzly.portunif.PUProtocolRequest;
import com.sun.grizzly.portunif.ProtocolHandler;
import com.sun.grizzly.util.OutputWriter;

import com.sun.grizzly.util.WorkerThread;


import java.io.EOFException;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectableChannel;
import java.nio.channels.SelectionKey;

import java.util.HashMap;
import java.util.Map;


/**
 * Portforward to Webstart servlet container.
 * At the time of writing webstart and Application have to
 * share same port on same machine.

 */
public class WebstartProtocolHandler implements ProtocolHandler {
    final public static String PROTOCOL = "Webstart";
    private String targetHost;
    private int targetPort;
    boolean debug;

    private Map<SelectionKey, ConnectorHandler> serverToClient =
            new HashMap<SelectionKey, ConnectorHandler>();


    public WebstartProtocolHandler(String targetHost, int targetPort, boolean debug) {
        this.targetHost = targetHost;
        this.targetPort = targetPort;
        this.debug = debug;
    }

    public String[] getProtocols() {
        return new String[]{PROTOCOL};
    }

    public boolean handle(Context context, PUProtocolRequest protocolRequest)
            throws IOException {

        SelectionKey key = context.getSelectionKey();
        ConnectorHandler webserverHandler = serverToClient.get(key);
        if (webserverHandler == null) {
               webserverHandler = context.getController().acquireConnectorHandler(Controller.Protocol.TCP);
            webserverHandler.setCallbackHandler(new WebserverCallbackHandler(key.channel(), webserverHandler));
            webserverHandler.connect(new InetSocketAddress(targetHost, targetPort));
            serverToClient.put(key, webserverHandler);
        }

        final WorkerThread workerThread
       = ((WorkerThread) Thread.currentThread());
        ByteBuffer buffer = workerThread.getByteBuffer();
        buffer.flip();
        long nwritten = 0;
        try {
            nwritten = webserverHandler.write(buffer, false);
           
        } catch (IOException e) {
            e.printStackTrace();
            cleanupConnection(context);
            return false;
        }
        if (nwritten == -1) {
            if (debug)
                System.out.println("EOF on Webserver");
            cleanupConnection(context);
            return false;
        }
        key.attach(System.currentTimeMillis()+15000L);

        context.getSelectorHandler().register(key, SelectionKey.OP_READ);
        return true;
    }

    public boolean expireKey(SelectionKey key) {
         // here I would clean up resources connected with key
        return true;
    }

    public ByteBuffer getByteBuffer() {
        // Use Thread associated byte buffer
        return null;
    }


    public class WebserverCallbackHandler implements CallbackHandler<Context> {
        private static final int BUFFER_SIZE = 8192 * 2;
        private SelectableChannel clientChannel;

        private ConnectorHandler webserverHandler;
        private ByteBuffer buffer;


        public WebserverCallbackHandler(
                SelectableChannel clientChannel,
                ConnectorHandler webserverHandler) {
            this.clientChannel = clientChannel;
            this.webserverHandler = webserverHandler;
            buffer = ByteBuffer.allocate(BUFFER_SIZE);
        }

        public void onConnect(IOEvent<Context> ioEvent) {
            SelectionKey key = ioEvent.attachment().getSelectionKey();
            try {
                webserverHandler.finishConnect(key);
                ioEvent.attachment().getController().registerKey(key,
                        SelectionKey.OP_READ,
                        Controller.Protocol.TCP);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        public void onRead(IOEvent<Context> ioEvent) {
            Context context = ioEvent.attachment();
            SelectionKey key = context.getSelectionKey();
            Controller controller = context.getController();
            try {
                long nRead = 0;
                while ((nRead = webserverHandler.read(buffer, false)) > 0L) {
                    buffer.flip();
                    long nwritten = OutputWriter.flushChannel(clientChannel, buffer);
                    if (nwritten == -1) {
                              throw new EOFException("ClientChannel closed ");
                    }
                    buffer.clear();
                }

                controller.registerKey(key,
                        SelectionKey.OP_READ,
                        Controller.Protocol.TCP);

            } catch (Exception ex) {
                cleanupConnection(context);
            }
        }

        public void onWrite(IOEvent<Context> ioEvent) {

        }

    }

    void cleanupConnection(Context context) {
        if (debug) System.out.println("Closing Webserver Connection");
        Controller controller = context.getController();
        ConnectorHandler handler = serverToClient.remove(context.getSelectionKey().channel());
        if (handler != null) {
            try {
                handler.close();
            } catch (IOException ex) {
            }
            controller.releaseConnectorHandler(handler);
        }
        controller.cancelKey(context.getSelectionKey());

    }

}
-- 
GMX startet ShortView.de. Hier findest Du Leute mit Deinen Interessen!
Jetzt dabei sein: http://www.shortview.de/?mc=sv_ext_mf@gmx