You are viewing a plain text version of this content. The canonical link for it is here.
Posted to awf-commits@incubator.apache.org by jm...@apache.org on 2012/02/13 23:07:51 UTC

svn commit: r1243729 [2/7] - in /incubator/deft/trunk: ./ awf-core/ awf-core/src/ awf-core/src/main/ awf-core/src/main/assembly/ awf-core/src/main/java/ awf-core/src/main/java/org/ awf-core/src/main/java/org/apache/ awf-core/src/main/java/org/apache/aw...

Added: incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/io/AsynchronousSocket.java
URL: http://svn.apache.org/viewvc/incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/io/AsynchronousSocket.java?rev=1243729&view=auto
==============================================================================
--- incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/io/AsynchronousSocket.java (added)
+++ incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/io/AsynchronousSocket.java Mon Feb 13 23:07:46 2012
@@ -0,0 +1,377 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF 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 org.apache.awf.io;
+
+import java.io.EOFException;
+import java.io.IOException;
+import java.net.ConnectException;
+import java.net.InetSocketAddress;
+import java.nio.ByteBuffer;
+import java.nio.channels.SelectableChannel;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.ServerSocketChannel;
+import java.nio.channels.SocketChannel;
+import java.nio.channels.UnresolvedAddressException;
+
+import org.apache.awf.io.buffer.DynamicByteBuffer;
+import org.apache.awf.util.Closeables;
+import org.apache.awf.util.KnuthMorrisPrattAlgorithm;
+import org.apache.awf.util.NopAsyncResult;
+import org.apache.awf.web.AsyncCallback;
+import org.apache.awf.web.AsyncResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class AsynchronousSocket implements IOHandler {
+
+    private static final Logger logger = LoggerFactory.getLogger(AsynchronousSocket.class);
+
+    private final IOLoop ioLoop;
+
+    private static final int DEFAULT_BYTEBUFFER_SIZE = 1024;
+    private static final int DEFAULT_INITIAL_READ_BYTEBUFFER_SIZE = 1024;
+    private static final int DEFAULT_INITIAL_WRITE_BYTEBUFFER_SIZE = 1024;
+
+    private final AsyncResult<byte[]> nopAsyncByteArrayResult = NopAsyncResult.of(byte[].class).nopAsyncResult;
+    private final AsyncResult<Boolean> nopAsyncBooleanResult = NopAsyncResult.of(Boolean.class).nopAsyncResult;
+
+    private final SocketChannel channel;
+    private int interestOps;
+
+    private byte[] readDelimiter = "".getBytes();
+    private int readBytes = Integer.MAX_VALUE;
+
+    private AsyncResult<Boolean> connectCallback = nopAsyncBooleanResult;
+    private AsyncCallback closeCallback = AsyncCallback.nopCb;
+    private AsyncResult<byte[]> readCallback = nopAsyncByteArrayResult;
+    private AsyncCallback writeCallback = AsyncCallback.nopCb;
+
+    private final DynamicByteBuffer readBuffer = DynamicByteBuffer.allocate(DEFAULT_INITIAL_READ_BYTEBUFFER_SIZE);
+    private final DynamicByteBuffer writeBuffer = DynamicByteBuffer.allocate(DEFAULT_INITIAL_WRITE_BYTEBUFFER_SIZE);
+
+    private boolean reachedEOF = false;
+
+    /**
+     * Creates a new {@code AsynchronousSocket} that will delegate its io
+     * operations to the given {@link SelectableChannel}.
+     * <p>
+     * Support for three non-blocking asynchronous methods that take callbacks:
+     * <p>
+     * {@link #readUntil(byte[], AsyncResult)}
+     * <p>
+     * {@link #readBytes(int, AsyncResult)} and
+     * <p>
+     * {@link #write(byte[], AsyncCallback)}
+     * <p>
+     * The {@link SelectableChannel} should be the result of either
+     * {@link SocketChannel#open()} (client operations, connected or
+     * unconnected) or {@link ServerSocketChannel#accept()} (server operations).
+     * <p>
+     * The given {@code SelectableChannel} will be configured to be in
+     * non-blocking mode, even if it is non-blocking already.
+     * 
+     * <p>
+     * Below is an example of how a simple server could be implemented.
+     * 
+     * <pre>
+     *   final ServerSocketChannel server = ServerSocketChannel.open();
+     *   server.socket().bind(new InetSocketAddress(9090));
+     * 	
+     *   AcceptUtil.accept(server, new AsyncCallback() { public void onCallback() { onAccept(server);} });
+     *   IOLoop.INSTANCE.start();
+     * 
+     *   private static void onAccept(ServerSocketChannel channel) {
+     *       SocketChannel client = channel.accept();
+     *       AsynchronousSocket socket = new AsynchronousSocket(client);
+     *       // use socket
+     *   }
+     * </pre>
+     */
+    public AsynchronousSocket(SocketChannel channel) {
+        this(IOLoop.INSTANCE, channel);
+    }
+
+    public AsynchronousSocket(IOLoop ioLoop, SocketChannel channel) {
+        this.ioLoop = ioLoop;
+        this.channel = channel;
+        try {
+            channel.configureBlocking(false);
+        } catch (IOException e) {
+            logger.error("Could not configure SocketChannel to be non-blocking");
+        }
+        if (channel.isConnected()) {
+            interestOps |= SelectionKey.OP_READ;
+        }
+        ioLoop.addHandler(channel, this, interestOps, null);
+    }
+
+    /**
+     * Connects to the given host port tuple and invokes the given callback when
+     * a successful connection is established.
+     * <p>
+     * You can both read and write on the {@code AsynchronousSocket} before it
+     * is connected (in which case the data will be written/read as soon as the
+     * connection is ready).
+     */
+    public void connect(String host, int port, AsyncResult<Boolean> ccb) {
+        ioLoop.updateHandler(channel, interestOps |= SelectionKey.OP_CONNECT);
+        connectCallback = ccb;
+        try {
+            channel.connect(new InetSocketAddress(host, port));
+        } catch (IOException e) {
+            logger.error("Failed to connect to: {}, message: {} ", host, e.getMessage());
+            invokeConnectFailureCallback(e);
+        } catch (UnresolvedAddressException e) {
+            logger.warn("Unresolvable host: {}", host);
+            invokeConnectFailureCallback(e);
+        }
+    }
+
+    /**
+     * Close the socket.
+     */
+    public void close() {
+        Closeables.closeQuietly(ioLoop, channel);
+        invokeCloseCallback();
+    }
+
+    /**
+     * The given callback will invoked when the underlaying {@code
+     * SelectableChannel} is closed.
+     */
+    public void setCloseCallback(AsyncCallback ccb) {
+        closeCallback = ccb;
+    }
+
+    /**
+     * Should only be invoked by the IOLoop
+     */
+    @Override
+    public void handleAccept(SelectionKey key) throws IOException {
+        logger.debug("handle accept...");
+    }
+
+    /**
+     * Should only be invoked by the IOLoop
+     */
+    @Override
+    public void handleConnect(SelectionKey key) throws IOException {
+        logger.debug("handle connect...");
+        if (channel.isConnectionPending()) {
+            try {
+                channel.finishConnect();
+                invokeConnectSuccessfulCallback();
+                interestOps &= ~SelectionKey.OP_CONNECT;
+                ioLoop.updateHandler(channel, interestOps |= SelectionKey.OP_READ);
+            } catch (ConnectException e) {
+                logger.warn("Connect failed: {}", e.getMessage());
+                invokeConnectFailureCallback(e);
+            }
+        }
+    }
+
+    /**
+     * Should only be invoked by the IOLoop
+     */
+    @Override
+    public void handleRead(SelectionKey key) throws IOException {
+        logger.debug("handle read...");
+        ByteBuffer buffer = ByteBuffer.allocate(DEFAULT_BYTEBUFFER_SIZE);
+        // TODO RS 110723 reuse byte buffers
+        int read = 0;
+        try {
+            read = channel.read(buffer);
+        } catch (IOException e) {
+            logger.error("IOException during read: {}", e.getMessage());
+            invokeCloseCallback();
+            Closeables.closeQuietly(ioLoop, channel);
+            return;
+        }
+
+        if (read == -1) { // EOF
+            reachedEOF = true;
+            ioLoop.updateHandler(channel, interestOps &= ~SelectionKey.OP_READ);
+            if (writeBuffer.position() == 0) {
+                invokeCloseCallback();
+            }
+
+            return;
+        }
+        buffer.flip();
+        readBuffer.put(buffer);
+        logger.debug("readBuffer size: {}", readBuffer.position());
+        checkReadState();
+    }
+
+    /**
+     * Should only be invoked by the IOLoop
+     */
+    @Override
+    public void handleWrite(SelectionKey key) {
+        logger.debug("handle write...");
+        doWrite();
+    }
+
+    /**
+     * Reads from the underlaying SelectableChannel until delimiter is reached.
+     * When it its, the given AsyncResult will be invoked.
+     */
+    public void readUntil(byte[] delimiter, AsyncResult<byte[]> rcb) {
+        logger.debug("readUntil delimiter: {}", new String(delimiter));
+        readDelimiter = delimiter;
+        readCallback = rcb;
+        checkReadState();
+    }
+
+    /**
+     * Reads from the underlaying SelectableChannel until n bytes are read. When
+     * it its, the given AsyncResult will be invoked.
+     */
+    public void readBytes(int n, AsyncResult<byte[]> rcb) {
+        logger.debug("readBytes #bytes: {}", n);
+        readBytes = n;
+        readCallback = rcb;
+        checkReadState();
+    }
+
+    /**
+     * If readBuffer contains readDelimiter, client read is finished => invoke
+     * readCallback (onSuccess) Or if readBytes bytes are read, client read is
+     * finished => invoke readCallback (onSuccess) Of if end-of-stream is
+     * reached => invoke readCallback (onFailure)
+     */
+    private void checkReadState() {
+        if (reachedEOF) {
+            invokeReadFailureCallback(new EOFException("Reached end-of-stream"));
+            return;
+        }
+        int index = KnuthMorrisPrattAlgorithm.indexOf(readBuffer.array(), 0, readBuffer.position(), readDelimiter);
+        if (index != -1 && readDelimiter.length > 0) {
+            byte[] result = getResult(index, readDelimiter.length);
+            readDelimiter = "".getBytes();
+            invokeReadSuccessfulCallback(result);
+        } else if (readBuffer.position() >= readBytes) {
+            byte[] result = getResult(readBytes, 0);
+            readBytes = Integer.MAX_VALUE;
+            invokeReadSuccessfulCallback(result);
+        }
+    }
+
+    /**
+     * Returns the resulting byte[] data that was requested by the client
+     * through readUntil(..) or readBytes(..)
+     * 
+     * @param size Number of bytes to fetch and remove from the read buffer.
+     * @param advance The number of bytes the read buffer's position should move
+     *            forward after the data has been fetched. (To ignore the
+     *            readDelimiter.)
+     */
+    private byte[] getResult(int size, int advance) {
+        readBuffer.flip();
+        byte[] result = new byte[size];
+        readBuffer.get(result, 0, size);
+        // ignore the delimiter (if it was a readUntil(..) call)
+        readBuffer.position(readBuffer.position() + advance);
+        // "delete" the result data (data after result is left intact and will
+        // not be overwritten)
+        readBuffer.compact();
+        logger.debug("readBuffer size: {}", readBuffer.position());
+        return result;
+    }
+
+    private void invokeReadSuccessfulCallback(byte[] result) {
+        AsyncResult<byte[]> cb = readCallback;
+        readCallback = nopAsyncByteArrayResult;
+        cb.onSuccess(result);
+    }
+
+    private void invokeReadFailureCallback(Exception e) {
+        AsyncResult<byte[]> cb = readCallback;
+        readCallback = nopAsyncByteArrayResult;
+        cb.onFailure(e);
+    }
+
+    private void invokeWriteCallback() {
+        AsyncCallback cb = writeCallback;
+        writeCallback = AsyncCallback.nopCb;
+        cb.onCallback();
+    }
+
+    private void invokeCloseCallback() {
+        AsyncCallback cb = closeCallback;
+        closeCallback = AsyncCallback.nopCb;
+        cb.onCallback();
+    }
+
+    private void invokeConnectSuccessfulCallback() {
+        AsyncResult<Boolean> cb = connectCallback;
+        connectCallback = nopAsyncBooleanResult;
+        cb.onSuccess(true);
+    }
+
+    private void invokeConnectFailureCallback(Exception e) {
+        AsyncResult<Boolean> cb = connectCallback;
+        connectCallback = nopAsyncBooleanResult;
+        cb.onFailure(e);
+        ;
+    }
+
+    /**
+     * Writes the given data to the underlaying SelectableChannel. When all data
+     * is successfully transmitted, the given AsyncCallback will be invoked
+     */
+    public void write(byte[] data, AsyncCallback wcb) {
+        logger.debug("write data: {}", new String(data));
+        writeBuffer.put(data);
+        logger.debug("writeBuffer size: {}", writeBuffer.position());
+        writeCallback = wcb;
+        doWrite();
+    }
+
+    /**
+     * If we succeed to write everything in writeBuffer, client write is
+     * finished => invoke writeCallback
+     */
+    private void doWrite() {
+        int written = 0;
+        try {
+            if (channel.isConnected()) {
+                writeBuffer.flip(); // prepare for write
+                written = channel.write(writeBuffer.getByteBuffer());
+                // make room for more data be "read" in
+                writeBuffer.compact();
+            }
+        } catch (IOException e) {
+            logger.error("IOException during write: {}", e.getMessage());
+            invokeCloseCallback();
+            Closeables.closeQuietly(ioLoop, channel);
+            return;
+        }
+        logger.debug("wrote: {} bytes", written);
+        logger.debug("writeBuffer size: {}", writeBuffer.position());
+        if (writeBuffer.position() > 0) {
+            ioLoop.updateHandler(channel, interestOps |= SelectionKey.OP_WRITE);
+        } else {
+            ioLoop.updateHandler(channel, interestOps &= ~SelectionKey.OP_WRITE);
+            invokeWriteCallback();
+        }
+    }
+
+}

