Browse Source

integration testing : Connection ans CallableStatement

pull/1/head
yichen 2 years ago
parent
commit
d5eaff0146
  1. 17
      agent/pom.xml
  2. 9
      agent/src/main/java/com/fanruan/AgentStarter.java
  3. 73
      agent/src/main/java/com/fanruan/agent/jdbc/AgentArray.java
  4. 73
      agent/src/main/java/com/fanruan/agent/jdbc/AgentBlob.java
  5. 85
      agent/src/main/java/com/fanruan/agent/jdbc/AgentClob.java
  6. 895
      agent/src/main/java/com/fanruan/agent/jdbc/AgentDataBaseMetaData.java
  7. 73
      agent/src/main/java/com/fanruan/agent/jdbc/AgentParameterMetaData.java
  8. 32
      agent/src/main/java/com/fanruan/agent/jdbc/AgentStruct.java
  9. 25
      agent/src/main/java/com/fanruan/agent/jdbc/connection/AgentConnection.java
  10. 1084
      agent/src/main/java/com/fanruan/agent/jdbc/statement/AgentCallableStatement.java
  11. 3
      agent/src/main/java/com/fanruan/agent/jdbc/statement/AgentStatement.java
  12. 8
      agent/src/main/java/com/fanruan/cache/BeanCache.java
  13. 5
      agent/src/main/java/com/fanruan/cache/BeanCacheImpl.java
  14. 7
      agent/src/main/java/com/fanruan/cache/Cache.java
  15. 13
      agent/src/main/java/com/fanruan/cache/CacheImpl.java
  16. 28
      agent/src/main/java/com/fanruan/handler/DispatcherHelper.java
  17. 34
      agent/src/main/java/com/fanruan/handler/DispatcherImpl.java
  18. 4
      agent/src/main/java/com/fanruan/handler/ResponseEmitter.java
  19. 4
      agent/src/main/java/com/fanruan/handler/ResponseEmitterImpl.java
  20. 1
      agent/src/main/java/com/fanruan/pojo/message/RpcRequest.java
  21. 29
      agent/src/test/java/HSQLTest.java
  22. 3
      agent/src/test/java/Test.java
  23. 14
      agent/src/test/java/TestSuite.java
  24. 24
      agent/src/test/java/com/fanruan/cache/BeanCacheImplTest.java
  25. 44
      agent/src/test/java/com/fanruan/cache/CacheImplTest.java
  26. 71
      agent/src/test/java/com/fanruan/handler/DispatcherHelperTest.java
  27. 27
      agent/src/test/java/com/fanruan/handler/DispatcherImplTest.java
  28. BIN
      pic/project structure.jpg
  29. 13
      service/pom.xml
  30. 6
      service/src/main/java/com/fanruan/ServerStater.java
  31. 1
      service/src/main/java/com/fanruan/pojo/message/RpcRequest.java
  32. 22
      service/src/test/java/AutoStarter.java
  33. 2
      service/src/test/java/ServiceTest.java
  34. 13
      service/src/test/java/TestSuite.java
  35. 15
      test/pom.xml
  36. 16
      test/src/test/java/TestSuite.java
  37. 170
      test/src/test/java/TestUtil.java
  38. 58
      test/src/test/java/com/fanruan/AbstractDriverTest.java
  39. 1171
      test/src/test/java/com/fanruan/AgentCallableStatementTest.java
  40. 432
      test/src/test/java/com/fanruan/BaseJDBCTest.java
  41. 314
      test/src/test/java/com/fanruan/ConnectionTest.java
  42. 21
      test/src/test/java/com/fanruan/DatabaseMetaDataTest.java
  43. 38
      test/src/test/java/com/fanruan/InterceptorIT.java
  44. 23
      test/src/test/java/com/fanruan/ProxyFactoryIT.java
  45. 183
      test/src/test/java/com/fanruan/TestUtil.java

17
agent/pom.xml

@ -76,13 +76,26 @@
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api -->
<!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-engine -->
<dependency> <dependency>
<groupId>org.junit.jupiter</groupId> <groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId> <artifactId>junit-jupiter-engine</artifactId>
<version>5.4.0</version> <version>5.9.0</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<!-- https://mvnrepository.com/artifact/org.junit.platform/junit-platform-suite-engine -->
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-suite-engine</artifactId>
<version>1.9.0</version>
<scope>test</scope>
</dependency>
</dependencies> </dependencies>
</project> </project>

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

