Browse Source

将客户端与服务端置于同一仓库

pull/1/head
yichen 2 years ago
commit
7c8ab12d61
  1. 2
      .gitignore
  2. 279
      README.md
  3. 88
      agent/pom.xml
  4. 135
      agent/src/main/java/com/fanruan/AgentStarter.java
  5. 34
      agent/src/main/java/com/fanruan/cache/BeanCache.java
  6. 41
      agent/src/main/java/com/fanruan/cache/BeanCacheImpl.java
  7. 54
      agent/src/main/java/com/fanruan/cache/Cache.java
  8. 39
      agent/src/main/java/com/fanruan/cache/CacheImpl.java
  9. 34
      agent/src/main/java/com/fanruan/handler/Dispatcher.java
  10. 60
      agent/src/main/java/com/fanruan/handler/DispatcherHelper.java
  11. 109
      agent/src/main/java/com/fanruan/handler/MyDispatcherImpl.java
  12. 34
      agent/src/main/java/com/fanruan/handler/ResponseEmitter.java
  13. 48
      agent/src/main/java/com/fanruan/handler/ResponseEmitterImpl.java
  14. 292
      agent/src/main/java/com/fanruan/jdbc/connection/MyConnection.java
  15. 74
      agent/src/main/java/com/fanruan/jdbc/driver/MyDriver.java
  16. 973
      agent/src/main/java/com/fanruan/jdbc/resultset/MyResultSet.java
  17. 517
      agent/src/main/java/com/fanruan/jdbc/statement/MyPreparedStatement.java
  18. 237
      agent/src/main/java/com/fanruan/jdbc/statement/MyStatement.java
  19. 20
      agent/src/main/java/com/fanruan/pojo/message/RpcRequest.java
  20. 19
      agent/src/main/java/com/fanruan/pojo/message/RpcResponse.java
  21. 54
      agent/src/main/java/com/fanruan/serializer/KryoSerializer.java
  22. 22
      agent/src/main/java/com/fanruan/serializer/Serializer.java
  23. 20
      agent/src/main/java/com/fanruan/utils/DBProperties.java
  24. 10
      agent/src/main/resources/log4j2.properties
  25. 14
      agent/src/main/resources/socket.properties
  26. 100
      agent/src/test/java/HSQLTest.java
  27. 37
      agent/src/test/java/Test.java
  28. 21
      pom.xml
  29. 82
      service/pom.xml
  30. 193
      service/src/main/java/com/fanruan/ServerStater.java
  31. 69
      service/src/main/java/com/fanruan/cache/ClientCache.java
  32. 45
      service/src/main/java/com/fanruan/cache/ClientWrapper.java
  33. 26
      service/src/main/java/com/fanruan/cache/LockAndCondition.java
  34. 891
      service/src/main/java/com/fanruan/jdbc/MyDataBaseMetaData.java
  35. 318
      service/src/main/java/com/fanruan/jdbc/connection/MyConnection.java
  36. 84
      service/src/main/java/com/fanruan/jdbc/driver/MyDriver.java
  37. 990
      service/src/main/java/com/fanruan/jdbc/resultset/MyResultSet.java
  38. 535
      service/src/main/java/com/fanruan/jdbc/statement/MyPreparedStatement.java
  39. 252
      service/src/main/java/com/fanruan/jdbc/statement/MyStatement.java
  40. 29
      service/src/main/java/com/fanruan/pojo/message/RpcRequest.java
  41. 21
      service/src/main/java/com/fanruan/pojo/message/RpcResponse.java
  42. 21
      service/src/main/java/com/fanruan/proxy/ProxyFactory.java
  43. 146
      service/src/main/java/com/fanruan/proxy/interceptor/Interceptor.java
  44. 118
      service/src/main/java/com/fanruan/proxy/interceptor/InterceptorUtils.java
  45. 54
      service/src/main/java/com/fanruan/serializer/KryoSerializer.java
  46. 21
      service/src/main/java/com/fanruan/serializer/Serializer.java
  47. 47
      service/src/main/java/com/fanruan/utils/Commons.java
  48. 21
      service/src/main/java/com/fanruan/utils/DBProperties.java
  49. 11
      service/src/main/resources/log4j2.properties
  50. 23
      service/src/main/resources/socketIO.properties
  51. 22
      service/src/test/java/AutoStarter.java
  52. 105
      service/src/test/java/ServiceTest.java
  53. 244
      service/src/test/java/Test.java
  54. 8
      service/src/test/java/TestUtils.java

2
.gitignore vendored

@ -0,0 +1,2 @@
.idea
*/target

279
README.md

@ -0,0 +1,279 @@
# README
## 项目功能
为达到`Service` 从公网访问客户端所在内网中数据源的效果,通过运行在客户机上的代理程序代理`Service`的所有`JDBC`请求,并将查询结果返回给`Service`。实现目标,`Service`除更改使用的`JDBC`驱动外,对代理存在无感知,支持主流的包含`JDBC`支持的数据库。
## 项目依赖
`Netty-socketio`与`Socket.io-client-Java`的对应关系是:
| [`netty-socketio`](https://github.com/mrniko/netty-socketio) | [`Java client`](https://github.com/socketio/socket.io-client-java) |
| ------------------------------------------------------------ | ------------------------------------------------------------ |
| 1.7.19 | 1.0.x |
| 暂无 | [Document](https://socketio.github.io/socket.io-client-java/installation.html) |
以下用`Service`指代`Socket`连接中的`socket`服务器,它也是需求查询用户内网数据源的公网服务器。
用`Agent`指代`Socket`连接中的客户端,也是运行在用户`PC`上承担远程调用`JDBC`方法的代理服务。
具体结构见下文项目结构图。
## QUICKSTART
1. 分别下载`Agent`和`Serviec`
2. 修改数据库配置和对应的SQL语句
3. 先运行`Service`中的`Test的`主函数
4. 运行`Agent`中的`Test`的主函数
即可在`Service`上观察到查询结果
```
目前只测试了mysql 数据库,但内置支持 mysql、 postgresql、 oracle、 sqlserver、 db2, 在 Agent 上注册驱动即可使用
```
## 实现方案
1. `Service` 启动`socket`服务与 `Agent`建立连接后,可以开始使用代理进行查询。
2. `Service`端通过自实现的`JDBC`驱动,进行`JDBC`操作。驱动中使用基于`CGlib`的动态代理,对`Service`端的所有`JDBC`相关驱动类进行增强,所有方法信息会被序列化传递到`Agent`执行,并有选择地将结果回送到`Service`
## 结构与流程
<img src="/pic/project structure.jpg" alt="project structure" title="project structure">
如上图,对于`Service` 端来讲,`Agent`对其的代理是无感知的。在`Service`来看,只是调用了一个自定义的`JDBC`驱动进行查询。
这得益于驱动内部方法地重写,自定义地实现类在`Agent`和`Service`中有相同的名字,但内部实现却不相同,这使得整个RPC的流程十分灵活。
## 动态代理
动态代理是该项目中的核心,如在 `Driver`类的 `connect`方法中:返回的`Connection`就被替换为了动态代理增强过的`MyConnection`,实现对`Service`中调用的`JDBC`方法的完全代理。代理类会依靠`info`从缓存中找到命名空间(本项目中以`/dataSoure Name`来区别命名空间)对应的`socket`,将方法调用信息以`RPCReqquest`的方式序列化后发送出去。
```java
// In Service Source Code
@Override
public Connection connect(String url, Properties info) throws SQLException {
String agentID = info.getProperty("agentID");
String dbName = info.getProperty("agentDBName");
if(dbName == null){
dbName = url.split(":")[1];
info.setProperty("agentDBName", dbName);
}
MyConnection myConn = (MyConnection) ProxyFactory.getProxy(MyConnection.class, info);
myConn.setInfo(info);
return myConn;
}
```
RPC实体类包含如下信息:
```java
@Data
@Accessors(chain = true)
public class RpcRequest {
// Marks whether the method delivered need loopback data
private boolean reply;
// Marks whether the method will create an instance requeired to be cached.
private boolean binding;
private String ID;
private String IDtoInvoke;
private Class ServiceClass;
private String MethodName;
private Object[] args;
private Class[] argTypes;
}
```
在`Agent`收到`Request`的时候,会按照报文要求对方法进行调用,某些创建的实例会被缓存,以便之后调用。在本项目中,这些实例的类是:
```
Drive( MyDriver ), Connection( MyConnection ), Statement( MyStatement ), PreparedStatement( MyPreparedStatement ), ResultSet( MyResult )
```
```java
public Object invokeAsRequest(RpcRequest rpcRequest, BeanCache beanCache) {
...
// The ID of the rpcRequest could be save as the ID of an instance
// Because one instance can only been create just once for an unique rpcRequest
String IDtoCache = rpcRequest.getID();
String IDtoInvoke = rpcRequest.getIDtoInvoke();
...
```
## RPC调用
在一次RPC调用流程中,`FutureTask` 异步获取返回结果,以“生产者-消费者”模型实现一次调用的同步管理。
`ClientWrapper` 持有着各个命名空间上的`socket`。在这些`socket`上的通信,每次调用,会在`wrapper`中注册一个工具类:`LockAndCondition`,发出消息后,等待`socket`上出现对应的响应报文唤醒`FutureTask` 线程。通过锁机制,保证逻辑的正确性。
```java
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ClientWrapper {
private SocketIOClient client;
private static Map<String, LockAndCondition> lockMap = new ConcurrentHashMap<>();
public SocketIOClient getClient(){
if(client == null) throw new RuntimeException("no such client");
return client;
}
public LockAndCondition getLockAndCondition(String messageID){
LockAndCondition lac = lockMap.get(messageID);
if(lac == null){
ReentrantLock lock = new ReentrantLock();
Condition condition = lock.newCondition();
lac = new LockAndCondition(lock, condition);
lockMap.put(messageID, lac);
}
return lac;
}
public void removeLockAndCondition(String messageID){
lockMap.remove(messageID);
}
}
```
```java
@Data
@NoArgsConstructor
@AllArgsConstructor
public class LockAndCondition{
private ReentrantLock lock;
private Condition condition;
private Object result;
private String BindingID;
LockAndCondition(ReentrantLock lock, Condition condition){
this.lock = lock;
this.condition = condition;
}
}
```
```java
FutureTask<Object> futureTask = new FutureTask<Object>(
new Callable<Object>() {
@Override
public Object call() throws Exception {
Object res = null;
ClientWrapper wrapper = ClientCache.getClientWrapper(agentID, dbName);
LockAndCondition lac = wrapper.getLockAndCondition(rpcRequest.getID());
ReentrantLock lock = lac.getLock();
Condition condition = lac.getCondition();
try{
byte[] bytes = ServerStater.serializer.serialize(rpcRequest);
lock.lock();
client.sendEvent("RPCRequest", bytes);
condition.await();
// get res from RPC response data
res = lac.getResult();
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
return res;
}
}
);
ServerStater.threadPool.submit(futureTask);
Object res = futureTask.get();
```
`socket`收到响应时解锁对应的线程。
```java
// rpcResponse
nameSpace.addEventListener("RPCResponse", byte[].class, ((client, data, ackRequest) -> {
RpcResponse rpcResponse = serializer.deserialize(data, RpcResponse.class);
logger.debug("RPCResponse: " + (rpcResponse.getStatus() ? "success" : "fail"));
String agentID = Commons.getAgentID(client);
String dbName = Commons.getDBName(client);
ClientWrapper wrapper = ClientCache.getClientWrapper(agentID, dbName);
LockAndCondition lac = wrapper.getLockAndCondition(rpcResponse.getID());
ReentrantLock lock = lac.getLock();
Condition condition = lac.getCondition();
// When a response is received, it notifies that the futuretask thread blocking on the lockandcondition
// If the response contains data, take it out.
try {
lock.lock();
Object resultData = rpcResponse.getResult();
if(!rpcResponse.getStatus()){
logger.error(resultData);
resultData = null;
}
if(resultData != null) lac.setResult(resultData);
condition.signal();
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
wrapper.removeLockAndCondition(rpcResponse.getID());
logger.debug("received response message, signaled condition");
}));
```
`Service`是使用`netty`实现的高效同步非阻塞`IO`,上文的同步机制可以很大程度上利用`socket`的并发效果。
## 绑定实例
确定`Agent`上缓存实例与`Service`端实例的一一对应关系是很必要,不然程序在反射调用方法时会产生问题。
例如,对于`createStatement()`方法必须由上一步生成的`Connection`类进行调用。为了达到这一点,这些`Service`端实例必须和`Agent`端具有相同的ID。
考虑到在进行`RPC`调用回调的时候,利用时间和随机数生成了一个唯一`ID`。
```java
public static String getID(){
return getTimeInMillis() + getRandom();
}
public static String getTimeInMillis() {
long timeInMillis = Calendar.getInstance().getTimeInMillis();
return timeInMillis+"";
}
public static String getRandom() {
Random random = new Random();
int nextInt = random.nextInt(9000000);
nextInt=nextInt+1000000;
String str=nextInt+"";
return str;
}
```
而`Agent`端的缓存实例是由某次调用产生的,所以只需将该次调用的`RPC`报文`ID`标记在实例上,并在收到`RPC`响应时为需要绑定的类型打上同样的标记即可。这样`Agent`方面,由于存储的实例都有了唯一的`ID`作为键,大大简化了缓存系统的复杂性。
标记实现:
```java
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { ...
Object returnObj = methodProxy.invokeSuper(o, objects);
// If the return instance is corresponding with another instance in agent, set the binding ID.
if (InterceptorUtils.isInBindList(returnObj)){
InterceptorUtils.setInvokeHelper(returnObj, "setID", rpcRequest.getID());
}
```
## 项目参考
[nuzzle: A Simple RPC Project](https://github.com/sakiila/nuzzle)
[CSV JDBC Driver](https://github.com/peterborkuti/csv-jdbc-driver)

88
agent/pom.xml

@ -0,0 +1,88 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>intranet</artifactId>
<groupId>org.example</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>agent</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>io.socket</groupId>
<artifactId>socket.io-client</artifactId>
<version>1.0.2</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
</dependency>
<dependency>
<groupId>com.esotericsoftware</groupId>
<artifactId>kryo</artifactId>
<version>5.3.0</version>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.4.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.17.2</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.17.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.29</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.17.2</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.hsqldb/hsqldb -->
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<classifier>debug</classifier>
<version>2.5.2</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.4.0</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

135
agent/src/main/java/com/fanruan/AgentStarter.java

@ -0,0 +1,135 @@
package com.fanruan;
import com.fanruan.handler.MyDispatcherImpl;
import com.fanruan.pojo.message.RpcRequest;
import com.fanruan.serializer.KryoSerializer;
import com.fanruan.serializer.Serializer;
import io.socket.client.IO;
import io.socket.client.Socket;
import io.socket.engineio.client.transports.WebSocket;
import okhttp3.Dispatcher;
import okhttp3.OkHttpClient;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URI;
import java.util.Properties;
import java.util.concurrent.TimeUnit;
/**
* @author YiChen Dai
*/
public class AgentStarter {
protected static final Logger logger = LogManager.getLogger();
public final static Serializer SERIALIZER = new KryoSerializer();
public static MyDispatcherImpl myDispatcherImpl;
public static String AgentID;
public AgentStarter(String[] DBs) {
myDispatcherImpl = new MyDispatcherImpl();
try {
createSocket(DBs);
} catch (Exception e) {
e.printStackTrace();
}
}
private void createSocket(String[] DBs) throws IOException {
logger.debug("加载配置");
IO.Options options = new IO.Options();
try{
InputStream in = this.getClass().getResourceAsStream("/socket.properties");
Properties props = new Properties();
InputStreamReader inputStreamReader = new InputStreamReader(in, "UTF-8");
props.load(inputStreamReader);
options.transports = new String[]{WebSocket.NAME};
options.reconnectionAttempts = Integer.parseInt(props.getProperty("reconnectionAttempts"));
options.query = "agentID=" + props.getProperty("agentID");
AgentID = props.getProperty("agentID");
options.reconnectionDelay = Integer.parseInt(props.getProperty("reconnectionDelay"));
options.timeout = Integer.parseInt(props.getProperty("timeout"));
String uri = props.getProperty("uri");
in.close();
// config the max number of socket
int MAX_CLIENTS = 10;
Dispatcher dispatcher = new Dispatcher();
dispatcher.setMaxRequests(MAX_CLIENTS * 2);
dispatcher.setMaxRequestsPerHost(MAX_CLIENTS * 2);
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.dispatcher(dispatcher)
// important for HTTP long-polling
.readTimeout(1, TimeUnit.MINUTES)
.build();
options.callFactory = okHttpClient;
options.webSocketFactory = okHttpClient;
Socket defaultSocket = IO.socket(URI.create(uri), options);
MyDispatcherImpl.CACHE.registerSocket("/", defaultSocket);
configDefaultSocket(defaultSocket);
for(String dbName : DBs){
Socket socket = IO.socket(URI.create(uri + "/" + dbName), options);
MyDispatcherImpl.CACHE.registerSocket(dbName, socket);
configSocket(socket, dbName);
}
}catch (Exception e){
e.printStackTrace();
}
}
private void configDefaultSocket(Socket socket) throws IOException {
socket.on(Socket.EVENT_CONNECT, objects -> {
logger.info("default-socket connected!");
});
socket.on(Socket.EVENT_CONNECT_ERROR, objects -> {
logger.info("default-socket error: " + objects[0].toString());
});
socket.on(Socket.EVENT_DISCONNECT, objects -> {
for(Object obj : objects){
logger.info("default-socket closed: " + obj.toString());
}
});
}
private void configSocket(Socket socket, String dbName) throws IOException {
socket.on(Socket.EVENT_CONNECT, objects -> {
logger.info(dbName + "-socket connected!");
});
socket.on(Socket.EVENT_DISCONNECT, objects -> {
for(Object obj : objects){
logger.info(dbName + "-socket closed: " + obj.toString());
}
});
socket.on(Socket.EVENT_CONNECT_ERROR, objects -> {
logger.info(dbName + "-socket error: " + objects[0].toString());
});
socket.on("RPCRequest", objects -> {
RpcRequest rpcRequest = SERIALIZER.deserialize((byte[]) objects[0], RpcRequest.class);
logger.debug(dbName + "-RPCRequest: " + rpcRequest.toString());
try {
myDispatcherImpl.doDispatch(rpcRequest, dbName);
} catch (Exception e) {
e.printStackTrace();
}
});
}
}

34
agent/src/main/java/com/fanruan/cache/BeanCache.java vendored

@ -0,0 +1,34 @@
package com.fanruan.cache;
/**
* Define the operation of the Map where cached instances like Driver, Connection
* @author Yichen Dai
* @date 2022/8/16 16:41
*/
public interface BeanCache {
/**
* Get cached instances like Driver, Connection
* @param ID The unique num of a cache instance, It comes from the RPC request ID,
* which asked to create the instance.
* @param clazz The class of the cached instance.
* @return cached instance of the given type.
*/
<T> T getCachedInstances(String ID, Class<T> clazz);
/**
* Remove a cached instance of given ID.
* @param ID The unique num of a cache instance, It comes from the RPC request ID,
* which asked to create the instance.
*/
void removeInstances(String ID);
/**
* Save the given object
* @param ID The unique num of a cache instance, It comes from the RPC request ID,
* which asked to create the instance.
* @param o Instance to be cached
*/
void cacheInstance(String ID, Object o);
}

41
agent/src/main/java/com/fanruan/cache/BeanCacheImpl.java vendored

@ -0,0 +1,41 @@
package com.fanruan.cache;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author Yichen Dai
*/
public class BeanCacheImpl implements BeanCache{
public String dbName;
/**
* cache those instances asked to be established by RPC request
*/
final private static Map<String, Object> CACHE = new ConcurrentHashMap<>();
public BeanCacheImpl(String dbName){
this.dbName = dbName;
}
@Override
public <T> T getCachedInstances(String ID, Class<T> clazz){
try {
return clazz.cast(CACHE.get(ID));
}catch (Exception e){
e.printStackTrace();
}
return null;
}
@Override
public void removeInstances(String ID){
CACHE.remove(ID);
}
@Override
public void cacheInstance(String ID, Object o){
CACHE.put(ID, o);
}
}

54
agent/src/main/java/com/fanruan/cache/Cache.java vendored

@ -0,0 +1,54 @@
package com.fanruan.cache;
import io.socket.client.Socket;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* Global cache which has the same life cycle with Dispatcher
* @author Yichen Dai
* @date 2022/8/16 16:13
*/
public interface Cache {
/**
* stored socket instance by dataBase name
*/
Map<String, Socket> SOCKET_MAP = new ConcurrentHashMap<>();
/**
* Bunch of Map where cached instances like Driver, Connection
*/
Map<String, BeanCacheImpl> BEAN_CACHE = new ConcurrentHashMap<>();
/**
* register the socket of specific nameSpace,
* the nameSpace is named as "/" + DB name.
* @param dbName the key of cache entry
* @param socket the value of cache entry
*/
void registerSocket(String dbName, Socket socket);
/**
* get socket by DB name
* @param dbName the key of cache entry
* @return socket of the nameSpace
*/
Socket getSocket(String dbName);
/**
* register the socket of specific nameSpace/db
* @param dbName the key of cache
* @param beanCache Map where cached instances like Driver, Connection
*/
void registerBeanCache(String dbName, BeanCacheImpl beanCache);
/**
* get the beanCache of specific nameSpace/db
* @param dbName the key of cache
* @return beanCache: Map where cached instances like Driver, Connection
*/
BeanCacheImpl getBeanCache(String dbName);
}

39
agent/src/main/java/com/fanruan/cache/CacheImpl.java vendored

@ -0,0 +1,39 @@
package com.fanruan.cache;
import io.socket.client.Socket;
/**
* @author Yichen Dai
* @date 2022/8/16 16:13
*/
public class CacheImpl implements Cache{
@Override
public void registerSocket(String dbName, Socket socket){
SOCKET_MAP.put(dbName, socket);
}
@Override
public Socket getSocket(String dbName){
Socket socket = SOCKET_MAP.get(dbName);
if (socket == null){
throw new RuntimeException("no such DataBase Name");
}
return socket;
}
@Override
public void registerBeanCache(String dbName, BeanCacheImpl beanCache) {
BEAN_CACHE.put(dbName, beanCache);
}
@Override
public BeanCacheImpl getBeanCache(String dbName) {
BeanCacheImpl beanCache = BEAN_CACHE.get(dbName);
if(beanCache == null){
beanCache = new BeanCacheImpl(dbName);
registerBeanCache(dbName, beanCache);
}
return beanCache;
}
}

34
agent/src/main/java/com/fanruan/handler/Dispatcher.java

@ -0,0 +1,34 @@
package com.fanruan.handler;
import com.fanruan.cache.BeanCacheImpl;
import com.fanruan.cache.CacheImpl;
import com.fanruan.pojo.message.RpcRequest;
/**
* Dispatch and process received requests
* @author Yichen Dai
* @date 2022/8/16 14:56
*/
public interface Dispatcher {
CacheImpl CACHE = new CacheImpl();
ResponseEmitterImpl RESPONSE_EMITTER_IMPL = new ResponseEmitterImpl();
/**
*
* @param rpcRequest
* @param dbName
*/
void doDispatch(RpcRequest rpcRequest, String dbName);
/**
*
* @param rpcRequest
* @param beanCache
* @return
* @throws Throwable
*/
Object invokeAsRequest(RpcRequest rpcRequest, BeanCacheImpl beanCache) throws Throwable;
}

60
agent/src/main/java/com/fanruan/handler/DispatcherHelper.java

@ -0,0 +1,60 @@
package com.fanruan.handler;
import java.util.HashMap;
import java.util.Map;
/**
* Some utils for MyDispatcher
* @author Yichen Dai
*/
public class DispatcherHelper {
private static final Map<String, Class<?>> WRAPPER_CLASS_MAP = new HashMap<String, Class<?>>(){
{
put("Integer", Integer.TYPE);
put("Short", Short.TYPE);
put("Long", Long.TYPE);
put("Double", Double.TYPE);
put("Float", Float.TYPE);
put("Byte", Byte.TYPE);
put("Character", Character.TYPE);
put("Boolean", Boolean.TYPE);
}
};
public final static String[] CACHE_LIST = new String[]{
"com.fanruan.jdbc.driver.MyDriver",
"com.fanruan.jdbc.connection.MyConnection",
"com.fanruan.jdbc.statement.MyStatement",
"com.fanruan.jdbc.statement.MyPreparedStatement",
"com.fanruan.jdbc.resultset.MyResultSet",
};
public static boolean isInCacheList(String className){
for(String s : CACHE_LIST){
if(s.equals(className)){
return true;
}
}
return false;
}
public static boolean isWraps(Class<?> clz){
return WRAPPER_CLASS_MAP.containsKey(getClassName(clz.getName()));
}
public static Class<?> castToPrimitiveClass(Class<?> clz){
return WRAPPER_CLASS_MAP.get(getClassName(clz.getName()));
}
public static String getClassName(String fullyQualifiedClassName){
String[] arr = fullyQualifiedClassName.split("\\.");
int n = arr.length;
if(n == 0) {
throw new RuntimeException("the class name invoked is wrong");
}
return arr[n-1];
}
}

109
agent/src/main/java/com/fanruan/handler/MyDispatcherImpl.java

@ -0,0 +1,109 @@
package com.fanruan.handler;
import com.fanruan.cache.BeanCacheImpl;
import com.fanruan.pojo.message.RpcRequest;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.lang.reflect.Method;
/**
* @author Yichen Dai
*/
public class MyDispatcherImpl implements Dispatcher{
protected static final Logger logger = LogManager.getLogger();
public final static String CLOSE_NAME = "close";
public MyDispatcherImpl(){}
@Override
public void doDispatch(RpcRequest rpcRequest, String dbName) {
logger.debug("do dispatcher");
BeanCacheImpl beanCache = CACHE.getBeanCache(dbName);
Object res = null;
try {
res = invokeAsRequest(rpcRequest, beanCache);
}catch (Exception e){
RESPONSE_EMITTER_IMPL.sendError(CACHE.getSocket(dbName), rpcRequest, e);
}
if(rpcRequest.isReply()){
RESPONSE_EMITTER_IMPL.replyWithData(CACHE.getSocket(dbName), rpcRequest, res);
}else {
RESPONSE_EMITTER_IMPL.sendOk(CACHE.getSocket(dbName), rpcRequest);
}
}
@Override
public Object invokeAsRequest(RpcRequest rpcRequest, BeanCacheImpl beanCache) throws Exception{
Class<?> clazz = rpcRequest.getServiceClass();
String methodName = rpcRequest.getMethodName();
Object[] args = rpcRequest.getArgs();
Class<?>[] argTypes = rpcRequest.getArgTypes();
Object calledClassInstance = null;
// The ID of the rpcRequest could be save as the ID of an instance
// Because one instance can only been create just once for an unique rpcRequest
String IDToCache = rpcRequest.getID();
String IDToInvoke = rpcRequest.getIDToInvoke();
String fullName = clazz.getName();
String className = DispatcherHelper.getClassName(fullName);
// If BeanCache contains instance, get it; if not, create it.
if(IDToInvoke == null){
try{
// create
calledClassInstance = Class.forName(fullName).newInstance();
}catch (Exception e) {
e.printStackTrace();
}
beanCache.cacheInstance(IDToCache, calledClassInstance);
}else{
calledClassInstance = beanCache.getCachedInstances(IDToInvoke, clazz);
}
Method method;
try {
// The primitive variable's type will be automatically packaged when passed as a class object,
// And an error will be reported when the method with the primitive variable as the parameter is called
method = clazz.getDeclaredMethod(methodName, argTypes);
}catch (Exception e){
for(int i=0; i<argTypes.length; i++){
Class<?> clz = argTypes[i];
if(DispatcherHelper.isWraps(clz)){
argTypes[i] = DispatcherHelper.castToPrimitiveClass(clz);
}
}
method = clazz.getDeclaredMethod(methodName, argTypes);
}
Object res = method.invoke(calledClassInstance, args);
if(CLOSE_NAME.equals(methodName)){
beanCache.removeInstances(IDToInvoke);
}
// Cached some instances need to be invoke later.
// Some method return null, so determine the value of `res` before referencing it.
if(res != null){
String resClassName = res.getClass().getName();
if(DispatcherHelper.isInCacheList(resClassName)) {
beanCache.cacheInstance(rpcRequest.getID(), res);
}
logger.info("invoke" + className + "-" + methodName + " and return a instance of" + res.getClass().getName());
}else{
logger.info("invoke" + className + "-" + methodName + " and no return value");
}
return res;
}
}

34
agent/src/main/java/com/fanruan/handler/ResponseEmitter.java

@ -0,0 +1,34 @@
package com.fanruan.handler;
import com.fanruan.pojo.message.RpcRequest;
import io.socket.client.Socket;
/**
* @author Yichen Dai
* @date 2022/8/16 16:57
*/
public interface ResponseEmitter {
/**
* Send success response for the request which not require reply.
* @param socket socket to send event
* @param rpcRequest corresponding request
*/
void sendOk(Socket socket, RpcRequest rpcRequest);
/**
* Send failure response when error occur while handle request.
* @param socket
* @param rpcRequest
* @param e Exception happened while handle request.
*/
void sendError(Socket socket, RpcRequest rpcRequest, Exception e);
/**
* Send success response with data asked by request.
* @param socket
* @param rpcRequest
* @param res data required.
*/
void replyWithData(Socket socket, RpcRequest rpcRequest, Object res);
}

48
agent/src/main/java/com/fanruan/handler/ResponseEmitterImpl.java

@ -0,0 +1,48 @@
package com.fanruan.handler;
import com.fanruan.AgentStarter;
import com.fanruan.pojo.message.RpcRequest;
import com.fanruan.pojo.message.RpcResponse;
import io.socket.client.Socket;
/**
* Utils for dispatcher to send response;
* @author Yichen Dai
*/
public class ResponseEmitterImpl implements ResponseEmitter{
@Override
public void sendOk(Socket socket, RpcRequest rpcRequest){
RpcResponse rpcResponse = new RpcResponse();
rpcResponse.setResult(null)
.setID(rpcRequest.getID())
.setBinding(rpcRequest.isBinding())
.setStatus(true);
byte[] bytes = AgentStarter.SERIALIZER.serialize(rpcResponse);
socket.emit("RPCResponse", bytes);
}
@Override
public void sendError(Socket socket, RpcRequest rpcRequest, Exception e){
RpcResponse rpcResponse = new RpcResponse();
rpcResponse.setResult("Some errors happened when AgentID: " + AgentStarter.AgentID + " "
+ rpcRequest.getMethodName() + " is being invoked!" + "\n"
+ "Error Message: " + e.getMessage()
+ " and check your code")
.setID(rpcRequest.getID())
.setBinding(rpcRequest.isBinding())
.setStatus(false);
byte[] bytes = AgentStarter.SERIALIZER.serialize(rpcResponse);
socket.emit("RPCResponse", bytes);
}
@Override
public void replyWithData(Socket socket, RpcRequest rpcRequest, Object res){
RpcResponse rpcResponse = new RpcResponse();
rpcResponse.setID(rpcRequest.getID())
.setStatus(true)
.setResult(res);
byte[] bytes = AgentStarter.SERIALIZER.serialize(rpcResponse);
socket.emit("RPCResponse", bytes);
}
}

292
agent/src/main/java/com/fanruan/jdbc/connection/MyConnection.java

@ -0,0 +1,292 @@
package com.fanruan.jdbc.connection;
import com.fanruan.jdbc.statement.MyPreparedStatement;
import com.fanruan.jdbc.statement.MyStatement;
import java.sql.*;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.Executor;
/**
* @author Yichen Dai
*/
public class MyConnection implements Connection {
final private Connection conn;
public MyConnection(Connection conn){
this.conn = conn;
}
@Override
public Statement createStatement() throws SQLException {
Statement st = this.conn.createStatement();
return new MyStatement(st);
}
@Override
public PreparedStatement prepareStatement(String sql) throws SQLException {
PreparedStatement pst = this.conn.prepareStatement(sql);
return new MyPreparedStatement(pst);
}
@Override
public CallableStatement prepareCall(String sql) throws SQLException {
return conn.prepareCall(sql);
}
@Override
public String nativeSQL(String sql) throws SQLException {
return conn.nativeSQL(sql);
}
@Override
public void setAutoCommit(boolean autoCommit) throws SQLException {
conn.setAutoCommit(autoCommit);
}
@Override
public boolean getAutoCommit() throws SQLException {
return conn.getAutoCommit();
}
@Override
public void commit() throws SQLException {
conn.commit();
}
@Override
public void rollback() throws SQLException {
conn.rollback();
}
@Override
public void close() throws SQLException {
conn.close();
}
@Override
public boolean isClosed() throws SQLException {
return conn.isClosed();
}
@Override
public DatabaseMetaData getMetaData() throws SQLException {
return conn.getMetaData();
}
@Override
public void setReadOnly(boolean readOnly) throws SQLException {
conn.setReadOnly(readOnly);
}
@Override
public boolean isReadOnly() throws SQLException {
return conn.isReadOnly();
}
@Override
public void setCatalog(String catalog) throws SQLException {
conn.setCatalog(catalog);
}
@Override
public String getCatalog() throws SQLException {
return conn.getCatalog();
}
@Override
public void setTransactionIsolation(int level) throws SQLException {
conn.setTransactionIsolation(level);
}
@Override
public int getTransactionIsolation() throws SQLException {
return conn.getTransactionIsolation();
}
@Override
public SQLWarning getWarnings() throws SQLException {
return conn.getWarnings();
}
@Override
public void clearWarnings() throws SQLException {
conn.clearWarnings();
}
@Override
public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException {
return conn.createStatement(resultSetType, resultSetConcurrency);
}
@Override
public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
return conn.prepareStatement(sql, resultSetType, resultSetConcurrency);
}
@Override
public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
return conn.prepareCall(sql, resultSetType, resultSetConcurrency);
}
@Override
public Map<String, Class<?>> getTypeMap() throws SQLException {
return conn.getTypeMap();
}
@Override
public void setTypeMap(Map<String, Class<?>> map) throws SQLException {
conn.setTypeMap(map);
}
@Override
public void setHoldability(int holdability) throws SQLException {
conn.setHoldability(holdability);
}
@Override
public int getHoldability() throws SQLException {
return conn.getHoldability();
}
@Override
public Savepoint setSavepoint() throws SQLException {
return conn.setSavepoint();
}
@Override
public Savepoint setSavepoint(String name) throws SQLException {
return conn.setSavepoint(name);
}
@Override
public void rollback(Savepoint savepoint) throws SQLException {
conn.rollback(savepoint);
}
@Override
public void releaseSavepoint(Savepoint savepoint) throws SQLException {
conn.releaseSavepoint(savepoint);
}
@Override
public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
return conn.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability);
}
@Override
public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
return conn.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
}
@Override
public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
return conn.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
}
@Override
public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {
return conn.prepareStatement(sql, autoGeneratedKeys);
}
@Override
public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException {
return conn.prepareStatement(sql, columnIndexes);
}
@Override
public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException {
return conn.prepareStatement(sql, columnNames);
}
@Override
public Clob createClob() throws SQLException {
return conn.createClob();
}
@Override
public Blob createBlob() throws SQLException {
return conn.createBlob();
}
@Override
public NClob createNClob() throws SQLException {
return conn.createNClob();
}
@Override
public SQLXML createSQLXML() throws SQLException {
return conn.createSQLXML();
}
@Override
public boolean isValid(int timeout) throws SQLException {
return conn.isValid(timeout);
}
@Override
public void setClientInfo(String name, String value) throws SQLClientInfoException {
conn.setClientInfo(name, value);
}
@Override
public void setClientInfo(Properties properties) throws SQLClientInfoException {
conn.setClientInfo(properties);
}
@Override
public String getClientInfo(String name) throws SQLException {
return conn.getClientInfo(name);
}
@Override
public Properties getClientInfo() throws SQLException {
return conn.getClientInfo();
}
@Override
public Array createArrayOf(String typeName, Object[] elements) throws SQLException {
return conn.createArrayOf(typeName, elements);
}
@Override
public Struct createStruct(String typeName, Object[] attributes) throws SQLException {
return conn.createStruct(typeName, attributes);
}
@Override
public void setSchema(String schema) throws SQLException {
conn.setSchema(schema);
}
@Override
public String getSchema() throws SQLException {
return conn.getSchema();
}
@Override
public void abort(Executor executor) throws SQLException {
conn.abort(executor);
}
@Override
public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException {
conn.setNetworkTimeout(executor, milliseconds);
}
@Override
public int getNetworkTimeout() throws SQLException {
return conn.getNetworkTimeout();
}
@Override
public <T> T unwrap(Class<T> iface) throws SQLException {
return conn.unwrap(iface);
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
return conn.isWrapperFor(iface);
}
}

