pax_global_header00006660000000000000000000000064122744610400014512gustar00rootroot0000000000000052 comment=e6cb898455ebffa7113c0e88aa39c7664d9d238f hawtdispatch-hawtdispatch-project-1.20/000077500000000000000000000000001227446104000202445ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/.gitignore000066400000000000000000000001451227446104000222340ustar00rootroot00000000000000.classpath .project .settings *.iml *.ipr *.iws webgen/out webgen/webgen.cache target .DS_Store .ideahawtdispatch-hawtdispatch-project-1.20/build.gradle000066400000000000000000000021121227446104000225170ustar00rootroot00000000000000subprojects { apply plugin: 'java' repositories { mavenCentral() } dependencies { compile 'asm:asm-tree:3.1', 'org.osgi:org.osgi.core:4.2.0', 'org.osgi:org.osgi.compendium:4.2.0', 'log4j:log4j:1.2.14', 'org.fusesource.hawtbuf:hawtbuf:1.9' testCompile 'junit:junit:4.7' } tasks.withType(Compile) { options.encoding = 'UTF-8' options.warnings = false } } project(':hawtdispatch-example') { dependencies { compile project(':hawtdispatch-scala'), project(':hawtdispatch-transport'), 'org.scala-lang:scala-library:2.10.0', 'org.scala-lang:scala-compiler:2.10.0' testCompile 'org.scalatest:scalatest_2.10.0:2.10.0' } } project(':hawtdispatch-netty') { dependencies { compile 'io.netty:netty-transport:4.0.0.Beta1', project(':hawtdispatch') } } project(':hawtdispatch-scala') { dependencies { compile 'iorg.scala-lang:scala-library:2.10.0', project(':hawtdispatch') testCompile 'org.scalatest:scalatest_2.10.0:2.10.0' } } project(':hawtdispatch-transport') { dependencies { compile project(':hawtdispatch') } } hawtdispatch-hawtdispatch-project-1.20/changelog.md000066400000000000000000000223501227446104000225170ustar00rootroot00000000000000# ![HawtDispatch](http://hawtdispatch.fusesource.org/images/project-logo.png) ============================================================================= ## [HawtDispatch 1.19](http://hawtdispatch.fusesource.org/blog/releases/release-1-19.html), released 2014-01-23 * You can now configure the what cypher suites are enabled on a SSLTransport via the enabledCypherSuites property * add gradle build script * Fix range check on timeout, as it always evaluated to true * Fixing bugs where the read/write rate limiting features of the tcp transport might not take effect. ## [HawtDispatch 1.18](http://hawtdispatch.fusesource.org/blog/releases/release-1-18.html), released 2013-10-11 * Do not even invoke getLocalHost() if not necessary * propagate name resolution exceptions in the correct thread context * Fixes issue #11 : Typo in TcpTransportServer ## [HawtDispatch 1.17](http://hawtdispatch.fusesource.org/blog/releases/release-1-17.html), released 2013-05-18 * Add a get method to Future objects. * Fixing bug where SSL transports were not getting past the SSL handshake (on linux). ## [HawtDispatch 1.16](http://hawtdispatch.fusesource.org/blog/releases/release-1-16.html), released 2013-05-10 * Fixing invalid the metric duration value. * Do a better job ignoring errors when JMX is not supported by the platform. (Android etc.) * Fixes issue #9: HawtDispatch does not work on Android 4.0 ## [HawtDispatch 1.15](http://hawtdispatch.fusesource.org/blog/releases/release-1-15.html), released 2013-04-19 * Also include info about how long the metric was monitored for. * Expose dispatch queue profiling data via JMX. ## [HawtDispatch 1.14](http://hawtdispatch.fusesource.org/blog/releases/release-1-14.html), released 2013-04-09 * Fixes bug where you could end up in a CPU spin when the SSL session closed. * Added a disabledCypherSuites property to the SSL transports to support disabling some of the supported cypher suites. * Add a getThread() method to the ThreadDispatchQueue class. ## [HawtDispatch 1.13](http://hawtdispatch.fusesource.org/blog/releases/release-1-13.html), released 2012-12-23 * Upgrade to scala 2.10 * Avoid possible NPE. * Setup the client SSL transports so that the internal session reuse strategy can be used. ## [HawtDispatch 1.12](http://hawtdispatch.fusesource.org/blog/releases/release-1-12.html), released 2012-09-20 * Custom dispatch sources will now return null after the event has been received to avoid accidentally double processing events. * Make sure we only return false from the offer method when the transport is also full() * Add a closeOnCancel option to disable closing the socket when the transport is stopped. * Rename the SecuredTransport interface to SecuredSession and now both the SSLProtocolCodec and SslTransport implement it. * You can now handle SSL/TLS encoding/decoding via a wrapping protocol codec. ProtocolCodec and Transport interfaces needs a couple of adjustments to properly support the co * Better handling of getting the local host address. * Protocol codec decoding optimizations. * Move all the connect logic into the start method. * Do host name resolutions on a blocking executor to avoid stalling the hawtdispatch threads. * Resize the read buffer after reading from the channel if to avoid to avoid holding on to large buffers. * Support changing the socket send/recv buffer size on started transports and servers. * Do at least a non blocking select when we notice that another thread requested the NIO manager wakeup. This should allow us to pickup any new IO events that have occurred * Dropped the continuations example, added a SSL transport client example ## [HawtDispatch 1.11](http://hawtdispatch.fusesource.org/blog/releases/release-1-11.html), released 2012-05-02 * Support buffer pooling in the abstract protocol codec. * Adding a TransportAware interface which codecs can implement to be injected with their associated codec. * Make it easy to configure the client auth mode on the ssl transport server. * Fixes SSL transport bug where inbound data was not delivered after SSL handshake completed. * Allow a SslTransportServer to be created just using the constructor. ## [HawtDispatch 1.10](http://hawtdispatch.fusesource.org/blog/releases/release-1-10.html), released 2012-04-06 * Fix assertion error message. * Switch to using 'Task' abstract base instead of the Runnable interface, in many cases it improves perf by 20% since virtual invocations are cheaper then interface invocation * Adding a UDP based transport. * Support configuring the client auth mode. ## [HawtDispatch 1.9](http://hawtdispatch.fusesource.org/blog/releases/release-1-9.html), released 2012-02-27 * Fixes LOW priority global queue was being created with a high thread priority. * Distribute work load spikes fairly to the worker threads. * Support updating the transport's dispatch queue. * Add assertion that catches the following error: queue.setTargetQueue(queue) * Adding a SecureTransport interface and removing many of the leaky abstractions in the transport package. ## [HawtDispatch 1.8](http://hawtdispatch.fusesource.org/blog/releases/release-1-8.html), released 2012-01-30 * Fixes CPU spin that occurred when a peer disconnected while SSL handshake is in progress. * Could not create a client initiated SSL connection. ## [HawtDispatch 1.7](http://hawtdispatch.fusesource.org/blog/releases/release-1-7.html), released 2012-01-13 * Cleaning up the transport interfaces. Added an abstract protocol codec that makes it easier to implement them. ## [HawtDispatch 1.6](http://hawtdispatch.fusesource.org/blog/releases/release-1-6.html), released 2011-12-19 * Support using a system property to configure the number of dispatch threads. * Added a hawtdispatch-transport module which provides nice Transport abstraction for working with Sockets and HawtDispatch. ## [HawtDispatch 1.5](http://hawtdispatch.fusesource.org/blog/releases/release-1-5.html), released 2011-11-29 * HawtDispatch threads are now in a thread group. Setting the UnchaughtExceptionHandler on one of the HawtDispatch threads set the handler for all the threads in the pool. * Pass an uncaught exceptions to the UncaughtExceptionHandler configured on the HawtDispatch threads. * Added UDP example * Fix race condition that was occurring when a serial dispatch queue was suspended. * Switch to new scalate version which fixes build problems when on OS X Lion. ## [HawtDispatch 1.4](http://hawtdispatch.fusesource.org/blog/releases/release-1-4.html), released 2011-07-18 * Support ordered EventAggregators ## [HawtDispatch 1.3](http://hawtdispatch.fusesource.org/blog/releases/release-1-3.html), released 2011-06-01 * Added an assertExecuting method to the DispatchQueue interface. * Protect against exceptions from the event dispatch source handlers. * Upgrade to Scala 2.9.0-1 ## [HawtDispatch 1.2](http://hawtdispatch.fusesource.org/blog/releases/release-1-2.html), released 2011-01-20 * Protect against exceptions from the event dispatch source handlers. * Adding a new HawtServerSocketChannel and HawtSocketChannel which use scala continuations and hawtdispatch to implement NIO based sockets * Enriching executors with a `runnable` - enriching dispatch queues with a `repeatAfter` method * Trimming dead code. * Inline the dispatch a bit. * Making dispatch queue interface more consistent with java executors. renamed dispatchAsync to just plain execute, and renamed dispatchAfter to executeAfter * Removing the Retained interface from the dispatch objects. It adds complexity and overhead without providing the much benefit due to the JVM's automatic GC * Added scala type getter/setters for the a dispatch queue label. * Protect against ConcurrentModificationException on the selector's selecteKeys. * Enriched the DispatchSource objects * Added some doco on the new `!!` method. * Adjusted paul's auto reset method so that it also returns a future. * Added await methods to the future since they are easier to spot than the apply methods. * Support for function, !^, that wraps a partial function in a reset block, thus hiding shift/reset. * OSGi integration, added activator so that started thread can be shutdown when the bundle is stopped. Also exposed the Dispatch interface * Added OSGi metadata to the jars. ## [HawtDispatch 1.1](http://hawtdispatch.fusesource.org/blog/releases/release-1-1.html), released 2011-01-20 * Fix bug where the scala version of getCurrentThreadQueue was returning null * A Future can trigger a callback once it's completed. * Scala continuation support added. * Built against Scala 2.8.1 * The maximum number of executions drained from a serial queue before checking global queues for more work is now configurable via the `hawtdispatch.drains` system property. * createSerialQueue renamed to createQueue to make the API more consistent. * Handling the case where a selector key is canceled during registration. * Timer thread is more efficient now. * Added a AggregatingExecutor to batch up executions * You can now hook into getting profiling statistics of the dispatch queues * Fixed the INTEGER_OR aggregator * Scala usage simplification, import org.fusesource.hawtdispatch._ instead of org.fusesource.hawtdispatch.ScalaDispatch._ * More test cases * Add getThreadQueue method ## [HawtDispatch 1.0](http://hawtdispatch.fusesource.org/blog/releases/release-1-0.html), released 2010-07-22 * Initial releasehawtdispatch-hawtdispatch-project-1.20/hawtdispatch-example/000077500000000000000000000000001227446104000243605ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-example/pom.xml000077500000000000000000000130001227446104000256720ustar00rootroot00000000000000 4.0.0 org.fusesource.hawtdispatch hawtdispatch-project 1.20 org.fusesource.hawtdispatch hawtdispatch-example 1.20 HawtDispatch: Examples org.fusesource.hawtbuf hawtbuf 1.1 org.fusesource.hawtdispatch hawtdispatch-scala 1.20 org.fusesource.hawtdispatch hawtdispatch-transport 1.20 org.fusesource.hawtbuf hawtbuf ${hawtbuf-version} org.scala-lang scala-library ${scala-version} provided org.scala-lang scala-compiler ${scala-version} provided org.scalatest scalatest_${scala-version} ${scalatest-version} test junit junit ${junit-version} test log4j log4j ${log4j-version} test install src/main/scala src/test/scala net.alchim31.maven scala-maven-plugin 3.1.0 compile testCompile scala.tools.nsc.ScalaDoc -Xmx1024m -deprecation -P:continuations:enable ${scala-version} org.scala-lang.plugins continuations ${scala-version} maven-surefire-plugin 2.4.3 false false true false idea net.alchim31.maven scala-maven-plugin 3.1.0 -deprecation -P:continuations:enable org.scala-lang.plugins continuations ${scala-version} hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-example/src/000077500000000000000000000000001227446104000251475ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-example/src/main/000077500000000000000000000000001227446104000260735ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-example/src/main/scala/000077500000000000000000000000001227446104000271565ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-example/src/main/scala/org/000077500000000000000000000000001227446104000277455ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-example/src/main/scala/org/fusesource/000077500000000000000000000000001227446104000321305ustar00rootroot00000000000000000077500000000000000000000000001227446104000345345ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-example/src/main/scala/org/fusesource/hawtdispatch000077500000000000000000000000001227446104000361675ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-example/src/main/scala/org/fusesource/hawtdispatch/exampleCustomDispatchSourceJava.java000066400000000000000000000037411227446104000437540ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-example/src/main/scala/org/fusesource/hawtdispatch/example/** * Copyright (C) 2012 FuseSource, Inc. * http://fusesource.com * * Licensed 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.fusesource.hawtdispatch.example; import org.fusesource.hawtdispatch.*; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Semaphore; import static org.fusesource.hawtdispatch.Dispatch.*; /** *

*