@ -16,6 +16,7 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.net.URI; import java.net.URI;
import java.util.List;
import java.util.Properties; import java.util.Properties;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -37,7 +38,6 @@ public class AgentStarter {
dispatcherImpl = new DispatcherImpl(); dispatcherImpl = new DispatcherImpl();
try { try {
createSocket(DBs); createSocket(DBs);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
@ -94,6 +94,13 @@ public class AgentStarter {
} }
} }
public void shutDown(){
List<Socket> sockets = DispatcherImpl.CACHE.getSockets();
for(Socket socket : sockets){
socket.close();
}
}
private void configDefaultSocket(Socket socket) throws IOException { private void configDefaultSocket(Socket socket) throws IOException {
socket.on(Socket.EVENT_CONNECT, objects -> { socket.on(Socket.EVENT_CONNECT, objects -> {
logger.info("default-socket connected!"); logger.info("default-socket connected!");

73
agent/src/main/java/com/fanruan/agent/jdbc/AgentArray.java

@ -0,0 +1,73 @@
package com.fanruan.agent.jdbc;
import java.sql.Array;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Map;
/**
* @author Yichen Dai
* @date 2022/8/31 16:52
*/
public class AgentArray implements Array {
Array array;
AgentArray(Array array){
this.array = array;
}
@Override
public String getBaseTypeName() throws SQLException {
return array.getBaseTypeName();
}
@Override
public int getBaseType() throws SQLException {
return array.getBaseType();
}
@Override
public Object getArray() throws SQLException {
return array.getArray();
}
@Override
public Object getArray(Map<String, Class<?>> map) throws SQLException {
return array.getArray(map);
}
@Override
public Object getArray(long index, int count) throws SQLException {
return array.getArray(index, count);
}
@Override
public Object getArray(long index, int count, Map<String, Class<?>> map) throws SQLException {
return array.getArray(index, count, map);
}
@Override
public ResultSet getResultSet() throws SQLException {
return array.getResultSet();
}
@Override
public ResultSet getResultSet(Map<String, Class<?>> map) throws SQLException {
return array.getResultSet(map);
}
@Override
public ResultSet getResultSet(long index, int count) throws SQLException {
return array.getResultSet(index, count);
}
@Override
public ResultSet getResultSet(long index, int count, Map<String, Class<?>> map) throws SQLException {
return array.getResultSet(index, count, map);
}
@Override
public void free() throws SQLException {
array.free();
}
}

73
agent/src/main/java/com/fanruan/agent/jdbc/AgentBlob.java

@ -0,0 +1,73 @@
package com.fanruan.agent.jdbc;
import java.io.InputStream;
import java.io.OutputStream;
import java.sql.Blob;
import java.sql.SQLException;
/**
* @author Yichen Dai
* @date 2022/8/29 20:33
*/
public class AgentBlob implements Blob {
private Blob blob;
AgentBlob(Blob blob){
this.blob = blob;
}
@Override
public long length() throws SQLException {
return blob.length();
}
@Override
public byte[] getBytes(long pos, int length) throws SQLException {
return blob.getBytes(pos, length);
}
@Override
public InputStream getBinaryStream() throws SQLException {
return blob.getBinaryStream();
}
@Override
public long position(byte[] pattern, long start) throws SQLException {
return blob.position(pattern, start);
}
@Override
public long position(Blob pattern, long start) throws SQLException {
return blob.position(pattern, start);
}
@Override
public int setBytes(long pos, byte[] bytes) throws SQLException {
return blob.setBytes(pos, bytes);
}
@Override
public int setBytes(long pos, byte[] bytes, int offset, int len) throws SQLException {
return blob.setBytes(pos, bytes, offset, len);
}
@Override
public OutputStream setBinaryStream(long pos) throws SQLException {
return blob.setBinaryStream(pos);
}
@Override
public void truncate(long len) throws SQLException {
blob.truncate(len);
}
@Override
public void free() throws SQLException {
blob.free();
}
@Override
public InputStream getBinaryStream(long pos, long length) throws SQLException {
return blob.getBinaryStream(pos, length);
}
}

85
agent/src/main/java/com/fanruan/agent/jdbc/AgentClob.java

@ -0,0 +1,85 @@
package com.fanruan.agent.jdbc;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.io.Writer;
import java.sql.Clob;
import java.sql.SQLException;
/**
* @author Yichen Dai
* @date 2022/8/29 20:34
*/
public class AgentClob implements Clob {
private Clob clob;
AgentClob(Clob clob){
this.clob = clob;
}
@Override
public long length() throws SQLException {
return clob.length();
}
@Override
public String getSubString(long pos, int length) throws SQLException {
return clob.getSubString(pos, length);
}
@Override
public Reader getCharacterStream() throws SQLException {
return clob.getCharacterStream();
}
@Override
public InputStream getAsciiStream() throws SQLException {
return clob.getAsciiStream();
}
@Override
public long position(String searchstr, long start) throws SQLException {
return clob.position(searchstr, start);
}
@Override
public long position(Clob searchstr, long start) throws SQLException {
return clob.position(searchstr, start);
}
@Override
public int setString(long pos, String str) throws SQLException {
return clob.setString(pos, str);
}
@Override
public int setString(long pos, String str, int offset, int len) throws SQLException {
return clob.setString(pos, str, offset, len);
}
@Override
public OutputStream setAsciiStream(long pos) throws SQLException {
return clob.setAsciiStream(pos);
}
@Override
public Writer setCharacterStream(long pos) throws SQLException {
return clob.setCharacterStream(pos);
}
@Override
public void truncate(long len) throws SQLException {
clob.truncate(len);
}
@Override
public void free() throws SQLException {
clob.free();
}
@Override
public Reader getCharacterStream(long pos, long length) throws SQLException {
return clob.getCharacterStream(pos, length);
}
}

895
agent/src/main/java/com/fanruan/agent/jdbc/AgentDataBaseMetaData.java

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

73
agent/src/main/java/com/fanruan/agent/jdbc/AgentParameterMetaData.java

@ -0,0 +1,73 @@
package com.fanruan.agent.jdbc;
import java.sql.ParameterMetaData;
import java.sql.SQLException;
/**
* @author Yichen Dai
* @date 2022/8/25 16:41
*/
public class AgentParameterMetaData implements ParameterMetaData {
private ParameterMetaData metaData;
public AgentParameterMetaData(ParameterMetaData metaData){
this.metaData = metaData;
}
@Override
public int getParameterCount() throws SQLException {
return metaData.getParameterCount();
}
@Override
public int isNullable(int param) throws SQLException {
return metaData.isNullable(param);
}
@Override
public boolean isSigned(int param) throws SQLException {
return metaData.isSigned(param);
}
@Override
public int getPrecision(int param) throws SQLException {
return metaData.getPrecision(param);
}
@Override
public int getScale(int param) throws SQLException {
return metaData.getScale(param);
}
@Override
public int getParameterType(int param) throws SQLException {
return metaData.getParameterType(param);
}
@Override
public String getParameterTypeName(int param) throws SQLException {
return metaData.getParameterTypeName(param);
}
@Override
public String getParameterClassName(int param) throws SQLException {
return metaData.getParameterClassName(param);
}
@Override
public int getParameterMode(int param) throws SQLException {
return metaData.getParameterMode(param);
}
@Override
public <T> T unwrap(Class<T> iface) throws SQLException {
return metaData.unwrap(iface);
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
return metaData.isWrapperFor(iface);
}
}

32
agent/src/main/java/com/fanruan/agent/jdbc/AgentStruct.java

@ -0,0 +1,32 @@
package com.fanruan.agent.jdbc;
import java.sql.SQLException;
import java.sql.Struct;
import java.util.Map;
/**
* @author Yichen Dai
* @date 2022/8/31 17:04
*/
public class AgentStruct implements Struct {
Struct struct;
AgentStruct(Struct struct){
this.struct = struct;
}
@Override
public String getSQLTypeName() throws SQLException {
return null;
}
@Override
public Object[] getAttributes() throws SQLException {
return new Object[0];
}
@Override
public Object[] getAttributes(Map<String, Class<?>> map) throws SQLException {
return new Object[0];
}
}

25
agent/src/main/java/com/fanruan/agent/jdbc/connection/AgentConnection.java

@ -1,5 +1,7 @@
package com.fanruan.agent.jdbc.connection; package com.fanruan.agent.jdbc.connection;
import com.fanruan.agent.jdbc.AgentDataBaseMetaData;
import com.fanruan.agent.jdbc.statement.AgentCallableStatement;
import com.fanruan.agent.jdbc.statement.AgentPreparedStatement; import com.fanruan.agent.jdbc.statement.AgentPreparedStatement;
import com.fanruan.agent.jdbc.statement.AgentStatement; import com.fanruan.agent.jdbc.statement.AgentStatement;
@ -32,7 +34,8 @@ public class AgentConnection implements Connection {
@Override @Override
public CallableStatement prepareCall(String sql) throws SQLException { public CallableStatement prepareCall(String sql) throws SQLException {
return conn.prepareCall(sql); CallableStatement cst = this.conn.prepareCall(sql);
return new AgentCallableStatement(cst);
} }
@Override @Override
@ -72,7 +75,7 @@ public class AgentConnection implements Connection {
@Override @Override
public DatabaseMetaData getMetaData() throws SQLException { public DatabaseMetaData getMetaData() throws SQLException {
return conn.getMetaData(); return new AgentDataBaseMetaData(conn.getMetaData());
} }
@Override @Override
@ -117,17 +120,17 @@ public class AgentConnection implements Connection {
@Override @Override
public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException {
return conn.createStatement(resultSetType, resultSetConcurrency); return new AgentStatement(conn.createStatement(resultSetType, resultSetConcurrency));
} }
@Override @Override
public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
return conn.prepareStatement(sql, resultSetType, resultSetConcurrency); return new AgentPreparedStatement(conn.prepareStatement(sql, resultSetType, resultSetConcurrency));
} }
@Override @Override
public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
return conn.prepareCall(sql, resultSetType, resultSetConcurrency); return new AgentCallableStatement(conn.prepareCall(sql, resultSetType, resultSetConcurrency));
} }
@Override @Override
@ -172,32 +175,32 @@ public class AgentConnection implements Connection {
@Override @Override
public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
return conn.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability); return new AgentStatement(conn.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability));
} }
@Override @Override
public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
return conn.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability); return new AgentPreparedStatement(conn.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability));
} }
@Override @Override
public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
return conn.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability); return new AgentCallableStatement(conn.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability));
} }
@Override @Override
public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {
return conn.prepareStatement(sql, autoGeneratedKeys); return new AgentPreparedStatement(conn.prepareStatement(sql, autoGeneratedKeys));
} }
@Override @Override
public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException { public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException {
return conn.prepareStatement(sql, columnIndexes); return new AgentPreparedStatement(conn.prepareStatement(sql, columnIndexes));
} }
@Override @Override
public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException { public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException {
return conn.prepareStatement(sql, columnNames); return new AgentPreparedStatement(conn.prepareStatement(sql, columnNames));
} }
@Override @Override

1084
agent/src/main/java/com/fanruan/agent/jdbc/statement/AgentCallableStatement.java

File diff suppressed because it is too large Load Diff

3
agent/src/main/java/com/fanruan/agent/jdbc/statement/AgentStatement.java

@ -4,6 +4,9 @@ import com.fanruan.agent.jdbc.resultset.AgentResultSet;
import java.sql.*; import java.sql.*;
/**
* @author Yichen Dai
*/
public class AgentStatement implements Statement { public class AgentStatement implements Statement {
final private Statement st; final private Statement st;

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

@ -31,4 +31,12 @@ public interface BeanCache {
*/ */
void cacheInstance(String ID, Object o); void cacheInstance(String ID, Object o);
/**
* verify whether the Instance is exit
* @param ID The unique num of a cache instance, It comes from the RPC request ID,
* which asked to create the instance.
* @return if it exits, true, otherwise false.
*/
boolean containsInstance(String ID);
} }

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

@ -38,4 +38,9 @@ public class BeanCacheImpl implements BeanCache{
public void cacheInstance(String ID, Object o){ public void cacheInstance(String ID, Object o){
CACHE.put(ID, o); CACHE.put(ID, o);
} }
@Override
public boolean containsInstance(String ID) {
return CACHE.containsKey(ID);
}
} }

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