Added: incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/io/IOHandler.java
URL: http://svn.apache.org/viewvc/incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/io/IOHandler.java?rev=1243729&view=auto
==============================================================================
--- incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/io/IOHandler.java (added)
+++ incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/io/IOHandler.java Mon Feb 13 23:07:46 2012
@@ -0,0 +1,41 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF 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 org.apache.awf.io;
+
+import java.io.IOException;
+import java.nio.channels.SelectionKey;
+
+/**
+ * {@code IOHandler}s are added to the IOLoop via {@link IOLoop#addHandler}
+ * method. The callbacks defined in the {@code IOHandler} will be invoked by the
+ * {@code IOLoop} when io is ready.
+ * 
+ */
+public interface IOHandler {
+
+    void handleAccept(SelectionKey key) throws IOException;
+
+    void handleConnect(SelectionKey key) throws IOException;
+
+    void handleRead(SelectionKey key) throws IOException;
+
+    void handleWrite(SelectionKey key);
+
+}

Added: incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/io/IOLoop.java
URL: http://svn.apache.org/viewvc/incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/io/IOLoop.java?rev=1243729&view=auto
==============================================================================
--- incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/io/IOLoop.java (added)
+++ incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/io/IOLoop.java Mon Feb 13 23:07:46 2012
@@ -0,0 +1,245 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF 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 org.apache.awf.io;
+
+import java.io.IOException;
+import java.nio.channels.CancelledKeyException;
+import java.nio.channels.ClosedChannelException;
+import java.nio.channels.SelectableChannel;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import com.google.common.base.Function;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+
+import org.apache.awf.io.callback.CallbackManager;
+import org.apache.awf.io.callback.JMXDebuggableCallbackManager;
+import org.apache.awf.io.timeout.JMXDebuggableTimeoutManager;
+import org.apache.awf.io.timeout.Timeout;
+import org.apache.awf.io.timeout.TimeoutManager;
+import org.apache.awf.util.MXBeanUtil;
+import org.apache.awf.web.AsyncCallback;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import static com.google.common.collect.Collections2.transform;
+
+public class IOLoop implements IOLoopMXBean {
+
+    /*
+     * IOLoop singleton to use for convenience (otherwise you would have to pass
+     * around the IOLoop instance explicitly, now you can simply use
+     * IOLoop.INSTANCE)
+     */
+    public static final IOLoop INSTANCE = new IOLoop();
+
+    private volatile boolean running = false;
+
+    private final Logger logger = LoggerFactory.getLogger(IOLoop.class);
+
+    private Selector selector;
+
+    private final Map<SelectableChannel, IOHandler> handlers = Maps.newHashMap();
+
+    private final TimeoutManager tm = new JMXDebuggableTimeoutManager();
+    private final CallbackManager cm = new JMXDebuggableCallbackManager();
+
+    private static final AtomicInteger sequence = new AtomicInteger();
+
+    public IOLoop() {
+        try {
+            selector = Selector.open();
+        } catch (IOException e) {
+            logger.error("Could not open selector: {}", e.getMessage());
+        }
+        MXBeanUtil.registerMXBean(this, "IOLoop");
+    }
+
+    /**
+     * Start the io loop. The thread that invokes this method will be blocked
+     * (until {@link IOLoop#stop} is invoked) and will be the io loop thread.
+     */
+    public void start() {
+        Thread.currentThread().setName("I/O-LOOP" + sequence.incrementAndGet());
+        running = true;
+
+        long selectorTimeout = 250; // 250 ms
+        while (running) {
+            try {
+                if (selector.select(selectorTimeout) == 0) {
+                    long ms = tm.execute();
+                    selectorTimeout = Math.min(ms, /* selectorTimeout */250);
+                    if (cm.execute()) {
+                        selectorTimeout = 1;
+                    }
+                    continue;
+                }
+
+                Iterator<SelectionKey> keys = selector.selectedKeys().iterator();
+                while (keys.hasNext()) {
+                    SelectionKey key = keys.next();
+                    IOHandler handler = handlers.get(key.channel());
+                    if (key.isAcceptable()) {
+                        handler.handleAccept(key);
+                    }
+                    if (key.isConnectable()) {
+                        handler.handleConnect(key);
+                    }
+                    if (key.isValid() && key.isReadable()) {
+                        handler.handleRead(key);
+                    }
+                    if (key.isValid() && key.isWritable()) {
+                        handler.handleWrite(key);
+                    }
+                    keys.remove();
+                }
+                long ms = tm.execute();
+                selectorTimeout = Math.min(ms, /* selectorTimeout */250);
+                if (cm.execute()) {
+                    selectorTimeout = 1;
+                }
+            } catch (IOException e) {
+                logger.error("IOException received in IOLoop: {}", e);
+            } catch (CancelledKeyException e) {
+                logger.error("CancelledKeyException received in IOLoop: {}", e);
+            }
+        }
+    }
+
+    /**
+     * Stop the io loop and release the thread (io loop thread) that invoked the
+     * {@link IOLoop#start} method.
+     */
+    public void stop() {
+        running = false;
+        logger.debug("Stopping IOLoop...");
+    }
+
+    /**
+     * Registers a new {@code IOHandler} with this {@code IOLoop}.
+     * 
+     * @param channel The {@code SelectableChannel}
+     * @param handler {@code IOHandler that will receive the io callbacks.}
+     * @param interestOps See {@link SelectionKey} for valid values. (Xor for
+     *            multiple interests).
+     * @param attachment The {@code attachment} that will be accessible from the
+     *            returning {@code SelectionKey}s attachment.
+     * 
+     */
+    public SelectionKey addHandler(SelectableChannel channel, IOHandler handler, int interestOps, Object attachment) {
+        handlers.put(channel, handler);
+        return registerChannel(channel, interestOps, attachment);
+    }
+
+    /**
+     * Unregisters the previously registered {@code IOHandler}.
+     * 
+     * @param channel The {@code SelectableChannel} that was registered with a
+     *            user defined {@code IOHandler}
+     */
+    public void removeHandler(SelectableChannel channel) {
+        handlers.remove(channel);
+    }
+
+    /**
+     * Update an earlier registered {@code SelectableChannel}
+     * 
+     * @param channel The {@code SelectableChannel}
+     * @param newInterestOps The complete new set of interest operations.
+     */
+    public void updateHandler(SelectableChannel channel, int newInterestOps) {
+        if (handlers.containsKey(channel)) {
+            channel.keyFor(selector).interestOps(newInterestOps);
+        } else {
+            logger.warn("Tried to update interestOps for an unknown SelectableChannel.");
+        }
+    }
+
+    /**
+     * 
+     * @param channel
+     * @param interestOps
+     * @param attachment
+     * @return
+     */
+    private SelectionKey registerChannel(SelectableChannel channel, int interestOps, Object attachment) {
+        try {
+            return channel.register(selector, interestOps, attachment);
+        } catch (ClosedChannelException e) {
+            removeHandler(channel);
+            logger.error("Could not register channel: {}", e.getMessage());
+        }
+        return null;
+    }
+
+    public void addKeepAliveTimeout(SelectableChannel channel, Timeout keepAliveTimeout) {
+        tm.addKeepAliveTimeout(channel, keepAliveTimeout);
+    }
+
+    public boolean hasKeepAliveTimeout(SelectableChannel channel) {
+        return tm.hasKeepAliveTimeout(channel);
+    }
+
+    public void addTimeout(Timeout timeout) {
+        tm.addTimeout(timeout);
+    }
+
+    /**
+     * The callback will be invoked in the next iteration in the io loop. This
+     * is the only thread safe method that is exposed by AWF. This is a
+     * convenient way to return control to the io loop.
+     */
+    public void addCallback(AsyncCallback callback) {
+        cm.addCallback(callback);
+    }
+
+    // implements IOLoopMXBean
+    @Override
+    public int getNumberOfRegisteredIOHandlers() {
+        return handlers.size();
+    }
+
+    @Override
+    public List<String> getRegisteredIOHandlers() {
+        Map<SelectableChannel, IOHandler> defensive = new HashMap<SelectableChannel, IOHandler>(handlers);
+        Collection<String> readables = transform(defensive.values(), new Function<IOHandler, String>() {
+            @Override
+            public String apply(IOHandler handler) {
+                return handler.toString();
+            }
+        });
+        return Lists.newLinkedList(readables);
+    }
+
+    /**
+     * Checks whether this IOLoop is running or not.
+     * 
+     * @return <code>true</code> if running; <code>false</code> otherwise.
+     */
+    public boolean isRunning() {
+        return running;
+    }
+}