74
agent/src/main/java/com/fanruan/jdbc/driver/MyDriver.java

@ -0,0 +1,74 @@
package com.fanruan.jdbc.driver;
import com.fanruan.jdbc.connection.MyConnection;
import java.sql.*;
import java.util.Enumeration;
import java.util.Properties;
import java.util.logging.Logger;
/**
* @author Yichen Dai
*/
public class MyDriver implements Driver {
static public final int DRIVER_VERSION_MAJOR = 1;
static public final int DRIVER_VERSION_MINOR = 1;
//依靠静态函数块注册驱动
static{
try {
DriverManager.registerDriver(new MyDriver());
} catch (Exception e) {
throw new RuntimeException("Can't register driver");
}
}
@Override
public Connection connect(String url, Properties info) throws SQLException {
return new MyConnection(DriverManager.getConnection(url, info));
}
@Override
public boolean acceptsURL(String url) throws SQLException {
Enumeration<Driver> registeredDrivers = DriverManager.getDrivers();
while (registeredDrivers.hasMoreElements()) {
Driver driver = registeredDrivers.nextElement();
if(driver instanceof MyDriver){
continue;
}
if(driver.acceptsURL(url)){
return true;
}
}
return false;
}
@Override
public DriverPropertyInfo[] getPropertyInfo(String url, Properties info){
return new DriverPropertyInfo[0];
}
@Override
public int getMajorVersion() {
return DRIVER_VERSION_MAJOR;
}
@Override
public int getMinorVersion() {
return DRIVER_VERSION_MINOR;
}
@Override
public boolean jdbcCompliant() {
return false;
}
@Override
public Logger getParentLogger(){
return null;
}
}

973
agent/src/main/java/com/fanruan/jdbc/resultset/MyResultSet.java