@ -2,6 +2,7 @@ package com.fanruan.cache;
import io.socket.client.Socket; import io.socket.client.Socket;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
@ -37,6 +38,12 @@ public interface Cache {
*/ */
Socket getSocket(String dbName); Socket getSocket(String dbName);
/**
* get sockets
* @return a list of socket
*/
List<Socket> getSockets();
/** /**
* register the socket of specific nameSpace/db * register the socket of specific nameSpace/db
* @param dbName the key of cache * @param dbName the key of cache

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

@ -2,6 +2,10 @@ package com.fanruan.cache;
import io.socket.client.Socket; import io.socket.client.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/** /**
* @author Yichen Dai * @author Yichen Dai
* @date 2022/8/16 16:13 * @date 2022/8/16 16:13
@ -22,6 +26,15 @@ public class CacheImpl implements Cache{
return socket; return socket;
} }
@Override
public List<Socket> getSockets() {
List<Socket> res = new ArrayList<>();
for(Map.Entry<String, Socket> e : SOCKET_MAP.entrySet()){
res.add(e.getValue());
}
return res;
}
@Override @Override
public void registerBeanCache(String dbName, BeanCacheImpl beanCache) { public void registerBeanCache(String dbName, BeanCacheImpl beanCache) {
BEAN_CACHE.put(dbName, beanCache); BEAN_CACHE.put(dbName, beanCache);

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

@ -30,10 +30,25 @@ public class DispatcherHelper {
"Statement", "Statement",
"PreparedStatement", "PreparedStatement",
"ResultSet", "ResultSet",
"MetaData",
"Clob",
"Blob",
"Array",
"Struct"
}; };
public static boolean isInCacheList(Object obj){
if(obj == null) {
return false;
}
return isInCacheList(obj.getClass().getName());
}
public static boolean isInCacheList(String className){ public static boolean isInCacheList(String className){
if (className == null){
return false;
}
for(String s : CACHE_LIST){ for(String s : CACHE_LIST){
if(Pattern.matches(".*" + s + ".*", className)){ if(Pattern.matches(".*" + s + ".*", className)){
return true; return true;
@ -43,6 +58,9 @@ public class DispatcherHelper {
} }
public static boolean isWraps(Class<?> clz){ public static boolean isWraps(Class<?> clz){
if(clz == null) {
return false;
}
return WRAPPER_CLASS_MAP.containsKey(getClassName(clz.getName())); return WRAPPER_CLASS_MAP.containsKey(getClassName(clz.getName()));
} }
@ -51,15 +69,11 @@ public class DispatcherHelper {
} }
public static String getClassName(String fullyQualifiedClassName){ public static String getClassName(String fullyQualifiedClassName){
String[] arr = fullyQualifiedClassName.split("\\."); String[] arr = fullyQualifiedClassName.trim().split("\\.");
int n = arr.length; int n = arr.length;
if(n == 0) { if(n < 1) {
throw new RuntimeException("the class name invoked is wrong"); throw new RuntimeException("the class's name invoked is wrong");
} }
return arr[n-1]; return arr[n-1];
} }
public static String transformName(String name){
return name.replace("servicejdbc", "agentjdbc");
}
} }

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

@ -6,6 +6,7 @@ import com.fanruan.pojo.message.RpcRequest;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
@ -27,8 +28,8 @@ public class DispatcherImpl implements Dispatcher{
Object res = null; Object res = null;
try { try {
res = invokeAsRequest(rpcRequest, beanCache); res = invokeAsRequest(rpcRequest, beanCache);
}catch (Exception e){ }catch (Throwable t){
RESPONSE_EMITTER_IMPL.sendError(CACHE.getSocket(dbName), rpcRequest, e); RESPONSE_EMITTER_IMPL.sendError(CACHE.getSocket(dbName), rpcRequest, t);
} }
if(res != null && !DispatcherHelper.isInCacheList(res.getClass().getName())){ if(res != null && !DispatcherHelper.isInCacheList(res.getClass().getName())){
@ -39,7 +40,7 @@ public class DispatcherImpl implements Dispatcher{
} }
@Override @Override
public Object invokeAsRequest(RpcRequest rpcRequest, BeanCacheImpl beanCache) throws Exception{ public Object invokeAsRequest(RpcRequest rpcRequest, BeanCacheImpl beanCache) throws Throwable {
String fullName = rpcRequest.getServiceClassName(); String fullName = rpcRequest.getServiceClassName();
Class<?> clazz = Class.forName(fullName); Class<?> clazz = Class.forName(fullName);
String methodName = rpcRequest.getMethodName(); String methodName = rpcRequest.getMethodName();
@ -80,28 +81,25 @@ public class DispatcherImpl implements Dispatcher{
} }
} }
method = clazz.getDeclaredMethod(methodName, argTypes); method = clazz.getDeclaredMethod(methodName, argTypes);
} }
Object res = null;
Object res = method.invoke(calledClassInstance, args); try{
res = method.invoke(calledClassInstance, args);
if(CLOSE_NAME.equals(methodName)){ }catch (InvocationTargetException e){
beanCache.removeInstances(IDToInvoke); throw e.getCause();
} }
// Cached some instances need to be invoke later. // Cached some instances need to be invoke later.
// Some method return null, so determine the value of `res` before referencing it. // Some method return null
if(res != null){
String resClassName = res.getClass().getName(); if(DispatcherHelper.isInCacheList(res)) {
if(DispatcherHelper.isInCacheList(resClassName)) { beanCache.cacheInstance(rpcRequest.getID(), res);
beanCache.cacheInstance(rpcRequest.getID(), res);
}
logger.debug("invoke" + className + "-" + methodName + " and return a instance of" + res.getClass().getName());
}else{
logger.debug("invoke" + className + "-" + methodName + " and no return value");
} }
logger.debug("invoke" + className + "-" + methodName + " and return value : " + res);
return res; return res;
} }

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

@ -20,9 +20,9 @@ public interface ResponseEmitter {
* Send failure response when error occur while handle request. * Send failure response when error occur while handle request.
* @param socket * @param socket
* @param rpcRequest * @param rpcRequest
* @param e Exception happened while handle request. * @param t Exception happened while handle request.
*/ */
void sendError(Socket socket, RpcRequest rpcRequest, Exception e); void sendError(Socket socket, RpcRequest rpcRequest, Throwable t);
/** /**
* Send success response with data asked by request. * Send success response with data asked by request.

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

@ -22,11 +22,11 @@ public class ResponseEmitterImpl implements ResponseEmitter{
} }
@Override @Override
public void sendError(Socket socket, RpcRequest rpcRequest, Exception e){ public void sendError(Socket socket, RpcRequest rpcRequest, Throwable t){
RpcResponse rpcResponse = new RpcResponse(); RpcResponse rpcResponse = new RpcResponse();
rpcResponse.setResult("Some errors happened when AgentID: " + AgentStarter.AgentID + " " rpcResponse.setResult("Some errors happened when AgentID: " + AgentStarter.AgentID + " "
+ rpcRequest.getMethodName() + " is being invoked!" + "\n" + rpcRequest.getMethodName() + " is being invoked!" + "\n"
+ "Error Message: " + e.getMessage() + "Error Message: " + t.getMessage()
+ " and check your code") + " and check your code")
.setID(rpcRequest.getID()) .setID(rpcRequest.getID())
.setStatus(false); .setStatus(false);

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

@ -10,7 +10,6 @@ import lombok.experimental.Accessors;
@Accessors(chain = true) @Accessors(chain = true)
public class RpcRequest { public class RpcRequest {
private String ID; private String ID;
// private boolean binding;
private String IDToInvoke; private String IDToInvoke;
private String serviceClassName; private String serviceClassName;
private String methodName; private String methodName;

29
agent/src/test/java/HSQLTest.java

@ -25,7 +25,7 @@ public class HSQLTest {
void getConnection() throws SQLException { void getConnection() throws SQLException {
Connection conn = null; Connection conn = null;
try { try {
conn = DriverManager.getConnection("jdbc:hsqldb:mem:test", "sa", ""); conn = DriverManager.getConnection("jdbc:hsqldb:mem:test;sql.syntax_mys=true", "sa", "");
Assertions.assertNotNull(conn, "can't get connection"); Assertions.assertNotNull(conn, "can't get connection");
} catch (SQLException e) { } catch (SQLException e) {
e.printStackTrace(); e.printStackTrace();
@ -34,6 +34,29 @@ public class HSQLTest {
} }
} }
private static String createStoredProcedure ="CREATE PROCEDURE get_city_name(" +
"IN c_id INT, " +
"OUT city_name varchar(20)) " +
"READS SQL DATA " +
"BEGIN ATOMIC " +
" SELECT city.name INTO city_name FROM city WHERE id = c_id; " +
"END;";
@Test
public void test() throws SQLException {
Connection conn = DriverManager.getConnection("jdbc:hsqldb:mem:test;sql.syntax_mys=true", "sa", "");
Statement statement = conn.createStatement();
statement.executeUpdate("CREATE TABLE city (id INTEGER, name varchar(20)); ");
statement.executeUpdate("INSERT INTO city VALUES (1, '成都'), (2, '上海'); ");
statement.execute(createStoredProcedure);
CallableStatement callableStatement = conn.prepareCall("{call get_city_name(?, ?)}");
callableStatement.setInt(1, 2);
callableStatement.registerOutParameter(2, Types.VARCHAR);
callableStatement.execute();
System.out.println(callableStatement.getString(2));
}
/** /**
* test to create statement instance and prepareStatement, create table, select form table, delete from table * test to create statement instance and prepareStatement, create table, select form table, delete from table
*/ */
@ -44,7 +67,7 @@ public class HSQLTest {
PreparedStatement pst = null; PreparedStatement pst = null;
ResultSet rs = null; ResultSet rs = null;
try { try {
conn = DriverManager.getConnection("jdbc:hsqldb:mem:test", "sa", ""); conn = DriverManager.getConnection("jdbc:hsqldb:mem:test;sql.syntax_mys=true", "sa", "");
st = conn.createStatement(); st = conn.createStatement();
st.executeUpdate("DROP TABLE student IF EXISTS;"); st.executeUpdate("DROP TABLE student IF EXISTS;");
@ -82,6 +105,8 @@ public class HSQLTest {
Assertions.assertEquals(rs.getString("student_address"), addressStrings[num-1]); Assertions.assertEquals(rs.getString("student_address"), addressStrings[num-1]);
num++; num++;
} }
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} finally { } finally {

3
agent/src/test/java/Test.java

@ -2,6 +2,8 @@ import com.fanruan.AgentStarter;
import com.fanruan.utils.DBProperties; import com.fanruan.utils.DBProperties;
import io.socket.client.Socket; import io.socket.client.Socket;
import java.util.HashMap;
public class Test { public class Test {
@ -27,7 +29,6 @@ public class Test {
Socket socket = AgentStarter.dispatcherImpl.CACHE.getSocket(DBProperties.HSQL[0]); Socket socket = AgentStarter.dispatcherImpl.CACHE.getSocket(DBProperties.HSQL[0]);
socket.connect(); socket.connect();
} }
} }

14
agent/src/test/java/TestSuite.java

@ -0,0 +1,14 @@
import org.junit.platform.suite.api.IncludeClassNamePatterns;
import org.junit.platform.suite.api.SelectPackages;
import org.junit.platform.suite.api.Suite;
/**
* @author Yichen Dai
* @date 2022/8/23 15:04
*/
@SelectPackages({"com.fanruan"})
@Suite
@IncludeClassNamePatterns(".*Test.*")
public class TestSuite {
}

24
agent/src/test/java/com/fanruan/cache/BeanCacheImplTest.java vendored

@ -0,0 +1,24 @@
package com.fanruan.cache;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
/**
* @author Yichen Dai
* @date 2022/8/22 19:54
*/
class BeanCacheImplTest {
@Test
void getCachedInstances() {
}
@Test
void removeInstances() {
}
@Test
void cacheInstance() {
}
}

44
agent/src/test/java/com/fanruan/cache/CacheImplTest.java vendored

@ -0,0 +1,44 @@
package com.fanruan.cache;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
/**
* @author Yichen Dai
* @date 2022/8/22 19:54
*/
class CacheImplTest {
@Test
void registerSocket() {
}
@Test
void getSocket() {
}
@Test
void registerBeanCache() {
}
@Test
void getBeanCache() {
}
@Test
void testRegisterSocket() {
}
@Test
void testGetSocket() {
}
@Test
void testRegisterBeanCache() {
}
@Test
void testGetBeanCache() {
}
}

71
agent/src/test/java/com/fanruan/handler/DispatcherHelperTest.java

@ -0,0 +1,71 @@
package com.fanruan.handler;
import com.fanruan.agent.jdbc.driver.AgentDriver;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
/**
* @author Yichen Dai
* @date 2022/8/22 15:07
*/
class DispatcherHelperTest{
@Test
void isInCacheList() {
Assertions.assertTrue(DispatcherHelper.isInCacheList(new AgentDriver()));
Assertions.assertTrue(DispatcherHelper.isInCacheList("com.fanruan.agent.jdbc.agentDriver"));
Assertions.assertTrue(DispatcherHelper.isInCacheList("com.fanruan.agent.jdbc.agentConnection"));
Assertions.assertTrue(DispatcherHelper.isInCacheList("com.fanruan.agent.jdbc.agentStatement"));
Assertions.assertTrue(DispatcherHelper.isInCacheList("com.fanruan.agent.jdbc.agentPrepareStatement"));
Assertions.assertTrue(DispatcherHelper.isInCacheList("com.fanruan.agent.jdbc.agentResultSet"));
Assertions.assertFalse(DispatcherHelper.isInCacheList("java.lang.String"));
Assertions.assertFalse(DispatcherHelper.isInCacheList("java.lang.Integer"));
Assertions.assertFalse(DispatcherHelper.isInCacheList("com.fanruan.agent.cache.BeanCache"));
Assertions.assertFalse(DispatcherHelper.isInCacheList(""));
Assertions.assertFalse(DispatcherHelper.isInCacheList(null));
}
@Test
void isWraps() {
Assertions.assertTrue(DispatcherHelper.isWraps(java.lang.Byte.class));
Assertions.assertTrue(DispatcherHelper.isWraps(java.lang.Character.class));
Assertions.assertTrue(DispatcherHelper.isWraps(java.lang.Short.class));
Assertions.assertTrue(DispatcherHelper.isWraps(java.lang.Integer.class));
Assertions.assertTrue(DispatcherHelper.isWraps(java.lang.Long.class));
Assertions.assertTrue(DispatcherHelper.isWraps(java.lang.Boolean.class));
Assertions.assertTrue(DispatcherHelper.isWraps(java.lang.Float.class));
Assertions.assertTrue(DispatcherHelper.isWraps(java.lang.Double.class));
Assertions.assertFalse(DispatcherHelper.isWraps(Integer.TYPE));
Assertions.assertFalse(DispatcherHelper.isWraps(java.lang.String.class));
Assertions.assertFalse(DispatcherHelper.isWraps(null));
}
@Test
void castToPrimitiveClass() {
Assertions.assertEquals(Byte.TYPE, DispatcherHelper.castToPrimitiveClass(Byte.class));
Assertions.assertEquals(Character.TYPE, DispatcherHelper.castToPrimitiveClass(Character.class));
Assertions.assertEquals(Short.TYPE, DispatcherHelper.castToPrimitiveClass(Short.class));
Assertions.assertEquals(Integer.TYPE, DispatcherHelper.castToPrimitiveClass(Integer.class));
Assertions.assertEquals(Long.TYPE, DispatcherHelper.castToPrimitiveClass(Long.class));
Assertions.assertEquals(Boolean.TYPE, DispatcherHelper.castToPrimitiveClass(Boolean.class));
Assertions.assertEquals(Float.TYPE, DispatcherHelper.castToPrimitiveClass(Float.class));
Assertions.assertEquals(Double.TYPE, DispatcherHelper.castToPrimitiveClass(Double.class));
}
@Test
void getClassName() {
Assertions.assertEquals("agentDriver", DispatcherHelper.getClassName("com.fanruan.agent.jdbc.agentDriver"));
Assertions.assertEquals("agentDriver", DispatcherHelper.getClassName(" com.fanruan.agent.jdbc.agentDriver "));
Assertions.assertEquals("fakeName", DispatcherHelper.getClassName("fakeName"));
Assertions.assertEquals("", DispatcherHelper.getClassName(""));
Assertions.assertThrows(RuntimeException.class, () -> DispatcherHelper.getClassName(null));
}
}

27
agent/src/test/java/com/fanruan/handler/DispatcherImplTest.java

@ -0,0 +1,27 @@
package com.fanruan.handler;
import org.junit.jupiter.api.Test;
/**
* @author Yichen Dai
* @date 2022/8/22 14:47
*/
class DispatcherImplTest {
@Test
void doDispatch() {
}
@Test
void invokeAsRequest() {
}
@Test
void testDoDispatch() {
}
@Test
void testInvokeAsRequest() {
}
}

BIN
pic/project structure.jpg

Binary file not shown.

Before

Width:  |  Height:  |  Size: 166 KiB

After

Width:  |  Height:  |  Size: 0 B

13
service/pom.xml

@ -69,11 +69,20 @@
<version>1.18.22</version> <version>1.18.22</version>
</dependency> </dependency>
<!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api --> <!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-engine -->
<dependency> <dependency>
<groupId>org.junit.jupiter</groupId> <groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId> <artifactId>junit-jupiter-engine</artifactId>
<version>5.4.0</version> <version>5.9.0</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.junit.platform/junit-platform-suite-engine -->
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-suite-engine</artifactId>
<version>1.9.0</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>

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

@ -58,6 +58,10 @@ public class ServerStater{
} }
public void shutDown(){
server.stop();
}
private void addEvent(SocketIONamespace nameSpace){ private void addEvent(SocketIONamespace nameSpace){
logger.debug("配置事件监听"); logger.debug("配置事件监听");
nameSpace.addConnectListener(client -> { nameSpace.addConnectListener(client -> {
@ -180,7 +184,7 @@ public class ServerStater{
client.disconnect(); client.disconnect();
} }
// 缓存连接 // remove client
ClientCache.deleteClient(agentID, dbName); ClientCache.deleteClient(agentID, dbName);
logger.info("agentID: " + agentID + "连接关闭"); logger.info("agentID: " + agentID + "连接关闭");
logger.info("agentID: " + agentID + "连接已删除"); logger.info("agentID: " + agentID + "连接已删除");

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

@ -14,7 +14,6 @@ public class RpcRequest {
* In the project, they are Drive( MyDriver ), Connection( MyConnection ), Statement( MyStatement ), * In the project, they are Drive( MyDriver ), Connection( MyConnection ), Statement( MyStatement ),
* PreparedStatement( MyPreparedStatement ), ResultSet( MyResult ). * PreparedStatement( MyPreparedStatement ), ResultSet( MyResult ).
*/ */
// private boolean binding;
private String ID; private String ID;
private String IDToInvoke; private String IDToInvoke;
private String serviceClassName; private String serviceClassName;

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

@ -1,22 +0,0 @@
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.service.jdbc.driver.ServiceDriver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}

2
service/src/test/java/ServiceTest.java

@ -15,7 +15,7 @@ import java.util.concurrent.FutureTask;
* @author Yichen Dai * @author Yichen Dai
* @date 2022/8/18 9:49 * @date 2022/8/18 9:49
*/ */
public class ServiceTest extends AutoStarter{ public class ServiceTest {
@BeforeEach @BeforeEach
void listen() throws ExecutionException, InterruptedException { void listen() throws ExecutionException, InterruptedException {

13
service/src/test/java/TestSuite.java

@ -0,0 +1,13 @@
import org.junit.platform.suite.api.IncludeClassNamePatterns;
import org.junit.platform.suite.api.SelectPackages;
import org.junit.platform.suite.api.Suite;
/**
* @author Yichen Dai
* @date 2022/8/23 15:30
*/
@SelectPackages({"com.fanruan"})
@IncludeClassNamePatterns(".*Test.*")
@Suite
public class TestSuite {
}

15
test/pom.xml

@ -29,14 +29,25 @@
<version>1.0-SNAPSHOT</version> <version>1.0-SNAPSHOT</version>
</dependency> </dependency>
<!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api --> <!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-engine -->
<dependency> <dependency>
<groupId>org.junit.jupiter</groupId> <groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId> <artifactId>junit-jupiter-engine</artifactId>
<version>5.4.0</version> <version>5.9.0</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<!-- https://mvnrepository.com/artifact/org.junit.platform/junit-platform-suite-engine -->
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-suite-engine</artifactId>
<version>1.9.0</version>
<scope>test</scope>
</dependency>
<dependency> <dependency>
<groupId>org.apache.logging.log4j</groupId> <groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId> <artifactId>log4j-api</artifactId>

16
test/src/test/java/TestSuite.java

@ -0,0 +1,16 @@
import org.junit.platform.suite.api.IncludeClassNamePatterns;
import org.junit.platform.suite.api.SelectPackages;
import org.junit.platform.suite.api.Suite;
/**
* @author Yichen Dai
* @date 2022/8/23 14:39
*/
@SelectPackages({"com.fanruan"})
@IncludeClassNamePatterns(".*Test.*")
@Suite
public class TestSuite {
}

170
test/src/test/java/TestUtil.java

@ -1,170 +0,0 @@
import com.fanruan.AgentStarter;
import com.fanruan.ServerStater;
import com.fanruan.service.jdbc.driver.ServiceDriver;
import com.fanruan.proxy.ProxyFactory;
import com.fanruan.utils.DBProperties;
import org.junit.jupiter.api.*;
import java.sql.*;
import java.util.Properties;
/**
* @author Yichen Dai
* @date 2022/8/18 15:27
*/
public class TestUtil {
static Connection conn = null;
static Statement st = null;
static PreparedStatement pst = null;
static ResultSet rs = null;
static void configService(){
String[][] DBs = new String[][]{
DBProperties.HSQL,
};
new ServerStater(DBs);
}
static void configAgent(){
String[][] DBs = new String[][]{
DBProperties.HSQL,
};
new AgentStarter(DBs);
}
@BeforeAll
static void autoConfig(){
configService();
configAgent();
try {
// 等待socket连接
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Test
void testConnect() throws SQLException {
// 建立连接
Properties info = new Properties();
info.setProperty("user", "sa");
info.setProperty("password", "");
info.setProperty("agentID", "1001");
info.setProperty("agentDBName", DBProperties.HSQL[0]);
Driver driver = (ServiceDriver) ProxyFactory.getProxy(ServiceDriver.class, null);
conn = driver.connect("jdbc:hsqldb:mem:test", info);
}
@Test
void testCreateTable() throws SQLException {
testConnect();
// 创建 statement
st = conn.createStatement();
// 创建表
int num = st.executeUpdate("DROP TABLE student IF EXISTS;");
Assertions.assertEquals(0, num);
num = 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)" +
");");
Assertions.assertEquals(0, num);
}
@Test
void testInsert() throws SQLException {
testCreateTable();
// 插入数据
int num = st.executeUpdate("INSERT INTO student VALUES" +
"(1, '张三', '上海')," +
"(2, '李四', '北京')," +
"(3, '王五', '成都');");
Assertions.assertEquals(3, num);
}
@Test
void testUpdate() throws SQLException {
testInsert();
// 预查询语句 删除指定 ID
pst = conn.prepareStatement("UPDATE student" +
" SET student_name = '李华', student_address = '杭州'"+
"WHERE student_id = ?");
Assertions.assertNotNull(pst);
pst.setInt(1, 1);
int num = pst.executeUpdate();
Assertions.assertEquals(1, num);
}
@Test
void testDelete() throws SQLException {
testInsert();
// 预查询语句 删除指定 ID
pst = conn.prepareStatement("delete from student where student_id = ?");
Assertions.assertNotNull(pst);
pst.setInt(1, 1);
int num = pst.executeUpdate();
Assertions.assertEquals(1, num);
}
@Test
void testSelect() throws SQLException {
testInsert();
rs = st.executeQuery("select * from student");
String[] nameStrings = new String[]{"张三", "李四", "王五"};
String[] addressStrings = new String[]{"上海", "北京", "成都"};
// 结果集断言
int num = 1;
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++;
}
}
@AfterAll
static void close() throws SQLException {
if(rs!= null){
rs.close();
}
if(pst != null){
pst.close();
}
if(st != null){
st.close();
}
if(conn != null){
conn.close();
}
}
}

58
test/src/test/java/com/fanruan/AbstractDriverTest.java

@ -0,0 +1,58 @@
package com.fanruan;
/**
* @author Yichen Dai
* @date 2022/8/23 15:49
*/
import com.fanruan.cache.ClientCache;
import com.fanruan.proxy.ProxyFactory;
import com.fanruan.service.jdbc.driver.ServiceDriver;
import com.fanruan.utils.DBProperties;
import java.sql.*;
import java.util.Properties;
/** Base test class with common constants, data structures and methods */
public class AbstractDriverTest {
static final Properties info = new Properties();
static final String[][] dbNameAndDriver = new String[][]{
DBProperties.HSQL
};
static final ServerStater server = new ServerStater(dbNameAndDriver);
static final AgentStarter agent = new AgentStarter(dbNameAndDriver);
static {
info.setProperty("user", "sa");
info.setProperty("password", "");
info.setProperty("agentID", "1001");
info.setProperty("agentDBName", DBProperties.HSQL[0]);
}
static void openSocket(){
while(ClientCache.getClient(
info.getProperty("agentID"),
info.getProperty("agentDBName"))
== null){
}
}
void shutDown(){
agent.shutDown();
server.shutDown();
}
/**
* Gets a connection
* @return Connection a database connection
* @throws SQLException raised if any error occurs
*/
public static Connection getConnection() throws SQLException {
Driver driver = (ServiceDriver) ProxyFactory.getProxy(ServiceDriver.class, null);
Connection conn = driver.connect("jdbc:hsqldb:mem:test;sql.syntax_mys=true", info);
return conn;
}
}

1171
test/src/test/java/com/fanruan/AgentCallableStatementTest.java

File diff suppressed because it is too large Load Diff

432
test/src/test/java/com/fanruan/BaseJDBCTest.java

@ -0,0 +1,432 @@
package com.fanruan;
import com.fanruan.annotation.RemoteClass;
import com.fanruan.pojo.message.RpcRequest;
import com.fanruan.service.jdbc.AbstractBind;
import com.fanruan.utils.Commons;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import java.io.*;
import java.sql.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author Yichen Dai
* @date 2022/8/23 15:47
*/
public class BaseJDBCTest extends AbstractDriverTest{
final String dbName = "hsql";
final Map<String, RpcRequest> map = new HashMap(1);
int getSizeOfResultSet(ResultSet rs) throws SQLException {
int count = 0;
while (rs.next()) {
count++;
}
return count;
}
List<String> getInfoBySQL(String sqlCmd) throws SQLException {
Connection con = getConnection();
Statement st = con.createStatement();
List<String> result = new ArrayList<>();
ResultSet rs = st.executeQuery(sqlCmd);
while (rs.next()) {
result.add(rs.getString(1));
}
return result;
}
public RpcRequest createRequest(AbstractBind bind, String methodName, Object[] args, Class<?>[] argTypes) {
RpcRequest request = new RpcRequest();
request.setID(Commons.getID())
.setIDToInvoke(bind.getID())
.setMethodName(methodName)
.setArgs(args)
.setArgTypes(argTypes);
Class clazz = bind.getClass();
if(clazz.isAnnotationPresent(RemoteClass.class)){
RemoteClass annotation = (RemoteClass) clazz.getAnnotation(RemoteClass.class);
request.setServiceClassName(annotation.remoteClassName());
}else{
request.setServiceClassName(clazz.getName());
}
return request;
}
public boolean isEqualRequest(RpcRequest r1, RpcRequest r2){
String[] s1 = new String[]{
r1.getID(),
r1.getIDToInvoke(),
r1.getMethodName(),
r1.getServiceClassName()
};
String[] s2 = new String[]{
r2.getID(),
r2.getIDToInvoke(),
r2.getMethodName(),
r2.getServiceClassName()
};
if(isNotEqualStringArray(s1, s2)){
return false;
}
Object[] o1 = r1.getArgs();
Object[] o2 = r2.getArgs();
int o1_len = o1.length;
int o2_len = o2.length;
String[] o1_sa = new String[o1_len];
String[] o2_sa = new String[o2_len];
for(int i=0; i<o1_len; i++){
o1_sa[i] = o1[i].getClass().getName();
o2_sa[i] = o2[i].getClass().getName();
}
if(isNotEqualStringArray(o1_sa, o2_sa)){
return false;
}
Class<?>[] c1 = r1.getArgTypes();
Class<?>[] c2 = r2.getArgTypes();
int c1_len = c1.length;
int c2_len = c2.length;
String[] c1_sa = new String[c1_len];
String[] c2_sa = new String[c2_len];
for(int i=0; i<o1_len; i++){
c1_sa[i] = c1[i].getName();
c2_sa[i] = c2[i].getName();
}
if(isNotEqualStringArray(c1_sa, c2_sa)){
return false;
}
return true;
}
public boolean isNotEqualStringArray(String[] s1, String[] s2){
if(s1.length != s2.length){
return true;
}
for(int i=0; i<s1.length; i++){
if(s1[i] == null && s2[i] != null){
return true;
}else if(s1[i] != null && !s1[i].equals(s2[i])){
return true;
}
}
return false;
}
public static void closeSQLObjects(Object...objects) throws SQLException {
for(Object obj : objects){
if(obj != null){
if(obj instanceof Connection){
Connection conn = (Connection) obj;
conn.close();
}else if(obj instanceof Statement){
Statement statement = (Statement) obj;
statement.close();
}else if(obj instanceof PreparedStatement){
PreparedStatement preparedStatement = (PreparedStatement) obj;
preparedStatement.close();
}else if(obj instanceof ResultSet){
ResultSet resultSet = (ResultSet) obj;
resultSet.close();
}else{
throw new SQLException("Some arguments passed in are not closable.");
}
}
}
}
}
class FakeInputStream extends InputStream {
@Override
public int read() throws IOException {
return 0;
}
}
class FakeReader extends Reader {
@Override
public int read(char[] cbuf, int off, int len) throws IOException {
return 0;
}
@Override
public void close() throws IOException {}
}
class FakeSQLXML implements SQLXML {
@Override
public void free() throws SQLException {}
@Override
public InputStream getBinaryStream() throws SQLException {
return null;
}
@Override
public OutputStream setBinaryStream() throws SQLException {
return null;
}
@Override
public Reader getCharacterStream() throws SQLException {
return null;
}
@Override
public Writer setCharacterStream() throws SQLException {
return null;
}
@Override
public String getString() throws SQLException {
return null;
}
@Override
public void setString(String value) throws SQLException {}
@Override
public <T extends Source> T getSource(Class<T> sourceClass) throws SQLException {
return null;
}
@Override
public <T extends Result> T setResult(Class<T> resultClass) throws SQLException {
return null;
}
}
class FakeBlob implements Blob {
@Override
public long length() throws SQLException {
return 0;
}
@Override
public byte[] getBytes(long pos, int length) throws SQLException {
return new byte[0];
}
@Override
public InputStream getBinaryStream() throws SQLException {
return null;
}
@Override
public long position(byte[] pattern, long start) throws SQLException {
return 0;
}
@Override
public long position(Blob pattern, long start) throws SQLException {
return 0;
}
@Override
public int setBytes(long pos, byte[] bytes) throws SQLException {
return 0;
}
@Override
public int setBytes(long pos, byte[] bytes, int offset, int len) throws SQLException {
return 0;
}
@Override
public OutputStream setBinaryStream(long pos) throws SQLException {
return null;
}
@Override
public void truncate(long len) throws SQLException {}
@Override
public void free() throws SQLException {}
@Override
public InputStream getBinaryStream(long pos, long length) throws SQLException {
return null;
}
}
class FakeArray implements Array {
@Override
public String getBaseTypeName() throws SQLException {
return null;
}
@Override
public int getBaseType() throws SQLException {
return 0;
}
@Override
public Object getArray() throws SQLException {
return null;
}
@Override
public Object getArray(Map<String, Class<?>> map) throws SQLException {
return null;
}
@Override
public Object getArray(long index, int count) throws SQLException {
return null;
}
@Override
public Object getArray(long index, int count, Map<String, Class<?>> map) throws SQLException {
return null;
}
@Override
public ResultSet getResultSet() throws SQLException {
return null;
}
@Override
public ResultSet getResultSet(Map<String, Class<?>> map) throws SQLException {
return null;
}
@Override
public ResultSet getResultSet(long index, int count) throws SQLException {
return null;
}
@Override
public ResultSet getResultSet(long index, int count, Map<String, Class<?>> map)
throws SQLException {
return null;
}
@Override
public void free() throws SQLException {}
}
class FakeRowId implements RowId {
@Override
public byte[] getBytes() {
return new byte[0];
}
}
class FakeNClob implements NClob {
@Override
public long length() throws SQLException {
return 0;
}
@Override
public String getSubString(long pos, int length) throws SQLException {
return null;
}
@Override
public Reader getCharacterStream() throws SQLException {
return null;
}
@Override
public InputStream getAsciiStream() throws SQLException {
return null;
}
@Override
public long position(String searchstr, long start) throws SQLException {
return 0;
}
@Override
public long position(Clob searchstr, long start) throws SQLException {
return 0;
}
@Override
public int setString(long pos, String str) throws SQLException {
return 0;
}
@Override
public int setString(long pos, String str, int offset, int len) throws SQLException {
return 0;
}
@Override
public OutputStream setAsciiStream(long pos) throws SQLException {
return null;
}
@Override
public Writer setCharacterStream(long pos) throws SQLException {
return null;
}
@Override
public void truncate(long len) throws SQLException {}
@Override
public void free() throws SQLException {}
@Override
public Reader getCharacterStream(long pos, long length) throws SQLException {
return null;
}
}
class FakeRef implements Ref {
@Override
public String getBaseTypeName() throws SQLException {
return null;
}
@Override
public Object getObject(Map<String, Class<?>> map) throws SQLException {
return null;
}
@Override
public Object getObject() throws SQLException {
return null;
}
@Override
public void setObject(Object value) throws SQLException {}
}
class FakeSavepoint implements Savepoint{
@Override
public int getSavepointId() throws SQLException {
return 0;
}
@Override
public String getSavepointName() throws SQLException {
return null;
}
}

314
test/src/test/java/com/fanruan/ConnectionTest.java

@ -0,0 +1,314 @@
package com.fanruan;
import com.fanruan.cache.BeanCacheImpl;
import com.fanruan.exception.NotImplementedException;
import com.fanruan.handler.DispatcherImpl;
import com.fanruan.pojo.message.RpcRequest;
import com.fanruan.service.jdbc.connection.ServiceConnection;
import org.junit.jupiter.api.*;
import java.sql.*;
import java.util.Collections;
import java.util.HashMap;
import java.util.Properties;
/**
* @author Yichen Dai
* @date 2022/8/30 10:23
*/
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class ConnectionTest extends BaseJDBCTest{
Connection connection = null;
String IDtoInvoke = "";
BeanCacheImpl beanCache = null;
DispatcherImpl dispatcher = null;
ServiceConnection serviceConnection = null;
@BeforeAll
public void setUp() throws SQLException {
openSocket();
connection = getConnection();
ServiceConnection conn = (ServiceConnection) connection;
IDtoInvoke = conn.getID();
dispatcher = agent.dispatcherImpl;
beanCache = dispatcher.CACHE.getBeanCache(dbName);
serviceConnection = (ServiceConnection) ProxyFactoryIT.getProxy(ServiceConnection.class, map);
}
@Test
public void testSetCatalogSchema() throws Throwable{
String db = connection.getCatalog();
String schema = connection.getSchema();
connection.setCatalog(db);
connection.setSchema("PUBLIC");
// get the current schema
ResultSet rst = connection.createStatement().executeQuery("SELECT * " +
"FROM INFORMATION_SCHEMA.TABLES");
Assertions.assertTrue(rst.next());
Assertions.assertEquals("PUBLIC", rst.getString(1));
Assertions.assertEquals(db, connection.getCatalog());
Assertions.assertEquals("PUBLIC", connection.getSchema());
// get the current schema
connection.setSchema(schema);
rst = connection.createStatement().executeQuery("SELECT * " +
"FROM INFORMATION_SCHEMA.TABLES");
Assertions.assertTrue(rst.next());
Assertions.assertEquals(schema, rst.getString(1));
rst.close();
}
@Test
public void testConnection() throws Throwable {
Properties property = connection.getClientInfo();
Assertions.assertNull(property);
Properties clientInfo = new Properties();
clientInfo.setProperty("name", "Peter");
clientInfo.setProperty("description", "HSQLDB JDBC");
Assertions.assertThrows(SQLClientInfoException.class, () -> {
serviceConnection.setClientInfo("name", "peter");
RpcRequest request = map.get(null);
request.setIDToInvoke(IDtoInvoke);
dispatcher.invokeAsRequest(request, beanCache);
});
Assertions.assertThrows(SQLClientInfoException.class, () -> {
serviceConnection.setClientInfo(clientInfo);
RpcRequest request = map.get(null);
request.setIDToInvoke(IDtoInvoke);
dispatcher.invokeAsRequest(request, beanCache);
});
}
@Test
public void testNetworkTimeout() throws SQLException {
int millis = connection.getNetworkTimeout();
Assertions.assertEquals(0, millis);
Assertions.assertThrows(SQLFeatureNotSupportedException.class, () -> {
serviceConnection.setNetworkTimeout(null, 200);
RpcRequest request = map.get(null);
request.setIDToInvoke(IDtoInvoke);
dispatcher.invokeAsRequest(request, beanCache);
});
}
@Test
public void testAbort() throws SQLException {
Assertions.assertThrows(SQLException.class, () -> {
serviceConnection.abort(null);
RpcRequest request = map.get(null);
request.setIDToInvoke(IDtoInvoke);
dispatcher.invokeAsRequest(request, beanCache);
});
}
@Test
public void testClose() throws SQLException {
Connection conn = getConnection();
Assertions.assertFalse(conn.isClosed());
conn.close();
Assertions.assertTrue(conn.isClosed());
}
@Test
public void testHoldability() throws Throwable {
connection.setHoldability(ResultSet.CLOSE_CURSORS_AT_COMMIT);
Assertions.assertEquals(ResultSet.CLOSE_CURSORS_AT_COMMIT, connection.getHoldability());
}
@Test
public void testIsValid() throws Throwable {
Assertions.assertTrue(connection.isValid(10));
}
@Test
public void testUnwrapper() throws SQLException {
boolean canUnwrap = connection.isWrapperFor(Connection.class);
Assertions.assertTrue(canUnwrap);
Assertions.assertThrows(NotImplementedException.class,
() -> connection.unwrap(null));
}
@Test
public void testNativeSQL() throws SQLException {
Assertions.assertEquals("select 1", connection.nativeSQL("select 1"));
}
@Test
public void testTypeMap() throws Throwable {
Assertions.assertEquals(Collections.emptyMap(), connection.getTypeMap());
Assertions.assertThrows(SQLException.class, () -> {
serviceConnection.setTypeMap(new HashMap<>());
RpcRequest request = map.get(null);
request.setIDToInvoke(IDtoInvoke);
dispatcher.invokeAsRequest(request, beanCache);
});
}
@Test
public void setReadOnly() throws SQLException {
Assertions.assertFalse(connection.isReadOnly());
connection.setReadOnly(true);
Assertions.assertTrue(connection.isReadOnly());
}
@Test
public void setTransactionIsolation() throws SQLException {
Connection conn = getConnection();
Assertions.assertEquals(Connection.TRANSACTION_READ_COMMITTED ,conn.getTransactionIsolation());
conn.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);
Assertions.assertEquals(Connection.TRANSACTION_SERIALIZABLE, conn.getTransactionIsolation());
closeSQLObjects(conn);
}
@Test
public void testGetWarning() throws SQLException {
connection.clearWarnings();
Assertions.assertNull(connection.getWarnings());
}
@Test
public void testCreateStatement() throws SQLException {
Statement st1 = connection.createStatement(
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.TYPE_FORWARD_ONLY);
Statement st2 = connection.createStatement(
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CLOSE_CURSORS_AT_COMMIT
);
closeSQLObjects(st1, st2);
}
@Test
void testPrepareStatement() throws SQLException {
PreparedStatement pst1 = connection.prepareStatement(
"select 1",
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.TYPE_FORWARD_ONLY
);
PreparedStatement pst2 = connection.prepareStatement(
"select 1",
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CLOSE_CURSORS_AT_COMMIT
);
PreparedStatement pst3 = connection.prepareStatement(
"select 2",
Statement.NO_GENERATED_KEYS
);
PreparedStatement pst4 = connection.prepareStatement(
"select 2",
new int[]{0}
);
PreparedStatement pst5 = connection.prepareStatement(
"select 2",
new String[]{"column_name"}
);
closeSQLObjects(pst1, pst2, pst3, pst4, pst5);
}
@Test
void testCallableStatement() throws SQLException {
Statement statement = connection.createStatement();
statement.executeUpdate("CREATE TABLE city (id INTEGER, name varchar(20)); ");
statement.executeUpdate("INSERT INTO city VALUES (1, '成都'), (2, '上海'); ");
CallableStatement cst1 = connection.prepareCall(
"CREATE PROCEDURE get_city_name(" +
"IN c_id INT, " +
"OUT city_name varchar(20)) " +
"READS SQL DATA " +
"BEGIN ATOMIC " +
" SELECT city.name INTO city_name FROM city WHERE id = c_id; " +
"END;",
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.TYPE_FORWARD_ONLY
);
CallableStatement cst2 = connection.prepareCall(
"CREATE PROCEDURE get_city_name(" +
"IN c_id INT, " +
"OUT city_name varchar(20)) " +
"READS SQL DATA " +
"BEGIN ATOMIC " +
" SELECT city.name INTO city_name FROM city WHERE id = c_id; " +
"END;",
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CLOSE_CURSORS_AT_COMMIT
);
closeSQLObjects(cst1, cst2);
}
@Test
void testSavePoint() throws SQLException {
Assertions.assertThrows(SQLException.class, () -> {
serviceConnection.setSavepoint();
RpcRequest request = map.get(null);
request.setIDToInvoke(IDtoInvoke);
dispatcher.invokeAsRequest(request, beanCache);
});
Assertions.assertThrows(SQLException.class, () -> {
serviceConnection.setSavepoint("savePoint");
RpcRequest request = map.get(null);
request.setIDToInvoke(IDtoInvoke);
dispatcher.invokeAsRequest(request, beanCache);
});
Assertions.assertThrows(SQLException.class, () -> {
serviceConnection.rollback(new FakeSavepoint());
RpcRequest request = map.get(null);
request.setIDToInvoke(IDtoInvoke);
dispatcher.invokeAsRequest(request, beanCache);
});
Assertions.assertThrows(SQLException.class, () -> {
serviceConnection.releaseSavepoint(new FakeSavepoint());
RpcRequest request = map.get(null);
request.setIDToInvoke(IDtoInvoke);
dispatcher.invokeAsRequest(request, beanCache);
});
}
@Test
void testCreateArrayOf() throws SQLException {
Array array = connection.createArrayOf("DOUBLE", new Double[]{0.1, 0.2});
}
@Test
void testCreateStruct() throws SQLException{
Assertions.assertThrows(SQLException.class, () -> {
serviceConnection.createStruct( "java.lang.String", new String[]{"hello"});
RpcRequest request = map.get(null);
request.setIDToInvoke(IDtoInvoke);
dispatcher.invokeAsRequest(request, beanCache);
});
}
@Test
void testAutoCommit() throws SQLException {
Connection conn = getConnection();
Assertions.assertTrue(conn.getAutoCommit());
conn.setAutoCommit(false);
Assertions.assertFalse(conn.getAutoCommit());
}
@Test
void testGetMetaData() throws SQLException {
DatabaseMetaData metaData = connection.getMetaData();
}
}

21
test/src/test/java/com/fanruan/DatabaseMetaDataTest.java

@ -0,0 +1,21 @@
package com.fanruan;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
/**
* @author Yichen Dai
* @date 2022/8/31 18:18
*/
public class DatabaseMetaDataTest extends BaseJDBCTest{
@Test
public void testGetConnection() throws SQLException {
Connection conn = getConnection();
DatabaseMetaData metaData = conn.getMetaData();
Assertions.assertEquals(conn, metaData.getConnection());
}
}

38
test/src/test/java/com/fanruan/InterceptorIT.java

@ -0,0 +1,38 @@
package com.fanruan;
import com.fanruan.pojo.message.RpcRequest;
import com.fanruan.proxy.interceptor.InterceptorUtils;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.Properties;
/**
* @author Yichen Dai
* @date 2022/8/29 11:11
*/
public class InterceptorIT implements MethodInterceptor {
Class<?> clazz;
Map<String, RpcRequest> map;
InterceptorIT(Class<?> clazz, Map<String, RpcRequest> map){
this.clazz = clazz;
this.map = map;
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
if(InterceptorUtils.isNotImplemented(method)
|| InterceptorUtils.isLocalMethod(method)){
return methodProxy.invokeSuper(o, objects);
}
RpcRequest request = InterceptorUtils.generateRequest(clazz, o, method, objects);
map.put(null, request);
return methodProxy.invokeSuper(o, objects);
}
}

23
test/src/test/java/com/fanruan/ProxyFactoryIT.java

@ -0,0 +1,23 @@
package com.fanruan;
import com.fanruan.pojo.message.RpcRequest;
import com.fanruan.proxy.interceptor.Interceptor;
import net.sf.cglib.proxy.Enhancer;
import java.util.Map;
import java.util.Properties;
/**
* @author Yichen Dai
* @date 2022/8/29 11:15
*/
public class ProxyFactoryIT {
public static Object getProxy(Class<?> clazz, Map<String, RpcRequest> map){
final Enhancer enhancer = new Enhancer();
enhancer.setClassLoader(clazz.getClassLoader());
enhancer.setSuperclass(clazz);
enhancer.setCallback(new InterceptorIT(clazz, map));
return enhancer.create();
}
}

183
test/src/test/java/com/fanruan/TestUtil.java

@ -0,0 +1,183 @@
package com.fanruan;
import org.junit.jupiter.api.*;
import java.sql.*;
/**
* @author Yichen Dai
* @date 2022/8/18 15:27
*/
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
@DisplayName("jdbc操作")
public class TestUtil extends BaseJDBCTest{
private Connection conn = null;
private Statement st = null;
private PreparedStatement pst = null;
@BeforeAll
void setup(){
openSocket();
}
@Test
@Order(1)
void testConnect() throws SQLException {
conn = getConnection();
}
@Test
@Order(2)
void testCreateTable1() throws SQLException {
// 创建 statement
st = conn.createStatement();
// 创建表
int num = st.executeUpdate("DROP TABLE student IF EXISTS;");
Assertions.assertEquals(0, num);
num = 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)" +
");");
Assertions.assertEquals(0, num);
}
@Test
@Order(3)
void testCreateTable2() throws SQLException {
// 创建表
int num = st.executeUpdate("DROP TABLE student_score IF EXISTS;");
Assertions.assertEquals(0, num);
num = st.executeUpdate("CREATE TABLE score (" +
"student_id int(10) PRIMARY KEY NOT NULL," +
"score int(10) NOT NULL" +
");"
);
Assertions.assertEquals(0, num);
}
@Test
@Order(4)
void testInsert1() throws SQLException {
// 插入数据
int num = st.executeUpdate("INSERT INTO student VALUES" +
"(1, '张三', '上海')," +
"(2, '李四', '北京')," +
"(3, '王五', '成都');");
Assertions.assertEquals(3, num);
}
@Test
@Order(5)
void testInsert2() throws SQLException {
// 插入数据
int num = st.executeUpdate("INSERT INTO score VALUES" +
"(1, 645)," +
"(2, 627)," +
"(3, 591);");
Assertions.assertEquals(3, num);
}
@Test
@Order(6)
void testUpdate() throws SQLException {
// 预查询语句 删除指定 ID
pst = conn.prepareStatement("UPDATE student" +
" SET student_name = '李华', student_address = '杭州'"+
"WHERE student_id = ?");
Assertions.assertNotNull(pst);
pst.setInt(1, 1);
int num = pst.executeUpdate();
Assertions.assertEquals(1, num);
}
@Test
@Order(7)
void testDelete() throws SQLException {
// 预查询语句 删除指定 ID
pst = conn.prepareStatement("delete from student where student_id = ?");
Assertions.assertNotNull(pst);
pst.setInt(1, 3);
int num = pst.executeUpdate();
Assertions.assertEquals(1, num);
}
@Test
@Order(8)
void testSelect() throws SQLException {
ResultSet rs = st.executeQuery("select * from student;");
Assertions.assertEquals(2, getSizeOfResultSet(rs));
closeSQLObjects(rs);
}
@Test
@Order(9)
void testSubSelect() throws SQLException {
// 插入数据
ResultSet rs = st.executeQuery(
"SELECT student_name FROM student " +
"WHERE student_id IN " +
"(SELECT student_id " +
"FROM score " +
"WHERE score > 600);"
);
Assertions.assertEquals(2, getSizeOfResultSet(rs));
closeSQLObjects(rs);
}
@Test
@Order(10)
void testJoin() throws SQLException {
// 插入数据
ResultSet rs = st.executeQuery(
"SELECT A.student_name " +
"FROM student A JOIN score B " +
"ON A.student_id = B.student_id " +
"WHERE score > 600;"
);
Assertions.assertEquals(2, getSizeOfResultSet(rs));
closeSQLObjects(rs);
}
@Test
@Order(10)
void testErrorQuery() throws SQLException {
// 插入数据
ResultSet rs = st.executeQuery("SELECT * FROM TEACHER;");
Assertions.assertFalse(rs.next());
closeSQLObjects(rs);
}
@AfterAll
void closeObject() throws SQLException {
closeSQLObjects(conn, st, pst);
}
}
Loading…
Cancel
Save