Added: incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/io/IOLoopMXBean.java
URL: http://svn.apache.org/viewvc/incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/io/IOLoopMXBean.java?rev=1243729&view=auto
==============================================================================
--- incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/io/IOLoopMXBean.java (added)
+++ incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/io/IOLoopMXBean.java Mon Feb 13 23:07:46 2012
@@ -0,0 +1,30 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF 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 org.apache.awf.io;
+
+import java.util.List;
+
+public interface IOLoopMXBean {
+
+    int getNumberOfRegisteredIOHandlers();
+
+    List<String> getRegisteredIOHandlers();
+
+}

Added: incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/io/buffer/DynamicByteBuffer.java
URL: http://svn.apache.org/viewvc/incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/io/buffer/DynamicByteBuffer.java?rev=1243729&view=auto
==============================================================================
--- incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/io/buffer/DynamicByteBuffer.java (added)
+++ incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/io/buffer/DynamicByteBuffer.java Mon Feb 13 23:07:46 2012
@@ -0,0 +1,188 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF 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 org.apache.awf.io.buffer;
+
+import java.nio.ByteBuffer;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Charsets;
+
+public class DynamicByteBuffer {
+	
+	private final static Logger logger = LoggerFactory.getLogger(DynamicByteBuffer.class);
+
+	private ByteBuffer backend;
+
+	private DynamicByteBuffer(ByteBuffer bb) { 	
+		this.backend = bb;
+	}
+	
+	/**
+	 * Allocate a new {@code DynamicByteBuffer} that will be using a {@code ByteBuffer} internally.
+	 * @param capacity initial capacity
+	 */
+	public static DynamicByteBuffer allocate(int capacity) {
+		return new DynamicByteBuffer(ByteBuffer.allocate(capacity));
+	}
+
+	/**
+	 * Append the data. Will reallocate if needed.
+	 */
+	public void put(byte[] src) {
+		ensureCapacity(src.length);
+		backend.put(src);
+	}
+	
+	/**
+	 * Append the bytes from the given src. Will reallocate if needed.
+	 */
+	public void put(ByteBuffer src) {
+		ensureCapacity(src.limit());
+		backend.put(src);
+	}
+
+
+    /**
+     * Append count bytes in the given byte array start at array position
+     * @param array     byte array to copy
+     * @param position  start position
+     * @param count     bytes to copy count
+     */
+    public void put(byte[] array, int position, int count) {
+        ensureCapacity(count);
+		backend.put(array, position, count);
+    }
+
+	/**
+	 * Prepend the data. Will reallocate if needed.
+	 */
+	public void prepend(String data) {
+		byte[] bytes = data.getBytes(Charsets.UTF_8);
+		int newSize = bytes.length + backend.position();
+		byte[] newBuffer = new byte[newSize];
+		System.arraycopy(bytes, 0, newBuffer, 0, bytes.length);	// initial line and headers
+		System.arraycopy(backend.array(), 0, newBuffer, bytes.length, backend.position()); // body
+		backend = ByteBuffer.wrap(newBuffer);
+		backend.position(newSize);
+	}
+
+	/**
+	 * Ensures that its safe to append size data to backend.
+	 * @param size The size of the data that is about to be appended.
+	 */
+	private void ensureCapacity(int size) {
+		int remaining = backend.remaining();
+		if (size > remaining) {
+			logger.debug("allocating new DynamicByteBuffer, old capacity {}: ", backend.capacity());
+            int missing = size - remaining;
+			int newSize =  (int) ((backend.capacity() + missing) * 1.5);
+			reallocate(newSize);
+		}
+	}
+
+	// Preserves position.
+	private void reallocate(int newCapacity) {
+		int oldPosition = backend.position();
+		byte[] newBuffer = new byte[newCapacity];
+		System.arraycopy(backend.array(), 0, newBuffer, 0, backend.position());
+		backend = ByteBuffer.wrap(newBuffer);
+		backend.position(oldPosition);
+		logger.debug("allocated new DynamicByteBufer, new capacity: {}", backend.capacity());
+	}
+
+	/**
+	 * Returns the {@code ByteBuffer} that is used internally by this {@code DynamicByteBufer}.
+	 * Changes made to the returned {@code ByteBuffer} will be incur modifications in this {@code DynamicByteBufer}.
+	 */
+	public ByteBuffer getByteBuffer() {
+		return backend;
+	}
+
+	/**
+	 * See {@link ByteBuffer#get(byte[], int, int)}
+	 */
+	public void get(byte[] dst, int offset, int length) {
+		backend.get(dst, offset, length);
+	}
+
+	public void position(int newPosition) {
+		backend.position(newPosition);
+	}
+
+	/**
+	 * See {@link ByteBuffer#flip}
+	 */
+	public void flip() {
+		backend.flip();
+	}
+
+	/**
+	 * See {@link ByteBuffer#limit}
+	 */
+	public int limit() {
+		return backend.limit();
+	}
+
+	/**
+	 * See {@link ByteBuffer#position}
+	 */
+	public int position() {
+		return backend.position();
+	}
+
+	/**
+	 * See {@link ByteBuffer#array}
+	 */
+	public byte[] array() {
+		return backend.array();
+	}
+
+	/**
+	 * See {@link ByteBuffer#capacity}
+	 */
+	public int capacity() {
+		return backend.capacity();
+	}
+
+	/**
+	 * See {@link ByteBuffer#hasRemaining}
+	 */
+	public boolean hasRemaining() {
+		return backend.hasRemaining();
+	}
+
+	/**
+	 * See {@link ByteBuffer#compact}
+	 */
+	public DynamicByteBuffer compact() {
+		backend.compact();
+		return this;
+	}
+
+	/**
+	 * See {@link ByteBuffer#clear}
+	 */
+	public DynamicByteBuffer clear() {
+		backend.clear();
+		return this;
+	}
+}