@ -0,0 +1,973 @@
package com.fanruan.jdbc.resultset;
import java.io.InputStream;
import java.io.Reader;
import java.math.BigDecimal;
import java.net.URL;
import java.sql.*;
import java.util.Calendar;
import java.util.Map;
public class MyResultSet implements ResultSet {
final private ResultSet resultSet;
public MyResultSet(ResultSet resultSet){
this.resultSet = resultSet;
}
@Override
public boolean next() throws SQLException {
return resultSet.next();
}
@Override
public void close() throws SQLException {
resultSet.close();
}
@Override
public boolean wasNull() throws SQLException {
return resultSet.wasNull();
}
@Override
public String getString(int columnIndex) throws SQLException {
return resultSet.getString(columnIndex);
}
@Override
public boolean getBoolean(int columnIndex) throws SQLException {
return resultSet.getBoolean(columnIndex);
}
@Override
public byte getByte(int columnIndex) throws SQLException {
return resultSet.getByte(columnIndex);
}
@Override
public short getShort(int columnIndex) throws SQLException {
return resultSet.getShort(columnIndex);
}
@Override
public int getInt(int columnIndex) throws SQLException {
return resultSet.getInt(columnIndex);
}
@Override
public long getLong(int columnIndex) throws SQLException {
return resultSet.getLong(columnIndex);
}
@Override
public float getFloat(int columnIndex) throws SQLException {
return resultSet.getFloat(columnIndex);
}
@Override
public double getDouble(int columnIndex) throws SQLException {
return resultSet.getDouble(columnIndex);
}
@Override
public BigDecimal getBigDecimal(int columnIndex, int scale) throws SQLException {
return resultSet.getBigDecimal(columnIndex, scale);
}
@Override
public byte[] getBytes(int columnIndex) throws SQLException {
return resultSet.getBytes(columnIndex);
}
@Override
public Date getDate(int columnIndex) throws SQLException {
return resultSet.getDate(columnIndex);
}
@Override
public Time getTime(int columnIndex) throws SQLException {
return resultSet.getTime(columnIndex);
}
@Override
public Timestamp getTimestamp(int columnIndex) throws SQLException {
return resultSet.getTimestamp(columnIndex);
}
@Override
public InputStream getAsciiStream(int columnIndex) throws SQLException {
return resultSet.getAsciiStream(columnIndex);
}
@Override
public InputStream getUnicodeStream(int columnIndex) throws SQLException {
return resultSet.getUnicodeStream(columnIndex);
}
@Override
public InputStream getBinaryStream(int columnIndex) throws SQLException {
return resultSet.getBinaryStream(columnIndex);
}
@Override
public String getString(String columnLabel) throws SQLException {
return resultSet.getString(columnLabel);
}
@Override
public boolean getBoolean(String columnLabel) throws SQLException {
return resultSet.getBoolean(columnLabel);
}
@Override
public byte getByte(String columnLabel) throws SQLException {
return resultSet.getByte(columnLabel);
}
@Override
public short getShort(String columnLabel) throws SQLException {
return resultSet.getShort(columnLabel);
}
@Override
public int getInt(String columnLabel) throws SQLException {
return resultSet.getInt(columnLabel);
}
@Override
public long getLong(String columnLabel) throws SQLException {
return resultSet.getLong(columnLabel);
}
@Override
public float getFloat(String columnLabel) throws SQLException {
return resultSet.getFloat(columnLabel);
}
@Override
public double getDouble(String columnLabel) throws SQLException {
return resultSet.getDouble(columnLabel);
}
@Override
public BigDecimal getBigDecimal(String columnLabel, int scale) throws SQLException {
return resultSet.getBigDecimal(columnLabel, scale);
}
@Override
public byte[] getBytes(String columnLabel) throws SQLException {
return resultSet.getBytes(columnLabel);
}
@Override
public Date getDate(String columnLabel) throws SQLException {
return resultSet.getDate(columnLabel);
}
@Override
public Time getTime(String columnLabel) throws SQLException {
return resultSet.getTime(columnLabel);
}
@Override
public Timestamp getTimestamp(String columnLabel) throws SQLException {
return resultSet.getTimestamp(columnLabel);
}
@Override
public InputStream getAsciiStream(String columnLabel) throws SQLException {
return resultSet.getAsciiStream(columnLabel);
}
@Override
public InputStream getUnicodeStream(String columnLabel) throws SQLException {
return resultSet.getUnicodeStream(columnLabel);
}
@Override
public InputStream getBinaryStream(String columnLabel) throws SQLException {
return resultSet.getBinaryStream(columnLabel);
}
@Override
public SQLWarning getWarnings() throws SQLException {
return resultSet.getWarnings();
}
@Override
public void clearWarnings() throws SQLException {
resultSet.clearWarnings();
}
@Override
public String getCursorName() throws SQLException {
return resultSet.getCursorName();
}
@Override
public ResultSetMetaData getMetaData() throws SQLException {
return resultSet.getMetaData();
}
@Override
public Object getObject(int columnIndex) throws SQLException {
return resultSet.getObject(columnIndex);
}
@Override
public Object getObject(String columnLabel) throws SQLException {
return resultSet.getObject(columnLabel);
}
@Override
public int findColumn(String columnLabel) throws SQLException {
return resultSet.findColumn(columnLabel);
}
@Override
public Reader getCharacterStream(int columnIndex) throws SQLException {
return resultSet.getCharacterStream(columnIndex);
}
@Override
public Reader getCharacterStream(String columnLabel) throws SQLException {
return resultSet.getCharacterStream(columnLabel);
}
@Override
public BigDecimal getBigDecimal(int columnIndex) throws SQLException {
return resultSet.getBigDecimal(columnIndex);
}
@Override
public BigDecimal getBigDecimal(String columnLabel) throws SQLException {
return resultSet.getBigDecimal(columnLabel);
}
@Override
public boolean isBeforeFirst() throws SQLException {
return resultSet.isBeforeFirst();
}
@Override
public boolean isAfterLast() throws SQLException {
return resultSet.isAfterLast();
}
@Override
public boolean isFirst() throws SQLException {
return resultSet.isFirst();
}
@Override
public boolean isLast() throws SQLException {
return resultSet.isLast();
}
@Override
public void beforeFirst() throws SQLException {
resultSet.beforeFirst();
}
@Override
public void afterLast() throws SQLException {
resultSet.afterLast();
}
@Override
public boolean first() throws SQLException {
return resultSet.first();
}
@Override
public boolean last() throws SQLException {
return resultSet.last();
}
@Override
public int getRow() throws SQLException {
return resultSet.getRow();
}
@Override
public boolean absolute(int row) throws SQLException {
return resultSet.absolute(row);
}
@Override
public boolean relative(int rows) throws SQLException {
return resultSet.relative(rows);
}
@Override
public boolean previous() throws SQLException {
return resultSet.previous();
}
@Override
public void setFetchDirection(int direction) throws SQLException {
resultSet.setFetchDirection(direction);
}
@Override
public int getFetchDirection() throws SQLException {
return resultSet.getFetchDirection();
}
@Override
public void setFetchSize(int rows) throws SQLException {
resultSet.setFetchSize(rows);
}
@Override
public int getFetchSize() throws SQLException {
return resultSet.getFetchSize();
}
@Override
public int getType() throws SQLException {
return resultSet.getType();
}
@Override
public int getConcurrency() throws SQLException {
return resultSet.getConcurrency();
}
@Override
public boolean rowUpdated() throws SQLException {
return resultSet.rowUpdated();
}
@Override
public boolean rowInserted() throws SQLException {
return resultSet.rowInserted();
}
@Override
public boolean rowDeleted() throws SQLException {
return resultSet.rowDeleted();
}
@Override
public void updateNull(int columnIndex) throws SQLException {
resultSet.updateNull(columnIndex);
}
@Override
public void updateBoolean(int columnIndex, boolean x) throws SQLException {
resultSet.updateBoolean(columnIndex, x);
}
@Override
public void updateByte(int columnIndex, byte x) throws SQLException {
resultSet.updateByte(columnIndex, x);
}
@Override
public void updateShort(int columnIndex, short x) throws SQLException {
resultSet.updateShort(columnIndex, x);
}
@Override
public void updateInt(int columnIndex, int x) throws SQLException {
resultSet.updateInt(columnIndex, x);
}
@Override
public void updateLong(int columnIndex, long x) throws SQLException {
resultSet.updateLong(columnIndex, x);
}
@Override
public void updateFloat(int columnIndex, float x) throws SQLException {
resultSet.updateFloat(columnIndex, x);
}
@Override
public void updateDouble(int columnIndex, double x) throws SQLException {
resultSet.updateDouble(columnIndex, x);
}
@Override
public void updateBigDecimal(int columnIndex, BigDecimal x) throws SQLException {
resultSet.updateBigDecimal(columnIndex, x);
}
@Override
public void updateString(int columnIndex, String x) throws SQLException {
resultSet.updateString(columnIndex, x);
}
@Override
public void updateBytes(int columnIndex, byte[] x) throws SQLException {
resultSet.updateBytes(columnIndex, x);
}
@Override
public void updateDate(int columnIndex, Date x) throws SQLException {
resultSet.updateDate(columnIndex, x);
}
@Override
public void updateTime(int columnIndex, Time x) throws SQLException {
resultSet.updateTime(columnIndex, x);
}
@Override
public void updateTimestamp(int columnIndex, Timestamp x) throws SQLException {
resultSet.updateTimestamp(columnIndex, x);
}
@Override
public void updateAsciiStream(int columnIndex, InputStream x, int length) throws SQLException {
resultSet.updateAsciiStream(columnIndex, x, length);
}
@Override
public void updateBinaryStream(int columnIndex, InputStream x, int length) throws SQLException {
resultSet.updateBinaryStream(columnIndex, x, length);
}
@Override
public void updateCharacterStream(int columnIndex, Reader x, int length) throws SQLException {
resultSet.updateCharacterStream(columnIndex, x, length);
}
@Override
public void updateObject(int columnIndex, Object x, int scaleOrLength) throws SQLException {
resultSet.updateObject(columnIndex, x, scaleOrLength);
}
@Override
public void updateObject(int columnIndex, Object x) throws SQLException {
resultSet.updateObject(columnIndex, x);
}
@Override
public void updateNull(String columnLabel) throws SQLException {
resultSet.updateNull(columnLabel);
}
@Override
public void updateBoolean(String columnLabel, boolean x) throws SQLException {
resultSet.updateBoolean(columnLabel, x);
}
@Override
public void updateByte(String columnLabel, byte x) throws SQLException {
resultSet.updateByte(columnLabel, x);
}
@Override
public void updateShort(String columnLabel, short x) throws SQLException {
resultSet.updateShort(columnLabel, x);
}
@Override
public void updateInt(String columnLabel, int x) throws SQLException {
resultSet.updateInt(columnLabel, x);
}
@Override
public void updateLong(String columnLabel, long x) throws SQLException {
resultSet.updateLong(columnLabel, x);
}
@Override
public void updateFloat(String columnLabel, float x) throws SQLException {
resultSet.updateFloat(columnLabel, x);
}
@Override
public void updateDouble(String columnLabel, double x) throws SQLException {
resultSet.updateDouble(columnLabel, x);
}
@Override
public void updateBigDecimal(String columnLabel, BigDecimal x) throws SQLException {
resultSet.updateBigDecimal(columnLabel, x);
}
@Override
public void updateString(String columnLabel, String x) throws SQLException {
resultSet.updateString(columnLabel, x);
}
@Override
public void updateBytes(String columnLabel, byte[] x) throws SQLException {
resultSet.updateBytes(columnLabel, x);
}
@Override
public void updateDate(String columnLabel, Date x) throws SQLException {
resultSet.updateDate(columnLabel, x);
}
@Override
public void updateTime(String columnLabel, Time x) throws SQLException {
resultSet.updateTime(columnLabel, x);
}
@Override
public void updateTimestamp(String columnLabel, Timestamp x) throws SQLException {
resultSet.updateTimestamp(columnLabel, x);
}
@Override
public void updateAsciiStream(String columnLabel, InputStream x, int length) throws SQLException {
resultSet.updateAsciiStream(columnLabel, x, length);
}
@Override
public void updateBinaryStream(String columnLabel, InputStream x, int length) throws SQLException {
resultSet.updateBinaryStream(columnLabel, x, length);
}
@Override
public void updateCharacterStream(String columnLabel, Reader reader, int length) throws SQLException {
resultSet.updateCharacterStream(columnLabel, reader, length);
}
@Override
public void updateObject(String columnLabel, Object x, int scaleOrLength) throws SQLException {
resultSet.updateObject(columnLabel, x, scaleOrLength);
}
@Override
public void updateObject(String columnLabel, Object x) throws SQLException {
resultSet.updateObject(columnLabel, x);
}
@Override
public void insertRow() throws SQLException {
resultSet.insertRow();
}
@Override
public void updateRow() throws SQLException {
resultSet.updateRow();
}
@Override
public void deleteRow() throws SQLException {
resultSet.deleteRow();
}
@Override
public void refreshRow() throws SQLException {
resultSet.refreshRow();
}
@Override
public void cancelRowUpdates() throws SQLException {
resultSet.cancelRowUpdates();
}
@Override
public void moveToInsertRow() throws SQLException {
resultSet.moveToInsertRow();
}
@Override
public void moveToCurrentRow() throws SQLException {
resultSet.moveToCurrentRow();
}
@Override
public Statement getStatement() throws SQLException {
return resultSet.getStatement();
}
@Override
public Object getObject(int columnIndex, Map<String, Class<?>> map) throws SQLException {
return resultSet.getObject(columnIndex, map);
}
@Override
public Ref getRef(int columnIndex) throws SQLException {
return resultSet.getRef(columnIndex);
}
@Override
public Blob getBlob(int columnIndex) throws SQLException {
return resultSet.getBlob(columnIndex);
}
@Override
public Clob getClob(int columnIndex) throws SQLException {
return resultSet.getClob(columnIndex);
}
@Override
public Array getArray(int columnIndex) throws SQLException {
return resultSet.getArray(columnIndex);
}
@Override
public Object getObject(String columnLabel, Map<String, Class<?>> map) throws SQLException {
return resultSet.getObject(columnLabel, map);
}
@Override
public Ref getRef(String columnLabel) throws SQLException {
return resultSet.getRef(columnLabel);
}
@Override
public Blob getBlob(String columnLabel) throws SQLException {
return resultSet.getBlob(columnLabel);
}
@Override
public Clob getClob(String columnLabel) throws SQLException {
return resultSet.getClob(columnLabel);
}
@Override
public Array getArray(String columnLabel) throws SQLException {
return resultSet.getArray(columnLabel);
}
@Override
public Date getDate(int columnIndex, Calendar cal) throws SQLException {
return resultSet.getDate(columnIndex, cal);
}
@Override
public Date getDate(String columnLabel, Calendar cal) throws SQLException {
return resultSet.getDate(columnLabel, cal);
}
@Override
public Time getTime(int columnIndex, Calendar cal) throws SQLException {
return resultSet.getTime(columnIndex, cal);
}
@Override
public Time getTime(String columnLabel, Calendar cal) throws SQLException {
return resultSet.getTime(columnLabel, cal);
}
@Override
public Timestamp getTimestamp(int columnIndex, Calendar cal) throws SQLException {
return resultSet.getTimestamp(columnIndex, cal);
}
@Override
public Timestamp getTimestamp(String columnLabel, Calendar cal) throws SQLException {
return resultSet.getTimestamp(columnLabel, cal);
}
@Override
public URL getURL(int columnIndex) throws SQLException {
return resultSet.getURL(columnIndex);
}
@Override
public URL getURL(String columnLabel) throws SQLException {
return resultSet.getURL(columnLabel);
}
@Override
public void updateRef(int columnIndex, Ref x) throws SQLException {
resultSet.updateRef(columnIndex, x);
}
@Override
public void updateRef(String columnLabel, Ref x) throws SQLException {
resultSet.updateRef(columnLabel, x);
}
@Override
public void updateBlob(int columnIndex, Blob x) throws SQLException {
resultSet.updateBlob(columnIndex, x);
}
@Override
public void updateBlob(String columnLabel, Blob x) throws SQLException {
resultSet.updateBlob(columnLabel, x);
}
@Override
public void updateClob(int columnIndex, Clob x) throws SQLException {
resultSet.updateClob(columnIndex, x);
}
@Override
public void updateClob(String columnLabel, Clob x) throws SQLException {
resultSet.updateClob(columnLabel, x);
}
@Override
public void updateArray(int columnIndex, Array x) throws SQLException {
resultSet.updateArray(columnIndex, x);
}
@Override
public void updateArray(String columnLabel, Array x) throws SQLException {
resultSet.updateArray(columnLabel, x);
}
@Override
public RowId getRowId(int columnIndex) throws SQLException {
return resultSet.getRowId(columnIndex);
}
@Override
public RowId getRowId(String columnLabel) throws SQLException {
return resultSet.getRowId(columnLabel);
}
@Override
public void updateRowId(int columnIndex, RowId x) throws SQLException {
resultSet.updateRowId(columnIndex, x);
}
@Override
public void updateRowId(String columnLabel, RowId x) throws SQLException {
resultSet.updateRowId(columnLabel, x);
}
@Override
public int getHoldability() throws SQLException {
return resultSet.getHoldability();
}
@Override
public boolean isClosed() throws SQLException {
return resultSet.isClosed();
}
@Override
public void updateNString(int columnIndex, String nString) throws SQLException {
resultSet.updateNString(columnIndex, nString);
}
@Override
public void updateNString(String columnLabel, String nString) throws SQLException {
resultSet.updateNString(columnLabel, nString);
}
@Override
public void updateNClob(int columnIndex, NClob nClob) throws SQLException {
resultSet.updateNClob(columnIndex, nClob);
}
@Override
public void updateNClob(String columnLabel, NClob nClob) throws SQLException {
resultSet.updateNClob(columnLabel, nClob);
}
@Override
public NClob getNClob(int columnIndex) throws SQLException {
return resultSet.getNClob(columnIndex);
}
@Override
public NClob getNClob(String columnLabel) throws SQLException {
return resultSet.getNClob(columnLabel);
}
@Override
public SQLXML getSQLXML(int columnIndex) throws SQLException {
return resultSet.getSQLXML(columnIndex);
}
@Override
public SQLXML getSQLXML(String columnLabel) throws SQLException {
return resultSet.getSQLXML(columnLabel);
}
@Override
public void updateSQLXML(int columnIndex, SQLXML xmlObject) throws SQLException {
resultSet.updateSQLXML(columnIndex, xmlObject);
}
@Override
public void updateSQLXML(String columnLabel, SQLXML xmlObject) throws SQLException {
resultSet.updateSQLXML(columnLabel, xmlObject);
}
@Override
public String getNString(int columnIndex) throws SQLException {
return resultSet.getNString(columnIndex);
}
@Override
public String getNString(String columnLabel) throws SQLException {
return resultSet.getNString(columnLabel);
}
@Override
public Reader getNCharacterStream(int columnIndex) throws SQLException {
return resultSet.getNCharacterStream(columnIndex);
}
@Override
public Reader getNCharacterStream(String columnLabel) throws SQLException {
return resultSet.getNCharacterStream(columnLabel);
}
@Override
public void updateNCharacterStream(int columnIndex, Reader x, long length) throws SQLException {
resultSet.updateNCharacterStream(columnIndex, x, length);
}
@Override
public void updateNCharacterStream(String columnLabel, Reader reader, long length) throws SQLException {
resultSet.updateNCharacterStream(columnLabel, reader, length);
}
@Override
public void updateAsciiStream(int columnIndex, InputStream x, long length) throws SQLException {
resultSet.updateAsciiStream(columnIndex, x, length);
}
@Override
public void updateBinaryStream(int columnIndex, InputStream x, long length) throws SQLException {
resultSet.updateBinaryStream(columnIndex, x, length);
}
@Override
public void updateCharacterStream(int columnIndex, Reader x, long length) throws SQLException {
resultSet.updateCharacterStream(columnIndex, x, length);
}
@Override
public void updateAsciiStream(String columnLabel, InputStream x, long length) throws SQLException {
resultSet.updateAsciiStream(columnLabel, x, length);
}
@Override
public void updateBinaryStream(String columnLabel, InputStream x, long length) throws SQLException {
resultSet.updateBinaryStream(columnLabel, x, length);
}
@Override
public void updateCharacterStream(String columnLabel, Reader reader, long length) throws SQLException {
resultSet.updateCharacterStream(columnLabel, reader, length);
}
@Override
public void updateBlob(int columnIndex, InputStream inputStream, long length) throws SQLException {
resultSet.updateBlob(columnIndex, inputStream, length);
}
@Override
public void updateBlob(String columnLabel, InputStream inputStream, long length) throws SQLException {
resultSet.updateBlob(columnLabel, inputStream, length);
}
@Override
public void updateClob(int columnIndex, Reader reader, long length) throws SQLException {
resultSet.updateClob(columnIndex, reader, length);
}
@Override
public void updateClob(String columnLabel, Reader reader, long length) throws SQLException {
resultSet.updateClob(columnLabel, reader, length);
}
@Override
public void updateNClob(int columnIndex, Reader reader, long length) throws SQLException {
resultSet.updateNClob(columnIndex, reader, length);
}
@Override
public void updateNClob(String columnLabel, Reader reader, long length) throws SQLException {
resultSet.updateNClob(columnLabel, reader, length);
}
@Override
public void updateNCharacterStream(int columnIndex, Reader x) throws SQLException {
resultSet.updateNCharacterStream(columnIndex, x);
}
@Override
public void updateNCharacterStream(String columnLabel, Reader reader) throws SQLException {
resultSet.updateNCharacterStream(columnLabel, reader);
}
@Override
public void updateAsciiStream(int columnIndex, InputStream x) throws SQLException {
resultSet.updateAsciiStream(columnIndex, x);
}
@Override
public void updateBinaryStream(int columnIndex, InputStream x) throws SQLException {
resultSet.updateBinaryStream(columnIndex, x);
}
@Override
public void updateCharacterStream(int columnIndex, Reader x) throws SQLException {
resultSet.updateCharacterStream(columnIndex, x);
}
@Override
public void updateAsciiStream(String columnLabel, InputStream x) throws SQLException {
resultSet.updateAsciiStream(columnLabel, x);
}
@Override
public void updateBinaryStream(String columnLabel, InputStream x) throws SQLException {
resultSet.updateBinaryStream(columnLabel, x);
}
@Override
public void updateCharacterStream(String columnLabel, Reader reader) throws SQLException {
resultSet.updateCharacterStream(columnLabel, reader);
}
@Override
public void updateBlob(int columnIndex, InputStream inputStream) throws SQLException {
resultSet.updateBlob(columnIndex, inputStream);
}
@Override
public void updateBlob(String columnLabel, InputStream inputStream) throws SQLException {
resultSet.updateBlob(columnLabel, inputStream);
}
@Override
public void updateClob(int columnIndex, Reader reader) throws SQLException {
resultSet.updateClob(columnIndex, reader);
}
@Override
public void updateClob(String columnLabel, Reader reader) throws SQLException {
resultSet.updateClob(columnLabel, reader);
}
@Override
public void updateNClob(int columnIndex, Reader reader) throws SQLException {
resultSet.updateNClob(columnIndex, reader);
}
@Override
public void updateNClob(String columnLabel, Reader reader) throws SQLException {
resultSet.updateNClob(columnLabel, reader);
}
@Override
public <T> T getObject(int columnIndex, Class<T> type) throws SQLException {
return resultSet.getObject(columnIndex, type);
}
@Override
public <T> T getObject(String columnLabel, Class<T> type) throws SQLException {
return resultSet.getObject(columnLabel, type);
}
@Override
public <T> T unwrap(Class<T> iface) throws SQLException {
return resultSet.unwrap(iface);
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
return resultSet.isWrapperFor(iface);
}
}

517
agent/src/main/java/com/fanruan/jdbc/statement/MyPreparedStatement.java