* * @author Hiram Chirino */ public class CustomDispatchSourceJava { public static void main(String[] args) throws Exception { run(); } public static void run() throws Exception { final Semaphore done = new Semaphore(1-(1000*1000)); DispatchQueue queue = createQueue(); final CustomDispatchSource source = createSource(EventAggregators.INTEGER_ADD, queue); source.setEventHandler(new Task() { public void run() { int count = source.getData(); System.out.println("got: " + count); done.release(count); } }); source.resume(); // Produce 1,000,000 concurrent merge events for (int i = 0; i < 1000; i++) { getGlobalQueue().execute(new Task() { public void run() { for (int j = 0; j < 1000; j++) { source.merge(1); } } }); } // Wait for all the event to arrive. done.acquire(); } } CustomDispatchSourceScala.scala000066400000000000000000000030231227446104000442510ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-example/src/main/scala/org/fusesource/hawtdispatch/example/** * Copyright (C) 2012 FuseSource, Inc. * http://fusesource.com * * Licensed 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.fusesource.hawtdispatch.example import java.util.concurrent.Semaphore import org.fusesource.hawtdispatch._ import org.fusesource.hawtdispatch.EventAggregators /** *

*

* * @author Hiram Chirino */ object CustomDispatchSourceScala { def main(args: Array[String]): Unit = { run } def run() = { val done = new Semaphore(1 - (1000 * 1000)) val queue = createQueue() val source = createSource(EventAggregators.INTEGER_ADD, queue) source.setEventHandler(^{ val count = source.getData() println("got: " + count) done.release(count.intValue) }); source.resume(); // Produce 1,000,000 concurrent merge events for (i <- 0 until 1000) { globalQueue { for (j <- 0 until 1000) { source.merge(1) } } } // Wait for all the event to arrive. done.acquire() } } EchoServer.scala000066400000000000000000000065551227446104000412540ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-example/src/main/scala/org/fusesource/hawtdispatch/example/** * Copyright (C) 2012 FuseSource, Inc. * http://fusesource.com * * Licensed 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.fusesource.hawtdispatch.example import java.io.{IOException} import java.net.{InetSocketAddress} import org.fusesource.hawtdispatch._ import java.nio.ByteBuffer; import java.nio.channels.SelectionKey; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; /** * A simple echo server example. * * @author Hiram Chirino */ object EchoServer { var port=4444; def main(args:Array[String]):Unit = { run } def run() = { val server = new Server(port).start println("Press enter to shutdown."); System.in.read server.stop } class Server(val port: Int) { val channel = ServerSocketChannel.open(); channel.socket().bind(new InetSocketAddress(port)); channel.configureBlocking(false); val queue = createQueue("server") val accept_source = createSource(channel, SelectionKey.OP_ACCEPT, queue); accept_source.setEventHandler(^ { val socket = channel.accept(); try { socket.configureBlocking(false); new Session(socket).start() } catch { case e: Exception => socket.close } }); println("Listening on port: "+port); def start() = { accept_source.resume this } def stop() = { accept_source.cancel } accept_source.onCancel { channel.close(); println("Closed port: "+port); } } class Session(val channel: SocketChannel) { val buffer = ByteBuffer.allocate(1024); val queue = createQueue("session") val read_source = createSource(channel, SelectionKey.OP_READ, queue); val write_source = createSource(channel, SelectionKey.OP_WRITE, queue); val remote_address = channel.socket.getRemoteSocketAddress.toString def start() = { println("Accepted connection from: "+remote_address); read_source.resume } def close() = { read_source.cancel } read_source.onCancel { write_source.cancel } write_source.onCancel { channel.close println("Closed connection from: "+remote_address); } read_source.setEventHandler(^{ try { if (channel.read(buffer) == -1) { close } else { buffer.flip; if (buffer.remaining > 0) { read_source.suspend write_source.resume } else { buffer.clear } } } catch { case e:IOException => close } }) write_source.setEventHandler(^{ try { channel.write(buffer) if (buffer.remaining == 0) { buffer.clear write_source.suspend read_source.resume } } catch { case e:IOException => close } }) } } SSLClientExample.java000066400000000000000000000121451227446104000421510ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-example/src/main/scala/org/fusesource/hawtdispatch/example/** * Copyright (C) 2012 FuseSource, Inc. * http://fusesource.com * * Licensed 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.fusesource.hawtdispatch.example; import org.fusesource.hawtbuf.AsciiBuffer; import org.fusesource.hawtbuf.Buffer; import org.fusesource.hawtdispatch.Dispatch; import org.fusesource.hawtdispatch.Task; import org.fusesource.hawtdispatch.transport.AbstractProtocolCodec; import org.fusesource.hawtdispatch.transport.DefaultTransportListener; import org.fusesource.hawtdispatch.transport.SslTransport; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import java.io.IOException; import java.net.URI; import java.security.SecureRandom; import java.security.cert.X509Certificate; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executors; /** */ public class SSLClientExample { // A fake trust manager to accept self signed certs. static final TrustManager[] TRUST_ALL_CERTS = new TrustManager[]{ new X509TrustManager() { public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; } public void checkClientTrusted(X509Certificate[] certs, String authType) { } public void checkServerTrusted(X509Certificate[] certs, String authType) { } } }; // A very simple codec that just passes along byte buffers.. // A more realistic example can be found at: // https://github.com/fusesource/stompjms/blob/master/stompjms-client/src/main/java/org/fusesource/stomp/codec/StompProtocolCodec.java private static class BufferProtocolCodec extends AbstractProtocolCodec { @Override protected void encode(Object value) throws IOException { Buffer buffer = (Buffer) value; nextWriteBuffer.write(buffer); } @Override protected Action initialDecodeAction() { return readCommand(); } protected Action readCommand() { return new Action() { public Object apply() throws IOException { int length = readBuffer.position() - readStart; if (length > 0) { int offset = readStart; readEnd = offset + length; readStart = readEnd; return new Buffer(readBuffer.array(), offset, length); } else { return null; } } }; } } public static void main(String[] args) throws Exception { // Setup an SSLContext that accepts self signed certs. SSLContext sslContext = SSLContext.getInstance("SSL"); sslContext.init(null, TRUST_ALL_CERTS, new SecureRandom()); final SslTransport client = new SslTransport(); client.setDispatchQueue(Dispatch.createQueue()); client.setSSLContext(sslContext); client.setBlockingExecutor(Executors.newCachedThreadPool()); client.setProtocolCodec(new BufferProtocolCodec()); client.connecting(new URI("ssl://localhost:61614"), null); final CountDownLatch done = new CountDownLatch(1); final Task onClose = new Task() { public void run() { System.out.println("Client closed."); done.countDown(); } }; client.setTransportListener(new DefaultTransportListener() { @Override public void onTransportConnected() { System.out.println("Connected"); client.resumeRead(); // Once we are connected send some data.. client.offer(new AsciiBuffer( "CONNECT\n" + "login:admin\n" + "passcode:password\n" + "\n\u0000\n" )); } // all we do is echo back the request, but change the frame, // command to RESPONSE. @Override public void onTransportCommand(Object command) { Buffer frame = (Buffer) command; System.out.println("Received :" + frame.ascii()); client.stop(onClose); } @Override public void onTransportFailure(IOException error) { System.out.println("Transport failure :" + error); client.stop(onClose); } }); client.start(Dispatch.NOOP); done.await(); } } UdpEchoServer.scala000066400000000000000000000114201227446104000417100ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-example/src/main/scala/org/fusesource/hawtdispatch/example/** * Copyright (C) 2012 FuseSource, Inc. * http://fusesource.com * * Licensed 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.fusesource.hawtdispatch.example import java.io.{IOException} import org.fusesource.hawtdispatch._ import java.nio.ByteBuffer import java.nio.channels.{DatagramChannel, SelectionKey, ServerSocketChannel, SocketChannel} import java.net.{SocketAddress, InetSocketAddress} import java.util.LinkedList /** * A udp echo server example. Concurrently reads and writes * packets by using 2 dispatch queues. Uses a custom dispatch * source to handle coalescing interaction events between * the sender and receiver queues. * * @author Hiram Chirino */ object UdpEchoServer { var port=4444; def main(args:Array[String]):Unit = { run } def run() = { val server = new Server(port) server.start println("Press enter to shutdown."); System.in.read server.close } class Server(val port: Int) { val channel = DatagramChannel.open(); channel.socket().bind(new InetSocketAddress(port)); channel.configureBlocking(false); println("Listening on port: "+port); object receiver { // All mutable state in this object is modified while executing // on this queue val queue = createQueue("receive") private var outbound = 0 private val outbound_max = 1024; val read_events = createSource(channel, SelectionKey.OP_READ, queue); read_events.onEvent { try { val buffer = ByteBuffer.allocate(1024); var address: SocketAddress = channel.receive(buffer); if( address!=null ) { buffer.flip; outbound += 1 sender.outbound_events.merge((buffer, address)) // stop receiving until the outbound is drained (aka: flow control) if ( outbound_max < outbound ) { read_events.suspend } } } catch { case e:IOException => close } } // outbound_ack_events is used to let the sender know when the sends complete val outbound_ack_events = createSource(EventAggregators.INTEGER_ADD, queue) outbound_ack_events.onEvent { outbound -= outbound_ack_events.getData() if(read_events.isSuspended) read_events.resume() } outbound_ack_events.resume(); } object sender { // All mutable state in this object is modified while executing // on this queue val queue = createQueue("send") // pick up outbound events private val outbound = new LinkedList[(ByteBuffer, SocketAddress)] // outbound_events is an event bridge between the receiver and the sender event queues // It will merge multiple events from the receiver queue into 1 event that gets delivered // to the sender queue val outbound_events = createSource(new ListEventAggregator[(ByteBuffer, SocketAddress)], queue) outbound_events.onEvent { for( value <- outbound_events.getData() ) { outbound.add(value) } drainOutbound } outbound_events.resume(); // We need to drain the list of outbound packets when socket reports it // can be written to. val write_events = createSource(channel, SelectionKey.OP_WRITE, queue); write_events.onEvent(drainOutbound) def drainOutbound:Unit = try { while(!outbound.isEmpty) { val (buffer, address) = outbound.peek(); channel.send(buffer, address) if(buffer.remaining()==0) { // Packet sent, let the receive know in case he stopped. receiver.outbound_ack_events.merge(1) outbound.poll() } else { // Could not complete the write, we may need // to resume the write source if(write_events.isSuspended) write_events.resume() return } } // Nothing left? then stop looking for write events if(!write_events.isSuspended) write_events.suspend } catch { case e:IOException => close } } def start() = { receiver.read_events.resume } def close() = { receiver.read_events.cancel sender.write_events.cancel channel.close } } } 000077500000000000000000000000001227446104000401765ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-example/src/main/scala/org/fusesource/hawtdispatch/example/discoveryEchoNetJava.java000066400000000000000000000346161227446104000432020ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-example/src/main/scala/org/fusesource/hawtdispatch/example/discovery/** * Copyright (C) 2012 FuseSource, Inc. * http://fusesource.com * * Licensed 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.fusesource.hawtdispatch.example.discovery; import org.fusesource.hawtdispatch.*; import static org.fusesource.hawtdispatch.Dispatch.*; import java.io.ByteArrayOutputStream; import java.io.EOFException; import java.io.IOException; import java.net.InetSocketAddress; import java.net.URI; import java.nio.ByteBuffer; import java.nio.channels.*; import java.util.ArrayList; import java.util.concurrent.TimeUnit; /** * An example of a networks of servers which advertise connection information to each other. */ public class EchoNetJava { public static void main(String[] args) throws Exception { run(); } public static void run() throws Exception { Server a = new Server(4444).start(); Server b = new Server(5555).start(); Server c = new Server(6666).start(); Thread.sleep(200); a.connect(3333); a.connect(b); b.connect(c); System.in.read(); } static class Server { final int port; final URI me; final ServerSocketChannel serverChannel; final ArrayList seen = new ArrayList(); final DispatchQueue queue; final DispatchSource accept_source; public Server(int port) throws Exception { this.port = port; this.me = URI.create("conn://localhost:" + port); this.serverChannel = ServerSocketChannel.open(); serverChannel.socket().bind(new InetSocketAddress(port)); serverChannel.configureBlocking(false); queue = createQueue(me.toString()); accept_source = createSource(serverChannel, SelectionKey.OP_ACCEPT, queue); accept_source.setEventHandler(new Task() { public void run() { // we are a server // when you are a server, we must first listen for the // address of the client before sending data. // once they send us their address, we will send our // full list of known addresses, followed by our own // address to signal that we are done. // Afterward we will only pulls our heartbeat SocketChannel client = null; try { client = serverChannel.accept(); InetSocketAddress address = (InetSocketAddress) client.socket().getRemoteSocketAddress(); trace("accept " + address.getPort()); client.configureBlocking(false); // Server sessions start by reading the client's greeting Session session = new Session(Server.this, client, address); session.start_read_greeting(); } catch (Exception e) { try { client.close(); } catch (IOException e1) { } } } }); accept_source.setCancelHandler(new Task() { public void run() { try { serverChannel.close(); } catch (Throwable e) { } } }); trace("Listening"); } public Server start() { accept_source.resume(); return this; } public void stop() { accept_source.suspend(); } public void close() { accept_source.cancel(); } public void connect(Server s) { connect(s.port); } public void connect(int port) { connect(URI.create("conn://localhost:" + port)); } public void connect(final URI uri) { queue.execute(new Task() { public void run() { if (me.equals(uri) || seen.contains(uri)) return; try { int port = uri.getPort(); String host = uri.getHost(); trace("open " + uri); final SocketChannel socketChannel = SocketChannel.open(); socketChannel.configureBlocking(false); final InetSocketAddress address = new InetSocketAddress(host, port); socketChannel.connect(address); final DispatchSource connect_source = createSource(socketChannel, SelectionKey.OP_CONNECT, queue); connect_source.setEventHandler(new Task() { public void run() { connect_source.cancel(); try { socketChannel.finishConnect(); trace("connected " + uri); Session session = new Session(Server.this, socketChannel, address, uri); session.start_write_greeting(); } catch (IOException e) { trace("connect to " + uri + " FAILED."); } } }); connect_source.resume(); seen.add(uri); } catch (IOException e) { e.printStackTrace(); } } }); } public void trace(String str) { System.out.println(String.format("%5d - %s", port, str)); } } static class Session { Server server; SocketChannel channel; InetSocketAddress address; URI uri; ByteBuffer read_buffer = ByteBuffer.allocate(1024); DispatchQueue queue; DispatchSource read_source; DispatchSource write_source; ArrayList seen; ArrayList listed = new ArrayList(); public Session(Server server, SocketChannel channel, InetSocketAddress address, URI uri) { this.server = server; this.channel = channel; this.address = address; this.uri = uri; this.queue = createQueue(uri.toString()); this.read_source = createSource(channel, SelectionKey.OP_READ, queue); this.write_source = createSource(channel, SelectionKey.OP_WRITE, queue); this.seen = new ArrayList(server.seen); } public Session(Server server, SocketChannel channel, InetSocketAddress address) { this(server, channel, address, URI.create("conn://" + address.getHostName() + ":" + address.getPort())); } public void start_read_greeting() { read_source.setEventHandler(read_greeting()); read_source.resume(); } public Task read_greeting() { return new Task() { public void run() { try { String message = read_frame(); if (message != null) { // stop looking for read events.. read_source.suspend(); URI uri = URI.create(message); trace("welcome"); // Send them our seen uris.. ArrayList list = new ArrayList(seen); list.remove(server.me); list.remove(uri); list.add("end"); start_write_data(new Task() { public void run() { start_read_hearbeat(); } }, list.toArray(new Object[list.size()])); } } catch (IOException e) { e.printStackTrace(); } } }; } public void start_write_greeting() throws IOException { trace("hello"); start_write_data(new Task() { public void run() { start_read_server_listings(); } }, server.me); } public void start_read_server_listings() { read_source.setEventHandler(read_server_listings()); read_source.resume(); } public Task read_server_listings() { return new Task() { public void run() { try { String message = read_frame(); if (message != null) { if (!message.equals("end")) { URI uri = URI.create(message); listed.add(uri); server.connect(uri); } else { // Send them our seen uris.. ArrayList list = new ArrayList(seen); list.removeAll(listed); list.remove(server.me); list.add("end"); start_write_data(new Task(){ public void run() { start_write_hearbeat(); } }, list.toArray(new Object[list.size()])); } } } catch (IOException e) { e.printStackTrace(); } } }; } public void start_read_client_listings() { read_source.setEventHandler(read_clientlistings()); read_source.resume(); } public Task read_clientlistings() { return new Task() { public void run() { try { String message = read_frame(); if (message != null) { if (!message.equals("end")) { server.connect(URI.create(message)); } else { start_read_hearbeat(); } } } catch (IOException e) { e.printStackTrace(); } } }; } public void start_write_hearbeat() { queue.executeAfter(1, TimeUnit.SECONDS, new Task() { public void run() { try { trace("ping"); start_write_data(new Task() { public void run() { start_write_hearbeat(); } }, "ping"); } catch (IOException e) { e.printStackTrace(); } } }); } public void start_read_hearbeat() { read_source.setEventHandler(read_hearbeat()); read_source.resume(); } public Task read_hearbeat() { return new Task() { public void run() { try { String message = read_frame(); if (message != null) { trace("pong"); } } catch (IOException e) { e.printStackTrace(); } } }; } public void start_write_data(Task onDone, Object... list) throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); for (Object next : list) { baos.write(next.toString().getBytes("UTF-8")); baos.write(0); } ByteBuffer buffer = ByteBuffer.wrap(baos.toByteArray()); write_source.setEventHandler(write_data(buffer, onDone)); write_source.resume(); } public Task write_data(final ByteBuffer buffer, final Task onDone) { return new Task() { public void run() { try { channel.write(buffer); if (buffer.remaining() == 0) { write_source.suspend(); onDone.run(); } } catch (IOException e) { e.printStackTrace(); } } }; } public String read_frame() throws IOException { if (channel.read(read_buffer) == -1) { throw new EOFException(); } byte[] buf = read_buffer.array(); int endPos = eof(buf, 0, read_buffer.position()); if (endPos < 0) { trace(" --- "); return null; } String rc = new String(buf, 0, endPos); int newPos = read_buffer.position() - endPos; System.arraycopy(buf, endPos + 1, buf, 0, newPos); read_buffer.position(newPos); return rc; } public int eof(byte[] data, int offset, int pos) { int i = offset; while (i < pos) { if (data[i] == 0) { return i; } i++; } return -1; } public void trace(String str) { System.out.println(String.format("%5d %5d - %s", server.port, uri.getPort(), str)); } } } EchoNetScala.scala000066400000000000000000000205341227446104000435000ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-example/src/main/scala/org/fusesource/hawtdispatch/example/discovery/** * Copyright (C) 2012 FuseSource, Inc. * http://fusesource.com * * Licensed 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.fusesource.hawtdispatch.example.discovery import _root_.java.io.{EOFException, ByteArrayOutputStream} import _root_.java.net.{ConnectException, InetSocketAddress, URI} import _root_.java.util.concurrent.TimeUnit import java.nio.ByteBuffer; import java.nio.channels.SelectionKey; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import org.fusesource.hawtdispatch._ /** * An example of a networks of servers which advertise connection information to each other. */ object EchoNetScala { def main(args:Array[String]):Unit = { run } def run() = { val a = new Server(4444).start(); val b = new Server(5555).start(); val c = new Server(6666).start(); Thread.sleep(200); a.connect(3333); a.connect(b); b.connect(c); System.in.read } class Server(val port: Int) { val me = URI.create("conn://localhost:" + port); val serverChannel = ServerSocketChannel.open(); serverChannel.socket().bind(new InetSocketAddress(port)); serverChannel.configureBlocking(false); var seen = List[URI]() val queue = createQueue(me.toString) val accept_source = createSource(serverChannel, SelectionKey.OP_ACCEPT, queue); accept_source.setEventHandler(^ { // we are a server // when you are a server, we must first listen for the // address of the client before sending data. // once they send us their address, we will send our // full list of known addresses, followed by our own // address to signal that we are done. // Afterward we will only pulls our heartbeat val client = serverChannel.accept(); try { val address = client.socket.getRemoteSocketAddress.asInstanceOf[InetSocketAddress] trace("accept " + address.getPort()); client.configureBlocking(false); // Server sessions start by reading the client's greeting val session = new Session(this, client, address) session.start_read_greeting } catch { case e: Exception => client.close } }); trace("Listening"); def start() = { accept_source.resume this } def stop() = { accept_source.suspend } def close() = { accept_source.cancel } accept_source.onCancel { serverChannel.close(); } def connect(s: Server):Unit = { connect(s.port); } def connect(port: Int):Unit = { connect(URI.create("conn://localhost:" + port)); } def connect(uri: URI): Unit = ^{ if ( me.equals(uri) || seen.contains(uri) ) return; val port = uri.getPort(); val host = uri.getHost(); trace("open " + uri); val socketChannel = SocketChannel.open(); socketChannel.configureBlocking(false); val address = new InetSocketAddress(host, port); socketChannel.connect(address); val connect_source = createSource(socketChannel, SelectionKey.OP_CONNECT, queue); connect_source.onEvent { connect_source.cancel try { socketChannel.finishConnect trace("connected " + uri); val session = new Session(this, socketChannel, address, uri) session.start_write_greeting } catch { case e:ConnectException => trace("connect to "+uri+" FAILED."); } } connect_source.resume seen = uri :: seen; } >>: queue def trace(str: String) { println(String.format("%5d - %s", new java.lang.Integer(port), str)); } } class Session(val server:Server, val channel: SocketChannel, val address: InetSocketAddress, val uri: URI) { def this(server:Server, channel: SocketChannel, address: InetSocketAddress) = { this (server, channel, address, URI.create("conn://" + address.getHostName() + ":" + address.getPort())) } val read_buffer = ByteBuffer.allocate(1024); val queue = createQueue(uri.toString) val read_source = createSource(channel, SelectionKey.OP_READ, queue); val write_source = createSource(channel, SelectionKey.OP_WRITE, queue); val seen = server.seen def start_read_greeting = { read_source.setEventHandler(read_greeting) read_source.resume } def read_greeting = ^{ val message = read_frame if (message!=null) { // stop looking for read events.. read_source.suspend val uri = URI.create(message); trace("welcome"); // Send them our seen uris.. var list:List[Any] = seen.filterNot(x=> x==server.me || x==uri ) list = list ::: List("end"); start_write_data(list, ^{ start_read_hearbeat }) } } def start_write_greeting = { trace("hello"); start_write_data(server.me::Nil, ^{ start_read_server_listings }) } def start_read_server_listings = { read_source.setEventHandler(read_server_listings) read_source.resume } var listed = List[URI]() def read_server_listings = ^ { val message = read_frame if (message!=null) { if( message != "end" ) { val uri: URI = URI.create(message) listed = uri :: listed; server.connect(uri) } else { // Send them our seen uris.. var list:List[Any] = seen.filterNot(x=> listed.contains(x) || x==server.me ) list = list ::: List("end"); start_write_data(list, ^{ // once done, start sending heartbeats. start_write_hearbeat }) } } } def start_read_client_listings = { read_source.setEventHandler(read_clientlistings) read_source.resume } def read_clientlistings = ^ { val message = read_frame if (message!=null) { if( message != "end" ) { server.connect(URI.create(message)) } else { start_read_hearbeat } } } def start_write_hearbeat:Unit = { queue.executeAfter(1, TimeUnit.SECONDS, ^{ trace("ping"); start_write_data("ping"::Nil, ^{ start_write_hearbeat }) }); } def start_read_hearbeat = { read_source.setEventHandler(read_hearbeat) read_source.resume } def read_hearbeat = ^ { val message = read_frame if (message != null) { trace("pong"); } } def start_write_data(list:List[Any], onDone:Runnable) = { val baos = new ByteArrayOutputStream() list.foreach { next => baos.write(next.toString().getBytes("UTF-8")) baos.write(0) } val buffer = ByteBuffer.wrap(baos.toByteArray) write_source.setEventHandler(write_data(buffer, onDone)) write_source.resume } def write_data(buffer:ByteBuffer, onDone:Runnable) = ^ { channel.write(buffer) if (buffer.remaining == 0) { write_source.suspend onDone.run } } def read_frame(): String = { if( channel.read(read_buffer) == -1 ) { throw new EOFException(); } val buf = read_buffer.array val endPos = eof(buf, 0, read_buffer.position) if (endPos < 0) { trace(" --- "); return null } var rc = new String(buf, 0, endPos) val newPos = read_buffer.position - endPos System.arraycopy(buf, endPos + 1, buf, 0, newPos) read_buffer.position(newPos) // trace(rc); return rc } def eof(data: Array[Byte], offset: Int, pos: Int): Int = { var i = offset while (i < pos) { if (data(i) == 0) { return i } i += 1 } return - 1 } def trace(str: String) = { println(String.format("%5d %5d - %s", new java.lang.Integer(server.port), new java.lang.Integer(uri.getPort()), str)); } } } hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-netty/000077500000000000000000000000001227446104000240705ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-netty/pom.xml000066400000000000000000000054461227446104000254160ustar00rootroot00000000000000 4.0.0 org.fusesource.hawtdispatch hawtdispatch-project 1.14-SNAPSHOT org.fusesource.hawtdispatch hawtdispatch-netty 1.14-SNAPSHOT bundle HawtDispatch Transport: Transport abstractions for HawtDispatch 4.7 3.1 1.2.14 4.2.0 org.fusesource.hawtdispatch hawtdispatch 1.14-SNAPSHOT io.netty netty-transport 4.0.0.Beta1-SNAPSHOT junit junit ${junit-version} test log4j log4j ${log4j-version} test org.apache.maven.plugins maven-compiler-plugin 1.6 1.6 org.apache.felix maven-bundle-plugin true true hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-netty/src/000077500000000000000000000000001227446104000246575ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-netty/src/main/000077500000000000000000000000001227446104000256035ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-netty/src/main/java/000077500000000000000000000000001227446104000265245ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-netty/src/main/java/org/000077500000000000000000000000001227446104000273135ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-netty/src/main/java/org/fusesource/000077500000000000000000000000001227446104000314765ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-netty/src/main/java/org/fusesource/hawtdispatch/000077500000000000000000000000001227446104000341615ustar00rootroot00000000000000000077500000000000000000000000001227446104000352455ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-netty/src/main/java/org/fusesource/hawtdispatch/nettyAbstractHawtEventLoopGroup.java000066400000000000000000000053731227446104000433600ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-netty/src/main/java/org/fusesource/hawtdispatch/netty/* * Copyright 2012 The Netty Project * Copyright 2013 Red Hat, Inc. * * The Netty Project 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.fusesource.hawtdispatch.netty; import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelPromise; import io.netty.channel.EventExecutor; import io.netty.channel.EventLoopGroup; import java.util.Set; import java.util.concurrent.TimeUnit; /** * Abstract base class for {@link EventLoopGroup} implementations that are backed by hawtdispatch. * * @author Norman Maurer */ abstract class AbstractHawtEventLoopGroup implements EventLoopGroup { @Override public ChannelFuture register(Channel channel) { return next().register(channel); } @Override public ChannelFuture register(Channel channel, ChannelPromise promise) { return next().register(channel, promise); } /** * Return a safe-copy of all of the children of this group. */ protected abstract Set children(); @Override public void shutdown() { if (isShutdown()) { return; } for (EventExecutor l: children()) { l.shutdown(); } } @Override public boolean isShutdown() { for (EventExecutor l: children()) { if (!l.isShutdown()) { return false; } } return true; } @Override public boolean isTerminated() { for (EventExecutor l: children()) { if (!l.isTerminated()) { return false; } } return true; } @Override public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException { long deadline = System.nanoTime() + unit.toNanos(timeout); loop: for (EventExecutor l: children()) { for (;;) { long timeLeft = deadline - System.nanoTime(); if (timeLeft <= 0) { break loop; } if (l.awaitTermination(timeLeft, TimeUnit.NANOSECONDS)) { break; } } } return isTerminated(); } } HawtAbstractChannel.java000077500000000000000000000161051227446104000417760ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-netty/src/main/java/org/fusesource/hawtdispatch/netty/* * Copyright 2012 The Netty Project * Copyright 2013 Red Hat, Inc. * * The Netty Project 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.fusesource.hawtdispatch.netty; import io.netty.channel.*; import org.fusesource.hawtdispatch.Dispatch; import org.fusesource.hawtdispatch.DispatchQueue; import org.fusesource.hawtdispatch.DispatchSource; import java.net.ConnectException; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.nio.channels.SelectableChannel; import java.nio.channels.SocketChannel; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; /** * Abstract base class for {@link Channel} implementations that use * HawtDispatch. * * @author Norman Maurer */ abstract class HawtAbstractChannel extends AbstractChannel { protected volatile SelectableChannel ch; /** * The future of the current connection attempt. If not null, subsequent * connection attempts will fail. */ private ChannelPromise connectPromise; private ScheduledFuture connectTimeoutFuture; private ConnectException connectTimeoutException; /** * Creates a new instance. * * @param id * the unique non-negative integer ID of this channel. * Specify {@code null} to auto-generate a unique negative integer * ID. * @param parent * the parent of this channel. {@code null} if there's no parent. * @param ch * the {@link SocketChannel} which will handle the IO or {@code null} if not created yet. */ protected HawtAbstractChannel(Channel parent, Integer id, SelectableChannel ch) { super(parent, id); this.ch = ch; } @Override public InetSocketAddress localAddress() { return (InetSocketAddress) super.localAddress(); } @Override public InetSocketAddress remoteAddress() { return (InetSocketAddress) super.remoteAddress(); } /** * Return the underlying {@link SocketChannel}. Be aware this should only be called after it was set as * otherwise it will throw an {@link IllegalStateException}. */ protected SelectableChannel javaChannel() { if (ch == null) { throw new IllegalStateException("Try to access Channel before eventLoop was registered"); } return ch; } @Override public boolean isOpen() { if (ch == null) { return true; } return ch.isOpen(); } @Override protected boolean isCompatible(EventLoop loop) { return loop instanceof HawtEventLoop; } @Override protected AbstractUnsafe newUnsafe() { return new HawtUnsafe(); } protected final DispatchSource createSource(int op) { return Dispatch.createSource(javaChannel(), op, getDispatchQueue()); } public DispatchQueue getDispatchQueue() { return ((HawtEventLoop) eventLoop()).queue(); } /** * Connect to the remote peer using the given localAddress if one is specified or {@code null} otherwise. */ protected abstract boolean doConnect(SocketAddress remoteAddress, SocketAddress localAddress) throws Exception; /** * Finish the connect */ protected abstract void doFinishConnect() throws Exception; @Override protected void doClose() throws Exception { if (connectTimeoutFuture != null) { connectTimeoutFuture.cancel(false); } } final class HawtUnsafe extends AbstractUnsafe { @Override public void connect( final SocketAddress remoteAddress, final SocketAddress localAddress, final ChannelPromise promise) { if (eventLoop().inEventLoop()) { if (!ensureOpen(promise)) { return; } try { if (connectPromise != null) { throw new IllegalStateException("connection attempt already made"); } boolean wasActive = isActive(); if (doConnect(remoteAddress, localAddress)) { promise.setSuccess(); if (!wasActive && isActive()) { pipeline().fireChannelActive(); } } else { connectPromise = promise; // Schedule connect timeout. int connectTimeoutMillis = config().getConnectTimeoutMillis(); if (connectTimeoutMillis > 0) { connectTimeoutFuture = eventLoop().schedule(new Runnable() { @Override public void run() { if (connectTimeoutException == null) { connectTimeoutException = new ConnectException("connection timed out"); } ChannelPromise connectPromise = HawtAbstractChannel.this.connectPromise; if (connectPromise != null && connectPromise.tryFailure(connectTimeoutException)) { close(voidFuture()); } } }, connectTimeoutMillis, TimeUnit.MILLISECONDS); } } } catch (Throwable t) { promise.setFailure(t); closeIfClosed(); } } else { eventLoop().execute(new Runnable() { @Override public void run() { connect(remoteAddress, localAddress, promise); } }); } } /** * Finish connect operation */ public void finishConnect() { assert eventLoop().inEventLoop(); assert connectPromise != null; try { boolean wasActive = isActive(); doFinishConnect(); connectPromise.setSuccess(); if (!wasActive && isActive()) { pipeline().fireChannelActive(); } } catch (Throwable t) { connectPromise.tryFailure(t); closeIfClosed(); } finally { connectTimeoutFuture.cancel(false); connectPromise = null; } } } } HawtEventLoop.java000066400000000000000000000155401227446104000406540ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-netty/src/main/java/org/fusesource/hawtdispatch/netty/* * Copyright 2012 The Netty Project * Copyright 2013 Red Hat, Inc. * * The Netty Project 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.fusesource.hawtdispatch.netty; import io.netty.channel.*; import org.fusesource.hawtdispatch.Dispatch; import org.fusesource.hawtdispatch.DispatchPriority; import org.fusesource.hawtdispatch.DispatchQueue; import org.fusesource.hawtdispatch.internal.ThreadDispatchQueue; import java.util.*; import java.util.concurrent.*; /** * {@link EventLoop} implementations which will * handle HawtDispatch based {@link Channel}s. * * @author Norman Maurer */ final class HawtEventLoop extends AbstractExecutorService implements EventLoop { private final EventLoopGroup parent; private volatile boolean shutdown; private final DispatchQueue queue; HawtEventLoop(EventLoopGroup parent, DispatchQueue queue) { if (parent == null) { throw new NullPointerException("parent"); } if (queue == null) { throw new NullPointerException("queue"); } this.parent = parent; this.queue = queue; } /** * Returns the backing {@link DispatchQueue} */ DispatchQueue queue() { return queue; } @Override public EventLoopGroup parent() { return parent; } @Override public boolean inEventLoop() { return queue.isExecuting(); } @Override public EventLoop next() { return this; } @Override public void shutdown() { shutdown = true; } @Override public List shutdownNow() { shutdown = true; return Collections.emptyList(); } @Override public boolean isShutdown() { return shutdown; } @Override public boolean isTerminated() { return shutdown; } @Override public boolean awaitTermination(long l, TimeUnit timeUnit) throws InterruptedException { return shutdown; } @SuppressWarnings("unchecked") @Override public ScheduledFuture schedule(Callable vCallable, long delay, TimeUnit timeUnit) { return new ScheduledFutureTask(vCallable, timeUnit.toNanos(delay)).schedule(); } @Override public ScheduledFuture schedule(final Runnable runnable, long delay, TimeUnit timeUnit) { return new ScheduledFutureTask(runnable, timeUnit.toNanos(delay)).schedule(); } @Override public ScheduledFuture scheduleAtFixedRate(Runnable runnable, long delay, long period, TimeUnit timeUnit) { return new ScheduledFutureTask(runnable, timeUnit.toNanos(delay), timeUnit.toNanos(period)).schedule(); } @Override public ScheduledFuture scheduleWithFixedDelay(Runnable runnable, long initialDelay, long delay, TimeUnit timeUnit) { throw new UnsupportedOperationException(); } private final class ScheduledFutureTask extends FutureTask implements ScheduledFuture { private long deadlineNanos; private final long periodNanos; ScheduledFutureTask(Runnable runnable,long nanoTime) { super(runnable, null); deadlineNanos = System.nanoTime()+nanoTime; periodNanos = 0; } ScheduledFutureTask(Runnable runnable, long nanoTime, long period) { super(runnable, null); if (period == 0) { throw new IllegalArgumentException("period: 0 (expected: != 0)"); } deadlineNanos = nanoTime; periodNanos = period; } ScheduledFutureTask(Callable callable, long nanoTime) { super(callable); deadlineNanos = nanoTime; periodNanos = 0; } public long delayNanos() { return Math.max(0, deadlineNanos - System.nanoTime()); } @Override public long getDelay(TimeUnit unit) { return unit.convert(delayNanos(), TimeUnit.NANOSECONDS); } @Override public int compareTo(Delayed o) { if (this == o) { return 0; } ScheduledFutureTask that = (ScheduledFutureTask) o; long d = deadlineNanos - that.deadlineNanos; if (d < 0) { return -1; } else if (d > 0) { return 1; } else { return 1; } } @Override public void run() { if (periodNanos == 0) { super.run(); } else { boolean reset = runAndReset(); if (reset && !isShutdown()) { long p = periodNanos; if (p > 0) { deadlineNanos += p; } else { deadlineNanos = System.nanoTime() - p; } schedule(); } } } ScheduledFuture schedule() { queue.executeAfter(delayNanos(), TimeUnit.NANOSECONDS, this); return this; } } @Override public void execute(Runnable runnable) { queue.execute(runnable); } @Override public boolean inEventLoop(Thread thread) { for (DispatchQueue queue: Dispatch.getThreadQueues(DispatchPriority.DEFAULT)) { if (thread == ((ThreadDispatchQueue) queue).getThread()) { return true; } } return false; } @Override public ChannelFuture register(Channel channel) { if (channel == null) { throw new NullPointerException("channel"); } return register(channel, channel.newPromise()); } @Override public ChannelFuture register(final Channel channel, final ChannelPromise promise) { if (isShutdown()) { channel.unsafe().closeForcibly(); promise.setFailure(new EventLoopException("cannot register a channel to a shut down loop")); return promise; } if (inEventLoop()) { channel.unsafe().register(this, promise); } else { execute(new Runnable() { @Override public void run() { channel.unsafe().register(HawtEventLoop.this, promise); } }); } return promise; } } HawtEventLoopGroup.java000066400000000000000000000063061227446104000416710ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-netty/src/main/java/org/fusesource/hawtdispatch/netty/* * Copyright 2013 Red Hat, Inc. * * The Netty Project 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.fusesource.hawtdispatch.netty; import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelPromise; import io.netty.channel.EventExecutor; import io.netty.channel.EventLoop; import io.netty.channel.group.ChannelGroup; import io.netty.channel.group.DefaultChannelGroup; import org.fusesource.hawtdispatch.DispatchQueue; import java.util.HashSet; import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; /** * {@link AbstractHawtEventLoopGroup} which will create a new serial {@link DispatchQueue} for every registered * {@link Channel}. * * @author Norman Maurer */ public class HawtEventLoopGroup extends AbstractHawtEventLoopGroup { private final ChannelGroup group = new DefaultChannelGroup(); private final DispatchQueue queue; private final AtomicInteger eventLoopId = new AtomicInteger(); private final ChannelFutureListener closeListener = new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture future) throws Exception { group.remove(future.channel()); } }; private final ChannelFutureListener registerListener = new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture future) throws Exception { if (future.isSuccess() && future.channel().isOpen()) { group.add(future.channel()); future.channel().closeFuture().addListener(closeListener); } } }; /** * Create a new instance * * @param queue the {@link DispatchQueue} from which the serial queues are created */ public HawtEventLoopGroup(DispatchQueue queue) { if (queue == null) { throw new NullPointerException("queue"); } this.queue = queue; } @Override public ChannelFuture register(Channel channel, ChannelPromise promise) { ChannelFuture future = super.register(channel, promise); future.addListener(registerListener); return future; } @Override protected Set children() { Set executors = new HashSet(group.size()); for (Channel channel: group) { executors.add(channel.eventLoop()); } return executors; } @Override public EventLoop next() { return new HawtEventLoop(this, queue.createQueue(HawtEventLoopGroup.class.getSimpleName() + '-' + eventLoopId.incrementAndGet())); } } HawtServerSocketChannel.java000077500000000000000000000143711227446104000426550ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-netty/src/main/java/org/fusesource/hawtdispatch/netty/* * Copyright 2012 The Netty Project * Copyright 2013 Red Hat, Inc. * * The Netty Project 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.fusesource.hawtdispatch.netty; import io.netty.buffer.BufType; import io.netty.channel.ChannelException; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelMetadata; import io.netty.channel.socket.DefaultServerSocketChannelConfig; import io.netty.channel.socket.ServerSocketChannel; import io.netty.channel.socket.ServerSocketChannelConfig; import io.netty.util.internal.InternalLogger; import io.netty.util.internal.InternalLoggerFactory; import org.fusesource.hawtdispatch.*; import static java.nio.channels.SelectionKey.*; import java.io.IOException; import java.net.SocketAddress; import java.nio.channels.SocketChannel; /** * {@link ServerSocketChannel} implementation which uses HawtDispatch. * * @author Norman Maurer */ public class HawtServerSocketChannel extends HawtAbstractChannel implements ServerSocketChannel { private static final ChannelMetadata METADATA = new ChannelMetadata(BufType.MESSAGE, false); private static final InternalLogger logger = InternalLoggerFactory.getInstance(HawtServerSocketChannel.class); private DispatchSource acceptSource; private static java.nio.channels.ServerSocketChannel newSocket() { try { return java.nio.channels.ServerSocketChannel.open(); } catch (IOException e) { throw new ChannelException( "Failed to open a server socket.", e); } } private final ServerSocketChannelConfig config; /** * Create a new instance */ public HawtServerSocketChannel() throws IOException { super(null, null, newSocket()); javaChannel().configureBlocking(false); config = new DefaultServerSocketChannelConfig(this, javaChannel().socket()); } @Override protected java.nio.channels.ServerSocketChannel javaChannel() { return (java.nio.channels.ServerSocketChannel) super.javaChannel(); } @Override public boolean isActive() { return ch != null && javaChannel().isOpen() && localAddress0() != null; } @Override public ChannelMetadata metadata() { return METADATA; } @Override protected SocketAddress localAddress0() { return javaChannel().socket().getLocalSocketAddress(); } @Override protected SocketAddress remoteAddress0() { return null; } @Override protected void doBind(SocketAddress localAddress) throws Exception { javaChannel().socket().bind(localAddress, config.getBacklog()); } @Override protected Runnable doRegister() throws Exception { final Runnable task = super.doRegister(); return new Runnable() { @Override public void run() { if (task != null) { task.run(); } // Create the source and register the handlers to it acceptSource = createSource(OP_ACCEPT); acceptSource.setEventHandler(new Task() { @Override public void run() { boolean added = false; for (;;) { try { SocketChannel channel = javaChannel().accept(); if (channel == null) { break; } pipeline().inboundMessageBuffer().add( new HawtSocketChannel(HawtServerSocketChannel.this, null, channel)); added = true; } catch (IOException e) { if (isOpen()) { logger.warn("Failed to create a new channel from an accepted socket.", e); } break; } } if (added) { pipeline().fireInboundBufferUpdated(); pipeline().fireChannelReadSuspended(); } // suspend accepts if needed if (!config().isAutoRead()) { acceptSource.suspend(); } } }); closeFuture().addListener(new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture future) throws Exception { acceptSource.cancel(); } }); } }; } @Override protected void doBeginRead() { if (acceptSource.isSuspended() && !acceptSource.isCanceled()) { acceptSource.resume(); } } @Override protected void doClose() throws Exception { super.doClose(); javaChannel().close(); } @Override protected boolean isFlushPending() { return false; } @Override protected boolean doConnect( SocketAddress remoteAddress, SocketAddress localAddress) throws Exception { throw new UnsupportedOperationException(); } @Override protected void doFinishConnect() throws Exception { throw new UnsupportedOperationException(); } @Override protected void doDisconnect() throws Exception { throw new UnsupportedOperationException(); } @Override public ServerSocketChannelConfig config() { return config; } } HawtSocketChannel.java000077500000000000000000000324301227446104000414620ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-netty/src/main/java/org/fusesource/hawtdispatch/netty/* * Copyright 2012 The Netty Project * Copyright 2013 Red Hat, Inc. * * The Netty Project 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.fusesource.hawtdispatch.netty; import io.netty.buffer.BufType; import io.netty.buffer.ByteBuf; import io.netty.channel.*; import io.netty.channel.socket.ChannelInputShutdownEvent; import io.netty.channel.socket.DefaultSocketChannelConfig; import io.netty.channel.socket.ServerSocketChannel; import io.netty.channel.socket.SocketChannel; import io.netty.util.internal.InternalLogger; import io.netty.util.internal.InternalLoggerFactory; import org.fusesource.hawtdispatch.DispatchSource; import org.fusesource.hawtdispatch.Task; import java.io.IOException; import java.net.InetSocketAddress; import java.net.SocketAddress; import static java.nio.channels.SelectionKey.*; /** * {@link SocketChannel} implementation which uses HawtDispatch. * * @author Norman Maurer */ public class HawtSocketChannel extends HawtAbstractChannel implements SocketChannel { private static final InternalLogger logger = InternalLoggerFactory.getInstance(HawtSocketChannel.class); private static final ChannelMetadata METADATA = new ChannelMetadata(BufType.BYTE, false); private final DefaultSocketChannelConfig config; private volatile boolean inputShutdown; private volatile boolean outputShutdown; private DispatchSource readSource; private DispatchSource writeSource; private static java.nio.channels.SocketChannel newSocket() { try { return java.nio.channels.SocketChannel.open(); } catch (IOException e) { throw new ChannelException("Failed to open a socket.", e); } } /** * Create a new instance */ public HawtSocketChannel() { this(newSocket()); } /** * Create a new instance using the given {@link java.nio.channels.SocketChannel}. */ public HawtSocketChannel(java.nio.channels.SocketChannel socket) { this(null, null, socket); } /** * Create a new instance * * @param parent the {@link Channel} which created this instance or {@code null} if it was created by the user * @param id the id to use for this instance or {@code null} if a new one should be generated * @param socket the {@link java.nio.channels.SocketChannel} which will be used */ public HawtSocketChannel(HawtServerSocketChannel parent, Integer id, java.nio.channels.SocketChannel socket) { super(parent, id, socket); try { socket.configureBlocking(false); } catch (IOException e) { try { socket.close(); } catch (IOException e2) { if (logger.isWarnEnabled()) { logger.warn( "Failed to close a partially initialized socket.", e2); } } throw new ChannelException("Failed to enter non-blocking mode.", e); } config = new DefaultSocketChannelConfig(this, socket.socket()); } @Override public ServerSocketChannel parent() { return (ServerSocketChannel) super.parent(); } @Override public DefaultSocketChannelConfig config() { return config; } @Override public boolean isActive() { return ch != null && javaChannel().isOpen() && remoteAddress0() != null; } @Override protected java.nio.channels.SocketChannel javaChannel() { return (java.nio.channels.SocketChannel) super.javaChannel(); } @Override public ChannelMetadata metadata() { return METADATA; } @Override public boolean isInputShutdown() { return inputShutdown; } /** * Shutdown the input of this {@link Channel}. */ void setInputShutdown() { inputShutdown = true; } @Override public boolean isOutputShutdown() { return outputShutdown; } @Override public ChannelFuture shutdownOutput() { return shutdownOutput(newPromise()); } @Override public ChannelFuture shutdownOutput(final ChannelPromise promise) { EventLoop loop = eventLoop(); if (loop.inEventLoop()) { boolean success = false; try { javaChannel().socket().shutdownOutput(); success = true; promise.setSuccess(); } catch (Throwable t) { promise.setFailure(t); } finally { if (success) { outputShutdown = true; } } } else { loop.execute(new Runnable() { @Override public void run() { shutdownOutput(promise); } }); } return promise; } @Override protected boolean doConnect(SocketAddress remoteAddress, SocketAddress localAddress) throws Exception { if (localAddress != null) { javaChannel().socket().bind(localAddress); } boolean success = false; try { boolean connected = javaChannel().connect(remoteAddress); if (!connected) { // Hook into the CONNECT event.. final DispatchSource connectSource = createSource(OP_CONNECT); // This gets triggered when the socket is connected.. connectSource.setEventHandler(new Task() { @Override public void run() { ((HawtUnsafe) unsafe()).finishConnect(); } }); // enable the delivery of the connect events. connectSource.resume(); } success = true; return connected; } finally { if (!success) { doClose(); } } } @Override protected InetSocketAddress localAddress0() { if (ch == null) { return null; } return (InetSocketAddress) javaChannel().socket().getLocalSocketAddress(); } @Override protected InetSocketAddress remoteAddress0() { if (ch == null) { return null; } return (InetSocketAddress) javaChannel().socket().getRemoteSocketAddress(); } @Override protected void doBind(SocketAddress localAddress) throws Exception { javaChannel().socket().bind(localAddress); } @Override protected void doDisconnect() throws Exception { doClose(); } @Override protected void doClose() throws Exception { super.doClose(); javaChannel().close(); inputShutdown = true; outputShutdown = true; } @Override protected boolean isFlushPending() { return false; } @Override protected void doFlushByteBuffer(ByteBuf buf) throws Exception { if (!buf.isReadable()) { // Reset reader/writerIndex to 0 if the buffer is empty. buf.clear(); return; } for (int i = config().getWriteSpinCount() - 1; i >= 0; i--) { int localFlushedAmount = doWriteBytes(buf, i == 0); if (localFlushedAmount > 0) { break; } if (!buf.isReadable()) { // Reset reader/writerIndex to 0 if the buffer is empty. buf.clear(); break; } } } protected int doWriteBytes(ByteBuf buf, boolean lastSpin) throws Exception { final int expectedWrittenBytes = buf.readableBytes(); final int writtenBytes = buf.readBytes(javaChannel(), expectedWrittenBytes); if (writtenBytes >= expectedWrittenBytes) { // Wrote the outbound buffer completely - clear OP_WRITE. writeSource.suspend(); } else { // Wrote something or nothing. // a) If wrote something, the caller will not retry. // - Set OP_WRITE so that the event loop calls flushForcibly() later. // b) If wrote nothing: // 1) If 'lastSpin' is false, the caller will call this method again real soon. // - Do not update OP_WRITE. // 2) If 'lastSpin' is true, the caller will not retry. // - Set OP_WRITE so that the event loop calls flushForcibly() later. if (writtenBytes > 0 || lastSpin) { writeSource.resume(); } } return writtenBytes; } @Override protected Runnable doRegister() throws Exception { final Runnable task = super.doRegister(); return new Runnable() { @Override public void run() { if (task != null) { task.run(); } // create the sources and set the event handlers readSource = createSource(OP_READ); readSource.setEventHandler(new Task() { @Override public void run() { onReadReady(); } }); writeSource = createSource(OP_WRITE); writeSource.setEventHandler(new Task() { @Override public void run() { unsafe().flushNow(); } }); closeFuture().addListener(new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture future) throws Exception { readSource.cancel(); writeSource.cancel(); } }); } }; } @Override protected void doBeginRead() throws Exception { assert readSource != null; if (readSource.isSuspended() && !readSource.isCanceled()) { readSource.resume(); } } private void onReadReady() { final ChannelPipeline pipeline = pipeline(); final ByteBuf byteBuf = pipeline.inboundByteBuffer(); boolean closed = false; boolean read = false; boolean firedInboundBufferSuspended = false; try { expandReadBuffer(byteBuf); loop: for (;;) { int localReadAmount = byteBuf.writeBytes(javaChannel(), byteBuf.writableBytes()); if (localReadAmount > 0) { read = true; } else if (localReadAmount < 0) { closed = true; break; } switch (expandReadBuffer(byteBuf)) { case 0: // Read all - stop reading. break loop; case 1: // Keep reading until everything is read. break; case 2: // Let the inbound handler drain the buffer and continue reading. if (read) { read = false; pipeline.fireInboundBufferUpdated(); if (!byteBuf.isWritable()) { throw new IllegalStateException( "an inbound handler whose buffer is full must consume at " + "least one byte."); } } } } } catch (Throwable t) { if (read) { read = false; pipeline.fireInboundBufferUpdated(); } if (t instanceof IOException) { closed = true; } else if (!closed) { firedInboundBufferSuspended = true; pipeline.fireChannelReadSuspended(); } pipeline().fireExceptionCaught(t); } finally { if (read) { pipeline.fireInboundBufferUpdated(); } if (closed) { setInputShutdown(); if (isOpen()) { if (Boolean.TRUE.equals(config().getOption(ChannelOption.ALLOW_HALF_CLOSURE))) { pipeline.fireUserEventTriggered(ChannelInputShutdownEvent.INSTANCE); } else { close(newPromise()); } } } else if (!firedInboundBufferSuspended) { pipeline.fireChannelReadSuspended(); } if (!config().isAutoRead()) { readSource.suspend(); } } } @Override protected void doFinishConnect() throws Exception { if (!javaChannel().finishConnect()) { throw new Error(); } } } SharedHawtEventLoopGroup.java000066400000000000000000000050201227446104000430100ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-netty/src/main/java/org/fusesource/hawtdispatch/netty/* * Copyright 2012 The Netty Project * Copyright 2013 Red Hat, Inc. * * The Netty Project 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.fusesource.hawtdispatch.netty; import io.netty.channel.*; import org.fusesource.hawtdispatch.DispatchQueue; import java.util.Collections; import java.util.LinkedHashMap; import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; /** * {@link AbstractHawtEventLoopGroup} implementation which use pre-created shared serial {@link DispatchQueue}s * between the registered {@link Channel}s. * * @author Norman Maurer */ public class SharedHawtEventLoopGroup extends AbstractHawtEventLoopGroup { private static final AtomicInteger poolId = new AtomicInteger(); private final EventLoop[] children; private final AtomicInteger childIndex = new AtomicInteger(); /** * Create a new instance * * @param queue the {@link DispatchQueue} from which the serial {@link DispatchQueue}s will be created. * @param queueNumber the number of serial {@link DispatchQueue}s created from the given {@link DispatchQueue} */ public SharedHawtEventLoopGroup(DispatchQueue queue, int queueNumber) { if (queueNumber < 1) { throw new IllegalArgumentException("queueNumber must be >= 1"); } if (queue == null) { throw new NullPointerException("queue"); } children = new EventLoop[queueNumber]; for (int i = 0; i < queueNumber; i++) { children[i] = new HawtEventLoop(this, queue.createQueue(poolId.get() + "-" + i)); } } @Override public EventLoop next() { return children[Math.abs(childIndex.getAndIncrement() % children.length)]; } @Override protected Set children() { Set children = Collections.newSetFromMap(new LinkedHashMap()); Collections.addAll(children, this.children); return children; } } 000077500000000000000000000000001227446104000367005ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-netty/src/main/java/org/fusesource/hawtdispatch/netty/exampleEchoClient.java000066400000000000000000000064611227446104000415670ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-netty/src/main/java/org/fusesource/hawtdispatch/netty/example/* * Copyright 2012 The Netty Project * * The Netty Project 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.fusesource.hawtdispatch.netty.example; import io.netty.bootstrap.Bootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; import io.netty.channel.socket.SocketChannel; import org.fusesource.hawtdispatch.Dispatch; import org.fusesource.hawtdispatch.netty.HawtEventLoopGroup; import org.fusesource.hawtdispatch.netty.HawtSocketChannel; import java.net.InetSocketAddress; /** * Sends one message when a connection is open and echoes back any received * data to the server. Simply put, the echo client initiates the ping-pong * traffic between the echo client and server by sending the first message to * the server. */ public class EchoClient { private final String host; private final int port; private final int firstMessageSize; public EchoClient(String host, int port, int firstMessageSize) { this.host = host; this.port = port; this.firstMessageSize = firstMessageSize; } public void run() throws Exception { // Configure the client. Bootstrap b = new Bootstrap(); try { b.group(new HawtEventLoopGroup(Dispatch.getGlobalQueue())) .channel(HawtSocketChannel.class) .option(ChannelOption.TCP_NODELAY, true) .remoteAddress(new InetSocketAddress(host, port)) .handler(new ChannelInitializer() { @Override public void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast( new EchoClientHandler(firstMessageSize)); } }); // Start the client. ChannelFuture f = b.connect().sync(); // Wait until the connection is closed. f.channel().closeFuture().sync(); } finally { // Shut down the event loop to terminate all threads. b.shutdown(); } } public static void main(String[] args) throws Exception { // Print usage if no argument is specified. if (args.length < 2 || args.length > 3) { System.err.println( "Usage: " + EchoClient.class.getSimpleName() + " []"); return; } // Parse options. final String host = args[0]; final int port = Integer.parseInt(args[1]); final int firstMessageSize; if (args.length == 3) { firstMessageSize = Integer.parseInt(args[2]); } else { firstMessageSize = 256; } new EchoClient(host, port, firstMessageSize).run(); } } EchoClientHandler.java000066400000000000000000000045171227446104000430650ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-netty/src/main/java/org/fusesource/hawtdispatch/netty/example/* * Copyright 2012 The Netty Project * * The Netty Project 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.fusesource.hawtdispatch.netty.example; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundByteHandlerAdapter; import java.util.logging.Level; import java.util.logging.Logger; /** * Handler implementation for the echo client. It initiates the ping-pong * traffic between the echo client and server by sending the first message to * the server. */ public class EchoClientHandler extends ChannelInboundByteHandlerAdapter { private static final Logger logger = Logger.getLogger( EchoClientHandler.class.getName()); private final ByteBuf firstMessage; /** * Creates a client-side handler. */ public EchoClientHandler(int firstMessageSize) { if (firstMessageSize <= 0) { throw new IllegalArgumentException("firstMessageSize: " + firstMessageSize); } firstMessage = Unpooled.buffer(firstMessageSize); for (int i = 0; i < firstMessage.capacity(); i ++) { firstMessage.writeByte((byte) i); } } @Override public void channelActive(ChannelHandlerContext ctx) { ctx.write(firstMessage); } @Override public void inboundBufferUpdated(ChannelHandlerContext ctx, ByteBuf in) { ByteBuf out = ctx.nextOutboundByteBuffer(); System.out.println("read:"+in.readableBytes()); out.writeBytes(in); ctx.flush(); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { // Close the connection when an exception is raised. logger.log(Level.WARNING, "Unexpected exception from downstream.", cause); ctx.close(); } } EchoServer.java000066400000000000000000000051221227446104000416100ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-netty/src/main/java/org/fusesource/hawtdispatch/netty/example/* * Copyright 2012 The Netty Project * * The Netty Project 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.fusesource.hawtdispatch.netty.example; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; import io.netty.channel.socket.SocketChannel; import org.fusesource.hawtdispatch.Dispatch; import org.fusesource.hawtdispatch.netty.HawtEventLoopGroup; import org.fusesource.hawtdispatch.netty.HawtServerSocketChannel; import java.net.InetSocketAddress; /** * Echoes back any received data from a client. */ public class EchoServer { private final int port; public EchoServer(int port) { this.port = port; } public void run() throws Exception { // Configure the server. ServerBootstrap b = new ServerBootstrap(); try { b.group(new HawtEventLoopGroup(Dispatch.getGlobalQueue()), new HawtEventLoopGroup(Dispatch.getGlobalQueue())) .channel(HawtServerSocketChannel.class) .option(ChannelOption.SO_BACKLOG, 100) .localAddress(new InetSocketAddress(port)) .childOption(ChannelOption.TCP_NODELAY, true) .childHandler(new ChannelInitializer() { @Override public void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast( new EchoServerHandler()); } }); // Start the server. ChannelFuture f = b.bind().sync(); // Wait until the server socket is closed. f.channel().closeFuture().sync(); } finally { // Shut down all event loops to terminate all threads. b.shutdown(); } } public static void main(String[] args) throws Exception { int port; if (args.length > 0) { port = Integer.parseInt(args[0]); } else { port = 8080; } new EchoServer(port).run(); } } EchoServerHandler.java000066400000000000000000000031651227446104000431130ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-netty/src/main/java/org/fusesource/hawtdispatch/netty/example/* * Copyright 2012 The Netty Project * * The Netty Project 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.fusesource.hawtdispatch.netty.example; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandler.Sharable; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundByteHandlerAdapter; import java.util.logging.Level; import java.util.logging.Logger; /** * Handler implementation for the echo server. */ @Sharable public class EchoServerHandler extends ChannelInboundByteHandlerAdapter { private static final Logger logger = Logger.getLogger( EchoServerHandler.class.getName()); @Override public void inboundBufferUpdated(ChannelHandlerContext ctx, ByteBuf in) { ByteBuf out = ctx.nextOutboundByteBuffer(); out.writeBytes(in); ctx.flush(); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { // Close the connection when an exception is raised. logger.log(Level.WARNING, "Unexpected exception from downstream.", cause); ctx.close(); } } package-info.java000066400000000000000000000015571227446104000404440ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-netty/src/main/java/org/fusesource/hawtdispatch/netty/* * Copyright 2012 The Netty Project * Copyright 2013 Red Hat, Inc. * * The Netty Project 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. */ /** * HawtDispatch-based netty socket channel API implementation - recommended for * a large number of connections (>= 1000) who's event handlers never block. */ package org.fusesource.hawtdispatch.netty; hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-netty/src/test/000077500000000000000000000000001227446104000256365ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-netty/src/test/java/000077500000000000000000000000001227446104000265575ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-netty/src/test/java/org/000077500000000000000000000000001227446104000273465ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-netty/src/test/java/org/fusesource/000077500000000000000000000000001227446104000315315ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-netty/src/test/java/org/fusesource/hawtdispatch/000077500000000000000000000000001227446104000342145ustar00rootroot00000000000000000077500000000000000000000000001227446104000353005ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-netty/src/test/java/org/fusesource/hawtdispatch/nettyHawtEchoTest.java000066400000000000000000000121441227446104000405070ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-netty/src/test/java/org/fusesource/hawtdispatch/netty/* * Copyright 2013 Red Hat, Inc. * * The Netty Project 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.fusesource.hawtdispatch.netty; import io.netty.bootstrap.Bootstrap; import io.netty.bootstrap.ServerBootstrap; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundByteHandlerAdapter; import org.fusesource.hawtdispatch.Dispatch; import org.junit.Test; import java.io.IOException; import java.net.InetSocketAddress; import java.util.Random; import java.util.concurrent.atomic.AtomicReference; import static org.junit.Assert.assertEquals; /** * @author Norman Maurer */ public class HawtEchoTest { private static final Random random = new Random(); static final byte[] data = new byte[4096];//could not test ultra jumbo frames static { random.nextBytes(data); } @Test public void testSimpleEcho() throws Throwable { // Configure the server. ServerBootstrap sb = new ServerBootstrap(); sb.group(new HawtEventLoopGroup(Dispatch.getGlobalQueue()), new HawtEventLoopGroup(Dispatch.getGlobalQueue())) .channel(HawtServerSocketChannel.class); // Configure the client. Bootstrap cb = new Bootstrap(); cb.group(new HawtEventLoopGroup(Dispatch.getGlobalQueue())) .channel(HawtSocketChannel.class); final EchoHandler sh = new EchoHandler(); final EchoHandler ch = new EchoHandler(); sb.childHandler(sh); cb.handler(ch); Channel sc = sb.bind(new InetSocketAddress(0)).sync().channel(); Channel cc = cb.connect(sc.localAddress()).sync().channel(); for (int i = 0; i < data.length; ) { int length = Math.min(random.nextInt(1024 * 64), data.length - i); cc.write(Unpooled.wrappedBuffer(data, i, length)); i += length; } while (ch.counter < data.length) { if (sh.exception.get() != null) { break; } if (ch.exception.get() != null) { break; } try { Thread.sleep(50); } catch (InterruptedException e) { // Ignore. } } while (sh.counter < data.length) { if (sh.exception.get() != null) { break; } if (ch.exception.get() != null) { break; } try { Thread.sleep(50); } catch (InterruptedException e) { // Ignore. } } sh.channel.close().sync(); ch.channel.close().sync(); sc.close().sync(); if (sh.exception.get() != null && !(sh.exception.get() instanceof IOException)) { throw sh.exception.get(); } if (ch.exception.get() != null && !(ch.exception.get() instanceof IOException)) { throw ch.exception.get(); } if (sh.exception.get() != null) { throw sh.exception.get(); } if (ch.exception.get() != null) { throw ch.exception.get(); } } private static class EchoHandler extends ChannelInboundByteHandlerAdapter { volatile Channel channel; final AtomicReference exception = new AtomicReference(); volatile int counter; @Override public ByteBuf newInboundBuffer(ChannelHandlerContext ctx) throws Exception { return Unpooled.buffer(); } @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { channel = ctx.channel(); } @Override public void inboundBufferUpdated( ChannelHandlerContext ctx, ByteBuf in) throws Exception { byte[] actual = new byte[in.readableBytes()]; in.readBytes(actual); int lastIdx = counter; for (int i = 0; i < actual.length; i++) { assertEquals(data[i + lastIdx], actual[i]); } if (channel.parent() != null) { channel.write(Unpooled.wrappedBuffer(actual)); } counter += actual.length; } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { if (exception.compareAndSet(null, cause)) { ctx.close(); } } } } hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-scala/000077500000000000000000000000001227446104000240105ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-scala/pom.xml000077500000000000000000000152561227446104000253410ustar00rootroot00000000000000 4.0.0 org.fusesource.hawtdispatch hawtdispatch-project 1.20 org.fusesource.hawtdispatch hawtdispatch-scala 1.20 bundle HawtDispatch: The libdispatch style API for Scala org.fusesource.hawtdispatch hawtdispatch 1.20 org.scala-lang scala-library ${scala-version} provided org.scalatest scalatest_${scala-version} ${scalatest-version} test junit junit ${junit-version} test log4j log4j ${log4j-version} test install src/main/scala src/test/scala org.apache.felix maven-bundle-plugin true true ${project.groupId}.hawtdispatch {local-packages};version=${project.version};-noimport:=true;-split-package:=first net.alchim31.maven scala-maven-plugin 3.1.0 compile testCompile scala.tools.nsc.ScalaDoc -Xmx1024m -deprecation -P:continuations:enable ${scala-version} org.scala-lang.plugins continuations ${scala-version} maven-surefire-plugin 2.4.3 false false true false net.alchim31.maven scala-maven-plugin 3.1.0 ${scala-version} -Xmx850M idea net.alchim31.maven scala-maven-plugin 3.1.0 -deprecation -P:continuations:enable org.scala-lang.plugins continuations ${scala-version} release net.alchim31.maven scala-maven-plugin 3.1.0 doc process-classes doc ${project.build.directory} apidocs hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-scala/src/000077500000000000000000000000001227446104000245775ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-scala/src/main/000077500000000000000000000000001227446104000255235ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-scala/src/main/scala/000077500000000000000000000000001227446104000266065ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-scala/src/main/scala/org/000077500000000000000000000000001227446104000273755ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-scala/src/main/scala/org/fusesource/000077500000000000000000000000001227446104000315605ustar00rootroot00000000000000hawtdispatch.scala000066400000000000000000000247451227446104000352050ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-scala/src/main/scala/org/fusesource/** * Copyright (C) 2012 FuseSource, Inc. * http://fusesource.com * * Licensed 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.fusesource import org.fusesource.hawtdispatch._ import java.nio.channels.SelectableChannel import scala.util.continuations._ import java.util.concurrent.{ExecutorService, CountDownLatch, Executor, TimeUnit} import java.util.concurrent.atomic.AtomicBoolean import java.io.Closeable /** *

*

* * @author Hiram Chirino */ package object hawtdispatch { implicit def ExecutorWrapper(x: Executor) = new RichExecutor(x) implicit def DispatchQueueWrapper(x: DispatchQueue) = new RichDispatchQueue(x) implicit def RichDispatchSourceWrapper(x: DispatchSource) = new RichDispatchSource(x) trait RichDispatchObject { def actual:DispatchObject def target_=(queue: DispatchQueue) { actual.setTargetQueue( queue ) } def target:DispatchQueue = actual.getTargetQueue } trait RichExecutorTrait { protected def execute(task:Task):Unit protected def execute(runnable:Runnable):Unit /** *

* Submits a partial function for asynchronous execution on a dispatch queue. *

* Calls to {@link #execute(Task)} always return immediately after the runnable has * been submitted, and never wait for the runnable to be executed. *

* The target queue determines whether the runnable will be invoked serially or * concurrently with respect to other runnables submitted to that same queue. * Serial queues are processed concurrently with with respect to each other. *

* The system will retain this queue until the runnable has finished. *

* * @param task * The function to submit to the dispatch queue. */ def apply(task: =>Unit) = execute(r(task _)) /** * Creates a Task object which executes the supplied partial * function on this executor when run. */ def runnable(task: =>Unit) = new Task() { val target = r(task _) def run: Unit = { execute(target) } } /** * Same as {@link #apply(=>Unit)} */ def ^(task: =>Unit) = execute(r(task _)) /** *

* Submits a runnable for asynchronous execution on a dispatch queue. *

* * @param task * The runnable to submit to the dispatch queue. */ def <<(task: Runnable) = execute(task) def <<(task: Task) = execute(task) /** * A right-associative version of the {@link #<<(Runnable)} method */ def >>:(task: Runnable) = execute(task) def >>:(task: Task) = execute(task) /** * Executes the supplied function on the dispatch queue * while blocking the calling thread as it waits for the response. */ def sync[T](func: =>T): T = future(func)() /** * Executes the supplied function on the dispatch queue * and returns a Future that can be used to wait on the future * result of the function. */ def future[T](func: =>T):Future[T] = { val rc = Future[T]() apply { rc(func) } rc } def flatFuture[T](func: =>Future[T]):Future[T] = { val rc = Future[T]() apply { func.onComplete(rc(_)) } rc } /** * Executes the supplied function on this executor. If not called from a * runnable being exectued in a Dispatch Queue, then is call blocks * until continuation is executed. Otherwise, the continuation is * resumed on the original calling dispatch queue once supplied function * completes. */ def ![T](func: =>T): T @suspendable = shift { k: (T=>Unit) => val original = getCurrentQueue if( original==null ) { k(sync(func)) } else { apply { val result = func original.apply { k(result) } } } } /** * Same as {@link #future(=>T)} except that the partial function is wrapped in a {@link reset} block. */ def !![T](func: =>T @suspendable):Future[T] = reset_future { func } } class RichDispatchSource(val actual:DispatchSource) extends Proxy with RichDispatchObject { def self = actual def onEvent(task: =>Unit) { actual.setEventHandler( r(task _) ) } def onCancel(task: =>Unit) { actual.setCancelHandler( r(task _) ) } } /** * Enriches the Executor interfaces with additional Scala friendly methods. */ final class RichExecutor(val executor: Executor) extends Proxy with RichExecutorTrait { def self: Any = executor protected def execute(task:Task) = executor.execute(task) protected def execute(task:Runnable) = executor.execute(task) } /** * Enriches the DispatchQueue interfaces with additional Scala friendly methods. */ final class RichDispatchQueue(val actual: DispatchQueue) extends Proxy with RichExecutorTrait with RichDispatchObject { def self = actual protected def execute(task:Runnable) = actual.execute(task) protected def execute(task:Task) = actual.execute(task) def label_=(value: String) { actual.setLabel( value ) } def label:String = actual.getLabel /** *

* Submits a partial function for asynchronous execution on a dispatch queue after * the specified time delay. *

* * @param time * The amount of time to delay * @param unit * The units of time the delay is specified in * @param task * The runnable to submit to the dispatch queue. */ def after(time:Long, unit:TimeUnit)(task: =>Unit) = actual.executeAfter(time, unit, r(task _)) /** *

* Submits a partial function for repetitive asynchronous execution on a dispatch queue * each time specified time delay elapses. Returns a Closable which when closed will * stop future executions of the task. *

* * @param time * The amount of time to delay * @param unit * The units of time the delay is specified in * @param task * The runnable to submit to the dispatch queue. */ def repeatAfter(time:Long, unit:TimeUnit)(task: =>Unit):Closeable = new Closeable { val closed = new AtomicBoolean def close: Unit = closed.set(true) val action:Task = new Task() { def run: Unit = { if (!closed.get) { try { task } catch { case e:Throwable => e.printStackTrace } if (!closed.get) { actual.executeAfter(time, unit, action) } } } } actual.executeAfter(time, unit, action) } /** *

* Submits a runnable for asynchronous execution on a dispatch queue if the * queue is not currently executing, otherwise if the queue is currently executing, * then the runnable is directly executed. *

* * @param task * The runnable to submit to execute */ def <<|(task: Task) = { if( actual.isExecuting ) { try { task.run } catch { case e:Exception => e.printStackTrace } } else { actual.execute(task); } this } def <<|(task: Runnable):RichDispatchQueue = this <<|(new TaskWrapper(task)) /** *

* Submits a runnable for asynchronous execution on a dispatch queue if the * queue is not currently executing, otherwise if the queue is currently executing, * then the runnable is directly executed. *

* * @param task * The runnable to submit to execute */ def | (task: =>Unit ) = { this.<<|( r(task _)) } /** * A right-associative version of the {@link #<<|(Runnable)} method */ def |>>:(task: Runnable) =this <<| task def |>>:(task: Task) = this <<| task } ///////////////////////////////////////////////////////////////////// // // re-export all the Dispatch static methods. // ///////////////////////////////////////////////////////////////////// /** * Same as {@link Dispatch.getThreadQueues} */ def getThreadQueues(priority:DispatchPriority=DispatchPriority.DEFAULT) = Dispatch.getThreadQueues(priority) /** * Same as {@link Dispatch.getCurrentQueue} */ def getCurrentThreadQueue = Dispatch.getCurrentThreadQueue /** * Same as {@link Dispatch.createSource(EventAggregator, DispatchQueue)} */ def createSource[Event, MergedEvent](aggregator: EventAggregator[Event, MergedEvent], queue: DispatchQueue) = { Dispatch.createSource(aggregator, queue) } /** * Same as {@link Dispatch.createSource(SelectableChannel, Int, DispatchQueue)} */ def createSource(channel: SelectableChannel, interestOps: Int, queue: DispatchQueue) = { Dispatch.createSource(channel, interestOps, queue) } /** * Same as {@link Dispatch.getCurrentQueue} */ def getCurrentQueue = Dispatch.getCurrentQueue /** * Same as {@link Dispatch.createQueue(String)} */ def createQueue(label: String=null) = Dispatch.createQueue(label) /** * Same as {@link Dispatch.getGlobalQueue(DispatchPriority)} */ def getGlobalQueue(priority: DispatchPriority=DispatchPriority.DEFAULT) = Dispatch.getGlobalQueue(priority) /** * Same as {@link Dispatch.getGlobalQueue } */ def globalQueue = Dispatch.getGlobalQueue /** * Same as {@link Dispatch.NOOP } */ def NOOP = Dispatch.NOOP ///////////////////////////////////////////////////////////////////// // // Make it easier to create Task objects. // ///////////////////////////////////////////////////////////////////// /** * Creates a runnable object from a partial function */ def ^(proc: => Unit): Task = r(proc _) /** * Creates a runnable object from a partial function */ private def r(proc: ()=>Unit): Task = new Task() { def run() { proc() } } /** * resets a CPS block, and returns it's result in a future. */ def reset_future[T](func: =>T @suspendable):Future[T] = { val rc = Future[T]() reset { val r = func rc(r) } rc } } 000077500000000000000000000000001227446104000341645ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-scala/src/main/scala/org/fusesource/hawtdispatchFuture.scala000066400000000000000000000116531227446104000364510ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-scala/src/main/scala/org/fusesource/hawtdispatch/** * Copyright (C) 2012 FuseSource, Inc. * http://fusesource.com * * Licensed 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.fusesource.hawtdispatch import java.util.concurrent.{TimeUnit} import scala.collection.mutable.ListBuffer trait Future[R] extends ( ()=>R ) { def get():R def await():R def await(time:Long, unit:TimeUnit):Option[R] def apply() = await() def onComplete(func: (R)=>Unit):Unit def completed:Boolean def map[X](func:R=>X):Future[X] } trait SettableFuture[T,R] extends (T => Unit) with Future[R] { protected var _callback:Option[(R)=>Unit] = None protected var _result:Option[R] = None protected object mutex protected def merge(value:T):Option[R] def apply(value:T):Unit = set(value) def set(value:T) = { val callback = mutex synchronized { if( !_result.isDefined ) { _result = merge(value) if( _result.isDefined ) { mutex.notifyAll _callback } else { None } } else { None } } callback.foreach(_(_result.get)) } def get():R = { _result.get } def await():R = { assert(getCurrentQueue==null, "You must not do any blocking waits when executing on HawtDispatch thread pool.") mutex.synchronized { while(_result.isEmpty) { mutex.wait } _result.get } } def await(time:Long, unit:TimeUnit):Option[R] = mutex synchronized { assert(getCurrentQueue==null, "You must not do any blocking waits when executing on HawtDispatch thread pool.") var now = System.currentTimeMillis var deadline = now + unit.toMillis(time) while(_result.isEmpty && now < deadline ) { mutex.wait(deadline-now) if(_result != None) { return _result } now = System.currentTimeMillis } return _result } def onComplete(func: (R)=>Unit) = { val callback = mutex synchronized { // Should only be used once per future. assert ( ! _callback.isDefined ) if( _result.isDefined ) { Some(func) } else { _callback = Some(func) None } } callback.foreach(_(_result.get)) } def completed = mutex synchronized { _result.isDefined } def map[X](func:R=>X) = { val rc = Future.apply(func) onComplete(rc(_)) rc } } object Future { /** * creates a new future. */ def apply[T]():SettableFuture[T,T] = new SettableFuture[T,T] { protected def merge(value: T): Option[T] = Some(value) } /** * creates a new future which does an on the fly * transformation of the value. */ def apply[T,R](func: T=>R):SettableFuture[T,R] = new SettableFuture[T,R] { protected def merge(value: T): Option[R] = Some(func(value)) } /** * creates a future which only waits for the first * of the supplied futures to get set. */ def first[T](futures:Iterable[Future[T]]):SettableFuture[T,T] = { assert(!futures.isEmpty) new SettableFuture[T,T] { futures.foreach(_.onComplete(apply _)) protected def merge(value: T): Option[T] = { Some(value) } } } /** * creates a future which waits for all * of the supplied futures to get set and collects all * the results in an iterable. */ def all[T](futures:Iterable[Future[T]]):Future[Iterable[T]] = { if( futures.isEmpty ) { val rc = apply[Iterable[T]]() rc(List()) rc } else { val results = new ListBuffer[T]() new SettableFuture[T,Iterable[T]] { futures.foreach(_.onComplete(apply _)) protected def merge(value: T): Option[Iterable[T]] = { results += value if( results.size == futures.size ) { Some(results) } else { None } } } } } /** * creates a future which waits for all * of the supplied futures to get set and collects * the results via folding function. */ def fold[T,R](futures:Iterable[Future[T]], initial:R)(func: (R,T)=>R):Future[R] = { if( futures.isEmpty ) { val rc = apply[R]() rc(initial) rc } else { var cur:R = initial var collected = 0 new SettableFuture[T,R] { futures.foreach(_.onComplete(apply _)) protected def merge(value: T): Option[R] = { cur = func(cur, value) collected += 1 if( collected == futures.size ) { Some(cur) } else { None } } } } } } HawtServerSocketChannel.scala000066400000000000000000000164551227446104000417400ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-scala/src/main/scala/org/fusesource/hawtdispatch/** * Copyright (C) 2012 FuseSource, Inc. * http://fusesource.com * * Licensed 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.fusesource.hawtdispatch import util.continuations._ import java.nio.channels.{SocketChannel, SelectionKey, ServerSocketChannel} import collection.mutable.ListBuffer import java.nio.ByteBuffer import java.net.SocketAddress import java.io.IOException /** *

*

* * @author Hiram Chirino */ case class HawtServerSocketChannel(channel: ServerSocketChannel, queue: DispatchQueue = createQueue()) { channel.configureBlocking(false); var accept_requests = ListBuffer[(Either[SocketChannel, IOException]) => Unit]() val accept_source = createSource(channel, SelectionKey.OP_ACCEPT, queue) accept_source.onEvent { var source_drained = false while (!source_drained && !accept_requests.isEmpty) { val k = accept_requests.head try { val socket = channel.accept if (socket == null) { source_drained = true } else { accept_requests = accept_requests.drop(1) k(Left(socket)) } } catch { case e: IOException => k(Right(e)) } } if (accept_requests.isEmpty) { accept_source.suspend } } def accept: Either[SocketChannel, IOException]@suspendable = shift { k:(Either[SocketChannel, IOException]=>Unit) => queue { if( canceled ) { k(Right(new IOException("canceled"))) } else { if (accept_requests.isEmpty) { accept_source.resume } accept_requests.append(k) } } } var canceled = false var cancel_requests = ListBuffer[ Unit => Unit]() accept_source.onCancel { canceled = true accept_requests.foreach(_(Right(new IOException("canceled")))) accept_requests.clear cancel_requests.foreach(_({})) cancel_requests.clear } def cancel: Unit @suspendable = shift { k:(Unit=>Unit) => queue { if( canceled ) { k({}) } else { cancel_requests.append(k) accept_source.cancel } } } } /** *

*

* * @author Hiram Chirino */ case class HawtSocketChannel(channel: SocketChannel, queue: DispatchQueue = createQueue()) { channel.configureBlocking(false); var connect_request: (Option[IOException])=>Unit = _ var connect_source:DispatchSource = _ def connect(address:SocketAddress): Option[IOException]@suspendable = shift { k:(Option[IOException]=>Unit) => queue { if( canceled ) { k(Some(new IOException("canceled"))) } else { try { if( channel.connect(address) ) { k(None) } else { connect_request = k connect_source = createSource(channel, SelectionKey.OP_CONNECT, queue) def check = if( !connect_source.isCanceled ) { if( connect_source!=null ) { try { if(channel.finishConnect) { connect_source.cancel connect_source = null connect_request = null k(None) } } catch { case e:IOException => connect_source.cancel connect_source = null connect_request = null k(Some(e)) } } } connect_source.onEvent { check } connect_source.resume // TODO: perhaps we should introduce a connect timeout... // def schedual_check:Unit = queue.after(5,TimeUnit.SECONDS) { // check // if( connect_source==null ) { // schedual_check // } // } // schedual_check } } catch { case e:IOException => k(Some(e)) } } } } var read_requests = ListBuffer[(ByteBuffer, (Option[IOException]) => Unit)]() val read_source = createSource(channel, SelectionKey.OP_READ, queue) read_source.onEvent { var source_drained = false while (!source_drained && !read_requests.isEmpty) { val k = read_requests.head try { val remaining = k._1.remaining val count = channel.read(k._1) if (count == 0 && remaining > 0 ) { source_drained = true } else { read_requests = read_requests.drop(1) k._2(None) } } catch { case e: IOException => k._2(Some(e)) } } if (read_requests.isEmpty) { read_source.suspend } } def read(buffer:ByteBuffer): Option[IOException]@suspendable = shift { k:(Option[IOException]=>Unit) => queue { if( canceled ) { k(canceled_exception) } else { if (read_requests.isEmpty) { read_source.resume } read_requests.append((buffer,k)) } } } var write_requests = ListBuffer[(ByteBuffer, (Option[IOException]) => Unit)]() val write_source = createSource(channel, SelectionKey.OP_WRITE, queue) write_source.onEvent { var source_drained = false while (!source_drained && !write_requests.isEmpty) { val k = write_requests.head try { val remaining = k._1.remaining val count = channel.write(k._1) if (count == 0 && remaining > 0 ) { source_drained = true } else { if( k._1.remaining==0 ) { write_requests = write_requests.drop(1) k._2(None) } } } catch { case e: IOException => k._2(Some(e)) } } if (write_requests.isEmpty) { write_source.suspend } } def write(buffer:ByteBuffer): Option[IOException]@suspendable = shift { k:(Option[IOException]=>Unit) => queue { if( canceled ) { k(canceled_exception) } else { if (write_requests.isEmpty) { write_source.resume } write_requests.append((buffer,k)) } } } var canceled = false var cancel_requests = ListBuffer[ Unit => Unit]() read_source.onCancel { write_source.cancel } write_source.onCancel { canceled = true if( connect_source!=null ) { connect_request(canceled_exception) connect_request = null connect_source.cancel connect_source = null } read_requests.foreach(_._2(canceled_exception)) read_requests.clear write_requests.foreach(_._2(canceled_exception)) write_requests.clear cancel_requests.foreach(_({})) cancel_requests.clear } def canceled_exception=Some(new IOException("canceled")) def cancel:Unit @suspendable = shift { k:(Unit=>Unit) => queue { if( canceled ) { k({}) } else { cancel_requests.append(k) read_source.cancel } } } }ListEventAggregator.scala000066400000000000000000000024011227446104000411060ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-scala/src/main/scala/org/fusesource/hawtdispatch/** * Copyright (C) 2012 FuseSource, Inc. * http://fusesource.com * * Licensed 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.fusesource.hawtdispatch import collection.mutable.ListBuffer /** *

* An EventAggregator that coalesces object data obtained via calls to * {@link CustomDispatchSource#merge(Object)} into a ListBuffer. *

* * @author Hiram Chirino */ class ListEventAggregator[T] extends OrderedEventAggregator[T, ListBuffer[T]] { def mergeEvent(previous:ListBuffer[T], event:T) = { if( previous == null ) { ListBuffer(event) } else { previous += event } } def mergeEvents(previous:ListBuffer[T], events:ListBuffer[T]):ListBuffer[T] = { previous ++= events } } ScalaDispatchHelpers.scala000066400000000000000000000052351227446104000412240ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-scala/src/main/scala/org/fusesource/hawtdispatch/** * Copyright (C) 2012 FuseSource, Inc. * http://fusesource.com * * Licensed 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.fusesource.hawtdispatch /** *

* Contains several helper method for working with retained objects * and callbacks. *

* * @author Hiram Chirino */ object ScalaDispatchHelpers { ///////////////////////////////////////////////////////////////////// // // Helpers for working with Retained objects. // ///////////////////////////////////////////////////////////////////// def using(resource: Retained): (=> Unit) => Runnable = { using(resource, resource) _ } def using(resources: Seq[Retained]): (=> Unit) => Runnable = { using(resources, resources) _ } def retaining(resource: Retained): (=> Unit) => Runnable = { using(resource, null) _ } def retaining(resources: Seq[Retained]): (=> Unit) => Runnable = { using(resources, null) _ } def releasing(resource: Retained): (=> Unit) => Runnable = { using(null, resource) _ } def releasing(resources: Seq[Retained]): (=> Unit) => Runnable = { using(null, resources) _ } private def using(retainedResource: Retained, releasedResource: Retained)(proc: => Unit): Runnable = { if (retainedResource != null) { retainedResource.retain } new Runnable() { def run = { try { proc; } finally { if (releasedResource != null) { releasedResource.release } } } } } private def using(retainedResources: Seq[Retained], releasedResources: Seq[Retained])(proc: => Unit): Runnable = { retain(retainedResources) new Runnable() { def run = { try { proc; } finally { release(releasedResources) } } } } def retain(retainedResources: Seq[Retained]) = { if (retainedResources != null) { for (resource <- retainedResources) { resource.retain } } } def release(releasedResources: Seq[Retained]) = { if (releasedResources != null) { for (resource <- releasedResources) { resource.release } } } } TaskTracker.scala000066400000000000000000000055531227446104000374170ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-scala/src/main/scala/org/fusesource/hawtdispatch/** * Copyright (C) 2012 FuseSource, Inc. * http://fusesource.com * * Licensed 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.fusesource.hawtdispatch import java.util.HashSet import java.util.concurrent.{CountDownLatch, TimeUnit} import org.fusesource.hawtdispatch._ /** *

* A TaskTracker is used to track multiple async processing tasks and * call a callback once they all complete. *

* * @author Hiram Chirino */ class TaskTracker(val name:String="unknown", var timeout: Long = 0) { private[this] val tasks = new HashSet[TrackedTask]() private[this] var _callback:Runnable = null val queue = createQueue("tracker: "+name); var done = false class TrackedTask(var name:Any) extends Task { def run = { remove(this) } override def toString = name.toString } def task(name:Any="unknown"):TrackedTask = { val rc = new TrackedTask(name) queue { assert(_callback==null || !tasks.isEmpty) tasks.add(rc) } return rc } def callback(handler: Runnable) { var start = System.currentTimeMillis queue { _callback = handler checkDone() } def schedualCheck(timeout:Long):Unit = { if( timeout>0 ) { queue.after(timeout, TimeUnit.MILLISECONDS) { if( !done ) { schedualCheck(onTimeout(start, tasks.toArray.toList.map(_.toString))) } } } } schedualCheck(timeout) } def callback(handler: =>Unit ) { callback(^(handler)) } /** * Subclasses can override if they want to log the timeout event. * the method should return the next timeout value. If 0, then * it will not check for further timeouts. */ protected def onTimeout(started:Long, tasks: List[String]):Long = 0 private def remove(r:Runnable) = queue { if( tasks.remove(r) ) { checkDone() } } private def checkDone() = { assert(!done) if( tasks.isEmpty && _callback!=null && !done ) { done = true _callback.run } } def await() = { val latch =new CountDownLatch(1) callback { latch.countDown } latch.await } def await(timeout:Long, unit:TimeUnit) = { val latch = new CountDownLatch(1) callback { latch.countDown } latch.await(timeout, unit) } override def toString = tasks.synchronized { name+" waiting on: "+tasks } } hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-scala/src/test/000077500000000000000000000000001227446104000255565ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-scala/src/test/scala/000077500000000000000000000000001227446104000266415ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-scala/src/test/scala/org/000077500000000000000000000000001227446104000274305ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-scala/src/test/scala/org/fusesource/000077500000000000000000000000001227446104000316135ustar00rootroot00000000000000000077500000000000000000000000001227446104000342175ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-scala/src/test/scala/org/fusesource/hawtdispatchContinuationTest.scala000066400000000000000000000027261227446104000405450ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-scala/src/test/scala/org/fusesource/hawtdispatch/** * Copyright (C) 2012 FuseSource, Inc. * http://fusesource.com * * Licensed 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.fusesource.hawtdispatch import org.scalatest._ import junit.JUnitRunner import org.junit.runner.RunWith import org.scalatest.matchers.ShouldMatchers import java.util.concurrent.CountDownLatch /** *

*

* * @author Hiram Chirino */ @RunWith(classOf[JUnitRunner]) class ContinuationTest extends FunSuite with ShouldMatchers { test("Continuation Test") { object Foo { var held:Int = 0; val a = createQueue() def hold(v:Int) = a ! { val rc = held held = v rc } } object Bar { var sum:Int = 0; val b = createQueue() def apply() = b !! { val result = Foo.hold(sum+5) sum += result sum } } Bar().await should equal(0) Foo.held should equal(5) Bar.sum should equal(0) } } HawtSocketChannelTest.scala000066400000000000000000000065101227446104000414330ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-scala/src/test/scala/org/fusesource/hawtdispatch/** * Copyright (C) 2012 FuseSource, Inc. * http://fusesource.com * * Licensed 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.fusesource.hawtdispatch import org.scalatest._ import junit.JUnitRunner import org.junit.runner.RunWith import org.scalatest.matchers.ShouldMatchers import java.util.concurrent.atomic.AtomicBoolean import java.net.InetSocketAddress import java.nio.channels.{SocketChannel, ServerSocketChannel} import java.nio.ByteBuffer import org.fusesource.hawtdispatch._ import util.continuations._ /** *

*

* * @author Hiram Chirino */ @RunWith(classOf[JUnitRunner]) class HawtSocketChannelTest extends FunSuite with ShouldMatchers { def noop = shift { k: (Unit=>Unit) => k() } test("Echo Server Test") { // Lets implement a simple non blocking echo server.. var server_shutdown = new AtomicBoolean() val server = HawtServerSocketChannel({ val channel = ServerSocketChannel.open(); channel.socket().bind(new InetSocketAddress(0)); channel }) // This handles a socket connection.. def service(channel:SocketChannel) = { val socket = HawtSocketChannel(channel) val buffer = ByteBuffer.allocate(1024*4) def close(reason:Exception) = { if( reason!=null ) { println("socket failure: "+reason) } socket.cancel socket.channel.close } // client processing is done on hawtdispatch queue socket.queue { reset { while (!server_shutdown.get() && socket.channel.isOpen ) { buffer.clear val rc = socket.read(buffer) if( !rc.isDefined ) { buffer.flip val rc = socket.write(buffer) if( rc.isDefined ) { close(rc.get) } else { noop } } else { close(rc.get) } } } } } // server accept processing is done on hawtdispatch queue server.queue { reset { while (!server_shutdown.get() && server.channel.isOpen) { val rc = server.accept if( rc.isLeft ) { service(rc.left.get) noop } else { println("accept failed: "+rc.right.get) server.cancel server.channel.close } } } } // // Use a simple blocking client to test the non blocking echo server.. val client = SocketChannel.open() client.connect(new InetSocketAddress("localhost", server.channel.socket.getLocalPort)) client.write(ByteBuffer.wrap("Hello".getBytes)); val buffer = ByteBuffer.allocate(1024); client.read(buffer) should equal(5) client.close // Shutdown the server server_shutdown.set(true) reset { server.cancel } } } SocketTest.scala000066400000000000000000000066771227446104000373340ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-scala/src/test/scala/org/fusesource/hawtdispatch/** * Copyright (C) 2012 FuseSource, Inc. * http://fusesource.com * * Licensed 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.fusesource.hawtdispatch import org.scalatest._ import junit.JUnitRunner import org.junit.runner.RunWith import org.scalatest.matchers.ShouldMatchers import java.nio._ import java.nio.channels._ import java.net._ import java.io.IOException import org.fusesource.hawtdispatch._ import java.util.concurrent.atomic.AtomicInteger; /** *

*

* * @author Hiram Chirino */ @RunWith(classOf[JUnitRunner]) class SocketTest extends FunSuite with ShouldMatchers { test("Socket Disconnect Event") { val connections = new AtomicInteger(0); class Server() { val channel = ServerSocketChannel.open(); channel.socket().bind(new InetSocketAddress(0)); channel.configureBlocking(false); val queue = createQueue("server") val accept_source = createSource(channel, SelectionKey.OP_ACCEPT, queue); accept_source.onEvent { val socket = channel.accept(); try { new Session(socket).start() } catch { case e: Exception => socket.close } } def start() = { accept_source.resume this } def stop() = { accept_source.cancel } accept_source.onCancel { channel.close(); } def port = channel.socket.getLocalPort } class Session(val channel: SocketChannel) { channel.configureBlocking(false); channel.socket.setSoLinger(true, 0) val buffer = ByteBuffer.allocate(1024); val queue = createQueue("session") val read_source = createSource(channel, SelectionKey.OP_READ, queue); var closed = false read_source.setEventHandler(^{ try { buffer.clear if( !channel.isConnected ) { close } else if (channel.read(buffer) == -1) { if( !closed ) { close } } } catch { case e:IOException => if( !closed ) { close } } }) connections.incrementAndGet def start() = read_source.resume def close() = { if( !closed ) { closed = true; read_source.cancel } } read_source.onCancel { connections.decrementAndGet channel.close } } def connections_should_equal(value:Int):Unit = { for( i <- 0 until 20 ) { if( connections.get==value ) { return; } Thread.sleep(100); } connections.get should equal(value) } val server = new Server() server.start for( i <- 0 until 20 ) { connections_should_equal(0) val socket = new Socket("localhost", server.port); socket.setSoLinger(true, 0) connections_should_equal(1) socket.close connections_should_equal(0) } } } hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-transport/000077500000000000000000000000001227446104000247615ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-transport/pom.xml000066400000000000000000000054001227446104000262750ustar00rootroot00000000000000 4.0.0 org.fusesource.hawtdispatch hawtdispatch-project 1.20 org.fusesource.hawtdispatch hawtdispatch-transport 1.20 bundle HawtDispatch Transport: Transport abstractions for HawtDispatch 4.7 3.1 1.2.14 4.2.0 org.fusesource.hawtdispatch hawtdispatch 1.20 org.fusesource.hawtbuf hawtbuf ${hawtbuf-version} true junit junit ${junit-version} test log4j log4j ${log4j-version} test org.apache.felix maven-bundle-plugin true true hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-transport/src/000077500000000000000000000000001227446104000255505ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-transport/src/main/000077500000000000000000000000001227446104000264745ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-transport/src/main/java/000077500000000000000000000000001227446104000274155ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-transport/src/main/java/org/000077500000000000000000000000001227446104000302045ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-transport/src/main/java/org/fusesource/000077500000000000000000000000001227446104000323675ustar00rootroot00000000000000000077500000000000000000000000001227446104000347735ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-transport/src/main/java/org/fusesource/hawtdispatch000077500000000000000000000000001227446104000370275ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-transport/src/main/java/org/fusesource/hawtdispatch/transportAbstractProtocolCodec.java000066400000000000000000000422101227446104000441140ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-transport/src/main/java/org/fusesource/hawtdispatch/transport/** * Copyright (C) 2012 FuseSource, Inc. * http://fusesource.com * * Licensed 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.fusesource.hawtdispatch.transport; import org.fusesource.hawtbuf.Buffer; import org.fusesource.hawtbuf.DataByteArrayOutputStream; import org.fusesource.hawtdispatch.util.BufferPool; import org.fusesource.hawtdispatch.util.BufferPools; import java.io.EOFException; import java.io.IOException; import java.net.ProtocolException; import java.net.SocketException; import java.nio.ByteBuffer; import java.nio.channels.GatheringByteChannel; import java.nio.channels.ReadableByteChannel; import java.nio.channels.SocketChannel; import java.util.Arrays; import java.util.LinkedList; /** * Provides an abstract base class to make implementing the ProtocolCodec interface * easier. * * @author Hiram Chirino */ public abstract class AbstractProtocolCodec implements ProtocolCodec { protected BufferPools bufferPools; protected BufferPool writeBufferPool; protected BufferPool readBufferPool; protected int writeBufferSize = 1024 * 64; protected long writeCounter = 0L; protected GatheringByteChannel writeChannel = null; protected DataByteArrayOutputStream nextWriteBuffer; protected long lastWriteIoSize = 0; protected LinkedList writeBuffer = new LinkedList(); private long writeBufferRemaining = 0; public static interface Action { Object apply() throws IOException; } protected long readCounter = 0L; protected int readBufferSize = 1024 * 64; protected ReadableByteChannel readChannel = null; protected ByteBuffer readBuffer; protected ByteBuffer directReadBuffer = null; protected int readEnd; protected int readStart; protected int lastReadIoSize; protected Action nextDecodeAction; public void setTransport(Transport transport) { this.writeChannel = (GatheringByteChannel) transport.getWriteChannel(); this.readChannel = transport.getReadChannel(); if( nextDecodeAction==null ) { nextDecodeAction = initialDecodeAction(); } if( transport instanceof TcpTransport) { TcpTransport tcp = (TcpTransport) transport; writeBufferSize = tcp.getSendBufferSize(); readBufferSize = tcp.getReceiveBufferSize(); } else if( transport instanceof UdpTransport) { UdpTransport tcp = (UdpTransport) transport; writeBufferSize = tcp.getSendBufferSize(); readBufferSize = tcp.getReceiveBufferSize(); } else { try { if (this.writeChannel instanceof SocketChannel) { writeBufferSize = ((SocketChannel) this.writeChannel).socket().getSendBufferSize(); readBufferSize = ((SocketChannel) this.readChannel).socket().getReceiveBufferSize(); } else if (this.writeChannel instanceof SslTransport.SSLChannel) { writeBufferSize = ((SslTransport.SSLChannel) this.readChannel).socket().getSendBufferSize(); readBufferSize = ((SslTransport.SSLChannel) this.writeChannel).socket().getReceiveBufferSize(); } } catch (SocketException ignore) { } } if( bufferPools!=null ) { readBufferPool = bufferPools.getBufferPool(readBufferSize); writeBufferPool = bufferPools.getBufferPool(writeBufferSize); } } public int getReadBufferSize() { return readBufferSize; } public int getWriteBufferSize() { return writeBufferSize; } public boolean full() { return writeBufferRemaining >= writeBufferSize; } public boolean isEmpty() { return writeBufferRemaining == 0 && (nextWriteBuffer==null || nextWriteBuffer.size() == 0); } public long getWriteCounter() { return writeCounter; } public long getLastWriteSize() { return lastWriteIoSize; } abstract protected void encode(Object value) throws IOException; public ProtocolCodec.BufferState write(Object value) throws IOException { if (full()) { return ProtocolCodec.BufferState.FULL; } else { boolean wasEmpty = isEmpty(); if( nextWriteBuffer == null ) { nextWriteBuffer = allocateNextWriteBuffer(); } encode(value); if (nextWriteBuffer.size() >= (writeBufferSize* 0.75)) { flushNextWriteBuffer(); } if (wasEmpty) { return ProtocolCodec.BufferState.WAS_EMPTY; } else { return ProtocolCodec.BufferState.NOT_EMPTY; } } } private DataByteArrayOutputStream allocateNextWriteBuffer() { if( writeBufferPool !=null ) { return new DataByteArrayOutputStream(writeBufferPool.checkout()) { @Override protected void resize(int newcount) { byte[] oldbuf = buf; super.resize(newcount); if( oldbuf.length == writeBufferPool.getBufferSize() ) { writeBufferPool.checkin(oldbuf); } } }; } else { return new DataByteArrayOutputStream(writeBufferSize); } } protected void writeDirect(ByteBuffer value) throws IOException { // is the direct buffer small enough to just fit into the nextWriteBuffer? int nextnextPospos = nextWriteBuffer.position(); int valuevalueLengthlength = value.remaining(); int available = nextWriteBuffer.getData().length - nextnextPospos; if (available > valuevalueLengthlength) { value.get(nextWriteBuffer.getData(), nextnextPospos, valuevalueLengthlength); nextWriteBuffer.position(nextnextPospos + valuevalueLengthlength); } else { if (nextWriteBuffer!=null && nextWriteBuffer.size() != 0) { flushNextWriteBuffer(); } writeBuffer.add(value); writeBufferRemaining += value.remaining(); } } protected void flushNextWriteBuffer() { DataByteArrayOutputStream next = allocateNextWriteBuffer(); ByteBuffer bb = nextWriteBuffer.toBuffer().toByteBuffer(); writeBuffer.add(bb); writeBufferRemaining += bb.remaining(); nextWriteBuffer = next; } public ProtocolCodec.BufferState flush() throws IOException { while (true) { if (writeBufferRemaining != 0) { if( writeBuffer.size() == 1) { ByteBuffer b = writeBuffer.getFirst(); lastWriteIoSize = writeChannel.write(b); if (lastWriteIoSize == 0) { return ProtocolCodec.BufferState.NOT_EMPTY; } else { writeBufferRemaining -= lastWriteIoSize; writeCounter += lastWriteIoSize; if(!b.hasRemaining()) { onBufferFlushed(writeBuffer.removeFirst()); } } } else { ByteBuffer[] buffers = writeBuffer.toArray(new ByteBuffer[writeBuffer.size()]); lastWriteIoSize = writeChannel.write(buffers, 0, buffers.length); if (lastWriteIoSize == 0) { return ProtocolCodec.BufferState.NOT_EMPTY; } else { writeBufferRemaining -= lastWriteIoSize; writeCounter += lastWriteIoSize; while (!writeBuffer.isEmpty() && !writeBuffer.getFirst().hasRemaining()) { onBufferFlushed(writeBuffer.removeFirst()); } } } } else { if (nextWriteBuffer==null || nextWriteBuffer.size() == 0) { if( writeBufferPool!=null && nextWriteBuffer!=null ) { writeBufferPool.checkin(nextWriteBuffer.getData()); nextWriteBuffer = null; } return ProtocolCodec.BufferState.EMPTY; } else { flushNextWriteBuffer(); } } } } /** * Called when a buffer is flushed out. Subclasses can implement * in case they want to recycle the buffer. * * @param byteBuffer */ protected void onBufferFlushed(ByteBuffer byteBuffer) { } ///////////////////////////////////////////////////////////////////// // // Non blocking read impl // ///////////////////////////////////////////////////////////////////// abstract protected Action initialDecodeAction(); public void unread(byte[] buffer) { assert ((readCounter == 0)); readBuffer = ByteBuffer.allocate(buffer.length); readBuffer.put(buffer); readCounter += buffer.length; } public long getReadCounter() { return readCounter; } public long getLastReadSize() { return lastReadIoSize; } public Object read() throws IOException { Object command = null; while (command == null) { if (directReadBuffer != null) { while (directReadBuffer.hasRemaining()) { lastReadIoSize = readChannel.read(directReadBuffer); readCounter += lastReadIoSize; if (lastReadIoSize == -1) { throw new EOFException("Peer disconnected"); } else if (lastReadIoSize == 0) { return null; } } command = nextDecodeAction.apply(); } else { if (readBuffer==null || readEnd >= readBuffer.position()) { int readPos = 0; boolean candidateForCheckin = false; if( readBuffer!=null ) { readPos = readBuffer.position(); candidateForCheckin = readBufferPool!=null && readStart == 0 && readBuffer.capacity() == readBufferPool.getBufferSize(); } if (readBuffer==null || readBuffer.remaining() == 0) { int loadedSize = readPos - readStart; int neededSize = readEnd - readStart; int newSize = 0; if( neededSize > loadedSize ) { newSize = Math.max(readBufferSize, neededSize); } else { newSize = loadedSize+readBufferSize; } byte[] newBuffer; if (loadedSize > 0) { newBuffer = Arrays.copyOfRange(readBuffer.array(), readStart, readStart + newSize); } else { if( readBufferPool!=null && newSize == readBufferPool.getBufferSize()) { newBuffer = readBufferPool.checkout(); } else { newBuffer = new byte[newSize]; } } if( candidateForCheckin ) { readBufferPool.checkin(readBuffer.array()); } readBuffer = ByteBuffer.wrap(newBuffer); readBuffer.position(loadedSize); readStart = 0; readEnd = neededSize; } lastReadIoSize = readChannel.read(readBuffer); readCounter += lastReadIoSize; if (lastReadIoSize == -1) { readCounter += 1; // to compensate for that -1 throw new EOFException("Peer disconnected"); } else if (lastReadIoSize == 0) { if ( readStart == readBuffer.position() ) { if (candidateForCheckin) { readBufferPool.checkin(readBuffer.array()); } readStart = 0; readEnd = 0; readBuffer = null; } return null; } // if we did not read a full buffer.. then resize the buffer if( readBuffer.hasRemaining() && readEnd <= readBuffer.position() ) { ByteBuffer perfectSized = ByteBuffer.wrap(Arrays.copyOfRange(readBuffer.array(), 0, readBuffer.position())); perfectSized.position(readBuffer.position()); if( candidateForCheckin ) { readBufferPool.checkin(readBuffer.array()); } readBuffer = perfectSized; } } command = nextDecodeAction.apply(); assert ((readStart <= readEnd)); } } return command; } protected Buffer readUntil(Byte octet) throws ProtocolException { return readUntil(octet, -1); } protected Buffer readUntil(Byte octet, int max) throws ProtocolException { return readUntil(octet, max, "Maximum protocol buffer length exeeded"); } protected Buffer readUntil(Byte octet, int max, String msg) throws ProtocolException { byte[] array = readBuffer.array(); Buffer buf = new Buffer(array, readEnd, readBuffer.position() - readEnd); int pos = buf.indexOf(octet); if (pos >= 0) { int offset = readStart; readEnd += pos + 1; readStart = readEnd; int length = readEnd - offset; if (max >= 0 && length > max) { throw new ProtocolException(msg); } return new Buffer(array, offset, length); } else { readEnd += buf.length; if (max >= 0 && (readEnd - readStart) > max) { throw new ProtocolException(msg); } return null; } } protected Buffer readBytes(int length) { readEnd = readStart + length; if (readBuffer.position() < readEnd) { return null; } else { int offset = readStart; readStart = readEnd; return new Buffer(readBuffer.array(), offset, length); } } protected Buffer peekBytes(int length) { readEnd = readStart + length; if (readBuffer.position() < readEnd) { return null; } else { // rewind.. readEnd = readStart; return new Buffer(readBuffer.array(), readStart, length); } } protected Boolean readDirect(ByteBuffer buffer) { assert (directReadBuffer == null || (directReadBuffer == buffer)); if (buffer.hasRemaining()) { // First we need to transfer the read bytes from the non-direct // byte buffer into the direct one.. int limit = readBuffer.position(); int transferSize = Math.min((limit - readStart), buffer.remaining()); byte[] readBufferArray = readBuffer.array(); buffer.put(readBufferArray, readStart, transferSize); // The direct byte buffer might have been smaller than our readBuffer one.. // compact the readBuffer to avoid doing additional mem allocations. int trailingSize = limit - (readStart + transferSize); if (trailingSize > 0) { System.arraycopy(readBufferArray, readStart + transferSize, readBufferArray, readStart, trailingSize); } readBuffer.position(readStart + trailingSize); } // For big direct byte buffers, it will still not have been filled, // so install it so that we directly read into it until it is filled. if (buffer.hasRemaining()) { directReadBuffer = buffer; return false; } else { directReadBuffer = null; buffer.flip(); return true; } } public BufferPools getBufferPools() { return bufferPools; } public void setBufferPools(BufferPools bufferPools) { this.bufferPools = bufferPools; if( bufferPools!=null ) { readBufferPool = bufferPools.getBufferPool(readBufferSize); writeBufferPool = bufferPools.getBufferPool(writeBufferSize); } else { readBufferPool = null; writeBufferPool = null; } } } DefaultTransportListener.java000066400000000000000000000021451227446104000447030ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-transport/src/main/java/org/fusesource/hawtdispatch/transport/** * Copyright (C) 2012 FuseSource, Inc. * http://fusesource.com * * Licensed 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.fusesource.hawtdispatch.transport; import java.io.IOException; /** *

*

* * @author Hiram Chirino */ public class DefaultTransportListener implements TransportListener { public void onRefill() { } public void onTransportCommand(Object command) { } public void onTransportConnected() { } public void onTransportDisconnected() { } public void onTransportFailure(IOException error) { } } HeartBeatMonitor.java000066400000000000000000000133641227446104000431100ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-transport/src/main/java/org/fusesource/hawtdispatch/transport/** * Copyright (C) 2012 FuseSource, Inc. * http://fusesource.com * * Licensed 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.fusesource.hawtdispatch.transport; import org.fusesource.hawtdispatch.Dispatch; import org.fusesource.hawtdispatch.Task; import java.util.concurrent.TimeUnit; /** *

A HeartBeatMonitor can be used to watch the read and write * activity of a transport and raise events when the write side * or read side has been idle too long.

* * @author Hiram Chirino */ public class HeartBeatMonitor { Transport transport; long initialWriteCheckDelay; long initialReadCheckDelay; long writeInterval; long readInterval; Task onKeepAlive = Dispatch.NOOP; Task onDead = Dispatch.NOOP; short session = 0; boolean readSuspendedInterval; short readSuspendCount; public void suspendRead() { readSuspendCount++; readSuspendedInterval = true; } public void resumeRead() { readSuspendCount--; } private void schedule(final short session, long interval, final Task func) { if (this.session == session) { transport.getDispatchQueue().executeAfter(interval, TimeUnit.MILLISECONDS, new Task() { public void run() { if (HeartBeatMonitor.this.session == session) { func.run(); } } }); } } private void scheduleCheckWrites(final short session) { final ProtocolCodec codec = transport.getProtocolCodec(); Task func; if (codec == null) { func = new Task() { public void run() { scheduleCheckWrites(session); } }; } else { final long lastWriteCounter = codec.getWriteCounter(); func = new Task() { public void run() { if (lastWriteCounter == codec.getWriteCounter()) { onKeepAlive.run(); } scheduleCheckWrites(session); } }; } schedule(session, writeInterval, func); } private void scheduleCheckReads(final short session) { final ProtocolCodec codec = transport.getProtocolCodec(); Task func; if (codec == null) { func = new Task() { public void run() { scheduleCheckReads(session); } }; } else { final long lastReadCounter = codec.getReadCounter(); func = new Task() { public void run() { if (lastReadCounter == codec.getReadCounter() && !readSuspendedInterval && readSuspendCount == 0) { onDead.run(); } readSuspendedInterval = false; scheduleCheckReads(session); } }; } schedule(session, readInterval, func); } public void start() { session++; readSuspendedInterval = false; if (writeInterval != 0) { if (initialWriteCheckDelay != 0) { transport.getDispatchQueue().executeAfter(initialWriteCheckDelay, TimeUnit.MILLISECONDS, new Task() { public void run() { scheduleCheckWrites(session); } }); } else { scheduleCheckWrites(session); } } if (readInterval != 0) { if (initialReadCheckDelay != 0) { transport.getDispatchQueue().executeAfter(initialReadCheckDelay, TimeUnit.MILLISECONDS, new Task() { public void run() { scheduleCheckReads(session); } }); } else { scheduleCheckReads(session); } } } public void stop() { session++; } public long getInitialReadCheckDelay() { return initialReadCheckDelay; } public void setInitialReadCheckDelay(long initialReadCheckDelay) { this.initialReadCheckDelay = initialReadCheckDelay; } public long getInitialWriteCheckDelay() { return initialWriteCheckDelay; } public void setInitialWriteCheckDelay(long initialWriteCheckDelay) { this.initialWriteCheckDelay = initialWriteCheckDelay; } public Task getOnDead() { return onDead; } public void setOnDead(Task onDead) { this.onDead = onDead; } public Task getOnKeepAlive() { return onKeepAlive; } public void setOnKeepAlive(Task onKeepAlive) { this.onKeepAlive = onKeepAlive; } public long getWriteInterval() { return writeInterval; } public void setWriteInterval(long writeInterval) { this.writeInterval = writeInterval; } public Transport getTransport() { return transport; } public void setTransport(Transport transport) { this.transport = transport; } public long getReadInterval() { return readInterval; } public void setReadInterval(long readInterval) { this.readInterval = readInterval; } } PipeTransport.java000066400000000000000000000170311227446104000425060ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-transport/src/main/java/org/fusesource/hawtdispatch/transport/** * Copyright (C) 2012 FuseSource, Inc. * http://fusesource.com * * Licensed 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.fusesource.hawtdispatch.transport; import org.fusesource.hawtdispatch.*; import java.io.EOFException; import java.io.IOException; import java.net.SocketAddress; import java.net.URI; import java.nio.channels.ReadableByteChannel; import java.nio.channels.WritableByteChannel; import java.util.LinkedList; import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicBoolean; /** * * @author Hiram Chirino */ public class PipeTransport implements Transport { static private final Object EOF_TOKEN = new Object(); final private PipeTransportServer server; PipeTransport peer; private TransportListener listener; private SocketAddress remoteAddress; private AtomicBoolean stopping = new AtomicBoolean(); private String name; private boolean marshal; private boolean trace; private DispatchQueue dispatchQueue; private CustomDispatchSource> dispatchSource; private boolean connected; private long writeCounter = 0; private long readCounter = 0; private ProtocolCodec protocolCodec; public PipeTransport(PipeTransportServer server) { this.server = server; } public DispatchQueue getDispatchQueue() { return dispatchQueue; } public void setDispatchQueue(DispatchQueue queue) { this.dispatchQueue = queue; } @Deprecated public void start(final Runnable onCompleted) { start(new TaskWrapper(onCompleted)); } public void start(final Task onCompleted) { if (dispatchQueue == null) { throw new IllegalArgumentException("dispatchQueue is not set"); } server.dispatchQueue.execute(new Task(){ public void run() { dispatchSource = Dispatch.createSource(EventAggregators.linkedList(), dispatchQueue); dispatchSource.setEventHandler(new Task() { public void run() { try { final LinkedList commands = dispatchSource.getData(); for (Object o : commands) { if (o == EOF_TOKEN) { throw new EOFException(); } readCounter++; listener.onTransportCommand(o); } // let the peer know that they have been processed. peer.dispatchQueue.execute(new Task() { public void run() { outbound -= commands.size(); drainInbound(); } }); } catch (IOException e) { listener.onTransportFailure(e); } } }); if( peer.dispatchSource != null ) { fireConnected(); peer.fireConnected(); } if( onCompleted!=null ) { onCompleted.run(); } } }); } private void fireConnected() { dispatchQueue.execute(new Task() { public void run() { connected = true; dispatchSource.resume(); listener.onTransportConnected(); drainInbound(); } }); } public void flush() { listener.onRefill(); } @Deprecated public void stop(final Runnable onCompleted) { stop(new TaskWrapper(onCompleted)); } public void stop(Task onCompleted) { if( connected ) { peer.dispatchSource.merge(EOF_TOKEN); } if( dispatchSource!=null ) { dispatchSource.setCancelHandler(onCompleted); dispatchSource.cancel(); } setDispatchQueue(null); } static final class OneWay { final Object command; final Retained retained; public OneWay(Object command, Retained retained) { this.command = command; this.retained = retained; } } int outbound = 0; int maxOutbound = 100; public boolean full() { return outbound >= maxOutbound; } public boolean offer(Object command) { if( !connected ) { return false; } if( full() ) { return false; } else { transmit(command); return true; } } public void drainInbound() { if( !full() ) { listener.onRefill(); } } private void transmit(Object command) { writeCounter++; outbound++; peer.dispatchSource.merge(command); } /** * @return The number of objects sent by the transport. */ public long getWriteCounter() { return writeCounter; } /** * @return The number of objects received by the transport. */ public long getReadCounter() { return readCounter; } public SocketAddress getLocalAddress() { return remoteAddress; } public SocketAddress getRemoteAddress() { return remoteAddress; } public void suspendRead() { dispatchSource.suspend(); } public void resumeRead() { dispatchSource.resume(); } public void setRemoteAddress(final String remoteAddress) { this.remoteAddress = new SocketAddress() { @Override public String toString() { return remoteAddress; } }; if (name == null) { name = remoteAddress; } } public void setName(String name) { this.name = name; } public TransportListener getTransportListener() { return listener; } public void setTransportListener(TransportListener transportListener) { this.listener = transportListener; } public ProtocolCodec getProtocolCodec() { return protocolCodec; } public void setProtocolCodec(ProtocolCodec protocolCodec) { this.protocolCodec = protocolCodec; } public boolean isTrace() { return trace; } public void setTrace(boolean trace) { this.trace = trace; } public boolean isMarshal() { return marshal; } public void setMarshal(boolean marshall) { this.marshal = marshall; } public boolean isConnected() { return !stopping.get(); } public boolean isClosed() { return false; } public Executor getBlockingExecutor() { return null; } public void setBlockingExecutor(Executor blockingExecutor) { } public ReadableByteChannel getReadChannel() { return null; } public WritableByteChannel getWriteChannel() { return null; } } PipeTransportRegistry.java000066400000000000000000000041541227446104000442410ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-transport/src/main/java/org/fusesource/hawtdispatch/transport/** * Copyright (C) 2012 FuseSource, Inc. * http://fusesource.com * * Licensed 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.fusesource.hawtdispatch.transport; import java.io.IOException; import java.net.URISyntaxException; import java.util.HashMap; import java.util.Map; /** * * @author Hiram Chirino */ public class PipeTransportRegistry { public static final HashMap servers = new HashMap(); synchronized static public TransportServer bind(String location) throws URISyntaxException, IOException { if (servers.containsKey(location)) { throw new IOException("Server already bound: " + location); } PipeTransportServer server = new PipeTransportServer(); server.setConnectURI(location); server.setName(location); servers.put(location, server); return server; } synchronized static public Transport connect(String location) throws IOException, URISyntaxException { PipeTransportServer server = lookup(location); if (server == null) { throw new IOException("Server is not bound: " + location); } return server.connect(); } synchronized static public PipeTransportServer lookup(String name) { return servers.get(name); } synchronized static public Map getServers() { return new HashMap(servers); } synchronized static public void unbind(PipeTransportServer server) { servers.remove(server.getName()); } } PipeTransportServer.java000066400000000000000000000110101227446104000436640ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-transport/src/main/java/org/fusesource/hawtdispatch/transport/** * Copyright (C) 2012 FuseSource, Inc. * http://fusesource.com * * Licensed 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.fusesource.hawtdispatch.transport; import org.fusesource.hawtdispatch.*; import java.net.InetSocketAddress; import java.net.URI; import java.util.LinkedList; import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicInteger; /** * * @author Hiram Chirino */ public class PipeTransportServer implements TransportServer { protected String connectURI; protected TransportServerListener listener; protected String name; protected boolean marshal; protected final AtomicInteger connectionCounter = new AtomicInteger(); DispatchQueue dispatchQueue; private CustomDispatchSource> acceptSource; public String getBoundAddress() { return connectURI; } public InetSocketAddress getSocketAddress() { return null; } public DispatchQueue getDispatchQueue() { return dispatchQueue; } public void setDispatchQueue(DispatchQueue queue) { dispatchQueue = queue; } public void suspend() { acceptSource.suspend(); } public void resume() { acceptSource.resume(); } public void setTransportServerListener(TransportServerListener listener) { this.listener = listener; } @Deprecated public void start(Runnable onCompleted) throws Exception { start(new TaskWrapper(onCompleted)); } @Deprecated public void stop(Runnable onCompleted) throws Exception { stop(new TaskWrapper(onCompleted)); } public void start(Task onCompleted) throws Exception { acceptSource = Dispatch.createSource(EventAggregators.linkedList(), dispatchQueue); acceptSource.setEventHandler(new Task() { public void run() { LinkedList transports = acceptSource.getData(); for (PipeTransport transport : transports) { try { listener.onAccept(transport); } catch (Exception e) { listener.onAcceptError(e); } } } }); acceptSource.resume(); if( onCompleted!=null ) { dispatchQueue.execute(onCompleted); } } public void stop(Task onCompleted) throws Exception { PipeTransportRegistry.unbind(this); acceptSource.setCancelHandler(onCompleted); acceptSource.cancel(); } public void setConnectURI(String connectURI) { this.connectURI = connectURI; } public void setName(String name) { this.name = name; } public String getName() { return name; } public PipeTransport connect() { int connectionId = connectionCounter.incrementAndGet(); String remoteAddress = connectURI.toString() + "#" + connectionId; assert this.listener != null : "Server does not have an accept listener"; PipeTransport clientTransport = createClientTransport(); PipeTransport serverTransport = createServerTransport(); clientTransport.peer = serverTransport; serverTransport.peer = clientTransport; clientTransport.setRemoteAddress(remoteAddress); serverTransport.setRemoteAddress(remoteAddress); serverTransport.setMarshal(marshal); this.acceptSource.merge(serverTransport); return clientTransport; } protected PipeTransport createClientTransport() { return new PipeTransport(this); } protected PipeTransport createServerTransport() { return new PipeTransport(this); } public boolean isMarshal() { return marshal; } public void setMarshal(boolean marshal) { this.marshal = marshal; } public Executor getBlockingExecutor() { return null; } public void setBlockingExecutor(Executor blockingExecutor) { } } ProtocolCodec.java000066400000000000000000000053701227446104000424360ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-transport/src/main/java/org/fusesource/hawtdispatch/transport/** * Copyright (C) 2012 FuseSource, Inc. * http://fusesource.com * * Licensed 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.fusesource.hawtdispatch.transport; import java.io.IOException; import java.nio.channels.ReadableByteChannel; import java.nio.channels.WritableByteChannel; /** * Interface to encode and decode commands in and out of a a non blocking channel. * * @author Hiram Chirino */ public interface ProtocolCodec { public void setTransport(Transport transport); /////////////////////////////////////////////////////////////////// // // Methods related with reading from the channel // /////////////////////////////////////////////////////////////////// /** * Non-blocking channel based decoding. * * @return * @throws IOException */ Object read() throws IOException; /** * Pushes back a buffer as being unread. * * @param buffer */ void unread(byte[] buffer); /** * @return The number of bytes received. */ public long getReadCounter(); /** * @return The number of bytes read in the last read io performed. */ public long getLastReadSize(); /////////////////////////////////////////////////////////////////// // // Methods related with writing to the channel // /////////////////////////////////////////////////////////////////// enum BufferState { EMPTY, WAS_EMPTY, NOT_EMPTY, FULL, } public int getReadBufferSize(); public int getWriteBufferSize(); /** * Non-blocking channel based encoding. * * @return true if the write completed. * @throws IOException */ BufferState write(Object value) throws IOException; /** * Attempts to complete the previous write which did not complete. * @return * @throws IOException */ BufferState flush() throws IOException; /** * Is the codec's buffer full? * @return */ boolean full(); /** * @return The number of bytes written. */ public long getWriteCounter(); /** * @return The number of bytes read in the last write io performed. */ public long getLastWriteSize(); } SecuredSession.java000066400000000000000000000017431227446104000426350ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-transport/src/main/java/org/fusesource/hawtdispatch/transport/** * Copyright (C) 2012 FuseSource, Inc. * http://fusesource.com * * Licensed 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.fusesource.hawtdispatch.transport; import java.security.cert.X509Certificate; /** *

*

* * @author Hiram Chirino */ public interface SecuredSession { /** * Gets the X509Certificate associated withe the peer. * @return */ public X509Certificate[] getPeerX509Certificates(); } ServiceBase.java000066400000000000000000000117671227446104000421010ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-transport/src/main/java/org/fusesource/hawtdispatch/transport/** * Copyright (C) 2012 FuseSource, Inc. * http://fusesource.com * * Licensed 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.fusesource.hawtdispatch.transport; import org.fusesource.hawtdispatch.DispatchQueue; import org.fusesource.hawtdispatch.Task; import org.fusesource.hawtdispatch.TaskWrapper; import java.util.LinkedList; /** *

* The BaseService provides helpers for dealing async service state. *

* * @author Hiram Chirino */ public abstract class ServiceBase { public static class State { public String toString() { return getClass().getSimpleName(); } public boolean isStarted() { return false; } public boolean isStarting() { return false; } } static class CallbackSupport extends State { LinkedList callbacks = new LinkedList(); void add(Task r) { if (r != null) { callbacks.add(r); } } void done() { for (Task callback : callbacks) { callback.run(); } } } public static final State CREATED = new State(); public static class STARTING extends CallbackSupport { public boolean isStarting() { return true; } } public static final State STARTED = new State() { public boolean isStarted() { return true; } }; public static class STOPPING extends CallbackSupport { } public static final State STOPPED = new State(); protected State _serviceState = CREATED; final public void start(final Runnable onCompleted) { start(new TaskWrapper(onCompleted)); } final public void start(final Task onCompleted) { getDispatchQueue().execute(new Task() { public void run() { if (_serviceState == CREATED || _serviceState == STOPPED) { final STARTING state = new STARTING(); state.add(onCompleted); _serviceState = state; _start(new Task() { public void run() { _serviceState = STARTED; state.done(); } }); } else if (_serviceState instanceof STARTING) { ((STARTING) _serviceState).add(onCompleted); } else if (_serviceState == STARTED) { if (onCompleted != null) { onCompleted.run(); } } else { if (onCompleted != null) { onCompleted.run(); } error("start should not be called from state: " + _serviceState); } } }); } final public void stop(final Runnable onCompleted) { stop(new TaskWrapper(onCompleted)); } final public void stop(final Task onCompleted) { getDispatchQueue().execute(new Task() { public void run() { if (_serviceState == STARTED) { final STOPPING state = new STOPPING(); state.add(onCompleted); _serviceState = state; _stop(new Task() { public void run() { _serviceState = STOPPED; state.done(); } }); } else if (_serviceState instanceof STOPPING) { ((STOPPING) _serviceState).add(onCompleted); } else if (_serviceState == STOPPED) { if (onCompleted != null) { onCompleted.run(); } } else { if (onCompleted != null) { onCompleted.run(); } error("stop should not be called from state: " + _serviceState); } } }); } private void error(String msg) { try { throw new AssertionError(msg); } catch (Exception e) { e.printStackTrace(); } } protected State getServiceState() { return _serviceState; } abstract protected DispatchQueue getDispatchQueue(); abstract protected void _start(Task onCompleted); abstract protected void _stop(Task onCompleted); }SslProtocolCodec.java000066400000000000000000000347701227446104000431260ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-transport/src/main/java/org/fusesource/hawtdispatch/transport/** * Copyright (C) 2012 FuseSource, Inc. * http://fusesource.com * * Licensed 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.fusesource.hawtdispatch.transport; import org.fusesource.hawtdispatch.Task; import javax.net.ssl.*; import java.io.EOFException; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.GatheringByteChannel; import java.nio.channels.ReadableByteChannel; import java.nio.channels.ScatteringByteChannel; import java.nio.channels.WritableByteChannel; import java.security.cert.Certificate; import java.security.cert.X509Certificate; import java.util.ArrayList; import static javax.net.ssl.SSLEngineResult.HandshakeStatus.*; import static javax.net.ssl.SSLEngineResult.Status.BUFFER_OVERFLOW; /** * Implements the SSL protocol as a WrappingProtocolCodec. Useful for when * you want to switch to the SSL protocol on a regular TCP Transport. */ public class SslProtocolCodec implements WrappingProtocolCodec, SecuredSession { private ReadableByteChannel readChannel; private WritableByteChannel writeChannel; public enum ClientAuth { WANT, NEED, NONE }; private SSLContext sslContext; private SSLEngine engine; private ByteBuffer readBuffer; private boolean readUnderflow; private ByteBuffer writeBuffer; private boolean writeFlushing; private ByteBuffer readOverflowBuffer; Transport transport; int lastReadSize; int lastWriteSize; long readCounter; long writeCounter; ProtocolCodec next; public SslProtocolCodec() { } public ProtocolCodec getNext() { return next; } public void setNext(ProtocolCodec next) { this.next = next; initNext(); } private void initNext() { if( next!=null ) { this.next.setTransport(new TransportFilter(transport){ public ReadableByteChannel getReadChannel() { return sslReadChannel; } public WritableByteChannel getWriteChannel() { return sslWriteChannel; } }); } } public void setSSLContext(SSLContext ctx) { assert engine == null; this.sslContext = ctx; } public SslProtocolCodec client() throws Exception { initializeEngine(); engine.setUseClientMode(true); engine.beginHandshake(); return this; } public SslProtocolCodec server(ClientAuth clientAuth) throws Exception { initializeEngine(); engine.setUseClientMode(false); switch (clientAuth) { case WANT: engine.setWantClientAuth(true); break; case NEED: engine.setNeedClientAuth(true); break; case NONE: engine.setWantClientAuth(false); break; } engine.beginHandshake(); return this; } protected void initializeEngine() throws Exception { assert engine == null; if( sslContext == null ) { sslContext = SSLContext.getDefault(); } engine = sslContext.createSSLEngine(); SSLSession session = engine.getSession(); readBuffer = ByteBuffer.allocateDirect(session.getPacketBufferSize()); readBuffer.flip(); writeBuffer = ByteBuffer.allocateDirect(session.getPacketBufferSize()); } public SSLSession getSSLSession() { return engine==null ? null : engine.getSession(); } public X509Certificate[] getPeerX509Certificates() { if( engine==null ) { return null; } try { ArrayList rc = new ArrayList(); for( Certificate c:engine.getSession().getPeerCertificates() ) { if(c instanceof X509Certificate) { rc.add((X509Certificate) c); } } return rc.toArray(new X509Certificate[rc.size()]); } catch (SSLPeerUnverifiedException e) { return null; } } SSLReadChannel sslReadChannel = new SSLReadChannel(); SSLWriteChannel sslWriteChannel = new SSLWriteChannel(); public void setTransport(Transport transport) { this.transport = transport; this.readChannel = transport.getReadChannel(); this.writeChannel = transport.getWriteChannel(); initNext(); } public void handshake() throws IOException { if( !transportFlush() ) { return; } switch (engine.getHandshakeStatus()) { case NEED_TASK: final Runnable task = engine.getDelegatedTask(); if( task!=null ) { transport.getBlockingExecutor().execute(new Task() { public void run() { task.run(); transport.getDispatchQueue().execute(new Task() { public void run() { if (readChannel.isOpen() && writeChannel.isOpen()) { try { handshake(); } catch (IOException e) { transport.getTransportListener().onTransportFailure(e); } } } }); } }); } break; case NEED_WRAP: secure_write(ByteBuffer.allocate(0)); break; case NEED_UNWRAP: if( secure_read(ByteBuffer.allocate(0)) == -1) { throw new EOFException("Peer disconnected during ssl handshake"); } break; case FINISHED: case NOT_HANDSHAKING: transport.drainInbound(); transport.getTransportListener().onRefill(); break; default: System.err.println("Unexpected ssl engine handshake status: "+ engine.getHandshakeStatus()); break; } } /** * @return true if fully flushed. * @throws IOException */ protected boolean transportFlush() throws IOException { while (true) { if(writeFlushing) { lastWriteSize = writeChannel.write(writeBuffer); if( lastWriteSize > 0 ) { writeCounter += lastWriteSize; } if( !writeBuffer.hasRemaining() ) { writeBuffer.clear(); writeFlushing = false; return true; } else { return false; } } else { if( writeBuffer.position()!=0 ) { writeBuffer.flip(); writeFlushing = true; } else { return true; } } } } private int secure_read(ByteBuffer plain) throws IOException { int rc=0; while ( plain.hasRemaining() ^ engine.getHandshakeStatus() == NEED_UNWRAP ) { if( readOverflowBuffer !=null ) { if( plain.hasRemaining() ) { // lets drain the overflow buffer before trying to suck down anymore // network bytes. int size = Math.min(plain.remaining(), readOverflowBuffer.remaining()); plain.put(readOverflowBuffer.array(), readOverflowBuffer.position(), size); readOverflowBuffer.position(readOverflowBuffer.position()+size); if( !readOverflowBuffer.hasRemaining() ) { readOverflowBuffer = null; } rc += size; } else { return rc; } } else if( readUnderflow ) { lastReadSize = readChannel.read(readBuffer); if( lastReadSize == -1 ) { // peer closed socket. if (rc==0) { return -1; } else { return rc; } } if( lastReadSize==0 ) { // no data available right now. return rc; } readCounter += lastReadSize; // read in some more data, perhaps now we can unwrap. readUnderflow = false; readBuffer.flip(); } else { SSLEngineResult result = engine.unwrap(readBuffer, plain); rc += result.bytesProduced(); if( result.getStatus() == BUFFER_OVERFLOW ) { readOverflowBuffer = ByteBuffer.allocate(engine.getSession().getApplicationBufferSize()); result = engine.unwrap(readBuffer, readOverflowBuffer); if( readOverflowBuffer.position()==0 ) { readOverflowBuffer = null; } else { readOverflowBuffer.flip(); } } switch( result.getStatus() ) { case CLOSED: if (rc==0) { engine.closeInbound(); return -1; } else { return rc; } case OK: if ( engine.getHandshakeStatus()!=NOT_HANDSHAKING ) { handshake(); } break; case BUFFER_UNDERFLOW: readBuffer.compact(); readUnderflow = true; break; case BUFFER_OVERFLOW: throw new AssertionError("Unexpected case."); } } } return rc; } private int secure_write(ByteBuffer plain) throws IOException { if( !transportFlush() ) { // can't write anymore until the write_secured_buffer gets fully flushed out.. return 0; } int rc = 0; while ( plain.hasRemaining() ^ engine.getHandshakeStatus()==NEED_WRAP ) { SSLEngineResult result = engine.wrap(plain, writeBuffer); assert result.getStatus()!= BUFFER_OVERFLOW; rc += result.bytesConsumed(); if( !transportFlush() ) { break; } } if( plain.remaining()==0 && engine.getHandshakeStatus()!=NOT_HANDSHAKING ) { handshake(); } return rc; } public class SSLReadChannel implements ScatteringByteChannel { public int read(ByteBuffer plain) throws IOException { if ( engine.getHandshakeStatus()!=NOT_HANDSHAKING ) { handshake(); } return secure_read(plain); } public boolean isOpen() { return readChannel.isOpen(); } public void close() throws IOException { readChannel.close(); } public long read(ByteBuffer[] dsts, int offset, int length) throws IOException { if(offset+length > dsts.length || length<0 || offset<0) { throw new IndexOutOfBoundsException(); } long rc=0; for (int i = 0; i < length; i++) { ByteBuffer dst = dsts[offset+i]; if(dst.hasRemaining()) { rc += read(dst); } if( dst.hasRemaining() ) { return rc; } } return rc; } public long read(ByteBuffer[] dsts) throws IOException { return read(dsts, 0, dsts.length); } } public class SSLWriteChannel implements GatheringByteChannel { public int write(ByteBuffer plain) throws IOException { if ( engine.getHandshakeStatus()!=NOT_HANDSHAKING ) { handshake(); } return secure_write(plain); } public boolean isOpen() { return writeChannel.isOpen(); } public void close() throws IOException { writeChannel.close(); } public long write(ByteBuffer[] srcs, int offset, int length) throws IOException { if(offset+length > srcs.length || length<0 || offset<0) { throw new IndexOutOfBoundsException(); } long rc=0; for (int i = 0; i < length; i++) { ByteBuffer src = srcs[offset+i]; if(src.hasRemaining()) { rc += write(src); } if( src.hasRemaining() ) { return rc; } } return rc; } public long write(ByteBuffer[] srcs) throws IOException { return write(srcs, 0, srcs.length); } } public void unread(byte[] buffer) { readBuffer.compact(); if( readBuffer.remaining() < buffer.length) { throw new IllegalStateException("Cannot unread now"); } readBuffer.put(buffer); readBuffer.flip(); } public Object read() throws IOException { return next.read(); } public ProtocolCodec.BufferState write(Object value) throws IOException { return next.write(value); } public ProtocolCodec.BufferState flush() throws IOException { return next.flush(); } public boolean full() { return next.full(); } public long getWriteCounter() { return writeCounter; } public long getLastWriteSize() { return lastWriteSize; } public long getReadCounter() { return readCounter; } public long getLastReadSize() { return lastReadSize; } public int getReadBufferSize() { return readBuffer.capacity(); } public int getWriteBufferSize() { return writeBuffer.capacity(); } }SslTransport.java000066400000000000000000000376471227446104000423710ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-transport/src/main/java/org/fusesource/hawtdispatch/transport/** * Copyright (C) 2012 FuseSource, Inc. * http://fusesource.com * * Licensed 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.fusesource.hawtdispatch.transport; import org.fusesource.hawtdispatch.Task; import javax.net.ssl.*; import java.io.EOFException; import java.io.IOException; import java.net.Socket; import java.net.URI; import java.nio.ByteBuffer; import java.nio.channels.*; import java.security.cert.Certificate; import java.security.cert.X509Certificate; import java.util.ArrayList; import static javax.net.ssl.SSLEngineResult.HandshakeStatus.*; import static javax.net.ssl.SSLEngineResult.Status.*; /** * An SSL Transport for secure communications. * * @author Hiram Chirino */ public class SslTransport extends TcpTransport implements SecuredSession { /** * Maps uri schemes to a protocol algorithm names. * Valid algorithm names listed at: * http://download.oracle.com/javase/6/docs/technotes/guides/security/StandardNames.html#SSLContext */ public static String protocol(String scheme) { if( scheme.equals("tls") ) { return "TLS"; } else if( scheme.startsWith("tlsv") ) { return "TLSv"+scheme.substring(4); } else if( scheme.equals("ssl") ) { return "SSL"; } else if( scheme.startsWith("sslv") ) { return "SSLv"+scheme.substring(4); } return null; } enum ClientAuth { WANT, NEED, NONE }; private ClientAuth clientAuth = ClientAuth.WANT; private String disabledCypherSuites = null; private String enabledCipherSuites = null; private SSLContext sslContext; private SSLEngine engine; private ByteBuffer readBuffer; private boolean readUnderflow; private ByteBuffer writeBuffer; private boolean writeFlushing; private ByteBuffer readOverflowBuffer; private SSLChannel ssl_channel = new SSLChannel(); public void setSSLContext(SSLContext ctx) { this.sslContext = ctx; } /** * Allows subclasses of TcpTransportFactory to create custom instances of * TcpTransport. */ public static SslTransport createTransport(URI uri) throws Exception { String protocol = protocol(uri.getScheme()); if( protocol !=null ) { SslTransport rc = new SslTransport(); rc.setSSLContext(SSLContext.getInstance(protocol)); return rc; } return null; } public class SSLChannel implements ScatteringByteChannel, GatheringByteChannel { public int write(ByteBuffer plain) throws IOException { return secure_write(plain); } public int read(ByteBuffer plain) throws IOException { return secure_read(plain); } public boolean isOpen() { return getSocketChannel().isOpen(); } public void close() throws IOException { getSocketChannel().close(); } public long write(ByteBuffer[] srcs, int offset, int length) throws IOException { if(offset+length > srcs.length || length<0 || offset<0) { throw new IndexOutOfBoundsException(); } long rc=0; for (int i = 0; i < length; i++) { ByteBuffer src = srcs[offset+i]; if(src.hasRemaining()) { rc += write(src); } if( src.hasRemaining() ) { return rc; } } return rc; } public long write(ByteBuffer[] srcs) throws IOException { return write(srcs, 0, srcs.length); } public long read(ByteBuffer[] dsts, int offset, int length) throws IOException { if(offset+length > dsts.length || length<0 || offset<0) { throw new IndexOutOfBoundsException(); } long rc=0; for (int i = 0; i < length; i++) { ByteBuffer dst = dsts[offset+i]; if(dst.hasRemaining()) { rc += read(dst); } if( dst.hasRemaining() ) { return rc; } } return rc; } public long read(ByteBuffer[] dsts) throws IOException { return read(dsts, 0, dsts.length); } public Socket socket() { SocketChannel c = channel; if( c == null ) { return null; } return c.socket(); } } public SSLSession getSSLSession() { return engine==null ? null : engine.getSession(); } public X509Certificate[] getPeerX509Certificates() { if( engine==null ) { return null; } try { ArrayList rc = new ArrayList(); for( Certificate c:engine.getSession().getPeerCertificates() ) { if(c instanceof X509Certificate) { rc.add((X509Certificate) c); } } return rc.toArray(new X509Certificate[rc.size()]); } catch (SSLPeerUnverifiedException e) { return null; } } @Override public void connecting(URI remoteLocation, URI localLocation) throws Exception { assert engine == null; engine = sslContext.createSSLEngine(remoteLocation.getHost(), remoteLocation.getPort()); engine.setUseClientMode(true); super.connecting(remoteLocation, localLocation); } @Override public void connected(SocketChannel channel) throws Exception { if (engine == null) { engine = sslContext.createSSLEngine(); engine.setUseClientMode(false); switch (clientAuth) { case WANT: engine.setWantClientAuth(true); break; case NEED: engine.setNeedClientAuth(true); break; case NONE: engine.setWantClientAuth(false); break; } } if (enabledCipherSuites != null) { engine.setEnabledCipherSuites(splitOnCommas(enabledCipherSuites)); } else { engine.setEnabledCipherSuites(engine.getSupportedCipherSuites()); } if( disabledCypherSuites!=null ) { String[] disabledList = splitOnCommas(disabledCypherSuites); ArrayList enabled = new ArrayList(); for (String suite : engine.getEnabledCipherSuites()) { boolean add = true; for (String disabled : disabledList) { if( suite.contains(disabled) ) { add = false; break; } } if( add ) { enabled.add(suite); } } engine.setEnabledCipherSuites(enabled.toArray(new String[enabled.size()])); } super.connected(channel); } private String[] splitOnCommas(String value) { ArrayList rc = new ArrayList(); for( String x : value.split(",") ) { rc.add(x.trim()); } return rc.toArray(new String[rc.size()]); } @Override protected void initializeChannel() throws Exception { super.initializeChannel(); SSLSession session = engine.getSession(); readBuffer = ByteBuffer.allocateDirect(session.getPacketBufferSize()); readBuffer.flip(); writeBuffer = ByteBuffer.allocateDirect(session.getPacketBufferSize()); } @Override protected void onConnected() throws IOException { super.onConnected(); engine.beginHandshake(); handshake(); } @Override public void flush() { if ( engine.getHandshakeStatus()!=NOT_HANDSHAKING ) { handshake(); } else { super.flush(); } } @Override public void drainInbound() { if ( engine.getHandshakeStatus()!=NOT_HANDSHAKING ) { handshake(); } else { super.drainInbound(); } } /** * @return true if fully flushed. * @throws IOException */ protected boolean transportFlush() throws IOException { while (true) { if(writeFlushing) { int count = super.getWriteChannel().write(writeBuffer); if( !writeBuffer.hasRemaining() ) { writeBuffer.clear(); writeFlushing = false; suspendWrite(); return true; } else { return false; } } else { if( writeBuffer.position()!=0 ) { writeBuffer.flip(); writeFlushing = true; resumeWrite(); } else { return true; } } } } private int secure_write(ByteBuffer plain) throws IOException { if( !transportFlush() ) { // can't write anymore until the write_secured_buffer gets fully flushed out.. return 0; } int rc = 0; while ( plain.hasRemaining() ^ engine.getHandshakeStatus()==NEED_WRAP ) { SSLEngineResult result = engine.wrap(plain, writeBuffer); assert result.getStatus()!= BUFFER_OVERFLOW; rc += result.bytesConsumed(); if( !transportFlush() || result.getStatus() == CLOSED) { break; } } if( plain.remaining()==0 && engine.getHandshakeStatus()!=NOT_HANDSHAKING ) { dispatchQueue.execute(new Task() { public void run() { handshake(); } }); } return rc; } private int secure_read(ByteBuffer plain) throws IOException { int rc=0; while ( plain.hasRemaining() ^ engine.getHandshakeStatus() == NEED_UNWRAP ) { if( readOverflowBuffer !=null ) { if( plain.hasRemaining() ) { // lets drain the overflow buffer before trying to suck down anymore // network bytes. int size = Math.min(plain.remaining(), readOverflowBuffer.remaining()); plain.put(readOverflowBuffer.array(), readOverflowBuffer.position(), size); readOverflowBuffer.position(readOverflowBuffer.position()+size); if( !readOverflowBuffer.hasRemaining() ) { readOverflowBuffer = null; } rc += size; } else { return rc; } } else if( readUnderflow ) { int count = super.getReadChannel().read(readBuffer); if( count == -1 ) { // peer closed socket. if (rc==0) { return -1; } else { return rc; } } if( count==0 ) { // no data available right now. return rc; } // read in some more data, perhaps now we can unwrap. readUnderflow = false; readBuffer.flip(); } else { SSLEngineResult result = engine.unwrap(readBuffer, plain); rc += result.bytesProduced(); if( result.getStatus() == BUFFER_OVERFLOW ) { readOverflowBuffer = ByteBuffer.allocate(engine.getSession().getApplicationBufferSize()); result = engine.unwrap(readBuffer, readOverflowBuffer); if( readOverflowBuffer.position()==0 ) { readOverflowBuffer = null; } else { readOverflowBuffer.flip(); } } switch( result.getStatus() ) { case CLOSED: if (rc==0) { engine.closeInbound(); return -1; } else { return rc; } case OK: if ( engine.getHandshakeStatus()!=NOT_HANDSHAKING ) { dispatchQueue.execute(new Task() { public void run() { handshake(); } }); } break; case BUFFER_UNDERFLOW: readBuffer.compact(); readUnderflow = true; break; case BUFFER_OVERFLOW: throw new AssertionError("Unexpected case."); } } } return rc; } public void handshake() { try { if( !transportFlush() ) { return; } switch (engine.getHandshakeStatus()) { case NEED_TASK: final Runnable task = engine.getDelegatedTask(); if( task!=null ) { blockingExecutor.execute(new Task() { public void run() { task.run(); dispatchQueue.execute(new Task() { public void run() { if (isConnected()) { handshake(); } } }); } }); } break; case NEED_WRAP: secure_write(ByteBuffer.allocate(0)); break; case NEED_UNWRAP: if( secure_read(ByteBuffer.allocate(0)) == -1) { throw new EOFException("Peer disconnected during ssl handshake"); } break; case FINISHED: case NOT_HANDSHAKING: break; default: System.err.println("Unexpected ssl engine handshake status: "+ engine.getHandshakeStatus()); break; } } catch (IOException e ) { onTransportFailure(e); } finally { if( engine.getHandshakeStatus() == NOT_HANDSHAKING ) { drainOutboundSource.merge(1); super.drainInbound(); } } } public ReadableByteChannel getReadChannel() { return ssl_channel; } public WritableByteChannel getWriteChannel() { return ssl_channel; } public String getClientAuth() { return clientAuth.name(); } public void setClientAuth(String clientAuth) { this.clientAuth = ClientAuth.valueOf(clientAuth.toUpperCase()); } public String getDisabledCypherSuites() { return disabledCypherSuites; } public String getEnabledCypherSuites() { return enabledCipherSuites; } public void setDisabledCypherSuites(String disabledCypherSuites) { this.disabledCypherSuites = disabledCypherSuites; } public void setEnabledCypherSuites(String enabledCypherSuites) { this.enabledCipherSuites = enabledCypherSuites; } } SslTransportServer.java000066400000000000000000000062061227446104000435430ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-transport/src/main/java/org/fusesource/hawtdispatch/transport/** * Copyright (C) 2012 FuseSource, Inc. * http://fusesource.com * * Licensed 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.fusesource.hawtdispatch.transport; import org.fusesource.hawtdispatch.Task; import javax.net.ssl.KeyManager; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; import java.net.URI; import java.security.NoSuchAlgorithmException; /** * @author Hiram Chirino */ public class SslTransportServer extends TcpTransportServer { public static SslTransportServer createTransportServer(URI uri) throws Exception { return new SslTransportServer(uri); } protected KeyManager[] keyManagers; private TrustManager[] trustManagers; protected String protocol = "TLS"; protected SSLContext sslContext; private String clientAuth = "want"; private String disabledCypherSuites = null; public SslTransportServer(URI location) throws Exception { super(location); setSSLContext(SSLContext.getInstance(SslTransport.protocol(location.getScheme()))); } public void setKeyManagers(KeyManager[] keyManagers) { this.keyManagers = keyManagers; } public void setTrustManagers(TrustManager[] trustManagers) { this.trustManagers = trustManagers; } public void start(Task onCompleted) throws Exception { if( keyManagers!=null ) { sslContext.init(keyManagers, trustManagers, null); } else { sslContext = SSLContext.getDefault(); } super.start(onCompleted); } protected TcpTransport createTransport() { SslTransport rc = new SslTransport(); rc.setDispatchQueue(dispatchQueue); rc.setBlockingExecutor(blockingExecutor); rc.setSSLContext(sslContext); rc.setClientAuth(clientAuth); rc.setDisabledCypherSuites(disabledCypherSuites); return rc; } public SslTransportServer protocol(String value) throws NoSuchAlgorithmException { this.protocol = value; sslContext = SSLContext.getInstance(protocol); return this; } public SSLContext getSSLContext() { return sslContext; } public void setSSLContext(SSLContext sslContext) { this.sslContext = sslContext; } public String getClientAuth() { return clientAuth; } public void setClientAuth(String clientAuth) { this.clientAuth = clientAuth; } public String getDisabledCypherSuites() { return disabledCypherSuites; } public void setDisabledCypherSuites(String disabledCypherSuites) { this.disabledCypherSuites = disabledCypherSuites; } } TcpTransport.java000066400000000000000000000715741227446104000423530ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-transport/src/main/java/org/fusesource/hawtdispatch/transport/** * Copyright (C) 2012 FuseSource, Inc. * http://fusesource.com * * Licensed 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.fusesource.hawtdispatch.transport; import org.fusesource.hawtdispatch.*; import org.fusesource.hawtdispatch.internal.BaseSuspendable; import java.io.IOException; import java.net.*; import java.nio.ByteBuffer; import java.nio.channels.*; import java.util.LinkedList; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; /** * An implementation of the {@link org.fusesource.hawtdispatch.transport.Transport} interface using raw tcp/ip * * @author Hiram Chirino */ public class TcpTransport extends ServiceBase implements Transport { static InetAddress localhost; synchronized static public InetAddress getLocalHost() throws UnknownHostException { // cache it... if( localhost==null ) { // this can be slow on some systems and we use repeatedly. localhost = InetAddress.getLocalHost(); } return localhost; } abstract static class SocketState { void onStop(Task onCompleted) { } void onCanceled() { } boolean is(Class clazz) { return getClass()==clazz; } } static class DISCONNECTED extends SocketState{} class CONNECTING extends SocketState{ void onStop(Task onCompleted) { trace("CONNECTING.onStop"); CANCELING state = new CANCELING(); socketState = state; state.onStop(onCompleted); } void onCanceled() { trace("CONNECTING.onCanceled"); CANCELING state = new CANCELING(); socketState = state; state.onCanceled(); } } class CONNECTED extends SocketState { public CONNECTED() { localAddress = channel.socket().getLocalSocketAddress(); remoteAddress = channel.socket().getRemoteSocketAddress(); } void onStop(Task onCompleted) { trace("CONNECTED.onStop"); CANCELING state = new CANCELING(); socketState = state; state.add(createDisconnectTask()); state.onStop(onCompleted); } void onCanceled() { trace("CONNECTED.onCanceled"); CANCELING state = new CANCELING(); socketState = state; state.add(createDisconnectTask()); state.onCanceled(); } Task createDisconnectTask() { return new Task(){ public void run() { listener.onTransportDisconnected(); } }; } } class CANCELING extends SocketState { private LinkedList runnables = new LinkedList(); private int remaining; private boolean dispose; public CANCELING() { if( readSource!=null ) { remaining++; readSource.cancel(); } if( writeSource!=null ) { remaining++; writeSource.cancel(); } } void onStop(Task onCompleted) { trace("CANCELING.onCompleted"); add(onCompleted); dispose = true; } void add(Task onCompleted) { if( onCompleted!=null ) { runnables.add(onCompleted); } } void onCanceled() { trace("CANCELING.onCanceled"); remaining--; if( remaining!=0 ) { return; } try { if( closeOnCancel ) { channel.close(); } } catch (IOException ignore) { } socketState = new CANCELED(dispose); for (Task runnable : runnables) { runnable.run(); } if (dispose) { dispose(); } } } class CANCELED extends SocketState { private boolean disposed; public CANCELED(boolean disposed) { this.disposed=disposed; } void onStop(Task onCompleted) { trace("CANCELED.onStop"); if( !disposed ) { disposed = true; dispose(); } onCompleted.run(); } } protected URI remoteLocation; protected URI localLocation; protected TransportListener listener; protected ProtocolCodec codec; protected SocketChannel channel; protected SocketState socketState = new DISCONNECTED(); protected DispatchQueue dispatchQueue; private DispatchSource readSource; private DispatchSource writeSource; protected CustomDispatchSource drainOutboundSource; protected CustomDispatchSource yieldSource; protected boolean useLocalHost = true; int maxReadRate; int maxWriteRate; int receiveBufferSize = 1024*64; int sendBufferSize = 1024*64; boolean closeOnCancel = true; boolean keepAlive = true; public static final int IPTOS_LOWCOST = 0x02; public static final int IPTOS_RELIABILITY = 0x04; public static final int IPTOS_THROUGHPUT = 0x08; public static final int IPTOS_LOWDELAY = 0x10; int trafficClass = IPTOS_THROUGHPUT; protected RateLimitingChannel rateLimitingChannel; SocketAddress localAddress; SocketAddress remoteAddress; protected Executor blockingExecutor; class RateLimitingChannel implements ScatteringByteChannel, GatheringByteChannel { int read_allowance = maxReadRate; boolean read_suspended = false; // int read_resume_counter = 0; int write_allowance = maxWriteRate; boolean write_suspended = false; public void resetAllowance() { if( read_allowance != maxReadRate || write_allowance != maxWriteRate) { read_allowance = maxReadRate; write_allowance = maxWriteRate; if( write_suspended ) { write_suspended = false; resumeWrite(); } if( read_suspended ) { read_suspended = false; resumeRead(); } } } public int read(ByteBuffer dst) throws IOException { if( maxReadRate ==0 ) { return channel.read(dst); } else { int rc=0; int reduction = 0; try { int remaining = dst.remaining(); if( read_allowance ==0 || remaining ==0 ) { return 0; } if( remaining > read_allowance) { reduction = remaining - read_allowance; dst.limit(dst.limit() - reduction); } rc = channel.read(dst); read_allowance -= rc; } finally { if( read_allowance<=0 && !read_suspended ) { // we need to suspend the read now until we get // a new allowance.. readSource.suspend(); read_suspended = true; } if( reduction!=0 ) { dst.limit(dst.limit() + reduction); } } return rc; } } public int write(ByteBuffer src) throws IOException { if( maxWriteRate ==0 ) { return channel.write(src); } else { int remaining = src.remaining(); if( write_allowance ==0 || remaining ==0 ) { return 0; } int reduction = 0; if( remaining > write_allowance) { reduction = remaining - write_allowance; src.limit(src.limit() - reduction); } int rc = 0; try { rc = channel.write(src); write_allowance -= rc; } finally { if( reduction!=0 ) { if( src.remaining() == 0 ) { // we need to suspend the read now until we get // a new allowance.. write_suspended = true; suspendWrite(); } src.limit(src.limit() + reduction); } } return rc; } } public boolean isOpen() { return channel.isOpen(); } public void close() throws IOException { channel.close(); } public void resumeRead() { // if( read_suspended ) { // read_resume_counter += 1; // } else { _resumeRead(); // } } public long read(ByteBuffer[] dsts, int offset, int length) throws IOException { if(offset+length > dsts.length || length<0 || offset<0) { throw new IndexOutOfBoundsException(); } long rc=0; for (int i = 0; i < length; i++) { ByteBuffer dst = dsts[offset+i]; if(dst.hasRemaining()) { rc += read(dst); } if( dst.hasRemaining() ) { return rc; } } return rc; } public long read(ByteBuffer[] dsts) throws IOException { return read(dsts, 0, dsts.length); } public long write(ByteBuffer[] srcs, int offset, int length) throws IOException { if(offset+length > srcs.length || length<0 || offset<0) { throw new IndexOutOfBoundsException(); } long rc=0; for (int i = 0; i < length; i++) { ByteBuffer src = srcs[offset+i]; if(src.hasRemaining()) { rc += write(src); } if( src.hasRemaining() ) { return rc; } } return rc; } public long write(ByteBuffer[] srcs) throws IOException { return write(srcs, 0, srcs.length); } } private final Task CANCEL_HANDLER = new Task() { public void run() { socketState.onCanceled(); } }; static final class OneWay { final Object command; final Retained retained; public OneWay(Object command, Retained retained) { this.command = command; this.retained = retained; } } public void connected(SocketChannel channel) throws IOException, Exception { this.channel = channel; initializeChannel(); this.socketState = new CONNECTED(); } protected void initializeChannel() throws Exception { this.channel.configureBlocking(false); Socket socket = channel.socket(); try { socket.setReuseAddress(true); } catch (SocketException e) { } try { socket.setSoLinger(true, 0); } catch (SocketException e) { } try { socket.setTrafficClass(trafficClass); } catch (SocketException e) { } try { socket.setKeepAlive(keepAlive); } catch (SocketException e) { } try { socket.setTcpNoDelay(true); } catch (SocketException e) { } try { socket.setReceiveBufferSize(receiveBufferSize); } catch (SocketException e) { } try { socket.setSendBufferSize(sendBufferSize); } catch (SocketException e) { } if( channel!=null && codec!=null ) { initializeCodec(); } } protected void initializeCodec() throws Exception { codec.setTransport(this); } private void initRateLimitingChannel() { if( (maxReadRate !=0 || maxWriteRate !=0) && rateLimitingChannel==null ) { rateLimitingChannel = new RateLimitingChannel(); } } public void connecting(final URI remoteLocation, final URI localLocation) throws Exception { this.channel = SocketChannel.open(); initializeChannel(); this.remoteLocation = remoteLocation; this.localLocation = localLocation; socketState = new CONNECTING(); } public DispatchQueue getDispatchQueue() { return dispatchQueue; } public void setDispatchQueue(DispatchQueue queue) { this.dispatchQueue = queue; if(readSource!=null) readSource.setTargetQueue(queue); if(writeSource!=null) writeSource.setTargetQueue(queue); if(drainOutboundSource!=null) drainOutboundSource.setTargetQueue(queue); if(yieldSource!=null) yieldSource.setTargetQueue(queue); } public void _start(Task onCompleted) { try { if (socketState.is(CONNECTING.class)) { // Resolving host names might block.. so do it on the blocking executor. this.blockingExecutor.execute(new Runnable() { public void run() { try { final InetSocketAddress localAddress = (localLocation != null) ? new InetSocketAddress(InetAddress.getByName(localLocation.getHost()), localLocation.getPort()) : null; String host = resolveHostName(remoteLocation.getHost()); final InetSocketAddress remoteAddress = new InetSocketAddress(host, remoteLocation.getPort()); // Done resolving.. switch back to the dispatch queue. dispatchQueue.execute(new Task() { @Override public void run() { // No need to complete if we have been canceled. if( ! socketState.is(CONNECTING.class) ) { return; } try { if (localAddress != null) { channel.socket().bind(localAddress); } trace("connecting..."); channel.connect(remoteAddress); // this allows the connect to complete.. readSource = Dispatch.createSource(channel, SelectionKey.OP_CONNECT, dispatchQueue); readSource.setEventHandler(new Task() { public void run() { if (getServiceState() != STARTED) { return; } try { trace("connected."); channel.finishConnect(); readSource.setCancelHandler(null); readSource.cancel(); readSource = null; socketState = new CONNECTED(); onConnected(); } catch (IOException e) { onTransportFailure(e); } } }); readSource.setCancelHandler(CANCEL_HANDLER); readSource.resume(); } catch (Exception e) { try { channel.close(); } catch (Exception ignore) { } socketState = new CANCELED(true); if (! (e instanceof IOException)) { e = new IOException(e); } listener.onTransportFailure((IOException)e); } } }); } catch (final IOException e) { // we're in blockingExecutor thread context here dispatchQueue.execute(new Task() { public void run() { try { channel.close(); } catch (IOException ignore) { } socketState = new CANCELED(true); listener.onTransportFailure(e); } }); } } }); } else if (socketState.is(CONNECTED.class)) { dispatchQueue.execute(new Task() { public void run() { try { trace("was connected."); onConnected(); } catch (IOException e) { onTransportFailure(e); } } }); } else { trace("cannot be started. socket state is: " + socketState); } } finally { if (onCompleted != null) { onCompleted.run(); } } } public void _stop(final Task onCompleted) { trace("stopping.. at state: "+socketState); socketState.onStop(onCompleted); } protected String resolveHostName(String host) throws UnknownHostException { if (isUseLocalHost()) { String localName = getLocalHost().getHostName(); if (localName != null && localName.equals(host)) { return "localhost"; } } return host; } protected void onConnected() throws IOException { yieldSource = Dispatch.createSource(EventAggregators.INTEGER_ADD, dispatchQueue); yieldSource.setEventHandler(new Task() { public void run() { drainInbound(); } }); yieldSource.resume(); drainOutboundSource = Dispatch.createSource(EventAggregators.INTEGER_ADD, dispatchQueue); drainOutboundSource.setEventHandler(new Task() { public void run() { flush(); } }); drainOutboundSource.resume(); readSource = Dispatch.createSource(channel, SelectionKey.OP_READ, dispatchQueue); writeSource = Dispatch.createSource(channel, SelectionKey.OP_WRITE, dispatchQueue); readSource.setCancelHandler(CANCEL_HANDLER); writeSource.setCancelHandler(CANCEL_HANDLER); readSource.setEventHandler(new Task() { public void run() { drainInbound(); } }); writeSource.setEventHandler(new Task() { public void run() { flush(); } }); initRateLimitingChannel(); if( rateLimitingChannel!=null ) { schedualRateAllowanceReset(); } listener.onTransportConnected(); } private void schedualRateAllowanceReset() { dispatchQueue.executeAfter(1, TimeUnit.SECONDS, new Task(){ public void run() { if( !socketState.is(CONNECTED.class) ) { return; } rateLimitingChannel.resetAllowance(); schedualRateAllowanceReset(); } }); } private void dispose() { if( readSource!=null ) { readSource.cancel(); readSource=null; } if( writeSource!=null ) { writeSource.cancel(); writeSource=null; } } public void onTransportFailure(IOException error) { listener.onTransportFailure(error); // socketState.onCanceled(); } public boolean full() { return codec==null || codec.full() || !socketState.is(CONNECTED.class) || getServiceState() != STARTED; } boolean rejectingOffers; public boolean offer(Object command) { dispatchQueue.assertExecuting(); if( full() ) { return false; } try { ProtocolCodec.BufferState rc = codec.write(command); rejectingOffers = codec.full(); switch (rc ) { case FULL: return false; default: drainOutboundSource.merge(1); } } catch (IOException e) { onTransportFailure(e); } return true; } boolean writeResumedForCodecFlush = false; /** * */ public void flush() { dispatchQueue.assertExecuting(); if (getServiceState() != STARTED || !socketState.is(CONNECTED.class)) { return; } try { if( codec.flush() == ProtocolCodec.BufferState.EMPTY && transportFlush() ) { if( writeResumedForCodecFlush) { writeResumedForCodecFlush = false; suspendWrite(); } rejectingOffers = false; listener.onRefill(); } else { if(!writeResumedForCodecFlush) { writeResumedForCodecFlush = true; resumeWrite(); } } } catch (IOException e) { onTransportFailure(e); } } protected boolean transportFlush() throws IOException { return true; } public void drainInbound() { if (!getServiceState().isStarted() || readSource.isSuspended()) { return; } try { long initial = codec.getReadCounter(); // Only process upto 2 x the read buffer worth of data at a time so we can give // other connections a chance to process their requests. while( codec.getReadCounter()-initial < codec.getReadBufferSize()<<2 ) { Object command = codec.read(); if ( command!=null ) { try { listener.onTransportCommand(command); } catch (Throwable e) { e.printStackTrace(); onTransportFailure(new IOException("Transport listener failure.")); } // the transport may be suspended after processing a command. if (getServiceState() == STOPPED || readSource.isSuspended()) { return; } } else { return; } } yieldSource.merge(1); } catch (IOException e) { onTransportFailure(e); } } public SocketAddress getLocalAddress() { return localAddress; } public SocketAddress getRemoteAddress() { return remoteAddress; } private boolean assertConnected() { try { if ( !isConnected() ) { throw new IOException("Not connected."); } return true; } catch (IOException e) { onTransportFailure(e); } return false; } public void suspendRead() { if( isConnected() && readSource!=null ) { readSource.suspend(); } } public void resumeRead() { if( isConnected() && readSource!=null ) { if( rateLimitingChannel!=null ) { rateLimitingChannel.resumeRead(); } else { _resumeRead(); } } } private void _resumeRead() { readSource.resume(); dispatchQueue.execute(new Task(){ public void run() { drainInbound(); } }); } protected void suspendWrite() { if( isConnected() && writeSource!=null ) { writeSource.suspend(); } } protected void resumeWrite() { if( isConnected() && writeSource!=null ) { writeSource.resume(); } } public TransportListener getTransportListener() { return listener; } public void setTransportListener(TransportListener transportListener) { this.listener = transportListener; } public ProtocolCodec getProtocolCodec() { return codec; } public void setProtocolCodec(ProtocolCodec protocolCodec) throws Exception { this.codec = protocolCodec; if( channel!=null && codec!=null ) { initializeCodec(); } } public boolean isConnected() { return socketState.is(CONNECTED.class); } public boolean isClosed() { return getServiceState() == STOPPED; } public boolean isUseLocalHost() { return useLocalHost; } /** * Sets whether 'localhost' or the actual local host name should be used to * make local connections. On some operating systems such as Macs its not * possible to connect as the local host name so localhost is better. */ public void setUseLocalHost(boolean useLocalHost) { this.useLocalHost = useLocalHost; } private void trace(String message) { // TODO: } public SocketChannel getSocketChannel() { return channel; } public ReadableByteChannel getReadChannel() { initRateLimitingChannel(); if(rateLimitingChannel!=null) { return rateLimitingChannel; } else { return channel; } } public WritableByteChannel getWriteChannel() { initRateLimitingChannel(); if(rateLimitingChannel!=null) { return rateLimitingChannel; } else { return channel; } } public int getMaxReadRate() { return maxReadRate; } public void setMaxReadRate(int maxReadRate) { this.maxReadRate = maxReadRate; } public int getMaxWriteRate() { return maxWriteRate; } public void setMaxWriteRate(int maxWriteRate) { this.maxWriteRate = maxWriteRate; } public int getTrafficClass() { return trafficClass; } public void setTrafficClass(int trafficClass) { this.trafficClass = trafficClass; } public int getReceiveBufferSize() { return receiveBufferSize; } public void setReceiveBufferSize(int receiveBufferSize) { this.receiveBufferSize = receiveBufferSize; if( channel!=null ) { try { channel.socket().setReceiveBufferSize(receiveBufferSize); } catch (SocketException ignore) { } } } public int getSendBufferSize() { return sendBufferSize; } public void setSendBufferSize(int sendBufferSize) { this.sendBufferSize = sendBufferSize; if( channel!=null ) { try { channel.socket().setReceiveBufferSize(sendBufferSize); } catch (SocketException ignore) { } } } public boolean isKeepAlive() { return keepAlive; } public void setKeepAlive(boolean keepAlive) { this.keepAlive = keepAlive; } public Executor getBlockingExecutor() { return blockingExecutor; } public void setBlockingExecutor(Executor blockingExecutor) { this.blockingExecutor = blockingExecutor; } public boolean isCloseOnCancel() { return closeOnCancel; } public void setCloseOnCancel(boolean closeOnCancel) { this.closeOnCancel = closeOnCancel; } } TcpTransportServer.java000066400000000000000000000152161227446104000435310ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-transport/src/main/java/org/fusesource/hawtdispatch/transport/** * Copyright (C) 2012 FuseSource, Inc. * http://fusesource.com * * Licensed 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.fusesource.hawtdispatch.transport; import org.fusesource.hawtdispatch.*; import java.io.IOException; import java.net.*; import java.nio.channels.SelectionKey; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.util.concurrent.Executor; /** * A TCP based implementation of {@link TransportServer} * * @author Hiram Chirino */ public class TcpTransportServer implements TransportServer { protected final String bindScheme; protected final InetSocketAddress bindAddress; protected int backlog = 100; protected ServerSocketChannel channel; protected TransportServerListener listener; protected DispatchQueue dispatchQueue; protected DispatchSource acceptSource; protected int receiveBufferSize = 64*1024; protected int sendBufferSize = 64*1024; protected Executor blockingExecutor; public TcpTransportServer(URI location) throws UnknownHostException { bindScheme = location.getScheme(); String host = location.getHost(); host = (host == null || host.length() == 0) ? "::" : host; bindAddress = new InetSocketAddress(InetAddress.getByName(host), location.getPort()); } public void setTransportServerListener(TransportServerListener listener) { this.listener = listener; } public InetSocketAddress getSocketAddress() { return (InetSocketAddress) channel.socket().getLocalSocketAddress(); } public DispatchQueue getDispatchQueue() { return dispatchQueue; } public void setDispatchQueue(DispatchQueue dispatchQueue) { this.dispatchQueue = dispatchQueue; } public void suspend() { acceptSource.suspend(); } public void resume() { acceptSource.resume(); } @Deprecated public void start(Runnable onCompleted) throws Exception { start(new TaskWrapper(onCompleted)); } @Deprecated public void stop(Runnable onCompleted) throws Exception { stop(new TaskWrapper(onCompleted)); } public void start(Task onCompleted) throws Exception { try { channel = ServerSocketChannel.open(); channel.configureBlocking(false); try { channel.socket().setReceiveBufferSize(receiveBufferSize); } catch (SocketException ignore) { } try { channel.socket().setReceiveBufferSize(sendBufferSize); } catch (SocketException ignore) { } channel.socket().bind(bindAddress, backlog); } catch (IOException e) { throw new IOException("Failed to bind to server socket: " + bindAddress + " due to: " + e); } acceptSource = Dispatch.createSource(channel, SelectionKey.OP_ACCEPT, dispatchQueue); acceptSource.setEventHandler(new Task() { public void run() { try { SocketChannel client = channel.accept(); while( client!=null ) { handleSocket(client); client = channel.accept(); } } catch (Exception e) { listener.onAcceptError(e); } } }); acceptSource.setCancelHandler(new Task() { public void run() { try { channel.close(); } catch (IOException e) { } } }); acceptSource.resume(); if( onCompleted!=null ) { dispatchQueue.execute(onCompleted); } } public String getBoundAddress() { try { return new URI(bindScheme, null, bindAddress.getAddress().getHostAddress(), channel.socket().getLocalPort(), null, null, null).toString(); } catch (URISyntaxException e) { throw new RuntimeException(e); } } public void stop(final Task onCompleted) throws Exception { if( acceptSource.isCanceled() ) { onCompleted.run(); } else { acceptSource.setCancelHandler(new Task() { public void run() { try { channel.close(); } catch (IOException e) { } onCompleted.run(); } }); acceptSource.cancel(); } } public int getBacklog() { return backlog; } public void setBacklog(int backlog) { this.backlog = backlog; } protected final void handleSocket(SocketChannel socket) throws Exception { TcpTransport transport = createTransport(); transport.connected(socket); listener.onAccept(transport); } protected TcpTransport createTransport() { final TcpTransport rc = new TcpTransport(); rc.setBlockingExecutor(blockingExecutor); rc.setDispatchQueue(dispatchQueue); return rc; } /** * @return pretty print of this */ public String toString() { return getBoundAddress(); } public int getReceiveBufferSize() { return receiveBufferSize; } public void setReceiveBufferSize(int receiveBufferSize) { this.receiveBufferSize = receiveBufferSize; if( channel!=null ) { try { channel.socket().setReceiveBufferSize(receiveBufferSize); } catch (SocketException ignore) { } } } public int getSendBufferSize() { return sendBufferSize; } public void setSendBufferSize(int sendBufferSize) { this.sendBufferSize = sendBufferSize; if( channel!=null ) { try { channel.socket().setReceiveBufferSize(sendBufferSize); } catch (SocketException ignore) { } } } public Executor getBlockingExecutor() { return blockingExecutor; } public void setBlockingExecutor(Executor blockingExecutor) { this.blockingExecutor = blockingExecutor; } }Transport.java000066400000000000000000000101141227446104000416630ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-transport/src/main/java/org/fusesource/hawtdispatch/transport/** * Copyright (C) 2012 FuseSource, Inc. * http://fusesource.com * * Licensed 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.fusesource.hawtdispatch.transport; import java.io.IOException; import java.net.SocketAddress; import java.net.URI; import java.nio.channels.ReadableByteChannel; import java.nio.channels.WritableByteChannel; import java.util.concurrent.Executor; import org.fusesource.hawtdispatch.DispatchQueue; import org.fusesource.hawtdispatch.Task; /** * Represents an abstract connection. It can be a client side or server side connection. * * @author Hiram Chirino */ public interface Transport { /** * Starts the service. Executes the onComplete runnable once the service has fully started up. * * @param onComplete my be set to null if not interested in a callback. */ void start(Runnable onComplete); /** * Stops the service. Executes the onComplete runnable once the service has fully stopped. * * @param onComplete my be set to null if not interested in a callback. */ void stop(Runnable onComplete); /** * Starts the service. Executes the onComplete runnable once the service has fully started up. * * @param onComplete my be set to null if not interested in a callback. */ void start(Task onComplete); /** * Stops the service. Executes the onComplete runnable once the service has fully stopped. * * @param onComplete my be set to null if not interested in a callback. */ void stop(Task onComplete); boolean full(); /** * A one way asynchronous send of a command. Only sent if the the transport is not full. * * @param command * @return true if the command was accepted. */ boolean offer(Object command); /** * Forces a flush of any output buffers. Once the flush completes the listener's * 'onRefill()' method will execute. */ public void flush(); /** * Returns the current transport listener * * @return */ TransportListener getTransportListener(); /** * Registers an inbound command listener * * @param transportListener */ void setTransportListener(TransportListener transportListener); /** * Returns the dispatch queue used by the transport * * @return */ DispatchQueue getDispatchQueue(); /** * Sets the dispatch queue used by the transport * * @param queue */ void setDispatchQueue(DispatchQueue queue); /** * suspend delivery of commands. */ void suspendRead(); /** * resume delivery of commands. */ void resumeRead(); /** * @return the remote address for this connection */ SocketAddress getRemoteAddress(); /** * @return the remote address for this connection */ SocketAddress getLocalAddress(); public void drainInbound(); /** * @return true if the transport is closed/stopped. */ boolean isClosed(); /** * @return true if the transport is connected */ boolean isConnected(); /** * @return The protocol codec for the transport. */ ProtocolCodec getProtocolCodec(); /** * Sets the protocol codec for the transport * @param protocolCodec */ void setProtocolCodec(ProtocolCodec protocolCodec) throws Exception; public Executor getBlockingExecutor(); public void setBlockingExecutor(Executor blockingExecutor); ReadableByteChannel getReadChannel(); WritableByteChannel getWriteChannel(); } TransportFilter.java000066400000000000000000000062401227446104000430360ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-transport/src/main/java/org/fusesource/hawtdispatch/transport/** * Copyright (C) 2012 FuseSource, Inc. * http://fusesource.com * * Licensed 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.fusesource.hawtdispatch.transport; import org.fusesource.hawtdispatch.DispatchQueue; import org.fusesource.hawtdispatch.Task; import java.net.SocketAddress; import java.nio.channels.ReadableByteChannel; import java.nio.channels.WritableByteChannel; import java.util.concurrent.Executor; /** */ public class TransportFilter implements Transport { final Transport next; public TransportFilter(Transport next) { this.next = next; } public void flush() { next.flush(); } public boolean full() { return next.full(); } public Executor getBlockingExecutor() { return next.getBlockingExecutor(); } public DispatchQueue getDispatchQueue() { return next.getDispatchQueue(); } public SocketAddress getLocalAddress() { return next.getLocalAddress(); } public ProtocolCodec getProtocolCodec() { return next.getProtocolCodec(); } public ReadableByteChannel getReadChannel() { return next.getReadChannel(); } public SocketAddress getRemoteAddress() { return next.getRemoteAddress(); } public TransportListener getTransportListener() { return next.getTransportListener(); } public WritableByteChannel getWriteChannel() { return next.getWriteChannel(); } public boolean isClosed() { return next.isClosed(); } public boolean isConnected() { return next.isConnected(); } public boolean offer(Object command) { return next.offer(command); } public void resumeRead() { next.resumeRead(); } public void setBlockingExecutor(Executor blockingExecutor) { next.setBlockingExecutor(blockingExecutor); } public void setDispatchQueue(DispatchQueue queue) { next.setDispatchQueue(queue); } public void setProtocolCodec(ProtocolCodec protocolCodec) throws Exception { next.setProtocolCodec(protocolCodec); } public void setTransportListener(TransportListener transportListener) { next.setTransportListener(transportListener); } public void start(Runnable onComplete) { next.start(onComplete); } public void start(Task onComplete) { next.start(onComplete); } public void stop(Runnable onComplete) { next.stop(onComplete); } public void stop(Task onComplete) { next.stop(onComplete); } public void suspendRead() { next.suspendRead(); } public void drainInbound() { next.drainInbound(); } } TransportListener.java000066400000000000000000000025431227446104000434000ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-transport/src/main/java/org/fusesource/hawtdispatch/transport/** * Copyright (C) 2012 FuseSource, Inc. * http://fusesource.com * * Licensed 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.fusesource.hawtdispatch.transport; import java.io.IOException; /** * An asynchronous listener of commands * */ public interface TransportListener { /** * called to process a command * @param command */ void onTransportCommand(Object command); /** * transport can now accept more commands for transmission. */ void onRefill(); /** * An unrecoverable exception has occured on the transport * @param error */ void onTransportFailure(IOException error); /** * The transport has been connected. */ public void onTransportConnected(); /** * The transport has been disconnected. */ public void onTransportDisconnected(); } TransportServer.java000066400000000000000000000052231227446104000430570ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-transport/src/main/java/org/fusesource/hawtdispatch/transport/** * Copyright (C) 2012 FuseSource, Inc. * http://fusesource.com * * Licensed 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.fusesource.hawtdispatch.transport; import java.net.SocketAddress; import java.util.concurrent.Executor; import org.fusesource.hawtdispatch.DispatchQueue; import org.fusesource.hawtdispatch.Task; /** * A TransportServer asynchronously accepts {@see Transport} objects and then * delivers those objects to a {@see TransportAcceptListener}. * * @version $Revision: 1.4 $ */ public interface TransportServer { /** * Starts the service. Executes the onComplete runnable once the service has fully started up. * * @param onComplete my be set to null if not interested in a callback. */ void start(Task onComplete) throws Exception; void start(Runnable onComplete) throws Exception; /** * Stops the service. Executes the onComplete runnable once the service has fully stopped. * * @param onComplete my be set to null if not interested in a callback. */ void stop(Task onComplete) throws Exception; void stop(Runnable onComplete) throws Exception; /** * Registers an {@see TransportAcceptListener} which is notified of accepted * channels. * * @param acceptListener */ void setTransportServerListener(TransportServerListener acceptListener); String getBoundAddress(); /** * @return The socket address that this transport is accepting connections * on or null if this does not or is not currently accepting * connections on a socket. */ SocketAddress getSocketAddress(); /** * Returns the dispatch queue used by the transport * * @return */ DispatchQueue getDispatchQueue(); /** * Sets the dispatch queue used by the transport * * @param queue */ void setDispatchQueue(DispatchQueue queue); /** * suspend accepting new transports */ void suspend(); /** * resume accepting new transports */ void resume(); public Executor getBlockingExecutor(); public void setBlockingExecutor(Executor blockingExecutor); } TransportServerListener.java000066400000000000000000000017011227446104000445620ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-transport/src/main/java/org/fusesource/hawtdispatch/transport/** * Copyright (C) 2012 FuseSource, Inc. * http://fusesource.com * * Licensed 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.fusesource.hawtdispatch.transport; /** * Implemented by object that need to get injected by * * @author Hiram Chirino */ public interface TransportServerListener { void onAccept(Transport transport) throws Exception; void onAcceptError(Exception error); } UdpTransport.java000066400000000000000000000464401227446104000423470ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-transport/src/main/java/org/fusesource/hawtdispatch/transport/** * Copyright (C) 2012 FuseSource, Inc. * http://fusesource.com * * Licensed 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.fusesource.hawtdispatch.transport; import org.fusesource.hawtdispatch.*; import java.io.IOException; import java.net.*; import java.nio.channels.DatagramChannel; import java.nio.channels.ReadableByteChannel; import java.nio.channels.SelectionKey; import java.nio.channels.WritableByteChannel; import java.util.LinkedList; import java.util.concurrent.Executor; /** *

*

* * @author Hiram Chirino */ public class UdpTransport extends ServiceBase implements Transport { public static final SocketAddress ANY_ADDRESS = new SocketAddress() { @Override public String toString() { return "*:*"; } }; abstract static class SocketState { void onStop(Task onCompleted) { } void onCanceled() { } boolean is(Class clazz) { return getClass()==clazz; } } static class DISCONNECTED extends SocketState{} class CONNECTING extends SocketState{ void onStop(Task onCompleted) { trace("CONNECTING.onStop"); CANCELING state = new CANCELING(); socketState = state; state.onStop(onCompleted); } void onCanceled() { trace("CONNECTING.onCanceled"); CANCELING state = new CANCELING(); socketState = state; state.onCanceled(); } } class CONNECTED extends SocketState { public CONNECTED() { localAddress = channel.socket().getLocalSocketAddress(); remoteAddress = channel.socket().getRemoteSocketAddress(); if(remoteAddress == null ) { remoteAddress = ANY_ADDRESS; } } void onStop(Task onCompleted) { trace("CONNECTED.onStop"); CANCELING state = new CANCELING(); socketState = state; state.add(createDisconnectTask()); state.onStop(onCompleted); } void onCanceled() { trace("CONNECTED.onCanceled"); CANCELING state = new CANCELING(); socketState = state; state.add(createDisconnectTask()); state.onCanceled(); } Task createDisconnectTask() { return new Task(){ public void run() { listener.onTransportDisconnected(); } }; } } class CANCELING extends SocketState { private LinkedList runnables = new LinkedList(); private int remaining; private boolean dispose; public CANCELING() { if( readSource!=null ) { remaining++; readSource.cancel(); } if( writeSource!=null ) { remaining++; writeSource.cancel(); } } void onStop(Task onCompleted) { trace("CANCELING.onCompleted"); add(onCompleted); dispose = true; } void add(Task onCompleted) { if( onCompleted!=null ) { runnables.add(onCompleted); } } void onCanceled() { trace("CANCELING.onCanceled"); remaining--; if( remaining!=0 ) { return; } try { channel.close(); } catch (IOException ignore) { } socketState = new CANCELED(dispose); for (Task runnable : runnables) { runnable.run(); } if (dispose) { dispose(); } } } class CANCELED extends SocketState { private boolean disposed; public CANCELED(boolean disposed) { this.disposed=disposed; } void onStop(Task onCompleted) { trace("CANCELED.onStop"); if( !disposed ) { disposed = true; dispose(); } onCompleted.run(); } } protected URI remoteLocation; protected URI localLocation; protected TransportListener listener; protected ProtocolCodec codec; protected DatagramChannel channel; protected SocketState socketState = new DISCONNECTED(); protected DispatchQueue dispatchQueue; private DispatchSource readSource; private DispatchSource writeSource; protected CustomDispatchSource drainOutboundSource; protected CustomDispatchSource yieldSource; protected boolean useLocalHost = true; int receiveBufferSize = 1024*64; int sendBufferSize = 1024*64; public static final int IPTOS_LOWCOST = 0x02; public static final int IPTOS_RELIABILITY = 0x04; public static final int IPTOS_THROUGHPUT = 0x08; public static final int IPTOS_LOWDELAY = 0x10; int trafficClass = IPTOS_THROUGHPUT; SocketAddress localAddress; SocketAddress remoteAddress = ANY_ADDRESS; Executor blockingExecutor; private final Task CANCEL_HANDLER = new Task() { public void run() { socketState.onCanceled(); } }; static final class OneWay { final Object command; final Retained retained; public OneWay(Object command, Retained retained) { this.command = command; this.retained = retained; } } public void connected(DatagramChannel channel) throws IOException, Exception { this.channel = channel; initializeChannel(); this.socketState = new CONNECTED(); } protected void initializeChannel() throws Exception { this.channel.configureBlocking(false); DatagramSocket socket = channel.socket(); try { socket.setReuseAddress(true); } catch (SocketException e) { } try { socket.setTrafficClass(trafficClass); } catch (SocketException e) { } try { socket.setReceiveBufferSize(receiveBufferSize); } catch (SocketException e) { } try { socket.setSendBufferSize(sendBufferSize); } catch (SocketException e) { } if( channel!=null && codec!=null ) { initializeCodec(); } } protected void initializeCodec() throws Exception { codec.setTransport(this); } public void connecting(final URI remoteLocation, final URI localLocation) throws Exception { this.channel = DatagramChannel.open(); initializeChannel(); this.remoteLocation = remoteLocation; this.localLocation = localLocation; socketState = new CONNECTING(); } public DispatchQueue getDispatchQueue() { return dispatchQueue; } public void setDispatchQueue(DispatchQueue queue) { this.dispatchQueue = queue; if(readSource!=null) readSource.setTargetQueue(queue); if(writeSource!=null) writeSource.setTargetQueue(queue); if(drainOutboundSource!=null) drainOutboundSource.setTargetQueue(queue); if(yieldSource!=null) yieldSource.setTargetQueue(queue); } public void _start(Task onCompleted) { try { if ( socketState.is(CONNECTING.class) ) { // Resolving host names might block.. so do it on the blocking executor. this.blockingExecutor.execute(new Runnable() { public void run() { // No need to complete if we have been canceled. if( ! socketState.is(CONNECTING.class) ) { return; } try { final InetSocketAddress localAddress = (localLocation != null) ? new InetSocketAddress(InetAddress.getByName(localLocation.getHost()), localLocation.getPort()) : null; String host = resolveHostName(remoteLocation.getHost()); final InetSocketAddress remoteAddress = new InetSocketAddress(host, remoteLocation.getPort()); // Done resolving.. switch back to the dispatch queue. dispatchQueue.execute(new Task() { @Override public void run() { try { if(localAddress!=null) { channel.socket().bind(localAddress); } channel.connect(remoteAddress); } catch (IOException e) { try { channel.close(); } catch (IOException ignore) { } socketState = new CANCELED(true); listener.onTransportFailure(e); } } }); } catch (IOException e) { try { channel.close(); } catch (IOException ignore) { } socketState = new CANCELED(true); listener.onTransportFailure(e); } } }); } else if (socketState.is(CONNECTED.class) ) { dispatchQueue.execute(new Task() { public void run() { try { trace("was connected."); onConnected(); } catch (IOException e) { onTransportFailure(e); } } }); } else { System.err.println("cannot be started. socket state is: "+socketState); } } finally { if( onCompleted!=null ) { onCompleted.run(); } } } public void _stop(final Task onCompleted) { trace("stopping.. at state: "+socketState); socketState.onStop(onCompleted); } protected String resolveHostName(String host) throws UnknownHostException { String localName = InetAddress.getLocalHost().getHostName(); if (localName != null && isUseLocalHost()) { if (localName.equals(host)) { return "localhost"; } } return host; } protected void onConnected() throws IOException { yieldSource = Dispatch.createSource(EventAggregators.INTEGER_ADD, dispatchQueue); yieldSource.setEventHandler(new Task() { public void run() { drainInbound(); } }); yieldSource.resume(); drainOutboundSource = Dispatch.createSource(EventAggregators.INTEGER_ADD, dispatchQueue); drainOutboundSource.setEventHandler(new Task() { public void run() { flush(); } }); drainOutboundSource.resume(); readSource = Dispatch.createSource(channel, SelectionKey.OP_READ, dispatchQueue); writeSource = Dispatch.createSource(channel, SelectionKey.OP_WRITE, dispatchQueue); readSource.setCancelHandler(CANCEL_HANDLER); writeSource.setCancelHandler(CANCEL_HANDLER); readSource.setEventHandler(new Task() { public void run() { drainInbound(); } }); writeSource.setEventHandler(new Task() { public void run() { flush(); } }); listener.onTransportConnected(); } Task onDispose; private void dispose() { if( readSource!=null ) { readSource.cancel(); readSource=null; } if( writeSource!=null ) { writeSource.cancel(); writeSource=null; } this.codec = null; if(onDispose!=null) { onDispose.run(); onDispose = null; } } public void onTransportFailure(IOException error) { listener.onTransportFailure(error); socketState.onCanceled(); } public boolean full() { return codec==null || codec.full(); } boolean rejectingOffers; public boolean offer(Object command) { dispatchQueue.assertExecuting(); try { if (!socketState.is(CONNECTED.class)) { throw new IOException("Not connected."); } if (getServiceState() != STARTED) { throw new IOException("Not running."); } ProtocolCodec.BufferState rc = codec.write(command); rejectingOffers = codec.full(); switch (rc ) { case FULL: return false; default: drainOutboundSource.merge(1); return true; } } catch (IOException e) { onTransportFailure(e); return false; } } boolean writeResumedForCodecFlush = false; /** * */ public void flush() { dispatchQueue.assertExecuting(); if (getServiceState() != STARTED || !socketState.is(CONNECTED.class)) { return; } try { if( codec.flush() == ProtocolCodec.BufferState.EMPTY && transportFlush() ) { if( writeResumedForCodecFlush) { writeResumedForCodecFlush = false; suspendWrite(); } rejectingOffers = false; listener.onRefill(); } else { if(!writeResumedForCodecFlush) { writeResumedForCodecFlush = true; resumeWrite(); } } } catch (IOException e) { onTransportFailure(e); } } protected boolean transportFlush() throws IOException { return true; } public void drainInbound() { if (!getServiceState().isStarted() || readSource.isSuspended()) { return; } try { long initial = codec.getReadCounter(); // Only process upto 2 x the read buffer worth of data at a time so we can give // other connections a chance to process their requests. while( codec.getReadCounter()-initial < codec.getReadBufferSize()<<2 ) { Object command = codec.read(); if ( command!=null ) { try { listener.onTransportCommand(command); } catch (Throwable e) { e.printStackTrace(); onTransportFailure(new IOException("Transport listener failure.")); } // the transport may be suspended after processing a command. if (getServiceState() == STOPPED || readSource.isSuspended()) { return; } } else { return; } } yieldSource.merge(1); } catch (IOException e) { onTransportFailure(e); } } public SocketAddress getLocalAddress() { return localAddress; } public SocketAddress getRemoteAddress() { return remoteAddress; } private boolean assertConnected() { try { if ( !isConnected() ) { throw new IOException("Not connected."); } return true; } catch (IOException e) { onTransportFailure(e); } return false; } public void suspendRead() { if( isConnected() && readSource!=null ) { readSource.suspend(); } } public void resumeRead() { if( isConnected() && readSource!=null ) { _resumeRead(); } } private void _resumeRead() { readSource.resume(); dispatchQueue.execute(new Task(){ public void run() { drainInbound(); } }); } protected void suspendWrite() { if( isConnected() && writeSource!=null ) { writeSource.suspend(); } } protected void resumeWrite() { if( isConnected() && writeSource!=null ) { writeSource.resume(); } } public TransportListener getTransportListener() { return listener; } public void setTransportListener(TransportListener transportListener) { this.listener = transportListener; } public ProtocolCodec getProtocolCodec() { return codec; } public void setProtocolCodec(ProtocolCodec protocolCodec) throws Exception { this.codec = protocolCodec; if( channel!=null && codec!=null ) { initializeCodec(); } } public boolean isConnected() { return socketState.is(CONNECTED.class); } public boolean isClosed() { return getServiceState() == STOPPED; } public boolean isUseLocalHost() { return useLocalHost; } /** * Sets whether 'localhost' or the actual local host name should be used to * make local connections. On some operating systems such as Macs its not * possible to connect as the local host name so localhost is better. */ public void setUseLocalHost(boolean useLocalHost) { this.useLocalHost = useLocalHost; } private void trace(String message) { // TODO: } public DatagramChannel getDatagramChannel() { return channel; } public ReadableByteChannel getReadChannel() { return channel; } public WritableByteChannel getWriteChannel() { return channel; } public int getTrafficClass() { return trafficClass; } public void setTrafficClass(int trafficClass) { this.trafficClass = trafficClass; } public int getReceiveBufferSize() { return receiveBufferSize; } public void setReceiveBufferSize(int receiveBufferSize) { this.receiveBufferSize = receiveBufferSize; } public int getSendBufferSize() { return sendBufferSize; } public void setSendBufferSize(int sendBufferSize) { this.sendBufferSize = sendBufferSize; } public Executor getBlockingExecutor() { return blockingExecutor; } public void setBlockingExecutor(Executor blockingExecutor) { this.blockingExecutor = blockingExecutor; } } UdpTransportServer.java000066400000000000000000000103611227446104000435270ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-transport/src/main/java/org/fusesource/hawtdispatch/transport/** * Copyright (C) 2012 FuseSource, Inc. * http://fusesource.com * * Licensed 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.fusesource.hawtdispatch.transport; import org.fusesource.hawtdispatch.DispatchQueue; import org.fusesource.hawtdispatch.Task; import java.net.*; import java.nio.channels.DatagramChannel; import java.util.concurrent.Executor; /** *

*

* * @author Hiram Chirino */ public class UdpTransportServer extends ServiceBase implements TransportServer { private final String bindScheme; private final InetSocketAddress bindAddress; private DatagramChannel channel; private TransportServerListener listener; private DispatchQueue dispatchQueue; private Executor blockingExecutor; public UdpTransportServer(URI location) throws UnknownHostException { bindScheme = location.getScheme(); String host = location.getHost(); host = (host == null || host.length() == 0) ? "::" : host; bindAddress = new InetSocketAddress(InetAddress.getByName(host), location.getPort()); } private UdpTransport transport; public void setTransportServerListener(TransportServerListener listener) { this.listener = listener; } public InetSocketAddress getSocketAddress() { return (InetSocketAddress) channel.socket().getLocalSocketAddress(); } public DispatchQueue getDispatchQueue() { return dispatchQueue; } public void setDispatchQueue(DispatchQueue dispatchQueue) { this.dispatchQueue = dispatchQueue; } @Override protected void _start(Task onCompleted) { accept(); if( onCompleted!=null ) { dispatchQueue.execute(onCompleted); } } private void queueAccept() { dispatchQueue.execute(new Task() { public void run() { accept(); } }); } private void accept() { if (getServiceState().isStarted() || getServiceState().isStarting()) { try { UdpTransport udpTransport = createTransport(); transport = udpTransport; transport.onDispose = new Task() { public void run() { queueAccept(); } }; channel = DatagramChannel.open(); channel.socket().bind(bindAddress); transport.connected(channel); listener.onAccept(transport); } catch (Exception e) { listener.onAcceptError(e); } } } protected UdpTransport createTransport() { final UdpTransport transport = new UdpTransport(); transport.setBlockingExecutor(blockingExecutor); transport.setDispatchQueue(dispatchQueue); return transport; } @Override protected void _stop(Task onCompleted) { transport.stop(onCompleted); } public void suspend() { dispatchQueue.suspend(); } public void resume() { dispatchQueue.resume(); } public String getBoundAddress() { try { String host = bindAddress.getAddress().getHostAddress(); int port = channel.socket().getLocalPort(); return new URI(bindScheme, null, host, port, null, null, null).toString(); } catch (URISyntaxException e) { throw new RuntimeException(e); } } /** * @return pretty print of this */ public String toString() { return getBoundAddress(); } public Executor getBlockingExecutor() { return blockingExecutor; } public void setBlockingExecutor(Executor blockingExecutor) { this.blockingExecutor = blockingExecutor; } } WrappingProtocolCodec.java000066400000000000000000000016631227446104000441470ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-transport/src/main/java/org/fusesource/hawtdispatch/transport/** * Copyright (C) 2012 FuseSource, Inc. * http://fusesource.com * * Licensed 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.fusesource.hawtdispatch.transport; /** * Interface of protocol codecs that wrap other protocol codecs. */ public interface WrappingProtocolCodec extends ProtocolCodec { /** * @returns the next codec. */ public ProtocolCodec getNext(); public void setNext(ProtocolCodec value); } 000077500000000000000000000000001227446104000357505ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-transport/src/main/java/org/fusesource/hawtdispatch/utilBufferPool.java000066400000000000000000000021131227446104000406530ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-transport/src/main/java/org/fusesource/hawtdispatch/util/** * Copyright (C) 2012 FuseSource, Inc. * http://fusesource.com * * Licensed 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.fusesource.hawtdispatch.util; /** *

*

* * @author Hiram Chirino */ public class BufferPool extends ThreadLocalPool { private final int bufferSize; public BufferPool(int bufferSize) { this.bufferSize = bufferSize; } @Override protected byte[] create() { return new byte[bufferSize]; } public int getBufferSize() { return bufferSize; } } BufferPools.java000066400000000000000000000021731227446104000410440ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-transport/src/main/java/org/fusesource/hawtdispatch/util/** * Copyright (C) 2012 FuseSource, Inc. * http://fusesource.com * * Licensed 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.fusesource.hawtdispatch.util; import java.util.HashMap; /** *

*

* * @author Hiram Chirino */ public class BufferPools { private final HashMap pools = new HashMap(); public synchronized BufferPool getBufferPool(int size) { BufferPool rc = pools.get(size); if( rc == null ) { rc = new BufferPool(size); pools.put(size, rc); } return rc; } } ThreadLocalPool.java000066400000000000000000000052261227446104000416340ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-transport/src/main/java/org/fusesource/hawtdispatch/util/** * Copyright (C) 2012 FuseSource, Inc. * http://fusesource.com * * Licensed 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.fusesource.hawtdispatch.util; import java.util.ArrayList; /** *

*

* * @author Hiram Chirino */ abstract public class ThreadLocalPool { class Pool { final ArrayList objects = new ArrayList(maxPoolSizePerThread()); long hitCounter; long missCounter; // public void monitor() { // DispatchQueue current = Dispatch.getCurrentThreadQueue(); // if( current!=null ) { // current.executeAfter(1, TimeUnit.SECONDS, new Task() { // @Override // public void run() { // if( hitCounter + missCounter > 0 ) { // System.out.println(String.format("Pool stats: %d hits, %d misses = %f percent", // hitCounter, missCounter, 100.0*hitCounter/(hitCounter + missCounter))); // } // hitCounter=0; // missCounter=0; // monitor(); // } // }); // } // } } private final ThreadLocal objectsThreadLocal = new ThreadLocal(); abstract protected T create(); protected int maxPoolSizePerThread() { return 10; } private Pool getPool() { Pool rc = objectsThreadLocal.get(); if (rc == null) { rc = new Pool(); // rc.monitor(); objectsThreadLocal.set(rc); } return rc; } public T checkout() { Pool pool = getPool(); ArrayList objects = pool.objects; if (!objects.isEmpty()) { pool.hitCounter++; return objects.remove(objects.size() - 1); } else { pool.missCounter++; return create(); } } public void checkin(T value) { ArrayList objects = getPool().objects; if (objects.size() < maxPoolSizePerThread()) { objects.add(value); } } } hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-transport/src/test/000077500000000000000000000000001227446104000265275ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-transport/src/test/resources/000077500000000000000000000000001227446104000305415ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-transport/src/test/resources/log4j.properties000077500000000000000000000024301227446104000337000ustar00rootroot00000000000000# # Copyright (C) 2012 FuseSource, Inc. # http://fusesource.com # # Licensed 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. # # # The logging properties used during tests.. # log4j.rootLogger=WARN, console, file log4j.logger.org.fusesource.hawtdispatch=INFO # Console will only display warnnings log4j.appender.console=org.apache.log4j.ConsoleAppender log4j.appender.console.layout=org.apache.log4j.PatternLayout log4j.appender.console.layout.ConversionPattern=%d | %-5p | %m%n log4j.appender.console.threshold=WARN # File appender will contain all info messages log4j.appender.file=org.apache.log4j.FileAppender log4j.appender.file.layout=org.apache.log4j.PatternLayout log4j.appender.file.layout.ConversionPattern=%d | %-5p | %m | %c | %t%n log4j.appender.file.file=target/test.log log4j.appender.file.append=true hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-website/000077500000000000000000000000001227446104000243675ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-website/ext/000077500000000000000000000000001227446104000251675ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-website/ext/ScalatePackage.scala000066400000000000000000000022641227446104000310300ustar00rootroot00000000000000/** * 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. */ import org.fusesource.scalate.support.TemplatePackage import org.fusesource.scalate.{Binding, TemplateSource} /** * Defines the template package of reusable imports, attributes and methods across templates */ class ScalatePackage extends TemplatePackage { def header(source: TemplateSource, bindings: List[Binding]) = """ // common imports go here import _root_.Website._; """ } hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-website/ext/Website.scala000066400000000000000000000047001227446104000275770ustar00rootroot00000000000000/** * 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. */ import org.fusesource.scalate.RenderContext package /** *

*

* * @author Hiram Chirino */ object Website { val project_name= "HawtDispatch" val project_slogan= "The libdispatch style API for Java and Scala" val project_id= "hawtdispatch" val project_jira_key= "HAWTDISPATCH" val project_issue_url= "http://hawtdispatch.assembla.com/spaces/hawtdispatch/support/tickets" val project_forums_url= "http://groups.google.com/group/hawtdispatch" val project_wiki_url= "http://wiki.github.com/fusesource/hawtdispatch" val project_logo= "/images/project-logo.png" val project_version= "1.16" val project_snapshot_version= "1.17-SNAPSHOT" val project_versions = List( project_version, "1.15", "1.14","1.13","1.12","1.11","1.10", "1.9","1.8","1.7","1.6","1.5","1.4","1.3","1.2","1.1","1.0") val project_keywords= "dispatch,executor,java,scala,libdispatch,gcd,actor,thread,pool" // ------------------------------------------------------------------- val github_page = "http://github.com/fusesource/hawtdispatch" val git_user_url = "git://github.com/fusesource/hawtdispatch.git" val git_commiter_url = "git@github.com:fusesource/hawtdispatch.git" val project_maven_groupId= "org.fusesource.hawtdispatch" val project_maven_artifactId= "hawtdispatch" val website_base_url= "http://hawtdispatch.fusesource.org" val api_dir = "http://hawtdispatch.fusesource.org/versions/"+project_version+"/maven/hawtdispatch/apidocs/org/fusesource/hawtdispatch" val scala_api_dir = "http://hawtdispatch.fusesource.org/versions/"+project_version+"/maven/hawtdispatch-scala/scaladocs" }hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-website/ext/scalate/000077500000000000000000000000001227446104000266035ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-website/ext/scalate/Boot.scala000066400000000000000000000046221227446104000305170ustar00rootroot00000000000000/** * 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 scalate import org.fusesource.scalate.util.Logging import java.util.concurrent.atomic.AtomicBoolean import _root_.Website._ import org.fusesource.scalate.TemplateEngine import org.fusesource.scalamd.{MacroDefinition, Markdown} import java.util.regex.Matcher import org.fusesource.scalate.wikitext.Pygmentize class Boot(engine: TemplateEngine) extends Logging { private var _initialised = new AtomicBoolean(false) def run: Unit = { if (_initialised.compareAndSet(false, true)) { def pygmentize(m:Matcher):String = Pygmentize.pygmentize(m.group(2), m.group(1)) def var_macro(name:String, value: => Any) = MacroDefinition("""\$\{"""+name+"""\}""", "", _ => value.toString, true) // add some macros to markdown. Markdown.macros :::= List( MacroDefinition("""\{pygmentize::(.*?)\}(.*?)\{pygmentize\}""", "s", pygmentize, true), MacroDefinition("""\{pygmentize\_and\_compare::(.*?)\}(.*?)\{pygmentize\_and\_compare\}""", "s", pygmentize, true), var_macro("project_version", project_version), var_macro("project_name", project_name), var_macro("project_id", project_id), var_macro("project_issue_url", project_issue_url), var_macro("website_base_url", website_base_url), var_macro("api_dir", api_dir), var_macro("scala_api_dir", scala_api_dir) ) for( ssp <- engine.filter("ssp"); md <- engine.filter("markdown") ) { engine.pipelines += "ssp.md"-> List(ssp, md) engine.pipelines += "ssp.markdown"-> List(ssp, md) } info("Bootstrapped website gen for: %s".format(project_name)) } } }hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-website/pom.xml000066400000000000000000000132251227446104000257070ustar00rootroot00000000000000 4.0.0 org.fusesource.hawtdispatch hawtdispatch-project 1.20 org.fusesource.hawtdispatch hawtdispatch-website 1.20 pom The HawtDispatch Website 2.9.1 1.5.3 1.5 1.6.0 7.0.1.v20091125 org.scala-lang scala-library ${scala-version} org.scala-lang scala-compiler ${scala-version} org.fusesource.scalate scalate-wikitext ${scalate-version} org.fusesource.scalate scalate-page ${scalate-version} org.fusesource.scalamd scalamd ${scalamd-version} org.slf4j slf4j-nop ${slf4j-version} ext org.scala-tools maven-scala-plugin 2.14 compile -Xmx1024m ${scala-version} org.fusesource.scalate maven-scalate-plugin ${scalate-version} ${basedir}/src website.fusesource.org dav:http://fusesource.com/forge/dav/${forge-project-id}/versions/${project.version}/website sitegen sitegen package deploy deploy deploy org.mortbay.jetty jetty-maven-plugin ${jetty-plugin-version} ${basedir}/src scalate.editor ${env.SCALATE_EDITOR} scalate.workdir ${basedir}/target/_scalate scalate.mode development 0 org.fusesource.mvnplugins maven-linkchecker-plugin 1.12 http://github.com/ http://git.or.cz/ http://localhost:8080/ http://repo.fusesource.com/ http://search.twitter.com/ http://www.chengin.com/ hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-website/src/000077500000000000000000000000001227446104000251565ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-website/src/WEB-INF/000077500000000000000000000000001227446104000262055ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-website/src/WEB-INF/scalate/000077500000000000000000000000001227446104000276215ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-website/src/WEB-INF/scalate/layouts/000077500000000000000000000000001227446104000313215ustar00rootroot00000000000000hawtdispatch-hawtdispatch-project-1.20/hawtdispatch-website/src/WEB-INF/scalate/layouts/default.jade000066400000000000000000000057571227446104000336100ustar00rootroot00000000000000!!! Basic :plain - response.setContentType("text/html") -@ var title : String = "" -@ var body: String = null -@ var overview: String = null -@ var spot: String = null -@ var blog: String = null -@ var head: String = null - val include_console = engine.isDevelopmentMode && engine.resourceLoader.exists("/org/fusesource/scalate/console/console_head.scaml") html(lang="en") head meta(content="text/html; charset=utf-8" http-equiv="Content-Type") meta(content="#{project_slogan}" name="description") meta(content="#{project_keywords}" name="keywords") meta(content="#{project_name}" name="author") link(type="text/css" rel="stylesheet" href={uri("/styles/impact/css/pygmentize.css")}) link(type="text/css" rel="stylesheet" href={uri("/styles/impact/css/site.css")}) - if (head!=null) !~~ head -# - if (include_console) - include("/org/fusesource/scalate/console/console_head.scaml") link(href={uri("/css/scalate/console.css")} rel="stylesheet" type="text/css") title= title body div#navigation div.wrapper - include("/_navigation.ssp.md") - if (overview!=null) div#overview div.wrapper -if ( project_logo!=null ) div.logo img(src="#{uri(project_logo)}" alt="#{project_name} logo") div.message !~~ overview - if (spot!=null) div#spot div.wrapper !~~ spot - if (body!=null) div#content div.wrapper !~~ body - if (blog!=null) div#blog div.wrapper !~~ blog -# - if (include_console) = include("/org/fusesource/scalate/console/console.scaml") -# :javascript var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www."); document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));