Added: incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/io/callback/CallbackManager.java
URL: http://svn.apache.org/viewvc/incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/io/callback/CallbackManager.java?rev=1243729&view=auto
==============================================================================
--- incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/io/callback/CallbackManager.java (added)
+++ incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/io/callback/CallbackManager.java Mon Feb 13 23:07:46 2012
@@ -0,0 +1,34 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF 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 org.apache.awf.io.callback;
+
+import org.apache.awf.web.AsyncCallback;
+
+public interface CallbackManager {
+
+	void addCallback(AsyncCallback callback);
+	
+	/**
+	 * 
+	 * @return true if there are callbacks scheduled to be executed during the next IO loop iteration.
+	 */
+	boolean execute();
+	
+}

Added: incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/io/callback/CallbackManagerMXBean.java
URL: http://svn.apache.org/viewvc/incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/io/callback/CallbackManagerMXBean.java?rev=1243729&view=auto
==============================================================================
--- incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/io/callback/CallbackManagerMXBean.java (added)
+++ incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/io/callback/CallbackManagerMXBean.java Mon Feb 13 23:07:46 2012
@@ -0,0 +1,26 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF 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 org.apache.awf.io.callback;
+
+public interface CallbackManagerMXBean {
+
+	int getNumberOfCallbacks();
+	
+}