@ -0,0 +1,517 @@
package com.fanruan.jdbc.statement;
import com.fanruan.jdbc.resultset.MyResultSet;
import java.io.InputStream;
import java.io.Reader;
import java.math.BigDecimal;
import java.net.URL;
import java.sql.*;
import java.util.Calendar;
/**
* @author Yichen Dai
*/
public class MyPreparedStatement implements PreparedStatement {
final PreparedStatement pst;
public MyPreparedStatement(PreparedStatement pst) {
this.pst = pst;
}
@Override
public ResultSet executeQuery() throws SQLException {
return new MyResultSet(pst.executeQuery());
}
@Override
public int executeUpdate() throws SQLException {
return pst.executeUpdate();
}
@Override
public void setNull(int parameterIndex, int sqlType) throws SQLException {
pst.setNull(parameterIndex, sqlType);
}
@Override
public void setBoolean(int parameterIndex, boolean x) throws SQLException {
pst.setBoolean(parameterIndex, x);
}
@Override
public void setByte(int parameterIndex, byte x) throws SQLException {
pst.setByte(parameterIndex, x);
}
@Override
public void setShort(int parameterIndex, short x) throws SQLException {
pst.setShort(parameterIndex, x);
}
@Override
public void setInt(int parameterIndex, int x) throws SQLException {
pst.setInt(parameterIndex, x);
}
@Override
public void setLong(int parameterIndex, long x) throws SQLException {
pst.setLong(parameterIndex, x);
}
@Override
public void setFloat(int parameterIndex, float x) throws SQLException {
pst.setFloat(parameterIndex, x);
}
@Override
public void setDouble(int parameterIndex, double x) throws SQLException {
pst.setDouble(parameterIndex, x);
}
@Override
public void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException {
pst.setBigDecimal(parameterIndex, x);
}
@Override
public void setString(int parameterIndex, String x) throws SQLException {
pst.setString(parameterIndex, x);
}
@Override
public void setBytes(int parameterIndex, byte[] x) throws SQLException {
pst.setBytes(parameterIndex, x);
}
@Override
public void setDate(int parameterIndex, Date x) throws SQLException {
pst.setDate(parameterIndex, x);
}
@Override
public void setTime(int parameterIndex, Time x) throws SQLException {
pst.setTime(parameterIndex, x);
}
@Override
public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException {
pst.setTimestamp(parameterIndex, x);
}
@Override
public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException {
pst.setAsciiStream(parameterIndex, x, length);
}
@Override
public void setUnicodeStream(int parameterIndex, InputStream x, int length) throws SQLException {
}
@Override
public void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException {
pst.setBinaryStream(parameterIndex, x, length);
}
@Override
public void clearParameters() throws SQLException {
pst.clearParameters();
}
@Override
public void setObject(int parameterIndex, Object x, int targetSqlType) throws SQLException {
pst.setObject(parameterIndex, x, targetSqlType);
}
@Override
public void setObject(int parameterIndex, Object x) throws SQLException {
pst.setObject(parameterIndex, x);
}
@Override
public boolean execute() throws SQLException {
return pst.execute();
}
@Override
public void addBatch() throws SQLException {
pst.addBatch();
}
@Override
public void setCharacterStream(int parameterIndex, Reader reader, int length) throws SQLException {
pst.setCharacterStream(parameterIndex, reader, length);
}
@Override
public void setRef(int parameterIndex, Ref x) throws SQLException {
pst.setRef(parameterIndex, x);
}
@Override
public void setBlob(int parameterIndex, Blob x) throws SQLException {
pst.setBlob(parameterIndex, x);
}
@Override
public void setClob(int parameterIndex, Clob x) throws SQLException {
pst.setClob(parameterIndex, x);
}
@Override
public void setArray(int parameterIndex, Array x) throws SQLException {
pst.setArray(parameterIndex, x);
}
@Override
public ResultSetMetaData getMetaData() throws SQLException {
return pst.getMetaData();
}
@Override
public void setDate(int parameterIndex, Date x, Calendar cal) throws SQLException {
pst.setDate(parameterIndex, x, cal);
}
@Override
public void setTime(int parameterIndex, Time x, Calendar cal) throws SQLException {
pst.setTime(parameterIndex, x, cal);
}
@Override
public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) throws SQLException {
pst.setTimestamp(parameterIndex, x, cal);
}
@Override
public void setNull(int parameterIndex, int sqlType, String typeName) throws SQLException {
pst.setNull(parameterIndex, sqlType, typeName);
}
@Override
public void setURL(int parameterIndex, URL x) throws SQLException {
pst.setURL(parameterIndex, x);
}
@Override
public ParameterMetaData getParameterMetaData() throws SQLException {
return pst.getParameterMetaData();
}
@Override
public void setRowId(int parameterIndex, RowId x) throws SQLException {
pst.setRowId(parameterIndex, x);
}
@Override
public void setNString(int parameterIndex, String value) throws SQLException {
pst.setNString(parameterIndex, value);
}
@Override
public void setNCharacterStream(int parameterIndex, Reader value, long length) throws SQLException {
pst.setNCharacterStream(parameterIndex, value, length);
}
@Override
public void setNClob(int parameterIndex, NClob value) throws SQLException {
pst.setNClob(parameterIndex, value);
}
@Override
public void setClob(int parameterIndex, Reader reader, long length) throws SQLException {
pst.setClob(parameterIndex, reader, length);
}
@Override
public void setBlob(int parameterIndex, InputStream inputStream, long length) throws SQLException {
pst.setBlob(parameterIndex, inputStream, length);
}
@Override
public void setNClob(int parameterIndex, Reader reader, long length) throws SQLException {
pst.setNClob(parameterIndex, reader, length);
}
@Override
public void setSQLXML(int parameterIndex, SQLXML xmlObject) throws SQLException {
pst.setSQLXML(parameterIndex, xmlObject);
}
@Override
public void setObject(int parameterIndex, Object x, int targetSqlType, int scaleOrLength) throws SQLException {
pst.setObject(parameterIndex, x, targetSqlType, scaleOrLength);
}
@Override
public void setAsciiStream(int parameterIndex, InputStream x, long length) throws SQLException {
pst.setAsciiStream(parameterIndex, x, length);
}
@Override
public void setBinaryStream(int parameterIndex, InputStream x, long length) throws SQLException {
pst.setBinaryStream(parameterIndex, x, length);
}
@Override
public void setCharacterStream(int parameterIndex, Reader reader, long length) throws SQLException {
pst.setCharacterStream(parameterIndex, reader, length);
}
@Override
public void setAsciiStream(int parameterIndex, InputStream x) throws SQLException {
pst.setAsciiStream(parameterIndex, x);
}
@Override
public void setBinaryStream(int parameterIndex, InputStream x) throws SQLException {
pst.setBinaryStream(parameterIndex, x);
}
@Override
public void setCharacterStream(int parameterIndex, Reader reader) throws SQLException {
pst.setCharacterStream(parameterIndex, reader);
}
@Override
public void setNCharacterStream(int parameterIndex, Reader value) throws SQLException {
pst.setNCharacterStream(parameterIndex, value);
}
@Override
public void setClob(int parameterIndex, Reader reader) throws SQLException {
pst.setClob(parameterIndex, reader);
}
@Override
public void setBlob(int parameterIndex, InputStream inputStream) throws SQLException {
pst.setBlob(parameterIndex, inputStream);
}
@Override
public void setNClob(int parameterIndex, Reader reader) throws SQLException {
pst.setNClob(parameterIndex, reader);
}
@Override
public ResultSet executeQuery(String sql) throws SQLException {
return pst.executeQuery(sql);
}
@Override
public int executeUpdate(String sql) throws SQLException {
return pst.executeUpdate(sql);
}
@Override
public void close() throws SQLException {
pst.close();
}
@Override
public int getMaxFieldSize() throws SQLException {
return pst.getMaxFieldSize();
}
@Override
public void setMaxFieldSize(int max) throws SQLException {
pst.setMaxFieldSize(max);
}
@Override
public int getMaxRows() throws SQLException {
return pst.getMaxRows();
}
@Override
public void setMaxRows(int max) throws SQLException {
pst.setMaxRows(max);
}
@Override
public void setEscapeProcessing(boolean enable) throws SQLException {
pst.setEscapeProcessing(enable);
}
@Override
public int getQueryTimeout() throws SQLException {
return pst.getQueryTimeout();
}
@Override
public void setQueryTimeout(int seconds) throws SQLException {
pst.setQueryTimeout(seconds);
}
@Override
public void cancel() throws SQLException {
pst.cancel();
}
@Override
public SQLWarning getWarnings() throws SQLException {
return pst.getWarnings();
}
@Override
public void clearWarnings() throws SQLException {
pst.clearWarnings();
}
@Override
public void setCursorName(String name) throws SQLException {
pst.setCursorName(name);
}
@Override
public boolean execute(String sql) throws SQLException {
return pst.execute(sql);
}
@Override
public ResultSet getResultSet() throws SQLException {
return pst.getResultSet();
}
@Override
public int getUpdateCount() throws SQLException {
return pst.getUpdateCount();
}
@Override
public boolean getMoreResults() throws SQLException {
return pst.getMoreResults();
}
@Override
public void setFetchDirection(int direction) throws SQLException {
pst.setFetchDirection(direction);
}
@Override
public int getFetchDirection() throws SQLException {
return pst.getFetchDirection();
}
@Override
public void setFetchSize(int rows) throws SQLException {
pst.setFetchSize(rows);
}
@Override
public int getFetchSize() throws SQLException {
return pst.getFetchSize();
}
@Override
public int getResultSetConcurrency() throws SQLException {
return pst.getResultSetConcurrency();
}
@Override
public int getResultSetType() throws SQLException {
return pst.getResultSetType();
}
@Override
public void addBatch(String sql) throws SQLException {
pst.addBatch(sql);
}
@Override
public void clearBatch() throws SQLException {
pst.clearBatch();
}
@Override
public int[] executeBatch() throws SQLException {
return pst.executeBatch();
}
@Override
public Connection getConnection() throws SQLException {
return pst.getConnection();
}
@Override
public boolean getMoreResults(int current) throws SQLException {
return pst.getMoreResults(current);
}
@Override
public ResultSet getGeneratedKeys() throws SQLException {
return pst.getGeneratedKeys();
}
@Override
public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException {
return pst.executeUpdate(sql, autoGeneratedKeys);
}
@Override
public int executeUpdate(String sql, int[] columnIndexes) throws SQLException {
return pst.executeUpdate(sql, columnIndexes);
}
@Override
public int executeUpdate(String sql, String[] columnNames) throws SQLException {
return pst.executeUpdate(sql, columnNames);
}
@Override
public boolean execute(String sql, int autoGeneratedKeys) throws SQLException {
return pst.execute(sql, autoGeneratedKeys);
}
@Override
public boolean execute(String sql, int[] columnIndexes) throws SQLException {
return pst.execute(sql, columnIndexes);
}
@Override
public boolean execute(String sql, String[] columnNames) throws SQLException {
return pst.execute(sql, columnNames);
}
@Override
public int getResultSetHoldability() throws SQLException {
return pst.getResultSetHoldability();
}
@Override
public boolean isClosed() throws SQLException {
return pst.isClosed();
}
@Override
public void setPoolable(boolean poolable) throws SQLException {
pst.setPoolable(poolable);
}
@Override
public boolean isPoolable() throws SQLException {
return pst.isPoolable();
}
@Override
public void closeOnCompletion() throws SQLException {
pst.closeOnCompletion();
}
@Override
public boolean isCloseOnCompletion() throws SQLException {
return pst.isCloseOnCompletion();
}
@Override
public <T> T unwrap(Class<T> iface) throws SQLException {
return pst.unwrap(iface);
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
return pst.isWrapperFor(iface);
}
}

237
agent/src/main/java/com/fanruan/jdbc/statement/MyStatement.java

@ -0,0 +1,237 @@
package com.fanruan.jdbc.statement;
import com.fanruan.jdbc.resultset.MyResultSet;
import java.sql.*;
public class MyStatement implements Statement {
final private Statement st;
public MyStatement(Statement statement) {
this.st = statement;
}
//使用与 Service 同名的类保证数据库对应的 JDBC
@Override
public ResultSet executeQuery(String sql) throws SQLException {
return new MyResultSet(st.executeQuery(sql));
}
@Override
public int executeUpdate(String sql) throws SQLException {
return st.executeUpdate(sql);
}
@Override
public void close() throws SQLException {
st.close();
}
@Override
public int getMaxFieldSize() throws SQLException {
return st.getMaxFieldSize();
}
@Override
public void setMaxFieldSize(int max) throws SQLException {
st.setMaxFieldSize(max);
}
@Override
public int getMaxRows() throws SQLException {
return st.getMaxRows();
}
@Override
public void setMaxRows(int max) throws SQLException {
st.setMaxRows(max);
}
@Override
public void setEscapeProcessing(boolean enable) throws SQLException {
st.setEscapeProcessing(enable);
}
@Override
public int getQueryTimeout() throws SQLException {
return st.getQueryTimeout();
}
@Override
public void setQueryTimeout(int seconds) throws SQLException {
st.setQueryTimeout(seconds);
}
@Override
public void cancel() throws SQLException {
st.cancel();
}
@Override
public SQLWarning getWarnings() throws SQLException {
return st.getWarnings();
}
@Override
public void clearWarnings() throws SQLException {
st.clearWarnings();
}
@Override
public void setCursorName(String name) throws SQLException {
st.setCursorName(name);
}
@Override
public boolean execute(String sql) throws SQLException {
return st.execute(sql);
}
@Override
public ResultSet getResultSet() throws SQLException {
return st.getResultSet();
}
@Override
public int getUpdateCount() throws SQLException {
return st.getUpdateCount();
}
@Override
public boolean getMoreResults() throws SQLException {
return st.getMoreResults();
}
@Override
public void setFetchDirection(int direction) throws SQLException {
st.setFetchDirection(direction);
}
@Override
public int getFetchDirection() throws SQLException {
return st.getFetchDirection();
}
@Override
public void setFetchSize(int rows) throws SQLException {
st.setFetchSize(rows);
}
@Override
public int getFetchSize() throws SQLException {
return st.getFetchSize();
}
@Override
public int getResultSetConcurrency() throws SQLException {
return st.getResultSetConcurrency();
}
@Override
public int getResultSetType() throws SQLException {
return st.getResultSetType();
}
@Override
public void addBatch(String sql) throws SQLException {
st.addBatch(sql);
}
@Override
public void clearBatch() throws SQLException {
st.clearBatch();
}
@Override
public int[] executeBatch() throws SQLException {
return st.executeBatch();
}
@Override
public Connection getConnection() throws SQLException {
return st.getConnection();
}
@Override
public boolean getMoreResults(int current) throws SQLException {
return st.getMoreResults(current);
}
@Override
public ResultSet getGeneratedKeys() throws SQLException {
return st.getGeneratedKeys();
}
@Override
public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException {
return st.executeUpdate(sql, autoGeneratedKeys);
}
@Override
public int executeUpdate(String sql, int[] columnIndexes) throws SQLException {
return st.executeUpdate(sql, columnIndexes);
}
@Override
public int executeUpdate(String sql, String[] columnNames) throws SQLException {
return st.executeUpdate(sql, columnNames);
}
@Override
public boolean execute(String sql, int autoGeneratedKeys) throws SQLException {
return st.execute(sql, autoGeneratedKeys);
}
@Override
public boolean execute(String sql, int[] columnIndexes) throws SQLException {
return st.execute(sql, columnIndexes);
}
@Override
public boolean execute(String sql, String[] columnNames) throws SQLException {
return st.execute(sql, columnNames);
}
@Override
public int getResultSetHoldability() throws SQLException {
return st.getResultSetHoldability();
}
@Override
public boolean isClosed() throws SQLException {
return st.isClosed();
}
@Override
public void setPoolable(boolean poolable) throws SQLException {
st.setPoolable(poolable);
}
@Override
public boolean isPoolable() throws SQLException {
return st.isPoolable();
}
@Override
public void closeOnCompletion() throws SQLException {
st.closeOnCompletion();
}
@Override
public boolean isCloseOnCompletion() throws SQLException {
return st.isCloseOnCompletion();
}
@Override
public <T> T unwrap(Class<T> iface) throws SQLException {
return st.unwrap(iface);
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
return st.isWrapperFor(iface);
}
}

20
agent/src/main/java/com/fanruan/pojo/message/RpcRequest.java

@ -0,0 +1,20 @@
package com.fanruan.pojo.message;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* @author Yichen Dai
*/
@Data
@Accessors(chain = true)
public class RpcRequest {
private boolean reply;
private String ID;
private boolean binding;
private String IDToInvoke;
private Class<?> serviceClass;
private String methodName;
private Object[] args;
private Class<?>[] argTypes;
}

19
agent/src/main/java/com/fanruan/pojo/message/RpcResponse.java

@ -0,0 +1,19 @@
package com.fanruan.pojo.message;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* @author Yichen Dai
*/
@Data
@Accessors(chain = true)
public class RpcResponse {
private String ID;
private Object result;
private boolean binding;
private Boolean status;
}

54
agent/src/main/java/com/fanruan/serializer/KryoSerializer.java

