diff --git a/.classpath b/.classpath new file mode 100644 index 0000000..4a3ff26 --- /dev/null +++ b/.classpath @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.project b/.project new file mode 100644 index 0000000..b3d72bc --- /dev/null +++ b/.project @@ -0,0 +1,23 @@ + + + snrpc + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + org.eclipse.jdt.core.javanature + org.eclipse.m2e.core.maven2Nature + + diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000..f9fe345 --- /dev/null +++ b/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,4 @@ +eclipse.preferences.version=1 +encoding//src/main/java=UTF-8 +encoding//src/test/java=UTF-8 +encoding/=UTF-8 diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..6249222 --- /dev/null +++ b/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,12 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.7 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.source=1.7 diff --git a/.settings/org.eclipse.m2e.core.prefs b/.settings/org.eclipse.m2e.core.prefs new file mode 100644 index 0000000..f897a7f --- /dev/null +++ b/.settings/org.eclipse.m2e.core.prefs @@ -0,0 +1,4 @@ +activeProfiles= +eclipse.preferences.version=1 +resolveWorkspaceProjects=true +version=1 diff --git a/README.md b/README.md new file mode 100644 index 0000000..3a8ffd5 --- /dev/null +++ b/README.md @@ -0,0 +1,70 @@ +SNRPC + +-------------------- + -- a simple netty RPC framework + use protostuff-1.07 for serializer,use netty-3.2.1 for nio. + + ##How to use + + e.g. + + 1, interface and implementor + // define an interface: + public interface SnRpcInterface { + public String getMessage(String param); + } + + // implement interface + public class SnRpcImpl implements SnRpcInterface { + public String getMessage(String param) { + return "hi,it is message from server...param+" + param; + } + } + +2, start server + + SnRpcInterface inter = new SnRpcImpl(); + SnRpcServer server = new SnNettyRpcServer(new Object[] { inter }); + try { + server.start(); + } catch (Throwable e) { + e.printStackTrace(); + } + +3, client invoker + + SnRpcConnectionFactory factory = new SnNettyRpcConnectionFactory( + "localhost", 8080); + factory = new PoolableRpcConnectionFactory(factory); + SnRpcClient client = new CommonSnRpcClient(factory); + try { + SnRpcInterface clazz = client.proxy(SnRpcInterface.class); + String message = clazz.getMessage("come on"); + System.out.println("client receive message .... : " + message); + } catch (Throwable e) { + e.printStackTrace(); + } + +## Pre-requirement + +* JDK6+ +* Maven 2 + + + +# Dependency + +* reflectasm-1.07.jar +* asm-4.0.jar +* log4j-1.2.16.jar +* dom4j-1.6.1.jar +* xml-apis-1.0.b2.jar +* slf4j-api-1.6.6.jar +* netty-3.2.1.Final.jar +* jaxen-1.1.6.jar +* protostuff-core-1.0.7.jar +* protostuff-api-1.0.7.jar +* protostuff-runtime-1.0.7.jar +* protostuff-collectionschema-1.0.7.jar +* commons-pool-1.6.jar + \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..550f793 --- /dev/null +++ b/pom.xml @@ -0,0 +1,91 @@ + + 4.0.0 + + org.stefan + snrpc + 0.0.1-SNAPSHOT + jar + + faraway + http://maven.apache.org + + + UTF-8 + + + + + junit + junit + 3.8.1 + test + + + com.esotericsoftware.reflectasm + reflectasm + 1.07 + + + log4j + log4j + 1.2.16 + runtime + + + dom4j + dom4j + 1.6.1 + + + org.slf4j + slf4j-api + 1.6.6 + true + provided + + + org.jboss.netty + netty + 3.2.1.Final + + + javax.servlet + servlet-api + + + commons-logging + commons-logging + + + true + provided + + + jaxen + jaxen + 1.1.6 + + + com.dyuproject.protostuff + protostuff-core + 1.0.7 + true + provided + + + com.dyuproject.protostuff + protostuff-runtime + 1.0.7 + true + provided + + + commons-pool + commons-pool + 1.6 + true + provided + + + diff --git a/src/main/java/org/stefan/snrpc/SnRpcClient.java b/src/main/java/org/stefan/snrpc/SnRpcClient.java new file mode 100644 index 0000000..03b4537 --- /dev/null +++ b/src/main/java/org/stefan/snrpc/SnRpcClient.java @@ -0,0 +1,9 @@ +package org.stefan.snrpc; + +/** + * @author zhaoliangang 2014-11-13 + */ +public interface SnRpcClient { + + public T proxy(Class interfaceClass) throws Throwable; +} diff --git a/src/main/java/org/stefan/snrpc/SnRpcConnection.java b/src/main/java/org/stefan/snrpc/SnRpcConnection.java new file mode 100644 index 0000000..5157005 --- /dev/null +++ b/src/main/java/org/stefan/snrpc/SnRpcConnection.java @@ -0,0 +1,20 @@ +package org.stefan.snrpc; + +import org.stefan.snrpc.serializer.SnRpcRequest; +import org.stefan.snrpc.serializer.SnRpcResponse; + +/** + * @author zhaoliangang 2014-11-13 + */ +public interface SnRpcConnection { + + SnRpcResponse sendRequest(SnRpcRequest request) throws Throwable; + + void connection() throws Throwable; + + void close() throws Throwable; + + boolean isConnected(); + + boolean isClosed(); +} diff --git a/src/main/java/org/stefan/snrpc/SnRpcConnectionFactory.java b/src/main/java/org/stefan/snrpc/SnRpcConnectionFactory.java new file mode 100644 index 0000000..26432d6 --- /dev/null +++ b/src/main/java/org/stefan/snrpc/SnRpcConnectionFactory.java @@ -0,0 +1,11 @@ +package org.stefan.snrpc; + +/** + * @author zhaoliangang 2014-11-13 + */ +public interface SnRpcConnectionFactory { + + SnRpcConnection getConnection() throws Throwable; + + void recycle(SnRpcConnection connection) throws Throwable; +} diff --git a/src/main/java/org/stefan/snrpc/SnRpcServer.java b/src/main/java/org/stefan/snrpc/SnRpcServer.java new file mode 100644 index 0000000..191f4eb --- /dev/null +++ b/src/main/java/org/stefan/snrpc/SnRpcServer.java @@ -0,0 +1,11 @@ +package org.stefan.snrpc; + +/** + * @author zhaoliangang 2014-11-13 + */ +public interface SnRpcServer { + + void start() throws Throwable; + + void stop() throws Throwable; +} diff --git a/src/main/java/org/stefan/snrpc/client/CommonSnRpcClient.java b/src/main/java/org/stefan/snrpc/client/CommonSnRpcClient.java new file mode 100644 index 0000000..844ddb7 --- /dev/null +++ b/src/main/java/org/stefan/snrpc/client/CommonSnRpcClient.java @@ -0,0 +1,150 @@ +package org.stefan.snrpc.client; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.LinkedList; +import java.util.List; + +import org.stefan.snrpc.SnRpcClient; +import org.stefan.snrpc.SnRpcConnection; +import org.stefan.snrpc.SnRpcConnectionFactory; +import org.stefan.snrpc.log.Logger; +import org.stefan.snrpc.log.LoggerFactory; +import org.stefan.snrpc.serializer.SnRpcRequest; +import org.stefan.snrpc.serializer.SnRpcResponse; +import org.stefan.snrpc.util.Sequence; + +/** + * rpc client + * @author zhaoliangang 2014-11-13 + */ +public class CommonSnRpcClient implements SnRpcClient { + + private static final Logger logger = LoggerFactory + .getLogger(CommonSnRpcClient.class); + + private SnRpcConnectionFactory connectionFactory; + + private SnRpcConnection connection; + + private SnRpcInvoker invoker = new SnRpcInvoker(); + + /** + * @param connectionFactory + */ + public CommonSnRpcClient(SnRpcConnectionFactory connectionFactory) { + if (null == connectionFactory) + throw new NullPointerException("connectionFactory is null..."); + this.connectionFactory = connectionFactory; + } + + /** + * @param connection + */ + public CommonSnRpcClient(SnRpcConnection connection) { + if (null == connection) + throw new NullPointerException("connection is null..."); + this.connection = connection; + } + + /** + * destroy + * @throws Throwable + */ + public void destroy() throws Throwable { + if (null != connection) { + connection.close(); + } + } + + + /** + * generate requestID + * @return + */ + protected String generateRequestID() { + return Sequence.next()+""; + } + + /** + * recycle + * @param connection + */ + private void recycle(SnRpcConnection connection) { + if (null != connection && null != connectionFactory) { + try { + connectionFactory.recycle(connection); + } catch (Throwable t) { + logger.warn("recycle rpc connection fail!", t); + } + } + } + + /** + * get connection + * @return + * @throws Throwable + */ + private SnRpcConnection getConnection() throws Throwable { + if (null != connection) { + if (!connection.isConnected()) { + connection.connection(); + } + return connection; + } else { + return connectionFactory.getConnection(); + } + } + + /* + * proxy + */ + @SuppressWarnings("unchecked") + public T proxy(Class interfaceClass) throws Throwable { + if (!interfaceClass.isInterface()) { + throw new IllegalArgumentException(interfaceClass.getName() + + " is not an interface"); + } + return (T) Proxy.newProxyInstance(interfaceClass.getClassLoader(), + new Class[] { interfaceClass }, invoker); + } + + + /** + * invoker + */ + private class SnRpcInvoker implements InvocationHandler { + public Object invoke(Object proxy, Method method, Object[] args) + throws Throwable { + String className = method.getDeclaringClass().getName(); + List parameterTypes = new LinkedList(); + for (Class parameterType : method.getParameterTypes()) { + parameterTypes.add(parameterType.getName()); + } + + String requestID = generateRequestID(); + SnRpcRequest request = new SnRpcRequest(requestID, className, + method.getName(), parameterTypes.toArray(new String[0]), + args); + SnRpcConnection connection = null; + SnRpcResponse response = null; + try { + connection = getConnection(); + response = connection.sendRequest(request); + } catch (Throwable t) { + logger.warn("send rpc request fail! request: <{}>", + new Object[] { request }, t); + throw new RuntimeException(t); + } finally { + recycle(connection); + } + + if (response.getException() != null) { + throw response.getException(); + } else { + return response.getResult(); + } + } + } +} diff --git a/src/main/java/org/stefan/snrpc/client/PoolableRpcConnectionFactory.java b/src/main/java/org/stefan/snrpc/client/PoolableRpcConnectionFactory.java new file mode 100644 index 0000000..d6712fe --- /dev/null +++ b/src/main/java/org/stefan/snrpc/client/PoolableRpcConnectionFactory.java @@ -0,0 +1,152 @@ +package org.stefan.snrpc.client; + +import org.apache.commons.pool.PoolableObjectFactory; +import org.apache.commons.pool.impl.GenericObjectPool; +import org.stefan.snrpc.SnRpcConnection; +import org.stefan.snrpc.SnRpcConnectionFactory; + +/** + * connection poolable + * + * @author zhaoliangang 2014-11-14 + */ +public class PoolableRpcConnectionFactory implements SnRpcConnectionFactory, + PoolableObjectFactory { + //connectionFactory + private SnRpcConnectionFactory connectionFactory; + + //org.apache.commons.pool + private GenericObjectPool pool = new GenericObjectPool( + this); + + public PoolableRpcConnectionFactory(SnRpcConnectionFactory factory) { + if (null == factory) { + throw new NullPointerException("factory"); + } + this.connectionFactory = factory; + } + + /* get Connection + * @see org.stefan.snrpc.SnRpcConnectionFactory#getConnection() + */ + public SnRpcConnection getConnection() throws Throwable { + return pool.borrowObject(); + } + + /* recycle connection pool + * @see org.stefan.snrpc.SnRpcConnectionFactory#recycle(org.stefan.snrpc.SnRpcConnection) + */ + public void recycle(SnRpcConnection connection) throws Throwable { + if (null != connection) { + pool.returnObject(connection); + } + } + + /** + * destroy connection pool + * @throws Throwable + */ + public void destroy() throws Throwable { + pool.close(); + } + + /* activate connection + * @see org.apache.commons.pool.PoolableObjectFactory#activateObject(java.lang.Object) + */ + public void activateObject(SnRpcConnection connection) throws Exception { + try { + connection.connection(); + } catch (Throwable e) { + throw new Exception(e); + } + } + + /*destroy connection + * @see org.apache.commons.pool.PoolableObjectFactory#destroyObject(java.lang.Object) + */ + public void destroyObject(SnRpcConnection connection) throws Exception { + try { + connection.close(); + } catch (Throwable e) { + throw new Exception(e); + } + } + + /* make connection + * @see org.apache.commons.pool.PoolableObjectFactory#makeObject() + */ + public SnRpcConnection makeObject() throws Exception { + try { + return connectionFactory.getConnection(); + } catch (Throwable e) { + throw new Exception(e); + } + } + + /* passivateconnection + * @see org.apache.commons.pool.PoolableObjectFactory#passivateObject(java.lang.Object) + */ + public void passivateObject(SnRpcConnection connection) throws Exception { + } + + /* validate connection + * @see org.apache.commons.pool.PoolableObjectFactory#validateObject(java.lang.Object) + */ + public boolean validateObject(SnRpcConnection connection) { + return connection.isConnected() && !connection.isClosed(); + } + + public void setLifo(boolean lifo) { + pool.setLifo(lifo); + } + + public void setMaxActive(int maxActive) { + pool.setMaxActive(maxActive); + } + + public void setMaxIdle(int maxIdle) { + pool.setMaxIdle(maxIdle); + } + + public void setMaxWait(long maxWait) { + pool.setMaxWait(maxWait); + } + + public void setMinEvictableIdleTimeMillis(long minEvictableIdleTimeMillis) { + pool.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis); + } + + public void setMinIdle(int minIdle) { + pool.setMinIdle(minIdle); + } + + public void setNumTestsPerEvictionRun(int numTestsPerEvictionRun) { + pool.setNumTestsPerEvictionRun(numTestsPerEvictionRun); + } + + public void setSoftMinEvictableIdleTimeMillis( + long softMinEvictableIdleTimeMillis) { + pool.setSoftMinEvictableIdleTimeMillis(softMinEvictableIdleTimeMillis); + } + + public void setTestOnBorrow(boolean testOnBorrow) { + pool.setTestOnBorrow(testOnBorrow); + } + + public void setTestOnReturn(boolean testOnReturn) { + pool.setTestOnReturn(testOnReturn); + } + + public void setTestWhileIdle(boolean testWhileIdle) { + pool.setTestWhileIdle(testWhileIdle); + } + + public void setTimeBetweenEvictionRunsMillis( + long timeBetweenEvictionRunsMillis) { + pool.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis); + } + + public void setWhenExhaustedAction(byte whenExhaustedAction) { + pool.setWhenExhaustedAction(whenExhaustedAction); + } +} diff --git a/src/main/java/org/stefan/snrpc/client/SnNettyRpcConnection.java b/src/main/java/org/stefan/snrpc/client/SnNettyRpcConnection.java new file mode 100644 index 0000000..b6c38ab --- /dev/null +++ b/src/main/java/org/stefan/snrpc/client/SnNettyRpcConnection.java @@ -0,0 +1,172 @@ +package org.stefan.snrpc.client; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +import org.jboss.netty.bootstrap.ClientBootstrap; +import org.jboss.netty.channel.Channel; +import org.jboss.netty.channel.ChannelFactory; +import org.jboss.netty.channel.ChannelFuture; +import org.jboss.netty.channel.ChannelHandlerContext; +import org.jboss.netty.channel.ChannelPipeline; +import org.jboss.netty.channel.ChannelPipelineFactory; +import org.jboss.netty.channel.Channels; +import org.jboss.netty.channel.MessageEvent; +import org.jboss.netty.channel.SimpleChannelHandler; +import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; +import org.jboss.netty.handler.codec.http.HttpChunkAggregator; +import org.jboss.netty.handler.codec.http.HttpContentCompressor; +import org.jboss.netty.handler.timeout.ReadTimeoutHandler; +import org.jboss.netty.util.HashedWheelTimer; +import org.jboss.netty.util.Timer; +import org.stefan.snrpc.SnRpcConnection; +import org.stefan.snrpc.conf.SnRpcConfig; +import org.stefan.snrpc.serializer.ProtobufSerializer; +import org.stefan.snrpc.serializer.SnRpcRequest; +import org.stefan.snrpc.serializer.SnRpcRequestEncoder; +import org.stefan.snrpc.serializer.SnRpcResponse; +import org.stefan.snrpc.serializer.SnRpcResponseDecoder; + +/** + * Sn netty rpc connection + * @author zhaoliangang 2014-11-13 + */ +public class SnNettyRpcConnection extends SimpleChannelHandler implements + SnRpcConnection { + + //inetsocket address + private InetSocketAddress inetAddr; + + //org.jboss.netty.channel.Channel + private volatile Channel channel; + + //response + private volatile SnRpcResponse response; + + //exception + private volatile Throwable exception; + + //HashedWheelTimer + private volatile Timer timer; + + private boolean connected; + + private SnRpcConfig snRpcConfig = SnRpcConfig.getInstance(); + + public SnNettyRpcConnection(String host, int port) { + snRpcConfig.loadProperties("snrpcserver.properties"); + this.inetAddr = new InetSocketAddress(host, port); + this.timer = new HashedWheelTimer(); + } + + public SnRpcResponse sendRequest(SnRpcRequest request) throws Throwable { + if (!isConnected()) { + throw new IllegalStateException("not connected"); + } + ChannelFuture writeFuture = channel.write(request); + if (!writeFuture.awaitUninterruptibly().isSuccess()) { + close(); + throw writeFuture.getCause(); + } + waitForResponse(); + + Throwable ex = exception; + SnRpcResponse resp = this.response; + this.response = null; + this.exception = null; + + if (null != ex) { + close(); + throw ex; + } + return resp; + } + + public void connection() throws Throwable { + if (connected) { + return; + } + ChannelFactory factory = new NioClientSocketChannelFactory( + Executors.newCachedThreadPool(), + Executors.newCachedThreadPool()); + ClientBootstrap bootstrap = new ClientBootstrap(factory); + + bootstrap.setOption("tcpNoDelay", Boolean.parseBoolean(snRpcConfig + .getProperty("snrpc.tcp.nodelay", "true"))); + bootstrap.setOption("reuseAddress", Boolean.parseBoolean(snRpcConfig + .getProperty("snrpc.tcp.reuseAddress", "true"))); + bootstrap.setPipelineFactory(new ChannelPipelineFactory() { + public ChannelPipeline getPipeline() { + ChannelPipeline pipeline = Channels.pipeline(); + int readTimeout = snRpcConfig.getReadTimeout(); + if (readTimeout > 0) { + pipeline.addLast("timeout", new ReadTimeoutHandler(timer, + readTimeout, TimeUnit.MILLISECONDS)); + } + pipeline.addLast("decoder", new SnRpcRequestEncoder( + ProtobufSerializer.getInstance())); + pipeline.addLast("aggregator", new HttpChunkAggregator(1024*1024)); + pipeline.addLast("encoder", new SnRpcResponseDecoder( + ProtobufSerializer.getInstance())); + pipeline.addLast("deflater", new HttpContentCompressor()); + pipeline.addLast("handler", SnNettyRpcConnection.this); + return pipeline; + } + }); + + ChannelFuture channelFuture = bootstrap.connect(inetAddr); + if (!channelFuture.awaitUninterruptibly().isSuccess()) { + bootstrap.releaseExternalResources(); + throw channelFuture.getCause(); + } + channel = channelFuture.getChannel(); + connected = true; + } + + public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) + throws Exception { + response = (SnRpcResponse) e.getMessage(); + synchronized (channel) { + channel.notifyAll(); + } + } + + public void close() throws Throwable { + connected = false; + if (null != timer) { + timer.stop(); + timer = null; + } + if (null != channel) { + channel.close().awaitUninterruptibly(); + channel.getFactory().releaseExternalResources(); + + this.exception = new IOException("connection closed"); + synchronized (channel) { + channel.notifyAll(); + } + channel = null; + } + } + + public void waitForResponse() { + synchronized (channel) { + try { + channel.wait(); + } catch (InterruptedException e) { + } + } + } + + public boolean isConnected() { + return connected; + } + + public boolean isClosed() { + return (null == channel) || !channel.isConnected() + || !channel.isReadable() || !channel.isWritable(); + } + +} diff --git a/src/main/java/org/stefan/snrpc/client/SnNettyRpcConnectionFactory.java b/src/main/java/org/stefan/snrpc/client/SnNettyRpcConnectionFactory.java new file mode 100644 index 0000000..7a2b7ef --- /dev/null +++ b/src/main/java/org/stefan/snrpc/client/SnNettyRpcConnectionFactory.java @@ -0,0 +1,30 @@ +package org.stefan.snrpc.client; + +import java.net.InetSocketAddress; + +import org.stefan.snrpc.SnRpcConnection; +import org.stefan.snrpc.SnRpcConnectionFactory; + +/** + * SnNettyRpcConnectionFactory + * @author zhaoliangang 2014-11-13 + */ +public class SnNettyRpcConnectionFactory implements SnRpcConnectionFactory { + private InetSocketAddress serverAddr; + + public SnNettyRpcConnectionFactory(String host, int port) { + this.serverAddr = new InetSocketAddress(host, port); + } + + public SnRpcConnection getConnection() throws Throwable { + return new SnNettyRpcConnection(this.serverAddr.getHostName(), + this.serverAddr.getPort()); + } + + public void recycle(SnRpcConnection connection) throws Throwable { + if (null != connection) { + connection.close(); + } + } + +} diff --git a/src/main/java/org/stefan/snrpc/conf/ConfigureParse.java b/src/main/java/org/stefan/snrpc/conf/ConfigureParse.java new file mode 100644 index 0000000..dde5a0d --- /dev/null +++ b/src/main/java/org/stefan/snrpc/conf/ConfigureParse.java @@ -0,0 +1,12 @@ +package org.stefan.snrpc.conf; + +import java.util.List; + +/** + * ConfigureParse + * @author zhaoliangang 2014-11-12 + */ +public interface ConfigureParse { + + List parseService(); +} diff --git a/src/main/java/org/stefan/snrpc/conf/RpcImplementor.java b/src/main/java/org/stefan/snrpc/conf/RpcImplementor.java new file mode 100644 index 0000000..57bd93e --- /dev/null +++ b/src/main/java/org/stefan/snrpc/conf/RpcImplementor.java @@ -0,0 +1,62 @@ +package org.stefan.snrpc.conf; + +import java.io.Serializable; + +import com.esotericsoftware.reflectasm.MethodAccess; + +/** + * RpcImplementor + * @author zhaoliangang 2014-11-12 + */ +public class RpcImplementor implements Serializable { + + private static final long serialVersionUID = 4679847970989376057L; + + private Class processorClass; + + private MethodAccess methodAccess; + + public RpcImplementor() { + } + + /** + * @return the processorClass + */ + public Class getProcessorClass() { + return processorClass; + } + + /** + * @param processorClass + * @param methodAccess + */ + public RpcImplementor(Class processorClass) { + super(); + this.processorClass = processorClass; + this.methodAccess = MethodAccess.get(processorClass); + } + + /** + * @param processorClass + * the processorClass to set + */ + public void setProcessorClass(Class processorClass) { + this.processorClass = processorClass; + } + + /** + * @return the methodAccess + */ + public MethodAccess getMethodAccess() { + return methodAccess; + } + + /** + * @param methodAccess + * the methodAccess to set + */ + public void setMethodAccess(MethodAccess methodAccess) { + this.methodAccess = methodAccess; + } + +} diff --git a/src/main/java/org/stefan/snrpc/conf/RpcService.java b/src/main/java/org/stefan/snrpc/conf/RpcService.java new file mode 100644 index 0000000..851f66c --- /dev/null +++ b/src/main/java/org/stefan/snrpc/conf/RpcService.java @@ -0,0 +1,107 @@ +package org.stefan.snrpc.conf; + +/** + * RpcService + * + * + * + * + * + * + * @author zhaoliangang 2014-11-12 + */ +public class RpcService { + + protected Class typeClass; + protected String id; + protected String name; + private boolean overload = false; + private RpcImplementor rpcImplementor; + + /** + * @param id + * @param name + */ + public RpcService(String id, String name) { + super(); + this.id = id; + this.name = name; + } + + /** + * @return the typeClass + */ + public Class getTypeClass() { + return typeClass; + } + + /** + * @param typeClass + * the typeClass to set + */ + public void setTypeClass(Class typeClass) { + this.typeClass = typeClass; + } + + /** + * @return the id + */ + public String getId() { + return id; + } + + /** + * @param id + * the id to set + */ + public void setId(String id) { + this.id = id; + } + + /** + * @return the name + */ + public String getName() { + return name; + } + + /** + * @param name + * the name to set + */ + public void setName(String name) { + this.name = name; + } + + /** + * @return the overload + */ + public boolean isOverload() { + return overload; + } + + /** + * @param overload + * the overload to set + */ + public void setOverload(boolean overload) { + this.overload = overload; + } + + /** + * @return the rpcImplementor + */ + public RpcImplementor getRpcImplementor() { + return rpcImplementor; + } + + /** + * @param rpcImplementor + * the rpcImplementor to set + */ + public void setRpcImplementor(RpcImplementor rpcImplementor) { + this.rpcImplementor = rpcImplementor; + } + +} diff --git a/src/main/java/org/stefan/snrpc/conf/SnRpcConfig.java b/src/main/java/org/stefan/snrpc/conf/SnRpcConfig.java new file mode 100644 index 0000000..98a19cf --- /dev/null +++ b/src/main/java/org/stefan/snrpc/conf/SnRpcConfig.java @@ -0,0 +1,105 @@ +package org.stefan.snrpc.conf; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Properties; + +import org.stefan.snrpc.exception.SnRpcException; +import org.stefan.snrpc.log.Logger; +import org.stefan.snrpc.log.LoggerFactory; +import org.stefan.snrpc.util.StringUtil; + +/** + * SnRpcConfig + * @author zhaoliangang 2014-11-13 + */ +public class SnRpcConfig { + + private static Logger logger = LoggerFactory.getLogger(SnRpcConfig.class); + + private static SnRpcConfig snRpcConfig; + + private static Properties properties = new Properties(); + + private SnRpcConfig() { + } + + public static SnRpcConfig getInstance() { + if (snRpcConfig == null) + snRpcConfig = new SnRpcConfig(); + return snRpcConfig; + } + + public void loadProperties(String fileName) { + if (StringUtil.isEmpty(fileName)) + throw new SnRpcException("snRpcConfig name is null..."); + InputStream inputStream = null; + try { + inputStream = Thread.currentThread().getContextClassLoader() + .getResourceAsStream(fileName); + properties.load(inputStream); + } catch (IOException e) { + throw new SnRpcException(" snRpcConfig file load failed... " + + fileName); + } finally { + try { + if (inputStream != null) + inputStream.close(); + } catch (IOException e) { + logger.error(e.getMessage(), e); + } + } + if (properties == null) + throw new RuntimeException("Properties file loading failed: " + + fileName); + } + + public Properties getProperties() { + return properties; + } + + public String getProperty(String key) { + return properties.getProperty(key).trim(); + } + + public String getProperty(String key, String defaultValue) { + return properties.getProperty(key, defaultValue.trim()); + } + + /** + * get the service properties file,default is config.xml + * + * @return + */ + public String getpropertiesFile() { + String f = properties.getProperty("properties.file", "config.xml"); + return f.trim(); + } + + public boolean getDevMod() { + String dev = properties.getProperty("snrpc.dev", "false"); + return Boolean.parseBoolean(dev); + } + + /** + * get the method's invoke timeout,default is 3s + * + * @return + */ + public int getReadTimeout() { + String timeOutStr = properties + .getProperty("snrpc.read.timeout", "3000"); + return Integer.parseInt(timeOutStr); + } + + /** + * get the server's HTTP port,default is -1 + * + * @return + */ + public int getHttpPort() { + String port = properties.getProperty("snrpc.http.port", "-1"); + return Integer.parseInt(port); + } + +} diff --git a/src/main/java/org/stefan/snrpc/conf/XmlConfigureParse.java b/src/main/java/org/stefan/snrpc/conf/XmlConfigureParse.java new file mode 100644 index 0000000..36a4ecd --- /dev/null +++ b/src/main/java/org/stefan/snrpc/conf/XmlConfigureParse.java @@ -0,0 +1,150 @@ +package org.stefan.snrpc.conf; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + +import org.dom4j.Document; +import org.dom4j.Element; +import org.dom4j.Node; +import org.dom4j.io.SAXReader; +import org.stefan.snrpc.log.Logger; +import org.stefan.snrpc.log.LoggerFactory; +import org.stefan.snrpc.util.StringUtil; + +/** + * + * XmlConfigureParse + * + + + + + + + * @author zhaoliangang 2014-11-12 + */ +public class XmlConfigureParse implements ConfigureParse { + + private static final Logger logger = LoggerFactory + .getLogger(XmlConfigureParse.class); + + private String configFile = null; + private Document document = null; + private Element root = null; + + /** + * @param configFile + * @param root + */ + public XmlConfigureParse(String configFile) { + super(); + this.configFile = configFile; + this.root = getRoot(); + } + + @SuppressWarnings("unchecked") + private Element getRoot() { + Document doc = getDocument(); + List list = doc.selectNodes("//application"); + if (list.size() > 0) { + Element aroot = list.get(0); + return aroot; + } + return null; + } + + private Document getDocument() { + InputStream is = getFileStream(); + try { + if (document == null) { + SAXReader sr = new SAXReader(); + sr.setValidation(false); + if (is == null) { + throw new RuntimeException("can not find config file..." + + configFile); + } + document = sr.read(is); + } + } catch (Exception e) { + logger.error(e.getMessage(), e); + throw new RuntimeException("get xml file failed"); + } finally { + if (is != null) + try { + is.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + return document; + } + + private InputStream getFileStream() { + return getFileStream(configFile); + } + + private InputStream getFileStream(String fileName) { + InputStream is = Thread.currentThread().getContextClassLoader() + .getResourceAsStream(fileName); + return is; + } + + @SuppressWarnings("unchecked") + public List parseService() { + + List slist = new ArrayList(); + Node serviceRoot = root.selectSingleNode("//rpcServices"); + List serviceList = serviceRoot.selectNodes("//rpcService"); + + int i = 0; + for (Element serviceNode : serviceList) { + String name = serviceNode.attributeValue("name");// service name + String interfaceStr = serviceNode.attributeValue("interface"); + String overloadStr = serviceNode.attributeValue("overload"); + + if (StringUtil.isEmpty(name)) { + logger.warn(configFile + ":a rpcservice's name is empty."); + continue; + } + if (StringUtil.isEmpty(interfaceStr)) { + logger.warn(configFile + ":rpcservice[" + name + + "] has an empty interface configure."); + continue; + } + Class type = null; + try { + type = Class.forName(interfaceStr); + } catch (ClassNotFoundException e) { + logger.error(e.getMessage()); + throw new RuntimeException("can't find rpc Interface:" + + interfaceStr); + } + RpcService service = new RpcService("" + i, name); + service.setTypeClass(type); + + if (StringUtil.isNotEmpty(overloadStr) + && "true".equals(overloadStr.trim())) { + service.setOverload(true); + } + + Element rpcImplementor = serviceNode.element("rpcImplementor"); + String processor = rpcImplementor.attributeValue("class"); + Class providerClass = null; + try { + providerClass = Class.forName(processor); + } catch (ClassNotFoundException e) { + logger.error(e.getMessage()); + throw new RuntimeException("can't find rpcImplementor Class:" + + processor); + } + RpcImplementor sv = new RpcImplementor(providerClass); + service.setRpcImplementor(sv); + slist.add(service); + i++; + } + return slist; + } + +} diff --git a/src/main/java/org/stefan/snrpc/exception/SerializerException.java b/src/main/java/org/stefan/snrpc/exception/SerializerException.java new file mode 100644 index 0000000..5dbf466 --- /dev/null +++ b/src/main/java/org/stefan/snrpc/exception/SerializerException.java @@ -0,0 +1,28 @@ +package org.stefan.snrpc.exception; + +/** + * SerializerException + * + * @author zhaoliangang + * + */ +public class SerializerException extends RuntimeException { + + private static final long serialVersionUID = -6831220895401658422L; + + public SerializerException() { + super(); + } + + public SerializerException(String msg) { + super(msg); + } + + public SerializerException(Throwable t) { + super(t); + } + + public SerializerException(String msg, Throwable t) { + super(msg, t); + } +} diff --git a/src/main/java/org/stefan/snrpc/exception/SnRpcException.java b/src/main/java/org/stefan/snrpc/exception/SnRpcException.java new file mode 100644 index 0000000..ab464fe --- /dev/null +++ b/src/main/java/org/stefan/snrpc/exception/SnRpcException.java @@ -0,0 +1,28 @@ +package org.stefan.snrpc.exception; + +/** + * SnRpcException + * + * @author zhaoliangang + * + */ +public class SnRpcException extends RuntimeException { + + private static final long serialVersionUID = 6443147893553933129L; + + public SnRpcException() { + super(); + } + + public SnRpcException(String msg) { + super(msg); + } + + public SnRpcException(Throwable t) { + super(t); + } + + public SnRpcException(String msg, Throwable t) { + super(msg, t); + } +} diff --git a/src/main/java/org/stefan/snrpc/log/AbstractLogger.java b/src/main/java/org/stefan/snrpc/log/AbstractLogger.java new file mode 100644 index 0000000..42386c8 --- /dev/null +++ b/src/main/java/org/stefan/snrpc/log/AbstractLogger.java @@ -0,0 +1,256 @@ +package org.stefan.snrpc.log; + +/** + * @author zhaoliangang 2014-11-12 + */ +public abstract class AbstractLogger implements Logger { + + private final String name; + + /** + * Instantiate the abstract logger. + */ + protected AbstractLogger(String nm) { + super(); + if (nm == null) { + throw new NullPointerException("Logger name may not be null."); + } + name = nm; + } + + /** + * Get the name of this logger. + */ + public String getName() { + return (name); + } + + /** + * Get the throwable from the last element of this array if it is Throwable, + * else null. + */ + public Throwable getThrowable(Object args[]) { + Throwable rv = null; + if (args.length > 0) { + if (args[args.length - 1] instanceof Throwable) { + rv = (Throwable) args[args.length - 1]; + } + } + return rv; + } + + /** + * True if debug is enabled for this logger. Default implementation always + * returns false + * + * @return true if debug messages would be displayed + */ + public abstract boolean isDebugEnabled(); + + /** + * True if debug is enabled for this logger. Default implementation always + * returns false + * + * @return true if info messages would be displayed + */ + public abstract boolean isInfoEnabled(); + + /** + * Log a message at debug level. + * + * @param message + * the message to log + * @param exception + * the exception that caused the message to be generated + */ + public void debug(Object message, Throwable exception) { + log(Level.DEBUG, message, exception); + } + + /** + * Log a formatted message at debug level. + * + * @param message + * the message to log + * @param args + * the arguments for that message + */ + public void debug(String message, Object... args) { + if (isDebugEnabled()) { + debug(String.format(message, args), getThrowable(args)); + } + } + + /** + * Log a message at debug level. + * + * @param message + * the message to log + */ + public void debug(Object message) { + debug(message, null); + } + + /** + * Log a message at info level. + * + * @param message + * the message to log + * @param exception + * the exception that caused the message to be generated + */ + public void info(Object message, Throwable exception) { + log(Level.INFO, message, exception); + } + + /** + * Log a formatted message at info level. + * + * @param message + * the message to log + * @param args + * the arguments for that message + */ + public void info(String message, Object... args) { + if (isInfoEnabled()) { + info(String.format(message, args), getThrowable(args)); + } + } + + /** + * Log a message at info level. + * + * @param message + * the message to log + */ + public void info(Object message) { + info(message, null); + } + + /** + * Log a message at warning level. + * + * @param message + * the message to log + * @param exception + * the exception that caused the message to be generated + */ + public void warn(Object message, Throwable exception) { + log(Level.WARN, message, exception); + } + + /** + * Log a formatted message at debug level. + * + * @param message + * the message to log + * @param args + * the arguments for that message + */ + public void warn(String message, Object... args) { + warn(String.format(message, args), getThrowable(args)); + } + + /** + * Log a message at warning level. + * + * @param message + * the message to log + */ + public void warn(Object message) { + warn(message, null); + } + + /** + * Log a message at error level. + * + * @param message + * the message to log + * @param exception + * the exception that caused the message to be generated + */ + public void error(Object message, Throwable exception) { + log(Level.ERROR, message, exception); + } + + /** + * Log a formatted message at debug level. + * + * @param message + * the message to log + * @param args + * the arguments for that message + */ + public void error(String message, Object... args) { + error(String.format(message, args), getThrowable(args)); + } + + /** + * Log a message at error level. + * + * @param message + * the message to log + */ + public void error(Object message) { + error(message, null); + } + + /** + * Log a message at fatal level. + * + * @param message + * the message to log + * @param exception + * the exception that caused the message to be generated + */ + public void fatal(Object message, Throwable exception) { + log(Level.FATAL, message, exception); + } + + /** + * Log a formatted message at debug level. + * + * @param message + * the message to log + * @param args + * the arguments for that message + */ + public void fatal(String message, Object... args) { + fatal(String.format(message, args), getThrowable(args)); + } + + /** + * Log a message at fatal level. + * + * @param message + * the message to log + */ + public void fatal(Object message) { + fatal(message, null); + } + + /** + * Log a message at the given level. + * + * @param level + * the level + * @param message + * the message + */ + public void log(Level level, Object message) { + log(level, message, null); + } + + /** + * Subclasses should implement this method to determine what to do when a + * client wants to log at a particular level. + * + * @param level + * the level to log at (see the fields of this class) + * @param message + * the message to log + * @param e + * the exception that caused the message (or null) + */ + public abstract void log(Level level, Object message, Throwable e); +} diff --git a/src/main/java/org/stefan/snrpc/log/DefaultLogger.java b/src/main/java/org/stefan/snrpc/log/DefaultLogger.java new file mode 100644 index 0000000..85a0dc5 --- /dev/null +++ b/src/main/java/org/stefan/snrpc/log/DefaultLogger.java @@ -0,0 +1,52 @@ +package org.stefan.snrpc.log; + +import java.text.SimpleDateFormat; +import java.util.Date; + +/** + * @author zhaoliangang 2014-11-12 + */ +public class DefaultLogger extends AbstractLogger { + + private final SimpleDateFormat df; + + /** + * Get an instance of DefaultLogger. + */ + public DefaultLogger(String name) { + super(name); + df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); + } + + /** + * False. + */ + @Override + public boolean isDebugEnabled() { + return (false); + } + + /** + * True. + */ + @Override + public boolean isInfoEnabled() { + return (true); + } + + /** + * @see AbstractLogger + */ + @Override + public synchronized void log(Level level, Object message, Throwable e) { + if (level == Level.INFO || level == Level.WARN || level == Level.ERROR + || level == Level.FATAL) { + System.err.printf("%s %s %s: %s\n", df.format(new Date()), + level.name(), getName(), message); + if (e != null) { + e.printStackTrace(); + } + } + } + +} \ No newline at end of file diff --git a/src/main/java/org/stefan/snrpc/log/Level.java b/src/main/java/org/stefan/snrpc/log/Level.java new file mode 100644 index 0000000..e689b70 --- /dev/null +++ b/src/main/java/org/stefan/snrpc/log/Level.java @@ -0,0 +1,18 @@ +package org.stefan.snrpc.log; + +/** + * log level + * + * @author zhaoliangang + * + */ +public enum Level { + + DEBUG, INFO, WARN, ERROR, FATAL; + + @Override + public String toString() { + return "{LogLevel:" + name() + "}"; + } + +} diff --git a/src/main/java/org/stefan/snrpc/log/Log4JLogger.java b/src/main/java/org/stefan/snrpc/log/Log4JLogger.java new file mode 100644 index 0000000..522a1b3 --- /dev/null +++ b/src/main/java/org/stefan/snrpc/log/Log4JLogger.java @@ -0,0 +1,80 @@ +package org.stefan.snrpc.log; + +/** + * @author zhaoliangang 2014-11-12 + */ +public class Log4JLogger extends AbstractLogger { + + // Can't really import this without confusion as there's another thing + // by this name in here. + private final org.apache.log4j.Logger l4jLogger; + + /** + * Get an instance of Log4JLogger. + */ + public Log4JLogger(String name) { + super(name); + + // Get the log4j logger instance. + l4jLogger = org.apache.log4j.Logger.getLogger(name); + } + + /** + * True if the underlying logger would allow debug messages through. + */ + @Override + public boolean isDebugEnabled() { + return (l4jLogger.isDebugEnabled()); + } + + /** + * True if the underlying logger would allow info messages through. + */ + @Override + public boolean isInfoEnabled() { + return (l4jLogger.isInfoEnabled()); + } + + /** + * Wrapper around log4j. + * + * @param level + * net.spy.compat.log.AbstractLogger level. + * @param message + * object message + * @param e + * optional throwable + */ + @Override + public void log(Level level, Object message, Throwable e) { + org.apache.log4j.Level pLevel = org.apache.log4j.Level.DEBUG; + + switch (level == null ? Level.FATAL : level) { + case DEBUG: + pLevel = org.apache.log4j.Level.DEBUG; + break; + case INFO: + pLevel = org.apache.log4j.Level.INFO; + break; + case WARN: + pLevel = org.apache.log4j.Level.WARN; + break; + case ERROR: + pLevel = org.apache.log4j.Level.ERROR; + break; + case FATAL: + pLevel = org.apache.log4j.Level.FATAL; + break; + default: + // I don't know what this is, so consider it fatal + pLevel = org.apache.log4j.Level.FATAL; + l4jLogger.log("org.stefan.snrpc.log.AbstractLogger", pLevel, + "Unhandled log level: " + level + + " for the following message", null); + } + + l4jLogger + .log("org.stefan.snrpc.log.AbstractLogger", pLevel, message, e); + } + +} diff --git a/src/main/java/org/stefan/snrpc/log/Logger.java b/src/main/java/org/stefan/snrpc/log/Logger.java new file mode 100644 index 0000000..a09bf49 --- /dev/null +++ b/src/main/java/org/stefan/snrpc/log/Logger.java @@ -0,0 +1,189 @@ +package org.stefan.snrpc.log; + +/** + * @author zhaoliangang + * + */ +public interface Logger { + + /** + * Get the name of this logger. + */ + String getName(); + + /** + * True if debug is enabled for this logger. + * + * @return true if debug messages would be displayed + */ + boolean isDebugEnabled(); + + /** + * True if info is enabled for this logger. + * + * @return true if info messages would be displayed + */ + boolean isInfoEnabled(); + + /** + * Log a message at the specified level. + * + * @param level + * the level at which to log + * @param message + * the message to log + * @param exception + * an exception that caused the message + */ + void log(Level level, Object message, Throwable exception); + + /** + * Log a message at the specified level. + * + * @param level + * the level at which to log + * @param message + * the message to log + */ + void log(Level level, Object message); + + /** + * Log a message at debug level. + * + * @param message + * the message to log + * @param exception + * the exception that caused the message to be generated + */ + void debug(Object message, Throwable exception); + + /** + * Log a message at debug level. + * + * @param message + * the message to log + */ + void debug(Object message); + + /** + * Log a formatted message at debug level. + * + * @param message + * the message to log + * @param args + * the arguments for that message + */ + void debug(String message, Object... args); + + /** + * Log a message at info level. + * + * @param message + * the message to log + * @param exception + * the exception that caused the message to be generated + */ + void info(Object message, Throwable exception); + + /** + * Log a message at info level. + * + * @param message + * the message to log + */ + void info(Object message); + + /** + * Log a formatted message at info level. + * + * @param message + * the message to log + * @param args + * the arguments for that message + */ + void info(String message, Object... args); + + /** + * Log a message at warning level. + * + * @param message + * the message to log + * @param exception + * the exception that caused the message to be generated + */ + void warn(Object message, Throwable exception); + + /** + * Log a message at warning level. + * + * @param message + * the message to log + */ + void warn(Object message); + + /** + * Log a formatted message at debug level. + * + * @param message + * the message to log + * @param args + * the arguments for that message + */ + void warn(String message, Object... args); + + /** + * Log a message at error level. + * + * @param message + * the message to log + * @param exception + * the exception that caused the message to be generated + */ + void error(Object message, Throwable exception); + + /** + * Log a message at error level. + * + * @param message + * the message to log + */ + void error(Object message); + + /** + * Log a formatted message at debug level. + * + * @param message + * the message to log + * @param args + * the arguments for that message + */ + void error(String message, Object... args); + + /** + * Log a message at fatal level. + * + * @param message + * the message to log + * @param exception + * the exception that caused the message to be generated + */ + void fatal(Object message, Throwable exception); + + /** + * Log a message at fatal level. + * + * @param message + * the message to log + */ + void fatal(Object message); + + /** + * Log a formatted message at debug level. + * + * @param message + * the message to log + * @param args + * the arguments for that message + */ + void fatal(String message, Object... args); +} diff --git a/src/main/java/org/stefan/snrpc/log/LoggerFactory.java b/src/main/java/org/stefan/snrpc/log/LoggerFactory.java new file mode 100644 index 0000000..5a017e4 --- /dev/null +++ b/src/main/java/org/stefan/snrpc/log/LoggerFactory.java @@ -0,0 +1,125 @@ +package org.stefan.snrpc.log; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +/** + * @author zhaoliangang 2014-11-12 + */ +public class LoggerFactory { + + private static LoggerFactory instance = null; + private final ConcurrentMap instances; + private Constructor instanceConstructor; + + private LoggerFactory() { + super(); + instances = new ConcurrentHashMap(); + } + + private static void init() { + if (instance == null) + instance = new LoggerFactory(); + } + + public static Logger getLogger(Class clazz) { + return getLogger(clazz.getName()); + } + + public static Logger getLogger(String name) { + if (name == null) + throw new NullPointerException("Logger name can not be null..."); + + init(); + return instance.internalGetLogger(name); + } + + private Logger internalGetLogger(String name) { + assert name != null : "logger name is null"; + Logger logger = instances.get(name); + if (logger == null) { + Logger newLogger = null; + try { + newLogger = getNewInstance(name); + } catch (Exception e) { + throw new RuntimeException("Problem getting logger", e); + } + Logger tmp = instances.putIfAbsent(name, newLogger); + logger = tmp == null ? newLogger : tmp; + } + + return logger; + } + + /** + * @param name + * @return + */ + private Logger getNewInstance(String name) throws InstantiationException, + IllegalAccessException, IllegalArgumentException, + InvocationTargetException { + if (instanceConstructor == null) { + getConstructor(); + } + Object[] args = { name }; + Logger logger = instanceConstructor.newInstance(args); + return logger; + } + + // Find the appropriate constructor + @SuppressWarnings({ "unchecked", "rawtypes" }) + private void getConstructor() { + Class c = DefaultLogger.class; + String className = System.getProperty("org.stefan.log.LoggerImpl"); + + if (className != null) { + try { + c = (Class) Class.forName(className); + } catch (NoClassDefFoundError e) { + System.err.println("Warning: " + className + + " not found while initializing" + + " org.stefan.snrpc.log.LoggerFactory"); + e.printStackTrace(); + c = DefaultLogger.class; + } catch (ClassNotFoundException e) { + System.err.println("Warning: " + className + + " not found while initializing" + + " org.stefan.snrpc.log.LoggerFactory"); + e.printStackTrace(); + c = DefaultLogger.class; + } + } + + // Find the best constructor + try { + // Try to find a constructor that takes a single string + Class[] args = { String.class }; + instanceConstructor = c.getConstructor(args); + } catch (NoSuchMethodException e) { + try { + // Try to find an empty constructor + Class[] args = {}; + instanceConstructor = c.getConstructor(args); + } catch (NoSuchMethodException e2) { + System.err.println("Warning: " + className + + " has no appropriate constructor, using defaults."); + + // Try to find a constructor that takes a single string + try { + Class[] args = { String.class }; + instanceConstructor = DefaultLogger.class + .getConstructor(args); + } catch (NoSuchMethodException e3) { + // This shouldn't happen. + throw new NoSuchMethodError( + "There used to be a constructor that takes a single " + + "String on " + DefaultLogger.class + + ", but I can't " + "find one now."); + } // SOL + } // No empty constructor + } // No constructor that takes a string + } // getConstructor + +} diff --git a/src/main/java/org/stefan/snrpc/log/SunLogger.java b/src/main/java/org/stefan/snrpc/log/SunLogger.java new file mode 100644 index 0000000..c25e1cf --- /dev/null +++ b/src/main/java/org/stefan/snrpc/log/SunLogger.java @@ -0,0 +1,111 @@ +package org.stefan.snrpc.log; + +/** + * @author zhaoliangang 2014-11-14 + */ +public class SunLogger extends AbstractLogger { + + // Can't really import this without confusion as there's another thing + // by this name in here. + private final java.util.logging.Logger sunLogger; + + /** + * Get an instance of SunLogger. + */ + public SunLogger(String name) { + super(name); + + // Get the sun logger instance. + sunLogger = java.util.logging.Logger.getLogger(name); + } + + /** + * True if the underlying logger would allow Level.FINE through. + */ + @Override + public boolean isDebugEnabled() { + return (sunLogger.isLoggable(java.util.logging.Level.FINE)); + } + + /** + * True if the underlying logger would allow Level.INFO through. + */ + @Override + public boolean isInfoEnabled() { + return (sunLogger.isLoggable(java.util.logging.Level.INFO)); + } + + /** + * Wrapper around sun logger. + * + * @param level + * net.spy.compat.log.AbstractLogger level. + * @param message + * object message + * @param e + * optional throwable + */ + @Override + public void log(Level level, Object message, Throwable e) { + java.util.logging.Level sLevel = java.util.logging.Level.SEVERE; + + switch (level == null ? Level.FATAL : level) { + case DEBUG: + sLevel = java.util.logging.Level.FINE; + break; + case INFO: + sLevel = java.util.logging.Level.INFO; + break; + case WARN: + sLevel = java.util.logging.Level.WARNING; + break; + case ERROR: + sLevel = java.util.logging.Level.SEVERE; + break; + case FATAL: + sLevel = java.util.logging.Level.SEVERE; + break; + default: + // I don't know what this is, so consider it fatal + sLevel = java.util.logging.Level.SEVERE; + sunLogger.log(sLevel, "Unhandled log level: " + level + + " for the following message"); + } + + // Figure out who was logging. + Throwable t = new Throwable(); + StackTraceElement[] ste = t.getStackTrace(); + StackTraceElement logRequestor = null; + String alclass = AbstractLogger.class.getName(); + for (int i = 0; i < ste.length && logRequestor == null; i++) { + if (ste[i].getClassName().equals(alclass)) { + // Make sure there's another stack frame. + if (i + 1 < ste.length) { + logRequestor = ste[i + 1]; + if (logRequestor.getClassName().equals(alclass)) { + logRequestor = null; + } // Also AbstractLogger + } // Found something that wasn't abstract logger + } // check for abstract logger + } + + // See if we could figure out who was doing the original logging, + // if we could, we want to include a useful class and method name + if (logRequestor != null) { + if (e != null) { + sunLogger.logp(sLevel, logRequestor.getClassName(), + logRequestor.getMethodName(), message.toString(), e); + } else { + sunLogger.logp(sLevel, logRequestor.getClassName(), + logRequestor.getMethodName(), message.toString()); + } + } else { + if (e != null) { + sunLogger.log(sLevel, message.toString(), e); + } else { + sunLogger.log(sLevel, message.toString()); + } + } + } + +} diff --git a/src/main/java/org/stefan/snrpc/serializer/AbstractProtostuffSerializer.java b/src/main/java/org/stefan/snrpc/serializer/AbstractProtostuffSerializer.java new file mode 100644 index 0000000..dab0d4f --- /dev/null +++ b/src/main/java/org/stefan/snrpc/serializer/AbstractProtostuffSerializer.java @@ -0,0 +1,90 @@ +package org.stefan.snrpc.serializer; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import org.stefan.snrpc.exception.SerializerException; +import org.stefan.snrpc.util.BufferCache; +import org.stefan.snrpc.util.IOUtils; +import org.stefan.snrpc.util.SchemaCache; + +import com.dyuproject.protostuff.LinkedBuffer; +import com.dyuproject.protostuff.Schema; + +/** + * AbstractProtostuffSerializer + * @author zhaoliangang 2014-11-14 + */ +public abstract class AbstractProtostuffSerializer implements ClientSerializer, + ServerSerializer { + /** + * @param buffer + * buffer writen to + * @param object + * @param schema + * @return length + */ + protected abstract int writeObject(LinkedBuffer buffer, T object, + Schema schema); + + /** + * @param bytes + * @param template + * @param schema + * @return + */ + protected abstract void parseObject(byte[] bytes, T template, + Schema schema); + + public SnRpcRequest decodeRequest(InputStream inputStream) + throws SerializerException, IOException { + return decode(inputStream, new SnRpcRequest()); + } + + public void encodeResponse(OutputStream outputStream, SnRpcResponse result) + throws SerializerException, IOException { + encode(outputStream, result); + } + + public SnRpcResponse decodeResponse(InputStream inputStream) + throws SerializerException, IOException { + return decode(inputStream, new SnRpcResponse()); + } + + public void encodeRequest(OutputStream outputStream, SnRpcRequest request) + throws SerializerException, IOException { + encode(outputStream, request); + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + private void encode(OutputStream out, T object) throws IOException { + LinkedBuffer buffer = BufferCache.getBuffer(); + Schema schema = null; + if (null == object) { + schema = SchemaCache.getSchema(Object.class); + } else { + schema = SchemaCache.getSchema(object.getClass()); + } + + // write the length header + int length = writeObject(buffer, object, schema); + IOUtils.writeInt(out, length); + // write content + LinkedBuffer.writeTo(out, buffer); + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + private T decode(InputStream in, T template) throws IOException { + Schema schema = SchemaCache.getSchema(template.getClass()); + + // read the length header + int length = IOUtils.readInt(in); + // read exactly $length bytes + byte[] bytes = new byte[length]; + IOUtils.readFully(in, bytes, 0, length); + // parse object + parseObject(bytes, template, schema); + return template; + } +} diff --git a/src/main/java/org/stefan/snrpc/serializer/ClientSerializer.java b/src/main/java/org/stefan/snrpc/serializer/ClientSerializer.java new file mode 100644 index 0000000..4f58532 --- /dev/null +++ b/src/main/java/org/stefan/snrpc/serializer/ClientSerializer.java @@ -0,0 +1,37 @@ +package org.stefan.snrpc.serializer; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import org.stefan.snrpc.exception.SerializerException; + +/** + * ClientSerializer + * @author zhaoliangang 2014-11-13 + */ +public interface ClientSerializer { + /** + * deserialize the inputStream + * + * @param inputStream + * @return + * @throws SerializeException + * @throws IOException + */ + SnRpcResponse decodeResponse(InputStream inputStream) + throws SerializerException, IOException; + + /** + * serialize the request object into the outputStream + * + * @param outputStream + * @param object + * @param method + * @param arguments + * @throws SerializeException + * @throws IOException + */ + void encodeRequest(OutputStream outputStream, SnRpcRequest request) + throws SerializerException, IOException; +} \ No newline at end of file diff --git a/src/main/java/org/stefan/snrpc/serializer/ProtobufSerializer.java b/src/main/java/org/stefan/snrpc/serializer/ProtobufSerializer.java new file mode 100644 index 0000000..66f8f43 --- /dev/null +++ b/src/main/java/org/stefan/snrpc/serializer/ProtobufSerializer.java @@ -0,0 +1,32 @@ +package org.stefan.snrpc.serializer; + +import com.dyuproject.protostuff.LinkedBuffer; +import com.dyuproject.protostuff.ProtobufIOUtil; +import com.dyuproject.protostuff.Schema; + +/** + * ProtobufSerializer + * @author zhaoliangang 2014-11-14 + */ +public class ProtobufSerializer extends AbstractProtostuffSerializer { + + private static final ProtobufSerializer INSTANCE = new ProtobufSerializer(); + + private ProtobufSerializer() { + } + + public static ProtobufSerializer getInstance() { + return INSTANCE; + } + + @Override + protected int writeObject(LinkedBuffer buffer, T object, + Schema schema) { + return ProtobufIOUtil.writeTo(buffer, object, schema); + } + + @Override + protected void parseObject(byte[] bytes, T template, Schema schema) { + ProtobufIOUtil.mergeFrom(bytes, template, schema); + } +} diff --git a/src/main/java/org/stefan/snrpc/serializer/ServerSerializer.java b/src/main/java/org/stefan/snrpc/serializer/ServerSerializer.java new file mode 100644 index 0000000..c5eae09 --- /dev/null +++ b/src/main/java/org/stefan/snrpc/serializer/ServerSerializer.java @@ -0,0 +1,35 @@ +package org.stefan.snrpc.serializer; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import org.stefan.snrpc.exception.SerializerException; + +/** + * ServerSerializer + * @author zhaoliangang 2014-11-13 + */ +public interface ServerSerializer { + /** + * deserialize the inputStream + * + * @param inputStream + * @return + * @throws SerializeException + * @throws IOException + */ + SnRpcRequest decodeRequest(InputStream inputStream) + throws SerializerException, IOException; + + /** + * serialize the result object into the outputStream + * + * @param outputStream + * @param result + * @throws SerializeException + * @throws IOException + */ + void encodeResponse(OutputStream outputStream, SnRpcResponse result) + throws SerializerException, IOException; +} diff --git a/src/main/java/org/stefan/snrpc/serializer/SnRpcRequest.java b/src/main/java/org/stefan/snrpc/serializer/SnRpcRequest.java new file mode 100644 index 0000000..ef589ab --- /dev/null +++ b/src/main/java/org/stefan/snrpc/serializer/SnRpcRequest.java @@ -0,0 +1,88 @@ +package org.stefan.snrpc.serializer; + +import org.stefan.snrpc.util.MessageFormatter; + +/** + * SnRpcRequest + * @author zhaoliangang 2014-11-13 + */ +public class SnRpcRequest { + + private String requestID; + + private String className; + + private String methodName; + + private String[] parameterTypes; + + private Object[] parameters; + + public SnRpcRequest() { + } + + public SnRpcRequest(String className, String methodName, + String[] parameterTypes, Object[] parameters) { + this.className = className; + this.methodName = methodName; + this.parameterTypes = parameterTypes; + this.parameters = parameters; + } + + public SnRpcRequest(String requestID, String className, String methodName, + String[] parameterTypes, Object[] parameters) { + this.requestID = requestID; + this.className = className; + this.methodName = methodName; + this.parameterTypes = parameterTypes; + this.parameters = parameters; + } + + public String getRequestID() { + return requestID; + } + + public void setRequestID(String requestID) { + this.requestID = requestID; + } + + public String getClassName() { + return className; + } + + public void setClassName(String className) { + this.className = className; + } + + public String getMethodName() { + return methodName; + } + + public void setMethodName(String methodName) { + this.methodName = methodName; + } + + public String[] getParameterTypes() { + return parameterTypes; + } + + public void setParameterTypes(String[] parameterTypes) { + this.parameterTypes = parameterTypes; + } + + public Object[] getParameters() { + return parameters; + } + + public void setParameters(Object[] parameters) { + this.parameters = parameters; + } + + @Override + public String toString() { + return MessageFormatter + .format("requestID: {}, className: {}, methodName: {}, parameterTypes: {}, parameters: {}", + new Object[] { requestID, className, methodName, + parameterTypes, parameters }); + } +} diff --git a/src/main/java/org/stefan/snrpc/serializer/SnRpcRequestDecoder.java b/src/main/java/org/stefan/snrpc/serializer/SnRpcRequestDecoder.java new file mode 100644 index 0000000..17253b9 --- /dev/null +++ b/src/main/java/org/stefan/snrpc/serializer/SnRpcRequestDecoder.java @@ -0,0 +1,37 @@ +package org.stefan.snrpc.serializer; + +import org.jboss.netty.buffer.ChannelBuffer; +import org.jboss.netty.buffer.ChannelBufferInputStream; +import org.jboss.netty.channel.Channel; +import org.jboss.netty.channel.ChannelHandlerContext; +import org.jboss.netty.handler.codec.frame.FrameDecoder; + +/** + * SnRpcRequestDecoder + * + * @author zhaoliangang 2014-11-13 + */ +public class SnRpcRequestDecoder extends FrameDecoder { + + private final ServerSerializer serializer; + + public SnRpcRequestDecoder(ServerSerializer serializer) { + this.serializer = serializer; + } + + @Override + protected Object decode(ChannelHandlerContext ctx, Channel channel, + ChannelBuffer buffer) throws Exception { + if (buffer.readableBytes() < 4) { + return null; + } + int length = buffer.getInt(buffer.readerIndex()); + if (buffer.readableBytes() < length + 4) { + return null; + } + ChannelBufferInputStream in = new ChannelBufferInputStream(buffer); + SnRpcRequest request = serializer.decodeRequest(in); + return request; + } + +} diff --git a/src/main/java/org/stefan/snrpc/serializer/SnRpcRequestEncoder.java b/src/main/java/org/stefan/snrpc/serializer/SnRpcRequestEncoder.java new file mode 100644 index 0000000..a9f69d6 --- /dev/null +++ b/src/main/java/org/stefan/snrpc/serializer/SnRpcRequestEncoder.java @@ -0,0 +1,33 @@ +package org.stefan.snrpc.serializer; + +import java.io.ByteArrayOutputStream; + +import org.jboss.netty.buffer.ChannelBuffer; +import org.jboss.netty.buffer.ChannelBuffers; +import org.jboss.netty.channel.ChannelHandlerContext; +import org.jboss.netty.channel.Channels; +import org.jboss.netty.channel.MessageEvent; +import org.jboss.netty.channel.SimpleChannelHandler; + +/** + * @author zhaoliangang 2014-11-13 + */ +public class SnRpcRequestEncoder extends SimpleChannelHandler { + + private final ClientSerializer serializer; + + public SnRpcRequestEncoder(ClientSerializer serializer) { + this.serializer = serializer; + } + + @Override + public void writeRequested(ChannelHandlerContext ctx, MessageEvent e) + throws Exception { + SnRpcRequest request = (SnRpcRequest) e.getMessage(); + ByteArrayOutputStream baos = new ByteArrayOutputStream(16384); + serializer.encodeRequest(baos, request); + ChannelBuffer buffer = ChannelBuffers.wrappedBuffer(baos.toByteArray()); + Channels.write(ctx, e.getFuture(), buffer); + } + +} diff --git a/src/main/java/org/stefan/snrpc/serializer/SnRpcResponse.java b/src/main/java/org/stefan/snrpc/serializer/SnRpcResponse.java new file mode 100644 index 0000000..f3d646a --- /dev/null +++ b/src/main/java/org/stefan/snrpc/serializer/SnRpcResponse.java @@ -0,0 +1,55 @@ +package org.stefan.snrpc.serializer; + +import org.stefan.snrpc.util.MessageFormatter; + +/** + * SnRpcResponse + * + * @author zhaoliangang 2014-11-13 + */ +public class SnRpcResponse { + + private String requestID; + + private Throwable exception; + + private Object result; + + public SnRpcResponse() { + } + + public SnRpcResponse(String requestID) { + this.requestID = requestID; + } + + public String getRequestID() { + return requestID; + } + + public void setRequestID(String requestID) { + this.requestID = requestID; + } + + public Throwable getException() { + return exception; + } + + public void setException(Throwable exception) { + this.exception = exception; + } + + public Object getResult() { + return result; + } + + public void setResult(Object result) { + this.result = result; + } + + @Override + public String toString() { + return MessageFormatter.format( + "requestID: {}, result: {}, exception: {}", new Object[] { + requestID, result, exception }); + } +} diff --git a/src/main/java/org/stefan/snrpc/serializer/SnRpcResponseDecoder.java b/src/main/java/org/stefan/snrpc/serializer/SnRpcResponseDecoder.java new file mode 100644 index 0000000..7ebaae4 --- /dev/null +++ b/src/main/java/org/stefan/snrpc/serializer/SnRpcResponseDecoder.java @@ -0,0 +1,35 @@ +package org.stefan.snrpc.serializer; + +import org.jboss.netty.buffer.ChannelBuffer; +import org.jboss.netty.buffer.ChannelBufferInputStream; +import org.jboss.netty.channel.Channel; +import org.jboss.netty.channel.ChannelHandlerContext; +import org.jboss.netty.handler.codec.frame.FrameDecoder; + +/** + * SnRpcResponseDecoder + * @author zhaoliangang 2014-11-13 + */ +public class SnRpcResponseDecoder extends FrameDecoder { + + private final ClientSerializer serializer; + + public SnRpcResponseDecoder(ClientSerializer serializer) { + this.serializer = serializer; + } + + @Override + protected Object decode(ChannelHandlerContext context, Channel channel, + ChannelBuffer buffer) throws Exception { + if (buffer.readableBytes() < 4) { + return null; + } + int length = buffer.getInt(buffer.readerIndex()); + if (buffer.readableBytes() < length + 4) { + return null; + } + ChannelBufferInputStream in = new ChannelBufferInputStream(buffer); + SnRpcResponse response = serializer.decodeResponse(in); + return response; + } +} diff --git a/src/main/java/org/stefan/snrpc/serializer/SnRpcResponseEncoder.java b/src/main/java/org/stefan/snrpc/serializer/SnRpcResponseEncoder.java new file mode 100644 index 0000000..7a110ce --- /dev/null +++ b/src/main/java/org/stefan/snrpc/serializer/SnRpcResponseEncoder.java @@ -0,0 +1,32 @@ +package org.stefan.snrpc.serializer; + +import java.io.ByteArrayOutputStream; + +import org.jboss.netty.buffer.ChannelBuffer; +import org.jboss.netty.buffer.ChannelBuffers; +import org.jboss.netty.channel.ChannelHandlerContext; +import org.jboss.netty.channel.Channels; +import org.jboss.netty.channel.MessageEvent; +import org.jboss.netty.channel.SimpleChannelHandler; + +/** + * SnRpcResponseEncoder + * @author zhaoliangang 2014-11-13 + */ +public class SnRpcResponseEncoder extends SimpleChannelHandler { + private final ServerSerializer serializer; + + public SnRpcResponseEncoder(ServerSerializer serializer) { + this.serializer = serializer; + } + + @Override + public void writeRequested(ChannelHandlerContext ctx, MessageEvent e) + throws Exception { + SnRpcResponse response = (SnRpcResponse) e.getMessage(); + ByteArrayOutputStream baos = new ByteArrayOutputStream(16384); + serializer.encodeResponse(baos, response); + ChannelBuffer buffer = ChannelBuffers.wrappedBuffer(baos.toByteArray()); + Channels.write(ctx, e.getFuture(), buffer); + } +} diff --git a/src/main/java/org/stefan/snrpc/server/ParseXmlToService.java b/src/main/java/org/stefan/snrpc/server/ParseXmlToService.java new file mode 100644 index 0000000..00de01b --- /dev/null +++ b/src/main/java/org/stefan/snrpc/server/ParseXmlToService.java @@ -0,0 +1,25 @@ +package org.stefan.snrpc.server; + +import java.util.List; + +import org.stefan.snrpc.conf.ConfigureParse; +import org.stefan.snrpc.conf.RpcService; +import org.stefan.snrpc.conf.SnRpcConfig; +import org.stefan.snrpc.conf.XmlConfigureParse; + +/** + * ParseXmlToService + * + * @author zhaoliangang 2014-11-14 + */ +public class ParseXmlToService { + + public void parse() { + String configFile = SnRpcConfig.getInstance().getpropertiesFile(); + ConfigureParse parse = new XmlConfigureParse(configFile); + List serviceList = parse.parseService(); + for (RpcService service : serviceList) { + SnNettyRpcServerHandler.putService(service); + } + } +} diff --git a/src/main/java/org/stefan/snrpc/server/SnNettyRpcServer.java b/src/main/java/org/stefan/snrpc/server/SnNettyRpcServer.java new file mode 100644 index 0000000..f6be170 --- /dev/null +++ b/src/main/java/org/stefan/snrpc/server/SnNettyRpcServer.java @@ -0,0 +1,179 @@ +package org.stefan.snrpc.server; + +import java.io.IOException; +import java.net.DatagramSocket; +import java.net.InetSocketAddress; +import java.net.ServerSocket; +import java.util.Map; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.jboss.netty.bootstrap.ServerBootstrap; +import org.jboss.netty.channel.Channel; +import org.jboss.netty.channel.ChannelPipeline; +import org.jboss.netty.channel.ChannelPipelineFactory; +import org.jboss.netty.channel.Channels; +import org.jboss.netty.channel.group.ChannelGroup; +import org.jboss.netty.channel.group.ChannelGroupFuture; +import org.jboss.netty.channel.group.DefaultChannelGroup; +import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; +import org.jboss.netty.handler.codec.http.HttpChunkAggregator; +import org.jboss.netty.handler.codec.http.HttpContentCompressor; +import org.jboss.netty.handler.timeout.ReadTimeoutHandler; +import org.jboss.netty.util.HashedWheelTimer; +import org.jboss.netty.util.Timer; +import org.stefan.snrpc.SnRpcServer; +import org.stefan.snrpc.conf.SnRpcConfig; +import org.stefan.snrpc.log.Logger; +import org.stefan.snrpc.log.LoggerFactory; +import org.stefan.snrpc.serializer.ProtobufSerializer; +import org.stefan.snrpc.serializer.SnRpcRequestDecoder; +import org.stefan.snrpc.serializer.SnRpcResponseEncoder; +import org.stefan.snrpc.util.HandlerMapper; + +/** + * + * SnNettyRpcServer + * + * @author zhaoliangang 2014-11-13 + */ +public class SnNettyRpcServer implements SnRpcServer { + + private static Logger logger = LoggerFactory + .getLogger(SnNettyRpcServer.class); + + protected Map handlersMap; + + private ServerBootstrap bootstrap = null; + private AtomicBoolean stopped = new AtomicBoolean(false); + private SnRpcConfig snRpcConfig = SnRpcConfig.getInstance(); + private Timer timer; + private int httpListenPort; + + public SnNettyRpcServer(Object... handlers) { + snRpcConfig.loadProperties("snrpcserver.properties"); + this.handlersMap = HandlerMapper.getHandlerMap(handlers); + } + + public SnNettyRpcServer(String fileName, Object... handlers) { + snRpcConfig.loadProperties(fileName); + this.handlersMap = HandlerMapper.getHandlerMap(handlers); + } + + private void initServerInfo() { + httpListenPort = snRpcConfig.getHttpPort(); + new ParseXmlToService().parse(); + } + + private void initHttpBootstrap() { + if (SnRpcConfig.getInstance().getDevMod()) { + StatisticsService.reportPerformance(); + } + logger.info("init HTTP Bootstrap..........."); + final ChannelGroup channelGroup = new DefaultChannelGroup(getClass() + .getName()); + bootstrap = new ServerBootstrap(new NioServerSocketChannelFactory( + Executors.newCachedThreadPool(), + Executors.newCachedThreadPool())); + + bootstrap.setOption("tcpNoDelay", Boolean.parseBoolean(snRpcConfig + .getProperty("snrpc.tcp.nodelay", "true"))); + bootstrap.setOption("reuseAddress", Boolean.parseBoolean(snRpcConfig + .getProperty("snrpc.tcp.reuseaddress", "true"))); + + timer = new HashedWheelTimer(); + bootstrap.setPipelineFactory(new ChannelPipelineFactory() { + public ChannelPipeline getPipeline() throws Exception { + ChannelPipeline pipeline = Channels.pipeline(); + + int readTimeout = snRpcConfig.getReadTimeout(); + if (readTimeout > 0) { + pipeline.addLast("timeout", new ReadTimeoutHandler(timer, + readTimeout, TimeUnit.MILLISECONDS)); + } + + pipeline.addLast("decoder", new SnRpcRequestDecoder( + ProtobufSerializer.getInstance())); + pipeline.addLast("aggregator", new HttpChunkAggregator(1048576)); + pipeline.addLast("encoder", new SnRpcResponseEncoder( + ProtobufSerializer.getInstance())); + pipeline.addLast("deflater", new HttpContentCompressor()); + pipeline.addLast("handler", new SnNettyRpcServerHandler( + handlersMap, channelGroup)); + return pipeline; + } + }); + + if (!checkPortConfig(httpListenPort)) { + throw new IllegalStateException("port: " + httpListenPort + + " already in use!"); + } + + Channel channel = bootstrap.bind(new InetSocketAddress(httpListenPort)); + channelGroup.add(channel); + logger.info("snrpc server started"); + + waitForShutdownCommand(); + ChannelGroupFuture future = channelGroup.close(); + future.awaitUninterruptibly(); + bootstrap.releaseExternalResources(); + timer.stop(); + timer = null; + + logger.info("snrpc server stoped"); + + } + + public void start() { + initServerInfo(); + initHttpBootstrap(); + } + + public void stop() throws Throwable { + stopped.set(true); + synchronized (stopped) { + stopped.notifyAll(); + } + } + + private void waitForShutdownCommand() { + synchronized (stopped) { + while (!stopped.get()) { + try { + stopped.wait(); + } catch (InterruptedException e) { + } + } + } + } + + private boolean checkPortConfig(int listenPort) { + if (listenPort < 0 || listenPort > 65536) { + throw new IllegalArgumentException("Invalid start port: " + + listenPort); + } + ServerSocket ss = null; + DatagramSocket ds = null; + try { + ss = new ServerSocket(listenPort); + ss.setReuseAddress(true); + ds = new DatagramSocket(listenPort); + ds.setReuseAddress(true); + return true; + } catch (IOException e) { + } finally { + if (ds != null) { + ds.close(); + } + if (ss != null) { + try { + ss.close(); + } catch (IOException e) { + } + } + } + return false; + } + +} diff --git a/src/main/java/org/stefan/snrpc/server/SnNettyRpcServerHandler.java b/src/main/java/org/stefan/snrpc/server/SnNettyRpcServerHandler.java new file mode 100644 index 0000000..93ae0c3 --- /dev/null +++ b/src/main/java/org/stefan/snrpc/server/SnNettyRpcServerHandler.java @@ -0,0 +1,123 @@ +package org.stefan.snrpc.server; + +import java.lang.reflect.Method; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import org.jboss.netty.channel.ChannelHandlerContext; +import org.jboss.netty.channel.ChannelStateEvent; +import org.jboss.netty.channel.ExceptionEvent; +import org.jboss.netty.channel.MessageEvent; +import org.jboss.netty.channel.SimpleChannelUpstreamHandler; +import org.jboss.netty.channel.group.ChannelGroup; +import org.stefan.snrpc.conf.RpcService; +import org.stefan.snrpc.conf.SnRpcConfig; +import org.stefan.snrpc.log.Logger; +import org.stefan.snrpc.log.LoggerFactory; +import org.stefan.snrpc.serializer.SnRpcRequest; +import org.stefan.snrpc.serializer.SnRpcResponse; +import org.stefan.snrpc.util.ReflectionCache; + +/** + * SnNettyRpcServerHandler + * + * @author zhaoliangang 2014-11-13 + */ +public class SnNettyRpcServerHandler extends SimpleChannelUpstreamHandler { + + private static final Logger logger = LoggerFactory + .getLogger(SnNettyRpcServerHandler.class); + + private final Map handlersMap; + + private final static Map serviceMap = new HashMap(); + + private final ChannelGroup channelGroups; + + public SnNettyRpcServerHandler(Map handlersMap) { + this(handlersMap, null); + } + + public SnNettyRpcServerHandler(Map handlersMap, + ChannelGroup channelGroups) { + this.handlersMap = handlersMap; + this.channelGroups = channelGroups; + } + + public static void putService(RpcService service) { + if (null != service) { + serviceMap.put(service.getName(), service); + } + } + + public static Map getServiceMap() { + return Collections.unmodifiableMap(serviceMap); + } + + public static RpcService getServiceByName(String serviceName) { + return serviceMap.get(serviceName); + } + + @Override + public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e) + throws Exception { + if (null != channelGroups) { + channelGroups.add(e.getChannel()); + } + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) + throws Exception { + SnRpcRequest request = (SnRpcRequest) ctx.getAttachment(); + logger.warn("handle rpc request fail! request: <{}>", + new Object[] { request }, e.getCause()); + e.getChannel().close().awaitUninterruptibly(); + } + + @Override + public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) + throws Exception { + Object msg = e.getMessage(); + if (!(msg instanceof SnRpcRequest)) { + return; + } + SnRpcRequest request = (SnRpcRequest) msg; + ctx.setAttachment(request); + + SnRpcResponse response = new SnRpcResponse(request.getRequestID()); + try { + Object result = handle(request); + response.setResult(result); + } catch (Throwable t) { + logger.warn("handle rpc request fail! request: <{}>", + new Object[] { request }, t); + response.setException(t); + } + e.getChannel().write(response); + } + + private Object handle(SnRpcRequest request) throws Throwable { + if (SnRpcConfig.getInstance().getDevMod()) { + StatisticsService.reportBeforeInvoke(request); + } + String className = request.getClassName(); + String[] classNameSplits = className.split("\\."); + String serviceName = classNameSplits[classNameSplits.length - 1]; + RpcService rpcService = getServiceByName(serviceName); + if (null == rpcService) + throw new NullPointerException("server interface config is null"); + + Class clazz = rpcService.getRpcImplementor().getProcessorClass(); + Method method = ReflectionCache.getMethod(clazz.getName(), + request.getMethodName(), request.getParameterTypes()); + Object[] parameters = request.getParameters(); + // get handler + Object handler = handlersMap.get(request.getClassName()); + // invoke + Object result = method.invoke(handler, parameters); + return result; + } + +} diff --git a/src/main/java/org/stefan/snrpc/server/StatisticsService.java b/src/main/java/org/stefan/snrpc/server/StatisticsService.java new file mode 100644 index 0000000..9286b6a --- /dev/null +++ b/src/main/java/org/stefan/snrpc/server/StatisticsService.java @@ -0,0 +1,73 @@ +package org.stefan.snrpc.server; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.concurrent.atomic.AtomicLong; + +import org.stefan.snrpc.log.Logger; +import org.stefan.snrpc.log.LoggerFactory; +import org.stefan.snrpc.serializer.SnRpcRequest; + +/** + * StatisticsService + * + * @author zhaoliangang 2014-11-13 + */ +public class StatisticsService { + + private static final Logger logger = LoggerFactory + .getLogger(StatisticsService.class); + + private static final AtomicLong requestTimes = new AtomicLong(); + private static final SimpleDateFormat df = new SimpleDateFormat( + "yyyy-MM-dd HH:mm:ss"); + + static final boolean reportBeforeInvoke(SnRpcRequest request) { + doReport(request); + return true; + } + + private static final void doReport(SnRpcRequest request) { + requestTimes.getAndIncrement(); + StringBuilder tip = new StringBuilder( + "\nsnRpc request report -------- ").append( + df.format(new Date())).append( + " ------------------------------\n"); + String className = request.getClassName(); + String methodName = request.getMethodName(); + String requestId = request.getRequestID(); + Object[] param = request.getParameters(); + tip.append("requestId : ").append(requestId); + tip.append("className : ").append(className); + tip.append("method : ").append(methodName); + tip.append("param[0] : ").append(param[0]).append("\n"); + tip.append("--------------------------------------------------------------------------------\n"); + System.out.print(tip.toString()); + } + + static final void reportPerformance() { + new Thread(new Runnable() { + public void run() { + final long begin = System.currentTimeMillis(); + while (true) { + try { + Thread.sleep(10000); + } catch (InterruptedException e) { + } + long pass = System.currentTimeMillis() - begin; + long totalMemory = Runtime.getRuntime().totalMemory(); + long freeMemory = Runtime.getRuntime().freeMemory(); + long usedMemory = totalMemory - freeMemory; + java.text.NumberFormat format = new java.text.DecimalFormat( + "###,###"); + String memoryInfo = format.format(usedMemory) + "/" + + format.format(totalMemory); + logger.warn("\r\nMemory:" + memoryInfo + ",Time:" + + df.format(new Date()) + ",Time passed:" + pass + + ",Total:" + requestTimes.get() + "(Average TPS:" + + (requestTimes.get() * 1000 / pass) + ")"); + } + } + }).start(); + } +} diff --git a/src/main/java/org/stefan/snrpc/util/BufferCache.java b/src/main/java/org/stefan/snrpc/util/BufferCache.java new file mode 100644 index 0000000..7db7c56 --- /dev/null +++ b/src/main/java/org/stefan/snrpc/util/BufferCache.java @@ -0,0 +1,22 @@ +package org.stefan.snrpc.util; + +import com.dyuproject.protostuff.LinkedBuffer; + +/** + * BufferCache + * @author zhaoliangang 2014-11-13 + */ +public class BufferCache { + + private static ThreadLocal BUFFERS = new ThreadLocal() { + protected LinkedBuffer initialValue() { + return LinkedBuffer.allocate(4096); + }; + }; + + public static LinkedBuffer getBuffer() { + LinkedBuffer buffer = BUFFERS.get(); + buffer.clear(); + return buffer; + } +} diff --git a/src/main/java/org/stefan/snrpc/util/FileUtil.java b/src/main/java/org/stefan/snrpc/util/FileUtil.java new file mode 100644 index 0000000..dd63dae --- /dev/null +++ b/src/main/java/org/stefan/snrpc/util/FileUtil.java @@ -0,0 +1,12 @@ +package org.stefan.snrpc.util; + +import java.io.File; + +public class FileUtil { + + public static File getFile(String path) { + String applicationPath = FileUtil.class.getClassLoader() + .getResource("").getPath(); + return new File(applicationPath, path); + } +} diff --git a/src/main/java/org/stefan/snrpc/util/HandlerMapper.java b/src/main/java/org/stefan/snrpc/util/HandlerMapper.java new file mode 100644 index 0000000..1de028c --- /dev/null +++ b/src/main/java/org/stefan/snrpc/util/HandlerMapper.java @@ -0,0 +1,48 @@ +package org.stefan.snrpc.util; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author zhaoliangang 2014-11-14 + */ +public class HandlerMapper { + + public static Map getHandlerMap(Object... handlers) { + if (null == handlers || handlers.length == 0) { + throw new IllegalArgumentException("handlers not provided"); + } + Map handlerMap = new HashMap(); + for (Object handler : handlers) { + Class[] interfaces = handler.getClass().getInterfaces(); + for (Class iface : interfaces) { + String interfaceName = iface.getName(); + if (ignore(interfaceName)) { + continue; + } + if (null != handlerMap.put(interfaceName, handler)) { + throw new IllegalArgumentException( + "more than one handler for the interface [" + + interfaceName + "]"); + } + } + } + return handlerMap; + } + + private static boolean ignore(String interfaceName) { + if (interfaceName.startsWith("java.")) { + return true; + } + if (interfaceName.startsWith("javax.")) { + return true; + } + if (interfaceName.startsWith("sun.")) { + return true; + } + if (interfaceName.startsWith("com.sun.")) { + return true; + } + return false; + } +} diff --git a/src/main/java/org/stefan/snrpc/util/IOUtils.java b/src/main/java/org/stefan/snrpc/util/IOUtils.java new file mode 100644 index 0000000..1250e66 --- /dev/null +++ b/src/main/java/org/stefan/snrpc/util/IOUtils.java @@ -0,0 +1,103 @@ +package org.stefan.snrpc.util; + +import java.io.Closeable; +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.Socket; + +/** + * @author zhaoliangang 2014-11-13 + */ +public class IOUtils { + /** + * block until exactly length bytes read into + * bytes + * + * @param in + * @param bytes + * @param offset + * @param length + * @throws IOException + */ + public static void readFully(InputStream in, byte[] bytes, int offset, + int length) throws IOException { + if (length < 0) { + throw new IndexOutOfBoundsException(); + } + int n = 0; + while (n < length) { + int count = in.read(bytes, offset + n, length - n); + if (count < 0) { + throw new EOFException(); + } + n += count; + } + } + + /** + * write an integer to the output stream + * + * @param out + * @param value + * @throws IOException + */ + public static void writeInt(OutputStream out, int value) throws IOException { + out.write((value >>> 24) & 0xFF); + out.write((value >>> 16) & 0xFF); + out.write((value >>> 8) & 0xFF); + out.write((value >>> 0) & 0xFF); + } + + /** + * read an integer from the input stream + * + * @param in + * @return + * @throws IOException + */ + public static int readInt(InputStream in) throws IOException { + int ch1 = in.read(); + int ch2 = in.read(); + int ch3 = in.read(); + int ch4 = in.read(); + if ((ch1 | ch2 | ch3 | ch4) < 0) { + throw new EOFException(); + } + return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4 << 0)); + } + + public static void closeQuietly(Closeable closeable) { + if (null == closeable) { + return; + } + try { + closeable.close(); + } catch (Throwable t) { + } + } + + public static void closeQuietly(Socket socket) { + if (null == socket) { + return; + } + if (!socket.isInputShutdown()) { + try { + socket.shutdownInput(); + } catch (IOException e) { + } + } + if (!socket.isOutputShutdown()) { + try { + socket.shutdownOutput(); + } catch (IOException e) { + } + } + try { + socket.close(); + } catch (Throwable t) { + } + } + +} diff --git a/src/main/java/org/stefan/snrpc/util/LRUMap.java b/src/main/java/org/stefan/snrpc/util/LRUMap.java new file mode 100644 index 0000000..c5943c8 --- /dev/null +++ b/src/main/java/org/stefan/snrpc/util/LRUMap.java @@ -0,0 +1,86 @@ +package org.stefan.snrpc.util; + +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; + +/** + * @author zhaoliangang 2014-11-13 + */ +public class LRUMap extends LinkedHashMap implements Map { + private static final long serialVersionUID = -188971896404993320L; + private int maxSize; + + public LRUMap(int maxSize) { + super((int) Math.ceil((1f * maxSize) / 0.75f) + 16, 0.75f, true); + this.maxSize = maxSize; + } + + @Override + protected synchronized boolean removeEldestEntry( + java.util.Map.Entry eldest) { + boolean delete = size() > maxSize; + return delete; + } + + @Override + public synchronized int size() { + return super.size(); + } + + @Override + public synchronized V get(Object key) { + return super.get(key); + } + + @Override + public synchronized V remove(Object key) { + return super.remove(key); + } + + @Override + public synchronized void clear() { + super.clear(); + } + + @Override + public synchronized boolean isEmpty() { + return super.isEmpty(); + } + + @Override + public synchronized boolean containsKey(Object key) { + return super.containsKey(key); + } + + @Override + public synchronized boolean containsValue(Object value) { + return super.containsValue(value); + } + + @Override + public synchronized V put(K key, V value) { + return super.put(key, value); + } + + @Override + public synchronized void putAll(Map m) { + super.putAll(m); + } + + @Override + public synchronized Set keySet() { + return super.keySet(); + } + + @Override + public synchronized Collection values() { + return super.values(); + } + + @Override + public synchronized Set> entrySet() { + return super.entrySet(); + } +} \ No newline at end of file diff --git a/src/main/java/org/stefan/snrpc/util/MessageFormatter.java b/src/main/java/org/stefan/snrpc/util/MessageFormatter.java new file mode 100644 index 0000000..1b59918 --- /dev/null +++ b/src/main/java/org/stefan/snrpc/util/MessageFormatter.java @@ -0,0 +1,293 @@ +package org.stefan.snrpc.util; + +import java.util.HashMap; +import java.util.Map; + + +/** + * @author zhaoliangang + * 2014-11-20 + */ +public class MessageFormatter { + public static final String DEFAULT_PLACE_HOLDER = "{}"; + + public static final char DEFAULT_ESCAPE_CHAR = '\\'; + + /** + * equivalent to + * LogFormatter.format(msgPattern, "{}", '\\', args) + * + * @param msgPattern + * @param args + * @return + */ + public static String format(String msgPattern, Object[] args) { + return format(msgPattern, DEFAULT_PLACE_HOLDER, DEFAULT_ESCAPE_CHAR, + args); + } + + /** + * equivalent to + * LogFormatter.format(msgPattern, placeholder, '\\', args) + * + * @param msgPattern + * @param placeholder + * @param args + * @return + */ + public static String format(String msgPattern, String placeholder, + Object[] args) { + return format(msgPattern, placeholder, DEFAULT_ESCAPE_CHAR, args); + } + + /** + * @param msgPattern + * @param placeholder + * @param escapeChar + * @param args + * @return + */ + @SuppressWarnings("rawtypes") + public static String format(String msgPattern, String placeholder, + char escapeChar, Object[] args) { + if (null == msgPattern || msgPattern.length() == 0) { + return null; + } + if (null == args || args.length == 0) { + return msgPattern; + } + if (null == placeholder || "".equals(placeholder)) { + return msgPattern; + } + + int lastMatchedIndex = 0, currentMatchedIndex = 0; + StringBuilder strbuf = new StringBuilder(msgPattern.length() + 64); + + for (int argIndex = 0; argIndex < args.length; argIndex++) { + currentMatchedIndex = msgPattern.indexOf(placeholder, + lastMatchedIndex); + + if (-1 == currentMatchedIndex) { + // no more variables + if (0 == lastMatchedIndex) { + // this is a simple string + return msgPattern; + } else { + // add the tail string which contains no variables + strbuf.append(msgPattern.substring(lastMatchedIndex, + msgPattern.length())); + return strbuf.toString(); + } + } else { + // successive escape chars before the placeholder + int cnt = countSuccessiveEscapeChar(msgPattern, escapeChar, + currentMatchedIndex, lastMatchedIndex); + if (0 == cnt) { // all escaped itself + strbuf.append(msgPattern.substring(lastMatchedIndex, + currentMatchedIndex)); + deeplyAppendParameter(strbuf, args[argIndex], new HashMap()); + lastMatchedIndex = currentMatchedIndex + + placeholder.length(); + } else { + int escapeItselfCnt = cnt / 2; + strbuf.append(msgPattern.substring(lastMatchedIndex, + (currentMatchedIndex - cnt + escapeItselfCnt))); + if (cnt % 2 != 0) { + argIndex--;// placeholder was escaped, thus should not + // be incremented + strbuf.append(placeholder.charAt(0)); + lastMatchedIndex = currentMatchedIndex + 1; + } else { + deeplyAppendParameter(strbuf, args[argIndex], + new HashMap()); + lastMatchedIndex = currentMatchedIndex + + placeholder.length(); + } + } + } + } + // append the characters following the last {} pair. + strbuf.append(msgPattern.substring(lastMatchedIndex, + msgPattern.length())); + return strbuf.toString(); + } + + private static int countSuccessiveEscapeChar(String msgPattern, + char escapeChar, int delimeterStartIndex, int delimeterStopIndex) { + if (0 == delimeterStartIndex) { + return 0; + } + int cnt = 0; + for (int i = delimeterStartIndex - 1; i >= delimeterStopIndex; i--) { + if (msgPattern.charAt(i) == escapeChar) { + ++cnt; + } else { + break; + } + } + return cnt; + } + + @SuppressWarnings("rawtypes") + private static void deeplyAppendParameter(StringBuilder sbuf, Object o, + Map seenMap) { + if (o == null) { + sbuf.append("null"); + return; + } + if (!o.getClass().isArray()) { + safeObjectAppend(sbuf, o); + } else { + // check for primitive array types because they + // unfortunately cannot be cast to Object[] + if (o instanceof boolean[]) { + booleanArrayAppend(sbuf, (boolean[]) o); + } else if (o instanceof byte[]) { + byteArrayAppend(sbuf, (byte[]) o); + } else if (o instanceof char[]) { + charArrayAppend(sbuf, (char[]) o); + } else if (o instanceof short[]) { + shortArrayAppend(sbuf, (short[]) o); + } else if (o instanceof int[]) { + intArrayAppend(sbuf, (int[]) o); + } else if (o instanceof long[]) { + longArrayAppend(sbuf, (long[]) o); + } else if (o instanceof float[]) { + floatArrayAppend(sbuf, (float[]) o); + } else if (o instanceof double[]) { + doubleArrayAppend(sbuf, (double[]) o); + } else { + objectArrayAppend(sbuf, (Object[]) o, seenMap); + } + } + } + + private static void safeObjectAppend(StringBuilder sbuf, Object o) { + try { + String oAsString = o.toString(); + sbuf.append(oAsString); + } catch (Throwable t) { + System.err + .println("Failed toString() invocation on an object of type [" + + o.getClass().getName() + "]"); + t.printStackTrace(); + sbuf.append("[FAILED toString()]"); + } + + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + private static void objectArrayAppend(StringBuilder sbuf, Object[] a, + Map seenMap) { + sbuf.append('['); + if (!seenMap.containsKey(a)) { + seenMap.put(a, null); + final int len = a.length; + for (int i = 0; i < len; i++) { + deeplyAppendParameter(sbuf, a[i], seenMap); + if (i != len - 1) { + sbuf.append(", "); + } + } + // allow repeats in siblings + seenMap.remove(a); + } else { + sbuf.append("..."); + } + sbuf.append(']'); + } + + private static void booleanArrayAppend(StringBuilder sbuf, boolean[] a) { + sbuf.append('['); + final int len = a.length; + for (int i = 0; i < len; i++) { + sbuf.append(a[i]); + if (i != len - 1) { + sbuf.append(", "); + } + } + sbuf.append(']'); + } + + private static void byteArrayAppend(StringBuilder sbuf, byte[] a) { + sbuf.append('['); + final int len = a.length; + for (int i = 0; i < len; i++) { + sbuf.append(a[i]); + if (i != len - 1) + sbuf.append(", "); + } + sbuf.append(']'); + } + + private static void charArrayAppend(StringBuilder sbuf, char[] a) { + sbuf.append('['); + final int len = a.length; + for (int i = 0; i < len; i++) { + sbuf.append(a[i]); + if (i != len - 1) + sbuf.append(", "); + } + sbuf.append(']'); + } + + private static void shortArrayAppend(StringBuilder sbuf, short[] a) { + sbuf.append('['); + final int len = a.length; + for (int i = 0; i < len; i++) { + sbuf.append(a[i]); + if (i != len - 1) { + sbuf.append(", "); + } + } + sbuf.append(']'); + } + + private static void intArrayAppend(StringBuilder sbuf, int[] a) { + sbuf.append('['); + final int len = a.length; + for (int i = 0; i < len; i++) { + sbuf.append(a[i]); + if (i != len - 1) { + sbuf.append(", "); + } + } + sbuf.append(']'); + } + + private static void longArrayAppend(StringBuilder sbuf, long[] a) { + sbuf.append('['); + final int len = a.length; + for (int i = 0; i < len; i++) { + sbuf.append(a[i]); + if (i != len - 1) { + sbuf.append(", "); + } + } + sbuf.append(']'); + } + + private static void floatArrayAppend(StringBuilder sbuf, float[] a) { + sbuf.append('['); + final int len = a.length; + for (int i = 0; i < len; i++) { + sbuf.append(a[i]); + if (i != len - 1) { + sbuf.append(", "); + } + } + sbuf.append(']'); + } + + private static void doubleArrayAppend(StringBuilder sbuf, double[] a) { + sbuf.append('['); + final int len = a.length; + for (int i = 0; i < len; i++) { + sbuf.append(a[i]); + if (i != len - 1) { + sbuf.append(", "); + } + } + sbuf.append(']'); + } +} diff --git a/src/main/java/org/stefan/snrpc/util/ReflectionCache.java b/src/main/java/org/stefan/snrpc/util/ReflectionCache.java new file mode 100644 index 0000000..b934638 --- /dev/null +++ b/src/main/java/org/stefan/snrpc/util/ReflectionCache.java @@ -0,0 +1,89 @@ +package org.stefan.snrpc.util; + +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; + +/** + * @author zhaoliangang 2014-11-13 + */ +public class ReflectionCache { + private static final Map> PRIMITIVE_CLASS = new HashMap>(); + + private static final LRUMap> CLASS_CACHE = new LRUMap>( + 128); + + private static final LRUMap METHOD_CACHE = new LRUMap( + 1024); + static { + PRIMITIVE_CLASS.put("boolean", boolean.class); + PRIMITIVE_CLASS.put("byte", byte.class); + PRIMITIVE_CLASS.put("short", short.class); + PRIMITIVE_CLASS.put("int", int.class); + PRIMITIVE_CLASS.put("long", long.class); + PRIMITIVE_CLASS.put("long", long.class); + PRIMITIVE_CLASS.put("float", float.class); + PRIMITIVE_CLASS.put("double", double.class); + PRIMITIVE_CLASS.put("void", void.class); + + CLASS_CACHE.putAll(PRIMITIVE_CLASS); + } + + public static Class getClass(String className) + throws ClassNotFoundException { + Class clazz = CLASS_CACHE.get(className); + if (null != clazz) { + return clazz; + } + synchronized (CLASS_CACHE) { + if (null == CLASS_CACHE.get(className)) { + clazz = PRIMITIVE_CLASS.get(className); + if (null == clazz) { + clazz = Class.forName(className); + } + CLASS_CACHE.put(className, clazz); + return clazz; + } else { + return CLASS_CACHE.get(className); + } + } + } + + public static Method getMethod(String className, String methodName, + String[] parameterTypes) throws ClassNotFoundException, + SecurityException, NoSuchMethodException { + String key = className + "-" + methodName + "-" + + join(parameterTypes, ";"); + Method method = METHOD_CACHE.get(key); + if (null != method) { + return method; + } + synchronized (METHOD_CACHE) { + if (null == METHOD_CACHE.get(key)) { + Class clazz = getClass(className); + Class[] parameterClasses = new Class[parameterTypes.length]; + for (int i = 0; i < parameterClasses.length; i++) { + parameterClasses[i] = getClass(parameterTypes[i]); + } + + method = clazz.getMethod(methodName, parameterClasses); + METHOD_CACHE.put(key, method); + return method; + } else { + return METHOD_CACHE.get(key); + } + } + } + + private static String join(String[] strs, String seperator) { + if (null == strs || 0 == strs.length) { + return ""; + } + StringBuilder sb = new StringBuilder(1024); + sb.append(strs[0]); + for (int i = 1; i < strs.length; i++) { + sb.append(seperator).append(strs[i]); + } + return sb.toString(); + } +} diff --git a/src/main/java/org/stefan/snrpc/util/SchemaCache.java b/src/main/java/org/stefan/snrpc/util/SchemaCache.java new file mode 100644 index 0000000..a9c84cb --- /dev/null +++ b/src/main/java/org/stefan/snrpc/util/SchemaCache.java @@ -0,0 +1,60 @@ +package org.stefan.snrpc.util; + +import org.stefan.snrpc.serializer.SnRpcRequest; +import org.stefan.snrpc.serializer.SnRpcResponse; + +import com.dyuproject.protostuff.Schema; +import com.dyuproject.protostuff.runtime.RuntimeSchema; + +/** + * SchemaCache + * @author zhaoliangang + * 2014-11-20 + */ +public class SchemaCache { + + private static final LRUMap> SCHEMA_CACHE = new LRUMap>( + 4096); + + @SuppressWarnings("unchecked") + public static Schema getSchema(Class clazz) { + String className = clazz.getName(); + Schema schema = (Schema) SCHEMA_CACHE.get(className); + if (null != schema) { + return schema; + } + synchronized (SCHEMA_CACHE) { + if (null == SCHEMA_CACHE.get(className)) { + schema = RuntimeSchema.getSchema(clazz); + SCHEMA_CACHE.put(className, schema); + return schema; + } else { + return (Schema) SCHEMA_CACHE.get(className); + } + } + } + + public static Schema getSchema(SnRpcRequest request) { + Schema schema = getSchema(SnRpcRequest.class); + Object[] parameters = request.getParameters(); + if (null != parameters && parameters.length > 0) { + for (Object param : parameters) { + if (null != param) { + getSchema(param.getClass()); + } + } + } + return schema; + } + + public static Schema getSchema(SnRpcResponse response) { + Schema schema = getSchema(SnRpcResponse.class); + if (response.getException() != null) { + getSchema(response.getException().getClass()); + } + if (response.getResult() != null) { + getSchema(response.getResult().getClass()); + } + return schema; + } +} diff --git a/src/main/java/org/stefan/snrpc/util/Sequence.java b/src/main/java/org/stefan/snrpc/util/Sequence.java new file mode 100644 index 0000000..cf3c277 --- /dev/null +++ b/src/main/java/org/stefan/snrpc/util/Sequence.java @@ -0,0 +1,21 @@ +package org.stefan.snrpc.util; + +/** + * @author zhaoliangang + * 2014-11-14 + */ +public class Sequence{ + private static final Object locker = new Object(); + private static int sequence = 1000; + + public static int next() + { + synchronized (locker) + { + sequence++; + if (sequence < 0) + sequence = 1; + return sequence; + } + } +} diff --git a/src/main/java/org/stefan/snrpc/util/StringUtil.java b/src/main/java/org/stefan/snrpc/util/StringUtil.java new file mode 100644 index 0000000..0165559 --- /dev/null +++ b/src/main/java/org/stefan/snrpc/util/StringUtil.java @@ -0,0 +1,16 @@ +package org.stefan.snrpc.util; + +/** + * @author zhaoliangang 2014-11-12 + */ +public class StringUtil { + + public static boolean isEmpty(String str) { + return str == null || "".equals(str.trim()) ? true : false; + } + + public static boolean isNotEmpty(String str) { + return str == null || "".equals(str.trim()) ? false : true; + } + +} diff --git a/src/test/java/org/stefan/snrpc/Client.java b/src/test/java/org/stefan/snrpc/Client.java new file mode 100644 index 0000000..1540671 --- /dev/null +++ b/src/test/java/org/stefan/snrpc/Client.java @@ -0,0 +1,28 @@ +package org.stefan.snrpc; + +import org.stefan.snrpc.client.CommonSnRpcClient; +import org.stefan.snrpc.client.PoolableRpcConnectionFactory; +import org.stefan.snrpc.client.SnNettyRpcConnectionFactory; +import org.stefan.snrpc.server.SnRpcInterface; + +/** + * @author zhaoliangang 2014-11-14 + */ +public class Client { + + public static void main(String[] args) { + SnRpcConnectionFactory factory = new SnNettyRpcConnectionFactory( + "localhost", 8080); + factory = new PoolableRpcConnectionFactory(factory); + SnRpcClient client = new CommonSnRpcClient(factory); + try { + SnRpcInterface clazz = client.proxy(SnRpcInterface.class); + String message = clazz.getMessage("come on"); + System.out.println("client receive message .... : " + message); + } catch (Throwable e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + } +} diff --git a/src/test/java/org/stefan/snrpc/Server.java b/src/test/java/org/stefan/snrpc/Server.java new file mode 100644 index 0000000..7b07468 --- /dev/null +++ b/src/test/java/org/stefan/snrpc/Server.java @@ -0,0 +1,22 @@ +package org.stefan.snrpc; + +import org.stefan.snrpc.server.SnNettyRpcServer; +import org.stefan.snrpc.server.SnRpcImpl; +import org.stefan.snrpc.server.SnRpcInterface; + +/** + * @author zhaoliangang 2014-11-14 + */ +public class Server { + + public static void main(String[] args) { + + SnRpcInterface inter = new SnRpcImpl(); + SnRpcServer server = new SnNettyRpcServer(new Object[] { inter }); + try { + server.start(); + } catch (Throwable e) { + e.printStackTrace(); + } + } +} diff --git a/src/test/java/org/stefan/snrpc/server/SnRpcImpl.java b/src/test/java/org/stefan/snrpc/server/SnRpcImpl.java new file mode 100644 index 0000000..df54e81 --- /dev/null +++ b/src/test/java/org/stefan/snrpc/server/SnRpcImpl.java @@ -0,0 +1,12 @@ +package org.stefan.snrpc.server; + +/** + * @author zhaoliangang 2014-11-14 + */ +public class SnRpcImpl implements SnRpcInterface { + + public String getMessage(String param) { + return "hi,it is message from server...param+" + param; + } + +} diff --git a/src/test/java/org/stefan/snrpc/server/SnRpcInterface.java b/src/test/java/org/stefan/snrpc/server/SnRpcInterface.java new file mode 100644 index 0000000..74bd36e --- /dev/null +++ b/src/test/java/org/stefan/snrpc/server/SnRpcInterface.java @@ -0,0 +1,9 @@ +package org.stefan.snrpc.server; + +/** + * @author zhaoliangang 2014-11-14 + */ +public interface SnRpcInterface { + + public String getMessage(String param); +} diff --git a/src/test/resources/config.xml b/src/test/resources/config.xml new file mode 100644 index 0000000..a4f9341 --- /dev/null +++ b/src/test/resources/config.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/snrpcserver.properties b/src/test/resources/snrpcserver.properties new file mode 100644 index 0000000..e154b8f --- /dev/null +++ b/src/test/resources/snrpcserver.properties @@ -0,0 +1,10 @@ +#tcpNoDelay +snrpc.tcp.nodelay=true +#call the bind method as many times as you want +snrpc.tcp.reuseAddress=true +#ISDEBUG +snrpc.dev=true +#TCP timeout +snrpc.read.timeout=25000 +#server port +snrpc.http.port=8080 diff --git a/target/classes/config.xml b/target/classes/config.xml new file mode 100644 index 0000000..a4f9341 --- /dev/null +++ b/target/classes/config.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/target/classes/org/stefan/snrpc/SnRpcClient.class b/target/classes/org/stefan/snrpc/SnRpcClient.class new file mode 100644 index 0000000..ac9b009 Binary files /dev/null and b/target/classes/org/stefan/snrpc/SnRpcClient.class differ diff --git a/target/classes/org/stefan/snrpc/SnRpcConnection.class b/target/classes/org/stefan/snrpc/SnRpcConnection.class new file mode 100644 index 0000000..819c3f4 Binary files /dev/null and b/target/classes/org/stefan/snrpc/SnRpcConnection.class differ diff --git a/target/classes/org/stefan/snrpc/SnRpcConnectionFactory.class b/target/classes/org/stefan/snrpc/SnRpcConnectionFactory.class new file mode 100644 index 0000000..02d846f Binary files /dev/null and b/target/classes/org/stefan/snrpc/SnRpcConnectionFactory.class differ diff --git a/target/classes/org/stefan/snrpc/SnRpcServer.class b/target/classes/org/stefan/snrpc/SnRpcServer.class new file mode 100644 index 0000000..18b4e80 Binary files /dev/null and b/target/classes/org/stefan/snrpc/SnRpcServer.class differ diff --git a/target/classes/org/stefan/snrpc/client/CommonSnRpcClient$SnRpcInvoker.class b/target/classes/org/stefan/snrpc/client/CommonSnRpcClient$SnRpcInvoker.class new file mode 100644 index 0000000..053e9aa Binary files /dev/null and b/target/classes/org/stefan/snrpc/client/CommonSnRpcClient$SnRpcInvoker.class differ diff --git a/target/classes/org/stefan/snrpc/client/CommonSnRpcClient.class b/target/classes/org/stefan/snrpc/client/CommonSnRpcClient.class new file mode 100644 index 0000000..c0a255a Binary files /dev/null and b/target/classes/org/stefan/snrpc/client/CommonSnRpcClient.class differ diff --git a/target/classes/org/stefan/snrpc/client/PoolableRpcConnectionFactory.class b/target/classes/org/stefan/snrpc/client/PoolableRpcConnectionFactory.class new file mode 100644 index 0000000..b262956 Binary files /dev/null and b/target/classes/org/stefan/snrpc/client/PoolableRpcConnectionFactory.class differ diff --git a/target/classes/org/stefan/snrpc/client/SnNettyRpcConnection$1.class b/target/classes/org/stefan/snrpc/client/SnNettyRpcConnection$1.class new file mode 100644 index 0000000..4bba6b4 Binary files /dev/null and b/target/classes/org/stefan/snrpc/client/SnNettyRpcConnection$1.class differ diff --git a/target/classes/org/stefan/snrpc/client/SnNettyRpcConnection.class b/target/classes/org/stefan/snrpc/client/SnNettyRpcConnection.class new file mode 100644 index 0000000..3bf6a8d Binary files /dev/null and b/target/classes/org/stefan/snrpc/client/SnNettyRpcConnection.class differ diff --git a/target/classes/org/stefan/snrpc/client/SnNettyRpcConnectionFactory.class b/target/classes/org/stefan/snrpc/client/SnNettyRpcConnectionFactory.class new file mode 100644 index 0000000..9120307 Binary files /dev/null and b/target/classes/org/stefan/snrpc/client/SnNettyRpcConnectionFactory.class differ diff --git a/target/classes/org/stefan/snrpc/conf/ConfigureParse.class b/target/classes/org/stefan/snrpc/conf/ConfigureParse.class new file mode 100644 index 0000000..168d9fa Binary files /dev/null and b/target/classes/org/stefan/snrpc/conf/ConfigureParse.class differ diff --git a/target/classes/org/stefan/snrpc/conf/RpcImplementor.class b/target/classes/org/stefan/snrpc/conf/RpcImplementor.class new file mode 100644 index 0000000..6f35047 Binary files /dev/null and b/target/classes/org/stefan/snrpc/conf/RpcImplementor.class differ diff --git a/target/classes/org/stefan/snrpc/conf/RpcService.class b/target/classes/org/stefan/snrpc/conf/RpcService.class new file mode 100644 index 0000000..fb89923 Binary files /dev/null and b/target/classes/org/stefan/snrpc/conf/RpcService.class differ diff --git a/target/classes/org/stefan/snrpc/conf/SnRpcConfig.class b/target/classes/org/stefan/snrpc/conf/SnRpcConfig.class new file mode 100644 index 0000000..a5c1e55 Binary files /dev/null and b/target/classes/org/stefan/snrpc/conf/SnRpcConfig.class differ diff --git a/target/classes/org/stefan/snrpc/conf/XmlConfigureParse.class b/target/classes/org/stefan/snrpc/conf/XmlConfigureParse.class new file mode 100644 index 0000000..36446ed Binary files /dev/null and b/target/classes/org/stefan/snrpc/conf/XmlConfigureParse.class differ diff --git a/target/classes/org/stefan/snrpc/exception/SerializerException.class b/target/classes/org/stefan/snrpc/exception/SerializerException.class new file mode 100644 index 0000000..0e06689 Binary files /dev/null and b/target/classes/org/stefan/snrpc/exception/SerializerException.class differ diff --git a/target/classes/org/stefan/snrpc/exception/SnRpcException.class b/target/classes/org/stefan/snrpc/exception/SnRpcException.class new file mode 100644 index 0000000..93fe189 Binary files /dev/null and b/target/classes/org/stefan/snrpc/exception/SnRpcException.class differ diff --git a/target/classes/org/stefan/snrpc/log/AbstractLogger.class b/target/classes/org/stefan/snrpc/log/AbstractLogger.class new file mode 100644 index 0000000..deab049 Binary files /dev/null and b/target/classes/org/stefan/snrpc/log/AbstractLogger.class differ diff --git a/target/classes/org/stefan/snrpc/log/DefaultLogger.class b/target/classes/org/stefan/snrpc/log/DefaultLogger.class new file mode 100644 index 0000000..6106023 Binary files /dev/null and b/target/classes/org/stefan/snrpc/log/DefaultLogger.class differ diff --git a/target/classes/org/stefan/snrpc/log/Level.class b/target/classes/org/stefan/snrpc/log/Level.class new file mode 100644 index 0000000..ae97459 Binary files /dev/null and b/target/classes/org/stefan/snrpc/log/Level.class differ diff --git a/target/classes/org/stefan/snrpc/log/Log4JLogger.class b/target/classes/org/stefan/snrpc/log/Log4JLogger.class new file mode 100644 index 0000000..2605f02 Binary files /dev/null and b/target/classes/org/stefan/snrpc/log/Log4JLogger.class differ diff --git a/target/classes/org/stefan/snrpc/log/Logger.class b/target/classes/org/stefan/snrpc/log/Logger.class new file mode 100644 index 0000000..b5e2ad0 Binary files /dev/null and b/target/classes/org/stefan/snrpc/log/Logger.class differ diff --git a/target/classes/org/stefan/snrpc/log/LoggerFactory.class b/target/classes/org/stefan/snrpc/log/LoggerFactory.class new file mode 100644 index 0000000..1310bd5 Binary files /dev/null and b/target/classes/org/stefan/snrpc/log/LoggerFactory.class differ diff --git a/target/classes/org/stefan/snrpc/log/SunLogger.class b/target/classes/org/stefan/snrpc/log/SunLogger.class new file mode 100644 index 0000000..3890ca6 Binary files /dev/null and b/target/classes/org/stefan/snrpc/log/SunLogger.class differ diff --git a/target/classes/org/stefan/snrpc/serializer/AbstractProtostuffSerializer.class b/target/classes/org/stefan/snrpc/serializer/AbstractProtostuffSerializer.class new file mode 100644 index 0000000..bec8b38 Binary files /dev/null and b/target/classes/org/stefan/snrpc/serializer/AbstractProtostuffSerializer.class differ diff --git a/target/classes/org/stefan/snrpc/serializer/ClientSerializer.class b/target/classes/org/stefan/snrpc/serializer/ClientSerializer.class new file mode 100644 index 0000000..c8dec47 Binary files /dev/null and b/target/classes/org/stefan/snrpc/serializer/ClientSerializer.class differ diff --git a/target/classes/org/stefan/snrpc/serializer/ProtobufSerializer.class b/target/classes/org/stefan/snrpc/serializer/ProtobufSerializer.class new file mode 100644 index 0000000..7a5bcba Binary files /dev/null and b/target/classes/org/stefan/snrpc/serializer/ProtobufSerializer.class differ diff --git a/target/classes/org/stefan/snrpc/serializer/ServerSerializer.class b/target/classes/org/stefan/snrpc/serializer/ServerSerializer.class new file mode 100644 index 0000000..a359752 Binary files /dev/null and b/target/classes/org/stefan/snrpc/serializer/ServerSerializer.class differ diff --git a/target/classes/org/stefan/snrpc/serializer/SnRpcRequest.class b/target/classes/org/stefan/snrpc/serializer/SnRpcRequest.class new file mode 100644 index 0000000..40a1cf6 Binary files /dev/null and b/target/classes/org/stefan/snrpc/serializer/SnRpcRequest.class differ diff --git a/target/classes/org/stefan/snrpc/serializer/SnRpcRequestDecoder.class b/target/classes/org/stefan/snrpc/serializer/SnRpcRequestDecoder.class new file mode 100644 index 0000000..5687ae7 Binary files /dev/null and b/target/classes/org/stefan/snrpc/serializer/SnRpcRequestDecoder.class differ diff --git a/target/classes/org/stefan/snrpc/serializer/SnRpcRequestEncoder.class b/target/classes/org/stefan/snrpc/serializer/SnRpcRequestEncoder.class new file mode 100644 index 0000000..6abaced Binary files /dev/null and b/target/classes/org/stefan/snrpc/serializer/SnRpcRequestEncoder.class differ diff --git a/target/classes/org/stefan/snrpc/serializer/SnRpcResponse.class b/target/classes/org/stefan/snrpc/serializer/SnRpcResponse.class new file mode 100644 index 0000000..b288b07 Binary files /dev/null and b/target/classes/org/stefan/snrpc/serializer/SnRpcResponse.class differ diff --git a/target/classes/org/stefan/snrpc/serializer/SnRpcResponseDecoder.class b/target/classes/org/stefan/snrpc/serializer/SnRpcResponseDecoder.class new file mode 100644 index 0000000..ad89e1a Binary files /dev/null and b/target/classes/org/stefan/snrpc/serializer/SnRpcResponseDecoder.class differ diff --git a/target/classes/org/stefan/snrpc/serializer/SnRpcResponseEncoder.class b/target/classes/org/stefan/snrpc/serializer/SnRpcResponseEncoder.class new file mode 100644 index 0000000..945c079 Binary files /dev/null and b/target/classes/org/stefan/snrpc/serializer/SnRpcResponseEncoder.class differ diff --git a/target/classes/org/stefan/snrpc/server/ParseXmlToService.class b/target/classes/org/stefan/snrpc/server/ParseXmlToService.class new file mode 100644 index 0000000..121590e Binary files /dev/null and b/target/classes/org/stefan/snrpc/server/ParseXmlToService.class differ diff --git a/target/classes/org/stefan/snrpc/server/SnNettyRpcServer$1.class b/target/classes/org/stefan/snrpc/server/SnNettyRpcServer$1.class new file mode 100644 index 0000000..8bf2335 Binary files /dev/null and b/target/classes/org/stefan/snrpc/server/SnNettyRpcServer$1.class differ diff --git a/target/classes/org/stefan/snrpc/server/SnNettyRpcServer.class b/target/classes/org/stefan/snrpc/server/SnNettyRpcServer.class new file mode 100644 index 0000000..4a85a75 Binary files /dev/null and b/target/classes/org/stefan/snrpc/server/SnNettyRpcServer.class differ diff --git a/target/classes/org/stefan/snrpc/server/SnNettyRpcServerHandler.class b/target/classes/org/stefan/snrpc/server/SnNettyRpcServerHandler.class new file mode 100644 index 0000000..8e2ed2e Binary files /dev/null and b/target/classes/org/stefan/snrpc/server/SnNettyRpcServerHandler.class differ diff --git a/target/classes/org/stefan/snrpc/server/StatisticsService$1.class b/target/classes/org/stefan/snrpc/server/StatisticsService$1.class new file mode 100644 index 0000000..b4ea1ab Binary files /dev/null and b/target/classes/org/stefan/snrpc/server/StatisticsService$1.class differ diff --git a/target/classes/org/stefan/snrpc/server/StatisticsService.class b/target/classes/org/stefan/snrpc/server/StatisticsService.class new file mode 100644 index 0000000..c023a25 Binary files /dev/null and b/target/classes/org/stefan/snrpc/server/StatisticsService.class differ diff --git a/target/classes/org/stefan/snrpc/util/BufferCache$1.class b/target/classes/org/stefan/snrpc/util/BufferCache$1.class new file mode 100644 index 0000000..940c804 Binary files /dev/null and b/target/classes/org/stefan/snrpc/util/BufferCache$1.class differ diff --git a/target/classes/org/stefan/snrpc/util/BufferCache.class b/target/classes/org/stefan/snrpc/util/BufferCache.class new file mode 100644 index 0000000..c3cf2e7 Binary files /dev/null and b/target/classes/org/stefan/snrpc/util/BufferCache.class differ diff --git a/target/classes/org/stefan/snrpc/util/FileUtil.class b/target/classes/org/stefan/snrpc/util/FileUtil.class new file mode 100644 index 0000000..a68ff20 Binary files /dev/null and b/target/classes/org/stefan/snrpc/util/FileUtil.class differ diff --git a/target/classes/org/stefan/snrpc/util/HandlerMapper.class b/target/classes/org/stefan/snrpc/util/HandlerMapper.class new file mode 100644 index 0000000..beb2ae6 Binary files /dev/null and b/target/classes/org/stefan/snrpc/util/HandlerMapper.class differ diff --git a/target/classes/org/stefan/snrpc/util/IOUtils.class b/target/classes/org/stefan/snrpc/util/IOUtils.class new file mode 100644 index 0000000..0f82be3 Binary files /dev/null and b/target/classes/org/stefan/snrpc/util/IOUtils.class differ diff --git a/target/classes/org/stefan/snrpc/util/LRUMap.class b/target/classes/org/stefan/snrpc/util/LRUMap.class new file mode 100644 index 0000000..efc7b23 Binary files /dev/null and b/target/classes/org/stefan/snrpc/util/LRUMap.class differ diff --git a/target/classes/org/stefan/snrpc/util/MessageFormatter.class b/target/classes/org/stefan/snrpc/util/MessageFormatter.class new file mode 100644 index 0000000..695e111 Binary files /dev/null and b/target/classes/org/stefan/snrpc/util/MessageFormatter.class differ diff --git a/target/classes/org/stefan/snrpc/util/ReflectionCache.class b/target/classes/org/stefan/snrpc/util/ReflectionCache.class new file mode 100644 index 0000000..55e2c83 Binary files /dev/null and b/target/classes/org/stefan/snrpc/util/ReflectionCache.class differ diff --git a/target/classes/org/stefan/snrpc/util/SchemaCache.class b/target/classes/org/stefan/snrpc/util/SchemaCache.class new file mode 100644 index 0000000..c05db8b Binary files /dev/null and b/target/classes/org/stefan/snrpc/util/SchemaCache.class differ diff --git a/target/classes/org/stefan/snrpc/util/Sequence.class b/target/classes/org/stefan/snrpc/util/Sequence.class new file mode 100644 index 0000000..338e65e Binary files /dev/null and b/target/classes/org/stefan/snrpc/util/Sequence.class differ diff --git a/target/classes/org/stefan/snrpc/util/StringUtil.class b/target/classes/org/stefan/snrpc/util/StringUtil.class new file mode 100644 index 0000000..709fd4b Binary files /dev/null and b/target/classes/org/stefan/snrpc/util/StringUtil.class differ diff --git a/target/classes/snrpcserver.properties b/target/classes/snrpcserver.properties new file mode 100644 index 0000000..e154b8f --- /dev/null +++ b/target/classes/snrpcserver.properties @@ -0,0 +1,10 @@ +#tcpNoDelay +snrpc.tcp.nodelay=true +#call the bind method as many times as you want +snrpc.tcp.reuseAddress=true +#ISDEBUG +snrpc.dev=true +#TCP timeout +snrpc.read.timeout=25000 +#server port +snrpc.http.port=8080 diff --git a/target/test-classes/config.xml b/target/test-classes/config.xml new file mode 100644 index 0000000..a4f9341 --- /dev/null +++ b/target/test-classes/config.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/target/test-classes/org/stefan/snrpc/Client.class b/target/test-classes/org/stefan/snrpc/Client.class new file mode 100644 index 0000000..b20dbfa Binary files /dev/null and b/target/test-classes/org/stefan/snrpc/Client.class differ diff --git a/target/test-classes/org/stefan/snrpc/Server.class b/target/test-classes/org/stefan/snrpc/Server.class new file mode 100644 index 0000000..517ee1f Binary files /dev/null and b/target/test-classes/org/stefan/snrpc/Server.class differ diff --git a/target/test-classes/org/stefan/snrpc/server/SnRpcImpl.class b/target/test-classes/org/stefan/snrpc/server/SnRpcImpl.class new file mode 100644 index 0000000..d0c4b87 Binary files /dev/null and b/target/test-classes/org/stefan/snrpc/server/SnRpcImpl.class differ diff --git a/target/test-classes/org/stefan/snrpc/server/SnRpcInterface.class b/target/test-classes/org/stefan/snrpc/server/SnRpcInterface.class new file mode 100644 index 0000000..076d26a Binary files /dev/null and b/target/test-classes/org/stefan/snrpc/server/SnRpcInterface.class differ diff --git a/target/test-classes/snrpcserver.properties b/target/test-classes/snrpcserver.properties new file mode 100644 index 0000000..e154b8f --- /dev/null +++ b/target/test-classes/snrpcserver.properties @@ -0,0 +1,10 @@ +#tcpNoDelay +snrpc.tcp.nodelay=true +#call the bind method as many times as you want +snrpc.tcp.reuseAddress=true +#ISDEBUG +snrpc.dev=true +#TCP timeout +snrpc.read.timeout=25000 +#server port +snrpc.http.port=8080