Added: incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/io/callback/JMXDebuggableCallbackManager.java
URL: http://svn.apache.org/viewvc/incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/io/callback/JMXDebuggableCallbackManager.java?rev=1243729&view=auto
==============================================================================
--- incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/io/callback/JMXDebuggableCallbackManager.java (added)
+++ incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/io/callback/JMXDebuggableCallbackManager.java Mon Feb 13 23:07:46 2012
@@ -0,0 +1,67 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF 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 org.apache.awf.io.callback;
+
+import java.util.AbstractCollection;
+import java.util.List;
+import java.util.concurrent.ConcurrentLinkedQueue;
+
+import org.apache.awf.util.MXBeanUtil;
+import org.apache.awf.web.AsyncCallback;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.Lists;
+
+public class JMXDebuggableCallbackManager implements CallbackManager, CallbackManagerMXBean {
+
+	private final Logger logger = LoggerFactory.getLogger(JMXDebuggableCallbackManager.class);
+	
+	private final AbstractCollection<AsyncCallback> callbacks = new ConcurrentLinkedQueue<AsyncCallback>();
+	
+	{ 	// instance initialization block
+		MXBeanUtil.registerMXBean(this, "CallbackManager"); 
+	}
+	
+	@Override
+	public int getNumberOfCallbacks() {
+		return callbacks.size();
+	}
+
+	@Override
+	public void addCallback(AsyncCallback callback) {
+		callbacks.add(callback);
+		logger.debug("Callback added");
+	}
+
+	@Override
+	public boolean execute() {
+		// makes a defensive copy to avoid (1) CME (new callbacks are added this iteration) and (2) IO starvation.
+		List<AsyncCallback> defensive = Lists.newLinkedList(callbacks);
+		callbacks.clear();
+		for (AsyncCallback callback : defensive) {
+			callback.onCallback();
+			logger.debug("Callback executed");
+		}
+		return !callbacks.isEmpty();
+	}
+	
+
+}

Added: incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/io/callback/PeriodicCallback.java
URL: http://svn.apache.org/viewvc/incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/io/callback/PeriodicCallback.java?rev=1243729&view=auto
==============================================================================
--- incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/io/callback/PeriodicCallback.java (added)
+++ incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/io/callback/PeriodicCallback.java Mon Feb 13 23:07:46 2012
@@ -0,0 +1,75 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF 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 org.apache.awf.io.callback;
+
+import org.apache.awf.io.IOLoop;
+import org.apache.awf.io.timeout.Timeout;
+import org.apache.awf.web.AsyncCallback;
+
+public class PeriodicCallback {
+	
+	private final IOLoop ioLoop;
+	private final AsyncCallback cb;
+	private final long period;
+	private boolean active = true;
+	
+	/** 
+	 * A periodic callback that will execute its callback once every period.
+	 * @param cb 
+	 * @param period The period in ms
+	 */
+	public PeriodicCallback(AsyncCallback cb, long period) {
+		this(IOLoop.INSTANCE, cb, period);
+	}
+	
+	public PeriodicCallback(IOLoop ioLoop, AsyncCallback cb, long period) {
+		this.ioLoop = ioLoop;
+		this.cb = cb;
+		this.period = period;
+	}
+	
+	/**
+	 * Start the {@code PeriodicCallback}
+	 */
+	public void start() {
+		ioLoop.addTimeout(
+				new Timeout(
+						System.currentTimeMillis() + period, 
+						new AsyncCallback() { @Override public void onCallback() { run(); }}
+				)
+		);
+	}
+	
+	private void run() {
+		if (active) {
+			cb.onCallback();
+			start();	// reschedule
+		}
+	}
+	
+	/**
+	 * Cancel the {@code PeriodicCallback}. (No way to resume the cancellation, you will need to create a new
+	 * {@code PeriodicCallback}).
+	 */
+	public void cancel() {
+		this.active = false;
+	}
+	
+}

Added: incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/io/timeout/JMXDebuggableTimeoutManager.java
URL: http://svn.apache.org/viewvc/incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/io/timeout/JMXDebuggableTimeoutManager.java?rev=1243729&view=auto
==============================================================================
--- incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/io/timeout/JMXDebuggableTimeoutManager.java (added)
+++ incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/io/timeout/JMXDebuggableTimeoutManager.java Mon Feb 13 23:07:46 2012
@@ -0,0 +1,168 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF 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 org.apache.awf.io.timeout;
+
+import java.nio.channels.SelectableChannel;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.TreeSet;
+
+import org.apache.awf.util.MXBeanUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import com.google.common.collect.TreeMultiset;
+
+
+public class JMXDebuggableTimeoutManager implements TimeoutManager, TimeoutManagerMXBean {
+
+	private final Logger logger = LoggerFactory.getLogger(JMXDebuggableTimeoutManager.class);
+
+	private final TreeSet<Timeout> timeouts = Sets.newTreeSet(new TimeoutComparator()); 
+	private final TreeMultiset<DecoratedTimeout> keepAliveTimeouts = TreeMultiset.create();
+	private final Map<SelectableChannel, DecoratedTimeout> index = Maps.newHashMap();
+
+	{ 	// instance initialization block
+		MXBeanUtil.registerMXBean(this, "TimeoutManager"); 
+	}
+
+	@Override
+	public void addKeepAliveTimeout(SelectableChannel channel, Timeout timeout) {
+		logger.debug("added keep-alive timeout: {}", timeout);
+		DecoratedTimeout oldTimeout = index.get(channel);
+		if (oldTimeout != null) {
+			keepAliveTimeouts.remove(oldTimeout);
+		}
+		DecoratedTimeout decorated = new DecoratedTimeout(channel, timeout);
+		keepAliveTimeouts.add(decorated);
+		index.put(channel, decorated);
+	}
+
+	@Override
+	public void addTimeout(Timeout timeout) {
+		logger.debug("added generic timeout: {}", timeout);
+		timeouts.add(timeout);
+	}
+
+	@Override
+	public boolean hasKeepAliveTimeout(SelectableChannel channel) {
+		return index.containsKey(channel);
+	}
+
+	@Override
+	public long execute() {
+		return Math.min(executeKeepAliveTimeouts(), executeTimeouts());
+	}
+	
+	private long executeKeepAliveTimeouts() {
+		// makes a defensive copy to avoid (1) CME (new timeouts are added this iteration) and (2) IO starvation.
+		TreeMultiset<DecoratedTimeout> defensive = TreeMultiset.create(keepAliveTimeouts);
+		Iterator<DecoratedTimeout> iter = defensive.iterator();
+		final long now = System.currentTimeMillis();
+		while (iter.hasNext()) {
+			DecoratedTimeout candidate = iter.next();
+			if (candidate.timeout.getTimeout() > now) { break; }
+			candidate.timeout.getCallback().onCallback();
+			index.remove(candidate.channel);
+			iter.remove();
+			keepAliveTimeouts.remove(candidate);
+			logger.debug("Keep-alive timeout triggered: {}", candidate.timeout);
+		}
+		return keepAliveTimeouts.isEmpty() ? Long.MAX_VALUE : Math.max(1, keepAliveTimeouts.iterator().next().timeout.getTimeout() - now);
+	}
+	
+	private long executeTimeouts() {
+		// makes a defensive copy to avoid (1) CME (new timeouts are added this iteration) and (2) IO starvation.
+		TreeSet<Timeout> defensive = new TreeSet<Timeout>(timeouts); /*Sets.newTreeSet(timeouts);*/
+		Iterator<Timeout> iter = defensive.iterator();
+		final long now = System.currentTimeMillis();
+		while (iter.hasNext()) {
+			Timeout candidate = iter.next();
+			if (candidate.getTimeout() > now) { break; }
+			candidate.getCallback().onCallback();
+			iter.remove();
+			timeouts.remove(candidate);
+			logger.debug("Timeout triggered: {}", candidate);
+		}
+		return timeouts.isEmpty() ? Long.MAX_VALUE : Math.max(1, timeouts.iterator().next().getTimeout() - now);
+	}
+
+	// implements TimoutMXBean
+	@Override
+	public int getNumberOfKeepAliveTimeouts() {
+		return index.size();
+	}
+
+	@Override
+	public int getNumberOfTimeouts() {
+		return keepAliveTimeouts.size() + timeouts.size();
+	}
+
+	private class DecoratedTimeout implements Comparable<DecoratedTimeout> {
+
+		public final SelectableChannel channel;
+		public final Timeout timeout;
+
+		public DecoratedTimeout(SelectableChannel channel, Timeout timeout) {
+			this.channel = channel;
+			this.timeout = timeout;
+		}
+
+		@Override
+		public int compareTo(DecoratedTimeout that) {
+			long diff = timeout.getTimeout() - that.timeout.getTimeout();
+			if (diff < 0) {
+				return -1;
+			} else if (diff > 0) {
+				return 1; 
+			} 
+			if (channel != null && that.channel != null) {
+				return channel.hashCode() - that.channel.hashCode(); 
+			} else if (channel == null && that.channel != null){
+				return -1;
+			} else if (channel != null && that.channel == null){
+				return -1;
+			} else {
+				return 0;
+			}
+		}
+		
+	}
+	
+	private class TimeoutComparator implements Comparator<Timeout> {
+
+		@Override
+		public int compare(Timeout lhs, Timeout rhs) {
+			if (lhs == rhs) { 
+				return 0;
+			}
+			long diff = lhs.getTimeout() - rhs.getTimeout();
+			if (diff <= 0) {
+				return -1;
+			}
+			return 1;	/// else if (diff > 0) { 
+		}
+		
+	}
+
+}