@ -0,0 +1,54 @@
package com.fanruan.serializer;
import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import com.fanruan.pojo.message.RpcRequest;
import com.fanruan.pojo.message.RpcResponse;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
/**
* @author Yichen Dai
*/
public class KryoSerializer implements Serializer {
private static final ThreadLocal<Kryo> kryoThreadLocal = ThreadLocal.withInitial(() -> {
final Kryo kryo = new Kryo();
kryo.register(RpcRequest.class);
kryo.register(RpcResponse.class);
kryo.setReferences(true);
kryo.setRegistrationRequired(false);
return kryo;
});
@Override
public byte[] serialize(Object object) {
try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
Output output = new Output(byteArrayOutputStream)) {
final Kryo kryo = kryoThreadLocal.get();
kryo.writeObject(output, object);
kryoThreadLocal.remove();
return output.toBytes();
} catch (IOException e) {
e.printStackTrace();
}
return new byte[0];
}
@Override
public <T> T deserialize(byte[] bytes, Class<T> clazz) {
try (ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
Input input = new Input(byteArrayInputStream)) {
final Kryo kryo = kryoThreadLocal.get();
final Object o = kryo.readObject(input, clazz);
kryoThreadLocal.remove();
return clazz.cast(o);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}

22
agent/src/main/java/com/fanruan/serializer/Serializer.java

@ -0,0 +1,22 @@
package com.fanruan.serializer;
/**
* @author Yichen Dai
*/
public interface Serializer {
/**
* Use to serialize a object to a byte array
* @param object to be serialized
* @return byte[] serialized data with the format of byte array
*/
byte[] serialize(Object object);
/**
* Use to deserialize a byte array to a class with designate class
* @param bytes Serialized data with the format of byte array
* @param clazz The class of the object to be deserialized
* @return object as designate class
*/
<T> T deserialize(byte[] bytes, Class<T> clazz);
}

20
agent/src/main/java/com/fanruan/utils/DBProperties.java

@ -0,0 +1,20 @@
package com.fanruan.utils;
/**
* @author Yichen Dai
*/
public class DBProperties {
public static final String MYSQL = "mysql";
public static final String POSTGRESQL = "postgresql";
public static final String ORACLE = "oracle";
public static final String SQLSERVER = "sqlserver";
public static final String DB2 = "db2";
public static final String HSQL = "hsql";
public static final String MYSQL_DRIVER_NAME = "com.mysql.cj.jdbc.Driver";
public static final String POSTGRESQL_DRIVER_NAME = "org.postgresql.Driver";
public static final String ORACLE_DRIVER_NAME = "oracle.jdbc.driver.OracleDriver";
public static final String SQLSERVER_DRIVER_NAME = "com.microsoft.jdbc.sqlserver.SQLServerDriver";
public static final String DB2_DRIVER_NAME = "com.ibm.db2.jdbc.app.DB2Driver";
public static final String HSQL_DRIVER_NAME = "org.hsqldb.jdbcDriver";
}

10
agent/src/main/resources/log4j2.properties

@ -0,0 +1,10 @@
# Console appender configuration
appender.console.type = Console
appender.console.name = STDOUT
appender.console.layout.type = PatternLayout
appender.console.layout.pattern = [%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c{1} - %msg%n
rootLogger.level = debug
rootLogger.appenderRefs = stdout
rootLogger.appenderRef.stdout.ref = STDOUT

14
agent/src/main/resources/socket.properties

@ -0,0 +1,14 @@
# 服务器地址
uri = http://127.0.0.1:10246
# 代理编号
agentID = 1001
# 重连尝试次数
reconnectionAttempts = 1
# 重连间隔事件
reconnectionDelay = 1000
# 连接超时时间
timeout = 500

100
agent/src/test/java/HSQLTest.java

@ -0,0 +1,100 @@
import com.fanruan.utils.DBProperties;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.sql.*;
/**
* @author Yichen Dai
* @date 2022/8/17 11:25
*/
public class HSQLTest {
@BeforeEach
void startHSQL(){
try {
Class.forName(DBProperties.HSQL_DRIVER_NAME);
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
}
@Test
void getConnection() throws SQLException {
Connection conn = null;
try {
conn = DriverManager.getConnection("jdbc:hsqldb:mem:test", "sa", "");
Assertions.assertNotNull(conn, "can't get connection");
} catch (SQLException e) {
e.printStackTrace();
}finally {
conn.close();
}
}
/**
* test to create statement instance and prepareStatement, create table, select form table, delete from table
*/
@Test
void testCURD(){
Connection conn = null;
Statement st = null;
PreparedStatement pst = null;
ResultSet rs = null;
try {
conn = DriverManager.getConnection("jdbc:hsqldb:mem:test", "sa", "");
st = conn.createStatement();
st.executeUpdate("DROP TABLE student IF EXISTS;");
st.executeUpdate("CREATE TABLE student (" +
"student_id INTEGER GENERATED BY DEFAULT AS IDENTITY " +
"(START WITH 1, INCREMENT BY 1) NOT NULL," +
"student_name VARCHAR(100) NOT NULL," +
"student_address VARCHAR(100) NOT NULL," +
"PRIMARY KEY (student_id)" +
");");
st.executeUpdate("INSERT INTO student VALUES" +
"(1, '张三', '上海')," +
"(2, '李四', '北京')," +
"(3, '王五', '成都');");
pst = conn.prepareStatement("delete from student where student_id = ?");
pst.setInt(1, 1);
pst.executeUpdate();
rs = st.executeQuery("select * from student");
String[] nameStrings = new String[]{"张三", "李四", "王五"};
String[] addressStrings = new String[]{"上海", "北京", "成都"};
int num = 2;
while(rs.next()) {
Assertions.assertEquals(rs.getInt("student_id"), num);
Assertions.assertEquals(rs.getString("student_name"), nameStrings[num-1]);
Assertions.assertEquals(rs.getString("student_address"), addressStrings[num-1]);
num++;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try{
rs.close();
st.close();
pst.close();
conn.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
}

37
agent/src/test/java/Test.java

@ -0,0 +1,37 @@
import com.fanruan.AgentStarter;
import com.fanruan.utils.DBProperties;
import io.socket.client.Socket;
import java.io.IOException;
public class Test {
public static void main(String[] args){
try{
testStart();
}catch(Exception e){
e.printStackTrace();
}
}
static void testStart() throws IOException, ClassNotFoundException {
Class.forName(DBProperties.HSQL_DRIVER_NAME);
String[] DBs = new String[]{
DBProperties.HSQL,
};
new AgentStarter(DBs);
Socket mainSocket = AgentStarter.myDispatcherImpl.CACHE.getSocket("/");
mainSocket.connect();
Socket socket = AgentStarter.myDispatcherImpl.CACHE.getSocket(DBProperties.HSQL);
socket.connect();
}
}

21
pom.xml

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>intranet</artifactId>
<version>1.0-SNAPSHOT</version>
<modules>
<module>agent</module>
<module>service</module>
</modules>
<packaging>pom</packaging>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
</project>

82
service/pom.xml

@ -0,0 +1,82 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>intranet</artifactId>
<groupId>org.example</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>service</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>com.corundumstudio.socketio</groupId>
<artifactId>netty-socketio</artifactId>
<version>1.7.19</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.17.2</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.17.2</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.17.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>31.1-jre</version>
</dependency>
<!-- https://mvnrepository.com/artifact/cglib/cglib -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.esotericsoftware/kryo -->
<dependency>
<groupId>com.esotericsoftware</groupId>
<artifactId>kryo</artifactId>
<version>5.3.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.4.0</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

193
service/src/main/java/com/fanruan/ServerStater.java

@ -0,0 +1,193 @@
package com.fanruan;
import com.corundumstudio.socketio.SocketConfig;
import com.corundumstudio.socketio.SocketIONamespace;
import com.corundumstudio.socketio.SocketIOServer;
import com.corundumstudio.socketio.Transport;
import com.fanruan.cache.ClientCache;
import com.fanruan.cache.ClientWrapper;
import com.fanruan.cache.LockAndCondition;
import com.fanruan.pojo.message.RpcResponse;
import com.fanruan.serializer.KryoSerializer;
import com.fanruan.serializer.Serializer;
import com.fanruan.utils.Commons;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.Properties;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author Yichen Dai
*/
public class ServerStater{
protected static final Logger logger = LogManager.getLogger();
public static final Serializer SERIALIZER = new KryoSerializer();
public static ExecutorService threadPool;
public static SocketIOServer server;
public static int workCount;
public ServerStater(String[] dbs){
try{
loadConfig();
for(String dbName : dbs){
SocketIONamespace namespace = server.addNamespace("/" + dbName);
addEvent(namespace);
}
server.start();
}catch (Exception e){
e.printStackTrace();
}
}
private void addEvent(SocketIONamespace nameSpace){
logger.debug("配置事件监听");
nameSpace.addConnectListener(client -> {
logger.info(nameSpace.getName() + "- socket connected!");
String agentID = Commons.getAgentID(client);
if(agentID == null){
// 如果连接信息错误,发送异常信息,关闭socket
logger.info("连接信息错误:agentID, 连接关闭");
client.disconnect();
}
String dbName = Commons.getDBName(client);
// 缓存连接
ClientCache.saveClient(agentID, dbName, client);
});
// rpcResponse
nameSpace.addEventListener("RPCResponse", byte[].class, ((client, data, ackRequest) -> {
RpcResponse rpcResponse = SERIALIZER.deserialize(data, RpcResponse.class);
logger.debug("RPCResponse: " + (rpcResponse.getStatus() ? "success" : "fail"));
String agentID = Commons.getAgentID(client);
String dbName = Commons.getDBName(client);
ClientWrapper wrapper = ClientCache.getClientWrapper(agentID, dbName);
LockAndCondition lac = wrapper.getLockAndCondition(rpcResponse.getID());
ReentrantLock lock = lac.getLock();
Condition condition = lac.getCondition();
// When a response is received, it notifies that the FutureTask thread blocking on the LockAndCondition
// If the response contains data, take it out.
lock.lock();
try {
Object resultData = rpcResponse.getResult();
if(!rpcResponse.getStatus()){
logger.error(resultData);
resultData = null;
}
if(resultData != null) {
lac.setResult(resultData);
}
condition.signal();
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
wrapper.removeLockAndCondition(rpcResponse.getID());
logger.debug("received response message, signaled condition");
}));
// 处理错误事件
nameSpace.addEventListener("ErrorMessage", String.class,
((client, data, ackRequest) -> logger.info("Error: " + data)
));
}
private void loadConfig() throws IOException {
logger.debug("加载配置");
SocketConfig socketConfig = new SocketConfig();
com.corundumstudio.socketio.Configuration config =
new com.corundumstudio.socketio.Configuration();
InputStream in = this.getClass().getResourceAsStream("/socketIO.properties");
Properties props = new Properties();
InputStreamReader inputStreamReader = new InputStreamReader(in, StandardCharsets.UTF_8);
props.load(inputStreamReader);
int bossCount = Integer.parseInt(props.getProperty("bossCount"));
String host = props.getProperty("host");
int port = Integer.parseInt(props.getProperty("port"));
workCount = Integer.parseInt(props.getProperty("workCount"));
boolean allowCustomRequests = Boolean.parseBoolean(props.getProperty("allowCustomRequests"));
int upgradeTimeout = Integer.parseInt(props.getProperty("upgradeTimeout"));
int pingTimeout = Integer.parseInt(props.getProperty("pingTimeout"));
int pingInterval = Integer.parseInt(props.getProperty("pingInterval"));
config.setSocketConfig(socketConfig);
config.setHostname(host);
config.setPort(port);
config.setBossThreads(bossCount);
config.setWorkerThreads(workCount);
config.setAllowCustomRequests(allowCustomRequests);
config.setUpgradeTimeout(upgradeTimeout);
config.setPingTimeout(pingTimeout);
config.setPingInterval(pingInterval);
config.setTransports(Transport.WEBSOCKET);
in.close();
threadPool = new ThreadPoolExecutor(
0, workCount,
60L, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(),
new ThreadFactoryBuilder().setNameFormat("Thread-for-FutureTask-%d").build()
);
server = new SocketIOServer(config);
server.addConnectListener(client -> {
String agentID = Commons.getAgentID(client);
String dbName = Commons.getDBName(client);
if(agentID == null){
// 如果连接信息错误,发送异常信息,关闭socket
logger.info("连接信息错误:agentID, 连接关闭");
client.disconnect();
}
// 缓存连接
ClientCache.saveClient(agentID, dbName, client);
});
// 添加客户端连接监听器
server.addDisconnectListener(client -> {
String agentID = Commons.getAgentID(client);
String dbName = Commons.getDBName(client);
if(agentID == null){
// 如果连接信息错误,发送异常信息,关闭socket
logger.info("agentID: 连接关闭");
client.disconnect();
}
// 缓存连接
ClientCache.deleteClient(agentID, dbName);
logger.info("agentID: " + agentID + "连接关闭");
logger.info("agentID: " + agentID + "连接已删除");
});
server.addEventListener("message", String.class,
((client, data, ackRequest) -> logger.info("message: " + data)
));
}
}

69
service/src/main/java/com/fanruan/cache/ClientCache.java vendored

@ -0,0 +1,69 @@
package com.fanruan.cache;
import com.corundumstudio.socketio.SocketIOClient;
import com.fanruan.ServerStater;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author Yichen Dai
*/
public class ClientCache {
private static final Map<String, Map<String, ClientWrapper>> AGENT_MAP = new ConcurrentHashMap<>();
/**
* 缓存代理通道
* @param agentID 代理名称
* @param client 代理通道
*/
public static void saveClient(String agentID, String dbName, SocketIOClient client){
Map<String, ClientWrapper> nameSpaceMap = AGENT_MAP.get(agentID);
if(nameSpaceMap == null){
nameSpaceMap = new ConcurrentHashMap<>(ServerStater.workCount * 10);
AGENT_MAP.put(agentID, nameSpaceMap);
}
ClientWrapper wrapper = nameSpaceMap.get(dbName);
if(wrapper == null){
wrapper = new ClientWrapper();
nameSpaceMap.put(dbName, wrapper);
}
wrapper.setClient(client);
}
public static SocketIOClient getClient(String agentID, String dbName){
Map<String, ClientWrapper> map = AGENT_MAP.get(agentID);
if(map == null) {
return null;
}
ClientWrapper wrapper = map.get(dbName);
if(wrapper == null) {
return null;
}
return wrapper.getClient();
}
public static void deleteClient(String agentID, String dbName){
Map<String, ClientWrapper> map = AGENT_MAP.get(agentID);
if(map == null) {
return;
}
map.remove(dbName);
}
public static ClientWrapper getClientWrapper(String agentID, String dbName){
Map<String, ClientWrapper> map = AGENT_MAP.get(agentID);
if(map == null) {
throw new RuntimeException("wrong agent ID");
}
ClientWrapper wrapper = map.get(dbName);
if(wrapper == null) {
throw new RuntimeException("wrong dbName");
}
return wrapper;
}
}

45
service/src/main/java/com/fanruan/cache/ClientWrapper.java vendored

@ -0,0 +1,45 @@
package com.fanruan.cache;
import com.corundumstudio.socketio.SocketIOClient;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author Yichen Dai
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ClientWrapper {
private SocketIOClient client;
private static Map<String, LockAndCondition> lockMap = new ConcurrentHashMap<>();
public SocketIOClient getClient(){
if(client == null) {
throw new RuntimeException("no such client");
}
return client;
}
public LockAndCondition getLockAndCondition(String messageID){
LockAndCondition lac = lockMap.get(messageID);
if(lac == null){
ReentrantLock lock = new ReentrantLock();
Condition condition = lock.newCondition();
lac = new LockAndCondition(lock, condition);
lockMap.put(messageID, lac);
}
return lac;
}
public void removeLockAndCondition(String messageID){
lockMap.remove(messageID);
}
}

26
service/src/main/java/com/fanruan/cache/LockAndCondition.java vendored

@ -0,0 +1,26 @@
package com.fanruan.cache;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author Yichen Dai
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class LockAndCondition{
private ReentrantLock lock;
private Condition condition;
private Object result;
private String BindingID;
LockAndCondition(ReentrantLock lock, Condition condition){
this.lock = lock;
this.condition = condition;
}
}

891
service/src/main/java/com/fanruan/jdbc/MyDataBaseMetaData.java

@ -0,0 +1,891 @@
package com.fanruan.jdbc;
import com.fanruan.jdbc.driver.MyDriver;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.RowIdLifetime;
import java.sql.SQLException;
public class MyDataBaseMetaData implements java.sql.DatabaseMetaData{
@Override
public boolean allProceduresAreCallable() throws SQLException {
return false;
}
@Override
public boolean allTablesAreSelectable() throws SQLException {
return false;
}
@Override
public String getURL() throws SQLException {
return null;
}
@Override
public String getUserName() throws SQLException {
return null;
}
@Override
public boolean isReadOnly() throws SQLException {
return false;
}
@Override
public boolean nullsAreSortedHigh() throws SQLException {
return false;
}
@Override
public boolean nullsAreSortedLow() throws SQLException {
return false;
}
@Override
public boolean nullsAreSortedAtStart() throws SQLException {
return false;
}
@Override
public boolean nullsAreSortedAtEnd() throws SQLException {
return false;
}
@Override
public String getDatabaseProductName() throws SQLException {
return "agent server 1.0.0";
}
@Override
public String getDatabaseProductVersion() throws SQLException {
return "1.0.0";
}
@Override
public String getDriverName() throws SQLException {
return "myDriver for Agent";
}
@Override
public String getDriverVersion() throws SQLException {
return "1.0.0";
}
@Override
public int getDriverMajorVersion() {
return MyDriver.DRIVER_VERSION_MAJOR;
}
@Override
public int getDriverMinorVersion() {
return MyDriver.DRIVER_VERSION_MINOR;
}
@Override
public boolean usesLocalFiles() throws SQLException {
return false;
}
@Override
public boolean usesLocalFilePerTable() throws SQLException {
return false;
}
@Override
public boolean supportsMixedCaseIdentifiers() throws SQLException {
return false;
}
@Override
public boolean storesUpperCaseIdentifiers() throws SQLException {
return false;
}
@Override
public boolean storesLowerCaseIdentifiers() throws SQLException {
return false;
}
@Override
public boolean storesMixedCaseIdentifiers() throws SQLException {
return false;
}
@Override
public boolean supportsMixedCaseQuotedIdentifiers() throws SQLException {
return false;
}
@Override
public boolean storesUpperCaseQuotedIdentifiers() throws SQLException {
return false;
}
@Override
public boolean storesLowerCaseQuotedIdentifiers() throws SQLException {
return false;
}
@Override
public boolean storesMixedCaseQuotedIdentifiers() throws SQLException {
return false;
}
@Override
public String getIdentifierQuoteString() throws SQLException {
return null;
}
@Override
public String getSQLKeywords() throws SQLException {
return null;
}
@Override
public String getNumericFunctions() throws SQLException {
return null;
}
@Override
public String getStringFunctions() throws SQLException {
return null;
}
@Override
public String getSystemFunctions() throws SQLException {
return null;
}
@Override
public String getTimeDateFunctions() throws SQLException {
return null;
}
@Override
public String getSearchStringEscape() throws SQLException {
return null;
}
@Override
public String getExtraNameCharacters() throws SQLException {
return null;
}
@Override
public boolean supportsAlterTableWithAddColumn() throws SQLException {
return false;
}
@Override
public boolean supportsAlterTableWithDropColumn() throws SQLException {
return false;
}
@Override
public boolean supportsColumnAliasing() throws SQLException {
return false;
}
@Override
public boolean nullPlusNonNullIsNull() throws SQLException {
return false;
}
@Override
public boolean supportsConvert() throws SQLException {
return false;
}
@Override
public boolean supportsConvert(int fromType, int toType) throws SQLException {
return false;
}
@Override
public boolean supportsTableCorrelationNames() throws SQLException {
return false;
}
@Override
public boolean supportsDifferentTableCorrelationNames() throws SQLException {
return false;
}
@Override
public boolean supportsExpressionsInOrderBy() throws SQLException {
return false;
}
@Override
public boolean supportsOrderByUnrelated() throws SQLException {
return false;
}
@Override
public boolean supportsGroupBy() throws SQLException {
return false;
}
@Override
public boolean supportsGroupByUnrelated() throws SQLException {
return false;
}
@Override
public boolean supportsGroupByBeyondSelect() throws SQLException {
return false;
}
@Override
public boolean supportsLikeEscapeClause() throws SQLException {
return false;
}
@Override
public boolean supportsMultipleResultSets() throws SQLException {
return false;
}
@Override
public boolean supportsMultipleTransactions() throws SQLException {
return false;
}
@Override
public boolean supportsNonNullableColumns() throws SQLException {
return false;
}
@Override
public boolean supportsMinimumSQLGrammar() throws SQLException {
return false;
}
@Override
public boolean supportsCoreSQLGrammar() throws SQLException {
return false;
}
@Override
public boolean supportsExtendedSQLGrammar() throws SQLException {
return false;
}
@Override
public boolean supportsANSI92EntryLevelSQL() throws SQLException {
return false;
}
@Override
public boolean supportsANSI92IntermediateSQL() throws SQLException {
return false;
}
@Override
public boolean supportsANSI92FullSQL() throws SQLException {
return false;
}
@Override
public boolean supportsIntegrityEnhancementFacility() throws SQLException {
return false;
}
@Override
public boolean supportsOuterJoins() throws SQLException {
return false;
}
@Override
public boolean supportsFullOuterJoins() throws SQLException {
return false;
}
@Override
public boolean supportsLimitedOuterJoins() throws SQLException {
return false;
}
@Override
public String getSchemaTerm() throws SQLException {
return null;
}
@Override
public String getProcedureTerm() throws SQLException {
return null;
}
@Override
public String getCatalogTerm() throws SQLException {
return null;
}
@Override
public boolean isCatalogAtStart() throws SQLException {
return false;
}
@Override
public String getCatalogSeparator() throws SQLException {
return null;
}
@Override
public boolean supportsSchemasInDataManipulation() throws SQLException {
return false;
}
@Override
public boolean supportsSchemasInProcedureCalls() throws SQLException {
return false;
}
@Override
public boolean supportsSchemasInTableDefinitions() throws SQLException {
return false;
}
@Override
public boolean supportsSchemasInIndexDefinitions() throws SQLException {
return false;
}
@Override
public boolean supportsSchemasInPrivilegeDefinitions() throws SQLException {
return false;
}
@Override
public boolean supportsCatalogsInDataManipulation() throws SQLException {
return false;
}
@Override
public boolean supportsCatalogsInProcedureCalls() throws SQLException {
return false;
}
@Override
public boolean supportsCatalogsInTableDefinitions() throws SQLException {
return false;
}
@Override
public boolean supportsCatalogsInIndexDefinitions() throws SQLException {
return false;
}
@Override
public boolean supportsCatalogsInPrivilegeDefinitions() throws SQLException {
return false;
}
@Override
public boolean supportsPositionedDelete() throws SQLException {
return false;
}
@Override
public boolean supportsPositionedUpdate() throws SQLException {
return false;
}
@Override
public boolean supportsSelectForUpdate() throws SQLException {
return false;
}
@Override
public boolean supportsStoredProcedures() throws SQLException {
return false;
}
@Override
public boolean supportsSubqueriesInComparisons() throws SQLException {
return false;
}
@Override
public boolean supportsSubqueriesInExists() throws SQLException {
return false;
}
@Override
public boolean supportsSubqueriesInIns() throws SQLException {
return false;
}
@Override
public boolean supportsSubqueriesInQuantifieds() throws SQLException {
return false;
}
@Override
public boolean supportsCorrelatedSubqueries() throws SQLException {
return false;
}
@Override
public boolean supportsUnion() throws SQLException {
return false;
}
@Override
public boolean supportsUnionAll() throws SQLException {
return false;
}
@Override
public boolean supportsOpenCursorsAcrossCommit() throws SQLException {
return false;
}
@Override
public boolean supportsOpenCursorsAcrossRollback() throws SQLException {
return false;
}
@Override
public boolean supportsOpenStatementsAcrossCommit() throws SQLException {
return false;
}
@Override
public boolean supportsOpenStatementsAcrossRollback() throws SQLException {
return false;
}
@Override
public int getMaxBinaryLiteralLength() throws SQLException {
return 0;
}
@Override
public int getMaxCharLiteralLength() throws SQLException {
return 0;
}
@Override
public int getMaxColumnNameLength() throws SQLException {
return 0;
}
@Override
public int getMaxColumnsInGroupBy() throws SQLException {
return 0;
}
@Override
public int getMaxColumnsInIndex() throws SQLException {
return 0;
}
@Override
public int getMaxColumnsInOrderBy() throws SQLException {
return 0;
}
@Override
public int getMaxColumnsInSelect() throws SQLException {
return 0;
}
@Override
public int getMaxColumnsInTable() throws SQLException {
return 0;
}
@Override
public int getMaxConnections() throws SQLException {
return 0;
}
@Override
public int getMaxCursorNameLength() throws SQLException {
return 0;
}
@Override
public int getMaxIndexLength() throws SQLException {
return 0;
}
@Override
public int getMaxSchemaNameLength() throws SQLException {
return 0;
}
@Override
public int getMaxProcedureNameLength() throws SQLException {
return 0;
}
@Override
public int getMaxCatalogNameLength() throws SQLException {
return 0;
}
@Override
public int getMaxRowSize() throws SQLException {
return 0;
}
@Override
public boolean doesMaxRowSizeIncludeBlobs() throws SQLException {
return false;
}
@Override
public int getMaxStatementLength() throws SQLException {
return 0;
}
@Override
public int getMaxStatements() throws SQLException {
return 0;
}
@Override
public int getMaxTableNameLength() throws SQLException {
return 0;
}
@Override
public int getMaxTablesInSelect() throws SQLException {
return 0;
}
@Override
public int getMaxUserNameLength() throws SQLException {
return 0;
}
@Override
public int getDefaultTransactionIsolation() throws SQLException {
return 0;
}
@Override
public boolean supportsTransactions() throws SQLException {
return false;
}
@Override
public boolean supportsTransactionIsolationLevel(int level) throws SQLException {
return false;
}
@Override
public boolean supportsDataDefinitionAndDataManipulationTransactions() throws SQLException {
return false;
}
@Override
public boolean supportsDataManipulationTransactionsOnly() throws SQLException {
return false;
}
@Override
public boolean dataDefinitionCausesTransactionCommit() throws SQLException {
return false;
}
@Override
public boolean dataDefinitionIgnoredInTransactions() throws SQLException {
return false;
}
@Override
public ResultSet getProcedures(String catalog, String schemaPattern, String procedureNamePattern) throws SQLException {
return null;
}
@Override
public ResultSet getProcedureColumns(String catalog, String schemaPattern, String procedureNamePattern, String columnNamePattern) throws SQLException {
return null;
}
@Override
public ResultSet getTables(String catalog, String schemaPattern, String tableNamePattern, String[] types) throws SQLException {
return null;
}
@Override
public ResultSet getSchemas() throws SQLException {
return null;
}
@Override
public ResultSet getCatalogs() throws SQLException {
return null;
}
@Override
public ResultSet getTableTypes() throws SQLException {
return null;
}
@Override
public ResultSet getColumns(String catalog, String schemaPattern, String tableNamePattern, String columnNamePattern) throws SQLException {
return null;
}
@Override
public ResultSet getColumnPrivileges(String catalog, String schema, String table, String columnNamePattern) throws SQLException {
return null;
}
@Override
public ResultSet getTablePrivileges(String catalog, String schemaPattern, String tableNamePattern) throws SQLException {
return null;
}
@Override
public ResultSet getBestRowIdentifier(String catalog, String schema, String table, int scope, boolean nullable) throws SQLException {
return null;
}
@Override
public ResultSet getVersionColumns(String catalog, String schema, String table) throws SQLException {
return null;
}
@Override
public ResultSet getPrimaryKeys(String catalog, String schema, String table) throws SQLException {
return null;
}
@Override
public ResultSet getImportedKeys(String catalog, String schema, String table) throws SQLException {
return null;
}
@Override
public ResultSet getExportedKeys(String catalog, String schema, String table) throws SQLException {
return null;
}
@Override
public ResultSet getCrossReference(String parentCatalog, String parentSchema, String parentTable, String foreignCatalog, String foreignSchema, String foreignTable) throws SQLException {
return null;
}
@Override
public ResultSet getTypeInfo() throws SQLException {
return null;
}
@Override
public ResultSet getIndexInfo(String catalog, String schema, String table, boolean unique, boolean approximate) throws SQLException {
return null;
}
@Override
public boolean supportsResultSetType(int type) throws SQLException {
return false;
}
@Override
public boolean supportsResultSetConcurrency(int type, int concurrency) throws SQLException {
return false;
}
@Override
public boolean ownUpdatesAreVisible(int type) throws SQLException {
return false;
}
@Override
public boolean ownDeletesAreVisible(int type) throws SQLException {
return false;
}
@Override
public boolean ownInsertsAreVisible(int type) throws SQLException {
return false;
}
@Override
public boolean othersUpdatesAreVisible(int type) throws SQLException {
return false;
}
@Override
public boolean othersDeletesAreVisible(int type) throws SQLException {
return false;
}
@Override
public boolean othersInsertsAreVisible(int type) throws SQLException {
return false;
}
@Override
public boolean updatesAreDetected(int type) throws SQLException {
return false;
}
@Override
public boolean deletesAreDetected(int type) throws SQLException {
return false;
}
@Override
public boolean insertsAreDetected(int type) throws SQLException {
return false;
}
@Override
public boolean supportsBatchUpdates() throws SQLException {
return false;
}
@Override
public ResultSet getUDTs(String catalog, String schemaPattern, String typeNamePattern, int[] types) throws SQLException {
return null;
}
@Override
public Connection getConnection() throws SQLException {
return null;
}
@Override
public boolean supportsSavepoints() throws SQLException {
return false;
}
@Override
public boolean supportsNamedParameters() throws SQLException {
return false;
}
@Override
public boolean supportsMultipleOpenResults() throws SQLException {
return false;
}
@Override
public boolean supportsGetGeneratedKeys() throws SQLException {
return false;
}
@Override
public ResultSet getSuperTypes(String catalog, String schemaPattern, String typeNamePattern) throws SQLException {
return null;
}
@Override
public ResultSet getSuperTables(String catalog, String schemaPattern, String tableNamePattern) throws SQLException {
return null;
}
@Override
public ResultSet getAttributes(String catalog, String schemaPattern, String typeNamePattern, String attributeNamePattern) throws SQLException {
return null;
}
@Override
public boolean supportsResultSetHoldability(int holdability) throws SQLException {
return false;
}
@Override
public int getResultSetHoldability() throws SQLException {
return 0;
}
@Override
public int getDatabaseMajorVersion() throws SQLException {
return 0;
}
@Override
public int getDatabaseMinorVersion() throws SQLException {
return 0;
}
@Override
public int getJDBCMajorVersion() throws SQLException {
return 0;
}
@Override
public int getJDBCMinorVersion() throws SQLException {
return 0;
}
@Override
public int getSQLStateType() throws SQLException {
return 0;
}
@Override
public boolean locatorsUpdateCopy() throws SQLException {
return false;
}
@Override
public boolean supportsStatementPooling() throws SQLException {
return false;
}
@Override
public RowIdLifetime getRowIdLifetime() throws SQLException {
return null;
}
@Override
public ResultSet getSchemas(String catalog, String schemaPattern) throws SQLException {
return null;
}
@Override
public boolean supportsStoredFunctionsUsingCallSyntax() throws SQLException {
return false;
}
@Override
public boolean autoCommitFailureClosesAllResultSets() throws SQLException {
return false;
}
@Override
public ResultSet getClientInfoProperties() throws SQLException {
return null;
}
@Override
public ResultSet getFunctions(String catalog, String schemaPattern, String functionNamePattern) throws SQLException {
return null;
}
@Override
public ResultSet getFunctionColumns(String catalog, String schemaPattern, String functionNamePattern, String columnNamePattern) throws SQLException {
return null;
}
@Override
public ResultSet getPseudoColumns(String catalog, String schemaPattern, String tableNamePattern, String columnNamePattern) throws SQLException {
return null;
}
@Override
public boolean generatedKeyAlwaysReturned() throws SQLException {
return false;
}
@Override
public <T> T unwrap(Class<T> iface) throws SQLException {
return null;
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
return false;
}
}

318
service/src/main/java/com/fanruan/jdbc/connection/MyConnection.java

@ -0,0 +1,318 @@
package com.fanruan.jdbc.connection;
import com.corundumstudio.socketio.SocketIOClient;
import com.fanruan.cache.ClientCache;
import com.fanruan.jdbc.MyDataBaseMetaData;
import com.fanruan.jdbc.statement.MyPreparedStatement;
import com.fanruan.jdbc.statement.MyStatement;
import com.fanruan.proxy.ProxyFactory;
import java.sql.*;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.Executor;
/**
* @author Yichen Dai
*/
public class MyConnection implements Connection {
private String ID;
private Properties info;
private boolean autoCommit = true;
SocketIOClient client;
public MyConnection(){
}
public void setID(String ID){
this.ID = ID;
}
public String getID(){
return this.ID;
}
public void setInfo(Properties info){
this.info = info;
client = ClientCache.getClient(info.getProperty("agentID"), info.getProperty("agentDBName"));
}
@Override
public Statement createStatement(){
MyStatement st = (MyStatement) ProxyFactory.getProxy(MyStatement.class, info);
st.setInfo(info);
return st;
}
@Override
public PreparedStatement prepareStatement(String sql) throws SQLException {
MyPreparedStatement pst = (MyPreparedStatement) ProxyFactory.getProxy(MyPreparedStatement.class, info);
// 将需要准备的sql 加入 properties 中, 将用以标识生成的 ResultSet
info.setProperty("PreparedSQL", sql);
pst.setInfo(info);
return pst;
}
@Override
public CallableStatement prepareCall(String sql) throws SQLException {
return null;
}
@Override
public String nativeSQL(String sql) throws SQLException {
return sql;
}
@Override
public void setAutoCommit(boolean autoCommit) throws SQLException {
this.autoCommit = autoCommit;
}
@Override
public boolean getAutoCommit() throws SQLException {
return autoCommit;
}
@Override
public void commit() throws SQLException {
}
@Override
public void rollback() throws SQLException {
}
@Override
public void close() throws SQLException {
client.disconnect();
}
@Override
public boolean isClosed() throws SQLException {
return client.isChannelOpen();
}
@Override
public DatabaseMetaData getMetaData() throws SQLException {
return new MyDataBaseMetaData();
}
@Override
public void setReadOnly(boolean readOnly) throws SQLException {
}
@Override
public boolean isReadOnly() throws SQLException {
return false;
}
@Override
public void setCatalog(String catalog) throws SQLException {
}
@Override
public String getCatalog() throws SQLException {
return null;
}
@Override
public void setTransactionIsolation(int level) throws SQLException {
}
@Override
public int getTransactionIsolation() throws SQLException {
return 0;
}
@Override
public SQLWarning getWarnings() throws SQLException {
return null;
}
@Override
public void clearWarnings() throws SQLException {
}
@Override
public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException {
return null;
}
@Override
public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
return null;
}
@Override
public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
return null;
}
@Override
public Map<String, Class<?>> getTypeMap() throws SQLException {
return null;
}
@Override
public void setTypeMap(Map<String, Class<?>> map) throws SQLException {
}
@Override
public void setHoldability(int holdability) throws SQLException {
}
@Override
public int getHoldability() throws SQLException {
return 0;
}
@Override
public Savepoint setSavepoint() throws SQLException {
return null;
}
@Override
public Savepoint setSavepoint(String name) throws SQLException {
return null;
}
@Override
public void rollback(Savepoint savepoint) throws SQLException {
}
@Override
public void releaseSavepoint(Savepoint savepoint) throws SQLException {
}
@Override
public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
return null;
}
@Override
public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
return null;
}
@Override
public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
return null;
}
@Override
public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {
return null;
}
@Override
public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException {
return null;
}
@Override
public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException {
return null;
}
@Override
public Clob createClob() throws SQLException {
return null;
}
@Override
public Blob createBlob() throws SQLException {
return null;
}
@Override
public NClob createNClob() throws SQLException {
return null;
}
@Override
public SQLXML createSQLXML() throws SQLException {
return null;
}
@Override
public boolean isValid(int timeout) throws SQLException {
return false;
}
@Override
public void setClientInfo(String name, String value) throws SQLClientInfoException {
}
@Override
public void setClientInfo(Properties properties) throws SQLClientInfoException {
}
@Override
public String getClientInfo(String name) throws SQLException {
return null;
}
@Override
public Properties getClientInfo() throws SQLException {
return null;
}
@Override
public Array createArrayOf(String typeName, Object[] elements) throws SQLException {
return null;
}
@Override
public Struct createStruct(String typeName, Object[] attributes) throws SQLException {
return null;
}
@Override
public void setSchema(String schema) throws SQLException {
}
@Override
public String getSchema() throws SQLException {
return null;
}
@Override
public void abort(Executor executor) throws SQLException {
}
@Override
public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException {
}
@Override
public int getNetworkTimeout() throws SQLException {
return 0;
}
@Override
public <T> T unwrap(Class<T> iface) throws SQLException {
return null;
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
return false;
}
}

84
service/src/main/java/com/fanruan/jdbc/driver/MyDriver.java

@ -0,0 +1,84 @@
package com.fanruan.jdbc.driver;
import com.fanruan.jdbc.connection.MyConnection;
import com.fanruan.proxy.ProxyFactory;
import java.sql.*;
import java.util.Properties;
import java.util.logging.Logger;
/**
* @author Yichen Dai
*/
public class MyDriver implements Driver {
static public final int DRIVER_VERSION_MAJOR = 1;
static public final int DRIVER_VERSION_MINOR = 1;
private String ID;
//依靠静态函数块注册驱动
static{
try {
DriverManager.registerDriver((MyDriver) ProxyFactory.getProxy(MyDriver.class, null));
} catch (Exception e) {
throw new RuntimeException("Can't register driver");
}
}
/**
* These corresponding code is to make the format correct, because the getID()
* will be called, even if the filed is never not null.
* @return ID
*/
public String getID(){
return this.ID;
}
public void setID(String ID){
this.ID = ID;
}
@Override
public Connection connect(String url, Properties info){
String dbName = info.getProperty("agentDBName");
if(dbName == null){
dbName = url.split(":")[1];
info.setProperty("agentDBName", dbName);
}
MyConnection myConn = (MyConnection) ProxyFactory.getProxy(MyConnection.class, info);
myConn.setInfo(info);
return myConn;
}
@Override
public boolean acceptsURL(String url){
return true;
}
@Override
public DriverPropertyInfo[] getPropertyInfo(String url, Properties info){
return new DriverPropertyInfo[0];
}
@Override
public int getMajorVersion() {
return DRIVER_VERSION_MAJOR;
}
@Override
public int getMinorVersion() {
return DRIVER_VERSION_MINOR;
}
@Override
public boolean jdbcCompliant() {
return false;
}
@Override
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
return null;
}
}

990
service/src/main/java/com/fanruan/jdbc/resultset/MyResultSet.java

@ -0,0 +1,990 @@
package com.fanruan.jdbc.resultset;
import java.io.InputStream;
import java.io.Reader;
import java.math.BigDecimal;
import java.net.URL;
import java.sql.*;
import java.util.Calendar;
import java.util.Map;
/**
* @author Yichen Dai
*/
public class MyResultSet implements ResultSet {
private String sql;
private String ID;
public String getID(){
return this.ID;
}
public void setID(String ID){
this.ID = ID;
}
public void setSql(String sql){
this.sql = sql;
}
public String getSql(){
return this.sql;
}
@Override
public boolean next() throws SQLException {
return false;
}
@Override
public void close() throws SQLException {
}
@Override
public boolean wasNull() throws SQLException {
return false;
}
@Override
public String getString(int columnIndex) throws SQLException {
return null;
}
@Override
public boolean getBoolean(int columnIndex) throws SQLException {
return false;
}
@Override
public byte getByte(int columnIndex) throws SQLException {
return 0;
}
@Override
public short getShort(int columnIndex) throws SQLException {
return 0;
}
@Override
public int getInt(int columnIndex) throws SQLException {
return 0;
}
@Override
public long getLong(int columnIndex) throws SQLException {
return 0;
}
@Override
public float getFloat(int columnIndex) throws SQLException {
return 0;
}
@Override
public double getDouble(int columnIndex) throws SQLException {
return 0;
}
@Override
public BigDecimal getBigDecimal(int columnIndex, int scale) throws SQLException {
return null;
}
@Override
public byte[] getBytes(int columnIndex) throws SQLException {
return new byte[0];
}
@Override
public Date getDate(int columnIndex) throws SQLException {
return null;
}
@Override
public Time getTime(int columnIndex) throws SQLException {
return null;
}
@Override
public Timestamp getTimestamp(int columnIndex) throws SQLException {
return null;
}
@Override
public InputStream getAsciiStream(int columnIndex) throws SQLException {
return null;
}
@Override
public InputStream getUnicodeStream(int columnIndex) throws SQLException {
return null;
}
@Override
public InputStream getBinaryStream(int columnIndex) throws SQLException {
return null;
}
@Override
public String getString(String columnLabel) throws SQLException {
return null;
}
@Override
public boolean getBoolean(String columnLabel) throws SQLException {
return false;
}
@Override
public byte getByte(String columnLabel) throws SQLException {
return 0;
}
@Override
public short getShort(String columnLabel) throws SQLException {
return 0;
}
@Override
public int getInt(String columnLabel) throws SQLException {
return 0;
}
@Override
public long getLong(String columnLabel) throws SQLException {
return 0;
}
@Override
public float getFloat(String columnLabel) throws SQLException {
return 0;
}
@Override
public double getDouble(String columnLabel) throws SQLException {
return 0;
}
@Override
public BigDecimal getBigDecimal(String columnLabel, int scale) throws SQLException {
return null;
}
@Override
public byte[] getBytes(String columnLabel) throws SQLException {
return new byte[0];
}
@Override
public Date getDate(String columnLabel) throws SQLException {
return null;
}
@Override
public Time getTime(String columnLabel) throws SQLException {
return null;
}
@Override
public Timestamp getTimestamp(String columnLabel) throws SQLException {
return null;
}
@Override
public InputStream getAsciiStream(String columnLabel) throws SQLException {
return null;
}
@Override
public InputStream getUnicodeStream(String columnLabel) throws SQLException {
return null;
}
@Override
public InputStream getBinaryStream(String columnLabel) throws SQLException {
return null;
}
@Override
public SQLWarning getWarnings() throws SQLException {
return null;
}
@Override
public void clearWarnings() throws SQLException {
}
@Override
public String getCursorName() throws SQLException {
return null;
}
@Override
public ResultSetMetaData getMetaData() throws SQLException {
return null;
}
@Override
public Object getObject(int columnIndex) throws SQLException {
return null;
}
@Override
public Object getObject(String columnLabel) throws SQLException {
return null;
}
@Override
public int findColumn(String columnLabel) throws SQLException {
return 0;
}
@Override
public Reader getCharacterStream(int columnIndex) throws SQLException {
return null;
}
@Override
public Reader getCharacterStream(String columnLabel) throws SQLException {
return null;
}
@Override
public BigDecimal getBigDecimal(int columnIndex) throws SQLException {
return null;
}
@Override
public BigDecimal getBigDecimal(String columnLabel) throws SQLException {
return null;
}
@Override
public boolean isBeforeFirst() throws SQLException {
return false;
}
@Override
public boolean isAfterLast() throws SQLException {
return false;
}
@Override
public boolean isFirst() throws SQLException {
return false;
}
@Override
public boolean isLast() throws SQLException {
return false;
}
@Override
public void beforeFirst() throws SQLException {
}
@Override
public void afterLast() throws SQLException {
}
@Override
public boolean first() throws SQLException {
return false;
}
@Override
public boolean last() throws SQLException {
return false;
}
@Override
public int getRow() throws SQLException {
return 0;
}
@Override
public boolean absolute(int row) throws SQLException {
return false;
}
@Override
public boolean relative(int rows) throws SQLException {
return false;
}
@Override
public boolean previous() throws SQLException {
return false;
}
@Override
public void setFetchDirection(int direction) throws SQLException {
}
@Override
public int getFetchDirection() throws SQLException {
return 0;
}
@Override
public void setFetchSize(int rows) throws SQLException {
}
@Override
public int getFetchSize() throws SQLException {
return 0;
}
@Override
public int getType() throws SQLException {
return 0;
}
@Override
public int getConcurrency() throws SQLException {
return 0;
}
@Override
public boolean rowUpdated() throws SQLException {
return false;
}
@Override
public boolean rowInserted() throws SQLException {
return false;
}
@Override
public boolean rowDeleted() throws SQLException {
return false;
}
@Override
public void updateNull(int columnIndex) throws SQLException {
}
@Override
public void updateBoolean(int columnIndex, boolean x) throws SQLException {
}
@Override
public void updateByte(int columnIndex, byte x) throws SQLException {
}
@Override
public void updateShort(int columnIndex, short x) throws SQLException {
}
@Override
public void updateInt(int columnIndex, int x) throws SQLException {
}
@Override
public void updateLong(int columnIndex, long x) throws SQLException {
}
@Override
public void updateFloat(int columnIndex, float x) throws SQLException {
}
@Override
public void updateDouble(int columnIndex, double x) throws SQLException {
}
@Override
public void updateBigDecimal(int columnIndex, BigDecimal x) throws SQLException {
}
@Override
public void updateString(int columnIndex, String x) throws SQLException {
}
@Override
public void updateBytes(int columnIndex, byte[] x) throws SQLException {
}
@Override
public void updateDate(int columnIndex, Date x) throws SQLException {
}
@Override
public void updateTime(int columnIndex, Time x) throws SQLException {
}
@Override
public void updateTimestamp(int columnIndex, Timestamp x) throws SQLException {
}
@Override
public void updateAsciiStream(int columnIndex, InputStream x, int length) throws SQLException {
}
@Override
public void updateBinaryStream(int columnIndex, InputStream x, int length) throws SQLException {
}
@Override
public void updateCharacterStream(int columnIndex, Reader x, int length) throws SQLException {
}
@Override
public void updateObject(int columnIndex, Object x, int scaleOrLength) throws SQLException {
}
@Override
public void updateObject(int columnIndex, Object x) throws SQLException {
}
@Override
public void updateNull(String columnLabel) throws SQLException {
}
@Override
public void updateBoolean(String columnLabel, boolean x) throws SQLException {
}
@Override
public void updateByte(String columnLabel, byte x) throws SQLException {
}
@Override
public void updateShort(String columnLabel, short x) throws SQLException {
}
@Override
public void updateInt(String columnLabel, int x) throws SQLException {
}
@Override
public void updateLong(String columnLabel, long x) throws SQLException {
}
@Override
public void updateFloat(String columnLabel, float x) throws SQLException {
}
@Override
public void updateDouble(String columnLabel, double x) throws SQLException {
}
@Override
public void updateBigDecimal(String columnLabel, BigDecimal x) throws SQLException {
}
@Override
public void updateString(String columnLabel, String x) throws SQLException {
}
@Override
public void updateBytes(String columnLabel, byte[] x) throws SQLException {
}
@Override
public void updateDate(String columnLabel, Date x) throws SQLException {
}
@Override
public void updateTime(String columnLabel, Time x) throws SQLException {
}
@Override
public void updateTimestamp(String columnLabel, Timestamp x) throws SQLException {
}
@Override
public void updateAsciiStream(String columnLabel, InputStream x, int length) throws SQLException {
}
@Override
public void updateBinaryStream(String columnLabel, InputStream x, int length) throws SQLException {
}
@Override
public void updateCharacterStream(String columnLabel, Reader reader, int length) throws SQLException {
}
@Override
public void updateObject(String columnLabel, Object x, int scaleOrLength) throws SQLException {
}
@Override
public void updateObject(String columnLabel, Object x) throws SQLException {
}
@Override
public void insertRow() throws SQLException {
}
@Override
public void updateRow() throws SQLException {
}
@Override
public void deleteRow() throws SQLException {
}
@Override
public void refreshRow() throws SQLException {
}
@Override
public void cancelRowUpdates() throws SQLException {
}
@Override
public void moveToInsertRow() throws SQLException {
}
@Override
public void moveToCurrentRow() throws SQLException {
}
@Override
public Statement getStatement() throws SQLException {
return null;
}
@Override
public Object getObject(int columnIndex, Map<String, Class<?>> map) throws SQLException {
return null;
}
@Override
public Ref getRef(int columnIndex) throws SQLException {
return null;
}
@Override
public Blob getBlob(int columnIndex) throws SQLException {
return null;
}
@Override
public Clob getClob(int columnIndex) throws SQLException {
return null;
}
@Override
public Array getArray(int columnIndex) throws SQLException {
return null;
}
@Override
public Object getObject(String columnLabel, Map<String, Class<?>> map) throws SQLException {
return null;
}
@Override
public Ref getRef(String columnLabel) throws SQLException {
return null;
}
@Override
public Blob getBlob(String columnLabel) throws SQLException {
return null;
}
@Override
public Clob getClob(String columnLabel) throws SQLException {
return null;
}
@Override
public Array getArray(String columnLabel) throws SQLException {
return null;
}
@Override
public Date getDate(int columnIndex, Calendar cal) throws SQLException {
return null;
}
@Override
public Date getDate(String columnLabel, Calendar cal) throws SQLException {
return null;
}
@Override
public Time getTime(int columnIndex, Calendar cal) throws SQLException {
return null;
}
@Override
public Time getTime(String columnLabel, Calendar cal) throws SQLException {
return null;
}
@Override
public Timestamp getTimestamp(int columnIndex, Calendar cal) throws SQLException {
return null;
}
@Override
public Timestamp getTimestamp(String columnLabel, Calendar cal) throws SQLException {
return null;
}
@Override
public URL getURL(int columnIndex) throws SQLException {
return null;
}
@Override
public URL getURL(String columnLabel) throws SQLException {
return null;
}
@Override
public void updateRef(int columnIndex, Ref x) throws SQLException {
}
@Override
public void updateRef(String columnLabel, Ref x) throws SQLException {
}
@Override
public void updateBlob(int columnIndex, Blob x) throws SQLException {
}
@Override
public void updateBlob(String columnLabel, Blob x) throws SQLException {
}
@Override
public void updateClob(int columnIndex, Clob x) throws SQLException {
}
@Override
public void updateClob(String columnLabel, Clob x) throws SQLException {
}
@Override
public void updateArray(int columnIndex, Array x) throws SQLException {
}
@Override
public void updateArray(String columnLabel, Array x) throws SQLException {
}
@Override
public RowId getRowId(int columnIndex) throws SQLException {
return null;
}
@Override
public RowId getRowId(String columnLabel) throws SQLException {
return null;
}
@Override
public void updateRowId(int columnIndex, RowId x) throws SQLException {
}
@Override
public void updateRowId(String columnLabel, RowId x) throws SQLException {
}
@Override
public int getHoldability() throws SQLException {
return 0;
}
@Override
public boolean isClosed() throws SQLException {
return false;
}
@Override
public void updateNString(int columnIndex, String nString) throws SQLException {
}
@Override
public void updateNString(String columnLabel, String nString) throws SQLException {
}
@Override
public void updateNClob(int columnIndex, NClob nClob) throws SQLException {
}
@Override
public void updateNClob(String columnLabel, NClob nClob) throws SQLException {
}
@Override
public NClob getNClob(int columnIndex) throws SQLException {
return null;
}
@Override
public NClob getNClob(String columnLabel) throws SQLException {
return null;
}
@Override
public SQLXML getSQLXML(int columnIndex) throws SQLException {
return null;
}
@Override
public SQLXML getSQLXML(String columnLabel) throws SQLException {
return null;
}
@Override
public void updateSQLXML(int columnIndex, SQLXML xmlObject) throws SQLException {
}
@Override
public void updateSQLXML(String columnLabel, SQLXML xmlObject) throws SQLException {
}
@Override
public String getNString(int columnIndex) throws SQLException {
return null;
}
@Override
public String getNString(String columnLabel) throws SQLException {
return null;
}
@Override
public Reader getNCharacterStream(int columnIndex) throws SQLException {
return null;
}
@Override
public Reader getNCharacterStream(String columnLabel) throws SQLException {
return null;
}
@Override
public void updateNCharacterStream(int columnIndex, Reader x, long length) throws SQLException {
}
@Override
public void updateNCharacterStream(String columnLabel, Reader reader, long length) throws SQLException {
}
@Override
public void updateAsciiStream(int columnIndex, InputStream x, long length) throws SQLException {
}
@Override
public void updateBinaryStream(int columnIndex, InputStream x, long length) throws SQLException {
}
@Override
public void updateCharacterStream(int columnIndex, Reader x, long length) throws SQLException {
}
@Override
public void updateAsciiStream(String columnLabel, InputStream x, long length) throws SQLException {
}
@Override
public void updateBinaryStream(String columnLabel, InputStream x, long length) throws SQLException {
}
@Override
public void updateCharacterStream(String columnLabel, Reader reader, long length) throws SQLException {
}
@Override
public void updateBlob(int columnIndex, InputStream inputStream, long length) throws SQLException {
}
@Override
public void updateBlob(String columnLabel, InputStream inputStream, long length) throws SQLException {
}
@Override
public void updateClob(int columnIndex, Reader reader, long length) throws SQLException {
}
@Override
public void updateClob(String columnLabel, Reader reader, long length) throws SQLException {
}
@Override
public void updateNClob(int columnIndex, Reader reader, long length) throws SQLException {
}
@Override
public void updateNClob(String columnLabel, Reader reader, long length) throws SQLException {
}
@Override
public void updateNCharacterStream(int columnIndex, Reader x) throws SQLException {
}
@Override
public void updateNCharacterStream(String columnLabel, Reader reader) throws SQLException {
}
@Override
public void updateAsciiStream(int columnIndex, InputStream x) throws SQLException {
}
@Override
public void updateBinaryStream(int columnIndex, InputStream x) throws SQLException {
}
@Override
public void updateCharacterStream(int columnIndex, Reader x) throws SQLException {
}
@Override
public void updateAsciiStream(String columnLabel, InputStream x) throws SQLException {
}
@Override
public void updateBinaryStream(String columnLabel, InputStream x) throws SQLException {
}
@Override
public void updateCharacterStream(String columnLabel, Reader reader) throws SQLException {
}
@Override
public void updateBlob(int columnIndex, InputStream inputStream) throws SQLException {
}
@Override
public void updateBlob(String columnLabel, InputStream inputStream) throws SQLException {
}
@Override
public void updateClob(int columnIndex, Reader reader) throws SQLException {
}
@Override
public void updateClob(String columnLabel, Reader reader) throws SQLException {
}
@Override
public void updateNClob(int columnIndex, Reader reader) throws SQLException {
}
@Override
public void updateNClob(String columnLabel, Reader reader) throws SQLException {
}
@Override
public <T> T getObject(int columnIndex, Class<T> type) throws SQLException {
return null;
}
@Override
public <T> T getObject(String columnLabel, Class<T> type) throws SQLException {
return null;
}
@Override
public <T> T unwrap(Class<T> iface) throws SQLException {
return null;
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
return false;
}
}

535
service/src/main/java/com/fanruan/jdbc/statement/MyPreparedStatement.java

@ -0,0 +1,535 @@
package com.fanruan.jdbc.statement;
import com.fanruan.jdbc.resultset.MyResultSet;
import com.fanruan.proxy.ProxyFactory;
import java.io.InputStream;
import java.io.Reader;
import java.math.BigDecimal;
import java.net.URL;
import java.sql.*;
import java.util.Calendar;
import java.util.Properties;
/**
* @author Yichen Dai
*/
public class MyPreparedStatement implements PreparedStatement {
private Properties info;
private String ID;
public MyPreparedStatement() {}
public String getID(){
return this.ID;
}
public void setID(String ID){
this.ID = ID;
}
public void setInfo(Properties info) {this.info = info;}
@Override
public ResultSet executeQuery() throws SQLException {
if(isClosed()) {
throw new SQLException("This Statement is closed.");
}
MyResultSet rs = (MyResultSet) ProxyFactory.getProxy(MyResultSet.class, info);
rs.setSql(info.getProperty("PreparedSQL"));
return rs;
}
@Override
public int executeUpdate() throws SQLException {
return 0;
}
@Override
public void setNull(int parameterIndex, int sqlType) throws SQLException {
}
@Override
public void setBoolean(int parameterIndex, boolean x) throws SQLException {
}
@Override
public void setByte(int parameterIndex, byte x) throws SQLException {
}
@Override
public void setShort(int parameterIndex, short x) throws SQLException {
}
@Override
public void setInt(int parameterIndex, int x) throws SQLException {
}
@Override
public void setLong(int parameterIndex, long x) throws SQLException {
}
@Override
public void setFloat(int parameterIndex, float x) throws SQLException {
}
@Override
public void setDouble(int parameterIndex, double x) throws SQLException {
}
@Override
public void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException {
}
@Override
public void setString(int parameterIndex, String x) throws SQLException {
}
@Override
public void setBytes(int parameterIndex, byte[] x) throws SQLException {
}
@Override
public void setDate(int parameterIndex, Date x) throws SQLException {
}
@Override
public void setTime(int parameterIndex, Time x) throws SQLException {
}
@Override
public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException {
}
@Override
public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException {
}
@Override
public void setUnicodeStream(int parameterIndex, InputStream x, int length) throws SQLException {
}
@Override
public void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException {
}
@Override
public void clearParameters() throws SQLException {
}
@Override
public void setObject(int parameterIndex, Object x, int targetSqlType) throws SQLException {
}
@Override
public void setObject(int parameterIndex, Object x) throws SQLException {
}
@Override
public boolean execute() throws SQLException {
return false;
}
@Override
public void addBatch() throws SQLException {
}
@Override
public void setCharacterStream(int parameterIndex, Reader reader, int length) throws SQLException {
}
@Override
public void setRef(int parameterIndex, Ref x) throws SQLException {
}
@Override
public void setBlob(int parameterIndex, Blob x) throws SQLException {
}
@Override
public void setClob(int parameterIndex, Clob x) throws SQLException {
}
@Override
public void setArray(int parameterIndex, Array x) throws SQLException {
}
@Override
public ResultSetMetaData getMetaData() throws SQLException {
return null;
}
@Override
public void setDate(int parameterIndex, Date x, Calendar cal) throws SQLException {
}
@Override
public void setTime(int parameterIndex, Time x, Calendar cal) throws SQLException {
}
@Override
public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) throws SQLException {
}
@Override
public void setNull(int parameterIndex, int sqlType, String typeName) throws SQLException {
}
@Override
public void setURL(int parameterIndex, URL x) throws SQLException {
}
@Override
public ParameterMetaData getParameterMetaData() throws SQLException {
return null;
}
@Override
public void setRowId(int parameterIndex, RowId x) throws SQLException {
}
@Override
public void setNString(int parameterIndex, String value) throws SQLException {
}
@Override
public void setNCharacterStream(int parameterIndex, Reader value, long length) throws SQLException {
}
@Override
public void setNClob(int parameterIndex, NClob value) throws SQLException {
}
@Override
public void setClob(int parameterIndex, Reader reader, long length) throws SQLException {
}
@Override
public void setBlob(int parameterIndex, InputStream inputStream, long length) throws SQLException {
}
@Override
public void setNClob(int parameterIndex, Reader reader, long length) throws SQLException {
}
@Override
public void setSQLXML(int parameterIndex, SQLXML xmlObject) throws SQLException {
}
@Override
public void setObject(int parameterIndex, Object x, int targetSqlType, int scaleOrLength) throws SQLException {
}
@Override
public void setAsciiStream(int parameterIndex, InputStream x, long length) throws SQLException {
}
@Override
public void setBinaryStream(int parameterIndex, InputStream x, long length) throws SQLException {
}
@Override
public void setCharacterStream(int parameterIndex, Reader reader, long length) throws SQLException {
}
@Override
public void setAsciiStream(int parameterIndex, InputStream x) throws SQLException {
}
@Override
public void setBinaryStream(int parameterIndex, InputStream x) throws SQLException {
}
@Override
public void setCharacterStream(int parameterIndex, Reader reader) throws SQLException {
}
@Override
public void setNCharacterStream(int parameterIndex, Reader value) throws SQLException {
}
@Override
public void setClob(int parameterIndex, Reader reader) throws SQLException {
}
@Override
public void setBlob(int parameterIndex, InputStream inputStream) throws SQLException {
}
@Override
public void setNClob(int parameterIndex, Reader reader) throws SQLException {
}
@Override
public ResultSet executeQuery(String sql) throws SQLException {
return null;
}
@Override
public int executeUpdate(String sql) throws SQLException {
return 0;
}
@Override
public void close() throws SQLException {
}
@Override
public int getMaxFieldSize() throws SQLException {
return 0;
}
@Override
public void setMaxFieldSize(int max) throws SQLException {
}
@Override
public int getMaxRows() throws SQLException {
return 0;
}
@Override
public void setMaxRows(int max) throws SQLException {
}
@Override
public void setEscapeProcessing(boolean enable) throws SQLException {
}
@Override
public int getQueryTimeout() throws SQLException {
return 0;
}
@Override
public void setQueryTimeout(int seconds) throws SQLException {
}
@Override
public void cancel() throws SQLException {
}
@Override
public SQLWarning getWarnings() throws SQLException {
return null;
}
@Override
public void clearWarnings() throws SQLException {
}
@Override
public void setCursorName(String name) throws SQLException {
}
@Override
public boolean execute(String sql) throws SQLException {
return false;
}
@Override
public ResultSet getResultSet() throws SQLException {
return null;
}
@Override
public int getUpdateCount() throws SQLException {
return 0;
}
@Override
public boolean getMoreResults() throws SQLException {
return false;
}
@Override
public void setFetchDirection(int direction) throws SQLException {
}
@Override
public int getFetchDirection() throws SQLException {
return 0;
}
@Override
public void setFetchSize(int rows) throws SQLException {
}
@Override
public int getFetchSize() throws SQLException {
return 0;
}
@Override
public int getResultSetConcurrency() throws SQLException {
return 0;
}
@Override
public int getResultSetType() throws SQLException {
return 0;
}
@Override
public void addBatch(String sql) throws SQLException {
}
@Override
public void clearBatch() throws SQLException {
}
@Override
public int[] executeBatch() throws SQLException {
return new int[0];
}
@Override
public Connection getConnection() throws SQLException {
return null;
}
@Override
public boolean getMoreResults(int current) throws SQLException {
return false;
}
@Override
public ResultSet getGeneratedKeys() throws SQLException {
return null;
}
@Override
public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException {
return 0;
}
@Override
public int executeUpdate(String sql, int[] columnIndexes) throws SQLException {
return 0;
}
@Override
public int executeUpdate(String sql, String[] columnNames) throws SQLException {
return 0;
}
@Override
public boolean execute(String sql, int autoGeneratedKeys) throws SQLException {
return false;
}
@Override
public boolean execute(String sql, int[] columnIndexes) throws SQLException {
return false;
}
@Override
public boolean execute(String sql, String[] columnNames) throws SQLException {
return false;
}
@Override
public int getResultSetHoldability() throws SQLException {
return 0;
}
@Override
public boolean isClosed() throws SQLException {
return false;
}
@Override
public void setPoolable(boolean poolable) throws SQLException {
}
@Override
public boolean isPoolable() throws SQLException {
return false;
}
@Override
public void closeOnCompletion() throws SQLException {
}
@Override
public boolean isCloseOnCompletion() throws SQLException {
return false;
}
@Override
public <T> T unwrap(Class<T> iface) throws SQLException {
return null;
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
return false;
}
}

252
service/src/main/java/com/fanruan/jdbc/statement/MyStatement.java

@ -0,0 +1,252 @@
package com.fanruan.jdbc.statement;
import com.fanruan.jdbc.resultset.MyResultSet;
import com.fanruan.proxy.ProxyFactory;
import java.sql.*;
import java.util.Properties;
public class MyStatement implements Statement {
private Properties info;
private String ID;
public MyStatement() {}
public String getID(){
return this.ID;
}
public void setID(String ID){
this.ID = ID;
}
public void setInfo(Properties info){
this.info = info;
}
@Override
public ResultSet executeQuery(String sql) throws SQLException {
if(isClosed()) {
throw new SQLException("This Statement is closed.");
}
MyResultSet rs = (MyResultSet) ProxyFactory.getProxy(MyResultSet.class, info);
rs.setSql(sql);
return rs;
}
@Override
public int executeUpdate(String sql) throws SQLException {
return 0;
}
@Override
public void close() throws SQLException {
}
@Override
public int getMaxFieldSize() throws SQLException {
return 0;
}
@Override
public void setMaxFieldSize(int max) throws SQLException {
}
@Override
public int getMaxRows() throws SQLException {
return 0;
}
@Override
public void setMaxRows(int max) throws SQLException {
}
@Override
public void setEscapeProcessing(boolean enable) throws SQLException {
}
@Override
public int getQueryTimeout() throws SQLException {
return 0;
}
@Override
public void setQueryTimeout(int seconds) throws SQLException {
}
@Override
public void cancel() throws SQLException {
}
@Override
public SQLWarning getWarnings() throws SQLException {
return null;
}
@Override
public void clearWarnings() throws SQLException {
}
@Override
public void setCursorName(String name) throws SQLException {
}
@Override
public boolean execute(String sql) throws SQLException {
return false;
}
@Override
public ResultSet getResultSet() throws SQLException {
return null;
}
@Override
public int getUpdateCount() throws SQLException {
return 0;
}
@Override
public boolean getMoreResults() throws SQLException {
return false;
}
@Override
public void setFetchDirection(int direction) throws SQLException {
}
@Override
public int getFetchDirection() throws SQLException {
return 0;
}
@Override
public void setFetchSize(int rows) throws SQLException {
}
@Override
public int getFetchSize() throws SQLException {
return 0;
}
@Override
public int getResultSetConcurrency() throws SQLException {
return 0;
}
@Override
public int getResultSetType() throws SQLException {
return 0;
}
@Override
public void addBatch(String sql) throws SQLException {
}
@Override
public void clearBatch() throws SQLException {
}
@Override
public int[] executeBatch() throws SQLException {
return new int[0];
}
@Override
public Connection getConnection() throws SQLException {
return null;
}
@Override
public boolean getMoreResults(int current) throws SQLException {
return false;
}
@Override
public ResultSet getGeneratedKeys() throws SQLException {
return null;
}
@Override
public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException {
return 0;
}
@Override
public int executeUpdate(String sql, int[] columnIndexes) throws SQLException {
return 0;
}
@Override
public int executeUpdate(String sql, String[] columnNames) throws SQLException {
return 0;
}
@Override
public boolean execute(String sql, int autoGeneratedKeys) throws SQLException {
return false;
}
@Override
public boolean execute(String sql, int[] columnIndexes) throws SQLException {
return false;
}
@Override
public boolean execute(String sql, String[] columnNames) throws SQLException {
return false;
}
@Override
public int getResultSetHoldability() throws SQLException {
return 0;
}
@Override
public boolean isClosed() throws SQLException {
return false;
}
@Override
public void setPoolable(boolean poolable) throws SQLException {
}
@Override
public boolean isPoolable() throws SQLException {
return false;
}
@Override
public void closeOnCompletion() throws SQLException {
}
@Override
public boolean isCloseOnCompletion() throws SQLException {
return false;
}
@Override
public <T> T unwrap(Class<T> iface) throws SQLException {
return null;
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
return false;
}
}

29
service/src/main/java/com/fanruan/pojo/message/RpcRequest.java

@ -0,0 +1,29 @@
package com.fanruan.pojo.message;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* @author Yichen Dai
*/
@Data
@Accessors(chain = true)
public class RpcRequest {
/**
* Marks whether the method delivered need loopback data
*/
private boolean reply;
/**
* Marks whether the method will create an instance requeired to be cached.
* In the project, they are Drive( MyDriver ), Connection( MyConnection ), Statement( MyStatement ),
* PreparedStatement( MyPreparedStatement ), ResultSet( MyResult ).
*/
private boolean binding;
private String ID;
private String IDToInvoke;
private Class serviceClass;
private String methodName;
private Object[] args;
private Class[] argTypes;
}

21
service/src/main/java/com/fanruan/pojo/message/RpcResponse.java

@ -0,0 +1,21 @@
package com.fanruan.pojo.message;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* @author Yichen Dai
*/
@Data
@Accessors(chain = true)
public class RpcResponse {
private String ID;
private Object result;
private boolean binding;
private Boolean status;
}

21
service/src/main/java/com/fanruan/proxy/ProxyFactory.java

@ -0,0 +1,21 @@
package com.fanruan.proxy;
import com.fanruan.proxy.interceptor.Interceptor;
import net.sf.cglib.proxy.Enhancer;
import java.util.Properties;
/**
* @author Yichen Dai
*/
public class ProxyFactory {
public static Object getProxy(Class<?> clazz, Properties info){
final Enhancer enhancer = new Enhancer();
enhancer.setClassLoader(clazz.getClassLoader());
enhancer.setSuperclass(clazz);
enhancer.setCallback(new Interceptor(clazz, info));
return enhancer.create();
}
}

146
service/src/main/java/com/fanruan/proxy/interceptor/Interceptor.java

@ -0,0 +1,146 @@
package com.fanruan.proxy.interceptor;
import com.corundumstudio.socketio.SocketIOClient;
import com.fanruan.ServerStater;
import com.fanruan.cache.ClientCache;
import com.fanruan.cache.ClientWrapper;
import com.fanruan.cache.LockAndCondition;
import com.fanruan.pojo.message.RpcRequest;
import com.fanruan.utils.Commons;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.lang.reflect.Method;
import java.util.Properties;
import java.util.concurrent.FutureTask;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author Yichen Dai
* cglib enhenced method to relize RPC
* For example, when service execute query operation,
* the RPC request will send to notify agent to do the same things,
* like create connection and statement
*/
public class Interceptor implements MethodInterceptor {
protected static final Logger logger = LogManager.getLogger();
private Class<?> clazz;
private SocketIOClient client;
private Properties info;
public Interceptor(Class<?> clazz, Properties info){
this.clazz = clazz;
this.info = info;
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
if(InterceptorUtils.isInExcludedList(method.getName())){
return methodProxy.invokeSuper(o, objects);
}
// Parameters injection of class MyDriver's construction method will be delayed util the first "connect" method was intercepted
// Because Driver Instance is registered on the DriverManager in the static code block,
// in which, the parameters used to fetch socket in cache is hard to pass in.
if(info == null){
info = (Properties) objects[1];
}
String agentId = info.getProperty("agentID");
String dbName = info.getProperty("agentDBName");
if(client == null){
client = ClientCache.getClient(agentId, dbName);
}
logger.debug("start invoke " + method.getName());
RpcRequest rpcRequest = new RpcRequest();
rpcRequest.setReply(false)
.setBinding(false)
.setID(Commons.getID())
.setServiceClass(clazz)
.setMethodName(method.getName())
.setArgs(objects)
.setArgTypes(getArgTypes(objects));
// Set whether the rpcResponses of this rpcRequest need to carry return value
if(o instanceof com.fanruan.jdbc.resultset.MyResultSet){
boolean flag = InterceptorUtils.isInReplyList(method.getName());
if(flag) {
rpcRequest.setReply(true);
}
}
// Some instance need to be bound one-to-one, to make sure the operator happen in service
// will be deliver to this specific corresponding instance.
if(InterceptorUtils.isInBindList(o)){
rpcRequest.setBinding(true);
}
// IDtoInvoke is an unique ID to identify an one-to-one binding relation.
// It comes from rpcRequest in which the instance in the agent is created.
String idToInvoke = InterceptorUtils.getInvokeHelper(o, "getID", String.class);
if(idToInvoke != null){
rpcRequest.setIDToInvoke(idToInvoke);
}
FutureTask<Object> futureTask = new FutureTask<>(
() -> {
Object res = null;
ClientWrapper wrapper = ClientCache.getClientWrapper(agentId, dbName);
LockAndCondition lac = wrapper.getLockAndCondition(rpcRequest.getID());
ReentrantLock lock = lac.getLock();
Condition condition = lac.getCondition();
lock.lock();
try{
byte[] bytes = ServerStater.SERIALIZER.serialize(rpcRequest);
client.sendEvent("RPCRequest", bytes);
condition.await();
// get res from RPC response data
res = lac.getResult();
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
return res;
}
);
ServerStater.threadPool.submit(futureTask);
Object res = futureTask.get();
// res is not null, it indicates the response carries data.
// if the type of res is primitive type, An error will occur when using cast(), just return them directly.
// And the data carried by response will never be the instance need to be bound.
if(res != null){
if(InterceptorUtils.isWraps(res)){
return res;
}
return res;
}
Object returnObj = methodProxy.invokeSuper(o, objects);
// If the return instance is corresponding with another instance in agent, set the binding ID.
if (InterceptorUtils.isInBindList(returnObj)){
InterceptorUtils.setInvokeHelper(returnObj, "setID", rpcRequest.getID());
}
return returnObj;
}
public Class<?>[] getArgTypes(Object[] objects){
int n = objects.length;
Class<?>[] argTypes = new Class[n];
for(int i=0; i<n; i++){
argTypes[i] = objects[i].getClass();
}
return argTypes;
}
}

118
service/src/main/java/com/fanruan/proxy/interceptor/InterceptorUtils.java

@ -0,0 +1,118 @@
package com.fanruan.proxy.interceptor;
import java.lang.reflect.Method;
import java.util.regex.Pattern;
/**
* @author Yichen Dai
*/
public class InterceptorUtils {
private static final String[] EXCLUDED_METHOD_LIST = new String[]{
"toString",
"hashCode",
"setInfo",
"setSql",
"getSql",
"setID",
"getID"
};
private static final String[] NEED_REPLY_LIST = new String[]{
"next",
};
private static final String[] WRAPPER_CLASS_LIST = new String[]{
"Boolean",
"Integer",
"Double",
"Long",
"Character",
"Byte",
"Short",
"Float"
};
private final static String[] BIND_LIST = new String[]{
".*MyDriver.*",
".*MyConnection.*",
".*MyStatement.*",
".*MyPreparedStatement.*",
".*MyResultSet.*",
};
public static boolean isInExcludedList(String methodName){
for(String ex : EXCLUDED_METHOD_LIST){
if(ex.equals(methodName)){
return true;
}
}
return false;
}
public static boolean isInReplyList(String methodName){
String pattern = "get.*";
boolean isMatch = Pattern.matches(pattern, methodName);
for(String ex : NEED_REPLY_LIST){
if(ex.equals(methodName)){
return true;
}
}
return isMatch;
}
public static boolean isWraps(Object o){
for(String ex : WRAPPER_CLASS_LIST){
if(ex.equals(getClassName(o.getClass().getName()))){
return true;
}
}
return false;
}
public static String getClassName(String fullyQualifiedClassName){
String[] arr = fullyQualifiedClassName.split("\\.");
int n = arr.length;
if(n == 0) {
throw new RuntimeException("the class name invoked is wrong");
}
return arr[n-1];
}
public static boolean isInBindList(Object o){
if (o == null) {
return false;
}
return isInBindList(o.getClass().getName());
}
public static boolean isInBindList(String className){
for(String pattern : BIND_LIST){
if(Pattern.matches(pattern, className)){
return true;
}
}
return false;
}
public static void setInvokeHelper(Object o, String methodName, String ID){
try {
Method method = o.getClass().getDeclaredMethod(methodName, String.class);
method.invoke(o, ID);
} catch (Exception e) {
e.printStackTrace();
}
}
public static <T> T getInvokeHelper(Object o, String methodName, Class<?> T){
try {
Method method = o.getClass().getDeclaredMethod(methodName);
T res = (T) method.invoke(o);
return res;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}

54
service/src/main/java/com/fanruan/serializer/KryoSerializer.java

@ -0,0 +1,54 @@
package com.fanruan.serializer;
import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import com.fanruan.pojo.message.RpcRequest;
import com.fanruan.pojo.message.RpcResponse;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
/**
* @author Yichen Dai
*/
public class KryoSerializer implements Serializer {
private static final ThreadLocal<Kryo> kryoThreadLocal = ThreadLocal.withInitial(() -> {
final Kryo kryo = new Kryo();
kryo.register(RpcRequest.class);
kryo.register(RpcResponse.class);
kryo.setReferences(true);
kryo.setRegistrationRequired(false);
return kryo;
});
@Override
public byte[] serialize(Object object) {
try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
Output output = new Output(byteArrayOutputStream)) {
final Kryo kryo = kryoThreadLocal.get();
kryo.writeObject(output, object);
kryoThreadLocal.remove();
return output.toBytes();
} catch (IOException e) {
e.printStackTrace();
}
return new byte[0];
}
@Override
public <T> T deserialize(byte[] bytes, Class<T> clazz) {
try (ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
Input input = new Input(byteArrayInputStream)) {
final Kryo kryo = kryoThreadLocal.get();
final Object o = kryo.readObject(input, clazz);
kryoThreadLocal.remove();
return clazz.cast(o);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}

21
service/src/main/java/com/fanruan/serializer/Serializer.java

@ -0,0 +1,21 @@
package com.fanruan.serializer;
/**
* @author Yichen Dai
*/
public interface Serializer {
/**
* Use to serialize a object to a byte array
* @param object to be serialized
* @return byte[] serialized data with the format of byte array
*/
byte[] serialize(Object object);
/**
* Use to deserialize a byte array to a class with designate class
* @param bytes Serialized data with the format of byte array
* @param clazz The class of the object to be deserialized
* @return object as designate class
*/
<T> T deserialize(byte[] bytes, Class<T> clazz);
}

47
service/src/main/java/com/fanruan/utils/Commons.java

@ -0,0 +1,47 @@
package com.fanruan.utils;
import com.corundumstudio.socketio.SocketIOClient;
import java.util.Calendar;
import java.util.Random;
/**
* @author Yichen Dai
*/
public class Commons {
static public String getAgentID(SocketIOClient client){
return client.getHandshakeData().getSingleUrlParam("agentID");
}
static public String getDBName(SocketIOClient client){
// the format of spaceNamed "/" + "dbName"
// default name space named as "/"
String spaceName = client.getNamespace().getName();
String dbName;
if(spaceName.length() > 1) {
dbName = spaceName.substring(1);
}else{
dbName = spaceName;
}
return dbName;
}
public static String getID(){
return getTimeInMillis() + getRandom();
}
public static String getTimeInMillis() {
long timeInMillis = Calendar.getInstance().getTimeInMillis();
return timeInMillis+"";
}
public static String getRandom() {
Random random = new Random();
int nextInt = random.nextInt(9000000);
nextInt = nextInt + 1000000;
return nextInt+"";
}
}

21
service/src/main/java/com/fanruan/utils/DBProperties.java

@ -0,0 +1,21 @@
package com.fanruan.utils;
/**
* @author Yichen Dai
*/
public class DBProperties {
public static final String MYSQL = "mysql";
public static final String POSTGRESQL = "postgresql";
public static final String ORACLE = "oracle";
public static final String SQLSERVER = "sqlserver";
public static final String DB2 = "db2";
public static final String HSQL = "hsql";
public static final String MYSQL_DRIVER_NAME = "com.mysql.cj.jdbc.Driver";
public static final String POSTGRESQL_DRIVER_NAME = "org.postgresql.Driver";
public static final String ORACLE_DRIVER_NAME = "oracle.jdbc.driver.OracleDriver";
public static final String SQLSERVER_DRIVER_NAME = "com.microsoft.jdbc.sqlserver.SQLServerDriver";
public static final String DB2_DRIVER_NAME = "com.ibm.db2.jdbc.app.DB2Driver";
public static final String HSQL_DRIVER_NAME = "org.hsqldb.jdbcDriver";
}

11
service/src/main/resources/log4j2.properties

@ -0,0 +1,11 @@
# Console appender configuration
appender.console.type = Console
appender.console.name = STDOUT
appender.console.layout.type = PatternLayout
appender.console.layout.pattern = [%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c{1} - %msg%n
rootLogger.level = info
rootLogger.appenderRefs = stdout
rootLogger.appenderRef.stdout.ref = STDOUT

23
service/src/main/resources/socketIO.properties

@ -0,0 +1,23 @@
#============================================================================
# netty socket io setting
#============================================================================
# host在本地测试可以设置为localhost或者本机IP,在Linux服务器跑可换成服务器IP
#监听的ip
host = 127.0.0.1
#监听端口
port = 10246
# 设置最大每帧处理数据的长度,防止他人利用大数据来攻击服务器
maxFramePayloadLength = 1048576
# 设置http交互最大内容长度
maxHttpContentLength = 1048576
# socket连接数大小(如只监听一个端口boss线程组为1即可)
bossCount = 1
workCount = 10
allowCustomRequests = true
# 协议升级超时时间(毫秒),默认10秒。HTTP握手升级为ws协议超时时间
upgradeTimeout = 1000000
# Ping消息超时时间(毫秒),默认60秒,这个时间间隔内没有接收到心跳消息就会发送超时事件
pingTimeout = 6000000
# Ping消息间隔(毫秒),默认25秒。客户端向服务器发送一条心跳消息间隔
pingInterval = 25000

22
service/src/test/java/AutoStarter.java

@ -0,0 +1,22 @@
import com.fanruan.ServerStater;
import com.fanruan.utils.DBProperties;
/**
* @author Yichen Dai
* @date 2022/8/18 9:54
*/
public class AutoStarter {
static {
String[] DBs = new String[]{
DBProperties.HSQL,
};
new ServerStater(DBs);
try {
Class.forName("com.fanruan.jdbc.driver.MyDriver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}

105
service/src/test/java/ServiceTest.java

@ -0,0 +1,105 @@
import com.corundumstudio.socketio.SocketIOClient;
import com.corundumstudio.socketio.SocketIOServer;
import com.fanruan.cache.ClientCache;
import com.fanruan.utils.DBProperties;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.net.Socket;
import java.sql.*;
import java.util.Properties;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
/**
* @author Yichen Dai
* @date 2022/8/18 9:49
*/
public class ServiceTest extends AutoStarter{
@BeforeEach
void listen() throws ExecutionException, InterruptedException {
FutureTask<SocketIOClient> ft = new FutureTask<>(
() -> {
while(ClientCache.getClient("1001", DBProperties.HSQL) == null){
try {
Thread.sleep(100);
}catch (Exception e){
e.printStackTrace();
}
}
return ClientCache.getClient("1001", DBProperties.HSQL);
}
);
ft.run();
ft.get();
}
@Test
void testCURD(){
Properties info = new Properties();
info.setProperty("user", "sa");
info.setProperty("password", "");
info.setProperty("agentID", "1001");
info.setProperty("agentDBName", DBProperties.HSQL);
Connection conn = null;
Statement st = null;
PreparedStatement pst = null;
ResultSet rs = null;
try {
conn = DriverManager.getConnection("jdbc:hsqldb:mem:test", info);
st = conn.createStatement();
st.executeUpdate("DROP TABLE student IF EXISTS;");
st.executeUpdate("CREATE TABLE student (" +
"student_id INTEGER GENERATED BY DEFAULT AS IDENTITY " +
"(START WITH 1, INCREMENT BY 1) NOT NULL," +
"student_name VARCHAR(100) NOT NULL," +
"student_address VARCHAR(100) NOT NULL," +
"PRIMARY KEY (student_id)" +
");");
st.executeUpdate("INSERT INTO student VALUES" +
"(1, '张三', '上海')," +
"(2, '李四', '北京')," +
"(3, '王五', '成都');");
pst = conn.prepareStatement("delete from student where student_id = ?");
pst.setInt(1, 1);
pst.executeUpdate();
rs = st.executeQuery("select * from student");
String[] nameStrings = new String[]{"张三", "李四", "王五"};
String[] addressStrings = new String[]{"上海", "北京", "成都"};
int num = 2;
while(rs.next()) {
Assertions.assertEquals(rs.getInt("student_id"), num);
Assertions.assertEquals(rs.getString("student_name"), nameStrings[num-1]);
Assertions.assertEquals(rs.getString("student_address"), addressStrings[num-1]);
num++;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try{
rs.close();
st.close();
pst.close();
conn.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
}

244
service/src/test/java/Test.java

@ -0,0 +1,244 @@
import com.fanruan.ServerStater;
import com.fanruan.cache.ClientCache;
import com.fanruan.utils.DBProperties;
import java.sql.*;
import java.util.Properties;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Test {
public static void main(String[] args) {
Test test = new Test();
String[] DBs = new String[]{
DBProperties.MYSQL,
DBProperties.POSTGRESQL,
// DBProperties.SQLSERVER,
// DBProperties.DB2,
// DBProperties.ORACLE
};
new ServerStater(DBs);
ExecutorService threadPool = Executors.newSingleThreadExecutor();
test.testPostSQL(threadPool);
test.testMySQL(threadPool);
}
public void testMySQL(ExecutorService threadPool){
Thread thread = new Thread(() -> {
while(ClientCache.getClient("1001", "mysql") == null){
try {
Thread.sleep(1000);
}catch (Exception e){
e.printStackTrace();
}
}
Properties info = new Properties();
info.setProperty("user", "root");
info.setProperty("password", "850656");
info.setProperty("agentID", "1001");
info.setProperty("agentDBName", "mysql");
Connection conn = null;
Statement st = null;
PreparedStatement pst = null;
PreparedStatement pst2 = null;
ResultSet rs1 = null;
ResultSet rs2 = null;
ResultSet rs3 = null;
try {
Class.forName("com.fanruan.jdbc.driver.MyDriver");
conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test", info);
st = conn.createStatement();
rs1 = st.executeQuery("select * from `student`");
System.out.println("-----------");
System.out.println("执行查询语句");
while(rs1.next()) {
System.out.print(rs1.getInt("student_id") + " ");
System.out.print(rs1.getString("student_name")+ " ");
System.out.println(rs1.getString("student_address")+ " ");
}
String sql = "select * from `student` where `student_name`= ?";
pst = conn.prepareStatement(sql);
pst.setString(1, "张三");
rs2 = pst.executeQuery();
System.out.println("-----------");
System.out.println("执行预查询语句1");
while(rs2.next()) {
System.out.print(rs2.getInt("student_id") + " ");
System.out.print(rs2.getString("student_name")+ " ");
System.out.println(rs2.getString("student_address")+ " ");
}
sql = "select * from `student` where `student_address`= ?";
pst2 = conn.prepareStatement(sql);
pst2.setString(1, "上海");
rs3 = pst2.executeQuery();
System.out.println("-----------");
System.out.println("执行预查询语句2");
while(rs3.next()) {
System.out.print(rs3.getInt("student_id") + " ");
System.out.print(rs3.getString("student_name")+ " ");
System.out.println(rs3.getString("student_address")+ " ");
}
}catch (Exception e) {
e.printStackTrace();
} finally {
// 7、关闭对象,回收数据库资源
if (rs1 != null) { //关闭结果集对象
try {
rs1.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (rs2 != null) { //关闭结果集对象
try {
rs2.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (st != null) { // 关闭数据库操作对象
try {
st.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (pst != null) { // 关闭数据库操作对象
try {
pst.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn != null) { // 关闭数据库连接对象
try {
if (!conn.isClosed()) {
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
});
threadPool.execute(thread);
}
public void testPostSQL(ExecutorService threadPool){
Thread thread = new Thread(() -> {
while(ClientCache.getClient("1001", "postgresql") == null){
try {
Thread.sleep(1000);
}catch (Exception e){
e.printStackTrace();
}
}
Properties info = new Properties();
info.setProperty("user", "postgres");
info.setProperty("password", "850656");
info.setProperty("agentID", "1001");
info.setProperty("agentDBName", "postgresql");
Connection conn = null;
Statement st = null;
PreparedStatement pst = null;
PreparedStatement pst2 = null;
ResultSet rs1 = null;
ResultSet rs2 = null;
ResultSet rs3 = null;
try {
Class.forName("com.fanruan.jdbc.driver.MyDriver");
conn = DriverManager.getConnection("jdbc:postgresql://127.0.0.1:5432/test", info);
st = conn.createStatement();
rs1 = st.executeQuery("select * from student");
System.out.println("-----------");
System.out.println("执行查询语句");
while(rs1.next()) {
System.out.print(rs1.getInt("student_id") + " ");
System.out.print(rs1.getString("student_name")+ " ");
System.out.println(rs1.getString("student_address")+ " ");
}
String sql = "select * from student where student_name= ?";
pst = conn.prepareStatement(sql);
pst.setString(1, "张三");
rs2 = pst.executeQuery();
System.out.println("-----------");
System.out.println("执行预查询语句1");
while(rs2.next()) {
System.out.print(rs2.getInt("student_id") + " ");
System.out.print(rs2.getString("student_name")+ " ");
System.out.println(rs2.getString("student_address")+ " ");
}
sql = "select * from student where student_address = ?";
pst2 = conn.prepareStatement(sql);
pst2.setString(1, "上海");
rs3 = pst2.executeQuery();
System.out.println("-----------");
System.out.println("执行预查询语句2");
while(rs3.next()) {
System.out.print(rs3.getInt("student_id") + " ");
System.out.print(rs3.getString("student_name")+ " ");
System.out.println(rs3.getString("student_address")+ " ");
}
}catch (Exception e) {
e.printStackTrace();
} finally {
// 7、关闭对象,回收数据库资源
if (rs1 != null) { //关闭结果集对象
try {
rs1.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (rs2 != null) { //关闭结果集对象
try {
rs2.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (st != null) { // 关闭数据库操作对象
try {
st.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (pst != null) { // 关闭数据库操作对象
try {
pst.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn != null) { // 关闭数据库连接对象
try {
if (!conn.isClosed()) {
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
});
threadPool.execute(thread);
}
}

8
service/src/test/java/TestUtils.java

@ -0,0 +1,8 @@
/**
* @author Yichen Dai
* @date 2022/8/16 11:36
*/
public class TestUtils {
}
Loading…
Cancel
Save