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();
+ }
+
+ }
+
+}