Added: incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/io/timeout/Timeout.java
URL: http://svn.apache.org/viewvc/incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/io/timeout/Timeout.java?rev=1243729&view=auto
==============================================================================
--- incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/io/timeout/Timeout.java (added)
+++ incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/io/timeout/Timeout.java Mon Feb 13 23:07:46 2012
@@ -0,0 +1,63 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF 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 org.apache.awf.io.timeout;
+
+import java.nio.channels.SelectableChannel;
+
+import org.apache.awf.io.IOLoop;
+import org.apache.awf.util.Closeables;
+import org.apache.awf.web.AsyncCallback;
+
+
+public class Timeout {
+
+	private final long timeout;
+	private final AsyncCallback cb;
+	private boolean cancelled = false;
+	
+	public Timeout(long timeout, AsyncCallback cb) {
+		this.timeout = timeout;
+		this.cb = cb;
+	}
+
+	public long getTimeout() {
+		return timeout;
+	}
+	
+	public void cancel() {
+		cancelled = true;
+	}
+	
+	public boolean isCancelled() {
+		return cancelled;
+	}
+
+	public AsyncCallback getCallback() {
+		return cancelled ? AsyncCallback.nopCb : cb;
+	}
+	
+	public static Timeout newKeepAliveTimeout(final IOLoop ioLoop, final SelectableChannel clientChannel, long keepAliveTimeout) {
+		return new Timeout(
+				System.currentTimeMillis() + keepAliveTimeout,
+				new AsyncCallback() { public void onCallback() { Closeables.closeQuietly(ioLoop, clientChannel); } }
+		);
+	}
+
+}

Added: incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/io/timeout/TimeoutManager.java
URL: http://svn.apache.org/viewvc/incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/io/timeout/TimeoutManager.java?rev=1243729&view=auto
==============================================================================
--- incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/io/timeout/TimeoutManager.java (added)
+++ incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/io/timeout/TimeoutManager.java Mon Feb 13 23:07:46 2012
@@ -0,0 +1,39 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF 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 org.apache.awf.io.timeout;
+
+import java.nio.channels.SelectableChannel;
+
+
+public interface TimeoutManager {
+
+	void addTimeout(Timeout timeout);
+	
+	void addKeepAliveTimeout(SelectableChannel channel, Timeout timeout);
+	
+	boolean hasKeepAliveTimeout(SelectableChannel channel);
+	
+	/**
+	 * 
+	 * @return the positive number (>0) in milliseconds until the deadline for the next scheduled timeout.
+	 */
+	long execute();
+	
+}

Added: incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/io/timeout/TimeoutManagerMXBean.java
URL: http://svn.apache.org/viewvc/incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/io/timeout/TimeoutManagerMXBean.java?rev=1243729&view=auto
==============================================================================
--- incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/io/timeout/TimeoutManagerMXBean.java (added)
+++ incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/io/timeout/TimeoutManagerMXBean.java Mon Feb 13 23:07:46 2012
@@ -0,0 +1,28 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF 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 org.apache.awf.io.timeout;
+
+public interface TimeoutManagerMXBean {
+
+	int getNumberOfTimeouts();
+	
+	int getNumberOfKeepAliveTimeouts();
+	
+}

Added: incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/util/AcceptUtil.java
URL: http://svn.apache.org/viewvc/incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/util/AcceptUtil.java?rev=1243729&view=auto
==============================================================================
--- incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/util/AcceptUtil.java (added)
+++ incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/util/AcceptUtil.java Mon Feb 13 23:07:46 2012
@@ -0,0 +1,57 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF 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 org.apache.awf.util;
+
+import java.io.IOException;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.ServerSocketChannel;
+
+import org.apache.awf.io.IOHandler;
+import org.apache.awf.io.IOLoop;
+import org.apache.awf.web.AsyncCallback;
+
+public class AcceptUtil {
+
+    public static void accept(ServerSocketChannel server, final AsyncCallback cb) {
+        accept(IOLoop.INSTANCE, server, cb);
+    }
+
+    public static void accept(IOLoop ioLoop, ServerSocketChannel server, final AsyncCallback cb) {
+        ioLoop.addHandler(server, new AcceptingIOHandler() {
+            public void handleAccept(SelectionKey key) {
+                cb.onCallback();
+            }
+        }, SelectionKey.OP_ACCEPT, null);
+    }
+
+    private static abstract class AcceptingIOHandler implements IOHandler {
+
+        public void handleConnect(SelectionKey key) throws IOException {
+        }
+
+        public void handleRead(SelectionKey key) throws IOException {
+        }
+
+        public void handleWrite(SelectionKey key) {
+        }
+
+    }
+
+}

Added: incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/util/ArrayUtil.java
URL: http://svn.apache.org/viewvc/incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/util/ArrayUtil.java?rev=1243729&view=auto
==============================================================================
--- incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/util/ArrayUtil.java (added)
+++ incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/util/ArrayUtil.java Mon Feb 13 23:07:46 2012
@@ -0,0 +1,42 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF 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 org.apache.awf.util;
+
+public class ArrayUtil {
+
+    // private static final List<String> EMPTY_STRING_LIST = Arrays.asList("");
+    // private static final String[] EMPTY_STRING_ARRAY = new String[0];
+    public static String[] dropFromEndWhile(String[] array, String regex) {
+        for (int i = array.length - 1; i >= 0; i--) {
+            if (!array[i].trim().equals("")) {
+                String[] trimmedArray = new String[i + 1];
+                System.arraycopy(array, 0, trimmedArray, 0, i + 1);
+                return trimmedArray;
+            }
+        }
+        return null;
+        // { // alternative impl
+        // List<String> list = new ArrayList<String>(Arrays.asList(array));
+        // list.removeAll(EMPTY_STRING_LIST);
+        // return list.toArray(EMPTY_STRING_ARRAY);
+        // }
+    }
+
+}

