├── .gitignore ├── LICENSE.txt ├── README.md ├── build.sh ├── craft-atom-io ├── pom.xml └── src │ └── main │ └── java │ └── io │ └── craft │ └── atom │ └── io │ ├── AbstractChannel.java │ ├── AbstractChannelEvent.java │ ├── AbstractIoByteChannel.java │ ├── AbstractIoChannel.java │ ├── AbstractIoHandler.java │ ├── Channel.java │ ├── ChannelEvent.java │ ├── ChannelEventType.java │ ├── ChannelState.java │ ├── IllegalChannelStateException.java │ ├── IoAcceptor.java │ ├── IoAcceptorMBean.java │ ├── IoAcceptorX.java │ ├── IoConfig.java │ ├── IoConnector.java │ ├── IoConnectorMBean.java │ ├── IoConnectorX.java │ ├── IoHandler.java │ ├── IoProcessor.java │ ├── IoProcessorMBean.java │ ├── IoProcessorX.java │ ├── IoProtocol.java │ ├── IoReactor.java │ └── IoReactorX.java ├── craft-atom-lock ├── pom.xml └── src │ ├── main │ └── java │ │ └── io │ │ └── craft │ │ └── atom │ │ └── lock │ │ ├── Redis24DLock.java │ │ ├── Redis26DLock.java │ │ ├── ShardedRedis24DLock.java │ │ ├── ShardedRedis26DLock.java │ │ └── api │ │ ├── DLock.java │ │ └── DLockFactory.java │ └── test │ └── java │ └── io │ └── craft │ └── atom │ └── lock │ ├── AbstractDLockTests.java │ ├── TestRedis24DLock.java │ └── TestShardedRedis24DLock.java ├── craft-atom-nio ├── pom.xml └── src │ ├── main │ └── java │ │ └── io │ │ └── craft │ │ └── atom │ │ └── nio │ │ ├── AbstractNioByteChannelEvent.java │ │ ├── NioAcceptor.java │ │ ├── NioAcceptorX.java │ │ ├── NioAdaptiveBufferSizePredictor.java │ │ ├── NioAdaptiveBufferSizePredictorFactory.java │ │ ├── NioByteBufferAllocator.java │ │ ├── NioByteChannel.java │ │ ├── NioByteChannelEvent.java │ │ ├── NioChannelIdleTimer.java │ │ ├── NioConfig.java │ │ ├── NioConnector.java │ │ ├── NioConnectorX.java │ │ ├── NioOrderedDirectChannelEventDispatcher.java │ │ ├── NioOrderedThreadPoolChannelEventDispatcher.java │ │ ├── NioProcessor.java │ │ ├── NioProcessorPool.java │ │ ├── NioProcessorX.java │ │ ├── NioReactor.java │ │ ├── NioReactorX.java │ │ ├── NioTcpAcceptor.java │ │ ├── NioTcpByteChannel.java │ │ ├── NioTcpConnector.java │ │ ├── NioUdpAcceptor.java │ │ ├── NioUdpByteChannel.java │ │ ├── api │ │ ├── NioAcceptorConfig.java │ │ ├── NioBuilder.java │ │ ├── NioConnectorConfig.java │ │ ├── NioFactory.java │ │ ├── NioTcpAcceptorBuilder.java │ │ └── NioTcpConnectorBuilder.java │ │ └── spi │ │ ├── AbstractNioChannelEventDispatcher.java │ │ ├── NioBufferSizePredictor.java │ │ ├── NioBufferSizePredictorFactory.java │ │ └── NioChannelEventDispatcher.java │ └── test │ ├── java │ └── io │ │ └── craft │ │ └── atom │ │ └── nio │ │ ├── NioAcceptorHandler.java │ │ ├── NioAcceptorNapHandler.java │ │ ├── NioConnectorHandler.java │ │ ├── NioEchoClient.java │ │ ├── NioEchoClientHandler.java │ │ ├── NioEchoServer.java │ │ ├── NioEchoServerHandler.java │ │ ├── TestNioBufferSizePredictor.java │ │ ├── TestNioBuilder.java │ │ ├── TestNioByteBuffer.java │ │ ├── TestNioMBean.java │ │ ├── TestNioTcpAcceptor.java │ │ ├── TestNioTcpAcceptorChannelSizeLimit.java │ │ ├── TestNioTcpConnector.java │ │ ├── TestNioTcpEchoServer.java │ │ ├── TestNioTcpEchoServerForOverloadProtection.java │ │ └── TestNioTimeout.java │ └── resources │ └── log4j.xml ├── craft-atom-protocol-http ├── pom.xml └── src │ ├── main │ └── java │ │ └── io │ │ └── craft │ │ └── atom │ │ └── protocol │ │ └── http │ │ ├── HttpConstants.java │ │ ├── HttpCookieDecoder.java │ │ ├── HttpCookieEncoder.java │ │ ├── HttpDates.java │ │ ├── HttpDecoder.java │ │ ├── HttpEncoder.java │ │ ├── HttpHeaders.java │ │ ├── HttpParameterDecoder.java │ │ ├── HttpParameterEncoder.java │ │ ├── HttpRequestDecoder.java │ │ ├── HttpRequestEncoder.java │ │ ├── HttpResponseDecoder.java │ │ ├── HttpResponseEncoder.java │ │ ├── api │ │ ├── HttpCodecFactory.java │ │ └── HttpRequestDecoderBuilder.java │ │ └── model │ │ ├── HttpChunk.java │ │ ├── HttpChunkEntity.java │ │ ├── HttpContentType.java │ │ ├── HttpCookie.java │ │ ├── HttpEntity.java │ │ ├── HttpHeader.java │ │ ├── HttpHeaderType.java │ │ ├── HttpHeaderValueElement.java │ │ ├── HttpMessage.java │ │ ├── HttpMethod.java │ │ ├── HttpRequest.java │ │ ├── HttpRequestLine.java │ │ ├── HttpResponse.java │ │ ├── HttpStartLine.java │ │ ├── HttpStatus.java │ │ ├── HttpStatusLine.java │ │ ├── HttpVersion.java │ │ └── MimeType.java │ └── test │ └── java │ └── io │ └── craft │ └── atom │ └── protocol │ └── http │ ├── TestHttpCookieDecoder.java │ ├── TestHttpParameterDecoder.java │ └── TestHttpRequestDecoder.java ├── craft-atom-protocol-rpc ├── pom.xml └── src │ ├── main │ └── java │ │ └── io │ │ └── craft │ │ └── atom │ │ └── protocol │ │ └── rpc │ │ ├── KryoSerialization.java │ │ ├── RpcDecoder.java │ │ ├── RpcEncoder.java │ │ ├── api │ │ ├── RpcCodecFactory.java │ │ └── SerializationRegistry.java │ │ ├── model │ │ ├── RpcBody.java │ │ ├── RpcHeader.java │ │ ├── RpcMessage.java │ │ ├── RpcMethod.java │ │ └── RpcOption.java │ │ └── spi │ │ └── Serialization.java │ └── test │ └── java │ └── io │ └── craft │ └── atom │ └── protocol │ └── rpc │ ├── RpcService.java │ ├── SerialA.java │ ├── SerialB.java │ ├── SerialEnum.java │ ├── TestKryoSerialization.java │ └── TestRpcCodec.java ├── craft-atom-protocol-ssl ├── pom.xml └── src │ ├── main │ └── java │ │ └── io │ │ └── craft │ │ └── atom │ │ └── protocol │ │ └── ssl │ │ ├── DefaultSslCodec.java │ │ ├── SslHandshakeHandler.java │ │ ├── api │ │ ├── SslCodec.java │ │ └── SslCodecFactory.java │ │ └── spi │ │ └── SslHandshakeHandler.java │ └── test │ ├── java │ └── io │ │ └── craft │ │ └── atom │ │ └── protocol │ │ └── ssl │ │ └── TestSslCodec.java │ └── resources │ ├── log4j.xml │ ├── ssl.keystore │ └── ssl.truststore ├── craft-atom-protocol-textline ├── pom.xml └── src │ ├── main │ └── java │ │ └── io │ │ └── craft │ │ └── atom │ │ └── protocol │ │ └── textline │ │ ├── TextLineDecoder.java │ │ ├── TextLineEncoder.java │ │ └── api │ │ ├── TextLineCodecFactory.java │ │ └── TextLineDecoderBuilder.java │ └── test │ └── java │ └── io │ └── craft │ └── atom │ └── protocol │ └── textline │ └── TestTextLineDecoder.java ├── craft-atom-protocol ├── pom.xml └── src │ └── main │ └── java │ └── io │ └── craft │ └── atom │ └── protocol │ ├── AbstractProtocolCodec.java │ ├── AbstractProtocolDecoder.java │ ├── AbstractProtocolEncoder.java │ ├── ProtocolDecoder.java │ ├── ProtocolEncoder.java │ ├── ProtocolException.java │ └── ProtocolExceptionType.java ├── craft-atom-redis ├── pom.xml └── src │ ├── main │ └── java │ │ └── io │ │ └── craft │ │ └── atom │ │ └── redis │ │ ├── AbstractMurmurHashSharded.java │ │ ├── AbstractRedis.java │ │ ├── AbstractShardedRedis.java │ │ ├── CommandEnum.java │ │ ├── DefaultMasterSlaveRedis.java │ │ ├── DefaultMasterSlaveShardedRedis.java │ │ ├── DefaultRedis.java │ │ ├── DefaultRedisPubSub.java │ │ ├── DefaultRedisTransaction.java │ │ ├── DefaultShardedRedis.java │ │ ├── JedisPubSubAdapter.java │ │ ├── MasterSlaveRedisMurmurHashSharded.java │ │ ├── MurmurHash.java │ │ ├── RedisMurmurHashSharded.java │ │ ├── api │ │ ├── AbstractRedisBuilder.java │ │ ├── MasterSlaveRedis.java │ │ ├── MasterSlaveRedisBuilder.java │ │ ├── MasterSlaveShardedRedis.java │ │ ├── MasterSlaveShardedRedisBuilder.java │ │ ├── Redis.java │ │ ├── RedisBuilder.java │ │ ├── RedisCommand.java │ │ ├── RedisConnectionException.java │ │ ├── RedisDataException.java │ │ ├── RedisException.java │ │ ├── RedisFactory.java │ │ ├── RedisPoolConfig.java │ │ ├── RedisPubSub.java │ │ ├── RedisTransaction.java │ │ ├── ScanResult.java │ │ ├── ShardedRedis.java │ │ ├── ShardedRedisBuilder.java │ │ ├── ShardedRedisCommand.java │ │ ├── Slowlog.java │ │ └── handler │ │ │ ├── RedisMonitorHandler.java │ │ │ ├── RedisPsubscribeHandler.java │ │ │ ├── RedisPubSubHandler.java │ │ │ └── RedisSubscribeHandler.java │ │ └── spi │ │ └── Sharded.java │ └── test │ └── java │ └── io │ └── craft │ └── atom │ └── redis │ ├── AbstractRedisTests.java │ ├── TestJedisLeak.java │ ├── TestMasterSlaveRedis.java │ ├── TestRedis.java │ ├── TestRedisTransaction.java │ └── TestShardedRedis.java ├── craft-atom-rpc ├── pom.xml └── src │ ├── main │ └── java │ │ └── io │ │ └── craft │ │ └── atom │ │ └── rpc │ │ ├── AbstractRpcInvoker.java │ │ ├── DefaultRpcAcceptor.java │ │ ├── DefaultRpcApi.java │ │ ├── DefaultRpcChannel.java │ │ ├── DefaultRpcClient.java │ │ ├── DefaultRpcClientInvoker.java │ │ ├── DefaultRpcClientX.java │ │ ├── DefaultRpcConnector.java │ │ ├── DefaultRpcExecutorFactory.java │ │ ├── DefaultRpcFuture.java │ │ ├── DefaultRpcProcessor.java │ │ ├── DefaultRpcProtocol.java │ │ ├── DefaultRpcProxyFactory.java │ │ ├── DefaultRpcRegistry.java │ │ ├── DefaultRpcServer.java │ │ ├── DefaultRpcServerInvoker.java │ │ ├── DefaultRpcServerX.java │ │ ├── RpcClientIoHandler.java │ │ ├── RpcException.java │ │ ├── RpcFuture.java │ │ ├── RpcInvocationHandler.java │ │ ├── RpcIoHandler.java │ │ ├── RpcMessages.java │ │ ├── RpcServerIoHandler.java │ │ ├── RpcThreadPoolExecutor.java │ │ ├── api │ │ ├── RpcClient.java │ │ ├── RpcClientBuilder.java │ │ ├── RpcClientMBean.java │ │ ├── RpcClientX.java │ │ ├── RpcContext.java │ │ ├── RpcFactory.java │ │ ├── RpcParameter.java │ │ ├── RpcServer.java │ │ ├── RpcServerBuilder.java │ │ ├── RpcServerMBean.java │ │ └── RpcServerX.java │ │ └── spi │ │ ├── RpcAcceptor.java │ │ ├── RpcApi.java │ │ ├── RpcChannel.java │ │ ├── RpcConnector.java │ │ ├── RpcExecutorFactory.java │ │ ├── RpcInvoker.java │ │ ├── RpcProcessor.java │ │ ├── RpcProtocol.java │ │ ├── RpcProxyFactory.java │ │ └── RpcRegistry.java │ └── test │ ├── java │ └── io │ │ └── craft │ │ └── atom │ │ └── rpc │ │ ├── DemoService.java │ │ ├── DemoServiceImpl1.java │ │ ├── DemoServiceImpl2.java │ │ └── TestRpc.java │ └── resources │ └── log4j.xml ├── craft-atom-test ├── pom.xml └── src │ └── main │ └── java │ └── io │ └── craft │ └── atom │ └── test │ ├── AvailablePortFinder.java │ └── CaseCounter.java ├── craft-atom-util ├── pom.xml └── src │ ├── main │ ├── java │ │ └── io │ │ │ └── craft │ │ │ └── atom │ │ │ └── util │ │ │ ├── Assert.java │ │ │ ├── ByteArrayBuffer.java │ │ │ ├── ByteUtil.java │ │ │ ├── DateUtil.java │ │ │ ├── FileUtil.java │ │ │ ├── GzipUtil.java │ │ │ ├── HttpUtil.java │ │ │ ├── NetUtil.java │ │ │ ├── StringUtil.java │ │ │ ├── buffer │ │ │ ├── AbstractAdaptiveByteBuffer.java │ │ │ ├── AdaptiveByteBuffer.java │ │ │ ├── AdaptiveByteBufferHexDumper.java │ │ │ ├── BufferAllocator.java │ │ │ ├── CachedBufferAllocator.java │ │ │ └── SimpleBufferAllocator.java │ │ │ ├── schedule │ │ │ ├── ExpirationListener.java │ │ │ └── TimingWheel.java │ │ │ └── thread │ │ │ ├── MonitoringExecutorService.java │ │ │ ├── MonitoringThreadPoolExecutor.java │ │ │ └── NamedThreadFactory.java │ └── scripts │ │ └── java-thread-monitor.sh │ └── test │ └── java │ └── io │ └── craft │ └── atom │ └── util │ ├── TestByteArrayBuffer.java │ ├── TestByteUtil.java │ ├── TestGzipUtil.java │ ├── TestNetUtil.java │ ├── TestStringUtil.java │ ├── buffer │ ├── Bar.java │ ├── Foo.java │ └── TestAdaptiveBuffer.java │ └── schedule │ └── TestTimingWheel.java ├── deploy.sh ├── javadoc.sh ├── pom.xml ├── release-notes-2.x.txt ├── release-notes.md ├── release.sh ├── source.sh └── version.sh /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | .project 3 | .classpath 4 | *.prefs 5 | *.class 6 | *.iml 7 | */target 8 | target/* 9 | */bin 10 | */checkout 11 | *.backup 12 | *.versionsBackup 13 | .idea/* 14 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 mindwind 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![craft-atom](http://mindwind.me/images/craft-logo.png) 2 | A crafted and elegant atomic component library for Java. It is a maven multi-module java projects, each module is a crafted and atomic java library for specific feature. 3 | 4 | This README is just a fast "quick start" document. 5 | You can find more detailed documentation [here](http://mindwind.me/craft/documentation). 6 | 7 | 8 | ## Philosophy 9 | `minimal` Minimal code and dependency. 10 | `atomic` Just do one thing right for every component. 11 | `compositional` Compose atomic components for complex function. 12 | 13 | 14 | ## How do I use it? 15 | Use it as a maven dependency: 16 | 17 | ```xml 18 | 19 | io.craftcode 20 | craft-atom-xxx 21 | 3.1.0 22 | jar 23 | 24 | ``` 25 | 26 | ## I want to contribute! 27 | That is great! 28 | 29 | * Use [Github](http://github.com) issues to report bugs or for detailed feature requests. 30 | * [Fork](https://help.github.com/articles/fork-a-repo/) and create a topic branch, add your feature last post a [pull request](https://help.github.com/articles/using-pull-requests/) on github. 31 | 32 | _NOTICE:_ 33 | 1. _Please add unit tests in order to prove your modification works smoothly._ 34 | 2. _Please make sure your modification passes all unit tests._ 35 | 3. _Please respect coding style of craft._ 36 | 37 | Thanks for helping! 38 | 39 | ## License 40 | See [LICENSE](https://github.com/mindwind/craft-atom/blob/master/LICENSE.txt). 41 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | mvn install -Dmaven.test.skip=true 2 | -------------------------------------------------------------------------------- /craft-atom-io/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | 4 | io.craftcode 5 | craft-atom 6 | 3.1.3-SNAPSHOT 7 | 8 | craft-atom-io 9 | ${project.artifactId} 10 | 11 | 12 | 13 | org.slf4j 14 | slf4j-api 15 | 16 | 17 | -------------------------------------------------------------------------------- /craft-atom-io/src/main/java/io/craft/atom/io/AbstractChannelEvent.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.io; 2 | 3 | import lombok.Getter; 4 | import lombok.ToString; 5 | 6 | /** 7 | * Base implementation class for common concept of channel event. 8 | * 9 | * @author mindwind 10 | * @version 1.0, Feb 26, 2013 11 | */ 12 | @ToString(of = "type") 13 | abstract public class AbstractChannelEvent { 14 | 15 | 16 | @Getter protected final ChannelEventType type; 17 | 18 | 19 | // ~ ----------------------------------------------------------------------------------------------------------- 20 | 21 | 22 | public AbstractChannelEvent(ChannelEventType type) { 23 | if (type == null) { 24 | throw new IllegalArgumentException("type == null"); 25 | } 26 | this.type = type; 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /craft-atom-io/src/main/java/io/craft/atom/io/AbstractIoByteChannel.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.io; 2 | 3 | import lombok.ToString; 4 | 5 | /** 6 | * Abstract channel transmit bytes. 7 | * 8 | * @author mindwind 9 | * @version 1.0, Feb 22, 2013 10 | */ 11 | @ToString(callSuper = true, of = {}) 12 | abstract public class AbstractIoByteChannel extends AbstractIoChannel implements Channel { 13 | 14 | public AbstractIoByteChannel() { 15 | super(); 16 | } 17 | 18 | public AbstractIoByteChannel(long id) { 19 | super(id); 20 | } 21 | 22 | public AbstractIoByteChannel(int minReadBufferSize) { 23 | super(minReadBufferSize); 24 | } 25 | 26 | public AbstractIoByteChannel(int minReadBufferSize, int defaultReadBufferSize) { 27 | super(minReadBufferSize, defaultReadBufferSize); 28 | } 29 | 30 | public AbstractIoByteChannel(int minReadBufferSize, int defaultReadBufferSize, int maxReadBufferSize) { 31 | super(minReadBufferSize, defaultReadBufferSize, maxReadBufferSize); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /craft-atom-io/src/main/java/io/craft/atom/io/AbstractIoHandler.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.io; 2 | 3 | import java.util.Arrays; 4 | 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | /** 9 | * An super abstract class for {@link IoHandler}. 10 | * Can be extended and selectively override required event handler methods only. 11 | * 12 | * @author mindwind 13 | * @version 1.0, Feb 21, 2013 14 | */ 15 | abstract public class AbstractIoHandler implements IoHandler { 16 | 17 | 18 | private static final Logger LOG = LoggerFactory.getLogger(AbstractIoHandler.class); 19 | 20 | 21 | @Override 22 | public void channelOpened(Channel channel) { 23 | LOG.debug("[CRAFT-ATOM-IO] Opened |channel={}|", channel); 24 | } 25 | 26 | @Override 27 | public void channelClosed(Channel channel) { 28 | LOG.debug("[CRAFT-ATOM-IO] Closed |channel={}|", channel); 29 | } 30 | 31 | @Override 32 | public void channelIdle(Channel channel) { 33 | LOG.debug("[CRAFT-ATOM-IO] Idle |channel={}|", channel); 34 | } 35 | 36 | @Override 37 | public void channelRead(Channel channel, byte[] bytes) { 38 | LOG.debug("[CRAFT-ATOM-IO] Read |channel={}, bytes={}|", channel, Arrays.toString(bytes)); 39 | } 40 | 41 | @Override 42 | public void channelFlush(Channel channel, byte[] bytes) { 43 | LOG.debug("[CRAFT-ATOM-IO] Flush |channel={}, bytes={}|", channel, Arrays.toString(bytes)); 44 | } 45 | 46 | @Override 47 | public void channelWritten(Channel channel, byte[] bytes) { 48 | LOG.debug("[CRAFT-ATOM-IO] Written |channel={}, bytes={}|", channel, Arrays.toString(bytes)); 49 | } 50 | 51 | @Override 52 | public void channelThrown(Channel channel, Exception cause) { 53 | LOG.warn("[CRAFT-ATOM-IO] Thrown |channel={}|", channel, cause); 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /craft-atom-io/src/main/java/io/craft/atom/io/ChannelEvent.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.io; 2 | 3 | /** 4 | * An I/O event associated with a {@link Channel}. 5 | * 6 | * @author mindwind 7 | * @version 1.0, Feb 22, 2013 8 | */ 9 | public interface ChannelEvent { 10 | 11 | /** 12 | * @return the {@link Channel} which is associated with this event. 13 | */ 14 | Channel getChannel(); 15 | 16 | /** 17 | * @return the event type. 18 | */ 19 | ChannelEventType getType(); 20 | 21 | /** 22 | * Fire the event. 23 | */ 24 | void fire(); 25 | 26 | } 27 | -------------------------------------------------------------------------------- /craft-atom-io/src/main/java/io/craft/atom/io/ChannelEventType.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.io; 2 | 3 | /** 4 | * An enumeration that represents the type of {@link ChannelEvent}. 5 | * 6 | * @author mindwind 7 | * @version 1.0, Feb 21, 2013 8 | */ 9 | public enum ChannelEventType { 10 | 11 | /** When channel has been opened, fire this event */ 12 | CHANNEL_OPENED, 13 | 14 | /** When channel has been closed, fire this event */ 15 | CHANNEL_CLOSED, 16 | 17 | /** When channel has read some data, fire this event */ 18 | CHANNEL_READ, 19 | 20 | /** When channel would flush out data in it, fire this event */ 21 | CHANNEL_FLUSH, 22 | 23 | /** When channel has written some data, fire this event */ 24 | CHANNEL_WRITTEN, 25 | 26 | /** When channel has no data transmit for a while, fire this event */ 27 | CHANNEL_IDLE, 28 | 29 | /** When channel operation throw exception, fire this event */ 30 | CHANNEL_THROWN 31 | 32 | } 33 | -------------------------------------------------------------------------------- /craft-atom-io/src/main/java/io/craft/atom/io/ChannelState.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.io; 2 | 3 | /** 4 | * The state of a {@link Channel}. 5 | * 6 | * @author mindwind 7 | * @version 1.0, Feb 21, 2013 8 | */ 9 | public enum ChannelState { 10 | 11 | /** Channel in OPEN state once a channel is created. */ 12 | OPEN, 13 | 14 | /** Channel in CLOSING state for async close operation, means in closing process. */ 15 | CLOSING, 16 | 17 | /** Channel in ClOSED state, means channel can not be used. */ 18 | CLOSED, 19 | 20 | /** Channel in PAUSED state, means pause accept new data transmit request, but data already in the buffer of channel can be transmitted. */ 21 | PAUSED 22 | 23 | } 24 | -------------------------------------------------------------------------------- /craft-atom-io/src/main/java/io/craft/atom/io/IllegalChannelStateException.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.io; 2 | 3 | /** 4 | * Unchecked exception thrown when an attempt is made to write data to channel that is not available. 5 | * 6 | * @author mindwind 7 | * @version 1.0, Aug 22, 2014 8 | */ 9 | public class IllegalChannelStateException extends IllegalStateException { 10 | 11 | 12 | private static final long serialVersionUID = 668172854459635294L; 13 | 14 | 15 | public IllegalChannelStateException() {} 16 | 17 | public IllegalChannelStateException(String message, Throwable cause) { 18 | super(message, cause); 19 | } 20 | 21 | public IllegalChannelStateException(String s) { 22 | super(s); 23 | } 24 | 25 | public IllegalChannelStateException(Throwable cause) { 26 | super(cause); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /craft-atom-io/src/main/java/io/craft/atom/io/IoAcceptor.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.io; 2 | 3 | import java.io.IOException; 4 | import java.net.SocketAddress; 5 | import java.util.Set; 6 | 7 | /** 8 | * Accepts I/O incoming request base on specific implementation. 9 | * 10 | * @author mindwind 11 | * @version 1.0, Mar 12, 2013 12 | */ 13 | public interface IoAcceptor extends IoReactor, IoAcceptorMBean { 14 | 15 | /** 16 | * Binds to specified local port with any local address and start to accept incoming request. 17 | * 18 | * @param port 19 | * @throws IOException 20 | */ 21 | void bind(int port) throws IOException; 22 | 23 | /** 24 | * Binds to the specified local addresses and start to accept incoming request. 25 | * If any address binding failed then rollback the already bound addresses. 26 | * Bind operation is fail fast, if encounter the first bind exception then throw it immediately. 27 | * 28 | * @param firstLocalAddress 29 | * @param otherLocalAddresses 30 | * @throws throw if bind failed. 31 | */ 32 | void bind(SocketAddress firstLocalAddress, SocketAddress... otherLocalAddresses) throws IOException; 33 | 34 | /** 35 | * Unbinds specified local addresses that is already bound to and stops to accept incoming connections at the port. 36 | * 37 | * @param port 38 | * @throws IOException throw if unbind failed 39 | */ 40 | void unbind(int port) throws IOException; 41 | 42 | /** 43 | * Unbinds specified local addresses that is already bound to and stops to accept incoming connections at the specified addresses. 44 | * All connections with these addresses will be closed. 45 | * 46 | *

NOTE: This method returns silently if no local address is bound yet. 47 | * 48 | * @param firstLocalAddress 49 | * @param otherLocalAddresses 50 | * @throws IOException throw if unbind failed 51 | */ 52 | void unbind(SocketAddress firstLocalAddress, SocketAddress... otherLocalAddresses) throws IOException; 53 | 54 | 55 | /** 56 | * Get currently bound addresses 57 | * 58 | * @return bound addresses 59 | */ 60 | Set getBoundAddresses(); 61 | 62 | } 63 | -------------------------------------------------------------------------------- /craft-atom-io/src/main/java/io/craft/atom/io/IoAcceptorMBean.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.io; 2 | 3 | /** 4 | * MBean for {@link IoAcceptor} 5 | * 6 | * @author mindwind 7 | * @version 1.0, Dec 24, 2013 8 | */ 9 | public interface IoAcceptorMBean { 10 | 11 | 12 | /** 13 | * @return x-ray of {@link IoAcceptor} 14 | */ 15 | IoAcceptorX x(); 16 | 17 | 18 | } 19 | -------------------------------------------------------------------------------- /craft-atom-io/src/main/java/io/craft/atom/io/IoAcceptorX.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.io; 2 | 3 | import java.net.SocketAddress; 4 | import java.util.Set; 5 | 6 | 7 | /** 8 | * The x-ray of {@link IoAcceptor} 9 | * 10 | * @author mindwind 11 | * @version 1.0, Oct 15, 2014 12 | */ 13 | public interface IoAcceptorX extends IoReactorX { 14 | 15 | /** 16 | * @return wait to bind address set. 17 | */ 18 | Set waitBindAddresses(); 19 | 20 | /** 21 | * @return wait to unbind address set. 22 | */ 23 | Set waitUnbindAddresses(); 24 | 25 | /** 26 | * @return already bound address set. 27 | */ 28 | Set boundAddresses(); 29 | 30 | } 31 | -------------------------------------------------------------------------------- /craft-atom-io/src/main/java/io/craft/atom/io/IoConfig.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.io; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | import lombok.ToString; 6 | 7 | /** 8 | * I/O common configuration object 9 | * 10 | * @author mindwind 11 | * @version 1.0, Feb 22, 2013 12 | */ 13 | @ToString(of = { "minReadBufferSize", "defaultReadBufferSize", "maxReadBufferSize", "ioTimeoutInMillis" }) 14 | public abstract class IoConfig { 15 | 16 | 17 | public static final int MIN_READ_BUFFER_SIZE = 64 ; 18 | public static final int DEFAULT_READ_BUFFER_SIZE = 2048 ; 19 | public static final int MAX_READ_BUFFER_SIZE = 65536; 20 | 21 | 22 | @Getter @Setter protected int minReadBufferSize = MIN_READ_BUFFER_SIZE ; 23 | @Getter @Setter protected int defaultReadBufferSize = DEFAULT_READ_BUFFER_SIZE; 24 | @Getter @Setter protected int maxReadBufferSize = MAX_READ_BUFFER_SIZE ; 25 | @Getter @Setter protected int ioTimeoutInMillis = 120 * 1000 ; 26 | 27 | } 28 | -------------------------------------------------------------------------------- /craft-atom-io/src/main/java/io/craft/atom/io/IoConnector.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.io; 2 | 3 | import java.io.IOException; 4 | import java.net.SocketAddress; 5 | import java.util.concurrent.Future; 6 | 7 | /** 8 | * Connects to server based on specific implementation. 9 | * 10 | * @author mindwind 11 | * @version 1.0, Mar 12, 2013 12 | */ 13 | public interface IoConnector extends IoReactor, IoConnectorMBean { 14 | 15 | /** 16 | * Connects to the specified ip and port. 17 | * 18 | * @param ip 19 | * @param port 20 | * @return Future instance which is completed when the channel initiated by this call succeeds or fails. 21 | * @throws IOException If some other I/O error occurs 22 | */ 23 | Future> connect(String ip, int port) throws IOException; 24 | 25 | /** 26 | * Connects to the specified remote address. 27 | * 28 | * @param remoteAddress 29 | * @return Future instance which is completed when the channel initiated by this call succeeds or fails. 30 | * @throws IOException If some other I/O error occurs 31 | */ 32 | Future> connect(SocketAddress remoteAddress) throws IOException; 33 | 34 | 35 | /** 36 | * Connects to the specified remote address and binds to the specified local address. 37 | * 38 | * @param remoteAddress 39 | * @param localAddress 40 | * @return Future instance which is completed when the channel initiated by this call succeeds or fails. 41 | * @throws IOException If some other I/O error occurs 42 | */ 43 | Future> connect(SocketAddress remoteAddress, SocketAddress localAddress) throws IOException; 44 | } 45 | -------------------------------------------------------------------------------- /craft-atom-io/src/main/java/io/craft/atom/io/IoConnectorMBean.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.io; 2 | 3 | /** 4 | * MBean for {@link IoConnector} 5 | * 6 | * @author mindwind 7 | * @version 1.0, Dec 25, 2013 8 | */ 9 | public interface IoConnectorMBean { 10 | 11 | /** 12 | * @return x-ray of {@link IoConnector} 13 | */ 14 | IoConnectorX x(); 15 | 16 | } 17 | -------------------------------------------------------------------------------- /craft-atom-io/src/main/java/io/craft/atom/io/IoConnectorX.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.io; 2 | 3 | /** 4 | * The x-ray of {@link IoConnector} 5 | * 6 | * @author mindwind 7 | * @version 1.0, Oct 15, 2014 8 | */ 9 | public interface IoConnectorX extends IoReactorX { 10 | 11 | 12 | /** 13 | * @return current connecting channel count. 14 | */ 15 | int connectingChannelCount(); 16 | 17 | /** 18 | * @return current disconnecting channel count. 19 | */ 20 | int disconnectingChannelCount(); 21 | 22 | } 23 | -------------------------------------------------------------------------------- /craft-atom-io/src/main/java/io/craft/atom/io/IoHandler.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.io; 2 | 3 | import java.io.IOException; 4 | 5 | /** 6 | * Handles I/O events fired by craft-atom-io series component. 7 | * 8 | * @author mindwind 9 | * @version 1.0, Feb 20, 2013 10 | */ 11 | public interface IoHandler { 12 | 13 | /** 14 | * Invoked when channel opened. 15 | * 16 | * @param channel 17 | */ 18 | void channelOpened(Channel channel); 19 | 20 | /** 21 | * Invoked when channel closed. 22 | * 23 | * @param channel 24 | */ 25 | void channelClosed(Channel channel); 26 | 27 | 28 | /** 29 | * Invoked when channel is idle, idle means there is no data transmission (read or write). 30 | * 31 | * @param channel 32 | */ 33 | void channelIdle(Channel channel); 34 | 35 | /** 36 | * Invoked when channel has read some bytes. 37 | * 38 | * @param channel 39 | * @param bytes 40 | */ 41 | void channelRead(Channel channel, byte[] bytes); 42 | 43 | /** 44 | * Invoked when channel would flush out some bytes. 45 | * 46 | * @param channel 47 | * @param bytes 48 | */ 49 | void channelFlush(Channel channel, byte[] bytes); 50 | 51 | /** 52 | * Invoked when channel has written some bytes. 53 | * 54 | * @param channel 55 | * @param bytes 56 | */ 57 | void channelWritten(Channel channel, byte[] bytes); 58 | 59 | /** 60 | * Invoked when any exception is thrown. 61 | * If cause is an instance of {@link IOException} channel should be closed. 62 | * 63 | * @param channel 64 | * @param cause 65 | */ 66 | void channelThrown(Channel channel, Exception cause); 67 | } 68 | -------------------------------------------------------------------------------- /craft-atom-io/src/main/java/io/craft/atom/io/IoProcessor.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.io; 2 | 3 | /** 4 | * Process I/O read and write, it is a mark interface, any class implements it indicate it is a I/O processor. 5 | * 6 | * @author mindwind 7 | * @version 1.0, Feb 8, 2014 8 | */ 9 | public interface IoProcessor extends IoReactor, IoProcessorMBean { 10 | 11 | } 12 | -------------------------------------------------------------------------------- /craft-atom-io/src/main/java/io/craft/atom/io/IoProcessorMBean.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.io; 2 | 3 | /** 4 | * MBean for {@link IoProcessor} 5 | * 6 | * @author mindwind 7 | * @version 1.0, Feb 8, 2014 8 | */ 9 | public interface IoProcessorMBean { 10 | 11 | 12 | /** 13 | * @return x-ray of {@link IoProcessor} 14 | */ 15 | IoProcessorX x(); 16 | 17 | 18 | } 19 | -------------------------------------------------------------------------------- /craft-atom-io/src/main/java/io/craft/atom/io/IoProcessorX.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.io; 2 | 3 | 4 | /** 5 | * The x-ray of {@link IoProcessor} 6 | * 7 | * @author mindwind 8 | * @version 1.0, Oct 15, 2014 9 | */ 10 | public interface IoProcessorX extends IoReactorX { 11 | 12 | 13 | } 14 | -------------------------------------------------------------------------------- /craft-atom-io/src/main/java/io/craft/atom/io/IoProtocol.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.io; 2 | 3 | /** 4 | * I/O protocol enumeration 5 | * 6 | * @author mindwind 7 | * @version 1.0, Feb 24, 2013 8 | */ 9 | public enum IoProtocol { 10 | TCP, UDP 11 | } 12 | -------------------------------------------------------------------------------- /craft-atom-io/src/main/java/io/craft/atom/io/IoReactor.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.io; 2 | 3 | 4 | /** 5 | * Abstracts reactor model, base api interface. 6 | * 7 | * @author mindwind 8 | * @version 1.0, Mar 12, 2013 9 | * @see IoAcceptor 10 | * @see IoConnector 11 | * @see IoProcessor 12 | */ 13 | public interface IoReactor { 14 | 15 | 16 | /** 17 | * Releases any resources allocated by this reactor. 18 | */ 19 | void shutdown(); 20 | 21 | /** 22 | * Returns the io handler associates with the reactor 23 | */ 24 | IoHandler getHandler(); 25 | 26 | } 27 | -------------------------------------------------------------------------------- /craft-atom-io/src/main/java/io/craft/atom/io/IoReactorX.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.io; 2 | 3 | /** 4 | * The x-ray of {@link IoReactor} 5 | * 6 | * @author mindwind 7 | * @version 1.0, Oct 15, 2014 8 | */ 9 | public interface IoReactorX { 10 | 11 | 12 | /** 13 | * @return current alive channel count. 14 | */ 15 | int aliveChannelCount(); 16 | 17 | /** 18 | * @return current new channel to be processed count. 19 | */ 20 | int newChannelCount(); 21 | 22 | /** 23 | * @return current flushing channel count. 24 | */ 25 | int flushingChannelCount(); 26 | 27 | /** 28 | * @return current closing channel count. 29 | */ 30 | int closingChannelCount(); 31 | 32 | } 33 | -------------------------------------------------------------------------------- /craft-atom-lock/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | 4 | io.craftcode 5 | craft-atom 6 | 3.1.3-SNAPSHOT 7 | 8 | ${project.artifactId} 9 | craft-atom-lock 10 | 11 | 12 | 13 | ${project.groupId} 14 | craft-atom-redis 15 | ${project.version} 16 | 17 | 18 | ${project.groupId} 19 | craft-atom-test 20 | ${project.version} 21 | test 22 | 23 | 24 | org.slf4j 25 | slf4j-api 26 | 27 | 28 | -------------------------------------------------------------------------------- /craft-atom-lock/src/main/java/io/craft/atom/lock/api/DLock.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.lock.api; 2 | 3 | import java.util.concurrent.TimeUnit; 4 | 5 | /** 6 | * {@code DLock} is the abbreviation of distributed lock. 7 | *

8 | * A distributed lock is a tool for controlling access to a shared resource by multiple threads or processes. 9 | * Commonly, a distributed lock provides exclusive access to a shared resource: only one thread at a time can acquire the lock and all access to the shared resource requires that the lock be acquired first. 10 | * 11 | * @author mindwind 12 | * @version 1.0, Nov 19, 2012 13 | */ 14 | public interface DLock { 15 | 16 | /** 17 | * Acquires the lock with specified lock key if it is free within the given TTL time. 18 | *

19 | * If the lock is available this method returns immediately with the value true, otherwise false 20 | * 21 | * @param lockKey lock key resource, which associated with a shared resource 22 | * @param ttl lock time to live 23 | * @param unit time unit for ttl 24 | * @return true if the lock was acquired and false if lock acquired failed. 25 | */ 26 | boolean tryLock(String lockKey, int ttl, TimeUnit unit); 27 | 28 | /** 29 | * Releases the lock with specified lock key. 30 | *

31 | * Tip: make sure you hold the lock, you release lock by invoking {@link #unlock(String)} 32 | * 33 | * @param lockKey 34 | * @return true if the lock was released and false if lock released failed. 35 | */ 36 | boolean unlock(String lockKey); 37 | } 38 | -------------------------------------------------------------------------------- /craft-atom-lock/src/main/java/io/craft/atom/lock/api/DLockFactory.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.lock.api; 2 | 3 | import io.craft.atom.lock.Redis24DLock; 4 | import io.craft.atom.lock.Redis26DLock; 5 | import io.craft.atom.lock.ShardedRedis24DLock; 6 | import io.craft.atom.lock.ShardedRedis26DLock; 7 | import io.craft.atom.redis.api.RedisCommand; 8 | import io.craft.atom.redis.api.ShardedRedisCommand; 9 | 10 | 11 | /** 12 | * Distributed lock factory 13 | * 14 | * @author mindwind 15 | * @version 1.0, Jul 16, 2013 16 | */ 17 | public class DLockFactory { 18 | 19 | /** 20 | * @param redis 21 | * @return new distributed lock base on singleton redis version 2.4.x 22 | */ 23 | public static DLock newRedis24DLock(RedisCommand redis) { 24 | return new Redis24DLock(redis); 25 | } 26 | 27 | /** 28 | * @param redis 29 | * @return new distributed lock base on sharded redis version 2.4.x 30 | */ 31 | public static DLock newRedis24DLock(ShardedRedisCommand redis) { 32 | return new ShardedRedis24DLock(redis); 33 | } 34 | 35 | /** 36 | * @param redis 37 | * @return new distributed lock base on singleton redis version 2.6.12+ 38 | */ 39 | public static DLock newRedis26DLock(RedisCommand redis) { 40 | return new Redis26DLock(redis); 41 | } 42 | 43 | /** 44 | * @param redis 45 | * @return new distributed lock base on sharded redis version 2.6.x 46 | */ 47 | public static DLock newRedis26DLock(ShardedRedisCommand redis) { 48 | return new ShardedRedis26DLock(redis); 49 | } 50 | 51 | /** 52 | * @deprecated replace by {@link #newRedis24DLock(ShardedRedisCommand)} 53 | * @param redis 54 | * @return new distributed lock base on sharded redis version 2.4.x 55 | */ 56 | public static DLock newShardedRedis24DLock(ShardedRedisCommand redis) { 57 | return new ShardedRedis24DLock(redis); 58 | } 59 | 60 | /** 61 | * @deprecated replace by {@link #newRedis26DLock(ShardedRedisCommand)} 62 | * @param redis 63 | * @return new distributed lock base on sharded redis version 2.6.12+ 64 | */ 65 | public static DLock newShardedRedis26DLock(ShardedRedisCommand redis) { 66 | return new ShardedRedis26DLock(redis); 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /craft-atom-lock/src/test/java/io/craft/atom/lock/AbstractDLockTests.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.lock; 2 | 3 | import io.craft.atom.lock.api.DLock; 4 | import io.craft.atom.lock.api.DLockFactory; 5 | import io.craft.atom.redis.api.Redis; 6 | import io.craft.atom.redis.api.RedisFactory; 7 | import io.craft.atom.redis.api.ShardedRedis; 8 | 9 | import org.junit.Assert; 10 | 11 | /** 12 | * @author mindwind 13 | * @version 1.0, Dec 22, 2013 14 | */ 15 | public abstract class AbstractDLockTests { 16 | 17 | protected Redis redis1 ; 18 | protected Redis redis2 ; 19 | protected DLock dLock ; 20 | protected ShardedRedis shardedRedis; 21 | protected DLock shardedDLock; 22 | 23 | 24 | public AbstractDLockTests() { 25 | init(); 26 | selfcheck(); 27 | } 28 | 29 | private void init() { 30 | redis1 = RedisFactory.newRedis("localhost", 6379) ; 31 | redis2 = RedisFactory.newRedis("localhost", 6380) ; 32 | shardedRedis = RedisFactory.newShardedRedis(redis1, redis2); 33 | dLock = DLockFactory.newRedis24DLock(redis1) ; 34 | shardedDLock = DLockFactory.newRedis24DLock(shardedRedis) ; 35 | } 36 | 37 | private void selfcheck() { 38 | try { 39 | redis1.ping(); 40 | } catch (Exception e) { 41 | e.printStackTrace(); 42 | System.err.println("[CRAFT-ATOM-LOCK] Self check for redis1 fail"); 43 | Assert.fail(); 44 | } 45 | 46 | try { 47 | redis2.ping(); 48 | } catch (Exception e) { 49 | e.printStackTrace(); 50 | System.err.println("[CRAFT-ATOM-LOCK] Self check for redis2 fail"); 51 | Assert.fail(); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /craft-atom-lock/src/test/java/io/craft/atom/lock/TestRedis24DLock.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.lock; 2 | 3 | import io.craft.atom.test.CaseCounter; 4 | 5 | import java.util.concurrent.TimeUnit; 6 | 7 | import junit.framework.Assert; 8 | 9 | import org.junit.Before; 10 | import org.junit.Test; 11 | 12 | 13 | /** 14 | * @author mindwind 15 | * @version 1.0, Dec 22, 2013 16 | */ 17 | public class TestRedis24DLock extends AbstractDLockTests { 18 | 19 | 20 | private String lockKey = "redis24.dlock"; 21 | 22 | 23 | // ~ ------------------------------------------------------------------------------------------------------------- 24 | 25 | 26 | public TestRedis24DLock() { 27 | super(); 28 | } 29 | 30 | @Before 31 | public void before() { 32 | redis1.flushall(); 33 | } 34 | 35 | 36 | // ~ ------------------------------------------------------------------------------------------------------------- 37 | 38 | 39 | @Test 40 | public void testTryLockFalse() { 41 | // WATCH: lock=true GET: lock=true -> LOCK: false 42 | // WATCH: lock=true GET: lock=false -> LOCK: false 43 | // WATCH: lock=false GET: lock=true -> LOCK: false 44 | redis1.set(lockKey, "1"); 45 | boolean b = dLock.tryLock(lockKey, 30, TimeUnit.SECONDS); 46 | Assert.assertFalse(b); 47 | System.out.println(String.format("[CRAFT-ATOM-REDIS] (^_^) <%s> Case -> test try lock false. ", CaseCounter.incr(1))); 48 | } 49 | 50 | @Test 51 | public void testTryLockTrue() { 52 | // WATCH: lock=false GET: lock=false -> LOCK: true 53 | redis1.del(lockKey); 54 | boolean b = dLock.tryLock(lockKey, 30, TimeUnit.SECONDS); 55 | Assert.assertTrue(b); 56 | System.out.println(String.format("[CRAFT-ATOM-REDIS] (^_^) <%s> Case -> test try lock true. ", CaseCounter.incr(1))); 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /craft-atom-lock/src/test/java/io/craft/atom/lock/TestShardedRedis24DLock.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.lock; 2 | 3 | import io.craft.atom.test.CaseCounter; 4 | 5 | import java.util.concurrent.TimeUnit; 6 | 7 | import junit.framework.Assert; 8 | 9 | import org.junit.Before; 10 | import org.junit.Test; 11 | 12 | 13 | /** 14 | * @author mindwind 15 | * @version 1.0, Dec 22, 2013 16 | */ 17 | public class TestShardedRedis24DLock extends AbstractDLockTests { 18 | 19 | 20 | private String lockKey = "sharded.redis24.dlock"; 21 | 22 | 23 | // ~ ------------------------------------------------------------------------------------------------------------- 24 | 25 | 26 | public TestShardedRedis24DLock() { 27 | super(); 28 | } 29 | 30 | @Before 31 | public void before() { 32 | redis1.flushall(); 33 | } 34 | 35 | 36 | // ~ ------------------------------------------------------------------------------------------------------------- 37 | 38 | 39 | @Test 40 | public void testTryLockFalse() { 41 | // WATCH: lock=true GET: lock=true -> LOCK: false 42 | // WATCH: lock=true GET: lock=false -> LOCK: false 43 | // WATCH: lock=false GET: lock=true -> LOCK: false 44 | shardedRedis.set(lockKey, lockKey, "1"); 45 | boolean b = shardedDLock.tryLock(lockKey, 30, TimeUnit.SECONDS); 46 | Assert.assertFalse(b); 47 | System.out.println(String.format("[CRAFT-ATOM-REDIS] (^_^) <%s> Case -> test try lock false. ", CaseCounter.incr(1))); 48 | } 49 | 50 | @Test 51 | public void testTryLockTrue() { 52 | // WATCH: lock=false GET: lock=false -> LOCK: true 53 | shardedRedis.del(lockKey, lockKey); 54 | boolean b = shardedDLock.tryLock(lockKey, 30, TimeUnit.SECONDS); 55 | Assert.assertTrue(b); 56 | System.out.println(String.format("[CRAFT-ATOM-REDIS] (^_^) <%s> Case -> test try lock true. ", CaseCounter.incr(1))); 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /craft-atom-nio/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | 4 | 5 | io.craftcode 6 | craft-atom 7 | 3.1.3-SNAPSHOT 8 | 9 | 10 | craft-atom-nio 11 | ${project.artifactId} 12 | 13 | 14 | 15 | ${project.groupId} 16 | craft-atom-test 17 | ${project.version} 18 | test 19 | 20 | 21 | ${project.groupId} 22 | craft-atom-io 23 | ${project.version} 24 | 25 | 26 | ${project.groupId} 27 | craft-atom-util 28 | ${project.version} 29 | 30 | 31 | org.slf4j 32 | slf4j-api 33 | 34 | 35 | -------------------------------------------------------------------------------- /craft-atom-nio/src/main/java/io/craft/atom/nio/AbstractNioByteChannelEvent.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.nio; 2 | 3 | import io.craft.atom.io.AbstractChannelEvent; 4 | import io.craft.atom.io.Channel; 5 | import io.craft.atom.io.ChannelEvent; 6 | import io.craft.atom.io.ChannelEventType; 7 | import lombok.ToString; 8 | 9 | 10 | /** 11 | * @author mindwind 12 | * @version 1.0, Feb 26, 2013 13 | */ 14 | @ToString(callSuper = true, of = "channel") 15 | abstract public class AbstractNioByteChannelEvent extends AbstractChannelEvent implements ChannelEvent { 16 | 17 | 18 | protected final NioByteChannel channel; 19 | 20 | 21 | // ~ -------------------------------------------------------------------------------------------------------------- 22 | 23 | 24 | AbstractNioByteChannelEvent(ChannelEventType type, NioByteChannel channel) { 25 | super(type); 26 | if (channel == null) { 27 | throw new IllegalArgumentException("channel == null"); 28 | } 29 | this.channel = channel; 30 | } 31 | 32 | 33 | // ~ -------------------------------------------------------------------------------------------------------------- 34 | 35 | 36 | @Override 37 | public Channel getChannel() { 38 | return channel; 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /craft-atom-nio/src/main/java/io/craft/atom/nio/NioAcceptorX.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.nio; 2 | 3 | import io.craft.atom.io.IoAcceptorX; 4 | 5 | import java.net.SocketAddress; 6 | import java.util.Set; 7 | 8 | import lombok.Getter; 9 | import lombok.Setter; 10 | import lombok.ToString; 11 | 12 | 13 | /** 14 | * @author mindwind 15 | * @version 1.0, Oct 15, 2014 16 | */ 17 | @ToString 18 | public class NioAcceptorX extends NioReactorX implements IoAcceptorX { 19 | 20 | 21 | @Getter @Setter private Set waitBindAddresses ; 22 | @Getter @Setter private Set waitUnbindAddresses; 23 | @Getter @Setter private Set boundAddresses ; 24 | 25 | 26 | @Override 27 | public Set waitBindAddresses() { 28 | return waitBindAddresses; 29 | } 30 | 31 | @Override 32 | public Set waitUnbindAddresses() { 33 | return waitUnbindAddresses; 34 | } 35 | 36 | @Override 37 | public Set boundAddresses() { 38 | return boundAddresses; 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /craft-atom-nio/src/main/java/io/craft/atom/nio/NioAdaptiveBufferSizePredictorFactory.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.nio; 2 | 3 | import io.craft.atom.nio.spi.NioBufferSizePredictor; 4 | import io.craft.atom.nio.spi.NioBufferSizePredictorFactory; 5 | 6 | /** 7 | * @author mindwind 8 | * @version 1.0, Feb 24, 2013 9 | */ 10 | public class NioAdaptiveBufferSizePredictorFactory implements NioBufferSizePredictorFactory { 11 | 12 | @Override 13 | public NioBufferSizePredictor newPredictor(int minimum, int initial, int maximum) { 14 | return new NioAdaptiveBufferSizePredictor(minimum, initial, maximum); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /craft-atom-nio/src/main/java/io/craft/atom/nio/NioConfig.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.nio; 2 | 3 | import io.craft.atom.io.IoConfig; 4 | import lombok.Getter; 5 | import lombok.Setter; 6 | import lombok.ToString; 7 | 8 | 9 | /** 10 | * Nio component common configuration object. 11 | * 12 | * @author mindwind 13 | * @version 1.0, Feb 21, 2013 14 | */ 15 | @ToString(callSuper = true, of = { "processorPoolSize", "executorSize", "readWritefair", "channelEventSize", "totalEventSize" }) 16 | abstract public class NioConfig extends IoConfig { 17 | 18 | 19 | @Getter protected int processorPoolSize = Runtime.getRuntime().availableProcessors(); 20 | @Getter @Setter protected int executorSize = processorPoolSize << 3 ; 21 | @Getter @Setter protected boolean readWritefair = true ; 22 | @Getter protected int channelEventSize = Integer.MAX_VALUE ; 23 | @Getter protected int totalEventSize = Integer.MAX_VALUE ; 24 | 25 | 26 | // ~ ------------------------------------------------------------------------------------------------------------- 27 | 28 | 29 | public void setProcessorPoolSize(int processorPoolSize) { 30 | if (processorPoolSize <= 0) { 31 | throw new IllegalArgumentException("processor pool size must > 0"); 32 | } 33 | 34 | this.processorPoolSize = processorPoolSize; 35 | } 36 | 37 | public void setChannelEventSize(int channelEventSize) { 38 | if (channelEventSize <= 0) { 39 | channelEventSize = Integer.MAX_VALUE; 40 | } 41 | 42 | this.channelEventSize = channelEventSize; 43 | } 44 | 45 | public void setTotalEventSize(int totalEventSize) { 46 | if (totalEventSize <= 0) { 47 | totalEventSize = Integer.MAX_VALUE; 48 | } 49 | 50 | this.totalEventSize = totalEventSize; 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /craft-atom-nio/src/main/java/io/craft/atom/nio/NioConnectorX.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.nio; 2 | 3 | import io.craft.atom.io.IoConnectorX; 4 | import lombok.Getter; 5 | import lombok.Setter; 6 | import lombok.ToString; 7 | 8 | 9 | /** 10 | * @author mindwind 11 | * @version 1.0, Oct 15, 2014 12 | */ 13 | @ToString 14 | public class NioConnectorX extends NioReactorX implements IoConnectorX { 15 | 16 | 17 | @Getter @Setter private int connectingChannelCount ; 18 | @Getter @Setter private int disconnectingChannelCount; 19 | 20 | 21 | @Override 22 | public int connectingChannelCount() { 23 | return connectingChannelCount; 24 | } 25 | 26 | @Override 27 | public int disconnectingChannelCount() { 28 | return disconnectingChannelCount; 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /craft-atom-nio/src/main/java/io/craft/atom/nio/NioOrderedDirectChannelEventDispatcher.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.nio; 2 | 3 | import io.craft.atom.io.ChannelEvent; 4 | import io.craft.atom.nio.spi.AbstractNioChannelEventDispatcher; 5 | import io.craft.atom.nio.spi.NioChannelEventDispatcher; 6 | import lombok.ToString; 7 | 8 | 9 | /** 10 | * An {@link NioChannelEventDispatcher} that maintains order of {@link NioByteChannelEvent} in the same channel. 11 | * It use io process thread pool to dispatch event. 12 | * 13 | * @author mindwind 14 | * @version 1.0, Feb 22, 2013 15 | */ 16 | @ToString(callSuper = true) 17 | public class NioOrderedDirectChannelEventDispatcher extends AbstractNioChannelEventDispatcher { 18 | 19 | 20 | public NioOrderedDirectChannelEventDispatcher() { 21 | super(); 22 | } 23 | 24 | public NioOrderedDirectChannelEventDispatcher(int totalEventSize) { 25 | super(totalEventSize); 26 | } 27 | 28 | 29 | // ~ ------------------------------------------------------------------------------------------------------------ 30 | 31 | 32 | @Override 33 | public void dispatch(ChannelEvent event) { 34 | NioByteChannel channel = (NioByteChannel) event.getChannel(); 35 | beforeDispatch(channel); 36 | try { 37 | event.fire(); 38 | } finally { 39 | afterDispatch(channel); 40 | } 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /craft-atom-nio/src/main/java/io/craft/atom/nio/NioProcessorX.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.nio; 2 | 3 | import io.craft.atom.io.IoProcessorX; 4 | 5 | /** 6 | * @author mindwind 7 | * @version 1.0, Oct 15, 2014 8 | */ 9 | public class NioProcessorX extends NioReactorX implements IoProcessorX { 10 | 11 | } 12 | -------------------------------------------------------------------------------- /craft-atom-nio/src/main/java/io/craft/atom/nio/NioReactor.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.nio; 2 | 3 | import io.craft.atom.io.IoHandler; 4 | import io.craft.atom.io.IoProcessorX; 5 | import io.craft.atom.io.IoReactor; 6 | import io.craft.atom.io.IoReactorX; 7 | import io.craft.atom.nio.spi.NioBufferSizePredictorFactory; 8 | import io.craft.atom.nio.spi.NioChannelEventDispatcher; 9 | import lombok.ToString; 10 | 11 | 12 | /** 13 | * Nio component provide a reactor pattern implementation. {@link NioReactor } 14 | * Represents a base reactor object. 15 | * 16 | * @author mindwind 17 | * @version 1.0, Feb 21, 2013 18 | * @see NioAcceptor 19 | * @see NioProcessor 20 | * @see NioConnector 21 | */ 22 | @ToString(of = { "handler", "dispatcher", "predictorFactory" }) 23 | abstract public class NioReactor implements IoReactor { 24 | 25 | 26 | protected IoHandler handler ; 27 | protected NioChannelEventDispatcher dispatcher ; 28 | protected NioBufferSizePredictorFactory predictorFactory; 29 | protected NioProcessorPool pool ; 30 | 31 | 32 | // ~ ---------------------------------------------------------------------------------------------------------- 33 | 34 | 35 | @Override 36 | public void shutdown() { 37 | dispatcher.shutdown(); 38 | pool.shutdown(); 39 | } 40 | 41 | @Override 42 | public IoHandler getHandler() { 43 | return handler; 44 | } 45 | 46 | public NioChannelEventDispatcher getDispatcher() { 47 | return dispatcher; 48 | } 49 | 50 | public NioBufferSizePredictorFactory getPredictorFactory() { 51 | return predictorFactory; 52 | } 53 | 54 | protected IoReactorX x() { 55 | NioReactorX x = new NioReactorX(); 56 | NioProcessor[] nps = pool.getPool(); 57 | int nc = 0; 58 | int fc = 0; 59 | int cc = 0; 60 | for (NioProcessor np : nps) { 61 | IoProcessorX px = np.x(); 62 | nc += px.newChannelCount(); 63 | fc += px.flushingChannelCount(); 64 | cc += px.closingChannelCount(); 65 | } 66 | x.setNewChannelCount(nc); 67 | x.setFlushingChannelCount(fc); 68 | x.setClosingChannelCount(cc); 69 | x.setAliveChannelCount(pool.getIdleTimer().aliveChannels().size()); 70 | return x; 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /craft-atom-nio/src/main/java/io/craft/atom/nio/NioReactorX.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.nio; 2 | 3 | import io.craft.atom.io.IoReactorX; 4 | import lombok.Getter; 5 | import lombok.Setter; 6 | import lombok.ToString; 7 | 8 | 9 | /** 10 | * @author mindwind 11 | * @version 1.0, Oct 15, 2014 12 | */ 13 | @ToString 14 | public class NioReactorX implements IoReactorX { 15 | 16 | 17 | @Getter @Setter private int aliveChannelCount ; 18 | @Getter @Setter private int newChannelCount ; 19 | @Getter @Setter private int flushingChannelCount; 20 | @Getter @Setter private int closingChannelCount ; 21 | 22 | 23 | @Override 24 | public int aliveChannelCount() { 25 | return aliveChannelCount; 26 | } 27 | 28 | @Override 29 | public int newChannelCount() { 30 | return newChannelCount; 31 | } 32 | 33 | @Override 34 | public int flushingChannelCount() { 35 | return flushingChannelCount; 36 | } 37 | 38 | @Override 39 | public int closingChannelCount() { 40 | return closingChannelCount; 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /craft-atom-nio/src/main/java/io/craft/atom/nio/NioUdpByteChannel.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.nio; 2 | 3 | import io.craft.atom.nio.spi.NioBufferSizePredictor; 4 | import io.craft.atom.nio.spi.NioChannelEventDispatcher; 5 | 6 | import java.io.IOException; 7 | import java.net.SocketAddress; 8 | import java.nio.ByteBuffer; 9 | import java.nio.channels.DatagramChannel; 10 | import java.nio.channels.SelectableChannel; 11 | 12 | import lombok.ToString; 13 | 14 | 15 | /** 16 | * A nio channel for datagram-oriented sockets. 17 | * 18 | * @author mindwind 19 | * @version 1.0, Feb 22, 2013 20 | */ 21 | @ToString(callSuper = true) 22 | public class NioUdpByteChannel extends NioByteChannel { 23 | 24 | 25 | private DatagramChannel datagramChannel; 26 | 27 | 28 | public NioUdpByteChannel(DatagramChannel datagramChannel, NioConfig config, NioBufferSizePredictor predictor, NioChannelEventDispatcher dispatcher) { 29 | super(config, predictor, dispatcher); 30 | 31 | if (datagramChannel == null) { 32 | throw new IllegalArgumentException("DatagramChannel can not be null."); 33 | } 34 | 35 | this.datagramChannel = datagramChannel; 36 | this.localAddress = datagramChannel.socket().getLocalSocketAddress(); 37 | } 38 | 39 | @Override 40 | protected SocketAddress readUdp(ByteBuffer buf) throws IOException { 41 | return datagramChannel.receive(buf); 42 | } 43 | 44 | @Override 45 | protected int writeUdp(ByteBuffer buf, SocketAddress target) throws IOException { 46 | return datagramChannel.send(buf, target); 47 | } 48 | 49 | @Override 50 | protected SelectableChannel innerChannel() { 51 | return datagramChannel; 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /craft-atom-nio/src/main/java/io/craft/atom/nio/api/NioAcceptorConfig.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.nio.api; 2 | 3 | import io.craft.atom.nio.NioConfig; 4 | import io.craft.atom.nio.NioTcpAcceptor; 5 | import lombok.Getter; 6 | import lombok.Setter; 7 | import lombok.ToString; 8 | 9 | 10 | /** 11 | * Configuration object for {@link NioTcpAcceptor} 12 | * 13 | * @author mindwind 14 | * @version 1.0, Feb 22, 2013 15 | */ 16 | @ToString(callSuper = true, of = { "reuseAddress", "backlog" }) 17 | public class NioAcceptorConfig extends NioConfig { 18 | 19 | 20 | @Getter @Setter private boolean reuseAddress = true ; 21 | @Getter @Setter private int channelSize = Integer.MAX_VALUE; 22 | @Getter private int backlog = 50 ; 23 | 24 | 25 | // ~ --------------------------------------------------------------------------------------------------------------- 26 | 27 | 28 | public void setBacklog(int backlog) { 29 | this.backlog = (backlog <= 0 ? 50 : backlog); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /craft-atom-nio/src/main/java/io/craft/atom/nio/api/NioConnectorConfig.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.nio.api; 2 | 3 | import io.craft.atom.nio.NioConfig; 4 | import io.craft.atom.nio.NioConnector; 5 | import lombok.Getter; 6 | import lombok.Setter; 7 | import lombok.ToString; 8 | 9 | 10 | /** 11 | * Configuration object for {@link NioConnector} 12 | * 13 | * @author mindwind 14 | * @version 1.0, Feb 24, 2013 15 | */ 16 | @ToString(callSuper = true, of = "connectTimeoutInMillis") 17 | public class NioConnectorConfig extends NioConfig { 18 | 19 | /** 2 seconds as default connect timeout */ 20 | @Getter @Setter private int connectTimeoutInMillis = 2000; 21 | 22 | } 23 | -------------------------------------------------------------------------------- /craft-atom-nio/src/main/java/io/craft/atom/nio/api/NioTcpAcceptorBuilder.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.nio.api; 2 | 3 | import io.craft.atom.io.IoAcceptor; 4 | import io.craft.atom.io.IoHandler; 5 | import io.craft.atom.nio.NioTcpAcceptor; 6 | 7 | 8 | /** 9 | * Builder for {@link NioTcpAcceptor} 10 | * 11 | * @author mindwind 12 | * @version 1.0, Mar 7, 2014 13 | */ 14 | public class NioTcpAcceptorBuilder extends NioBuilder { 15 | 16 | 17 | private int backlog = 50 ; 18 | private int channelSize = Integer.MAX_VALUE; 19 | private boolean reuseAddress = true ; 20 | 21 | 22 | public NioTcpAcceptorBuilder(IoHandler handler) { 23 | super(handler); 24 | } 25 | 26 | 27 | public NioTcpAcceptorBuilder backlog (int backlog) { this.backlog = backlog ; return this; } 28 | public NioTcpAcceptorBuilder channelSize (int channelSize) { this.channelSize = channelSize ; return this; } 29 | public NioTcpAcceptorBuilder reuseAddress(boolean reuseAddress) { this.reuseAddress = reuseAddress; return this; } 30 | 31 | 32 | public IoAcceptor build() { 33 | NioAcceptorConfig config = new NioAcceptorConfig(); 34 | config.setBacklog(backlog); 35 | config.setChannelSize(channelSize); 36 | config.setReuseAddress(reuseAddress); 37 | set(config); 38 | return new NioTcpAcceptor(handler, config, dispatcher, predictorFactory); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /craft-atom-nio/src/main/java/io/craft/atom/nio/api/NioTcpConnectorBuilder.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.nio.api; 2 | 3 | import io.craft.atom.io.IoConnector; 4 | import io.craft.atom.io.IoHandler; 5 | import io.craft.atom.nio.NioTcpConnector; 6 | 7 | 8 | /** 9 | * Builder for {@link NioTcpConnector} 10 | * 11 | * @author mindwind 12 | * @version 1.0, Mar 7, 2014 13 | */ 14 | public class NioTcpConnectorBuilder extends NioBuilder { 15 | 16 | 17 | private int connectTimeoutInMillis = 2000; 18 | 19 | 20 | public NioTcpConnectorBuilder(IoHandler handler) { 21 | super(handler); 22 | } 23 | 24 | 25 | public NioTcpConnectorBuilder connectTimeoutInMillis(int timeout) { this.connectTimeoutInMillis = timeout; return this; } 26 | 27 | 28 | public IoConnector build() { 29 | NioConnectorConfig config = new NioConnectorConfig(); 30 | config.setConnectTimeoutInMillis(connectTimeoutInMillis); 31 | set(config); 32 | return new NioTcpConnector(handler, config, dispatcher, predictorFactory); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /craft-atom-nio/src/main/java/io/craft/atom/nio/spi/AbstractNioChannelEventDispatcher.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.nio.spi; 2 | 3 | import io.craft.atom.nio.NioByteChannel; 4 | 5 | import java.util.concurrent.Semaphore; 6 | 7 | import lombok.ToString; 8 | 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | 12 | 13 | /** 14 | * Base implementation of {@link NioChannelEventDispatcher} 15 | * 16 | * @author mindwind 17 | * @version 1.0, Feb 27, 2013 18 | */ 19 | @ToString(of = { "semaphore" }) 20 | abstract public class AbstractNioChannelEventDispatcher implements NioChannelEventDispatcher { 21 | 22 | 23 | private static final Logger LOG = LoggerFactory.getLogger(AbstractNioChannelEventDispatcher.class); 24 | 25 | 26 | protected final Semaphore semaphore; 27 | 28 | 29 | // ~ ------------------------------------------------------------------------------------------------------------ 30 | 31 | 32 | public AbstractNioChannelEventDispatcher() { 33 | this(Integer.MAX_VALUE); 34 | } 35 | 36 | public AbstractNioChannelEventDispatcher(int totalEventSize) { 37 | if (totalEventSize <= 0) { 38 | totalEventSize = Integer.MAX_VALUE; 39 | } 40 | this.semaphore = new Semaphore(totalEventSize, false); 41 | } 42 | 43 | 44 | // ~ ------------------------------------------------------------------------------------------------------------ 45 | 46 | 47 | protected void beforeDispatch(NioByteChannel channel) { 48 | boolean b = channel.tryAcquire(); 49 | if (!b) { 50 | channel.pause(); 51 | LOG.warn("[CRAFT-ATOM-NIO]] Pause |channel={}, availablePermits={}|", channel, channel.availablePermits()); 52 | } 53 | 54 | try { 55 | semaphore.acquire(); 56 | } catch (InterruptedException e) { 57 | LOG.warn("[CRAFT-ATOM-NIO] Semaphore acquire interrupt", e); 58 | } 59 | } 60 | 61 | protected void afterDispatch(NioByteChannel channel) { 62 | channel.release(); 63 | if (channel.isPaused()) { 64 | channel.resume(); 65 | LOG.warn("[CRAFT-ATOM-NIO]] Resume |channel={} availablePermits={}|", channel, channel.availablePermits()); 66 | } 67 | 68 | semaphore.release(); 69 | } 70 | 71 | @Override 72 | public void shutdown() {} 73 | 74 | } 75 | -------------------------------------------------------------------------------- /craft-atom-nio/src/main/java/io/craft/atom/nio/spi/NioBufferSizePredictor.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.nio.spi; 2 | 3 | /** 4 | * Predicts the nio buffer size. 5 | *

6 | * Predict buffer size allocation, More accurate the prediction is, more effective the memory utilization will be. 7 | * 8 | * @author mindwind 9 | * @version 1.0, Jan 25, 2013 10 | */ 11 | public interface NioBufferSizePredictor { 12 | 13 | /** 14 | * Predicts the size of next operaion. 15 | * 16 | * @return the expected size at this time for next operation 17 | */ 18 | int next(); 19 | 20 | /** 21 | * Updates predictor by specifying the actual size in the previous operation. 22 | * 23 | * @param previousSize the actual size in the previous read operation 24 | */ 25 | void previous(int previousSize); 26 | 27 | } 28 | -------------------------------------------------------------------------------- /craft-atom-nio/src/main/java/io/craft/atom/nio/spi/NioBufferSizePredictorFactory.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.nio.spi; 2 | 3 | /** 4 | * Factory of {@link NioBufferSizePredictor} 5 | * 6 | * @author mindwind 7 | * @version 1.0, Feb 24, 2013 8 | */ 9 | public interface NioBufferSizePredictorFactory { 10 | 11 | /** 12 | * Return a nio buffer size predictor 13 | * 14 | * @param minimum the inclusive lower bound of the expected buffer size 15 | * @param initial the initial buffer size when no feed back was received 16 | * @param maximum the inclusive upper bound of the expected buffer size 17 | * @return a nio buffer size predictor 18 | */ 19 | NioBufferSizePredictor newPredictor(int minimum, int initial, int maximum); 20 | 21 | } 22 | -------------------------------------------------------------------------------- /craft-atom-nio/src/main/java/io/craft/atom/nio/spi/NioChannelEventDispatcher.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.nio.spi; 2 | 3 | import io.craft.atom.io.ChannelEvent; 4 | import io.craft.atom.io.IoHandler; 5 | import io.craft.atom.nio.NioOrderedDirectChannelEventDispatcher; 6 | import io.craft.atom.nio.NioOrderedThreadPoolChannelEventDispatcher; 7 | 8 | 9 | /** 10 | * Nio channel event dispatcher, dispatch all channel I/O events to {@link IoHandler} 11 | * 12 | * @author mindwind 13 | * @version 1.0, Feb 22, 2013 14 | * @see NioOrderedThreadPoolChannelEventDispatcher 15 | * @see NioOrderedDirectChannelEventDispatcher 16 | */ 17 | public interface NioChannelEventDispatcher { 18 | 19 | /** 20 | * Dispatch event to handle. 21 | * 22 | * @param event 23 | */ 24 | void dispatch(ChannelEvent event); 25 | 26 | /** 27 | * Shutdown the dispatcher and dispose holden resources. 28 | */ 29 | void shutdown(); 30 | 31 | } 32 | -------------------------------------------------------------------------------- /craft-atom-nio/src/test/java/io/craft/atom/nio/NioAcceptorHandler.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.nio; 2 | 3 | import io.craft.atom.io.AbstractIoHandler; 4 | import io.craft.atom.io.Channel; 5 | 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | /** 10 | * @author mindwind 11 | * @version 1.0, 2011-12-19 12 | */ 13 | public class NioAcceptorHandler extends AbstractIoHandler { 14 | 15 | private static final Logger LOG = LoggerFactory.getLogger(NioAcceptorHandler.class); 16 | private static final byte LF = 10 ; 17 | 18 | 19 | private StringBuilder buf = new StringBuilder(); 20 | 21 | 22 | @Override 23 | public void channelRead(Channel channel, byte[] bytes) { 24 | LOG.debug("[CRAFT-ATOM-NIO] Channel read bytes size={}", bytes.length); 25 | 26 | for (byte b : bytes) { 27 | buf.append((char) b); 28 | } 29 | 30 | if (bytes[bytes.length - 1] == LF) { 31 | byte[] echoBytes = buf.toString().getBytes(); 32 | LOG.debug("[CRAFT-ATOM-NIO] Echo bytes size={} \n", echoBytes.length); 33 | channel.write(echoBytes); 34 | buf = new StringBuilder(); 35 | } 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /craft-atom-nio/src/test/java/io/craft/atom/nio/NioAcceptorNapHandler.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.nio; 2 | 3 | import io.craft.atom.io.AbstractIoHandler; 4 | import io.craft.atom.io.Channel; 5 | 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | /** 10 | * @author mindwind 11 | * @version 1.0, 2011-12-19 12 | */ 13 | public class NioAcceptorNapHandler extends AbstractIoHandler { 14 | 15 | 16 | private static final Logger LOG = LoggerFactory.getLogger(NioAcceptorNapHandler.class); 17 | private static final byte LF = 10 ; 18 | 19 | 20 | private StringBuilder buf = new StringBuilder(); 21 | 22 | 23 | @Override 24 | public void channelRead(Channel channel, byte[] bytes) { 25 | LOG.debug("[CRAFT-ATOM-NIO] Channel read bytes size={}, is paused={}", bytes.length, channel.isPaused()); 26 | 27 | for (byte b : bytes) { 28 | buf.append((char) b); 29 | } 30 | 31 | nap(); 32 | 33 | if (bytes[bytes.length - 1] == LF) { 34 | byte[] echoBytes = buf.toString().getBytes(); 35 | LOG.debug("[CRAFT-ATOM-NIO] Echo bytes size={}, take a nap \n", echoBytes.length); 36 | channel.write(echoBytes); 37 | buf = new StringBuilder(); 38 | } 39 | } 40 | 41 | private void nap() { 42 | try { 43 | Thread.sleep(200); 44 | } catch (InterruptedException e) { 45 | e.printStackTrace(); 46 | } 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /craft-atom-nio/src/test/java/io/craft/atom/nio/NioConnectorHandler.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.nio; 2 | 3 | import io.craft.atom.io.AbstractIoHandler; 4 | import io.craft.atom.io.Channel; 5 | import lombok.Getter; 6 | 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | 10 | /** 11 | * @author mindwind 12 | * @version 1.0, 2011-12-19 13 | */ 14 | public class NioConnectorHandler extends AbstractIoHandler { 15 | 16 | 17 | private static final Logger LOG = LoggerFactory.getLogger(NioConnectorHandler.class); 18 | private static final byte LF = 10 ; 19 | 20 | 21 | @Getter private StringBuilder buf = new StringBuilder(); 22 | @Getter private String rcv = null ; 23 | 24 | 25 | @Override 26 | public void channelRead(Channel channel, byte[] bytes) { 27 | LOG.debug("[CRAFT-ATOM-NIO] Channel read bytes size={}", bytes.length); 28 | 29 | for (byte b : bytes) { 30 | buf.append((char) b); 31 | } 32 | 33 | if (bytes[bytes.length - 1] == LF) { 34 | rcv = buf.toString(); 35 | byte[] echoBytes = buf.toString().getBytes(); 36 | LOG.debug("[CRAFT-ATOM-NIO] Echo received bytes size={} \n", echoBytes.length); 37 | buf = new StringBuilder(); 38 | synchronized(channel) { 39 | channel.notifyAll(); 40 | } 41 | } 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /craft-atom-nio/src/test/java/io/craft/atom/nio/NioEchoClient.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.nio; 2 | 3 | import io.craft.atom.io.IoConnector; 4 | import io.craft.atom.nio.api.NioFactory; 5 | 6 | import java.io.IOException; 7 | 8 | 9 | /** 10 | * @author mindwind 11 | * @version 1.0, Mar 18, 2014 12 | */ 13 | public class NioEchoClient { 14 | 15 | private String ip ; 16 | private int port; 17 | 18 | public NioEchoClient(String ip, int port) { 19 | this.ip = ip; 20 | this.port = port; 21 | } 22 | 23 | public void start() throws IOException { 24 | IoConnector connector = NioFactory.newTcpConnectorBuilder(new NioEchoClientHandler()).connectTimeoutInMillis(3000).build(); 25 | connector.connect(ip, port); 26 | } 27 | 28 | public static void main(String[] args) throws IOException { 29 | new NioEchoClient("127.0.0.1", 1314).start(); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /craft-atom-nio/src/test/java/io/craft/atom/nio/NioEchoClientHandler.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.nio; 2 | 3 | import io.craft.atom.io.AbstractIoHandler; 4 | import io.craft.atom.io.Channel; 5 | 6 | import java.util.concurrent.atomic.AtomicInteger; 7 | 8 | 9 | /** 10 | * @author mindwind 11 | * @version 1.0, Mar 15, 2014 12 | */ 13 | public class NioEchoClientHandler extends AbstractIoHandler { 14 | 15 | private AtomicInteger counter = new AtomicInteger(); 16 | 17 | @Override 18 | public void channelOpened(Channel channel) { 19 | send(channel); 20 | } 21 | 22 | @Override 23 | public void channelRead(Channel channel, byte[] bytes) { 24 | System.out.println("ECHO-RECV: " + new String(bytes)); 25 | try { Thread.sleep(1000); } catch (InterruptedException e) {} 26 | send(channel); 27 | } 28 | 29 | private void send(Channel channel) { 30 | String toSend = Integer.toString(counter.incrementAndGet()); 31 | channel.write(toSend.getBytes()); 32 | System.out.println("ECHO-SENT: " + toSend); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /craft-atom-nio/src/test/java/io/craft/atom/nio/NioEchoServer.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.nio; 2 | 3 | import io.craft.atom.io.IoAcceptor; 4 | import io.craft.atom.nio.api.NioFactory; 5 | 6 | import java.io.IOException; 7 | 8 | 9 | /** 10 | * @author mindwind 11 | * @version 1.0, Mar 15, 2014 12 | */ 13 | public class NioEchoServer { 14 | 15 | private int port; 16 | 17 | public NioEchoServer(int port) { 18 | this.port = port; 19 | } 20 | 21 | public void start() throws IOException { 22 | IoAcceptor acceptor = NioFactory.newTcpAcceptorBuilder(new NioEchoServerHandler()).build(); 23 | acceptor.bind(port); 24 | } 25 | 26 | public static void main(String[] args) throws IOException { 27 | new NioEchoServer(1314).start(); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /craft-atom-nio/src/test/java/io/craft/atom/nio/NioEchoServerHandler.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.nio; 2 | 3 | import io.craft.atom.io.AbstractIoHandler; 4 | import io.craft.atom.io.Channel; 5 | 6 | /** 7 | * @author mindwind 8 | * @version 1.0, Mar 15, 2014 9 | */ 10 | public class NioEchoServerHandler extends AbstractIoHandler { 11 | 12 | @Override 13 | public void channelRead(Channel channel, byte[] bytes) { 14 | channel.write(bytes); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /craft-atom-nio/src/test/java/io/craft/atom/nio/TestNioBuilder.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.nio; 2 | 3 | import io.craft.atom.io.Channel; 4 | import io.craft.atom.io.IoAcceptor; 5 | import io.craft.atom.io.IoConnector; 6 | import io.craft.atom.nio.api.NioFactory; 7 | import io.craft.atom.test.AvailablePortFinder; 8 | import io.craft.atom.test.CaseCounter; 9 | 10 | import java.io.IOException; 11 | import java.util.concurrent.ExecutionException; 12 | import java.util.concurrent.Future; 13 | import java.util.concurrent.TimeUnit; 14 | import java.util.concurrent.TimeoutException; 15 | 16 | import org.junit.Assert; 17 | import org.junit.Test; 18 | 19 | /** 20 | * @author mindwind 21 | * @version 1.0, Mar 9, 2014 22 | */ 23 | public class TestNioBuilder { 24 | 25 | 26 | @Test 27 | public void testNioAcceptorBuilder() throws IOException { 28 | IoAcceptor acceptor = NioFactory.newTcpAcceptorBuilder(new NioAcceptorHandler()).reuseAddress(true).backlog(100).totalEventSize(50000).ioTimeoutInMillis(30000).build(); 29 | int port = AvailablePortFinder.getNextAvailable(22222); 30 | acceptor.bind(port); 31 | 32 | try { 33 | acceptor.bind(port); 34 | Assert.fail(); 35 | } catch(IOException e) { 36 | 37 | } 38 | 39 | System.out.println(String.format("[CRAFT-ATOM-NIO] (^_^) <%s> Case -> test nio tcp acceptor builder. ", CaseCounter.incr(1))); 40 | } 41 | 42 | @Test 43 | public void testNioConnectorBuilder() throws IOException { 44 | IoConnector connector = NioFactory.newTcpConnectorBuilder(new NioConnectorHandler()).connectTimeoutInMillis(1000).ioTimeoutInMillis(60000).executorSize(32).build(); 45 | Future> future = connector.connect("127.0.0.1", AvailablePortFinder.getNextAvailable()); 46 | 47 | try { 48 | future.get(1, TimeUnit.SECONDS); 49 | } catch (InterruptedException e) { 50 | 51 | } catch (ExecutionException e) { 52 | 53 | } catch (TimeoutException e) { 54 | Assert.assertTrue(true); 55 | } 56 | System.out.println(String.format("[CRAFT-ATOM-NIO] (^_^) <%s> Case -> test nio tcp connector builder. ", CaseCounter.incr(1))); 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /craft-atom-nio/src/test/java/io/craft/atom/nio/TestNioTcpAcceptorChannelSizeLimit.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.nio; 2 | 3 | import io.craft.atom.io.Channel; 4 | import io.craft.atom.io.IoAcceptor; 5 | import io.craft.atom.io.IoConnector; 6 | import io.craft.atom.nio.api.NioFactory; 7 | import io.craft.atom.test.AvailablePortFinder; 8 | import io.craft.atom.test.CaseCounter; 9 | 10 | import java.io.IOException; 11 | import java.util.concurrent.Future; 12 | import java.util.concurrent.TimeUnit; 13 | 14 | import org.junit.Assert; 15 | import org.junit.Before; 16 | import org.junit.Test; 17 | 18 | /** 19 | * @author mindwind 20 | * @version 1.0, Sep 23, 2014 21 | */ 22 | public class TestNioTcpAcceptorChannelSizeLimit { 23 | 24 | 25 | private static final int PORT = AvailablePortFinder.getNextAvailable(33333); 26 | 27 | 28 | private IoConnector connector ; 29 | private IoAcceptor acceptor ; 30 | private int channelSize; 31 | 32 | 33 | @Before 34 | public void before() throws IOException { 35 | channelSize = 2; 36 | acceptor = NioFactory.newTcpAcceptorBuilder(new NioAcceptorHandler()).channelSize(channelSize).build(); 37 | acceptor.bind(PORT); 38 | connector = NioFactory.newTcpConnector(new NioConnectorHandler()); 39 | } 40 | 41 | @Test 42 | public void testChannelSizeLimit() throws IOException { 43 | for (int i = 0; i < channelSize; i++) { 44 | connector.connect("127.0.0.1", PORT); 45 | } 46 | 47 | try { 48 | Thread.sleep(100); 49 | Future> future = connector.connect("127.0.0.1", PORT); 50 | Channel channel = future.get(200, TimeUnit.MILLISECONDS); 51 | Thread.sleep(200); 52 | Assert.assertFalse(channel.isOpen()); 53 | } catch (Exception e) { 54 | Assert.fail(); 55 | } 56 | System.out.println(String.format("[CRAFT-ATOM-NIO] (^_^) <%s> Case -> test nio acceptor channel size limit ", CaseCounter.incr(1))); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /craft-atom-nio/src/test/java/io/craft/atom/nio/TestNioTcpConnector.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.nio; 2 | 3 | import io.craft.atom.io.Channel; 4 | import io.craft.atom.io.IoConnector; 5 | import io.craft.atom.nio.NioTcpConnector; 6 | import io.craft.atom.nio.api.NioFactory; 7 | import io.craft.atom.test.AvailablePortFinder; 8 | import io.craft.atom.test.CaseCounter; 9 | 10 | import java.io.IOException; 11 | import java.util.concurrent.ExecutionException; 12 | import java.util.concurrent.Future; 13 | import java.util.concurrent.TimeUnit; 14 | import java.util.concurrent.TimeoutException; 15 | 16 | import org.junit.Assert; 17 | import org.junit.Test; 18 | import org.slf4j.Logger; 19 | import org.slf4j.LoggerFactory; 20 | 21 | /** 22 | * Tests for {@link NioTcpConnector} 23 | * 24 | * @author mindwind 25 | * @version 1.0, 2011-12-20 26 | */ 27 | public class TestNioTcpConnector { 28 | 29 | 30 | private static final Logger LOG = LoggerFactory.getLogger(TestNioTcpConnector.class); 31 | 32 | 33 | @Test 34 | public void testTimeout() throws IOException { 35 | IoConnector connector = NioFactory.newTcpConnector(new NioConnectorHandler()); 36 | Future> future = connector.connect("127.0.0.1", AvailablePortFinder.getNextAvailable()); 37 | 38 | try { 39 | future.get(200, TimeUnit.MILLISECONDS); 40 | Assert.fail(); 41 | } catch (InterruptedException e) { 42 | 43 | } catch (ExecutionException e) { 44 | 45 | } catch (TimeoutException e) { 46 | LOG.debug("[CRAFT-ATOM-NIO] Test catch timeout exception"); 47 | Assert.assertTrue(true); 48 | } 49 | System.out.println(String.format("[CRAFT-ATOM-NIO] (^_^) <%s> Case -> test nio tcp connector timeout. ", CaseCounter.incr(1))); 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /craft-atom-nio/src/test/java/io/craft/atom/nio/TestNioTimeout.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.nio; 2 | 3 | import io.craft.atom.io.AbstractIoHandler; 4 | import io.craft.atom.io.Channel; 5 | import io.craft.atom.io.IoAcceptor; 6 | import io.craft.atom.io.IoHandler; 7 | import io.craft.atom.nio.api.NioFactory; 8 | import io.craft.atom.nio.api.NioTcpAcceptorBuilder; 9 | import io.craft.atom.test.AvailablePortFinder; 10 | import io.craft.atom.test.CaseCounter; 11 | import junit.framework.Assert; 12 | 13 | import org.junit.Test; 14 | 15 | /** 16 | * Test for nio timeout config 17 | * 18 | * @author mindwind 19 | * @version 1.0, Sep 5, 2014 20 | */ 21 | public class TestNioTimeout { 22 | 23 | 24 | @Test 25 | public void testMaxIntegerTimeout() { 26 | try { 27 | int port = AvailablePortFinder.getNextAvailable(); 28 | NioTcpAcceptorBuilder builder = NioFactory.newTcpAcceptorBuilder(new NioAcceptorHandler()); 29 | IoAcceptor acceptor = builder.ioTimeoutInMillis(Integer.MAX_VALUE).build(); 30 | acceptor.bind(port); 31 | } catch (Throwable t) { 32 | Assert.fail(); 33 | } 34 | 35 | Assert.assertTrue(true); 36 | System.out.println(String.format("[CRAFT-ATOM-NIO] (^_^) <%s> Case -> test max integer timeout. ", CaseCounter.incr(1))); 37 | } 38 | 39 | @Test 40 | public void testLessOneHundredMillisecondsTimeout() { 41 | try { 42 | int port = AvailablePortFinder.getNextAvailable(); 43 | IoHandler handler = new AbstractIoHandler() { 44 | @Override 45 | public void channelIdle(Channel channel) { 46 | super.channelIdle(channel); 47 | channel.close(); 48 | } 49 | }; 50 | NioTcpAcceptorBuilder builder = NioFactory.newTcpAcceptorBuilder(handler); 51 | IoAcceptor acceptor = builder.ioTimeoutInMillis(50).build(); 52 | acceptor.bind(port); 53 | } catch (Throwable t) { 54 | t.printStackTrace(); 55 | Assert.fail(); 56 | } 57 | 58 | Assert.assertTrue(true); 59 | System.out.println(String.format("[CRAFT-ATOM-NIO] (^_^) <%s> Case -> test less one hundred milliseconds timeout. ", CaseCounter.incr(1))); 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /craft-atom-nio/src/test/resources/log4j.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /craft-atom-protocol-http/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | 4 | io.craftcode 5 | craft-atom 6 | 3.1.3-SNAPSHOT 7 | 8 | craft-atom-protocol-http 9 | ${project.artifactId} 10 | 11 | 12 | 13 | ${project.groupId} 14 | craft-atom-protocol 15 | ${project.version} 16 | 17 | 18 | ${project.groupId} 19 | craft-atom-test 20 | ${project.version} 21 | test 22 | 23 | 24 | org.slf4j 25 | slf4j-api 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /craft-atom-protocol-http/src/main/java/io/craft/atom/protocol/http/HttpCookieEncoder.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.protocol.http; 2 | 3 | import io.craft.atom.protocol.AbstractProtocolCodec; 4 | import io.craft.atom.protocol.ProtocolEncoder; 5 | import io.craft.atom.protocol.ProtocolException; 6 | import io.craft.atom.protocol.http.model.HttpCookie; 7 | 8 | import java.nio.charset.Charset; 9 | 10 | import lombok.ToString; 11 | 12 | 13 | /** 14 | * A {@link ProtocolEncoder} which encodes a {@code Cookie} object into bytes follow the HTTP specification, default charset is utf-8. 15 | *
16 | * Thread safe. 17 | * 18 | * @author mindwind 19 | * @version 1.0, Mar 25, 2013 20 | */ 21 | @ToString(callSuper = true) 22 | public class HttpCookieEncoder extends AbstractProtocolCodec implements ProtocolEncoder { 23 | 24 | 25 | public HttpCookieEncoder() {} 26 | 27 | public HttpCookieEncoder(Charset charset) { 28 | this.charset = charset; 29 | } 30 | 31 | @Override 32 | public byte[] encode(HttpCookie cookie) throws ProtocolException { 33 | if (cookie == null) return null; 34 | String httpString = cookie.toHttpString(); 35 | return httpString.getBytes(charset); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /craft-atom-protocol-http/src/main/java/io/craft/atom/protocol/http/HttpDates.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.protocol.http; 2 | 3 | import java.text.DateFormat; 4 | import java.text.ParseException; 5 | import java.text.SimpleDateFormat; 6 | import java.util.Date; 7 | import java.util.Locale; 8 | import java.util.TimeZone; 9 | 10 | /** 11 | * Generates date in the format required by the HTTP protocol. 12 | * 13 | * @author mindwind 14 | * @version 1.0, Mar 22, 2013 15 | */ 16 | public class HttpDates { 17 | 18 | 19 | /** The date format pattern used to generate the header in RFC 1123 format. */ 20 | private static final String DATE_FORMAT_RFC1123 = "EEE, dd MMM yyyy HH:mm:ss zzz"; 21 | private static final TimeZone GMT = TimeZone.getTimeZone("GMT") ; 22 | private static final ThreadLocal threadLocal = new ThreadLocal() ; 23 | private static long dateAsLong = 0L ; 24 | private static String dateAsText = null ; 25 | 26 | 27 | // ~ ----------------------------------------------------------------------------------------------------------- 28 | 29 | 30 | private static DateFormat getDateFormat() { 31 | DateFormat df = threadLocal.get(); 32 | if (df == null) { 33 | df = new SimpleDateFormat(DATE_FORMAT_RFC1123, Locale.US); 34 | df.setTimeZone(GMT); 35 | threadLocal.set(df); 36 | } 37 | return df; 38 | } 39 | 40 | public static String formatCurrentDate() { 41 | long now = System.currentTimeMillis(); 42 | if (now - dateAsLong > 1000) { 43 | dateAsText = format(new Date(now)); 44 | dateAsLong = now; 45 | } 46 | return dateAsText; 47 | } 48 | 49 | public static String format(Date date) { 50 | DateFormat df = getDateFormat(); 51 | return df.format(date); 52 | } 53 | 54 | public static Date parse(String dateString) { 55 | DateFormat df = getDateFormat(); 56 | try { 57 | return df.parse(dateString); 58 | } catch (ParseException e) { 59 | throw new IllegalArgumentException("Invalid date string format=" + dateString, e); 60 | } 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /craft-atom-protocol-http/src/main/java/io/craft/atom/protocol/http/HttpEncoder.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.protocol.http; 2 | 3 | import io.craft.atom.protocol.AbstractProtocolEncoder; 4 | import lombok.ToString; 5 | 6 | 7 | /** 8 | * @author mindwind 9 | * @version 1.0, Feb 3, 2013 10 | * @see HttpRequestEncoder 11 | * @see HttpResponseEncoder 12 | */ 13 | @ToString(callSuper = true) 14 | abstract public class HttpEncoder extends AbstractProtocolEncoder { 15 | 16 | } 17 | -------------------------------------------------------------------------------- /craft-atom-protocol-http/src/main/java/io/craft/atom/protocol/http/HttpParameterEncoder.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.protocol.http; 2 | 3 | import static io.craft.atom.protocol.http.HttpConstants.S_AMPERSAND; 4 | import static io.craft.atom.protocol.http.HttpConstants.S_EQUAL_SIGN; 5 | 6 | import io.craft.atom.protocol.AbstractProtocolCodec; 7 | import io.craft.atom.protocol.ProtocolEncoder; 8 | import io.craft.atom.protocol.ProtocolException; 9 | 10 | import java.io.UnsupportedEncodingException; 11 | import java.net.URLEncoder; 12 | import java.nio.charset.Charset; 13 | import java.util.List; 14 | import java.util.Map; 15 | import java.util.Map.Entry; 16 | import java.util.Set; 17 | 18 | import lombok.ToString; 19 | 20 | 21 | /** 22 | * A {@link ProtocolEncoder} which encodes a {@code Map>} object into bytes 23 | * with the application/x-www-form-urlencoded MIME format follow the HTTP specification, default charset is utf-8. 24 | *
25 | * Thread safe. 26 | * 27 | * @author mindwind 28 | * @version 1.0, Mar 25, 2013 29 | */ 30 | @ToString(callSuper = true) 31 | public class HttpParameterEncoder extends AbstractProtocolCodec implements ProtocolEncoder>> { 32 | 33 | 34 | public HttpParameterEncoder() {} 35 | 36 | public HttpParameterEncoder(Charset charset) { 37 | this.charset = charset; 38 | } 39 | 40 | @Override 41 | public byte[] encode(Map> paras) throws ProtocolException { 42 | if (paras == null) return null; 43 | StringBuilder buf = new StringBuilder(); 44 | Set>> entrys = paras.entrySet(); 45 | for (Entry> entry : entrys) { 46 | String name = entry.getKey(); 47 | List values = entry.getValue(); 48 | for (String value : values) { 49 | try { 50 | name = URLEncoder.encode(name, charset.name()); 51 | value = URLEncoder.encode(value, charset.name()); 52 | buf.append(name).append(S_EQUAL_SIGN).append(value).append(S_AMPERSAND); 53 | } catch (UnsupportedEncodingException e) { 54 | throw new ProtocolException(e); 55 | } 56 | } 57 | } 58 | 59 | // delete last & char 60 | buf.deleteCharAt(buf.length() - 1); 61 | return buf.toString().getBytes(charset); 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /craft-atom-protocol-http/src/main/java/io/craft/atom/protocol/http/HttpRequestEncoder.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.protocol.http; 2 | 3 | import io.craft.atom.protocol.ProtocolEncoder; 4 | import io.craft.atom.protocol.ProtocolException; 5 | import io.craft.atom.protocol.http.model.HttpRequest; 6 | 7 | import java.nio.charset.Charset; 8 | 9 | import lombok.ToString; 10 | 11 | 12 | /** 13 | * A {@link ProtocolEncoder} which encodes a {@code HttpRequest} object into bytes follow the HTTP specification, default charset is utf-8. 14 | *
15 | * Thread safe. 16 | * 17 | * @author mindwind 18 | * @version 1.0, Feb 3, 2013 19 | */ 20 | @ToString(callSuper = true) 21 | public class HttpRequestEncoder extends HttpEncoder implements ProtocolEncoder { 22 | 23 | 24 | public HttpRequestEncoder() {} 25 | 26 | public HttpRequestEncoder(Charset charset) { 27 | this.charset = charset; 28 | } 29 | 30 | 31 | @Override 32 | public byte[] encode(HttpRequest request) throws ProtocolException { 33 | if (request == null) return null; 34 | String httpString = request.toHttpString(charset); 35 | return httpString.getBytes(charset); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /craft-atom-protocol-http/src/main/java/io/craft/atom/protocol/http/HttpResponseDecoder.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.protocol.http; 2 | 3 | import io.craft.atom.protocol.ProtocolDecoder; 4 | import io.craft.atom.protocol.ProtocolException; 5 | import io.craft.atom.protocol.http.model.HttpResponse; 6 | 7 | import java.util.List; 8 | 9 | import lombok.ToString; 10 | 11 | 12 | /** 13 | * A {@link ProtocolDecoder} which decodes bytes into {@code HttpResponse} object, default charset is utf-8 14 | *
15 | * Not thread safe 16 | * 17 | * @author mindwind 18 | * @version 1.0, Feb 3, 2013 19 | */ 20 | @ToString(callSuper = true) 21 | public class HttpResponseDecoder extends HttpDecoder implements ProtocolDecoder { 22 | 23 | @Override 24 | public List decode(byte[] bytes) throws ProtocolException { 25 | // TODO Auto-generated method stub 26 | return null; 27 | } 28 | 29 | @Override 30 | boolean hasEntity(HttpResponse httpMessage) { 31 | // Here assume all response has entity, it does not hurt the correctness. 32 | return true; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /craft-atom-protocol-http/src/main/java/io/craft/atom/protocol/http/HttpResponseEncoder.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.protocol.http; 2 | 3 | import io.craft.atom.protocol.ProtocolEncoder; 4 | import io.craft.atom.protocol.ProtocolException; 5 | import io.craft.atom.protocol.http.model.HttpResponse; 6 | 7 | import java.nio.charset.Charset; 8 | 9 | import lombok.ToString; 10 | 11 | 12 | /** 13 | * A {@link ProtocolEncoder} which encodes a {@code HttpResponse} object into bytes follow the HTTP specification, default charset is utf-8. 14 | *
15 | * Thread safe. 16 | * 17 | * @author mindwind 18 | * @version 1.0, Feb 3, 2013 19 | */ 20 | @ToString(callSuper = true) 21 | public class HttpResponseEncoder extends HttpEncoder implements ProtocolEncoder { 22 | 23 | public HttpResponseEncoder() { 24 | super(); 25 | } 26 | 27 | public HttpResponseEncoder(Charset charset) { 28 | this.charset = charset; 29 | } 30 | 31 | @Override 32 | public byte[] encode(HttpResponse response) throws ProtocolException { 33 | if (response == null) return null; 34 | String httpString = response.toHttpString(charset); 35 | return httpString.getBytes(charset); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /craft-atom-protocol-http/src/main/java/io/craft/atom/protocol/http/api/HttpRequestDecoderBuilder.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.protocol.http.api; 2 | 3 | import io.craft.atom.protocol.ProtocolDecoder; 4 | import io.craft.atom.protocol.http.HttpRequestDecoder; 5 | import io.craft.atom.protocol.http.model.HttpRequest; 6 | 7 | import java.nio.charset.Charset; 8 | 9 | 10 | /** 11 | * Builder for {@link HttpRequestDecoder} 12 | * 13 | * @author mindwind 14 | * @version 1.0, Aug 5, 2014 15 | */ 16 | public class HttpRequestDecoderBuilder { 17 | 18 | 19 | private Charset charset = Charset.forName("utf-8"); 20 | private int defaultBufferSize = 2048 ; 21 | private int maxLineLength = defaultBufferSize ; 22 | private int maxRequestSize = defaultBufferSize * 1024; 23 | 24 | 25 | public HttpRequestDecoderBuilder charset (Charset charset) { this.charset = charset ; return this; } 26 | public HttpRequestDecoderBuilder defaultBufferSize(int defaultBufferSize) { this.defaultBufferSize = defaultBufferSize; return this; } 27 | public HttpRequestDecoderBuilder maxLineLength (int maxLineLength) { this.maxLineLength = maxLineLength ; return this; } 28 | public HttpRequestDecoderBuilder maxRequestSize (int maxRequestSize) { this.maxRequestSize = maxRequestSize ; return this; } 29 | 30 | 31 | public ProtocolDecoder build() { 32 | return new HttpRequestDecoder(charset, defaultBufferSize, maxLineLength, maxRequestSize); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /craft-atom-protocol-http/src/main/java/io/craft/atom/protocol/http/model/HttpContentType.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.protocol.http.model; 2 | 3 | import java.io.Serializable; 4 | import java.nio.charset.Charset; 5 | 6 | import lombok.Getter; 7 | import lombok.ToString; 8 | 9 | /** 10 | * Represents an http content type header value, it is useful for content codec. 11 | *

12 | * Content type information consisting of a MIME type and an optional charset. 13 | * 14 | * @author mindwind 15 | * @version 1.0, Mar 5, 2013 16 | */ 17 | @ToString(of = { "mimeType", "charset" }) 18 | public class HttpContentType implements Serializable { 19 | 20 | private static final long serialVersionUID = -7286615457150709389L ; 21 | public static final HttpContentType DEFAULT = new HttpContentType(MimeType.TEXT_HTML, Charset.forName("utf-8")); 22 | 23 | 24 | @Getter private final MimeType mimeType; 25 | @Getter private final Charset charset ; 26 | 27 | 28 | // ~ ----------------------------------------------------------------------------------------------------------- 29 | 30 | 31 | public HttpContentType(Charset charset) { 32 | this(null, charset); 33 | } 34 | 35 | public HttpContentType(MimeType mimeType) { 36 | this(mimeType, null); 37 | } 38 | 39 | public HttpContentType(MimeType mimeType, Charset charset) { 40 | this.mimeType = mimeType; 41 | this.charset = charset; 42 | } 43 | 44 | 45 | // ~ ----------------------------------------------------------------------------------------------------------- 46 | 47 | 48 | public String toHttpString() { 49 | StringBuilder buf = new StringBuilder(); 50 | buf.append(this.mimeType.toString()); 51 | if (this.charset != null) { 52 | buf.append("; charset="); 53 | buf.append(this.charset.name()); 54 | } 55 | return buf.toString(); 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /craft-atom-protocol-http/src/main/java/io/craft/atom/protocol/http/model/HttpEntity.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.protocol.http.model; 2 | 3 | import java.io.Serializable; 4 | import java.nio.charset.Charset; 5 | 6 | import lombok.Getter; 7 | import lombok.Setter; 8 | import lombok.ToString; 9 | 10 | /** 11 | * Represents a http entity.
12 | * An entity that can be sent or received with a HTTP message, 13 | * but not all messages contain entity, it is optional. 14 | * The entity contains a block of arbitrary data. 15 | * 16 | * @author mindwind 17 | * @version 1.0, Feb 1, 2013 18 | */ 19 | @ToString(of = { "contentType", "content" }) 20 | public class HttpEntity implements Serializable { 21 | 22 | 23 | private static final long serialVersionUID = -3461343279665456788L; 24 | 25 | 26 | @Getter @Setter protected HttpContentType contentType = HttpContentType.DEFAULT; 27 | @Getter @Setter protected byte[] content ; 28 | 29 | 30 | // ~ ----------------------------------------------------------------------------------------------------------- 31 | 32 | 33 | public HttpEntity() { 34 | super(); 35 | } 36 | 37 | public HttpEntity(byte[] content) { 38 | this.content = content; 39 | } 40 | 41 | public HttpEntity(String content, HttpContentType contentType) { 42 | this.contentType = contentType; 43 | Charset charset = contentType.getCharset(); 44 | this.content = content.getBytes(charset == null ? Charset.defaultCharset() : charset); 45 | } 46 | 47 | 48 | // ~ ----------------------------------------------------------------------------------------------------------- 49 | 50 | 51 | public String getContentAsString() { 52 | Charset charset = contentType.getCharset(); 53 | return new String(content, charset == null ? Charset.defaultCharset() : charset); 54 | } 55 | 56 | public String toHttpString() { 57 | Charset charset = contentType.getCharset(); 58 | return new String(content, charset == null ? Charset.defaultCharset() : charset); 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /craft-atom-protocol-http/src/main/java/io/craft/atom/protocol/http/model/HttpMethod.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.protocol.http.model; 2 | 3 | /** 4 | * Enumeration of HTTP request methods. 5 | * 6 | * @author mindwind 7 | * @version 1.0, Feb 1, 2013 8 | */ 9 | public enum HttpMethod { 10 | 11 | GET, HEAD, PUT, POST, TRACE, OPTIONS, DELETE; 12 | 13 | } 14 | -------------------------------------------------------------------------------- /craft-atom-protocol-http/src/main/java/io/craft/atom/protocol/http/model/HttpRequestLine.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.protocol.http.model; 2 | 3 | import static io.craft.atom.protocol.http.HttpConstants.S_CR; 4 | import static io.craft.atom.protocol.http.HttpConstants.S_LF; 5 | import static io.craft.atom.protocol.http.HttpConstants.S_SP; 6 | import lombok.Getter; 7 | import lombok.Setter; 8 | import lombok.ToString; 9 | 10 | 11 | /** 12 | * The Request-Line begins with a method token, followed by the Request-URI and the protocol version, 13 | * and ending with CRLF. The elements are separated by SP characters.
14 | * No CR or LF is allowed except in the final CRLF sequence. 15 | * 16 | *

17 |  *      Request-Line   = Method SP Request-URI SP HTTP-Version CRLF
18 |  * 
19 | * 20 | * @author mindwind 21 | * @version 1.0, Feb 1, 2013 22 | * @see HttpRequest 23 | */ 24 | @ToString(callSuper = true, of = { "method", "uri" }) 25 | public class HttpRequestLine extends HttpStartLine { 26 | 27 | 28 | private static final long serialVersionUID = 1393510808581169505L; 29 | 30 | 31 | @Getter @Setter private HttpMethod method; 32 | @Getter @Setter private String uri ; 33 | 34 | 35 | // ~ ------------------------------------------------------------------------------------------------------------ 36 | 37 | 38 | public HttpRequestLine() { 39 | super(); 40 | } 41 | 42 | public HttpRequestLine(HttpMethod method, String uri, HttpVersion version) { 43 | super(version); 44 | this.method = method; 45 | this.uri = uri; 46 | } 47 | 48 | 49 | // ~ ------------------------------------------------------------------------------------------------------------ 50 | 51 | 52 | public String toHttpString() { 53 | StringBuilder sb = new StringBuilder(); 54 | sb.append(getMethod()).append(S_SP).append(getUri()).append(S_SP).append(getVersion().getValue()).append(S_CR).append(S_LF); 55 | return sb.toString(); 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /craft-atom-protocol-http/src/main/java/io/craft/atom/protocol/http/model/HttpStartLine.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.protocol.http.model; 2 | 3 | import java.io.Serializable; 4 | 5 | import lombok.Getter; 6 | import lombok.Setter; 7 | import lombok.ToString; 8 | 9 | /** 10 | * The start line of http protocol string. 11 | * 12 | * @author mindwind 13 | * @version 1.0, Feb 1, 2013 14 | * @see HttpRequestLine 15 | * @see HttpStatusLine 16 | */ 17 | @ToString(of = "version") 18 | public abstract class HttpStartLine implements Serializable { 19 | 20 | 21 | private static final long serialVersionUID = -2856300388955363870L; 22 | 23 | 24 | @Getter @Setter protected HttpVersion version; 25 | 26 | 27 | // ~ ------------------------------------------------------------------------------------------------------------ 28 | 29 | 30 | public HttpStartLine() { 31 | super(); 32 | } 33 | 34 | public HttpStartLine(HttpVersion version) { 35 | this.version = version; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /craft-atom-protocol-http/src/main/java/io/craft/atom/protocol/http/model/HttpStatusLine.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.protocol.http.model; 2 | 3 | import static io.craft.atom.protocol.http.HttpConstants.S_CR; 4 | import static io.craft.atom.protocol.http.HttpConstants.S_LF; 5 | import static io.craft.atom.protocol.http.HttpConstants.S_SP; 6 | import lombok.Getter; 7 | import lombok.Setter; 8 | import lombok.ToString; 9 | 10 | /** 11 | * The first line of a Response message is the Status-Line, consisting 12 | * of the protocol version followed by a numeric status code and its 13 | * associated textual phrase, with each element separated by SP 14 | * characters. No CR or LF is allowed except in the final CRLF sequence. 15 | *
16 |  *     Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF
17 |  * 
18 | * 19 | * @author mindwind 20 | * @version 1.0, Feb 1, 2013 21 | * @see HttpResponse 22 | */ 23 | @ToString(callSuper = true, of = "status") 24 | public class HttpStatusLine extends HttpStartLine { 25 | 26 | 27 | private static final long serialVersionUID = -3219302257563696666L; 28 | 29 | 30 | @Getter @Setter private HttpStatus status; 31 | 32 | 33 | // ~ ------------------------------------------------------------------------------------------------------------ 34 | 35 | 36 | public HttpStatusLine() { 37 | super(); 38 | } 39 | 40 | public HttpStatusLine(HttpVersion version, HttpStatus status) { 41 | super(version); 42 | this.status = status; 43 | } 44 | 45 | public String toHttpString() { 46 | StringBuilder sb = new StringBuilder(); 47 | sb.append(getVersion().getValue()).append(S_SP).append(getStatus().getStatusCode()).append(S_SP).append(getStatus().getReasonPhrase()).append(S_CR).append(S_LF); 48 | return sb.toString(); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /craft-atom-protocol-http/src/main/java/io/craft/atom/protocol/http/model/HttpVersion.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.protocol.http.model; 2 | 3 | /** 4 | * Represents an HTTP version. HTTP uses a "major.minor" numbering 5 | * scheme to indicate versions of the protocol. 6 | *

7 | * The version of an HTTP message is indicated by an HTTP-Version field 8 | * in the first line of the message. 9 | *

10 | *
11 |  *     HTTP-Version   = "HTTP" "/" 1*DIGIT "." 1*DIGIT
12 |  * 
13 | * 14 | * @author mindwind 15 | * @version 1.0, Feb 1, 2013 16 | * @see HttpStartLine 17 | * @see HttpRequestLine 18 | * @see HttpStatusLine 19 | */ 20 | public enum HttpVersion { 21 | 22 | 23 | HTTP_1_1("HTTP/1.1"), 24 | HTTP_1_0("HTTP/1.0"), 25 | HTTP_0_9("HTTP/0.9"); 26 | 27 | 28 | private final String value; 29 | 30 | private HttpVersion(String value) { 31 | this.value = value; 32 | } 33 | 34 | /** 35 | * Returns the {@link HttpVersion} instance from the specified string. 36 | * 37 | * @return The version, or null if no version is matched 38 | */ 39 | public static HttpVersion from(String version) { 40 | if (HTTP_1_1.value.equalsIgnoreCase(version)) { 41 | return HTTP_1_1; 42 | } 43 | 44 | if (HTTP_1_0.value.equalsIgnoreCase(version)) { 45 | return HTTP_1_0; 46 | } 47 | 48 | if (HTTP_0_9.value.equalsIgnoreCase(version)) { 49 | return HTTP_0_9; 50 | } 51 | 52 | return null; 53 | } 54 | 55 | public String getValue() { 56 | return value; 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /craft-atom-protocol-http/src/test/java/io/craft/atom/protocol/http/TestHttpParameterDecoder.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.protocol.http; 2 | 3 | import io.craft.atom.protocol.ProtocolDecoder; 4 | import io.craft.atom.protocol.ProtocolEncoder; 5 | import io.craft.atom.protocol.ProtocolException; 6 | import io.craft.atom.protocol.http.api.HttpCodecFactory; 7 | import io.craft.atom.test.CaseCounter; 8 | 9 | import java.util.List; 10 | import java.util.Map; 11 | 12 | import junit.framework.Assert; 13 | 14 | import org.junit.Test; 15 | import org.slf4j.Logger; 16 | import org.slf4j.LoggerFactory; 17 | 18 | /** 19 | * @author mindwind 20 | * @version 1.0, Mar 25, 2013 21 | */ 22 | public class TestHttpParameterDecoder { 23 | 24 | 25 | private static final Logger LOG = LoggerFactory.getLogger(TestHttpParameterDecoder.class); 26 | 27 | 28 | private ProtocolDecoder>> decoder = HttpCodecFactory.newHttpParameterDecoder(); 29 | private ProtocolEncoder>> encoder = HttpCodecFactory.newHttpParameterEncoder(); 30 | 31 | 32 | @Test 33 | public void testParameter() throws ProtocolException { 34 | String queryString = "a=aa&%E6%B5%8B%E8%AF%95=%E6%B5%8B%E8%AF%95value&a=bb"; 35 | List>> paralist = decoder.decode(queryString.getBytes()); 36 | Map> paras = paralist.get(0); 37 | Assert.assertEquals(2, paras.size()); 38 | LOG.debug("[CRAFT-ATOM-PROTOCOL-HTTP] Encoded parameter={}", new String(encoder.encode(paras))); 39 | System.out.println(String.format("[CRAFT-ATOM-PROTOCOL-HTTP] (^_^) <%s> Case -> test parameter. ", CaseCounter.incr(1))); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /craft-atom-protocol-rpc/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | 4 | io.craftcode 5 | craft-atom 6 | 3.1.3-SNAPSHOT 7 | 8 | craft-atom-protocol-rpc 9 | craft-atom-protocol-rpc 10 | 11 | 12 | 13 | ${project.groupId} 14 | craft-atom-protocol 15 | ${project.version} 16 | 17 | 18 | ${project.groupId} 19 | craft-atom-test 20 | ${project.version} 21 | test 22 | 23 | 24 | org.slf4j 25 | slf4j-api 26 | 27 | 28 | com.esotericsoftware 29 | kryo 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /craft-atom-protocol-rpc/src/main/java/io/craft/atom/protocol/rpc/api/RpcCodecFactory.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.protocol.rpc.api; 2 | 3 | import io.craft.atom.protocol.ProtocolDecoder; 4 | import io.craft.atom.protocol.ProtocolEncoder; 5 | import io.craft.atom.protocol.rpc.RpcDecoder; 6 | import io.craft.atom.protocol.rpc.RpcEncoder; 7 | import io.craft.atom.protocol.rpc.model.RpcMessage; 8 | 9 | 10 | /** 11 | * RPC codec factory, which provides static factory method to create {@link ProtocolEncoder} and {@link ProtocolDecoder} instance. 12 | * 13 | * @author mindwind 14 | * @version 1.0, Aug 5, 2014 15 | */ 16 | public class RpcCodecFactory { 17 | 18 | 19 | public static ProtocolEncoder newRpcEncoder() { 20 | return new RpcEncoder(); 21 | } 22 | 23 | public static ProtocolDecoder newRpcDecoder() { 24 | return new RpcDecoder(); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /craft-atom-protocol-rpc/src/main/java/io/craft/atom/protocol/rpc/api/SerializationRegistry.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.protocol.rpc.api; 2 | 3 | import io.craft.atom.protocol.rpc.KryoSerialization; 4 | import io.craft.atom.protocol.rpc.model.RpcBody; 5 | import io.craft.atom.protocol.rpc.spi.Serialization; 6 | 7 | import java.util.HashMap; 8 | import java.util.Map; 9 | 10 | 11 | 12 | /** 13 | * Serialization registry contains the {@code Serialization} and its type mapping. 14 | * 15 | * @author mindwind 16 | * @version 1.0, Jul 23, 2014 17 | */ 18 | public class SerializationRegistry { 19 | 20 | 21 | // singleton 22 | private static final SerializationRegistry INSTNACE = new SerializationRegistry(); 23 | public static SerializationRegistry getInstance() { return INSTNACE; } 24 | private SerializationRegistry() { 25 | registry.put(KryoSerialization.getInstance().type(), KryoSerialization.getInstance()); 26 | } 27 | 28 | 29 | private Map> registry = new HashMap>(); 30 | 31 | 32 | // ~ -------------------------------------------------------------------------------------------------------------- 33 | 34 | 35 | /** 36 | * Lookup by type 37 | * 38 | * @param type 39 | * @return mapping serialization. 40 | */ 41 | public Serialization lookup(byte type) { 42 | return registry.get(type); 43 | } 44 | 45 | 46 | /** 47 | * Register a serialization. 48 | * 49 | * @param type 50 | * @param serialization 51 | */ 52 | public void register(byte type, Serialization serialization) { 53 | if (registry.containsKey(type)) { 54 | throw new IllegalArgumentException("Serialization `type` is conflict!"); 55 | } 56 | registry.put(type, serialization); 57 | } 58 | 59 | /** 60 | * Unregister a serialization. 61 | * 62 | * @param type 63 | */ 64 | public void unregister(byte type) { 65 | registry.remove(type); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /craft-atom-protocol-rpc/src/main/java/io/craft/atom/protocol/rpc/model/RpcBody.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.protocol.rpc.model; 2 | 3 | import java.io.Serializable; 4 | import java.util.Map; 5 | 6 | import lombok.EqualsAndHashCode; 7 | import lombok.Getter; 8 | import lombok.Setter; 9 | import lombok.ToString; 10 | 11 | /** 12 | * Represents a RPC body field. 13 | *

14 | * A body that can be sent or received with a rpc message, 15 | * but not all messages contain a body, it is optional. 16 | * The body contains a block of arbitrary data and can be serialized by specific serializer. 17 | * 18 | * @author mindwind 19 | * @version 1.0, Jul 18, 2014 20 | */ 21 | @ToString 22 | @EqualsAndHashCode(of = { "rpcInterface", "rpcMethod", "returnObject", "exception", "attachments" }) 23 | public class RpcBody implements Serializable { 24 | 25 | 26 | private static final long serialVersionUID = 5138100956693144357L; 27 | 28 | 29 | @Getter @Setter private String rpcId ; 30 | @Getter @Setter private Class rpcInterface; 31 | @Getter @Setter private RpcMethod rpcMethod ; 32 | @Getter @Setter private RpcOption rpcOption ; 33 | @Getter @Setter private Map attachments ; 34 | @Getter @Setter private Object returnObject; 35 | @Getter @Setter private Exception exception ; 36 | 37 | } 38 | -------------------------------------------------------------------------------- /craft-atom-protocol-rpc/src/main/java/io/craft/atom/protocol/rpc/model/RpcMethod.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.protocol.rpc.model; 2 | 3 | import java.io.Serializable; 4 | 5 | import lombok.EqualsAndHashCode; 6 | import lombok.Getter; 7 | import lombok.Setter; 8 | import lombok.ToString; 9 | 10 | /** 11 | * A RpcMethod provides information about a RPC interface exposed method. 12 | * 13 | * @author mindwind 14 | * @version 1.0, Aug 8, 2014 15 | */ 16 | @ToString 17 | @EqualsAndHashCode(of = { "name", "parameterTypes" }) 18 | public class RpcMethod implements Serializable { 19 | 20 | 21 | private static final long serialVersionUID = -4302065109637231162L; 22 | 23 | 24 | @Getter @Setter private String name ; 25 | @Getter private Class[] parameterTypes; 26 | @Getter private Object[] parameters ; 27 | 28 | 29 | // ~ ------------------------------------------------------------------------------------------------------------- 30 | 31 | 32 | public RpcMethod() {} 33 | 34 | public RpcMethod(String name, Class[] parameterTypes) { 35 | this.name = name; 36 | this.parameterTypes = parameterTypes; 37 | } 38 | 39 | public RpcMethod(String name, Class[] parameterTypes, Object[] parameters) { 40 | this(name, parameterTypes); 41 | this.parameters = parameters; 42 | } 43 | 44 | 45 | // ~ ------------------------------------------------------------------------------------------------------------- 46 | 47 | 48 | public void setParameterTypes(Class... parameterTypes) { 49 | this.parameterTypes = parameterTypes; 50 | } 51 | 52 | public void setParameters(Object... parameters) { 53 | this.parameters = parameters; 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /craft-atom-protocol-rpc/src/main/java/io/craft/atom/protocol/rpc/model/RpcOption.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.protocol.rpc.model; 2 | 3 | import java.io.Serializable; 4 | import java.net.InetSocketAddress; 5 | 6 | import lombok.Getter; 7 | import lombok.Setter; 8 | import lombok.ToString; 9 | 10 | /** 11 | * A RpcOption provides optional information about rpc invocation. 12 | * 13 | * @author mindwind 14 | * @version 1.0, Aug 8, 2014 15 | */ 16 | @ToString 17 | public class RpcOption implements Serializable { 18 | 19 | 20 | private static final long serialVersionUID = -9035174922898235358L; 21 | 22 | 23 | @Getter @Setter transient private InetSocketAddress serverAddress ; 24 | @Getter @Setter transient private InetSocketAddress clientAddress ; 25 | @Getter @Setter private int rpcTimeoutInMillis = Integer.MAX_VALUE; 26 | 27 | 28 | } 29 | -------------------------------------------------------------------------------- /craft-atom-protocol-rpc/src/main/java/io/craft/atom/protocol/rpc/spi/Serialization.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.protocol.rpc.spi; 2 | 3 | import io.craft.atom.protocol.ProtocolException; 4 | 5 | /** 6 | * Serialize object to bytes or deserialize object from bytes. 7 | * 8 | * @author mindwind 9 | * @version 1.0, Jul 23, 2014 10 | */ 11 | public interface Serialization { 12 | 13 | /** 14 | * @return serialization type. 15 | */ 16 | byte type(); 17 | 18 | /** 19 | * Serialize object to bytes. 20 | * 21 | * @param object 22 | * @return serialized bytes 23 | */ 24 | byte[] serialize(T object) throws ProtocolException; 25 | 26 | /** 27 | * Deserialize object from bytes. 28 | * 29 | * @param bytes byte array 30 | * @return deserialized object. 31 | */ 32 | T deserialize(byte[] bytes) throws ProtocolException; 33 | 34 | /** 35 | * Deserialize object from bytes at specific offset . 36 | * 37 | * @param bytes byte array 38 | * @param off offset 39 | * @return deserialized object. 40 | */ 41 | T deserialize(byte[] bytes, int off) throws ProtocolException; 42 | 43 | } 44 | -------------------------------------------------------------------------------- /craft-atom-protocol-rpc/src/test/java/io/craft/atom/protocol/rpc/RpcService.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.protocol.rpc; 2 | 3 | /** 4 | * @author mindwind 5 | * @version 1.0, Jul 22, 2014 6 | */ 7 | public interface RpcService { 8 | 9 | void rpc(String s, int i); 10 | 11 | } 12 | -------------------------------------------------------------------------------- /craft-atom-protocol-rpc/src/test/java/io/craft/atom/protocol/rpc/SerialB.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.protocol.rpc; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | 6 | 7 | /** 8 | * @author mindwind 9 | * @version 1.0, Jul 25, 2014 10 | */ 11 | public class SerialB { 12 | 13 | @Getter @Setter private SerialA sea ; 14 | @Getter @Setter private byte[] bytes; 15 | 16 | } 17 | -------------------------------------------------------------------------------- /craft-atom-protocol-rpc/src/test/java/io/craft/atom/protocol/rpc/SerialEnum.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.protocol.rpc; 2 | 3 | import lombok.Getter; 4 | 5 | /** 6 | * @author mindwind 7 | * @version 1.0, Jul 25, 2014 8 | */ 9 | public enum SerialEnum { 10 | 11 | A(1, "a"), 12 | B(2, "b"); 13 | 14 | @Getter private int code; 15 | @Getter private String desc; 16 | 17 | private SerialEnum(int code, String desc) { 18 | this.code = code; 19 | this.desc = desc; 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /craft-atom-protocol-ssl/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | 4 | io.craftcode 5 | craft-atom 6 | 3.1.3-SNAPSHOT 7 | 8 | craft-atom-protocol-ssl 9 | craft-atom-protocol-ssl 10 | 11 | 12 | 13 | ${project.groupId} 14 | craft-atom-protocol 15 | ${project.version} 16 | 17 | 18 | ${project.groupId} 19 | craft-atom-util 20 | ${project.version} 21 | 22 | 23 | ${project.groupId} 24 | craft-atom-nio 25 | ${project.version} 26 | test 27 | 28 | 29 | ${project.groupId} 30 | craft-atom-test 31 | ${project.version} 32 | test 33 | 34 | 35 | 36 | org.slf4j 37 | slf4j-api 38 | 39 | 40 | log4j 41 | log4j 42 | test 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /craft-atom-protocol-ssl/src/main/java/io/craft/atom/protocol/ssl/SslHandshakeHandler.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.protocol.ssl; 2 | 3 | /** 4 | * The handshake handler for {@link SslCodec} 5 | * 6 | * @author mindwind 7 | * @version 1.0, Oct 18, 2013 8 | * @deprecated replaced by {@code org.craft.atom.protocol.ssl.spi.SslHandshakeHandler} 9 | */ 10 | public interface SslHandshakeHandler { 11 | 12 | /** 13 | * Need write some handshake data to remote side before handshake can continue. 14 | * 15 | * @param bytes 16 | */ 17 | void needWrite(byte[] bytes); 18 | 19 | } 20 | -------------------------------------------------------------------------------- /craft-atom-protocol-ssl/src/main/java/io/craft/atom/protocol/ssl/api/SslCodec.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.protocol.ssl.api; 2 | 3 | import io.craft.atom.protocol.ssl.spi.SslHandshakeHandler; 4 | 5 | 6 | /** 7 | * SSL codec, it is a combination of ssl encoder and decoder. 8 | * 9 | * @author mindwind 10 | * @version 1.0, Aug 5, 2014 11 | */ 12 | public interface SslCodec { 13 | 14 | /** 15 | * Encode data to ssl encrypted data. 16 | * 17 | * @param data 18 | * @return Encrypted app data 19 | */ 20 | byte[] encode(byte[] data); 21 | 22 | /** 23 | * Decode for ssl encrypted data 24 | * 25 | * @param data 26 | * @return Only decrypted app data, the handshake data will write back to remote by {@link SslHandshakeHandler} 27 | */ 28 | byte[] decode(byte[] data); 29 | 30 | } 31 | -------------------------------------------------------------------------------- /craft-atom-protocol-ssl/src/main/java/io/craft/atom/protocol/ssl/api/SslCodecFactory.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.protocol.ssl.api; 2 | 3 | import io.craft.atom.protocol.ssl.DefaultSslCodec; 4 | 5 | import javax.net.ssl.SSLContext; 6 | 7 | 8 | /** 9 | * SSL codec factory, which provides static factory method to create {@code SslCodec} instance. 10 | * 11 | * @author mindwind 12 | * @version 1.0, Aug 5, 2014 13 | */ 14 | public class SslCodecFactory { 15 | 16 | public static SslCodec newSslCodec(SSLContext sslContext, io.craft.atom.protocol.ssl.spi.SslHandshakeHandler sslHandshakeHandler) { 17 | return new DefaultSslCodec(sslContext, sslHandshakeHandler); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /craft-atom-protocol-ssl/src/main/java/io/craft/atom/protocol/ssl/spi/SslHandshakeHandler.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.protocol.ssl.spi; 2 | 3 | /** 4 | * The handshake handler for {@code SslCodec} 5 | * 6 | * @author mindwind 7 | * @version 1.0, Oct 18, 2013 8 | */ 9 | public interface SslHandshakeHandler { 10 | 11 | /** 12 | * Need write some handshake data to remote side before handshake can continue. 13 | * 14 | * @param bytes 15 | */ 16 | void needWrite(byte[] bytes); 17 | 18 | } 19 | -------------------------------------------------------------------------------- /craft-atom-protocol-ssl/src/test/resources/log4j.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /craft-atom-protocol-ssl/src/test/resources/ssl.keystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mindwind/craft-atom/6c72a2f1669da35bb06c184d7952e4cf2e1297f6/craft-atom-protocol-ssl/src/test/resources/ssl.keystore -------------------------------------------------------------------------------- /craft-atom-protocol-ssl/src/test/resources/ssl.truststore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mindwind/craft-atom/6c72a2f1669da35bb06c184d7952e4cf2e1297f6/craft-atom-protocol-ssl/src/test/resources/ssl.truststore -------------------------------------------------------------------------------- /craft-atom-protocol-textline/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | 4 | io.craftcode 5 | craft-atom 6 | 3.1.3-SNAPSHOT 7 | 8 | craft-atom-protocol-textline 9 | ${project.artifactId} 10 | 11 | 12 | 13 | ${project.groupId} 14 | craft-atom-protocol 15 | ${project.version} 16 | 17 | 18 | ${project.groupId} 19 | craft-atom-test 20 | ${project.version} 21 | test 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /craft-atom-protocol-textline/src/main/java/io/craft/atom/protocol/textline/TextLineEncoder.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.protocol.textline; 2 | 3 | import io.craft.atom.protocol.AbstractProtocolEncoder; 4 | import io.craft.atom.protocol.ProtocolEncoder; 5 | import io.craft.atom.protocol.ProtocolException; 6 | 7 | import java.nio.charset.Charset; 8 | 9 | import lombok.Getter; 10 | import lombok.Setter; 11 | import lombok.ToString; 12 | 13 | 14 | /** 15 | * A {@link ProtocolEncoder} which encodes a text line string into bytes which ends with the delimiter, default charset is utf-8. 16 | *
17 | * Thread safe. 18 | * 19 | * @author Hu Feng 20 | * @version 1.0, Oct 16, 2012 21 | */ 22 | @ToString(callSuper = true, of = { "delimiter" }) 23 | public class TextLineEncoder extends AbstractProtocolEncoder implements ProtocolEncoder { 24 | 25 | 26 | @Getter @Setter private String delimiter = "\n" ; 27 | private int maxLineLength = Integer.MAX_VALUE; 28 | 29 | 30 | // ~ ------------------------------------------------------------------------------------------------------------ 31 | 32 | 33 | public TextLineEncoder() { 34 | super(); 35 | } 36 | 37 | public TextLineEncoder(Charset charset) { 38 | this.charset = charset; 39 | } 40 | 41 | public TextLineEncoder(Charset charset, String delimiter) { 42 | this(charset); 43 | this.delimiter = delimiter; 44 | } 45 | 46 | public TextLineEncoder(Charset charset, String delimiter, int maxLineLength) { 47 | this(charset, delimiter); 48 | this.maxLineLength = maxLineLength; 49 | } 50 | 51 | 52 | // ~ ------------------------------------------------------------------------------------------------------------ 53 | 54 | 55 | @Override 56 | public byte[] encode(String str) throws ProtocolException { 57 | if (str == null) return null; 58 | str += delimiter; 59 | byte[] lineBytes = str.getBytes(charset); 60 | if (lineBytes.length > maxLineLength) { 61 | throw new ProtocolException("Line is too long, maxLineLength=" + maxLineLength ); 62 | } 63 | 64 | return lineBytes; 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /craft-atom-protocol-textline/src/main/java/io/craft/atom/protocol/textline/api/TextLineCodecFactory.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.protocol.textline.api; 2 | 3 | import io.craft.atom.protocol.ProtocolDecoder; 4 | import io.craft.atom.protocol.ProtocolEncoder; 5 | import io.craft.atom.protocol.textline.TextLineDecoder; 6 | import io.craft.atom.protocol.textline.TextLineEncoder; 7 | 8 | import java.nio.charset.Charset; 9 | 10 | 11 | /** 12 | * TextLine codec factory, which provides static factory method to create {@link ProtocolEncoder} and {@link ProtocolDecoder}. 13 | * 14 | * @author mindwind 15 | * @version 1.0, Aug 4, 2014 16 | */ 17 | public class TextLineCodecFactory { 18 | 19 | 20 | public static ProtocolEncoder newTextLineEncoder(Charset charset, String delimiter) { 21 | return new TextLineEncoder(charset, delimiter); 22 | } 23 | 24 | public static ProtocolDecoder newTextLineDecoder(Charset charset, String delimiter) { 25 | return new TextLineDecoder(charset, delimiter); 26 | } 27 | 28 | public static TextLineDecoderBuilder newTextLineDecoderBuilder(Charset charset, String delimiter) { 29 | return new TextLineDecoderBuilder(charset, delimiter); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /craft-atom-protocol-textline/src/main/java/io/craft/atom/protocol/textline/api/TextLineDecoderBuilder.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.protocol.textline.api; 2 | 3 | import io.craft.atom.protocol.ProtocolDecoder; 4 | import io.craft.atom.protocol.textline.TextLineDecoder; 5 | 6 | import java.nio.charset.Charset; 7 | 8 | 9 | /** 10 | * @author mindwind 11 | * @version 1.0, Aug 5, 2014 12 | */ 13 | public class TextLineDecoderBuilder { 14 | 15 | 16 | private String delimiter = "\n" ; 17 | private Charset charset = Charset.forName("utf-8"); 18 | private int defaultBufferSize = 2048 ; 19 | private int maxSize = defaultBufferSize * 1024; 20 | 21 | 22 | public TextLineDecoderBuilder(Charset charset, String delimiter) { 23 | this.delimiter = delimiter; 24 | this.charset = charset; 25 | } 26 | 27 | 28 | public TextLineDecoderBuilder defaultBufferSize(int defaultBufferSize) { this.defaultBufferSize = defaultBufferSize; return this; } 29 | public TextLineDecoderBuilder maxSize (int maxSize) { this.maxSize = maxSize ; return this; } 30 | 31 | 32 | public ProtocolDecoder build() { 33 | return new TextLineDecoder(charset, delimiter, defaultBufferSize, maxSize); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /craft-atom-protocol/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | 4 | io.craftcode 5 | craft-atom 6 | 3.1.3-SNAPSHOT 7 | 8 | craft-atom-protocol 9 | ${project.artifactId} 10 | 11 | 12 | 13 | ${project.groupId} 14 | craft-atom-util 15 | ${project.version} 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /craft-atom-protocol/src/main/java/io/craft/atom/protocol/AbstractProtocolCodec.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.protocol; 2 | 3 | import java.nio.charset.Charset; 4 | 5 | import lombok.Getter; 6 | import lombok.Setter; 7 | import lombok.ToString; 8 | 9 | /** 10 | * @author mindwind 11 | * @version 1.0, Feb 6, 2013 12 | */ 13 | @ToString(of = "charset") 14 | public class AbstractProtocolCodec { 15 | 16 | @Getter @Setter protected Charset charset = Charset.forName("utf-8"); 17 | 18 | } 19 | -------------------------------------------------------------------------------- /craft-atom-protocol/src/main/java/io/craft/atom/protocol/AbstractProtocolEncoder.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.protocol; 2 | 3 | import lombok.ToString; 4 | 5 | /** 6 | * @author mindwind 7 | * @version 1.0, Feb 6, 2013 8 | */ 9 | @ToString(callSuper = true) 10 | public class AbstractProtocolEncoder extends AbstractProtocolCodec { 11 | 12 | } 13 | -------------------------------------------------------------------------------- /craft-atom-protocol/src/main/java/io/craft/atom/protocol/ProtocolDecoder.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.protocol; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * Decodes binary data into higher-level protocol objects, thread safe is not required. 7 | * 8 | * @author mindwind 9 | * @version 1.0, Oct 16, 2012 10 | */ 11 | public interface ProtocolDecoder

{ 12 | 13 | /** 14 | * Decodes binary data into higher-level protocol objects. 15 | * 16 | * @param bytes 17 | * @return higher-level protocol objects, an empty list returned if these bytes are incomplete for protocol definition. 18 | * @throws ProtocolException 19 | */ 20 | List

decode(byte[] bytes) throws ProtocolException; 21 | 22 | /** 23 | * Reset decoder internal state. 24 | */ 25 | void reset(); 26 | 27 | } 28 | -------------------------------------------------------------------------------- /craft-atom-protocol/src/main/java/io/craft/atom/protocol/ProtocolEncoder.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.protocol; 2 | 3 | /** 4 | * Encodes higher-level protocol objects into binary data, implementor should be thread safe. 5 | * 6 | * @author mindwind 7 | * @version 1.0, Oct 16, 2012 8 | */ 9 | public interface ProtocolEncoder

{ 10 | 11 | /** 12 | * Encodes higher-level protocol objects into binary data. 13 | * If input null output null 14 | * 15 | * @param protocolObject 16 | * @return byte array 17 | * @throws ProtocolException 18 | */ 19 | byte[] encode(P protocolObject) throws ProtocolException; 20 | 21 | } 22 | -------------------------------------------------------------------------------- /craft-atom-protocol/src/main/java/io/craft/atom/protocol/ProtocolException.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.protocol; 2 | 3 | import java.util.Arrays; 4 | 5 | 6 | 7 | /** 8 | * An exception that is thrown when {@link ProtocolEncoder} or {@link ProtocolDecoder} 9 | * cannot understand or failed to validate data to process. 10 | * 11 | * @author mindwind 12 | * @version 1.0, Oct 16, 2012 13 | */ 14 | public class ProtocolException extends RuntimeException { 15 | 16 | private static final long serialVersionUID = 2606442495710868565L; 17 | 18 | public ProtocolException() { 19 | super(); 20 | } 21 | 22 | public ProtocolException(String message, Throwable cause) { 23 | super(message, cause); 24 | } 25 | 26 | public ProtocolException(String message) { 27 | super(message); 28 | } 29 | 30 | public ProtocolException(Throwable cause) { 31 | super(cause); 32 | } 33 | 34 | public ProtocolException(ProtocolExceptionType type, Object... params) { 35 | super(type.getDesc() + Arrays.toString(params)); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /craft-atom-protocol/src/main/java/io/craft/atom/protocol/ProtocolExceptionType.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.protocol; 2 | 3 | /** 4 | * Some common protocol exception type enumeration 5 | * 6 | * @author mindwind 7 | * @version 1.0, Feb 4, 2013 8 | */ 9 | public enum ProtocolExceptionType { 10 | 11 | 12 | UNEXPECTED ("Unexpected protocol processing error, cause="), 13 | LINE_LENGTH_LIMIT("Line length limit exceeded, limit="), 14 | MAX_SIZE_LIMIT ("Max size limit exceeded, limit="); 15 | 16 | 17 | private final String desc; 18 | 19 | 20 | private ProtocolExceptionType(String desc) { 21 | this.desc = desc; 22 | } 23 | 24 | public String getDesc() { 25 | return desc; 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /craft-atom-redis/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | 4 | io.craftcode 5 | craft-atom 6 | 3.1.3-SNAPSHOT 7 | 8 | craft-atom-redis 9 | ${project.artifactId} 10 | 11 | 12 | 13 | ${project.groupId} 14 | craft-atom-test 15 | ${project.version} 16 | test 17 | 18 | 19 | redis.clients 20 | jedis 21 | 22 | 23 | org.slf4j 24 | slf4j-api 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /craft-atom-redis/src/main/java/io/craft/atom/redis/AbstractMurmurHashSharded.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.redis; 2 | 3 | import io.craft.atom.redis.api.RedisCommand; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | import java.util.SortedMap; 8 | import java.util.TreeMap; 9 | 10 | import lombok.ToString; 11 | 12 | 13 | /** 14 | * @author mindwind 15 | * @version 1.0, Jun 25, 2013 16 | */ 17 | @ToString(of = {"shards"}) 18 | public abstract class AbstractMurmurHashSharded { 19 | 20 | 21 | private TreeMap nodes ; 22 | private List shards; 23 | private MurmurHash murmur; 24 | 25 | 26 | // ~ ------------------------------------------------------------------------------------------------------------ 27 | 28 | 29 | public AbstractMurmurHashSharded(List shards) { 30 | this.shards = shards; 31 | this.murmur = new MurmurHash(); 32 | init(shards); 33 | } 34 | 35 | private void init(List shards) { 36 | nodes = new TreeMap(); 37 | for (int i = 0; i < shards.size(); i++) { 38 | R redis = shards.get(i); 39 | for (int n = 0; n < 160; n++) { 40 | Long k = murmur.hash("SHARD-" + i + "-NODE-" + n); 41 | nodes.put(k, redis); 42 | } 43 | } 44 | } 45 | 46 | public R shard(String shardkey) { 47 | SortedMap tail = nodes.tailMap(murmur.hash(shardkey)); 48 | if (tail.isEmpty()) { 49 | return nodes.get(nodes.firstKey()); 50 | } 51 | return tail.get(tail.firstKey()); 52 | } 53 | 54 | public List shards() { 55 | return new ArrayList(shards); 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /craft-atom-redis/src/main/java/io/craft/atom/redis/AbstractRedis.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.redis; 2 | 3 | import io.craft.atom.redis.api.RedisCommand; 4 | 5 | /** 6 | * @author mindwind 7 | * @version 1.0, Jun 26, 2013 8 | */ 9 | public abstract class AbstractRedis implements RedisCommand { 10 | 11 | 12 | 13 | 14 | } 15 | -------------------------------------------------------------------------------- /craft-atom-redis/src/main/java/io/craft/atom/redis/DefaultMasterSlaveShardedRedis.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.redis; 2 | 3 | import io.craft.atom.redis.api.MasterSlaveRedis; 4 | import io.craft.atom.redis.api.MasterSlaveShardedRedis; 5 | import io.craft.atom.redis.spi.Sharded; 6 | 7 | import java.util.List; 8 | 9 | import lombok.ToString; 10 | 11 | 12 | /** 13 | * @author mindwind 14 | * @version 1.0, Jun 26, 2013 15 | */ 16 | @ToString(callSuper = true) 17 | public class DefaultMasterSlaveShardedRedis extends AbstractShardedRedis implements MasterSlaveShardedRedis { 18 | 19 | 20 | public DefaultMasterSlaveShardedRedis(List shards) { 21 | this.sharded = new MasterSlaveRedisMurmurHashSharded(shards); 22 | } 23 | 24 | public DefaultMasterSlaveShardedRedis(Sharded sharded) { 25 | this.sharded = sharded; 26 | } 27 | 28 | 29 | // ~ --------------------------------------------------------------------------------------------------------- 30 | 31 | 32 | @Override 33 | public List shards() { 34 | return sharded.shards(); 35 | } 36 | 37 | @Override 38 | public MasterSlaveRedis shard(String shardkey) { 39 | return sharded.shard(shardkey); 40 | } 41 | 42 | @Override 43 | public void enableReadSlave() { 44 | for (MasterSlaveRedis msr : shards()) { 45 | msr.enableReadSlave(); 46 | } 47 | } 48 | 49 | @Override 50 | public void disableReadSlave() { 51 | for (MasterSlaveRedis msr : shards()) { 52 | msr.disableReadSlave(); 53 | } 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /craft-atom-redis/src/main/java/io/craft/atom/redis/DefaultRedisPubSub.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.redis; 2 | 3 | import io.craft.atom.redis.api.RedisPubSub; 4 | import lombok.ToString; 5 | 6 | 7 | import redis.clients.jedis.JedisPubSub; 8 | 9 | /** 10 | * @author mindwind 11 | * @version 1.0, Jul 1, 2013 12 | */ 13 | @ToString 14 | public class DefaultRedisPubSub implements RedisPubSub { 15 | 16 | 17 | private JedisPubSub jps; 18 | 19 | 20 | DefaultRedisPubSub(JedisPubSub jps) { 21 | this.jps = jps; 22 | } 23 | 24 | void subscribe(String... channels) { 25 | jps.subscribe(channels); 26 | } 27 | 28 | void unsubscribe(String... channels) { 29 | if (channels == null || channels.length == 0) { 30 | jps.unsubscribe(); 31 | } else { 32 | jps.unsubscribe(channels); 33 | } 34 | } 35 | 36 | void psubscribe(String... patterns) { 37 | jps.psubscribe(patterns); 38 | } 39 | 40 | void punsubscribe(String... patterns) { 41 | if (patterns == null || patterns.length == 0) { 42 | jps.punsubscribe(); 43 | } else { 44 | jps.punsubscribe(patterns); 45 | } 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /craft-atom-redis/src/main/java/io/craft/atom/redis/DefaultShardedRedis.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.redis; 2 | 3 | import io.craft.atom.redis.api.Redis; 4 | import io.craft.atom.redis.api.ShardedRedis; 5 | import io.craft.atom.redis.spi.Sharded; 6 | 7 | import java.util.List; 8 | 9 | import lombok.ToString; 10 | 11 | 12 | /** 13 | * @author mindwind 14 | * @version 1.0, Jun 25, 2013 15 | */ 16 | @ToString(callSuper = true) 17 | public class DefaultShardedRedis extends AbstractShardedRedis implements ShardedRedis { 18 | 19 | 20 | public DefaultShardedRedis(List shards) { 21 | this.sharded = new RedisMurmurHashSharded(shards); 22 | } 23 | 24 | public DefaultShardedRedis(Sharded sharded) { 25 | this.sharded = sharded; 26 | } 27 | 28 | 29 | // ~ --------------------------------------------------------------------------------------------------------- 30 | 31 | 32 | @Override 33 | public List shards() { 34 | return sharded.shards(); 35 | } 36 | 37 | @Override 38 | public Redis shard(String shardkey) { 39 | return sharded.shard(shardkey); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /craft-atom-redis/src/main/java/io/craft/atom/redis/JedisPubSubAdapter.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.redis; 2 | 3 | import lombok.ToString; 4 | import redis.clients.jedis.JedisPubSub; 5 | 6 | /** 7 | * @author mindwind 8 | * @version 1.0, Jun 23, 2013 9 | */ 10 | @ToString 11 | public class JedisPubSubAdapter extends JedisPubSub { 12 | 13 | @Override 14 | public void onMessage(String channel, String message) { 15 | 16 | } 17 | 18 | @Override 19 | public void onPMessage(String pattern, String channel, String message) { 20 | 21 | } 22 | 23 | @Override 24 | public void onSubscribe(String channel, int subscribedChannels) { 25 | 26 | } 27 | 28 | @Override 29 | public void onUnsubscribe(String channel, int subscribedChannels) { 30 | 31 | } 32 | 33 | @Override 34 | public void onPUnsubscribe(String pattern, int subscribedChannels) { 35 | 36 | } 37 | 38 | @Override 39 | public void onPSubscribe(String pattern, int subscribedChannels) { 40 | 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /craft-atom-redis/src/main/java/io/craft/atom/redis/MasterSlaveRedisMurmurHashSharded.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.redis; 2 | 3 | import io.craft.atom.redis.api.MasterSlaveRedis; 4 | import io.craft.atom.redis.spi.Sharded; 5 | 6 | import java.util.List; 7 | 8 | import lombok.ToString; 9 | 10 | 11 | /** 12 | * @author mindwind 13 | * @version 1.0, Jun 25, 2013 14 | */ 15 | @ToString(callSuper = true) 16 | public class MasterSlaveRedisMurmurHashSharded extends AbstractMurmurHashSharded implements Sharded { 17 | 18 | public MasterSlaveRedisMurmurHashSharded(List shards) { 19 | super(shards); 20 | } 21 | 22 | @Override 23 | public MasterSlaveRedis shard(String shardkey) { 24 | return super.shard(shardkey); 25 | } 26 | 27 | @Override 28 | public List shards() { 29 | return super.shards(); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /craft-atom-redis/src/main/java/io/craft/atom/redis/RedisMurmurHashSharded.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.redis; 2 | 3 | import io.craft.atom.redis.api.Redis; 4 | import io.craft.atom.redis.spi.Sharded; 5 | 6 | import java.util.List; 7 | 8 | import lombok.ToString; 9 | 10 | 11 | /** 12 | * @author mindwind 13 | * @version 1.0, Jun 25, 2013 14 | */ 15 | @ToString(callSuper = true) 16 | public class RedisMurmurHashSharded extends AbstractMurmurHashSharded implements Sharded { 17 | 18 | public RedisMurmurHashSharded(List shards) { 19 | super(shards); 20 | } 21 | 22 | @Override 23 | public Redis shard(String shardkey) { 24 | return super.shard(shardkey); 25 | } 26 | 27 | @Override 28 | public List shards() { 29 | return super.shards(); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /craft-atom-redis/src/main/java/io/craft/atom/redis/api/MasterSlaveRedis.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.redis.api; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * The master-slave redis client. 7 | *

8 | * The master slave should be in chain structure, for example 9 | *

10 |  *         MASTER --- SLAVE1 --- SLAVE2 ... --- ... SLAVEn
11 |  * index     0          1          2                  n
12 |  * 
13 | * All commands would be sent to master node, if switch master would trigger rebuild chain structure as follows: 14 | *
15 |  *         SLAVE0 --> SLAVE1     MASTER2 ... --- ... SLAVEn
16 |  *           |                                         |
17 |  *           |-----------------------------------------|
18 |  * 
19 | * 20 | * @author mindwind 21 | * @version 1.0, Jun 25, 2013 22 | */ 23 | public interface MasterSlaveRedis extends RedisCommand { 24 | 25 | /** 26 | * Set master node by index and rebuild chain. 27 | * 28 | * @param index 29 | */ 30 | void master(int index); 31 | 32 | /** 33 | * Reset master-slave chain, using zero-index node as the master. 34 | */ 35 | void reset(); 36 | 37 | /** 38 | * Enable read from slave and write still on master. 39 | * For commands type "Server" "Connection" and "Transaction" all commands of these type all send to master. 40 | */ 41 | void enableReadSlave(); 42 | 43 | /** 44 | * Disable read from slave. 45 | */ 46 | void disableReadSlave(); 47 | 48 | /** 49 | * @return master redis node. 50 | */ 51 | Redis master(); 52 | 53 | /** 54 | * @return master node index. 55 | */ 56 | int index(); 57 | 58 | /** 59 | * @return master-slave redis chain list. 60 | */ 61 | List chain(); 62 | 63 | } 64 | -------------------------------------------------------------------------------- /craft-atom-redis/src/main/java/io/craft/atom/redis/api/MasterSlaveRedisBuilder.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.redis.api; 2 | 3 | import io.craft.atom.redis.DefaultMasterSlaveRedis; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | 9 | 10 | /** 11 | * Builder for {@link MasterSlaveRedis} 12 | * 13 | * @author mindwind 14 | * @version 1.0, Apr 19, 2014 15 | */ 16 | public class MasterSlaveRedisBuilder extends AbstractRedisBuilder { 17 | 18 | 19 | private String masterslavestring; 20 | 21 | 22 | /** 23 | * @param masterslavestring format string e.g. localhost:6379-localhost:6380-localhost:6381 the first is master, others are slaves. 24 | */ 25 | public MasterSlaveRedisBuilder(String masterslavestring) { 26 | this.masterslavestring = masterslavestring; 27 | } 28 | 29 | 30 | static String[] parse(String masterslavestring) { 31 | return masterslavestring.trim().split("-"); 32 | } 33 | 34 | 35 | @Override 36 | public MasterSlaveRedis build() { 37 | RedisPoolConfig poolConfig = new RedisPoolConfig(); 38 | set(poolConfig); 39 | String[] hostports = parse(masterslavestring); 40 | 41 | List chain = new ArrayList(hostports.length); 42 | for (String hostport : hostports) { 43 | Redis redis = new RedisBuilder(hostport).copy(this).build(); 44 | chain.add(redis); 45 | } 46 | return new DefaultMasterSlaveRedis(chain, 0); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /craft-atom-redis/src/main/java/io/craft/atom/redis/api/MasterSlaveShardedRedis.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.redis.api; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * The master slave sharded redis client. 7 | * 8 | * @author mindwind 9 | * @version 1.0, Jun 25, 2013 10 | */ 11 | public interface MasterSlaveShardedRedis extends ShardedRedisCommand { 12 | 13 | /** 14 | * @return all shards 15 | */ 16 | List shards(); 17 | 18 | /** 19 | * @param shardkey 20 | * @return MasterSlaveRedis instance by shardkey 21 | */ 22 | MasterSlaveRedis shard(String shardkey); 23 | 24 | /** 25 | * Enable all MasterSlaveRedis shards read from slave and write on master. 26 | */ 27 | void enableReadSlave(); 28 | 29 | 30 | /** 31 | * Disable all MasterSlaveRedis shards read from slave. 32 | */ 33 | void disableReadSlave(); 34 | } 35 | -------------------------------------------------------------------------------- /craft-atom-redis/src/main/java/io/craft/atom/redis/api/MasterSlaveShardedRedisBuilder.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.redis.api; 2 | 3 | import io.craft.atom.redis.DefaultMasterSlaveShardedRedis; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | 9 | 10 | /** 11 | * Builder for {@link MasterSlaveShardedRedis} 12 | * 13 | * @author mindwind 14 | * @version 1.0, Apr 19, 2014 15 | */ 16 | public class MasterSlaveShardedRedisBuilder extends AbstractRedisBuilder { 17 | 18 | 19 | private String masterslaveshardstring; 20 | 21 | 22 | /** 23 | * @param masterslaveshardstring format string e.g. localhost:6379-localhost:6380,localhost:6389-localhost:6390 24 | */ 25 | public MasterSlaveShardedRedisBuilder(String masterslaveshardstring) { 26 | this.masterslaveshardstring = masterslaveshardstring; 27 | } 28 | 29 | 30 | static String[] parse(String masterslaveshardstring) { 31 | return masterslaveshardstring.trim().split(","); 32 | } 33 | 34 | 35 | @Override 36 | public MasterSlaveShardedRedis build() { 37 | RedisPoolConfig poolConfig = new RedisPoolConfig(); 38 | set(poolConfig); 39 | String[] masterslavestrings = parse(masterslaveshardstring); 40 | 41 | List shards = new ArrayList(); 42 | for (String masterslavestring : masterslavestrings) { 43 | MasterSlaveRedis msr = new MasterSlaveRedisBuilder(masterslavestring).copy(this).build(); 44 | shards.add(msr); 45 | } 46 | return new DefaultMasterSlaveShardedRedis(shards); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /craft-atom-redis/src/main/java/io/craft/atom/redis/api/Redis.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.redis.api; 2 | 3 | 4 | /** 5 | * The singleton redis client. 6 | * 7 | * @author mindwind 8 | * @version 1.0, May 3, 2013 9 | */ 10 | public interface Redis extends RedisCommand { 11 | 12 | /** 13 | * @return redis server host. 14 | */ 15 | String host(); 16 | 17 | /** 18 | * @return redis server port. 19 | */ 20 | int port(); 21 | 22 | /** 23 | * @return redis server password. 24 | */ 25 | String password(); 26 | 27 | /** 28 | * @return socket connect/read timeout in milliseconds. 29 | */ 30 | int timeoutInMillis(); 31 | 32 | /** 33 | * @return redis database num 34 | */ 35 | int database(); 36 | 37 | /** 38 | * @return redis client connection pool config. 39 | */ 40 | RedisPoolConfig poolConfig(); 41 | 42 | 43 | 44 | } 45 | -------------------------------------------------------------------------------- /craft-atom-redis/src/main/java/io/craft/atom/redis/api/RedisBuilder.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.redis.api; 2 | 3 | import io.craft.atom.redis.DefaultRedis; 4 | 5 | /** 6 | * Builder for {@link Redis} 7 | * 8 | * @author mindwind 9 | * @version 1.0, Apr 19, 2014 10 | */ 11 | public class RedisBuilder extends AbstractRedisBuilder { 12 | 13 | 14 | private String host; 15 | private int port; 16 | 17 | 18 | public RedisBuilder(String host, int port) { 19 | this.host = host; 20 | this.port = port; 21 | } 22 | 23 | /** 24 | * @param hostport format string e.g. localhost:6379 25 | */ 26 | public RedisBuilder(String hostport) { 27 | String[] a = parse(hostport); 28 | this.host = a[0]; 29 | this.port = Integer.parseInt(a[1]); 30 | } 31 | 32 | 33 | static String[] parse(String hostport) { 34 | return hostport.trim().split(":"); 35 | } 36 | 37 | 38 | @Override 39 | public Redis build() { 40 | RedisPoolConfig poolConfig = new RedisPoolConfig(); 41 | set(poolConfig); 42 | return new DefaultRedis(host, port, timeoutInMillis, poolConfig, password, database); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /craft-atom-redis/src/main/java/io/craft/atom/redis/api/RedisConnectionException.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.redis.api; 2 | 3 | /** 4 | * @author mindwind 5 | * @version 1.0, Jun 18, 2013 6 | */ 7 | public class RedisConnectionException extends RedisException { 8 | 9 | 10 | private static final long serialVersionUID = 3878126572474819403L; 11 | 12 | 13 | public RedisConnectionException(String message) { 14 | super(message); 15 | } 16 | 17 | public RedisConnectionException(Throwable cause) { 18 | super(cause); 19 | } 20 | 21 | public RedisConnectionException(String message, Throwable cause) { 22 | super(message, cause); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /craft-atom-redis/src/main/java/io/craft/atom/redis/api/RedisDataException.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.redis.api; 2 | 3 | /** 4 | * @author mindwind 5 | * @version 1.0, Jun 18, 2013 6 | */ 7 | public class RedisDataException extends RedisException { 8 | 9 | 10 | private static final long serialVersionUID = 3878126572474819403L; 11 | 12 | 13 | public RedisDataException(String message) { 14 | super(message); 15 | } 16 | 17 | public RedisDataException(Throwable cause) { 18 | super(cause); 19 | } 20 | 21 | public RedisDataException(String message, Throwable cause) { 22 | super(message, cause); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /craft-atom-redis/src/main/java/io/craft/atom/redis/api/RedisException.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.redis.api; 2 | 3 | /** 4 | * @author mindwind 5 | * @version 1.0, Jun 18, 2013 6 | */ 7 | public class RedisException extends RuntimeException { 8 | 9 | 10 | private static final long serialVersionUID = -2946266495682282677L; 11 | 12 | 13 | public RedisException(String message) { 14 | super(message); 15 | } 16 | 17 | public RedisException(Throwable e) { 18 | super(e); 19 | } 20 | 21 | public RedisException(String message, Throwable cause) { 22 | super(message, cause); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /craft-atom-redis/src/main/java/io/craft/atom/redis/api/RedisPubSub.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.redis.api; 2 | 3 | /** 4 | * @author mindwind 5 | * @version 1.0, Jul 1, 2013 6 | */ 7 | public interface RedisPubSub { 8 | 9 | } 10 | -------------------------------------------------------------------------------- /craft-atom-redis/src/main/java/io/craft/atom/redis/api/ScanResult.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.redis.api; 2 | 3 | import java.util.List; 4 | 5 | import lombok.Getter; 6 | import lombok.ToString; 7 | 8 | /** 9 | * Redis SCAN SSCAN HSCAN ZSCAN command return result object. 10 | * 11 | * @author mindwind 12 | * @version 1.0, Apr 23, 2014 13 | */ 14 | @ToString 15 | public class ScanResult { 16 | 17 | 18 | @Getter private String cursor ; 19 | @Getter private List elements; 20 | 21 | 22 | public ScanResult(String cursor, List elements) { 23 | this.cursor = cursor ; 24 | this.elements = elements; 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /craft-atom-redis/src/main/java/io/craft/atom/redis/api/ShardedRedis.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.redis.api; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * The sharded redis client. 7 | *

8 | * In ShardedRedis, use shardkey force certain keys to go to the same shard.
9 | * In fact we use shardkey to select shard, so we can guarantee atomicity of command execution. 10 | * 11 | * @author mindwind 12 | * @version 1.0, May 4, 2013 13 | */ 14 | public interface ShardedRedis extends ShardedRedisCommand { 15 | 16 | /** 17 | * @return all shards 18 | */ 19 | List shards(); 20 | 21 | /** 22 | * @param shardkey 23 | * @return Redis instance by shardkey 24 | */ 25 | Redis shard(String shardkey); 26 | 27 | 28 | } 29 | -------------------------------------------------------------------------------- /craft-atom-redis/src/main/java/io/craft/atom/redis/api/ShardedRedisBuilder.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.redis.api; 2 | 3 | import io.craft.atom.redis.DefaultShardedRedis; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | 9 | 10 | /** 11 | * Builder for {@link ShardedRedis} 12 | * 13 | * @author mindwind 14 | * @version 1.0, Apr 19, 2014 15 | */ 16 | public class ShardedRedisBuilder extends AbstractRedisBuilder { 17 | 18 | 19 | private String shardstring; 20 | 21 | 22 | /** 23 | * @param shardstring format string e.g. localhost:6379,localhost:6380,localhost:6381 24 | */ 25 | public ShardedRedisBuilder(String shardstring) { 26 | this.shardstring = shardstring; 27 | } 28 | 29 | 30 | static String[] parse(String shardstring) { 31 | return shardstring.trim().split(","); 32 | } 33 | 34 | @Override 35 | public ShardedRedis build() { 36 | RedisPoolConfig poolConfig = new RedisPoolConfig(); 37 | set(poolConfig); 38 | String[] hostports = parse(shardstring); 39 | 40 | List shards = new ArrayList(hostports.length); 41 | for (String hostport : hostports) { 42 | Redis redis = new RedisBuilder(hostport).copy(this).build(); 43 | shards.add(redis); 44 | } 45 | return new DefaultShardedRedis(shards); 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /craft-atom-redis/src/main/java/io/craft/atom/redis/api/Slowlog.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.redis.api; 2 | 3 | import java.util.List; 4 | 5 | import lombok.Getter; 6 | import lombok.ToString; 7 | 8 | /** 9 | * Redis slow log object. 10 | * 11 | * @author mindwind 12 | * @version 1.0, Jun 12, 2013 13 | */ 14 | @ToString 15 | public class Slowlog { 16 | 17 | /** 18 | * Fields description:
19 | * id : A unique progressive identifier for every slow log entry.
20 | * timestamp: The unix timestamp at which the logged command was processed.
21 | * elapse : The amount of time needed for its execution, in microseconds.
22 | * command : The command with arguments. 23 | */ 24 | @Getter private final long id ; 25 | @Getter private final long timestamp; 26 | @Getter private final long elapse ; 27 | @Getter private final List command ; 28 | 29 | 30 | // ~ ----------------------------------------------------------------------------------------------------------- 31 | 32 | 33 | public Slowlog(long id, long timestamp, long elapse, List command) { 34 | super(); 35 | this.id = id ; 36 | this.timestamp = timestamp; 37 | this.elapse = elapse ; 38 | this.command = command ; 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /craft-atom-redis/src/main/java/io/craft/atom/redis/api/handler/RedisMonitorHandler.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.redis.api.handler; 2 | 3 | /** 4 | * Handles redis monitor events. 5 | * 6 | * @author mindwind 7 | * @version 1.0, Jun 12, 2013 8 | */ 9 | public interface RedisMonitorHandler { 10 | 11 | /** 12 | * Invoked on a command be executed. 13 | * 14 | * @param command 15 | */ 16 | void onCommand(String command); 17 | 18 | } 19 | -------------------------------------------------------------------------------- /craft-atom-redis/src/main/java/io/craft/atom/redis/api/handler/RedisPsubscribeHandler.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.redis.api.handler; 2 | 3 | 4 | /** 5 | * Handles redis psubscribe events 6 | * 7 | * @author mindwind 8 | * @version 1.0, Jun 6, 2013 9 | */ 10 | public interface RedisPsubscribeHandler extends RedisPubSubHandler { 11 | 12 | /** 13 | * Invoked on psubscribe occur. 14 | * 15 | * @param pattern 16 | * @param no 17 | */ 18 | void onPsubscribe(String pattern, int no); 19 | 20 | /** 21 | * Invoked on message published to the pattern. 22 | * 23 | * @param pattern 24 | * @param channel 25 | * @param message 26 | */ 27 | void onMessage(String pattern, String channel, String message); 28 | } 29 | -------------------------------------------------------------------------------- /craft-atom-redis/src/main/java/io/craft/atom/redis/api/handler/RedisPubSubHandler.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.redis.api.handler; 2 | 3 | import io.craft.atom.redis.api.RedisException; 4 | 5 | /** 6 | * @author mindwind 7 | * @version 1.0, Jul 1, 2013 8 | */ 9 | public interface RedisPubSubHandler { 10 | 11 | /** 12 | * Invoked on redis exception occur. 13 | * 14 | * @param e 15 | */ 16 | void onException(RedisException e); 17 | 18 | } 19 | -------------------------------------------------------------------------------- /craft-atom-redis/src/main/java/io/craft/atom/redis/api/handler/RedisSubscribeHandler.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.redis.api.handler; 2 | 3 | 4 | 5 | 6 | /** 7 | * Handles redis subscribe events 8 | * 9 | * @author mindwind 10 | * @version 1.0, Jun 6, 2013 11 | */ 12 | public interface RedisSubscribeHandler extends RedisPubSubHandler { 13 | 14 | /** 15 | * Invoked on subscribe occur. 16 | * 17 | * @param channel 18 | * @param no 19 | */ 20 | void onSubscribe(String channel, int no); 21 | 22 | /** 23 | * Invoked on message published to the channel. 24 | * 25 | * @param channel 26 | * @param message 27 | */ 28 | void onMessage(String channel, String message); 29 | 30 | } 31 | -------------------------------------------------------------------------------- /craft-atom-redis/src/main/java/io/craft/atom/redis/spi/Sharded.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.redis.spi; 2 | 3 | import io.craft.atom.redis.api.RedisCommand; 4 | 5 | import java.util.List; 6 | 7 | 8 | /** 9 | * Implements this interface to provide custom sharded algorithm. 10 | * 11 | * @author mindwind 12 | * @version 1.0, Jun 25, 2013 13 | */ 14 | public interface Sharded { 15 | 16 | /** 17 | * @param shardkey 18 | * @return redis shard by shardkey 19 | */ 20 | R shard(String shardkey); 21 | 22 | /** 23 | * @return all redis shards. 24 | */ 25 | List shards(); 26 | 27 | } 28 | -------------------------------------------------------------------------------- /craft-atom-redis/src/test/java/io/craft/atom/redis/AbstractRedisTests.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.redis; 2 | 3 | import io.craft.atom.redis.api.Redis; 4 | import io.craft.atom.redis.api.RedisFactory; 5 | 6 | import org.junit.After; 7 | import org.junit.Assert; 8 | import org.junit.Before; 9 | 10 | /** 11 | * @author mindwind 12 | * @version 1.0, Dec 3, 2013 13 | */ 14 | public abstract class AbstractRedisTests { 15 | 16 | 17 | protected static final int PORT1 = 6379 ; 18 | protected static final int PORT2 = 6380 ; 19 | protected static final int PORT3 = 6381 ; 20 | protected static final String HOST = "127.0.0.1"; 21 | 22 | 23 | protected Redis redis1; 24 | protected Redis redis2; 25 | protected Redis redis3; 26 | 27 | 28 | // ~ ------------------------------------------------------------------------------------------------------------- 29 | 30 | 31 | public AbstractRedisTests() { 32 | init(); 33 | selfcheck(); 34 | } 35 | 36 | 37 | private void init() { 38 | redis1 = RedisFactory.newRedis(HOST, PORT1); 39 | redis2 = RedisFactory.newRedis(HOST, PORT2); 40 | redis3 = RedisFactory.newRedis(HOST, PORT3); 41 | } 42 | 43 | 44 | private void selfcheck() { 45 | try { 46 | redis1.ping(); 47 | } catch (Exception e) { 48 | e.printStackTrace(); 49 | System.err.println("[CRAFT-ATOM-REDIS] Self check for redis1 fail"); 50 | Assert.fail(); 51 | } 52 | 53 | try { 54 | redis2.ping(); 55 | } catch (Exception e) { 56 | e.printStackTrace(); 57 | System.err.println("[CRAFT-ATOM-REDIS] Self check for redis2 fail"); 58 | Assert.fail(); 59 | } 60 | 61 | try { 62 | redis3.ping(); 63 | } catch (Exception e) { 64 | e.printStackTrace(); 65 | System.err.println("[CRAFT-ATOM-REDIS] Self check for redis3 fail"); 66 | Assert.fail(); 67 | } 68 | } 69 | 70 | @Before 71 | public void before() { 72 | clean(); 73 | } 74 | 75 | @After 76 | public void after() { 77 | clean(); 78 | } 79 | 80 | protected void clean() { 81 | try { 82 | redis1.flushall(); 83 | redis2.flushall(); 84 | redis3.flushall(); 85 | } catch (Exception e) { 86 | e.printStackTrace(); 87 | } 88 | } 89 | 90 | } 91 | -------------------------------------------------------------------------------- /craft-atom-redis/src/test/java/io/craft/atom/redis/TestJedisLeak.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.redis; 2 | 3 | import io.craft.atom.redis.api.Redis; 4 | import io.craft.atom.redis.api.RedisDataException; 5 | import io.craft.atom.redis.api.RedisFactory; 6 | import io.craft.atom.redis.api.RedisPoolConfig; 7 | import io.craft.atom.test.CaseCounter; 8 | 9 | import java.util.NoSuchElementException; 10 | 11 | import junit.framework.Assert; 12 | 13 | import org.junit.Test; 14 | 15 | /** 16 | * This test is for issue #1, {@link https://github.com/mindwind/craft-atom/issues/1 } 17 | * 18 | * @author mindwind 19 | * @version 1.0, Jan 21, 2014 20 | */ 21 | public class TestJedisLeak extends AbstractRedisTests { 22 | 23 | 24 | private Redis redis; 25 | 26 | 27 | // ~ ------------------------------------------------------------------------------------------------------------- 28 | 29 | 30 | public TestJedisLeak() { 31 | RedisPoolConfig cfg = new RedisPoolConfig(); 32 | cfg.setMaxTotal(5); 33 | cfg.setMaxIdle(5); 34 | cfg.setMinIdle(0); 35 | cfg.setBlockWhenExhausted(false); 36 | redis = RedisFactory.newRedis(HOST, PORT1, 2000, cfg); 37 | System.out.println(String.format("[CRAFT-ATOM-REDIS] (^_^) <%s> Case -> test jedis leak. ", CaseCounter.incr(1))); 38 | } 39 | 40 | 41 | // ~ ------------------------------------------------------------------------------------------------------------- 42 | 43 | 44 | @Test 45 | public void test() { 46 | String key = "test.jedis.leak"; 47 | redis.hset(key, "1", "1"); 48 | for (int i = 0; i < 10; i++) { 49 | try { 50 | redis.get(key); 51 | } catch (RedisDataException e) { 52 | 53 | } catch (NoSuchElementException e) { 54 | Assert.fail(); 55 | } 56 | } 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /craft-atom-rpc/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | 4 | io.craftcode 5 | craft-atom 6 | 3.1.3-SNAPSHOT 7 | 8 | craft-atom-rpc 9 | craft-atom-rpc 10 | 11 | 12 | 13 | ${project.groupId} 14 | craft-atom-protocol-rpc 15 | ${project.version} 16 | 17 | 18 | ${project.groupId} 19 | craft-atom-nio 20 | ${project.version} 21 | 22 | 23 | ${project.groupId} 24 | craft-atom-test 25 | ${project.version} 26 | test 27 | 28 | 29 | org.slf4j 30 | slf4j-api 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /craft-atom-rpc/src/main/java/io/craft/atom/rpc/AbstractRpcInvoker.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.rpc; 2 | 3 | import io.craft.atom.rpc.spi.RpcConnector; 4 | import io.craft.atom.rpc.spi.RpcInvoker; 5 | import io.craft.atom.rpc.spi.RpcRegistry; 6 | 7 | /** 8 | * @author mindwind 9 | * @version 1.0, Oct 11, 2014 10 | */ 11 | public abstract class AbstractRpcInvoker implements RpcInvoker { 12 | 13 | 14 | @Override 15 | public void setConnector(RpcConnector connector) {} 16 | 17 | @Override 18 | public void setRegistry(RpcRegistry registry) {} 19 | 20 | } 21 | -------------------------------------------------------------------------------- /craft-atom-rpc/src/main/java/io/craft/atom/rpc/DefaultRpcAcceptor.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.rpc; 2 | 3 | 4 | import io.craft.atom.io.IoAcceptor; 5 | import io.craft.atom.io.IoHandler; 6 | import io.craft.atom.nio.NioOrderedDirectChannelEventDispatcher; 7 | import io.craft.atom.nio.api.NioFactory; 8 | import io.craft.atom.rpc.spi.RpcAcceptor; 9 | import io.craft.atom.rpc.spi.RpcProcessor; 10 | import io.craft.atom.rpc.spi.RpcProtocol; 11 | 12 | import java.io.IOException; 13 | import java.net.SocketAddress; 14 | 15 | import lombok.Getter; 16 | import lombok.Setter; 17 | 18 | 19 | /** 20 | * @author mindwind 21 | * @version 1.0, Aug 6, 2014 22 | */ 23 | public class DefaultRpcAcceptor implements RpcAcceptor { 24 | 25 | 26 | @Getter @Setter private int ioTimeoutInMillis; 27 | @Getter @Setter private int connections ; 28 | @Getter @Setter private SocketAddress address ; 29 | @Getter @Setter private RpcProcessor processor ; 30 | @Getter @Setter private RpcProtocol protocol ; 31 | @Getter @Setter private IoHandler ioHandler ; 32 | @Getter @Setter private IoAcceptor ioAcceptor ; 33 | 34 | 35 | // ~ ------------------------------------------------------------------------------------------------------------ 36 | 37 | 38 | public DefaultRpcAcceptor() {} 39 | 40 | 41 | // ~ ------------------------------------------------------------------------------------------------------------ 42 | 43 | 44 | @Override 45 | public void bind() throws IOException { 46 | ioHandler = new RpcServerIoHandler(protocol, processor); 47 | ioAcceptor = NioFactory.newTcpAcceptorBuilder(ioHandler) 48 | .channelSize(connections) 49 | .ioTimeoutInMillis(ioTimeoutInMillis) 50 | .dispatcher(new NioOrderedDirectChannelEventDispatcher()) 51 | .build(); 52 | ioAcceptor.bind(address); 53 | } 54 | 55 | 56 | @Override 57 | public int connectionCount() { 58 | return ioAcceptor.x().aliveChannelCount(); 59 | } 60 | 61 | 62 | @Override 63 | public void close() { 64 | ioAcceptor.shutdown(); 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /craft-atom-rpc/src/main/java/io/craft/atom/rpc/DefaultRpcClientInvoker.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.rpc; 2 | 3 | import io.craft.atom.protocol.rpc.model.RpcMessage; 4 | import io.craft.atom.rpc.api.RpcContext; 5 | import io.craft.atom.rpc.spi.RpcConnector; 6 | import lombok.Getter; 7 | import lombok.Setter; 8 | 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | 12 | /** 13 | * @author mindwind 14 | * @version 1.0, Aug 21, 2014 15 | */ 16 | public class DefaultRpcClientInvoker extends AbstractRpcInvoker { 17 | 18 | 19 | private static final Logger LOG = LoggerFactory.getLogger(DefaultRpcClientInvoker.class); 20 | 21 | 22 | @Getter @Setter private RpcConnector connector; 23 | 24 | 25 | @Override 26 | public RpcMessage invoke(RpcMessage req) throws RpcException { 27 | try { 28 | RpcContext ctx = RpcContext.getContext(); 29 | req.setRpcTimeoutInMillis(rpcTimeoutInMillis(ctx)); 30 | req.setOneway(ctx.isOneway()); 31 | req.setAttachments(ctx.getAttachments()); 32 | req.setRpcId(ctx.getRpcId()); 33 | boolean async = ctx.isAsync(); 34 | LOG.debug("[CRAFT-ATOM-RPC] Rpc client invoker is invoking, |req={}, async={}|", req, async); 35 | return connector.send(req, async); 36 | } finally { 37 | RpcContext.removeContext(); 38 | } 39 | 40 | } 41 | 42 | private int rpcTimeoutInMillis(RpcContext ctx) { 43 | // Get timeout with this invocation from RpcContext 44 | int timeout = ctx.getRpcTimeoutInMillis(); 45 | if (timeout > 0) return timeout; 46 | 47 | // if does not set timeout for this invocation, get global setting. 48 | timeout = connector.getRpcTimeoutInMillis(); 49 | if (timeout > 0) return timeout; 50 | 51 | // default 52 | timeout = Integer.MAX_VALUE; 53 | return timeout; 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /craft-atom-rpc/src/main/java/io/craft/atom/rpc/DefaultRpcClientX.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.rpc; 2 | 3 | import io.craft.atom.rpc.api.RpcClientX; 4 | import lombok.Getter; 5 | import lombok.Setter; 6 | import lombok.ToString; 7 | 8 | 9 | /** 10 | * @author mindwind 11 | * @version 1.0, Oct 14, 2014 12 | */ 13 | @ToString 14 | public class DefaultRpcClientX implements RpcClientX { 15 | 16 | 17 | @Getter @Setter private int waitCount; 18 | 19 | @Override 20 | public int waitCount() { 21 | return waitCount; 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /craft-atom-rpc/src/main/java/io/craft/atom/rpc/DefaultRpcProtocol.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.rpc; 2 | 3 | import io.craft.atom.protocol.ProtocolDecoder; 4 | import io.craft.atom.protocol.ProtocolEncoder; 5 | import io.craft.atom.protocol.rpc.api.RpcCodecFactory; 6 | import io.craft.atom.protocol.rpc.model.RpcMessage; 7 | import io.craft.atom.rpc.spi.RpcProtocol; 8 | 9 | 10 | /** 11 | * @author mindwind 12 | * @version 1.0, Aug 7, 2014 13 | */ 14 | public class DefaultRpcProtocol implements RpcProtocol { 15 | 16 | 17 | private ProtocolEncoder encoder; 18 | 19 | 20 | public DefaultRpcProtocol() { 21 | this.encoder = RpcCodecFactory.newRpcEncoder(); 22 | } 23 | 24 | 25 | @Override 26 | public ProtocolEncoder getRpcEncoder() { 27 | return encoder; 28 | } 29 | 30 | @Override 31 | public ProtocolDecoder getRpcDecoder() { 32 | return RpcCodecFactory.newRpcDecoder(); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /craft-atom-rpc/src/main/java/io/craft/atom/rpc/DefaultRpcProxyFactory.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.rpc; 2 | 3 | import io.craft.atom.rpc.spi.RpcInvoker; 4 | import io.craft.atom.rpc.spi.RpcProxyFactory; 5 | 6 | import java.lang.reflect.Proxy; 7 | 8 | import lombok.Getter; 9 | import lombok.Setter; 10 | 11 | 12 | /** 13 | * @author mindwind 14 | * @version 1.0, Aug 20, 2014 15 | */ 16 | public class DefaultRpcProxyFactory implements RpcProxyFactory { 17 | 18 | 19 | @Getter @Setter private RpcInvoker invoker; 20 | 21 | 22 | @Override 23 | @SuppressWarnings("unchecked") 24 | public T getProxy(Class rpcInterface) { 25 | return (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[] { rpcInterface }, new RpcInvocationHandler(invoker)); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /craft-atom-rpc/src/main/java/io/craft/atom/rpc/DefaultRpcRegistry.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.rpc; 2 | 3 | import io.craft.atom.rpc.spi.RpcApi; 4 | import io.craft.atom.rpc.spi.RpcRegistry; 5 | 6 | import java.util.Collections; 7 | import java.util.Map; 8 | import java.util.Set; 9 | import java.util.TreeSet; 10 | import java.util.concurrent.ConcurrentHashMap; 11 | 12 | 13 | /** 14 | * RPC registry 15 | * 16 | * @author mindwind 17 | * @version 1.0, Aug 12, 2014 18 | */ 19 | public class DefaultRpcRegistry implements RpcRegistry { 20 | 21 | 22 | private Map registry = new ConcurrentHashMap(); 23 | 24 | 25 | @Override 26 | public void register(RpcApi api) { 27 | registry.put(api.getKey(), api); 28 | } 29 | 30 | @Override 31 | public void unregister(RpcApi api) { 32 | registry.remove(api.getKey()); 33 | } 34 | 35 | @Override 36 | public RpcApi lookup(RpcApi api) { 37 | return registry.get(api.getKey()); 38 | } 39 | 40 | @Override 41 | public Set apis() { 42 | Set apis = new TreeSet(registry.values()); 43 | return Collections.unmodifiableSet(apis); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /craft-atom-rpc/src/main/java/io/craft/atom/rpc/DefaultRpcServerX.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.rpc; 2 | 3 | import io.craft.atom.rpc.api.RpcServerX; 4 | import io.craft.atom.rpc.spi.RpcApi; 5 | 6 | import java.util.Map; 7 | import java.util.Set; 8 | 9 | import lombok.Getter; 10 | import lombok.Setter; 11 | import lombok.ToString; 12 | 13 | 14 | /** 15 | * @author mindwind 16 | * @version 1.0, Oct 13, 2014 17 | */ 18 | @ToString 19 | public class DefaultRpcServerX implements RpcServerX { 20 | 21 | 22 | @Getter @Setter private int connectionCount; 23 | @Getter @Setter private Set apis ; 24 | @Getter @Setter private Map counts ; 25 | 26 | 27 | @Override 28 | public int connectionCount() { 29 | return connectionCount; 30 | } 31 | 32 | @Override 33 | public Set apis() { 34 | return apis; 35 | } 36 | 37 | @Override 38 | public int waitCount(RpcApi api) { 39 | return (int) counts.get(api.getKey())[0]; 40 | } 41 | 42 | @Override 43 | public int processingCount(RpcApi api) { 44 | return (int) counts.get(api.getKey())[1]; 45 | } 46 | 47 | @Override 48 | public long completeCount(RpcApi api) { 49 | return counts.get(api.getKey())[2]; 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /craft-atom-rpc/src/main/java/io/craft/atom/rpc/RpcClientIoHandler.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.rpc; 2 | 3 | import io.craft.atom.io.Channel; 4 | import io.craft.atom.protocol.rpc.model.RpcMessage; 5 | 6 | import java.nio.channels.ClosedChannelException; 7 | import java.util.List; 8 | 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | 12 | /** 13 | * @author mindwind 14 | * @version 1.0, Aug 15, 2014 15 | */ 16 | public class RpcClientIoHandler extends RpcIoHandler { 17 | 18 | 19 | private static final Logger LOG = LoggerFactory.getLogger(RpcClientIoHandler.class); 20 | private DefaultRpcConnector connector; 21 | 22 | 23 | // ~ ------------------------------------------------------------------------------------------------------------- 24 | 25 | 26 | public RpcClientIoHandler(DefaultRpcConnector connector) { 27 | this.connector = connector; 28 | } 29 | 30 | 31 | // ~ ------------------------------------------------------------------------------------------------------------- 32 | 33 | 34 | @Override 35 | public void channelRead(Channel channel, byte[] bytes) { 36 | DefaultRpcChannel rpcChannel = (DefaultRpcChannel) channel.getAttribute(RpcIoHandler.RPC_CHANNEL); 37 | List rsps = rpcChannel.read(bytes); 38 | for (RpcMessage rsp : rsps) { 39 | rpcChannel.notifyRpcMessage(rsp); 40 | } 41 | } 42 | 43 | @Override 44 | public void channelClosed(Channel channel) { 45 | LOG.debug("[CRAFT-ATOM-RPC] Channel closed, |channel={}|", channel); 46 | channelThrown0(channel, new ClosedChannelException()); 47 | connector.reconnect(channel.getId()); 48 | } 49 | 50 | @Override 51 | public void channelThrown(Channel channel, Exception cause) { 52 | LOG.warn("[CRAFT-ATOM-RPC] Channel thrown, |channel={}|", channel, cause); 53 | channelThrown0(channel, cause); 54 | channel.close(); 55 | } 56 | 57 | private void channelThrown0(Channel channel, Exception cause) { 58 | DefaultRpcChannel rpcChannel = (DefaultRpcChannel) channel.getAttribute(RpcIoHandler.RPC_CHANNEL); 59 | rpcChannel.notifyRpcException(cause); 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /craft-atom-rpc/src/main/java/io/craft/atom/rpc/RpcException.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.rpc; 2 | 3 | import lombok.Getter; 4 | import lombok.ToString; 5 | 6 | /** 7 | * @author mindwind 8 | * @version 1.0, Aug 8, 2014 9 | */ 10 | @ToString(callSuper = true) 11 | public final class RpcException extends RuntimeException { 12 | 13 | 14 | private static final long serialVersionUID = -4168884981656035910L; 15 | 16 | 17 | public static final byte UNKNOWN = 0 ; 18 | public static final byte NETWORK = 10; 19 | public static final byte CLIENT_BAD_REQ = 40; 20 | public static final byte CLIENT_TIMEOUT = 41; 21 | public static final byte SERVER_ERROR = 50; 22 | public static final byte SERVER_TIMEOUT = 51; 23 | public static final byte SERVER_OVERLOAD = 52; 24 | 25 | 26 | @Getter private byte code; 27 | 28 | 29 | public RpcException() {} 30 | 31 | public RpcException(byte code, String message) { 32 | super(message); 33 | this.code = code; 34 | } 35 | 36 | public RpcException(byte code, String message, Throwable cause) { 37 | super(message, cause); 38 | this.code = code; 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /craft-atom-rpc/src/main/java/io/craft/atom/rpc/RpcFuture.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.rpc; 2 | 3 | import io.craft.atom.protocol.rpc.model.RpcMessage; 4 | 5 | import java.io.IOException; 6 | import java.util.concurrent.Future; 7 | import java.util.concurrent.TimeUnit; 8 | import java.util.concurrent.TimeoutException; 9 | 10 | 11 | /** 12 | * Represents the completion of an asynchronous rpc invocation. 13 | * 14 | * @author mindwind 15 | * @version 1.0, Aug 19, 2014 16 | */ 17 | public interface RpcFuture extends Future { 18 | 19 | 20 | /** 21 | * Wait for the asynchronous operation to complete with the specified timeout. 22 | * 23 | * @param timeout 24 | * @param unit 25 | * @return true if the operation is completed. 26 | * @throws InterruptedException if the current thread was interrupted while waiting 27 | */ 28 | boolean await(long timeout, TimeUnit unit) throws InterruptedException; 29 | 30 | /** 31 | * Returns the cause of the rpc failure if and only if the rpc operation has failed due to an {@link Exception}. 32 | * Otherwise, null is returned. 33 | */ 34 | Exception getException(); 35 | 36 | /** 37 | * Returns the rpc response message, it returns null if this future is not ready. 38 | * @return rpc response message. 39 | * @throws TimeoutException if the wait timed out 40 | * @throws IOException if some other I/O error occurs 41 | */ 42 | RpcMessage getResponse() throws IOException, TimeoutException; 43 | 44 | /** 45 | * Set the cause of the rpc failure, and notifies all threads waiting for 46 | * this future. This method is invoked internally. Please do not call this 47 | * method directly. 48 | * 49 | * @param exception 50 | */ 51 | void setException(Exception exception); 52 | 53 | /** 54 | * Set the rpc response message, and notifies all threads waiting for this 55 | * future. This method is invoked internally. Please do not call this method 56 | * directly. 57 | * 58 | * @param response rpc response message. 59 | */ 60 | void setResponse(RpcMessage response); 61 | 62 | } 63 | -------------------------------------------------------------------------------- /craft-atom-rpc/src/main/java/io/craft/atom/rpc/RpcInvocationHandler.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.rpc; 2 | 3 | import io.craft.atom.protocol.rpc.model.RpcMessage; 4 | import io.craft.atom.rpc.spi.RpcInvoker; 5 | 6 | import java.lang.reflect.InvocationHandler; 7 | import java.lang.reflect.Method; 8 | 9 | import lombok.Getter; 10 | import lombok.Setter; 11 | 12 | import org.slf4j.Logger; 13 | import org.slf4j.LoggerFactory; 14 | 15 | /** 16 | * @author mindwind 17 | * @version 1.0, Aug 20, 2014 18 | */ 19 | public class RpcInvocationHandler implements InvocationHandler { 20 | 21 | 22 | private static final Logger LOG = LoggerFactory.getLogger(RpcInvocationHandler.class); 23 | 24 | 25 | @Getter @Setter private RpcInvoker invoker; 26 | 27 | 28 | public RpcInvocationHandler(RpcInvoker invoker) { 29 | this.invoker = invoker; 30 | } 31 | 32 | 33 | @Override 34 | public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 35 | Class rpcInterface = method.getDeclaringClass(); 36 | String methodName = method.getName(); 37 | Class[] parameterTypes = method.getParameterTypes(); 38 | Object[] parameters = args; 39 | RpcMessage req = RpcMessages.newRequestRpcMessage(rpcInterface, methodName, parameterTypes, parameters); 40 | 41 | LOG.debug("[CRAFT-ATOM-RPC] Rpc client proxy before invocation, |req={}|", req); 42 | RpcMessage rsp = invoker.invoke(req); 43 | LOG.debug("[CRAFT-ATOM-RPC] Rpc client proxy after invocation, |rsp={}|", rsp); 44 | 45 | return RpcMessages.unpackResponseMessage(rsp); 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /craft-atom-rpc/src/main/java/io/craft/atom/rpc/RpcIoHandler.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.rpc; 2 | 3 | import io.craft.atom.io.Channel; 4 | import io.craft.atom.io.IoHandler; 5 | 6 | /** 7 | * @author mindwind 8 | * @version 1.0, Sep 22, 2014 9 | */ 10 | public abstract class RpcIoHandler implements IoHandler { 11 | 12 | 13 | static final String RPC_CHANNEL = "rpc.channel"; 14 | 15 | 16 | @Override 17 | public void channelOpened(Channel channel) {} 18 | @Override 19 | public void channelClosed(Channel channel) {} 20 | @Override 21 | public void channelIdle(Channel channel) {} 22 | @Override 23 | public void channelRead(Channel channel, byte[] bytes) {} 24 | @Override 25 | public void channelFlush(Channel channel, byte[] bytes) {} 26 | @Override 27 | public void channelWritten(Channel channel, byte[] bytes) {} 28 | @Override 29 | public void channelThrown(Channel channel, Exception cause) {} 30 | 31 | } 32 | -------------------------------------------------------------------------------- /craft-atom-rpc/src/main/java/io/craft/atom/rpc/RpcThreadPoolExecutor.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.rpc; 2 | 3 | import io.craft.atom.util.thread.MonitoringThreadPoolExecutor; 4 | 5 | import java.util.concurrent.BlockingQueue; 6 | import java.util.concurrent.ThreadFactory; 7 | import java.util.concurrent.TimeUnit; 8 | 9 | 10 | /** 11 | * @author mindwind 12 | * @version 1.0, Sep 9, 2014 13 | */ 14 | public class RpcThreadPoolExecutor extends MonitoringThreadPoolExecutor { 15 | 16 | 17 | public RpcThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue, ThreadFactory threadFactory) { 18 | super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory); 19 | } 20 | 21 | @Override 22 | public String toString() { 23 | return String 24 | .format("RpcThreadPoolExecutor(" + 25 | "corePoolSize=%s, " + 26 | "maximumPoolSize=%s, " + 27 | "keepAliveTime=%s, " + 28 | "workQueueSize=%s, " + 29 | "poolSize=%s, " + 30 | "activeCount=%s, " + 31 | "largestPoolSize=%s, " + 32 | "taskCount=%s, " + 33 | "completedTaskCount=%s)", 34 | getCorePoolSize(), 35 | getMaximumPoolSize(), 36 | getKeepAliveTime(TimeUnit.SECONDS), 37 | getQueue().size(), 38 | getPoolSize(), 39 | getActiveCount(), 40 | getLargestPoolSize(), 41 | getTaskCount(), 42 | getCompletedTaskCount()); 43 | } 44 | 45 | 46 | } 47 | -------------------------------------------------------------------------------- /craft-atom-rpc/src/main/java/io/craft/atom/rpc/api/RpcClient.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.rpc.api; 2 | 3 | import io.craft.atom.rpc.RpcException; 4 | 5 | /** 6 | * RPC client. 7 | *

8 | * Use {@link RpcFactory} creates a rpc client and invoke remote method by refer a remote api proxy instance. 9 | * Open the client before launch any remote invocation. 10 | * 11 | * @author mindwind 12 | * @version 1.0, Aug 4, 2014 13 | */ 14 | public interface RpcClient extends RpcClientMBean { 15 | 16 | /** 17 | * Refer the rpc api proxy instance which implements the specific rpc interface. 18 | * 19 | * @param rpcInterface 20 | * @return a proxy instance. 21 | */ 22 | T refer(Class rpcInterface); 23 | 24 | /** 25 | * Open the client, connect to rpc server for communicating. 26 | * Just invoke this once. 27 | * 28 | * @throws RpcException If some other rpc error occurs 29 | */ 30 | void open() throws RpcException; 31 | 32 | /** 33 | * Close the client, disconnect all the connections and dispose all other resources. 34 | */ 35 | void close(); 36 | 37 | } 38 | -------------------------------------------------------------------------------- /craft-atom-rpc/src/main/java/io/craft/atom/rpc/api/RpcClientMBean.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.rpc.api; 2 | 3 | /** 4 | * MBean for {@link RpcClient } 5 | * 6 | * @author mindwind 7 | * @version 1.0, Oct 13, 2014 8 | */ 9 | public interface RpcClientMBean { 10 | 11 | /** 12 | * @return x-ray of {@link RpcClient } 13 | */ 14 | RpcClientX x(); 15 | 16 | } 17 | -------------------------------------------------------------------------------- /craft-atom-rpc/src/main/java/io/craft/atom/rpc/api/RpcClientX.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.rpc.api; 2 | 3 | 4 | /** 5 | * The x-ray of {@link RpcClient} 6 | * 7 | * @author mindwind 8 | * @version 1.0, Oct 13, 2014 9 | */ 10 | public interface RpcClientX { 11 | 12 | /** 13 | * @return the approximate wait to be sent request count. 14 | */ 15 | int waitCount(); 16 | 17 | } 18 | -------------------------------------------------------------------------------- /craft-atom-rpc/src/main/java/io/craft/atom/rpc/api/RpcFactory.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.rpc.api; 2 | 3 | /** 4 | * RPC factory, which provides static factory method and builder to create {@link RpcServer} and {@link RpcClient} instance. 5 | * 6 | * @author mindwind 7 | * @version 1.0, Aug 7, 2014 8 | */ 9 | public class RpcFactory { 10 | 11 | 12 | // ~ --------------------------------------------------------------------------------------------------- rpc server 13 | 14 | 15 | public static RpcServer newRpcServer(int port) { 16 | return newRpcServerBuilder(port).build(); 17 | } 18 | 19 | public static RpcServerBuilder newRpcServerBuilder(int port) { 20 | return new RpcServerBuilder().port(port); 21 | } 22 | 23 | 24 | // ~ --------------------------------------------------------------------------------------------------- rpc client 25 | 26 | 27 | public static RpcClient newRpcClient(String host, int port) { 28 | return newRpcClientBuilder(host, port).build(); 29 | } 30 | 31 | public static RpcClientBuilder newRpcClientBuilder(String host, int port) { 32 | return new RpcClientBuilder().host(host).port(port); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /craft-atom-rpc/src/main/java/io/craft/atom/rpc/api/RpcParameter.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.rpc.api; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | import lombok.ToString; 6 | 7 | /** 8 | * RPC behavioral parameter. 9 | * 10 | * @author mindwind 11 | * @version 1.0, Sep 5, 2014 12 | */ 13 | @ToString 14 | public class RpcParameter { 15 | 16 | 17 | /** RPC thread number for each rpc method. */ 18 | @Getter @Setter private int rpcThreads = 1; 19 | 20 | /** RPC queue size for each rpc method. */ 21 | @Getter @Setter private int rpcQueues = 10; 22 | 23 | 24 | public RpcParameter() {} 25 | 26 | public RpcParameter(int rpcThreads, int rpcQueues) { 27 | this.rpcThreads = rpcThreads; 28 | this.rpcQueues = rpcQueues; 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /craft-atom-rpc/src/main/java/io/craft/atom/rpc/api/RpcServerMBean.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.rpc.api; 2 | 3 | /** 4 | * MBean for {@link RpcServer} 5 | * 6 | * @author mindwind 7 | * @version 1.0, Oct 13, 2014 8 | */ 9 | public interface RpcServerMBean { 10 | 11 | /** 12 | * @return x-ray of {@link RpcServer } 13 | */ 14 | RpcServerX x(); 15 | 16 | } 17 | -------------------------------------------------------------------------------- /craft-atom-rpc/src/main/java/io/craft/atom/rpc/api/RpcServerX.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.rpc.api; 2 | 3 | import io.craft.atom.rpc.spi.RpcApi; 4 | 5 | import java.util.Set; 6 | 7 | 8 | /** 9 | * The x-ray of {@link RpcServer} 10 | * 11 | * @author mindwind 12 | * @version 1.0, Oct 13, 2014 13 | */ 14 | public interface RpcServerX { 15 | 16 | /** 17 | * @return current connection count of the rpc server. 18 | */ 19 | int connectionCount(); 20 | 21 | /** 22 | * @return rpc api collection. 23 | */ 24 | Set apis(); 25 | 26 | /** 27 | * @return the approximate wait to be handle request count of the rpc api. 28 | */ 29 | int waitCount(RpcApi api); 30 | 31 | /** 32 | * @return the approximate processing request count of the rpc api. 33 | */ 34 | int processingCount(RpcApi api); 35 | 36 | /** 37 | * @return the approximate complete request count of the rpc api. 38 | */ 39 | long completeCount(RpcApi api); 40 | } 41 | -------------------------------------------------------------------------------- /craft-atom-rpc/src/main/java/io/craft/atom/rpc/spi/RpcAcceptor.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.rpc.spi; 2 | 3 | import java.io.IOException; 4 | import java.net.SocketAddress; 5 | 6 | /** 7 | * RPC acceptor. 8 | *

9 | * Accepts incoming rpc requests, use {@link RpcChannel} to communicate with rpc client. 10 | * 11 | * @see RpcChannel 12 | * @author mindwind 13 | * @version 1.0, Aug 6, 2014 14 | */ 15 | public interface RpcAcceptor { 16 | 17 | /** 18 | * Bind to settled local address. 19 | * 20 | * @throws IOException If some other I/O error occurs 21 | */ 22 | void bind() throws IOException; 23 | 24 | /** 25 | * Close itself and release all the resources. 26 | */ 27 | void close(); 28 | 29 | /** 30 | * Set rpc processor 31 | * 32 | * @param processor 33 | */ 34 | void setProcessor(RpcProcessor processor); 35 | 36 | /** 37 | * Set rpc protocol 38 | * 39 | * @param protocol 40 | */ 41 | void setProtocol(RpcProtocol protocol); 42 | 43 | /** 44 | * Set address to bind. 45 | * 46 | * @param address 47 | */ 48 | void setAddress(SocketAddress address); 49 | 50 | /** 51 | * Set io timeout in millisecond 52 | * 53 | * @param ioTimeoutInMillis 54 | */ 55 | void setIoTimeoutInMillis(int ioTimeoutInMillis); 56 | 57 | /** 58 | * Set max accepted connection size 59 | * 60 | * @param connections 61 | */ 62 | void setConnections(int connections); 63 | 64 | /** 65 | * @return current connection count of the acceptor. 66 | */ 67 | int connectionCount(); 68 | 69 | } 70 | -------------------------------------------------------------------------------- /craft-atom-rpc/src/main/java/io/craft/atom/rpc/spi/RpcApi.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.rpc.spi; 2 | 3 | import io.craft.atom.rpc.api.RpcParameter; 4 | 5 | /** 6 | * RPC api object, used by {@link RpcRegistry} to encapsulate exported remote API. 7 | * 8 | * @author mindwind 9 | * @version 1.0, Oct 11, 2014 10 | */ 11 | public interface RpcApi { 12 | 13 | /** 14 | * @return rpc api key for unique mapping. 15 | */ 16 | String getKey(); 17 | 18 | /** 19 | * @return rpc api name for human read. 20 | */ 21 | String getName(); 22 | 23 | /** 24 | * @return rpc api id for distinguish different implementor. 25 | */ 26 | String getId(); 27 | 28 | /** 29 | * @return rpc api interface. 30 | */ 31 | Class getInterface(); 32 | 33 | /** 34 | * @return rpc api method name. 35 | */ 36 | String getMethodName(); 37 | 38 | /** 39 | * @return rpc api method parameter types. 40 | */ 41 | Class[] getMethodParameterTypes(); 42 | 43 | /** 44 | * @return implementor object of rpc interface 45 | */ 46 | Object getRpcObject(); 47 | 48 | /** 49 | * @return rpc behavioral parameter 50 | */ 51 | RpcParameter getRpcParameter(); 52 | 53 | } 54 | -------------------------------------------------------------------------------- /craft-atom-rpc/src/main/java/io/craft/atom/rpc/spi/RpcChannel.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.rpc.spi; 2 | 3 | import io.craft.atom.protocol.rpc.model.RpcMessage; 4 | import io.craft.atom.rpc.RpcException; 5 | 6 | import java.util.List; 7 | 8 | 9 | /** 10 | * RPC channel, provides abilities:
11 | * - Write RpcMessage to remote peer.
12 | * - Read RpcMessage from remote peer. 13 | * 14 | * @see RpcAcceptor 15 | * @author mindwind 16 | * @version 1.0, Aug 22, 2014 17 | */ 18 | public interface RpcChannel { 19 | 20 | /** 21 | * Write rpc message and encode it to bytes to remote peer of the channel. 22 | * 23 | * @param msg 24 | * @throws RpcException if any other error occurs 25 | */ 26 | void write(RpcMessage msg) throws RpcException; 27 | 28 | /** 29 | * Read bytes and decode it to rcp messages from remote peer of the channel. 30 | * 31 | * @param bytes 32 | * @return rpc message list 33 | */ 34 | List read(byte[] bytes); 35 | 36 | } 37 | -------------------------------------------------------------------------------- /craft-atom-rpc/src/main/java/io/craft/atom/rpc/spi/RpcExecutorFactory.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.rpc.spi; 2 | 3 | import io.craft.atom.rpc.RpcException; 4 | import io.craft.atom.util.thread.MonitoringExecutorService; 5 | 6 | 7 | /** 8 | * RPC executor factory provides method for getting or creating ExecutorService instance. 9 | * 10 | * @see RpcProcessor 11 | * @author mindwind 12 | * @version 1.0, Aug 11, 2014 13 | */ 14 | public interface RpcExecutorFactory { 15 | 16 | /** 17 | * Get a new (or reusable) monitoring executor service. 18 | * 19 | * @param api 20 | * @return executor 21 | * @throws RpcException if any rpc error occurs. 22 | */ 23 | MonitoringExecutorService getExecutor(RpcApi api) throws RpcException; 24 | 25 | /** 26 | * Set rpc registry 27 | * 28 | * @param registry 29 | */ 30 | void setRegistry(RpcRegistry registry); 31 | 32 | /** 33 | * Shutdown the factory 34 | */ 35 | void shutdown(); 36 | 37 | } 38 | -------------------------------------------------------------------------------- /craft-atom-rpc/src/main/java/io/craft/atom/rpc/spi/RpcInvoker.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.rpc.spi; 2 | 3 | import io.craft.atom.protocol.rpc.model.RpcMessage; 4 | import io.craft.atom.rpc.RpcException; 5 | 6 | 7 | /** 8 | * RPC invoker, launch the rpc invocation. 9 | * 10 | * @author mindwind 11 | * @version 1.0, Aug 7, 2014 12 | */ 13 | public interface RpcInvoker { 14 | 15 | /** 16 | * Invoke on the client or server side. 17 | *

18 | * Client Side
19 | * Encode the rpc request and send to the rpc server, wait the server resonse. 20 | *

21 | * Server Side
22 | * Decode the rpc request and invoke the right method of rpc api implementor. 23 | * 24 | * @param req request message 25 | * @return rpc response message 26 | * @throws RpcException if any rpc error occurs. 27 | */ 28 | RpcMessage invoke(RpcMessage req) throws RpcException; 29 | 30 | /** 31 | * Set rpc connector. Only client side invoker need implement this method. 32 | * 33 | * @param connector 34 | */ 35 | void setConnector(RpcConnector connector); 36 | 37 | /** 38 | * Set rpc registry 39 | * 40 | * @param registry 41 | */ 42 | void setRegistry(RpcRegistry registry); 43 | } 44 | -------------------------------------------------------------------------------- /craft-atom-rpc/src/main/java/io/craft/atom/rpc/spi/RpcProcessor.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.rpc.spi; 2 | 3 | import io.craft.atom.protocol.rpc.model.RpcMessage; 4 | 5 | /** 6 | * RPC processor. 7 | *

8 | * Processor in charge of process rpc request, it delegates {@link RpcExecutorFactory} to implement special thread execute strategy 9 | * and delegates {@link RpcInvoker} to implement special reflected invocation. {@code RpcProcessor } itself manages execute timeout and handle exception. 10 | * 11 | * @see RpcInvoker 12 | * @see RpcExecutorFactory 13 | * @author mindwind 14 | * @version 1.0, Aug 7, 2014 15 | */ 16 | public interface RpcProcessor { 17 | 18 | /** 19 | * Process rpc request. 20 | * 21 | * @param req rpc request 22 | * @param channel used to send back rpc response message. 23 | */ 24 | void process(RpcMessage req, RpcChannel channel); 25 | 26 | /** 27 | * Close itself and release all the resources. 28 | */ 29 | void close(); 30 | 31 | /** 32 | * Set rpc invoker. 33 | * 34 | * @param invoker 35 | */ 36 | void setInvoker(RpcInvoker invoker); 37 | 38 | /** 39 | * set rpc executor factory. 40 | * 41 | * @param executorFactory 42 | */ 43 | void setExecutorFactory(RpcExecutorFactory executorFactory); 44 | 45 | /** 46 | * @return the approximate wait request count of the rpc api. 47 | */ 48 | int waitCount(RpcApi api); 49 | 50 | /** 51 | * @return the approximate processing request count of the rpc api. 52 | */ 53 | int processingCount(RpcApi api); 54 | 55 | /** 56 | * @return the approximate complete request count of the rpc api. 57 | */ 58 | long completeCount(RpcApi api); 59 | 60 | } 61 | -------------------------------------------------------------------------------- /craft-atom-rpc/src/main/java/io/craft/atom/rpc/spi/RpcProtocol.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.rpc.spi; 2 | 3 | import io.craft.atom.protocol.ProtocolDecoder; 4 | import io.craft.atom.protocol.ProtocolEncoder; 5 | import io.craft.atom.protocol.rpc.model.RpcMessage; 6 | 7 | 8 | /** 9 | * RPC protocol object, provide protocol encoder and decoder. 10 | * 11 | * @author mindwind 12 | * @version 1.0, Aug 7, 2014 13 | */ 14 | public interface RpcProtocol { 15 | 16 | /** 17 | * @return a new (or reusable) instance of {@link ProtocolEncoder} 18 | */ 19 | ProtocolEncoder getRpcEncoder(); 20 | 21 | 22 | /** 23 | * @return a new (or reusable) instance of {@link ProtocolDecoder} 24 | */ 25 | ProtocolDecoder getRpcDecoder(); 26 | 27 | } 28 | -------------------------------------------------------------------------------- /craft-atom-rpc/src/main/java/io/craft/atom/rpc/spi/RpcProxyFactory.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.rpc.spi; 2 | 3 | /** 4 | * RPC proxy factory provides method for getting or creating dynamic proxy instance. 5 | * 6 | * @see RpcInvoker 7 | * @author mindwind 8 | * @version 1.0, Aug 20, 2014 9 | */ 10 | public interface RpcProxyFactory { 11 | 12 | /** 13 | * Get an instance of proxy class for the specified interface. 14 | * 15 | * @param rpcInterface 16 | * @return a proxy instance that implements the specified interface. 17 | */ 18 | T getProxy(Class rpcInterface); 19 | 20 | /** 21 | * Set rpc invoker. Proxy instance created by factory would use {@link RpcInvoker} to launch a rpc invocation. 22 | * 23 | * @param invoker 24 | */ 25 | void setInvoker(RpcInvoker invoker); 26 | 27 | } 28 | -------------------------------------------------------------------------------- /craft-atom-rpc/src/main/java/io/craft/atom/rpc/spi/RpcRegistry.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.rpc.spi; 2 | 3 | import java.util.Set; 4 | 5 | 6 | /** 7 | * RPC registry 8 | * 9 | * @author mindwind 10 | * @version 1.0, Oct 11, 2014 11 | */ 12 | public interface RpcRegistry { 13 | 14 | /** 15 | * Register a rpc api. 16 | * 17 | * @param api 18 | */ 19 | void register(RpcApi api); 20 | 21 | /** 22 | * Unregister a rpc api. 23 | * 24 | * @param api 25 | */ 26 | void unregister(RpcApi api); 27 | 28 | /** 29 | * Lookup a rpc api. 30 | * 31 | * @param api query api object 32 | * @return result rpc api. 33 | */ 34 | RpcApi lookup(RpcApi api); 35 | 36 | /** 37 | * @return all registered rpc apis. 38 | */ 39 | Set apis(); 40 | } 41 | -------------------------------------------------------------------------------- /craft-atom-rpc/src/test/java/io/craft/atom/rpc/DemoService.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.rpc; 2 | 3 | /** 4 | * @author mindwind 5 | * @version 1.0, Sep 5, 2014 6 | */ 7 | public interface DemoService { 8 | 9 | 10 | String echo(String in); 11 | String attachment(); 12 | String oneway(); 13 | void noreturn(String in); 14 | void timeout(String in) throws InterruptedException; 15 | void overload() throws InterruptedException; 16 | void bizException() throws IllegalAccessException; 17 | void undeclaredException() throws IllegalStateException; 18 | void error(); 19 | 20 | } 21 | -------------------------------------------------------------------------------- /craft-atom-rpc/src/test/java/io/craft/atom/rpc/DemoServiceImpl1.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.rpc; 2 | 3 | import io.craft.atom.io.IllegalChannelStateException; 4 | import io.craft.atom.rpc.api.RpcContext; 5 | 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | /** 10 | * @author mindwind 11 | * @version 1.0, Sep 5, 2014 12 | */ 13 | public class DemoServiceImpl1 implements DemoService { 14 | 15 | 16 | private static final Logger LOG = LoggerFactory.getLogger(DemoServiceImpl1.class); 17 | 18 | 19 | @Override 20 | public String echo(String in) { 21 | return in; 22 | } 23 | 24 | @Override 25 | public void noreturn(String in) { 26 | LOG.debug("[CRAFT-ATOM-RPC] Invoked noreturn() in={}", in); 27 | } 28 | 29 | @Override 30 | public void timeout(String in) throws InterruptedException { 31 | Thread.sleep(200); 32 | } 33 | 34 | @Override 35 | public String attachment() { 36 | RpcContext ctx = RpcContext.getContext(); 37 | String r = ctx.getAttachment("demo"); 38 | return r; 39 | } 40 | 41 | @Override 42 | public String oneway() { 43 | LOG.debug("[CRAFT-ATOM-RPC] Invoked oneway()"); 44 | return "oneway"; 45 | } 46 | 47 | @Override 48 | public void overload() throws InterruptedException { 49 | Thread.sleep(1000); 50 | } 51 | 52 | @Override 53 | public void bizException() throws IllegalAccessException { 54 | throw new IllegalAccessException("biz error"); 55 | } 56 | 57 | @Override 58 | public void error() { 59 | throw new OutOfMemoryError(); 60 | } 61 | 62 | @Override 63 | public void undeclaredException() throws IllegalStateException { 64 | throw new IllegalChannelStateException(); 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /craft-atom-rpc/src/test/java/io/craft/atom/rpc/DemoServiceImpl2.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.rpc; 2 | 3 | /** 4 | * @author mindwind 5 | * @version 1.0, Sep 12, 2014 6 | */ 7 | public class DemoServiceImpl2 extends DemoServiceImpl1 { 8 | 9 | @Override 10 | public String echo(String in) { 11 | return in + in; 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /craft-atom-rpc/src/test/resources/log4j.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /craft-atom-test/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | 4 | io.craftcode 5 | craft-atom 6 | 3.1.3-SNAPSHOT 7 | 8 | craft-atom-test 9 | craft-atom-test 10 | 11 | -------------------------------------------------------------------------------- /craft-atom-test/src/main/java/io/craft/atom/test/CaseCounter.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.test; 2 | 3 | import java.text.DecimalFormat; 4 | import java.util.concurrent.atomic.AtomicInteger; 5 | 6 | /** 7 | * Test case counter. 8 | * 9 | * @author mindwind 10 | * @version 1.0, Sep 26, 2013 11 | */ 12 | public class CaseCounter { 13 | 14 | 15 | private static final AtomicInteger counter = new AtomicInteger(0); 16 | 17 | 18 | public static String incr(int delta) { 19 | String format = "00000"; 20 | DecimalFormat df = new DecimalFormat(format); 21 | long c = counter.addAndGet(delta); 22 | return df.format(c); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /craft-atom-util/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | 4 | 5 | io.craftcode 6 | craft-atom 7 | 3.1.3-SNAPSHOT 8 | 9 | 10 | craft-atom-util 11 | ${project.artifactId} 12 | 13 | 14 | 15 | ${project.groupId} 16 | craft-atom-test 17 | ${project.version} 18 | test 19 | 20 | 21 | org.slf4j 22 | slf4j-api 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /craft-atom-util/src/main/java/io/craft/atom/util/DateUtil.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.util; 2 | 3 | import java.util.Calendar; 4 | import java.util.Date; 5 | 6 | /** 7 | * Date Util 8 | * 9 | * @author mindwind 10 | * @version 1.0, May 15, 2012 11 | * @deprecated use org.apache.commons.lang3.time.DateUtils as an alternative 12 | */ 13 | public class DateUtil { 14 | 15 | /** 16 | * Get the first day of the month specified by date argument. 17 | * 18 | * @param date 19 | * @return the first day of the month 20 | */ 21 | public static Date getMonthHead(Date date){ 22 | if(date == null) { return null; } 23 | 24 | Calendar c = Calendar.getInstance(); 25 | c.setTime(date); 26 | c.set(Calendar.DAY_OF_MONTH, 1); 27 | c.set(Calendar.HOUR, 0); 28 | c.set(Calendar.MINUTE, 0); 29 | c.set(Calendar.SECOND, 0); 30 | return c.getTime(); 31 | } 32 | 33 | /** 34 | * Get today morning 35 | * 36 | * @return today morning date 37 | */ 38 | public static Date getTodayMorning() { 39 | return getMorning(new Date()); 40 | } 41 | 42 | /** 43 | * Get morning of specified date. 44 | * 45 | * @param date 46 | * @return morning date 47 | */ 48 | public static Date getMorning(Date date) { 49 | Calendar c = Calendar.getInstance(); 50 | c.setTime(date); 51 | c.set(Calendar.HOUR_OF_DAY, 0); 52 | c.set(Calendar.MINUTE, 0); 53 | c.set(Calendar.SECOND, 0); 54 | return c.getTime(); 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /craft-atom-util/src/main/java/io/craft/atom/util/GzipUtil.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.util; 2 | 3 | import java.io.ByteArrayInputStream; 4 | import java.io.ByteArrayOutputStream; 5 | import java.io.IOException; 6 | import java.util.zip.GZIPInputStream; 7 | import java.util.zip.GZIPOutputStream; 8 | 9 | /** 10 | * A Gzip utility class that zip and unzip bytes. 11 | * 12 | * @author mindwind 13 | * @version 1.0, Jun 3, 2012 14 | */ 15 | public class GzipUtil { 16 | 17 | /** 18 | * Compress data bytes by gzip algorithm 19 | * 20 | * @param data 21 | * @return compressed data 22 | * @throws IOException 23 | */ 24 | public static byte[] gzip(byte[] data) throws IOException { 25 | if (data == null) { 26 | return data; 27 | } 28 | 29 | ByteArrayOutputStream out = new ByteArrayOutputStream(); 30 | GZIPOutputStream gos = null; 31 | try { 32 | gos = new GZIPOutputStream(out); 33 | gos.write(data); 34 | } finally { 35 | if (gos != null) { 36 | gos.close(); 37 | } 38 | } 39 | 40 | return out.toByteArray(); 41 | } 42 | 43 | /** 44 | * Decompress data bytes with gzip algorithm. 45 | * 46 | * @param data 47 | * @return data decompressed. 48 | * @throws IOException 49 | */ 50 | public static byte[] ungzip(byte[] data) throws IOException { 51 | if (data == null) { return data; } 52 | 53 | ByteArrayOutputStream out = new ByteArrayOutputStream(); 54 | ByteArrayInputStream in = new ByteArrayInputStream(data); 55 | 56 | GZIPInputStream gis = null; 57 | try { 58 | gis = new GZIPInputStream(in); 59 | byte[] buffer = new byte[1024]; 60 | int n; 61 | while ((n = gis.read(buffer)) >= 0) { 62 | out.write(buffer, 0, n); 63 | } 64 | } finally { 65 | if (gis != null) { 66 | gis.close(); 67 | } 68 | } 69 | 70 | return out.toByteArray(); 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /craft-atom-util/src/main/java/io/craft/atom/util/buffer/BufferAllocator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | * 19 | */ 20 | package io.craft.atom.util.buffer; 21 | 22 | import java.nio.ByteBuffer; 23 | 24 | /** 25 | * Allocates {@link AdaptiveByteBuffer}s and manages them. Please implement this 26 | * interface if you need more advanced memory management scheme. 27 | * 28 | * @author Apache MINA Project 29 | */ 30 | public interface BufferAllocator { 31 | 32 | /** 33 | * Returns the buffer which is capable of the specified size. 34 | * 35 | * @param capacity the capacity of the buffer 36 | * @param direct true to get a direct buffer, 37 | * false to get a heap buffer. 38 | */ 39 | AdaptiveByteBuffer allocate(int capacity, boolean direct); 40 | 41 | /** 42 | * Returns the NIO buffer which is capable of the specified size. 43 | * 44 | * @param capacity the capacity of the buffer 45 | * @param direct true to get a direct buffer, 46 | * false to get a heap buffer. 47 | */ 48 | ByteBuffer allocateNioBuffer(int capacity, boolean direct); 49 | 50 | /** 51 | * Wraps the specified NIO {@link ByteBuffer} into MINA buffer. 52 | */ 53 | AdaptiveByteBuffer wrap(ByteBuffer nioBuffer); 54 | 55 | /** 56 | * Dispose of this allocator. 57 | */ 58 | void dispose(); 59 | } 60 | -------------------------------------------------------------------------------- /craft-atom-util/src/main/java/io/craft/atom/util/schedule/ExpirationListener.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.util.schedule; 2 | 3 | /** 4 | * A listener for expired object events. 5 | * 6 | * @author mindwind 7 | * @version 1.0, Sep 20, 2012 8 | * @see TimingWheel 9 | */ 10 | public interface ExpirationListener { 11 | 12 | /** 13 | * Invoking when a expired event occurs. 14 | * 15 | * @param expiredObject 16 | */ 17 | void expired(E expiredObject); 18 | 19 | } 20 | -------------------------------------------------------------------------------- /craft-atom-util/src/main/java/io/craft/atom/util/thread/MonitoringExecutorService.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.util.thread; 2 | 3 | import java.util.concurrent.ExecutorService; 4 | 5 | /** 6 | * An {@link ExecutorService} that provides extra monitoring function. 7 | * 8 | * @author mindwind 9 | * @version 1.0, Oct 13, 2014 10 | */ 11 | public interface MonitoringExecutorService extends ExecutorService { 12 | 13 | /** 14 | * @return the approximate wait task count of the executor. 15 | */ 16 | int waitCount(); 17 | 18 | /** 19 | * @return the approximate executing count of the executor. 20 | */ 21 | int executingCount(); 22 | 23 | /** 24 | * @return the approximate complete count of the executor. 25 | */ 26 | long completeCount(); 27 | 28 | } 29 | -------------------------------------------------------------------------------- /craft-atom-util/src/main/java/io/craft/atom/util/thread/MonitoringThreadPoolExecutor.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.util.thread; 2 | 3 | import java.util.concurrent.BlockingQueue; 4 | import java.util.concurrent.RejectedExecutionHandler; 5 | import java.util.concurrent.ThreadFactory; 6 | import java.util.concurrent.ThreadPoolExecutor; 7 | import java.util.concurrent.TimeUnit; 8 | 9 | /** 10 | * @author mindwind 11 | * @version 1.0, Oct 13, 2014 12 | */ 13 | public class MonitoringThreadPoolExecutor extends ThreadPoolExecutor implements MonitoringExecutorService { 14 | 15 | 16 | public MonitoringThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue, RejectedExecutionHandler handler) { 17 | super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler); 18 | } 19 | 20 | public MonitoringThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) { 21 | super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler); 22 | } 23 | 24 | public MonitoringThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue, ThreadFactory threadFactory) { 25 | super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory); 26 | } 27 | 28 | public MonitoringThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue) { 29 | super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue); 30 | } 31 | 32 | 33 | // ~ ------------------------------------------------------------------------------------------------------------- 34 | 35 | 36 | @Override 37 | public int waitCount() { 38 | return getQueue().size(); 39 | } 40 | 41 | @Override 42 | public int executingCount() { 43 | return getActiveCount(); 44 | } 45 | 46 | @Override 47 | public long completeCount() { 48 | return getCompletedTaskCount(); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /craft-atom-util/src/main/java/io/craft/atom/util/thread/NamedThreadFactory.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.util.thread; 2 | 3 | import java.util.concurrent.ThreadFactory; 4 | import java.util.concurrent.atomic.AtomicInteger; 5 | 6 | import lombok.ToString; 7 | 8 | /** 9 | * A named thread factory implementor.
10 | * When using thread pool with your own named thread is a better practice. 11 | * 12 | * @author mindwind 13 | * @version 1.0, Nov 19, 2012 14 | */ 15 | @ToString 16 | public class NamedThreadFactory implements ThreadFactory { 17 | 18 | 19 | private static final AtomicInteger threadNumber = new AtomicInteger(1); 20 | 21 | 22 | private final String name ; 23 | private final boolean daemon; 24 | 25 | 26 | public NamedThreadFactory(String prefix) { 27 | this(prefix, false); 28 | } 29 | 30 | public NamedThreadFactory(String prefix, boolean daemon) { 31 | this.name = prefix + "-pool-thread-"; 32 | this.daemon = daemon; 33 | } 34 | 35 | @Override 36 | public Thread newThread(Runnable r) { 37 | Thread t = new Thread(r, name + threadNumber.getAndIncrement()); 38 | t.setDaemon(daemon); 39 | return t; 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /craft-atom-util/src/main/scripts/java-thread-monitor.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | 4 | # author: mindwind 5 | # date : Apr 10, 2014 6 | 7 | function monitor() 8 | { 9 | # get load avg last 1 minute 10 | loadavg1=$(cat /proc/loadavg | awk '{print $1}') 11 | 12 | 13 | # load is low (<30), it is normal so we exit 14 | if [ $(echo "$loadavg1 < 30"|bc) = 1 ]; then 15 | echo load=$loadavg1 is normal 16 | return 17 | fi 18 | 19 | 20 | # load is high (>=30), find top 3 java process id 21 | runtime=$(date "+%Y%m%d-%H%M%S") 22 | pids=$(ps auxw|grep 'java'|grep -v 'grep'|sort -rn -k3|head -3|awk '{print $2}') 23 | for p in $pids 24 | do 25 | echo "jstack pid=$p runtime=$runtime" 26 | jstack -F $p > $p-stack-$runtime.log 27 | top -p $p -H -b -n 1 > $p-top-$runtime.log 28 | done 29 | } 30 | 31 | while [ "1" = "1" ] 32 | do 33 | monitor 34 | sleep 5 35 | done -------------------------------------------------------------------------------- /craft-atom-util/src/test/java/io/craft/atom/util/TestGzipUtil.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.util; 2 | 3 | import io.craft.atom.test.CaseCounter; 4 | import io.craft.atom.util.GzipUtil; 5 | 6 | import java.io.IOException; 7 | import java.nio.charset.Charset; 8 | 9 | import junit.framework.Assert; 10 | 11 | import org.junit.Test; 12 | 13 | /** 14 | * Test for {@code GzipUtil} 15 | * 16 | * @author mindwind 17 | * @version 1.0, Feb 9, 2013 18 | */ 19 | public class TestGzipUtil { 20 | 21 | @Test 22 | public void testZipUnzip() throws IOException { 23 | Charset charset = Charset.forName("utf-8"); 24 | String raw = "这是一个gzip压缩测试!!~~hhhllsjf123123"; 25 | byte[] gzipData = GzipUtil.gzip(raw.getBytes(charset)); 26 | String ungzipData = new String(GzipUtil.ungzip(gzipData), charset); 27 | Assert.assertEquals(raw, ungzipData); 28 | System.out.println(String.format("[CRAFT-ATOM-UTIL] (^_^) <%s> Case -> test zip & unzip. ", CaseCounter.incr(1))); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /craft-atom-util/src/test/java/io/craft/atom/util/TestNetUtil.java: -------------------------------------------------------------------------------- 1 | package io.craft.atom.util; 2 | 3 | import io.craft.atom.test.AvailablePortFinder; 4 | import io.craft.atom.test.CaseCounter; 5 | import io.craft.atom.util.NetUtil; 6 | 7 | import java.io.IOException; 8 | import java.net.ServerSocket; 9 | 10 | import junit.framework.Assert; 11 | 12 | import org.junit.Test; 13 | 14 | /** 15 | * @author Hu Feng 16 | * @version 1.0, Dec 31, 2012 17 | */ 18 | public class TestNetUtil { 19 | 20 | 21 | @Test 22 | public void testIsPortUsing() throws IOException { 23 | int port = AvailablePortFinder.getNextAvailable(); 24 | boolean isUsing = NetUtil.isPortUsing("127.0.0.1", port); 25 | Assert.assertFalse(isUsing); 26 | 27 | port = 6666; 28 | ServerSocket ss = new ServerSocket(port); 29 | isUsing = NetUtil.isPortUsing("127.0.0.1", port); 30 | Assert.assertTrue(isUsing); 31 | ss.close(); 32 | System.out.println(String.format("[CRAFT-ATOM-UTIL] (^_^) <%s> Case -> test is port using. ", CaseCounter.incr(2))); 33 | } 34 | 35 | @Test 36 | public void testGetIpv4Address() throws IOException { 37 | String addr = NetUtil.getIpv4Address().getHostAddress(); 38 | Assert.assertNotNull(addr); 39 | addr = NetUtil.getIpv4Address("11.24").getHostAddress(); 40 | Assert.assertNotNull(addr); 41 | System.out.println(String.format("[CRAFT-ATOM-UTIL] (^_^) <%s> Case -> test get ipv4 address. ", CaseCounter.incr(2))); 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /craft-atom-util/src/test/java/io/craft/atom/util/buffer/Bar.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | * 19 | */ 20 | package io.craft.atom.util.buffer; 21 | 22 | 23 | /** 24 | * The subtype of {@link Foo}. It is used to test the serialization of inherited object 25 | * in {@link TestAdaptiveBuffer}. 26 | * 27 | * @author Apache MINA Project 28 | */ 29 | public class Bar extends Foo { 30 | 31 | private static final long serialVersionUID = -7360624845308368521L; 32 | 33 | private int barValue; 34 | 35 | public int getBarValue() { 36 | return barValue; 37 | } 38 | 39 | public void setBarValue(int barValue) { 40 | this.barValue = barValue; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /craft-atom-util/src/test/java/io/craft/atom/util/buffer/Foo.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | * 19 | */ 20 | package io.craft.atom.util.buffer; 21 | 22 | import java.io.Serializable; 23 | 24 | /** 25 | * The parent class of {@link Bar}. It is used to test the serialization of inherited object 26 | * in {@link TestAdaptiveBuffer}. 27 | * 28 | * @author Apache MINA Project 29 | */ 30 | public class Foo implements Serializable { 31 | 32 | private static final long serialVersionUID = 6467037996528575216L; 33 | 34 | private int fooValue; 35 | 36 | public int getFooValue() { 37 | return fooValue; 38 | } 39 | 40 | public void setFooValue(int fooValue) { 41 | this.fooValue = fooValue; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /deploy.sh: -------------------------------------------------------------------------------- 1 | mvn deploy -Dmaven.test.skip=true 2 | -------------------------------------------------------------------------------- /javadoc.sh: -------------------------------------------------------------------------------- 1 | mvn javadoc:javadoc 2 | -------------------------------------------------------------------------------- /release.sh: -------------------------------------------------------------------------------- 1 | mvn clean 2 | mvn install 3 | mvn javadoc:jar 4 | mvn source:jar 5 | mvn release:clean 6 | mvn release:prepare 7 | mvn release:perform 8 | -------------------------------------------------------------------------------- /source.sh: -------------------------------------------------------------------------------- 1 | mvn source:jar 2 | -------------------------------------------------------------------------------- /version.sh: -------------------------------------------------------------------------------- 1 | mvn versions:set -DnewVersion=3.0.0-SNAPSHOT 2 | --------------------------------------------------------------------------------