Added: incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/util/Closeables.java
URL: http://svn.apache.org/viewvc/incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/util/Closeables.java?rev=1243729&view=auto
==============================================================================
--- incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/util/Closeables.java (added)
+++ incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/util/Closeables.java Mon Feb 13 23:07:46 2012
@@ -0,0 +1,44 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF 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 org.apache.awf.util;
+
+import java.io.IOException;
+import java.nio.channels.SelectableChannel;
+
+import org.apache.awf.io.IOLoop;
+
+public class Closeables {
+
+    private Closeables() {
+    }
+
+    public static void closeQuietly(SelectableChannel channel) {
+        closeQuietly(IOLoop.INSTANCE, channel);
+    }
+
+    public static void closeQuietly(IOLoop ioLoop, SelectableChannel channel) {
+        try {
+            ioLoop.removeHandler(channel);
+            com.google.common.io.Closeables.close(channel, true);
+        } catch (IOException ignore) {
+        }
+    }
+
+}

Added: incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/util/CookieUtil.java
URL: http://svn.apache.org/viewvc/incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/util/CookieUtil.java?rev=1243729&view=auto
==============================================================================
--- incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/util/CookieUtil.java (added)
+++ incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/util/CookieUtil.java Mon Feb 13 23:07:46 2012
@@ -0,0 +1,38 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF 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 org.apache.awf.util;
+
+/**
+ * Utility type providing cookie-related functionality.
+ */
+public class CookieUtil {
+
+    /**
+     * Utility method to calculate the expiration date of a cookie, starting
+     * with a time of validity in seconds.
+     * 
+     * @param seconds time of validity
+     * @return expiry date
+     */
+    public static String maxAgeToExpires(Long seconds) {
+        return DateUtil.parseToRFC1123(System.currentTimeMillis() + seconds * 1000);
+    }
+
+}

Added: incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/util/DateUtil.java
URL: http://svn.apache.org/viewvc/incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/util/DateUtil.java?rev=1243729&view=auto
==============================================================================
--- incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/util/DateUtil.java (added)
+++ incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/util/DateUtil.java Mon Feb 13 23:07:46 2012
@@ -0,0 +1,118 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF 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 org.apache.awf.util;
+
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
+import java.util.regex.Pattern;
+
+public class DateUtil {
+
+    private final static Locale LOCALE = Locale.US;
+    private final static TimeZone GMT_ZONE;
+    private final static String RFC_1123_PATTERN = "EEE, dd MMM yyyy HH:mm:ss zzz";
+    private final static DateFormat RFC_1123_FORMAT;
+
+    /** Pattern to find digits only. */
+    private final static Pattern DIGIT_PATTERN = Pattern.compile("^\\d+$");
+
+    static {
+        RFC_1123_FORMAT = new SimpleDateFormat(DateUtil.RFC_1123_PATTERN, DateUtil.LOCALE);
+        GMT_ZONE = TimeZone.getTimeZone("GMT");
+        DateUtil.RFC_1123_FORMAT.setTimeZone(DateUtil.GMT_ZONE);
+    }
+
+    public static String getCurrentAsString() {
+        return DateUtil.RFC_1123_FORMAT.format(new Date());
+    }
+
+    /**
+     * Translate a given date <code>String</code> in the <em>RFC 1123</em>
+     * format to a <code>long</code> representing the number of milliseconds
+     * since epoch.
+     * 
+     * @param dateString a date <code>String</code> in the <em>RFC 1123</em>
+     *            format.
+     * @return the parsed <code>Date</code> in milliseconds.
+     */
+    private static long parseDateStringToMilliseconds(final String dateString) {
+
+        try {
+            return DateUtil.RFC_1123_FORMAT.parse(dateString).getTime();
+        } catch (final ParseException e) {
+            return 0;
+        }
+    }
+
+    /**
+     * Parse a given date <code>String</code> to a <code>long</code>
+     * representation of the time. Where the provided value is all digits the
+     * value is returned as a <code>long</code>, otherwise attempt is made to
+     * parse the <code>String</code> as a <em>RFC 1123</em> date.
+     * 
+     * @param dateValue the value to parse.
+     * @return the <code>long</code> value following parse, or zero where not
+     *         successful.
+     */
+    public static long parseToMilliseconds(final String dateValue) {
+
+        long ms = 0;
+
+        if (DateUtil.DIGIT_PATTERN.matcher(dateValue).matches()) {
+            ms = Long.parseLong(dateValue);
+        } else {
+            ms = parseDateStringToMilliseconds(dateValue);
+        }
+
+        return ms;
+    }
+
+    /**
+     * Converts a millisecond representation of a date to a
+     * <code>RFC 1123</code> formatted <code>String</code>.
+     * 
+     * @param dateValue the <code>Date</code> represented as milliseconds.
+     * @return a <code>String</code> representation of the date.
+     */
+    public static String parseToRFC1123(final long dateValue) {
+
+        final Calendar calendar = Calendar.getInstance();
+        calendar.setTimeInMillis(dateValue);
+
+        return DateUtil.RFC_1123_FORMAT.format(calendar.getTime());
+    }
+
+    /**
+     * Convert a given <code>Date</code> object to a <code>RFC 1123</code>
+     * formatted <code>String</code>.
+     * 
+     * @param date the <code>Date</code> object to convert
+     * @return a <code>String</code> representation of the date.
+     */
+    public static String getDateAsString(Date date) {
+        return RFC_1123_FORMAT.format(date);
+    }
+
+}

Added: incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/util/HttpUtil.java
URL: http://svn.apache.org/viewvc/incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/util/HttpUtil.java?rev=1243729&view=auto
==============================================================================
--- incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/util/HttpUtil.java (added)
+++ incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/util/HttpUtil.java Mon Feb 13 23:07:46 2012
@@ -0,0 +1,68 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF 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 org.apache.awf.util;
+
+import java.io.File;
+import java.math.BigInteger;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+import org.apache.awf.web.http.HttpRequest;
+
+public class HttpUtil {
+
+    /*
+     * MessageDigest are not thread-safe and are expensive to create. Do it
+     * lazily for each thread that need access to one.
+     */
+    private static final ThreadLocal<MessageDigest> md = new ThreadLocal<MessageDigest>();
+
+    public static boolean verifyRequest(HttpRequest request) {
+        String version = request.getVersion();
+        boolean requestOk = true;
+        if (version.equals("HTTP/1.1")) { // TODO might be optimized? Could do
+            // version.endsWith("1"), or similar
+            requestOk = request.getHeader("host") != null;
+        }
+
+        return requestOk;
+    }
+
+    public static String getEtag(byte[] bytes) {
+        if (md.get() == null) {
+            try {
+                md.set(MessageDigest.getInstance("MD5"));
+            } catch (NoSuchAlgorithmException e) {
+                throw new RuntimeException("MD5 cryptographic algorithm is not available.", e);
+            }
+        }
+        byte[] digest = md.get().digest(bytes);
+        BigInteger number = new BigInteger(1, digest);
+        // prepend a '0' to get a proper MD5 hash
+        return '0' + number.toString(16);
+
+    }
+
+    public static String getEtag(File file) {
+        // TODO RS 101011 Implement if etag response header should be present
+        // while static file serving.
+        return "";
+    }
+}

Added: incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/util/KnuthMorrisPrattAlgorithm.java
URL: http://svn.apache.org/viewvc/incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/util/KnuthMorrisPrattAlgorithm.java?rev=1243729&view=auto
==============================================================================
--- incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/util/KnuthMorrisPrattAlgorithm.java (added)
+++ incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/util/KnuthMorrisPrattAlgorithm.java Mon Feb 13 23:07:46 2012
@@ -0,0 +1,78 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF 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 org.apache.awf.util;
+
+/**
+ * The Knuth Morris Pratt string searching algorithm (or KMP algorithm) searches
+ * for occurrences of a "word" W within a main "text string" S by employing the
+ * observation that when a mismatch occurs, the word itself embodies sufficient
+ * information to determine where the next match could begin, thus bypassing
+ * re-examination of previously matched characters.
+ * 
+ * The algorithm was conceived by Donald Knuth and Vaughan Pratt and
+ * independently by James H. Morris in 1977, but the three published it jointly.
+ * 
+ */
+
+public class KnuthMorrisPrattAlgorithm {
+
+    /**
+     * Search for pattern in data, [start, end). Returns -1 if no match is found
+     * or if pattern is of length 0.
+     */
+    public static int indexOf(byte[] data, int start, int end, byte[] pattern) {
+        if (pattern.length == 0) {
+            return -1;
+        }
+        int[] failure = failure(pattern);
+
+        int j = 0;
+
+        for (int i = 0; i < end; i++) {
+            while (j > 0 && pattern[j] != data[i]) {
+                j = failure[j - 1];
+            }
+            if (pattern[j] == data[i]) {
+                j++;
+            }
+            if (j == pattern.length) {
+                return i - pattern.length + 1;
+            }
+        }
+        return -1;
+    }
+
+    private static int[] failure(byte[] pattern) {
+        int[] failure = new int[pattern.length];
+
+        int j = 0;
+        for (int i = 1; i < pattern.length; i++) {
+            while (j > 0 && pattern[j] != pattern[i]) {
+                j = failure[j - 1];
+            }
+            if (pattern[j] == pattern[i]) {
+                j++;
+            }
+            failure[i] = j;
+        }
+
+        return failure;
+    }
+}

Added: incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/util/MXBeanUtil.java
URL: http://svn.apache.org/viewvc/incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/util/MXBeanUtil.java?rev=1243729&view=auto
==============================================================================
--- incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/util/MXBeanUtil.java (added)
+++ incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/util/MXBeanUtil.java Mon Feb 13 23:07:46 2012
@@ -0,0 +1,47 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF 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 org.apache.awf.util;
+
+import java.lang.management.ManagementFactory;
+
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class MXBeanUtil {
+
+    private static final Logger logger = LoggerFactory.getLogger(MXBeanUtil.class);
+
+    private MXBeanUtil() {
+    }
+
+    public static void registerMXBean(Object self, String type) {
+        MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
+        try {
+            String mbeanName = "org.apache.awf:type=" + type + ",name=" + self.getClass().getSimpleName();
+            mbs.registerMBean(self, new ObjectName(mbeanName));
+        } catch (Exception e) {
+            logger.error("Unable to register {} MXBean: {}", self.getClass().getCanonicalName(), e);
+        }
+    }
+
+}

Added: incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/util/NopAsyncResult.java
URL: http://svn.apache.org/viewvc/incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/util/NopAsyncResult.java?rev=1243729&view=auto
==============================================================================
--- incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/util/NopAsyncResult.java (added)
+++ incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/util/NopAsyncResult.java Mon Feb 13 23:07:46 2012
@@ -0,0 +1,47 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF 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 org.apache.awf.util;
+
+import org.apache.awf.web.AsyncResult;
+
+/**
+ * Convenience class used to limit the Java verboseness.
+ */
+public class NopAsyncResult<T> {
+
+    private NopAsyncResult() {
+    }
+
+    public final AsyncResult<T> nopAsyncResult = new AsyncResult<T>() {
+
+        @Override
+        public void onFailure(Throwable caught) {
+        }
+
+        @Override
+        public void onSuccess(T result) {
+        }
+
+    };
+
+    public static <T> NopAsyncResult<T> of(Class<T> type) {
+        return new NopAsyncResult<T>();
+    }
+}

Added: incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/util/Pair.java
URL: http://svn.apache.org/viewvc/incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/util/Pair.java?rev=1243729&view=auto
==============================================================================
--- incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/util/Pair.java (added)
+++ incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/util/Pair.java Mon Feb 13 23:07:46 2012
@@ -0,0 +1,35 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF 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 org.apache.awf.util;
+
+public class Pair<T1, T2> {
+
+    public final T1 _1;
+    public final T2 _2;
+
+    public Pair(T1 first, T2 second) {
+        this._1 = first;
+        this._2 = second;
+    }
+
+    public static <X, Y> Pair<X, Y> of(X _1, Y _2) {
+        return new Pair<X, Y>(_1, _2);
+    }
+}

Added: incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/util/ReflectionTools.java
URL: http://svn.apache.org/viewvc/incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/util/ReflectionTools.java?rev=1243729&view=auto
==============================================================================
--- incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/util/ReflectionTools.java (added)
+++ incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/util/ReflectionTools.java Mon Feb 13 23:07:46 2012
@@ -0,0 +1,62 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF 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 org.apache.awf.util;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Common functionality relating to the use of Reflection.
+ */
+public class ReflectionTools {
+
+    private final static Logger logger = LoggerFactory.getLogger(ReflectionTools.class);
+
+    /**
+     * Prevent instantiation of this type.
+     */
+    private ReflectionTools() {
+        // Do nothing.
+    }
+
+    /**
+     * Create an instance of the given type.
+     * 
+     * @param fqcn the fully-qualified class name of the required type.
+     * @return an <code>Object</code> of the requested type, or
+     *         <code>null</code> on any problem.
+     */
+    public static Object createInstance(String fqcn) {
+
+        Object instance = null;
+
+        try {
+            instance = Class.forName(fqcn).newInstance();
+        } catch (InstantiationException e) {
+            logger.error("InstantiationException", e);
+        } catch (IllegalAccessException e) {
+            logger.error("IllegalAccessException", e);
+        } catch (ClassNotFoundException e) {
+            logger.error("ClassNotFoundException", e);
+        }
+
+        return instance;
+    }
+}

Added: incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/util/UrlUtil.java
URL: http://svn.apache.org/viewvc/incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/util/UrlUtil.java?rev=1243729&view=auto
==============================================================================
--- incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/util/UrlUtil.java (added)
+++ incubator/deft/trunk/awf-core/src/main/java/org/apache/awf/util/UrlUtil.java Mon Feb 13 23:07:46 2012
@@ -0,0 +1,51 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF 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 org.apache.awf.util;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+
+public class UrlUtil {
+
+    /**
+     * Example:
+     * 
+     * <pre>
+     * {@code 
+     * url: http://tt.se/                 Location: /start              =>  http://tt.se/start
+     * url: http://localhost/moved_perm   Location: /                   =>  http://localhost/
+     * url: http://github.com/            Location: http://github.com/  =>  https://github.com/
+     * }
+     * 
+     * (If the new url throws a MalformedURLException the url String representation will be returned.)
+     */
+    public static String urlJoin(URL url, String locationHeader) {
+        try {
+            if (locationHeader.startsWith("http")) {
+                return new URL(locationHeader).toString();
+            }
+            return new URL(url.getProtocol() + "://" + url.getAuthority() + locationHeader).toString();
+        } catch (MalformedURLException e) {
+            return url.toString();
+        }
+
+    }
+
+}