From 4affab88b190c5c490dcddf1aa57497096470640 Mon Sep 17 00:00:00 2001 From: Apress Date: Fri, 7 Oct 2016 00:38:33 +0100 Subject: [PATCH] First commit --- 2658.pdf | Bin 0 -> 150456 bytes 2659.pdf | Bin 0 -> 301212 bytes 9781590596371.jpg | Bin 0 -> 11316 bytes LICENSE.txt | 27 + README.md | 15 + contributing.md | 14 + ...baseMetaDataTool_DatabaseInformation.class | Bin 0 -> 1337 bytes ...abaseMetaDataTool_DatabaseInformation.java | 28 + .../GetColumnNamesFromResultSet_MySQL.class | Bin 0 -> 2673 bytes .../GetColumnNamesFromResultSet_MySQL.java | 89 + .../GetColumnNamesFromResultSet_Oracle.class | Bin 0 -> 2702 bytes .../GetColumnNamesFromResultSet_Oracle.java | 89 + .../GetColumnPrivileges_Oracle.class | Bin 0 -> 1848 bytes .../Chapter02/GetColumnPrivileges_Oracle.java | 48 + ...baseMetaDataTool_DatabaseInformation.class | Bin 0 -> 1324 bytes ...abaseMetaDataTool_DatabaseInformation.java | 28 + .../Chapter02/TestMySqlDataSource.class | Bin 0 -> 3526 bytes .../Chapter02/TestMySqlDataSource.java | 96 + .../TestMySqlDatabaseMetaDataTool.class | Bin 0 -> 4382 bytes .../TestMySqlDatabaseMetaDataTool.java | 207 ++ ...tabaseMetaDataTool_BestRowIdentifier.class | Bin 0 -> 1791 bytes ...atabaseMetaDataTool_BestRowIdentifier.java | 50 + .../TestOracleDatabaseMetaDataTool.class | Bin 0 -> 4458 bytes .../TestOracleDatabaseMetaDataTool.java | 211 ++ ...tabaseMetaDataTool_BestRowIdentifier.class | Bin 0 -> 1774 bytes ...atabaseMetaDataTool_BestRowIdentifier.java | 50 + .../Chapter03/DemoGetExportedKeys_MySQL.class | Bin 0 -> 1797 bytes .../Chapter03/DemoGetExportedKeys_MySQL.java | 44 + .../DemoGetExportedKeys_Oracle.class | Bin 0 -> 1830 bytes .../Chapter03/DemoGetExportedKeys_Oracle.java | 45 + .../Chapter03/DemoGetImportedKeys_MySQL.class | Bin 0 -> 1836 bytes .../Chapter03/DemoGetImportedKeys_MySQL.java | 45 + .../DemoGetImportedKeys_Oracle.class | Bin 0 -> 1869 bytes .../Chapter03/DemoGetImportedKeys_Oracle.java | 46 + .../Chapter03/TestBatchUpdate.class | Bin 0 -> 3096 bytes sourceMetadata/Chapter03/TestBatchUpdate.java | 74 + ...tabaseMetaDataTool_DriverInformation.class | Bin 0 -> 1660 bytes ...atabaseMetaDataTool_DriverInformation.java | 43 + .../TestMySqlDatabaseMetaDataTool_Index.class | Bin 0 -> 2471 bytes .../TestMySqlDatabaseMetaDataTool_Index.java | 90 + ...tabaseMetaDataTool_DriverInformation.class | Bin 0 -> 1680 bytes ...atabaseMetaDataTool_DriverInformation.java | 44 + ...TestOracleDatabaseMetaDataTool_Index.class | Bin 0 -> 2451 bytes .../TestOracleDatabaseMetaDataTool_Index.java | 89 + .../TestOracleDatabaseMetaDataTool_SPC.class | Bin 0 -> 2519 bytes .../TestOracleDatabaseMetaDataTool_SPC.java | 91 + .../TestMySqlResultSetMetaDataTool.class | Bin 0 -> 1988 bytes .../TestMySqlResultSetMetaDataTool.java | 52 + .../TestMySqlTableResultSetMetaDataTool.class | Bin 0 -> 1670 bytes .../TestMySqlTableResultSetMetaDataTool.java | 46 + ...TableResultSetMetaDataTool_WebRowSet.class | Bin 0 -> 1717 bytes ...lTableResultSetMetaDataTool_WebRowSet.java | 47 + .../TestOracleResultSetMetaDataTool.class | Bin 0 -> 2007 bytes .../TestOracleResultSetMetaDataTool.java | 53 + ...TestOracleTableResultSetMetaDataTool.class | Bin 0 -> 1689 bytes .../TestOracleTableResultSetMetaDataTool.java | 47 + ...TableResultSetMetaDataTool_WebRowSet.class | Bin 0 -> 1729 bytes ...eTableResultSetMetaDataTool_WebRowSet.java | 47 + sourceMetadata/Chapter05/CallProc3.class | Bin 0 -> 2023 bytes sourceMetadata/Chapter05/CallProc3.java | 62 + sourceMetadata/Chapter05/CallSimpleProc.class | Bin 0 -> 2027 bytes sourceMetadata/Chapter05/CallSimpleProc.java | 67 + .../Chapter05/CreateParameterMetaData.class | Bin 0 -> 1650 bytes .../Chapter05/CreateParameterMetaData.java | 41 + .../CreateParameterMetaData_Derby.class | Bin 0 -> 2341 bytes .../CreateParameterMetaData_Derby.java | 52 + .../CreateParameterMetaData_HSQLDB.class | Bin 0 -> 2079 bytes .../CreateParameterMetaData_HSQLDB.java | 55 + .../CreateParameterMetaData_Oracle.class | Bin 0 -> 1707 bytes .../CreateParameterMetaData_Oracle.java | 44 + .../Chapter05/DemoDynamicParams.class | Bin 0 -> 1791 bytes .../Chapter05/DemoDynamicParams.java | 67 + .../ExamineParameterMetaData_HSQLDB.class | Bin 0 -> 3118 bytes .../ExamineParameterMetaData_HSQLDB.java | 89 + .../ParameterMetaDataAsXML_HSQLDB.class | Bin 0 -> 3619 bytes .../ParameterMetaDataAsXML_HSQLDB.java | 126 + .../Chapter06/PrintDriverPropertyInfo.class | Bin 0 -> 2553 bytes .../Chapter06/PrintDriverPropertyInfo.java | 93 + .../Chapter06/TestDriverPropertyInfo.class | Bin 0 -> 2837 bytes .../Chapter06/TestDriverPropertyInfo.java | 114 + .../TestDriverPropertyInfo_MySQL.class | Bin 0 -> 3410 bytes .../TestDriverPropertyInfo_MySQL.java | 135 ++ sourceMetadata/Chapter07/AgeFilter.class | Bin 0 -> 1201 bytes sourceMetadata/Chapter07/AgeFilter.java | 72 + .../CreateCustomRowSetMetaData.class | Bin 0 -> 1587 bytes .../Chapter07/CreateCustomRowSetMetaData.java | 79 + .../Chapter07/CreateRowSetMetaData.class | Bin 0 -> 1779 bytes .../Chapter07/CreateRowSetMetaData.java | 53 + .../Chapter07/CustomRowSetReader.class | Bin 0 -> 2261 bytes .../Chapter07/CustomRowSetReader.java | 67 + .../Chapter07/CustomRowSetWriter.class | Bin 0 -> 722 bytes .../Chapter07/CustomRowSetWriter.java | 23 + .../Chapter07/DemoCustomRowSet.class | Bin 0 -> 2815 bytes .../Chapter07/DemoCustomRowSet.java | 111 + .../Chapter07/DemoFilteredRowSet.class | Bin 0 -> 2491 bytes .../Chapter07/DemoFilteredRowSet.java | 95 + sourceMetadata/Chapter07/DemoWebRowSet.class | Bin 0 -> 1685 bytes sourceMetadata/Chapter07/DemoWebRowSet.java | 64 + .../Chapter07/ExampleListener.class | Bin 0 -> 859 bytes sourceMetadata/Chapter07/ExampleListener.java | 22 + .../Chapter07/JdbcRowSetExample.class | Bin 0 -> 1862 bytes .../Chapter07/JdbcRowSetExample.java | 55 + sourceMetadata/Chapter07/MySyncProvider.class | Bin 0 -> 1696 bytes sourceMetadata/Chapter07/MySyncProvider.java | 92 + .../Chapter07/WebRowSetExample.class | Bin 0 -> 2815 bytes .../Chapter07/WebRowSetExample.java | 92 + .../Chapter07/WebRowSetMetaDataExample.class | Bin 0 -> 2052 bytes .../Chapter07/WebRowSetMetaDataExample.java | 65 + sourceMetadata/Chapter08/GetColumns.class | Bin 0 -> 5168 bytes sourceMetadata/Chapter08/GetColumns.java | 188 ++ sourceMetadata/Chapter08/GetPKColumns.class | Bin 0 -> 3985 bytes sourceMetadata/Chapter08/GetPKColumns.java | 133 + sourceMetadata/Chapter08/GetSQLKeywords.class | Bin 0 -> 3558 bytes sourceMetadata/Chapter08/GetSQLKeywords.java | 119 + .../Chapter08/GetStoredProcedures.class | Bin 0 -> 3896 bytes .../Chapter08/GetStoredProcedures.java | 161 ++ sourceMetadata/Chapter08/GetTableTypes.class | Bin 0 -> 3719 bytes sourceMetadata/Chapter08/GetTableTypes.java | 127 + sourceMetadata/Chapter08/GetTables.class | Bin 0 -> 4783 bytes sourceMetadata/Chapter08/GetTables.java | 180 ++ .../Chapter08/GetTablesAndViews.class | Bin 0 -> 5264 bytes .../Chapter08/GetTablesAndViews.java | 201 ++ sourceMetadata/Chapter08/GetViews.class | Bin 0 -> 4769 bytes sourceMetadata/Chapter08/GetViews.java | 184 ++ .../Chapter08/MyDatabaseServlet.class | Bin 0 -> 2712 bytes .../Chapter08/MyDatabaseServlet.java | 68 + .../Chapter09/GetBestRowIdentifier.class | Bin 0 -> 5148 bytes .../Chapter09/GetBestRowIdentifier.java | 229 ++ sourceMetadata/Chapter09/GetCatalogs.class | Bin 0 -> 3493 bytes sourceMetadata/Chapter09/GetCatalogs.java | 118 + .../Chapter09/GetColumnPrivileges.class | Bin 0 -> 4516 bytes .../Chapter09/GetColumnPrivileges.java | 195 ++ .../Chapter09/GetExportedKeys.class | Bin 0 -> 6111 bytes sourceMetadata/Chapter09/GetExportedKeys.java | 273 +++ sourceMetadata/Chapter09/GetForeignKeys.class | Bin 0 -> 6126 bytes sourceMetadata/Chapter09/GetForeignKeys.java | 270 +++ .../Chapter09/GetRowSetMetaData.class | Bin 0 -> 2111 bytes .../Chapter09/GetRowSetMetaData.java | 81 + sourceMetadata/Chapter09/GetSPColumns.class | Bin 0 -> 5041 bytes sourceMetadata/Chapter09/GetSPColumns.java | 208 ++ sourceMetadata/Chapter09/GetSchemas.class | Bin 0 -> 3487 bytes sourceMetadata/Chapter09/GetSchemas.java | 116 + .../Chapter09/GetTablePrivileges.class | Bin 0 -> 4319 bytes .../Chapter09/GetTablePrivileges.java | 185 ++ sourceMetadata/Chapter09/GetTypes.class | Bin 0 -> 3143 bytes sourceMetadata/Chapter09/GetTypes.java | 116 + sourceMetadata/Chapter10/tables.xml | 26 + sourceMetadata/README.txt | 78 + .../jcb-package/src/conf/datasource.xml | 55 + .../src/jcb/db/DataSourceConfig.class | Bin 0 -> 3123 bytes .../src/jcb/db/DataSourceConfig.java | 126 + .../src/jcb/db/DataSourceDigester.class | Bin 0 -> 2692 bytes .../src/jcb/db/DataSourceDigester.java | 131 + .../src/jcb/db/DataSourceManager.class | Bin 0 -> 577 bytes .../src/jcb/db/DataSourceManager.java | 41 + .../jcb/db/VeryBasicConnectionManager.class | Bin 0 -> 1695 bytes .../jcb/db/VeryBasicConnectionManager.java | 70 + .../src/jcb/meta/DatabaseMetaDataTool.class | Bin 0 -> 26686 bytes .../src/jcb/meta/DatabaseMetaDataTool.java | 2055 ++++++++++++++++ .../src/jcb/meta/ResultSetMetaDataTool.class | Bin 0 -> 5897 bytes .../src/jcb/meta/ResultSetMetaDataTool.java | 414 ++++ .../jcb-package/src/jcb/util/DOM2Writer.class | Bin 0 -> 5250 bytes .../jcb-package/src/jcb/util/DOM2Writer.java | 467 ++++ .../jcb-package/src/jcb/util/DataTypes.class | Bin 0 -> 770 bytes .../jcb-package/src/jcb/util/DataTypes.java | 19 + .../src/jcb/util/DatabaseUtil.class | Bin 0 -> 1654 bytes .../src/jcb/util/DatabaseUtil.java | 116 + .../src/jcb/util/DocumentManager.class | Bin 0 -> 33335 bytes .../src/jcb/util/DocumentManager.java | 2136 +++++++++++++++++ .../src/jcb/util/DriverManagerTool.class | Bin 0 -> 2940 bytes .../src/jcb/util/DriverManagerTool.java | 127 + .../jcb-package/src/jcb/util/IOUtil.class | Bin 0 -> 1362 bytes .../jcb-package/src/jcb/util/IOUtil.java | 127 + .../jcb-package/src/jcb/util/Mapping.class | Bin 0 -> 942 bytes .../jcb-package/src/jcb/util/Mapping.java | 98 + .../jcb-package/src/jcb/util/NSStack.class | Bin 0 -> 2649 bytes .../jcb-package/src/jcb/util/NSStack.java | 319 +++ .../jcb-package/src/jcb/util/RandomGUID.class | Bin 0 -> 2886 bytes .../jcb-package/src/jcb/util/RandomGUID.java | 234 ++ .../jcb-package/src/jcb/util/SimpleXML.class | Bin 0 -> 17273 bytes .../jcb-package/src/jcb/util/SimpleXML.java | 1263 ++++++++++ .../jcb-package/src/jcb/util/SqlUtil.class | Bin 0 -> 5243 bytes .../jcb-package/src/jcb/util/SqlUtil.java | 212 ++ .../src/jcb/util/TransformUtil.class | Bin 0 -> 3194 bytes .../src/jcb/util/TransformUtil.java | 169 ++ .../src/jcb/util/XMLValidator.class | Bin 0 -> 6397 bytes .../src/jcb/util/XMLValidator.java | 334 +++ .../jcb-package/src/servlets/Base64.class | Bin 0 -> 2418 bytes .../jcb-package/src/servlets/Base64.java | 125 + .../src/servlets/BlobServletMySql.class | Bin 0 -> 3925 bytes .../src/servlets/BlobServletMySql.java | 116 + .../servlets/DeleteBlobFromMySqlServlet.class | Bin 0 -> 2600 bytes .../servlets/DeleteBlobFromMySqlServlet.java | 63 + .../DeleteBlobFromOracleServlet.class | Bin 0 -> 2625 bytes .../servlets/DeleteBlobFromOracleServlet.java | 63 + .../servlets/DeleteClobFromMySqlServlet.class | Bin 0 -> 2441 bytes .../servlets/DeleteClobFromMySqlServlet.java | 59 + .../DeleteClobFromOracleServlet.class | Bin 0 -> 2473 bytes .../servlets/DeleteClobFromOracleServlet.java | 59 + .../DisplayMySqlBlobAsURLServlet.class | Bin 0 -> 4138 bytes .../DisplayMySqlBlobAsURLServlet.java | 136 ++ .../servlets/DisplayMySqlBlobServlet.class | Bin 0 -> 3479 bytes .../src/servlets/DisplayMySqlBlobServlet.java | 101 + .../DisplayMySqlClobAsURLServlet.class | Bin 0 -> 3933 bytes .../DisplayMySqlClobAsURLServlet.java | 125 + .../servlets/DisplayMySqlClobServlet.class | Bin 0 -> 3207 bytes .../src/servlets/DisplayMySqlClobServlet.java | 89 + .../DisplayOracleBlobAsURLServlet.class | Bin 0 -> 4163 bytes .../DisplayOracleBlobAsURLServlet.java | 137 ++ .../servlets/DisplayOracleBlobServlet.class | Bin 0 -> 3504 bytes .../servlets/DisplayOracleBlobServlet.java | 101 + .../DisplayOracleClobAsURLServlet.class | Bin 0 -> 3974 bytes .../DisplayOracleClobAsURLServlet.java | 127 + .../servlets/DisplayOracleClobServlet.class | Bin 0 -> 3227 bytes .../servlets/DisplayOracleClobServlet.java | 89 + .../jcb-package/src/servlets/GetColumns.class | Bin 0 -> 5168 bytes .../jcb-package/src/servlets/GetColumns.java | 188 ++ .../src/servlets/GetExportedKeys.class | Bin 0 -> 6111 bytes .../src/servlets/GetExportedKeys.java | 273 +++ .../src/servlets/GetForeignKeys.class | Bin 0 -> 6126 bytes .../src/servlets/GetForeignKeys.java | 270 +++ .../src/servlets/GetRowSetMetaData.class | Bin 0 -> 2111 bytes .../src/servlets/GetRowSetMetaData.java | 81 + .../src/servlets/GetSPColumns.class | Bin 0 -> 5041 bytes .../src/servlets/GetSPColumns.java | 208 ++ .../src/servlets/GetSQLKeywords.class | Bin 0 -> 3558 bytes .../src/servlets/GetSQLKeywords.java | 119 + .../src/servlets/GetStoredProcedures.class | Bin 0 -> 3896 bytes .../src/servlets/GetStoredProcedures.java | 161 ++ .../src/servlets/GetTableTypes.class | Bin 0 -> 3719 bytes .../src/servlets/GetTableTypes.java | 127 + .../jcb-package/src/servlets/GetTables.class | Bin 0 -> 4783 bytes .../jcb-package/src/servlets/GetTables.java | 180 ++ .../src/servlets/GetTablesAndViews.class | Bin 0 -> 5264 bytes .../src/servlets/GetTablesAndViews.java | 201 ++ .../jcb-package/src/servlets/GetTypes.class | Bin 0 -> 3143 bytes .../jcb-package/src/servlets/GetTypes.java | 116 + .../jcb-package/src/servlets/GetViews.class | Bin 0 -> 4769 bytes .../jcb-package/src/servlets/GetViews.java | 184 ++ .../servlets/InsertClobToMySqlServlet.class | Bin 0 -> 3307 bytes .../servlets/InsertClobToMySqlServlet.java | 99 + .../servlets/InsertClobToOracleServlet.class | Bin 0 -> 3340 bytes .../servlets/InsertClobToOracleServlet.java | 99 + .../src/servlets/JDBCDemoCreate.class | Bin 0 -> 1312 bytes .../src/servlets/JDBCDemoCreate.java | 57 + .../src/servlets/JDBCDemoSelect.class | Bin 0 -> 1809 bytes .../src/servlets/JDBCDemoSelect.java | 63 + .../src/servlets/JDBCDemoUpdate.class | Bin 0 -> 1743 bytes .../src/servlets/JDBCDemoUpdate.java | 70 + .../src/servlets/JDBCEmbedObjectDemo.class | Bin 0 -> 3713 bytes .../src/servlets/JDBCEmbedObjectDemo.java | 136 ++ .../src/servlets/KeyValuePair.class | Bin 0 -> 982 bytes .../src/servlets/KeyValuePair.java | 45 + .../jcb-package/src/servlets/MakeList.class | Bin 0 -> 2514 bytes .../jcb-package/src/servlets/MakeList.java | 182 ++ .../src/servlets/MyDatabaseServlet.class | Bin 0 -> 2712 bytes .../src/servlets/MyDatabaseServlet.java | 68 + .../servlets/PreparedHTML$PlaceHolder.class | Bin 0 -> 666 bytes .../src/servlets/PreparedHTML.class | Bin 0 -> 2844 bytes .../src/servlets/PreparedHTML.java | 237 ++ .../servlets/UpdateBlobToMySqlServlet.class | Bin 0 -> 3389 bytes .../servlets/UpdateBlobToMySqlServlet.java | 100 + .../servlets/UpdateBlobToOracleServlet.class | Bin 0 -> 4401 bytes .../servlets/UpdateBlobToOracleServlet.java | 147 ++ .../src/servlets/UpdateMySqlClobServlet.class | Bin 0 -> 3225 bytes .../src/servlets/UpdateMySqlClobServlet.java | 96 + .../servlets/UpdateOracleClobServlet.class | Bin 0 -> 3258 bytes .../src/servlets/UpdateOracleClobServlet.java | 97 + 268 files changed, 20453 insertions(+) create mode 100644 2658.pdf create mode 100644 2659.pdf create mode 100644 9781590596371.jpg create mode 100644 LICENSE.txt create mode 100644 README.md create mode 100644 contributing.md create mode 100644 sourceMetadata/Chapter01/TestDatabaseMetaDataTool_DatabaseInformation.class create mode 100644 sourceMetadata/Chapter01/TestDatabaseMetaDataTool_DatabaseInformation.java create mode 100644 sourceMetadata/Chapter02/GetColumnNamesFromResultSet_MySQL.class create mode 100644 sourceMetadata/Chapter02/GetColumnNamesFromResultSet_MySQL.java create mode 100644 sourceMetadata/Chapter02/GetColumnNamesFromResultSet_Oracle.class create mode 100644 sourceMetadata/Chapter02/GetColumnNamesFromResultSet_Oracle.java create mode 100644 sourceMetadata/Chapter02/GetColumnPrivileges_Oracle.class create mode 100644 sourceMetadata/Chapter02/GetColumnPrivileges_Oracle.java create mode 100644 sourceMetadata/Chapter02/TestDatabaseMetaDataTool_DatabaseInformation.class create mode 100644 sourceMetadata/Chapter02/TestDatabaseMetaDataTool_DatabaseInformation.java create mode 100644 sourceMetadata/Chapter02/TestMySqlDataSource.class create mode 100644 sourceMetadata/Chapter02/TestMySqlDataSource.java create mode 100644 sourceMetadata/Chapter02/TestMySqlDatabaseMetaDataTool.class create mode 100644 sourceMetadata/Chapter02/TestMySqlDatabaseMetaDataTool.java create mode 100644 sourceMetadata/Chapter02/TestMySqlDatabaseMetaDataTool_BestRowIdentifier.class create mode 100644 sourceMetadata/Chapter02/TestMySqlDatabaseMetaDataTool_BestRowIdentifier.java create mode 100644 sourceMetadata/Chapter02/TestOracleDatabaseMetaDataTool.class create mode 100644 sourceMetadata/Chapter02/TestOracleDatabaseMetaDataTool.java create mode 100644 sourceMetadata/Chapter02/TestOracleDatabaseMetaDataTool_BestRowIdentifier.class create mode 100644 sourceMetadata/Chapter02/TestOracleDatabaseMetaDataTool_BestRowIdentifier.java create mode 100644 sourceMetadata/Chapter03/DemoGetExportedKeys_MySQL.class create mode 100644 sourceMetadata/Chapter03/DemoGetExportedKeys_MySQL.java create mode 100644 sourceMetadata/Chapter03/DemoGetExportedKeys_Oracle.class create mode 100644 sourceMetadata/Chapter03/DemoGetExportedKeys_Oracle.java create mode 100644 sourceMetadata/Chapter03/DemoGetImportedKeys_MySQL.class create mode 100644 sourceMetadata/Chapter03/DemoGetImportedKeys_MySQL.java create mode 100644 sourceMetadata/Chapter03/DemoGetImportedKeys_Oracle.class create mode 100644 sourceMetadata/Chapter03/DemoGetImportedKeys_Oracle.java create mode 100644 sourceMetadata/Chapter03/TestBatchUpdate.class create mode 100644 sourceMetadata/Chapter03/TestBatchUpdate.java create mode 100644 sourceMetadata/Chapter03/TestMySqlDatabaseMetaDataTool_DriverInformation.class create mode 100644 sourceMetadata/Chapter03/TestMySqlDatabaseMetaDataTool_DriverInformation.java create mode 100644 sourceMetadata/Chapter03/TestMySqlDatabaseMetaDataTool_Index.class create mode 100644 sourceMetadata/Chapter03/TestMySqlDatabaseMetaDataTool_Index.java create mode 100644 sourceMetadata/Chapter03/TestOracleDatabaseMetaDataTool_DriverInformation.class create mode 100644 sourceMetadata/Chapter03/TestOracleDatabaseMetaDataTool_DriverInformation.java create mode 100644 sourceMetadata/Chapter03/TestOracleDatabaseMetaDataTool_Index.class create mode 100644 sourceMetadata/Chapter03/TestOracleDatabaseMetaDataTool_Index.java create mode 100644 sourceMetadata/Chapter03/TestOracleDatabaseMetaDataTool_SPC.class create mode 100644 sourceMetadata/Chapter03/TestOracleDatabaseMetaDataTool_SPC.java create mode 100644 sourceMetadata/Chapter04/TestMySqlResultSetMetaDataTool.class create mode 100644 sourceMetadata/Chapter04/TestMySqlResultSetMetaDataTool.java create mode 100644 sourceMetadata/Chapter04/TestMySqlTableResultSetMetaDataTool.class create mode 100644 sourceMetadata/Chapter04/TestMySqlTableResultSetMetaDataTool.java create mode 100644 sourceMetadata/Chapter04/TestMySqlTableResultSetMetaDataTool_WebRowSet.class create mode 100644 sourceMetadata/Chapter04/TestMySqlTableResultSetMetaDataTool_WebRowSet.java create mode 100644 sourceMetadata/Chapter04/TestOracleResultSetMetaDataTool.class create mode 100644 sourceMetadata/Chapter04/TestOracleResultSetMetaDataTool.java create mode 100644 sourceMetadata/Chapter04/TestOracleTableResultSetMetaDataTool.class create mode 100644 sourceMetadata/Chapter04/TestOracleTableResultSetMetaDataTool.java create mode 100644 sourceMetadata/Chapter04/TestOracleTableResultSetMetaDataTool_WebRowSet.class create mode 100644 sourceMetadata/Chapter04/TestOracleTableResultSetMetaDataTool_WebRowSet.java create mode 100644 sourceMetadata/Chapter05/CallProc3.class create mode 100644 sourceMetadata/Chapter05/CallProc3.java create mode 100644 sourceMetadata/Chapter05/CallSimpleProc.class create mode 100644 sourceMetadata/Chapter05/CallSimpleProc.java create mode 100644 sourceMetadata/Chapter05/CreateParameterMetaData.class create mode 100644 sourceMetadata/Chapter05/CreateParameterMetaData.java create mode 100644 sourceMetadata/Chapter05/CreateParameterMetaData_Derby.class create mode 100644 sourceMetadata/Chapter05/CreateParameterMetaData_Derby.java create mode 100644 sourceMetadata/Chapter05/CreateParameterMetaData_HSQLDB.class create mode 100644 sourceMetadata/Chapter05/CreateParameterMetaData_HSQLDB.java create mode 100644 sourceMetadata/Chapter05/CreateParameterMetaData_Oracle.class create mode 100644 sourceMetadata/Chapter05/CreateParameterMetaData_Oracle.java create mode 100644 sourceMetadata/Chapter05/DemoDynamicParams.class create mode 100644 sourceMetadata/Chapter05/DemoDynamicParams.java create mode 100644 sourceMetadata/Chapter05/ExamineParameterMetaData_HSQLDB.class create mode 100644 sourceMetadata/Chapter05/ExamineParameterMetaData_HSQLDB.java create mode 100644 sourceMetadata/Chapter05/ParameterMetaDataAsXML_HSQLDB.class create mode 100644 sourceMetadata/Chapter05/ParameterMetaDataAsXML_HSQLDB.java create mode 100644 sourceMetadata/Chapter06/PrintDriverPropertyInfo.class create mode 100644 sourceMetadata/Chapter06/PrintDriverPropertyInfo.java create mode 100644 sourceMetadata/Chapter06/TestDriverPropertyInfo.class create mode 100644 sourceMetadata/Chapter06/TestDriverPropertyInfo.java create mode 100644 sourceMetadata/Chapter06/TestDriverPropertyInfo_MySQL.class create mode 100644 sourceMetadata/Chapter06/TestDriverPropertyInfo_MySQL.java create mode 100644 sourceMetadata/Chapter07/AgeFilter.class create mode 100644 sourceMetadata/Chapter07/AgeFilter.java create mode 100644 sourceMetadata/Chapter07/CreateCustomRowSetMetaData.class create mode 100644 sourceMetadata/Chapter07/CreateCustomRowSetMetaData.java create mode 100644 sourceMetadata/Chapter07/CreateRowSetMetaData.class create mode 100644 sourceMetadata/Chapter07/CreateRowSetMetaData.java create mode 100644 sourceMetadata/Chapter07/CustomRowSetReader.class create mode 100644 sourceMetadata/Chapter07/CustomRowSetReader.java create mode 100644 sourceMetadata/Chapter07/CustomRowSetWriter.class create mode 100644 sourceMetadata/Chapter07/CustomRowSetWriter.java create mode 100644 sourceMetadata/Chapter07/DemoCustomRowSet.class create mode 100644 sourceMetadata/Chapter07/DemoCustomRowSet.java create mode 100644 sourceMetadata/Chapter07/DemoFilteredRowSet.class create mode 100644 sourceMetadata/Chapter07/DemoFilteredRowSet.java create mode 100644 sourceMetadata/Chapter07/DemoWebRowSet.class create mode 100644 sourceMetadata/Chapter07/DemoWebRowSet.java create mode 100644 sourceMetadata/Chapter07/ExampleListener.class create mode 100644 sourceMetadata/Chapter07/ExampleListener.java create mode 100644 sourceMetadata/Chapter07/JdbcRowSetExample.class create mode 100644 sourceMetadata/Chapter07/JdbcRowSetExample.java create mode 100644 sourceMetadata/Chapter07/MySyncProvider.class create mode 100644 sourceMetadata/Chapter07/MySyncProvider.java create mode 100644 sourceMetadata/Chapter07/WebRowSetExample.class create mode 100644 sourceMetadata/Chapter07/WebRowSetExample.java create mode 100644 sourceMetadata/Chapter07/WebRowSetMetaDataExample.class create mode 100644 sourceMetadata/Chapter07/WebRowSetMetaDataExample.java create mode 100644 sourceMetadata/Chapter08/GetColumns.class create mode 100644 sourceMetadata/Chapter08/GetColumns.java create mode 100644 sourceMetadata/Chapter08/GetPKColumns.class create mode 100644 sourceMetadata/Chapter08/GetPKColumns.java create mode 100644 sourceMetadata/Chapter08/GetSQLKeywords.class create mode 100644 sourceMetadata/Chapter08/GetSQLKeywords.java create mode 100644 sourceMetadata/Chapter08/GetStoredProcedures.class create mode 100644 sourceMetadata/Chapter08/GetStoredProcedures.java create mode 100644 sourceMetadata/Chapter08/GetTableTypes.class create mode 100644 sourceMetadata/Chapter08/GetTableTypes.java create mode 100644 sourceMetadata/Chapter08/GetTables.class create mode 100644 sourceMetadata/Chapter08/GetTables.java create mode 100644 sourceMetadata/Chapter08/GetTablesAndViews.class create mode 100644 sourceMetadata/Chapter08/GetTablesAndViews.java create mode 100644 sourceMetadata/Chapter08/GetViews.class create mode 100644 sourceMetadata/Chapter08/GetViews.java create mode 100644 sourceMetadata/Chapter08/MyDatabaseServlet.class create mode 100644 sourceMetadata/Chapter08/MyDatabaseServlet.java create mode 100644 sourceMetadata/Chapter09/GetBestRowIdentifier.class create mode 100644 sourceMetadata/Chapter09/GetBestRowIdentifier.java create mode 100644 sourceMetadata/Chapter09/GetCatalogs.class create mode 100644 sourceMetadata/Chapter09/GetCatalogs.java create mode 100644 sourceMetadata/Chapter09/GetColumnPrivileges.class create mode 100644 sourceMetadata/Chapter09/GetColumnPrivileges.java create mode 100644 sourceMetadata/Chapter09/GetExportedKeys.class create mode 100644 sourceMetadata/Chapter09/GetExportedKeys.java create mode 100644 sourceMetadata/Chapter09/GetForeignKeys.class create mode 100644 sourceMetadata/Chapter09/GetForeignKeys.java create mode 100644 sourceMetadata/Chapter09/GetRowSetMetaData.class create mode 100644 sourceMetadata/Chapter09/GetRowSetMetaData.java create mode 100644 sourceMetadata/Chapter09/GetSPColumns.class create mode 100644 sourceMetadata/Chapter09/GetSPColumns.java create mode 100644 sourceMetadata/Chapter09/GetSchemas.class create mode 100644 sourceMetadata/Chapter09/GetSchemas.java create mode 100644 sourceMetadata/Chapter09/GetTablePrivileges.class create mode 100644 sourceMetadata/Chapter09/GetTablePrivileges.java create mode 100644 sourceMetadata/Chapter09/GetTypes.class create mode 100644 sourceMetadata/Chapter09/GetTypes.java create mode 100644 sourceMetadata/Chapter10/tables.xml create mode 100644 sourceMetadata/README.txt create mode 100644 sourceMetadata/jcb-package/src/conf/datasource.xml create mode 100644 sourceMetadata/jcb-package/src/jcb/db/DataSourceConfig.class create mode 100644 sourceMetadata/jcb-package/src/jcb/db/DataSourceConfig.java create mode 100644 sourceMetadata/jcb-package/src/jcb/db/DataSourceDigester.class create mode 100644 sourceMetadata/jcb-package/src/jcb/db/DataSourceDigester.java create mode 100644 sourceMetadata/jcb-package/src/jcb/db/DataSourceManager.class create mode 100644 sourceMetadata/jcb-package/src/jcb/db/DataSourceManager.java create mode 100644 sourceMetadata/jcb-package/src/jcb/db/VeryBasicConnectionManager.class create mode 100644 sourceMetadata/jcb-package/src/jcb/db/VeryBasicConnectionManager.java create mode 100644 sourceMetadata/jcb-package/src/jcb/meta/DatabaseMetaDataTool.class create mode 100644 sourceMetadata/jcb-package/src/jcb/meta/DatabaseMetaDataTool.java create mode 100644 sourceMetadata/jcb-package/src/jcb/meta/ResultSetMetaDataTool.class create mode 100644 sourceMetadata/jcb-package/src/jcb/meta/ResultSetMetaDataTool.java create mode 100644 sourceMetadata/jcb-package/src/jcb/util/DOM2Writer.class create mode 100644 sourceMetadata/jcb-package/src/jcb/util/DOM2Writer.java create mode 100644 sourceMetadata/jcb-package/src/jcb/util/DataTypes.class create mode 100644 sourceMetadata/jcb-package/src/jcb/util/DataTypes.java create mode 100644 sourceMetadata/jcb-package/src/jcb/util/DatabaseUtil.class create mode 100644 sourceMetadata/jcb-package/src/jcb/util/DatabaseUtil.java create mode 100644 sourceMetadata/jcb-package/src/jcb/util/DocumentManager.class create mode 100644 sourceMetadata/jcb-package/src/jcb/util/DocumentManager.java create mode 100644 sourceMetadata/jcb-package/src/jcb/util/DriverManagerTool.class create mode 100644 sourceMetadata/jcb-package/src/jcb/util/DriverManagerTool.java create mode 100644 sourceMetadata/jcb-package/src/jcb/util/IOUtil.class create mode 100644 sourceMetadata/jcb-package/src/jcb/util/IOUtil.java create mode 100644 sourceMetadata/jcb-package/src/jcb/util/Mapping.class create mode 100644 sourceMetadata/jcb-package/src/jcb/util/Mapping.java create mode 100644 sourceMetadata/jcb-package/src/jcb/util/NSStack.class create mode 100644 sourceMetadata/jcb-package/src/jcb/util/NSStack.java create mode 100644 sourceMetadata/jcb-package/src/jcb/util/RandomGUID.class create mode 100644 sourceMetadata/jcb-package/src/jcb/util/RandomGUID.java create mode 100644 sourceMetadata/jcb-package/src/jcb/util/SimpleXML.class create mode 100644 sourceMetadata/jcb-package/src/jcb/util/SimpleXML.java create mode 100644 sourceMetadata/jcb-package/src/jcb/util/SqlUtil.class create mode 100644 sourceMetadata/jcb-package/src/jcb/util/SqlUtil.java create mode 100644 sourceMetadata/jcb-package/src/jcb/util/TransformUtil.class create mode 100644 sourceMetadata/jcb-package/src/jcb/util/TransformUtil.java create mode 100644 sourceMetadata/jcb-package/src/jcb/util/XMLValidator.class create mode 100644 sourceMetadata/jcb-package/src/jcb/util/XMLValidator.java create mode 100644 sourceMetadata/jcb-package/src/servlets/Base64.class create mode 100644 sourceMetadata/jcb-package/src/servlets/Base64.java create mode 100644 sourceMetadata/jcb-package/src/servlets/BlobServletMySql.class create mode 100644 sourceMetadata/jcb-package/src/servlets/BlobServletMySql.java create mode 100644 sourceMetadata/jcb-package/src/servlets/DeleteBlobFromMySqlServlet.class create mode 100644 sourceMetadata/jcb-package/src/servlets/DeleteBlobFromMySqlServlet.java create mode 100644 sourceMetadata/jcb-package/src/servlets/DeleteBlobFromOracleServlet.class create mode 100644 sourceMetadata/jcb-package/src/servlets/DeleteBlobFromOracleServlet.java create mode 100644 sourceMetadata/jcb-package/src/servlets/DeleteClobFromMySqlServlet.class create mode 100644 sourceMetadata/jcb-package/src/servlets/DeleteClobFromMySqlServlet.java create mode 100644 sourceMetadata/jcb-package/src/servlets/DeleteClobFromOracleServlet.class create mode 100644 sourceMetadata/jcb-package/src/servlets/DeleteClobFromOracleServlet.java create mode 100644 sourceMetadata/jcb-package/src/servlets/DisplayMySqlBlobAsURLServlet.class create mode 100644 sourceMetadata/jcb-package/src/servlets/DisplayMySqlBlobAsURLServlet.java create mode 100644 sourceMetadata/jcb-package/src/servlets/DisplayMySqlBlobServlet.class create mode 100644 sourceMetadata/jcb-package/src/servlets/DisplayMySqlBlobServlet.java create mode 100644 sourceMetadata/jcb-package/src/servlets/DisplayMySqlClobAsURLServlet.class create mode 100644 sourceMetadata/jcb-package/src/servlets/DisplayMySqlClobAsURLServlet.java create mode 100644 sourceMetadata/jcb-package/src/servlets/DisplayMySqlClobServlet.class create mode 100644 sourceMetadata/jcb-package/src/servlets/DisplayMySqlClobServlet.java create mode 100644 sourceMetadata/jcb-package/src/servlets/DisplayOracleBlobAsURLServlet.class create mode 100644 sourceMetadata/jcb-package/src/servlets/DisplayOracleBlobAsURLServlet.java create mode 100644 sourceMetadata/jcb-package/src/servlets/DisplayOracleBlobServlet.class create mode 100644 sourceMetadata/jcb-package/src/servlets/DisplayOracleBlobServlet.java create mode 100644 sourceMetadata/jcb-package/src/servlets/DisplayOracleClobAsURLServlet.class create mode 100644 sourceMetadata/jcb-package/src/servlets/DisplayOracleClobAsURLServlet.java create mode 100644 sourceMetadata/jcb-package/src/servlets/DisplayOracleClobServlet.class create mode 100644 sourceMetadata/jcb-package/src/servlets/DisplayOracleClobServlet.java create mode 100644 sourceMetadata/jcb-package/src/servlets/GetColumns.class create mode 100644 sourceMetadata/jcb-package/src/servlets/GetColumns.java create mode 100644 sourceMetadata/jcb-package/src/servlets/GetExportedKeys.class create mode 100644 sourceMetadata/jcb-package/src/servlets/GetExportedKeys.java create mode 100644 sourceMetadata/jcb-package/src/servlets/GetForeignKeys.class create mode 100644 sourceMetadata/jcb-package/src/servlets/GetForeignKeys.java create mode 100644 sourceMetadata/jcb-package/src/servlets/GetRowSetMetaData.class create mode 100644 sourceMetadata/jcb-package/src/servlets/GetRowSetMetaData.java create mode 100644 sourceMetadata/jcb-package/src/servlets/GetSPColumns.class create mode 100644 sourceMetadata/jcb-package/src/servlets/GetSPColumns.java create mode 100644 sourceMetadata/jcb-package/src/servlets/GetSQLKeywords.class create mode 100644 sourceMetadata/jcb-package/src/servlets/GetSQLKeywords.java create mode 100644 sourceMetadata/jcb-package/src/servlets/GetStoredProcedures.class create mode 100644 sourceMetadata/jcb-package/src/servlets/GetStoredProcedures.java create mode 100644 sourceMetadata/jcb-package/src/servlets/GetTableTypes.class create mode 100644 sourceMetadata/jcb-package/src/servlets/GetTableTypes.java create mode 100644 sourceMetadata/jcb-package/src/servlets/GetTables.class create mode 100644 sourceMetadata/jcb-package/src/servlets/GetTables.java create mode 100644 sourceMetadata/jcb-package/src/servlets/GetTablesAndViews.class create mode 100644 sourceMetadata/jcb-package/src/servlets/GetTablesAndViews.java create mode 100644 sourceMetadata/jcb-package/src/servlets/GetTypes.class create mode 100644 sourceMetadata/jcb-package/src/servlets/GetTypes.java create mode 100644 sourceMetadata/jcb-package/src/servlets/GetViews.class create mode 100644 sourceMetadata/jcb-package/src/servlets/GetViews.java create mode 100644 sourceMetadata/jcb-package/src/servlets/InsertClobToMySqlServlet.class create mode 100644 sourceMetadata/jcb-package/src/servlets/InsertClobToMySqlServlet.java create mode 100644 sourceMetadata/jcb-package/src/servlets/InsertClobToOracleServlet.class create mode 100644 sourceMetadata/jcb-package/src/servlets/InsertClobToOracleServlet.java create mode 100644 sourceMetadata/jcb-package/src/servlets/JDBCDemoCreate.class create mode 100644 sourceMetadata/jcb-package/src/servlets/JDBCDemoCreate.java create mode 100644 sourceMetadata/jcb-package/src/servlets/JDBCDemoSelect.class create mode 100644 sourceMetadata/jcb-package/src/servlets/JDBCDemoSelect.java create mode 100644 sourceMetadata/jcb-package/src/servlets/JDBCDemoUpdate.class create mode 100644 sourceMetadata/jcb-package/src/servlets/JDBCDemoUpdate.java create mode 100644 sourceMetadata/jcb-package/src/servlets/JDBCEmbedObjectDemo.class create mode 100644 sourceMetadata/jcb-package/src/servlets/JDBCEmbedObjectDemo.java create mode 100644 sourceMetadata/jcb-package/src/servlets/KeyValuePair.class create mode 100644 sourceMetadata/jcb-package/src/servlets/KeyValuePair.java create mode 100644 sourceMetadata/jcb-package/src/servlets/MakeList.class create mode 100644 sourceMetadata/jcb-package/src/servlets/MakeList.java create mode 100644 sourceMetadata/jcb-package/src/servlets/MyDatabaseServlet.class create mode 100644 sourceMetadata/jcb-package/src/servlets/MyDatabaseServlet.java create mode 100644 sourceMetadata/jcb-package/src/servlets/PreparedHTML$PlaceHolder.class create mode 100644 sourceMetadata/jcb-package/src/servlets/PreparedHTML.class create mode 100644 sourceMetadata/jcb-package/src/servlets/PreparedHTML.java create mode 100644 sourceMetadata/jcb-package/src/servlets/UpdateBlobToMySqlServlet.class create mode 100644 sourceMetadata/jcb-package/src/servlets/UpdateBlobToMySqlServlet.java create mode 100644 sourceMetadata/jcb-package/src/servlets/UpdateBlobToOracleServlet.class create mode 100644 sourceMetadata/jcb-package/src/servlets/UpdateBlobToOracleServlet.java create mode 100644 sourceMetadata/jcb-package/src/servlets/UpdateMySqlClobServlet.class create mode 100644 sourceMetadata/jcb-package/src/servlets/UpdateMySqlClobServlet.java create mode 100644 sourceMetadata/jcb-package/src/servlets/UpdateOracleClobServlet.class create mode 100644 sourceMetadata/jcb-package/src/servlets/UpdateOracleClobServlet.java diff --git a/2658.pdf b/2658.pdf new file mode 100644 index 0000000000000000000000000000000000000000..ced0fa838d439c0199796e9241dbb7e506570155 GIT binary patch literal 150456 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 _KEHPT01f17&>8{37 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 N;>RCXH&?GN{t1DY0dfEU literal 0 HcmV?d00001 diff --git a/2659.pdf b/2659.pdf new file mode 100644 index 0000000000000000000000000000000000000000..6f65c5d7e2776a6e263f225c9b47fa923d434d7c GIT binary patch literal 301212 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

@Wb;DCt@ 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 DRbEI4 literal 0 HcmV?d00001 diff --git a/9781590596371.jpg b/9781590596371.jpg new file mode 100644 index 0000000000000000000000000000000000000000..cbde169f3efe376ee4b59ae6a9dff9deb51b0e9c GIT binary patch literal 11316 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 literal 0 HcmV?d00001 diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..6a490f9 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,27 @@ +Freeware License, some rights reserved + +Copyright (c) 2006 Mahmoud Parsian + +Permission is hereby granted, free of charge, to anyone obtaining a copy +of this software and associated documentation files (the "Software"), +to work with the Software within the limits of freeware distribution and fair use. +This includes the rights to use, copy, and modify the Software for personal use. +Users are also allowed and encouraged to submit corrections and modifications +to the Software for the benefit of other users. + +It is not allowed to reuse, modify, or redistribute the Software for +commercial use in any way, or for a user’s educational materials such as books +or blog articles without prior permission from the copyright holder. + +The above copyright notice and this permission notice need to be included +in all copies or substantial portions of the software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS OR APRESS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + diff --git a/README.md b/README.md new file mode 100644 index 0000000..d2d358c --- /dev/null +++ b/README.md @@ -0,0 +1,15 @@ +#Apress Source Code + +This repository accompanies [*JDBC Metadata, MySQL, and Oracle Recipes*](http://www.apress.com/9781590596371) by Mahmoud Parsian (Apress, 2006). + +![Cover image](9781590596371.jpg) + +Download the files as a zip using the green button, or clone the repository to your machine using Git. + +##Releases + +Release v1.0 corresponds to the code in the published book, without corrections or updates. + +##Contributions + +See the file Contributing.md for more information on how you can contribute to this repository. diff --git a/contributing.md b/contributing.md new file mode 100644 index 0000000..f6005ad --- /dev/null +++ b/contributing.md @@ -0,0 +1,14 @@ +# Contributing to Apress Source Code + +Copyright for Apress source code belongs to the author(s). However, under fair use you are encouraged to fork and contribute minor corrections and updates for the benefit of the author(s) and other readers. + +## How to Contribute + +1. Make sure you have a GitHub account. +2. Fork the repository for the relevant book. +3. Create a new branch on which to make your change, e.g. +`git checkout -b my_code_contribution` +4. Commit your change. Include a commit message describing the correction. Please note that if your commit message is not clear, the correction will not be accepted. +5. Submit a pull request. + +Thank you for your contribution! \ No newline at end of file diff --git a/sourceMetadata/Chapter01/TestDatabaseMetaDataTool_DatabaseInformation.class b/sourceMetadata/Chapter01/TestDatabaseMetaDataTool_DatabaseInformation.class new file mode 100644 index 0000000000000000000000000000000000000000..d593fe7b1692d232c2059cb86d660704f7f5f05d GIT binary patch literal 1337 zcmb7ET~pIQ6g^ARri4JDP~=lVQCnz<;1>cS@+nM<%(TKVj-%T&c7kbA+th(y0s^9>j!#I1(}@6@;KEwD+EjDH+oYfqBz5-310;G`7PaEju}b zA(S+2W2;ig8l?=+TI7)m+_V{bqpy?u{1ewKZs)bMTQcqZoY<(Ook~eJ)=WX3${1yL zg}Xe<%SOs@xfo|0$9j9_+_2v}r2=8n<`-bi^jPC1MEtl1HjMCu}FPr)@ zou5`HQHt9F#QF@*8-{$5wg8B8zy9g{_$h5BO1^>Wc62dij}SD{qVMho#1s9Us} z@JQiy&)4x8LtEtQlupn^9Ga`Mk{I+$KaL>L0T$^=glf1;N!PIrfxFnNp?AzpstQnu z-$u-KvK>@qh<;n0^yBNo46QFx0V^1w2tD+^B1lp(+vLlTZ5mc;V#Hv6DQLDBEQ7fWVlZXPMwXJT#AuevRm~0U2#kN{{ zv#o9Iw9kFQBc zh`qQGq$5kml#ZJM{v%e-a*qnE>+HHDpba_`QlL3*izFs-RyWI5eA<(@Lu#(Bzrf#cVEVW+fLoJF8|FWua)hBhu|( z_GO#7Ol-u>Te(cX4x4bYro~{JI=qH#^5HdQax98JQPopPERe`@FTjSj=|PrhUUHxG^W~ zI@3kwpyeIM)sZ!jgQH{Gz&_m4kvC8P*NX;baGR*T`qV%^QJkDq0UD2_t1yo$JhKMo zaL2%VxI<*C?JRpj88$5&hI1_DK!<_%@qs{nN7z-HG|<6a?1<6fhq$X`A1RAiZ7dxh z8~6nG1P({N-wR6?PRWdwD=D+pao@nF3hzGb7x1M?i2)UBo}{U0l?DR43eqNF!q!BO z2e~I~W@LDh8xxk#E#*9GH%Fl7e|l60n+|J;GBQ_iWtJH` zMMakq3d@NN^LBF?Rhn5El-Rj)nUtAUN;Yr46&aPdw}LVy_|=R`{#M?}BxRc6Tsh*h z$x5{ko66~W3@)z|P?Zuj+J>B!>7pwy6lH#{dWYARs)k|}me5`6R5}$ax)!NSI;G5l z9OFb?9JW*7k=VRkUj?ITr?^lnsX*yhk}WkhH7}16HG74ldiv&Q-b^!qCTA_?tC2~U zu#*pCgpW0#fqRQ6+g{GLvlr}r-OnJNav%_6>-QGx`S|j(L!GA@$2#~Z+ZL)j7g`q& zX^D`Q>|TU#Jkk?gguhQ~)1Fj3v_t3EpiLvaHPKTuXB+qrp$!{xfKmlzFD1P8mSa4p zzOuXB{U?0lN%sr5$&^mr!6OaE{iiS3+Npu05tMCsHEU<+T+X#O< zlW0c^cChV07j_ZyZVX@#B<&=IFagh+oU$G_Bwt%gR zcqz_t8R<5niY#Eehit1-YNt|YN1w*z!@U1`+L-6gIwV=@jy@kXRAQdyF7{k~xn~i( zBa7Jc7`i{xG z(Lp0k{G>(`D-q)MMR16tK4yK4Uw=b5jk8GL9L5l*&rz5hNq)Xr7^n9nKOfHXlVO-~ hM)~xQ;VxzOD4XZ}0p|}nf5iDuxXkFUF>W1R{};+"); + + // get the column names; column indexes start from 1 + for (int i=1; i"); + } + columnNames.append(""); + return columnNames.toString(); + } + + public static void main(String[] args) { + Connection conn = null; + Statement stmt = null; + ResultSet rs = null; + try { + System.out.println("------GetColumnNamesFromResultSet_MySQL begin---------"); + + conn = getConnection(); + System.out.println("conn="+conn); + System.out.println("---------------"); + + // + // prepare query + // + String query = "select id, name, age from employees"; + + // + // create a statement + // + stmt = conn.createStatement(); + + + // + // execute query and return result as a ResultSet + // + rs = stmt.executeQuery(query); + + // + // get the column names from the ResultSet + // + String columnNames = getColumnNames(rs); + System.out.println(columnNames); + System.out.println("------GetColumnNamesFromResultSet_MySQL end---------"); + } + catch(Exception e){ + e.printStackTrace(); + System.exit(1); + } + finally { + // release database resources + DatabaseUtil.close(rs); + DatabaseUtil.close(stmt); + DatabaseUtil.close(conn); + } + } +} \ No newline at end of file diff --git a/sourceMetadata/Chapter02/GetColumnNamesFromResultSet_Oracle.class b/sourceMetadata/Chapter02/GetColumnNamesFromResultSet_Oracle.class new file mode 100644 index 0000000000000000000000000000000000000000..dee33037d4a90b98eeb8ecf49634a513cdcaa90c GIT binary patch literal 2702 zcma)8YgbfN7=AXKnKKMW&=FL;AdabA1|~4I22m5y)B#j(nVFs$HhA#N#hEjR-K;dS zva+)5b6@y>SJs5qpD}0!(3R-phX8cR%kt=kI@h{{uib9t9CWZvck_ z=nLRT07rv3hBt#aj{aJlz(6fd;*^fJ0yrH+5NFi>tQz7v27{=hgCp z(i{n3RLvJ^Foy8}CW3ey7lY`)I{{o$YVQVcIe_LAI zu!3mCOpuPQ>#%jC1pJ4swB;NTsBUc=7ts1MlTx5QZl&c=A(fE1Q8QulWZkrM`ZMXY zOgdI3EwH(@Ek0w;n$i3XJ6aa>3Iqq{k}|8b@&a|PnO#Vwhs>1ZL2GN-?1Ib}Y-dC| zz01CAGd&$0adK9Ax>pBp(NdE!3~aN3b~{_X(@>NPAQ0`yH4gZsnQKs zhI3}pmR$<6flhP@?9415O(v3ElR0Zv=DIws6YhpsXDEt!YBA@Um5v>=GfC6FmdQJ@ z?gKsDv80*LS|$-zrLs(6D%+zYV<3wgI&ubik=NlEC}38{O#^ed#bDgDRYY>UFf}D} zO!47l8T}E3@_hpz;6no+;X`J8wVh>8D#N;E!VXggj*c-c70(Y3rFej z6MU*|wOEr87jvY=oR%$9e6SXo%G#M*QZjL08u$ud>$q>=8+>cvH5?E);Q4q7 zfHFN(0|1|HyhHT4=HnJhT+d_m^e+lt-2GF256E3t&` z8fTJ;Xu+{aWzs2O=H(bSs&&|zJWFEpa()$zvYp~WrKAL}!7p@staJS2_CK!y446c84lg zHI8cdDBB*YIvc8vhqS?vZ>W6{{)vuA=OXl&)}%ctd1!{twLzP8^j1et_1taXe+W(3 zi2al*D6N#R@h#u+ochY{X8T|8i6`w#2nfVGmQW+m_Z-2Cq1tCKhO~oPqqbeU`YQ%H z8nq>?t3u4@uIjk*cRok`#b;O_+OU97laE7aqgwgZs)54-8W*r>;;tqh|GU%~+N?I6 z3)oVI-$Ss#7D8+y{2dIU84cLUF^o3sCj33js-Nk$hIk^om2|7#54xKi~TRs#5luM7-Fh- z$9&XKfw`KmaOUZr$RhT3EMnhdbg8#kK%2IR_LY(bW~V~6$^Yk5#^}do*o;EW^NicZ zO?RHhJ$Lp(^b literal 0 HcmV?d00001 diff --git a/sourceMetadata/Chapter02/GetColumnNamesFromResultSet_Oracle.java b/sourceMetadata/Chapter02/GetColumnNamesFromResultSet_Oracle.java new file mode 100644 index 0000000..a8d7bb0 --- /dev/null +++ b/sourceMetadata/Chapter02/GetColumnNamesFromResultSet_Oracle.java @@ -0,0 +1,89 @@ +import java.util.*; +import java.io.*; +import java.sql.*; + +import jcb.db.*; +import jcb.meta.*; +import jcb.util.DatabaseUtil; + +public class GetColumnNamesFromResultSet_Oracle { + + public static Connection getConnection() throws Exception { + String driver = "oracle.jdbc.driver.OracleDriver"; + String url = "jdbc:oracle:thin:@localhost:1521:caspian"; + String username = "mp"; + String password = "mp2"; + + Class.forName(driver); // load Oracle driver + Connection conn = DriverManager.getConnection(url, username, password); + return conn; + } + + public static String getColumnNames(ResultSet rs) + throws SQLException { + if (rs == null) { + return null; + } + + // get result set meta data + ResultSetMetaData rsMetaData = rs.getMetaData(); + int numberOfColumns = rsMetaData.getColumnCount(); + StringBuffer columnNames = new StringBuffer(""); + + // get the column names; column indexes start from 1 + for (int i=1; i"); + } + columnNames.append(""); + return columnNames.toString(); + } + + public static void main(String[] args) { + Connection conn = null; + Statement stmt = null; + ResultSet rs = null; + try { + System.out.println("------GetColumnNamesFromResultSet_Oracle begin---------"); + + conn = getConnection(); + System.out.println("conn="+conn); + System.out.println("---------------"); + + // + // prepare query + // + String query = "select id, name, age from employees"; + + // + // create a statement + // + stmt = conn.createStatement(); + + + // + // execute query and return result as a ResultSet + // + rs = stmt.executeQuery(query); + + // + // get the column names from the ResultSet + // + String columnNames = getColumnNames(rs); + System.out.println(columnNames); + System.out.println("------GetColumnNamesFromResultSet_Oracle end---------"); + } + catch(Exception e){ + e.printStackTrace(); + System.exit(1); + } + finally { + // release database resources + DatabaseUtil.close(rs); + DatabaseUtil.close(stmt); + DatabaseUtil.close(conn); + } + } +} \ No newline at end of file diff --git a/sourceMetadata/Chapter02/GetColumnPrivileges_Oracle.class b/sourceMetadata/Chapter02/GetColumnPrivileges_Oracle.class new file mode 100644 index 0000000000000000000000000000000000000000..ae2cc45f958f0a4a7eb20ad9d327dc84126dad05 GIT binary patch literal 1848 zcmbVNTUQfT6#foOGQ&6sM(!4jt&~6vDYo_!M6H0AngBI`MXh!+8N=XYCT1o|e^Fm+ zA24m#YTx^ty1M$EnN-LEeQ2`Qx$OPzefIhGK70Q9=eIuqEWpt*g*gpb4VN_JG|cPB z;}e~#%Q`0UX&*kr6&0WB&?W8*Ie#gKujEkBv52c0mQLXsu4}lV;cE>ybu42=!>Wc` zI&R~Rin}@{@QqGq_f!;BlmwDj9nT4`3G`-Ww*{1CziJB%6dliAYt<`ubJMK2l=Ro^ zaM|}f+X@}u6By0R7Wd4TWAa+m&EL*>c>f-4sYzo)~zFhm4`TQ{G%3#SH;5t>Om*CMp6KrBOOc!c35k*$L8z{G_G61Cz`5 z{Zv>6svy&64=?dHTLzvXZJ>r-fr)o#LSXRFc)ha6g5cc_MawRE6i}b}%{8;mv!*jA zr2dE~GGN_|L_TCW#c3>=o>`N;mQHYR#J*Ea$0hG7&?E7eJIU|$TfD_^?8EW%pcz$wzI5rt8-PCikpLzHWzReubin8Q3LmQp0VG6cni$ zjS=HY2RSB@ZH)hfse&S<=ae=+h$TiLAs6F`KVLJZB(~VkWb9k;7}H~R3^{vfM03o{ zeGE}HOio5F`#Jmb_t)|hBy)`#x;bH)JXT9iU}2y41rnGHr+V}Uo^JGpe#Ch!4OKB zw%Di?bE1^xIg2Dpk()L{SM+simw)0(i`#`{#x0q4VMZ!y8K+V*#EL1w6IoGqm$=Jw zye!hfCzgt#fKa z^rYg6j%my=T)!ODLdCT5qQu}g9NT`XV-__sr{fvsRXo?RfJKH8GV{+*#gdL?tT1%c z{VeYrVoxTZV-*n{FR;cC|DVhm+Un+B=5~eQG7Rq;xnw?<+!CdO1zt9dMT(zZ$WfZx zydZOGrIOUe46$f~rg)=Q$6ig?%NnLfRw}KZ*!Atp~ zm_gl>Ad5yK(#SbYM1b$@2|Le_Xau+t@JYkS;RU=`mYLXJ@Ilw{29cpNdKE|(2V_l) zG>6I4`8z+9G}VnqtX|klRcz=aBArxR(>inViY{^hEvHON(S1^e%eJUgp;|FBE;l}8 zOWcs_CiYG0i4t9lZDAN;T73C6fpSEIXcyfEh%@5;(Ic=!I?x^v4b+4|G@~0mbe7Ox z@WD@;@=S1If5DvR?!@OPjW2hjMAtNn4<41EIOKNeJPlv%8aIlHHx{ z%xp=jhzcr*cM-)a;w36lE$Aj80<9M`-~|Qo&hyAW|Ed4{Bc3y}Nj7PG9{0z0zVFO; z?(aD>`_g}&eICF*yrJM0^vUR#F(Bhs1%tS)21B@A#vKao#9b2ZmhpClSnp6^BB>yS zv<#~j!x-UZRDvyGOhJtGj5E#fl9iE@;3(LHyo}Q_T;6&zd>I7^XB1q9dt^-1ViIR- z@lL#pmwP3=o9*5w;XMj=vC8){eV>f`nLZ%n{Y*a~x7JjV2MGCt4Fe?i6<6?_R_R#1b- zC45D~69SP#cFy*X2vj!hzEz;A%}HAVb)9z3>MmrHmfLS8GsLONns!cLL(?6dW9AuC z&zQLpz0Y^;+(;`6Dt%7DOKE>2^Ldv0-XXI9d{%#GUg|; z*+h2IJDo`!bL}&hE3j=WolF@4&(QUZlQJ`-j_2!6%6IYwkNj{Q$CvO`6<@>GC4580 z6uwCoopB?cam=)pj+5b&o$+*_F(KhwD!z>;1=cP3eS9Ki<$c?sfVQ@q9Xgzu~P0g5W7F(XjF zWHd|`1;3JYv|wk_9DFoT5zm=fD}FexViwP;n8ObRb~OJVzl9JBzMau;Hoeh69jE*$ z@|mqBNHrBKF>F#g-N^)(-ZnD=ds0p|;T3X;v0U0t40|aj=UWqg;*>Sq-q#i$+Cw1~ z&*6DWc)7m3>zuJEghat5Wy&yR)X=$-CA$-PXjtzE4VE;rYcEhq`KE*mDlXzj5`L`W zC-|v~7x6QJ&1_~-yqhx9mN7lA*R)+O>(2$YJFc0^Sb;e`?>HH~Ctxfgk1Y73c231S z!=PpnR4QI#Mx~$1t9Y5W1oDEd;um;Q#VvP6@TScT(?TAE`x1Pa?DEk6fH*-wtY|nvNi0uToHjQnpPPKWvoD;b(z|}AhDEv zr$EXZ!pjSZ38N>0<@s7jij?Qp?Aoq0nXK%#ons zMl7GOn4EEgO5m&5a8%T7h_h)>RxS^L<%`^-H9e zA$y??mxwPRyMY@uz}!N@2k0frBQxW8RG$S{t}w*Ir7jpoeZH9*@23}!h3)8|?@#_! zK+t^dq_vAqjYI{}>OIpC=V>F*O=~1zM(LZZ2fehXs}=ts?pnI=TCAcoR@oJ+>W)-MrxA%sMaWZFYee{<(4lGuwO2N4L{y_%tDZqLe71(3RqmG>BrP(FI)Nv! zPm452v#77Y1yUfBf;q&7rm-%zzK8}*rlp7tB=&$Lrrw%o0~_fyhfPEEwbRfHNt0rm zV_S;YI!L?5*f!qH;j$r3nnv7^H959@7MEARsL^U>@iu|Su$gx|1ev_TP)MalKJT1* z>&+$YyU2wmL(!Dj?jrUO*;~YwM4F385YdacN>kQW|FcK|D6y-HxQ58JMO??0r?KCt z)oNo0G-VbomGsdR@>ETY9Vp`91sFzDi_W2SXby*lVuz=3WE$7c;)V)n(OKLmV64%i zv7@o0vuLY?QCF6hW1JSsNr@FT>VutD|H64x zqn^MJr-~=UIZ-Upd8&6&Tog>_#mh`f2ze7Nw68}cVIo2w@-zfNcREk#1Z=2(2gby5I2RrxR>_#qZtq5Dm+U6lOD%4^a*txeXZ`Ny0p;O z&_TRTe;D4NzY%|<{}X@5_4pTVz`r>?I4UHxi8VMTHsH8uM7!95TSPNXh!%8<8_^@W za8jgkN@UR|&Z1vDf&p<3cZz3l7ezTJW^kK$4nyK1@m?g}JkeK(zKXjk(vuWp1y21J DN+iU} literal 0 HcmV?d00001 diff --git a/sourceMetadata/Chapter02/TestMySqlDataSource.java b/sourceMetadata/Chapter02/TestMySqlDataSource.java new file mode 100644 index 0000000..b49b57e --- /dev/null +++ b/sourceMetadata/Chapter02/TestMySqlDataSource.java @@ -0,0 +1,96 @@ +import java.util.*; +import java.io.*; +import java.sql.*; +import javax.sql.*; +import javax.naming.*; + +import oracle.jdbc.pool.*; + +import jcb.db.*; +import jcb.meta.*; +import jcb.util.DatabaseUtil; + +public class TestMySqlDataSource { + + public static void main(String[] args) { + String driver = "org.gjt.mm.mysql.Driver"; + String url = "jdbc:mysql://localhost/octopus"; + String username = "root"; + String password = "root"; + Connection conn = null; + + try { + Class.forName(driver); + System.out.println("ok: loaded MySQL driver."); + } + catch( Exception e ) { + System.out.println("Failed to load MySQL driver."); + System.exit(1); + } + + try { + conn = DriverManager.getConnection(url, username, password); + + + // + // print the list of tables + // + java.util.List tables = DatabaseMetaDataTool.getTableNames(conn); + System.out.println("Got results: list of tables"); + for (int i=0; i < tables.size(); i++) { + // process results one element at a time + String tableName = (String) tables.get(i); + System.out.println("table name = " + tableName); + } + System.out.println("------------------------------------"); + + // Set up the environment for creating the initial context + Hashtable env = new Hashtable(11); + env.put(Context.INITIAL_CONTEXT_FACTORY, + "com.sun.jndi.fscontext.RefFSContextFactory"); + env.put(Context.PROVIDER_URL, "file:/jdbc"); + + Context context = new InitialContext(env); + NamingEnumeration list = context.list("jdbc"); + + while (list.hasMore()) { + NameClassPair nc = (NameClassPair)list.next(); + System.out.println(nc); + } + System.out.println("------------------------------------"); + + + OracleDataSource ods = new OracleDataSource(); + ods.setDriverType("thin"); + ods.setServerName("localhost"); + ods.setNetworkProtocol("tcp"); + ods.setDatabaseName("maui"); + ods.setPortNumber(1521); + ods.setUser("system"); + ods.setPassword("system9"); + //... + //Register the Data Source + //... + Context ctx = new InitialContext(); + ctx.bind("file:/jdbc/mydb", ods); + + // Get the initial context of JNDI and lookup the datasource. + InitialContext ic = new InitialContext(); + javax.sql.DataSource ds1 = (javax.sql.DataSource) ic.lookup("file:/jdbc/mydb"); + // Set the optional printwriter where the trace log is to be directed. + ds1.setLogWriter(new PrintWriter(new FileOutputStream("d:/mp/book/datasource.log"))); + Connection con1 = ds1.getConnection(); + Connection con2 = ds1.getConnection("octopus","octopus"); + System.out.println("con1="+con1); + System.out.println("con2="+con2); + } + catch(Exception e){ + e.printStackTrace(); + System.exit(1); + } + finally { + DatabaseUtil.close(conn); + } + } + +} diff --git a/sourceMetadata/Chapter02/TestMySqlDatabaseMetaDataTool.class b/sourceMetadata/Chapter02/TestMySqlDatabaseMetaDataTool.class new file mode 100644 index 0000000000000000000000000000000000000000..398e535515fe0fbfb896555e9bd3b85ccadf1b6d GIT binary patch literal 4382 zcmb_fTXa{A@780P81h5IHfTbrhhhf5*Ibr5Z zASh^6P-sQbinJ)+s#Y>CW`;)6ruD=sJi`(%H1%qA;VY>%A6x`vZqdUF0 z3p>5oh20A7uERI6hlg)@pnEXvg^zi{JV$si7`azLRKY%8#uSVw*ss9kU0gvzfu&%S zcLx+C6{PB5BduVJj}9t0q+pzvhZWqz^Sug=@O)IkeLUZ<;M+Vupx{Ba^&thv6dYIZ zFrPlc!wDWvD)^3q@AC3d1*g1t43B$Ji_;!F;lYyvHLGHYn7u|oZeO%RpsLr37y^y` zv4pWD9UnH5L;A2uCslDhmJn!d-_<{&kLf{EPeg-*b~2WT_OPIL&`Kx6#)cS!=L{Js zdtiLVVnVmyC@WNr9V3 zBE#X3a~28)O)IRM`>d25w8FMEnof~LNz1Z5_@0WVaK?kDRh-551*Tj3Lz-#n5hJ3J z3Agua5r?tUgCD3khi3$u3m&XL6gEcfm_@G5+@O>35zV$7@ls(G&*HoXDGFL>~x zikI+1f#62V){;glZQ3c)8cW%lwO1pTO+&NCM~#%$QS$NNWfiYrLdC22kw8cq?`RC!nqUTOB=rz(Di3j$)kib-51TXQ(gQM-+jgTfvy4;590p0p{T zDl)j@T9p-9n9_P3H&R-ew2G^En^HHgA{E|e#Pu@URs5V$v-7Ah6^3a=r@(%}u=YHR zswQS~YEfMcO-(Kp@8Ft14&I?fEOIKFG)1qh8HYGcT^LuyyG25I>CamT6vEcsT_jym zWp{VE%J*-bQ`4Q?~DKDQy26ynz55hH9<3oI03uc@b~5nLD1%JuQT|GbxouNWiMFbJ6Zhg) z$8>tBV78eK=m|aQw2-J__gaYrIq0;!feLg*Zn*7z>dB()5o;*Wk@>Sm!o$Hh)oZX) z-{V3I@+ahKDt4G6LEl=NXe3^KoK3Ez^W~Hc zB+1t3qoYP5LU~%j-C~KXziz`NLB+OmZMmg=Dv%I)hd3{|S&|_;s9(C<2HH}9<9c$O zQj_jiR(AL^UpVhD>1rafY~OJ^qCn68NLT!&olCaTx2G?1R+DW=0zTT5wMl_JUsUT< zx2B#{eAec?tAz$DaNz%`_X}FWuQ8Zy;?$@r8&J`Oy23M3+*@e3w!D2)8+E$#dTz+e z1Qu7OuVCp;F7=&U>O~BP^rEd(~uSmPYl z((loY_!_MVT5Y2mGXVJ+pVaS@2Ygjqd{v<;5vpF2LG>MPqQ>W$gff9?p&H(JX;YO! z-O`Q#O=_q*P@O@2_O5~MoS^sEtBvE z6dEScN@5Rr#KeC-Vy?E3hxJT%xD>wYMGbdHvo1F}Q5Ces7+wu82)zwz>kF z*JZmUgE=8q>zhk#G_y*cee-Az(4$_#dSf*TODf4aTUSWFuW}f z=am1-1hi01pk@+Z<O%o%6$o6rL^aw(MXgcgcFJS&QFlH~b$e7kA@h7%ev;>G zrHk{3(prU#daC*c!Z*^YiT;}5M+j$wEC((f?2=xMP#YO&Kp4NXLiI35ZPp}f7q6h!PD&faUaTC^wdFT~O>6c&+Hi%8w zD8jUkVL&9YMI6Rf@c_1olh`57VV8IbyTxm`TfBum;yMiRd+Ze-BPu?DDgJ`E_!J58 zcUaw2F@(|vacjE(j48M`@!EY%-*X8^1p?nNC apKTbS6LhuQUD8AD!t;({p!M56gn- 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 P_6N*SsTtNC!1=!ca{kTh literal 0 HcmV?d00001 diff --git a/sourceMetadata/Chapter03/DemoGetImportedKeys_MySQL.java b/sourceMetadata/Chapter03/DemoGetImportedKeys_MySQL.java new file mode 100644 index 0000000..1db75ef --- /dev/null +++ b/sourceMetadata/Chapter03/DemoGetImportedKeys_MySQL.java @@ -0,0 +1,45 @@ +import java.util.*; +import java.io.*; +import java.sql.*; + +import jcb.db.*; +import jcb.meta.*; +import jcb.util.DatabaseUtil; + +public class DemoGetImportedKeys_MySQL { + + public static Connection getConnection() throws Exception { + String driver = "org.gjt.mm.mysql.Driver"; + String url = "jdbc:mysql://localhost/octopus"; + String username = "root"; + String password = "root"; + Class.forName(driver); // load MySQL driver + Connection conn = DriverManager.getConnection(url, username, password); + return conn; + } + + public static void main(String[] args) { + Connection conn = null; + Statement stmt = null; + ResultSet rs = null; + try { + System.out.println("------DemoGetImportedKeys_MySQL begin---------"); + + conn = getConnection(); + System.out.println("DemoGetImportedKeys_MySQL: conn="+conn); + String tableName = args[0]; + System.out.println("tableName=" + tableName); + String importedKeysAsXML = DatabaseMetaDataTool.getImportedKeys(conn, "octopus", null, tableName); + System.out.println("importedKeysAsXML=" + importedKeysAsXML); + System.out.println("------DemoGetImportedKeys_MySQL end---------"); + } + catch(Exception e){ + e.printStackTrace(); + System.exit(1); + } + finally { + // release database resources + DatabaseUtil.close(conn); + } + } +} \ No newline at end of file diff --git a/sourceMetadata/Chapter03/DemoGetImportedKeys_Oracle.class b/sourceMetadata/Chapter03/DemoGetImportedKeys_Oracle.class new file mode 100644 index 0000000000000000000000000000000000000000..27ab20f621b6f19e010eeabb5d697b86056ab1e5 GIT binary patch literal 1869 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 literal 0 HcmV?d00001 diff --git a/sourceMetadata/Chapter03/TestBatchUpdate.java b/sourceMetadata/Chapter03/TestBatchUpdate.java new file mode 100644 index 0000000..67b4de9 --- /dev/null +++ b/sourceMetadata/Chapter03/TestBatchUpdate.java @@ -0,0 +1,74 @@ +import java.sql.Connection; +import java.sql.Statement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.BatchUpdateException; +import java.sql.DriverManager; + +import jcb.util.DatabaseUtil; + +public class TestBatchUpdate { + + public static Connection getConnection() throws Exception { + String driver = "org.gjt.mm.mysql.Driver"; + String url = "jdbc:mysql://localhost/octopus"; + String username = "root"; + String password = "root"; + Class.forName(driver); // load MySQL driver + return DriverManager.getConnection(url, username, password); + } + + public static void main(String args[]) { + ResultSet rs = null; + Statement stmt = null; + Connection conn = null; + try { + conn = getConnection(); + stmt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, + ResultSet.CONCUR_UPDATABLE); + conn.setAutoCommit(false); + stmt.addBatch("INSERT INTO batch_table(id, name) "+ + "VALUES('11', 'Alex')"); + stmt.addBatch("INSERT INTO batch_table(id, name) "+ + "VALUES('22', 'Mary')"); + stmt.addBatch("INSERT INTO batch_table(id, name) "+ + "VALUES('33', 'Bob')"); + int[] updateCounts = stmt.executeBatch(); + conn.commit(); + rs = stmt.executeQuery("SELECT * FROM batch_table"); + System.out.println("-- Table batch_table after insertion --"); + + while (rs.next()) { + String id = rs.getString("id"); + String name = rs.getString("name"); + System.out.println("id="+id +" name="+name); + } + } + catch(BatchUpdateException b) { + System.err.println("SQLException: " + b.getMessage()); + System.err.println("SQLState: " + b.getSQLState()); + System.err.println("Message: " + b.getMessage()); + System.err.println("Vendor error code: " + b.getErrorCode()); + System.err.print("Update counts: "); + int [] updateCounts = b.getUpdateCounts(); + for (int i = 0; i < updateCounts.length; i++) { + System.err.print(updateCounts[i] + " "); + } + } + catch(SQLException ex) { + System.err.println("SQLException: " + ex.getMessage()); + System.err.println("SQLState: " + ex.getSQLState()); + System.err.println("Message: " + ex.getMessage()); + System.err.println("Vendor error code: " + ex.getErrorCode()); + } + catch(Exception e) { + e.printStackTrace(); + System.err.println("Exception: " + e.getMessage()); + } + finally { + DatabaseUtil.close(rs); + DatabaseUtil.close(stmt); + DatabaseUtil.close(conn); + } + } +} \ No newline at end of file diff --git a/sourceMetadata/Chapter03/TestMySqlDatabaseMetaDataTool_DriverInformation.class b/sourceMetadata/Chapter03/TestMySqlDatabaseMetaDataTool_DriverInformation.class new file mode 100644 index 0000000000000000000000000000000000000000..bebc7defeafadcbd1c1b909f319a51ae6d31e3c3 GIT binary patch literal 1660 zcmb7FO;_7S6ukoi8ASwQ3?Vd7nvh~+Y&A{#h4ay1LQAooG<6Efvkp$*qlNR`2-9NAK|)+k2Rc=;2UzjDThzw@TrE+@Oc7XXxKtQ#Vrjf+}61F zj*7b~z7&|e<@io?M_@dic_N?`gF{TBaLzR1AFIwjw9+1umvD zrKb79G}_Ny9lueK`Lt@#2`ziqkvVSG z>~>T>sy=sj%*d>pZM$qoru?o2f&0Tw=)ADQJ^#lb^h_B)FA3M%rP^{uxztJu@=4faW@r_jKew>yq|Xomt57PY*sqlB^?DmotEp^9&H zJVI4q?Nq=s7Ak5w9)l{*o#c5ZzK*9@((xS*1dRVFtibF^#0T{zFP$}UVk)|3o5HEQ ziHhm*=B}kjT(2F5UCf2ZQ`esAwQ63RsV1K`2hAn3m;Q;^YQ9H6d7I@I% zDdyuCPGCG_5k?Gbn;x0P5}r2mge?hjS;6xo2+9JUG+Qm(KNQG~0t^xE7XTBU!p9mH z`llH#7~&IA5UU`Ndi(YUfJ7`et-9gy#TcWW54VjfU4cxW_tOMWSQKieCuKD6+Z+nbDZoMr!Xa-DaLxx61Ps!cR4w>pByhGm2y(4Y;-a4G`pGWVscBl zr2P6W!U|M=Pjk-0_MF9%JShvvg#;xKO5dGX^D-v2E@bER|`SSGrgrhHI@N=iFbf7=H`} z_M%j8e#C6s*k@mW>c0(JQh`azpOJhTb%_F1@$hKl+WC?7U!Z2O5 zGwn>5{STeVrki9sgg&O-bk!fx|IlSOot`U;7=x3^qVkN-z2~0u-S3=x&XxZB_vhaL zT*aP*ONfYwig-`NRS9EwzX>1Unuu`;AL6=z8zNMRR1*?z;+BBh5?Z*+9WL)SV-iz* zG%X?~Vn)I&J`(YI`jh!_w!=g|uEwX=#%*zJg|03_amT@w~RHMNQ4hMUzg^uyPaJ zQA*n7Vn&}exN$h8mz>0Ya>tBmj+WL+dO~+JK2F)TxjtuQ^}Ps(k?{`RW$3kwxkxVW zL<)sSVZXFvMq)){S1&RQgv>J)U-32xoMZ2sAJ^#vae{{j(~?U*6>Kcr!qdn zV}?F^OI1u;%j#K$Xe`E+tcw>Bur6Z*8bfC_ikZEPzU>$`g*Py(Q2<%Rv0e9CXBlZ^ z1Y~9CctWJB2$eicl?^k?Sp_q;WkqtjGffejb}l@8OGXZx0t^{>Y{@XO#V|7JJqnq+ zIhnJb*u{dzxhThru4E77T|=2HR+GA!5(7i%nDF`=_KUQuGUUQ!I6dqv+fO3t0r zd-yqTm+Cf^z+7xSnVL*3CD-TXV>7EVc0jT9yF?XBE9k0n%7n7&R*SdlF=lA3_{_MQ zstV6ViJ{|^_t+T2;A_yw#soMr%Gj0hIj@?bH>fg(_UbV$r1N^lq0p+TX;Ui^7lHCV zPa!c}3fHOc6DrqXq6Rj(Uvl&Ub&y>q@a~GSVMp&%b2wBQx>g{EO2O5tY2$5fWK!vM z*V~wPB%Kw(`oeR(&3atw)FIJIha@yhb337hmm3`)1?X0Cq7K}NFucw^s~N7S_zqP# zq94$>ZS<`ZXweiO~wT3wPg>8KRg#96~?I-1=EbX$SyZsY%Ccs7dRHM-Kmb%`##LT40V8*I~)2XsQ4ti-rHU|(?Qo#}I2p|Olc`sN6rmF(MS)K0%nbfb%~LWI_X z3+Sa&??VIw^x1O`%cOlw1++s|uus+TC9Qr-Sl?k3-_zI754eUOF^*qx9e>~k{(_3X zaTot!k}*uNe#F=iX4p9HvD=6<`u<@XSY|p_i1i}N;{mggWF^w=k?w%xS0um2DlzAr H8!-AGZCr1* literal 0 HcmV?d00001 diff --git a/sourceMetadata/Chapter03/TestMySqlDatabaseMetaDataTool_Index.java b/sourceMetadata/Chapter03/TestMySqlDatabaseMetaDataTool_Index.java new file mode 100644 index 0000000..dad9490 --- /dev/null +++ b/sourceMetadata/Chapter03/TestMySqlDatabaseMetaDataTool_Index.java @@ -0,0 +1,90 @@ +import java.util.*; +import java.io.*; +import java.sql.*; + +import jcb.db.*; +import jcb.meta.*; +import jcb.util.DatabaseUtil; + +public class TestMySqlDatabaseMetaDataTool_Index { + + public static void main(String[] args) { + String driver = "org.gjt.mm.mysql.Driver"; + String url = "jdbc:mysql://localhost/tiger"; + String username = "root"; + String password = "root"; + Connection conn = null; + + try { + Class.forName(driver); + System.out.println("ok: loaded MySQL driver."); + } + catch( Exception e ) { + System.out.println("Failed to load MySQL driver."); + System.exit(1); + } + + try { + conn = DriverManager.getConnection(url, username, password); + + System.out.println("conn.getCatalog()="+conn.getCatalog()); + + System.out.println("-------- getIndexInformation -------------"); + String indexInformation = DatabaseMetaDataTool.getIndexInformation + (conn, + conn.getCatalog(), + null, + "ACCOUNT", // table name + true, // unique index? + true); + System.out.println("-------- getIndexInformation -------------"); + System.out.println(indexInformation); + System.out.println("------------------------------------"); + + System.out.println("-------- getIndexInformation -------------"); + String indexInformation2 = DatabaseMetaDataTool.getIndexInformation + (conn, + conn.getCatalog(), + null, + "ACCOUNT", // table name + false, // unique index? + true); + System.out.println("-------- getIndexInformation -------------"); + System.out.println(indexInformation2); + System.out.println("------------------------------------"); + + System.out.println("-------- Does index exist? -------------"); + System.out.println("conn="+conn); + boolean indexExist = DatabaseMetaDataTool.indexExists + (conn, + conn.getCatalog(), // catalog + null, // schema + "ACCOUNT", // table name + "ID_STATUS_INDEX"); // index name + System.out.println("Index name: ID_STATUS_INDEX"); + System.out.println("Table name: ACCOUNT"); + System.out.println("Index Exist?: " + indexExist); + + System.out.println("-------- Does index exist? -------------"); + boolean indexExist22 = DatabaseMetaDataTool.indexExists + (conn, + conn.getCatalog(), // catalog + null, // schema + "ACCOUNT", // table name + "ID_STATUS_INDEX22"); // index name + System.out.println("Index name: ID_STATUS_INDEX22"); + System.out.println("Table name: ACCOUNT"); + System.out.println("Index Exist?: " + indexExist22); + + + } + catch(Exception e){ + e.printStackTrace(); + System.exit(1); + } + finally { + DatabaseUtil.close(conn); + } + } + +} diff --git a/sourceMetadata/Chapter03/TestOracleDatabaseMetaDataTool_DriverInformation.class b/sourceMetadata/Chapter03/TestOracleDatabaseMetaDataTool_DriverInformation.class new file mode 100644 index 0000000000000000000000000000000000000000..9369cfdaca4565c133baea342eef81293286d758 GIT binary patch literal 1680 zcmb7F%XZpU6x|og2rKd<7#zoq6SuJ&Fb3kJ?gR3waooBFoCcEA>7Yvp)sZVC3L-20 zqE4F*99FwlJMXX`)YW|@661mg)!<&;bM|>?-*b-s`scSl0Bqv9hDEH#uolCIG2GCQ zLR!N*G8!&nV+vX1V#sT_iA@!^G+dD2+j9R%E?aW>Si>jyG=|SK6i`%gM?(U4HQL@& zabLv)f#@CEwf%bn6RGr50j1Nz*le(Sd*$k2rKw6Y`5^h@l3;c;dTAO=GLvvLd)pc0;*^FUc1*-@wtv|lvM2K zSjI!STvf5F;|qK#kjW076;d;j+R9sPu&db9@fG&TTR_?n4ck52X<8kDNt5*6)lo)8 zE>#@|c%g-;E73-DF8&Ohw>8E&~lWvj2 z5SW0FUC#AAo|d@_?vv|pAYSuD;0o7hAe_RK>{CPnXql#y)Ln^3_Tv-fxKfEL)%89m zpJg_(eMAe&W#yN59L82mLBuXA;$ixliy}^8MGvgwEBlnS} g^>vi6%1O3HKPiryG`*xaAksMGUq;{q`ibEBzp9O(4gdfE literal 0 HcmV?d00001 diff --git a/sourceMetadata/Chapter03/TestOracleDatabaseMetaDataTool_DriverInformation.java b/sourceMetadata/Chapter03/TestOracleDatabaseMetaDataTool_DriverInformation.java new file mode 100644 index 0000000..d46e0af --- /dev/null +++ b/sourceMetadata/Chapter03/TestOracleDatabaseMetaDataTool_DriverInformation.java @@ -0,0 +1,44 @@ +import java.util.*; +import java.io.*; +import java.sql.*; + +import jcb.db.*; +import jcb.meta.*; +import jcb.util.DatabaseUtil; + +public class TestOracleDatabaseMetaDataTool_DriverInformation { + + public static Connection getConnection() throws Exception { + + String driver = "oracle.jdbc.driver.OracleDriver"; + String url = "jdbc:oracle:thin:@localhost:1521:maui"; // office + //String url = "jdbc:oracle:thin:@localhost:1521:scorpian"; // home + String username = "octopus"; //office + String password = "octopus"; // office + + Class.forName(driver); // load Oracle driver + Connection conn = DriverManager.getConnection(url, username, password); + return conn; + } + + public static void main(String[] args) { + + Connection conn = null; + try { + conn = getConnection(); + System.out.println("-------- getDriverInformation -------------"); + System.out.println("conn="+conn); + String driverInfo = DatabaseMetaDataTool.getDriverInformation(conn); + System.out.println(driverInfo); + System.out.println("------------------------------------"); + } + catch(Exception e){ + e.printStackTrace(); + System.exit(1); + } + finally { + DatabaseUtil.close(conn); + } + } + +} diff --git a/sourceMetadata/Chapter03/TestOracleDatabaseMetaDataTool_Index.class b/sourceMetadata/Chapter03/TestOracleDatabaseMetaDataTool_Index.class new file mode 100644 index 0000000000000000000000000000000000000000..ecfbfb2a46e436d9a19d020a89ce3c59a89ce3a1 GIT binary patch literal 2451 zcmb_e%~umw6#qR)m|++Qjzow`8LhTKB`K+242og`8VvzWK!sMEBm)jkW@2VyvFCKz zWtUxc?XKt81<>}KcJH#w{vBQR^z^>TAOup6izes1JMX@GfA4E<7({LBxF#5BO0*L{Y?|ge5$b(2Yj|9t&7z=(=XwrZ>gV z86RC@2&J8h!4S!rwvlgCOGdq@mn`Chs=8@29E-2yHuRTz($ekqWWlSO_WC4OlnPFx zUN&Y;E<9Q^TyMUvmn|csdwNNCjXA^9`E${6tktYtF*Xw%N5-d!GmJRCaAKoUDkmy+ z^QBQw1p5AlAo-Ej6w|zCrmfwyoU(2`b6igwzmyu++_F=znK~IMIAzbNHCzEJGQPl< z0-nfN#Z!iu^ITIcN3R$awTZ6=w+SFyN+>fN-Scl|vuxBn(;>{^S)E*~sGj5NAJCRj zfgxZ`#yXxcoEr;%>bl|i&Svd3r(V@Lmb!cBQwEU1^XcOJ!eW7*rqk*9#e7kKDPsfA z8P2qb|HpQO^Mx7yCc5M5)3=37h*fJc{ z1iX+@M~$i?n^`Rsr;Ce))oea9^GJpZkKu&xp=#?@LsJikP&oYp3Qhy>82XwzGrobE z%5Q5h966w!N>Sk7gPuwWcq!v6Y|41W>*&mf6dptWUIgY#8%CL&i0rY_mhQTg3d&fX zd}25oZ&UO8SiZt!3vA()>lsz*DyKo<(WbEJBp0Y*Jc_!ZS4p8+YOQR#xW|+GU+3xUrRqylM#(|HhUePA?Q5;Vdr)#_gX+G}ZK4&9EyBV{KeMtPwN- zxzr-xtc}U{$%~%T3>(8h{IKA=9Je}4h}WG-P8XwK8IsCN<;r- zyiM5lf)M3-ZFnXXR4~04X~V~Z<+#)jL+vf(wHWbhx8UjJ=S3Rn22SBDz4iF7g9aT9 zds;_nH%ydfAHwIh!QRjVO-)+6d}cSjq0Zw1J(Fn1ZQ}Njz^c-bQ#$9AP+kdXA*O}T z?;!l}Cv+*o7R1*$qIL0&M4QkKdM=E`h{#%)Gkb{{3oCs}MClI^JCNmUI*xTUsiFjQ zzj&uFF6^Rkaeg1)?}{I7?tjI=<84HhV_O)Eg|{%Yg&3X0!m;qrI8Od5{mO|QoV@HS z4+kJ0wJML0a#Y-c+EnJ(aQGIGQyiq5ADw;=NcTICSa=5?zlN&$o}S^+30S?F2 zxQRb8jlbyA=5J(J1b5jW?y(W%*aQ~Y6qd;11(wErb_Wkwj(GQpS0uVZ^a&o4)njCD H2NM4ROm1tj literal 0 HcmV?d00001 diff --git a/sourceMetadata/Chapter03/TestOracleDatabaseMetaDataTool_Index.java b/sourceMetadata/Chapter03/TestOracleDatabaseMetaDataTool_Index.java new file mode 100644 index 0000000..5ac179b --- /dev/null +++ b/sourceMetadata/Chapter03/TestOracleDatabaseMetaDataTool_Index.java @@ -0,0 +1,89 @@ +import java.util.*; +import java.io.*; +import java.sql.*; + +import jcb.db.*; +import jcb.meta.*; +import jcb.util.DatabaseUtil; + +public class TestOracleDatabaseMetaDataTool_Index { + + public static void main(String[] args) { + String driver = "oracle.jdbc.driver.OracleDriver"; + //String url = "jdbc:oracle:thin:@localhost:1521:maui"; // office + String url = "jdbc:oracle:thin:@localhost:1521:scorpian"; // home + String username = "octopus"; //office + String password = "octopus"; // office + Connection conn = null; + + try { + Class.forName(driver); + System.out.println("ok: loaded Oracle driver."); + } + catch( Exception e ) { + System.out.println("Failed to load Oracle driver."); + System.exit(1); + } + + try { + conn = DriverManager.getConnection(url, username, password); + + System.out.println("-------- getIndexInformation -------------"); + String indexInformation = DatabaseMetaDataTool.getIndexInformation + (conn, + "", + "OCTOPUS", // user + "ACCOUNT", // table name + true, // unique? + true); + System.out.println("-------- getIndexInformation -------------"); + System.out.println(indexInformation); + System.out.println("------------------------------------"); + + System.out.println("-------- getIndexInformation -------------"); + String indexInformation2 = DatabaseMetaDataTool.getIndexInformation + (conn, + "", + "OCTOPUS", // user + "ACCOUNT", // table name + false, // unique? + true); + System.out.println("-------- getIndexInformation -------------"); + System.out.println(indexInformation2); + System.out.println("------------------------------------"); + + System.out.println("-------- Does index exist? -------------"); + System.out.println("conn="+conn); + boolean indexExist = DatabaseMetaDataTool.indexExists + (conn, + conn.getCatalog(), // catalog + null, // schema + "ACCOUNT", // table name + "ID_STATUS_INDEX"); // index name + System.out.println("Index name: ID_STATUS_INDEX"); + System.out.println("Table name: ACCOUNT"); + System.out.println("Index Exist?: " + indexExist); + + System.out.println("-------- Does index exist? -------------"); + boolean indexExist22 = DatabaseMetaDataTool.indexExists + (conn, + conn.getCatalog(), // catalog + null, // schema + "ACCOUNT", // table name + "ID_STATUS_INDEX22"); // index name + System.out.println("Index name: ID_STATUS_INDEX22"); + System.out.println("Table name: ACCOUNT"); + System.out.println("Index Exist?: " + indexExist22); + + + } + catch(Exception e){ + e.printStackTrace(); + System.exit(1); + } + finally { + DatabaseUtil.close(conn); + } + } + +} diff --git a/sourceMetadata/Chapter03/TestOracleDatabaseMetaDataTool_SPC.class b/sourceMetadata/Chapter03/TestOracleDatabaseMetaDataTool_SPC.class new file mode 100644 index 0000000000000000000000000000000000000000..c906087be65a7f1078df6f440b503cb7860ea227 GIT binary patch literal 2519 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 literal 0 HcmV?d00001 diff --git a/sourceMetadata/Chapter04/TestMySqlTableResultSetMetaDataTool.java b/sourceMetadata/Chapter04/TestMySqlTableResultSetMetaDataTool.java new file mode 100644 index 0000000..1967b6f --- /dev/null +++ b/sourceMetadata/Chapter04/TestMySqlTableResultSetMetaDataTool.java @@ -0,0 +1,46 @@ +import java.util.*; +import java.io.*; +import java.sql.*; + +import jcb.db.*; +import jcb.meta.*; +import jcb.util.DatabaseUtil; + +public class TestMySqlTableResultSetMetaDataTool { + + + public static Connection getConnection() throws Exception { + + String driver = "org.gjt.mm.mysql.Driver"; + String url = "jdbc:mysql://localhost/octopus"; + String username = "root"; + String password = "root"; + + Class.forName(driver); // load MySQL driver + Connection conn = DriverManager.getConnection(url, username, password); + return conn; + } + + public static void main(String[] args) { + + Connection conn = null; + try { + conn = getConnection(); + System.out.println("-------- getTableMetaData -------------"); + System.out.println("conn="+conn); + String deptTableName = "zperson"; + String rsMetaData = + ResultSetMetaDataTool.getTableMetaData(conn, deptTableName); + System.out.println(rsMetaData); + System.out.println("------------------------------------"); + } + catch(Exception e){ + e.printStackTrace(); + System.exit(1); + } + finally { + DatabaseUtil.close(conn); + } + } + +} diff --git a/sourceMetadata/Chapter04/TestMySqlTableResultSetMetaDataTool_WebRowSet.class b/sourceMetadata/Chapter04/TestMySqlTableResultSetMetaDataTool_WebRowSet.class new file mode 100644 index 0000000000000000000000000000000000000000..e45ddce6bc9cf321ef30c16463ac195b25cb13e8 GIT binary patch literal 1717 zcmb7EU31e$6g_ej%MpSE69-b#)RaJ+_(PP^(%O6!96}+sLu1E*!VHxa)s-tt#*!)N zAL?uAgYmR8?K{7rzopZ&az0GsPN#aDv?(ee5~Sx0ACaK6ES=$hU+nWrs8wtV<@P&ftw0$sYu|q z%I#k$xTD~%gy;?1wS!v{CQ>VP33AcfwIocJY}cyv+6}8)Ga3#(C!1DK^jz061KV>Y zoK3BiTEI)}Kx@Gx2C#YIM*$Rv`BQR>7=RDuB8e85E^yWl*4e#MR*?8S%uGtE5 z?RKucM@qT1uKm*LN?2^|Hq3nJ%j>%1nTGS7=LfoH241Hp7b2hQyZr8*&u1ygLsCi8F?>HM@Cr6Glu#zSuu&tW-|gAX zu3$H5vZXgQRIn+AM;gAumIUR;j@9)&S3y-n4ciiyM8yC46x22B;IV`=M;Q-KL&FoC z*YGu-O341NPD_|MinrNlQ3I67k*g?bChKp#ZpCQxATOoHoc4$-+(4U$CIbexj5e7K8~Co96?O#3 zp`a6E2nsz%jZVjMciG`_fMbOBg}{XG;D{oMKIK;;SZ`cJ1vj=53+nLn%ur?AP#*D}JnsF+`a^A@cVEn}^H0+c11KjO} zIg#iBqM=j8l(^K0gwPVVPI7G_9@&Ubl;UzZE>~6unA}NcvI9i(^1S@>VT45}oKJJl z45OW9q&PIpa+V;GIV8C%GfRRi7w{oxg3h1&Ilhrf11P0m5Q|Usq0;__6Hneii=XV{ zRJxDpK4!QOKV42|28dUP$PR(=GqmXeW`Dv$In&3SJiyuEzm}K9WM2N`HFHOB8|%z3 zY@NB+u^HMr9*1_=iHGD3wkyKEMA?l~?8h?Muafl@T*P%Oaeo>`WEkNx?sIhmDaJ~p TN?)D!8SQgqS>r{HqN6`an}%OW*xbF29q|Ff7t#9`>2D@B2G@@BH)cAAbRuhofNvGhxhz5f3Aw zVGc0Q5YXV*&WcG{~MymF$ojMULDA1PoO;M3rHTo+X7PW_CPg>fx;q0XH zUe$7T7Gyjv@7AlPSg~Y`D+N*W)~beSiw#k$+g@IHS>YK=hG!I9*G|fSIwmotV9IUk zCHG22Gg+!yFGMxjGF@t36iiD|x}}!(b}c7;*LF?A-gRqUdj971`E=Q+TMAUy^xR6l zrXs5&hcy)sbzH`}B=4%&(2+-h1?QJD%Zr8RY;}63muQ~ zrGog}@h?iu&J+@TBW<24p6K`rPwBsjrVpR{b;~Y^s)C?N+;8jn8sA8=t;0Z3g{h+i ziP|ZLZ@H*=reg=Yl30@LDY$SFvHfH^o?}XfjWQwrpXX3;{=~ytagVLR&N*Q%+D45n zpgwb}Iit)>r(+$Oz{hGDu!Dx1K4fFH-ZE=A#*RcH+rfd){9HCb-zAxFn!p~5KBpjE(WHW9B#C7W|M)G0Q{E@V_H!YL`3>!ff7z~feAz*G9I zH(xj|=4|UyKkT`!S5Ywd21K7CH757WVyet3PqmTo&phoqP08kyX&GqD$_<|6@i#{9Q`jb1YzX?Abna>McQVb9f z`xaj@5L=zu!aH2+6WshjH&{NVNTa+>@KksPXJ0{i$q$99K&Z*=L62NV=xVBFXd0w! zJks?b(w&I}vXMY;wt?WIcw(-BP&zOg_^s_>5-Pv@Xwy$`1N0PujzNA6@$X<5S11iI z$|xn%c#mIE22W5wM9D8oM#(C<2GmUaHNqUiM5O06v@Ya+M{h(w!a1IQqVMr5^heGg zVIY2l$Pq43z+48?0g6WhEw#uH&qM>ml#Ik1xcDoQGT9?s3N$cwS~8dp`Wd6azh5%X z5Z1BHT;+Ml{I-o5wCIDOi+6Y8u1(;ikDdNWmdYtTJPa1RuQAG z6gF{<3w$0=`IozmSrifHqD;_#3NB?e%D$uQkoO;W|B?5fc>ftUh}l)f>q6{5&cO8a literal 0 HcmV?d00001 diff --git a/sourceMetadata/Chapter04/TestOracleResultSetMetaDataTool.java b/sourceMetadata/Chapter04/TestOracleResultSetMetaDataTool.java new file mode 100644 index 0000000..95a8298 --- /dev/null +++ b/sourceMetadata/Chapter04/TestOracleResultSetMetaDataTool.java @@ -0,0 +1,53 @@ +import java.util.*; +import java.io.*; +import java.sql.*; + +import jcb.db.*; +import jcb.meta.*; +import jcb.util.DatabaseUtil; + +public class TestOracleResultSetMetaDataTool { + + + public static Connection getConnection() throws Exception { + + String driver = "oracle.jdbc.driver.OracleDriver"; + String url = "jdbc:oracle:thin:@localhost:1521:maui"; // office + //String url = "jdbc:oracle:thin:@localhost:1521:scorpian"; // home + String username = "octopus"; //office + String password = "octopus"; // office + + Class.forName(driver); // load Oracle driver + Connection conn = DriverManager.getConnection(url, username, password); + return conn; + } + + public static void main(String[] args) { + + Connection conn = null; + Statement stmt = null; + ResultSet rs = null; + try { + conn = getConnection(); + // Create a result set + stmt = conn.createStatement(); + rs = stmt.executeQuery("SELECT * FROM employees"); + + System.out.println("-------- getResultSetMetaData -------------"); + System.out.println("conn="+conn); + String rsMetaData = ResultSetMetaDataTool.getResultSetMetaData(rs); + System.out.println(rsMetaData); + System.out.println("------------------------------------"); + } + catch(Exception e){ + e.printStackTrace(); + System.exit(1); + } + finally { + DatabaseUtil.close(stmt); + DatabaseUtil.close(rs); + DatabaseUtil.close(conn); + } + } + +} diff --git a/sourceMetadata/Chapter04/TestOracleTableResultSetMetaDataTool.class b/sourceMetadata/Chapter04/TestOracleTableResultSetMetaDataTool.class new file mode 100644 index 0000000000000000000000000000000000000000..663be477e9c6aa99e7601ba9b9db3732f7faae21 GIT binary patch literal 1689 zcma)6U31e`5IxsXEJuh0L>x#-LnsNc<1a!>X&t_bLny>{C^iNPGp%f^L8)xHmdw!p zp}v+r7!RFk-}@W-TRJ^ga)?9BO!aX0-raL|_nzI=-~Yb-6Tmv2YnaDM3>RZqjUk~S zi8T!=q&1vDW(ry4Vz{Icd0EA$8jeZuXHs5~%ja^r8p9VFzC=ET4Gq_DUBwLzaop5+ z{g#TaRNNMbUbEY_e?wp*k*o^QvKWB+8?|mT40`mv|PU9kacgtN2~Jy}KdfX%)BEZCG2j zjFGHbp1;#I8;%u3eQ0?-$FEp^$@0xj(>JTG>ttnA9UtMWz&SSnXZM=*Mz-0tUs~O4 zcz-iE2&_m`K7{4{7j`>;%W)f~^TPG~{Q8y4>-m=1vjtSQ;k%ulr=p-^6L(Z>=~%>F zxtvq+wT^qZFR+>!eoLey$Zm6&+PP5?DUu`2z~OcoSHwdfwwrsvF7)ZxGF!|n+PSTSB9kblUnaCWLXjK>`PRn_G z!ktX#pJ9yeMR5SN_&Z|8R394UA2{~(4RqspAJeHmX8JfmgK@HyN)KR^iO7UN;}m6T zfZ1QMP)hePrwnj9JnMNyZswK0UNd$CH?hU|Qq~xI3p;_V;YlDvChjwDkgf=MiIRJsT)xobo$l_{IzL6~Xd<=~A9i literal 0 HcmV?d00001 diff --git a/sourceMetadata/Chapter04/TestOracleTableResultSetMetaDataTool.java b/sourceMetadata/Chapter04/TestOracleTableResultSetMetaDataTool.java new file mode 100644 index 0000000..fd9c79a --- /dev/null +++ b/sourceMetadata/Chapter04/TestOracleTableResultSetMetaDataTool.java @@ -0,0 +1,47 @@ +import java.util.*; +import java.io.*; +import java.sql.*; + +import jcb.db.*; +import jcb.meta.*; +import jcb.util.DatabaseUtil; + +public class TestOracleTableResultSetMetaDataTool { + + + public static Connection getConnection() throws Exception { + + String driver = "oracle.jdbc.driver.OracleDriver"; + String url = "jdbc:oracle:thin:@localhost:1521:maui"; // office + //String url = "jdbc:oracle:thin:@localhost:1521:scorpian"; // home + String username = "octopus"; //office + String password = "octopus"; // office + + Class.forName(driver); // load Oracle driver + Connection conn = DriverManager.getConnection(url, username, password); + return conn; + } + + public static void main(String[] args) { + + Connection conn = null; + try { + conn = getConnection(); + System.out.println("-------- getTableMetaData -------------"); + System.out.println("conn="+conn); + String deptTableName = "zdepts"; + String rsMetaData = + ResultSetMetaDataTool.getTableMetaData(conn, deptTableName); + System.out.println(rsMetaData); + System.out.println("------------------------------------"); + } + catch(Exception e){ + e.printStackTrace(); + System.exit(1); + } + finally { + DatabaseUtil.close(conn); + } + } + +} diff --git a/sourceMetadata/Chapter04/TestOracleTableResultSetMetaDataTool_WebRowSet.class b/sourceMetadata/Chapter04/TestOracleTableResultSetMetaDataTool_WebRowSet.class new file mode 100644 index 0000000000000000000000000000000000000000..a59c4bc540bcc2983dd5643179fc6480cdd2d2a8 GIT binary patch literal 1729 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 MNCbf)o)f|FKZ2zA$p8QV literal 0 HcmV?d00001 diff --git a/sourceMetadata/Chapter05/CallSimpleProc.java b/sourceMetadata/Chapter05/CallSimpleProc.java new file mode 100644 index 0000000..4726d6c --- /dev/null +++ b/sourceMetadata/Chapter05/CallSimpleProc.java @@ -0,0 +1,67 @@ +import java.sql.*; +import jcb.util.DatabaseUtil; + +public class CallSimpleProc { + + public static Connection getConnection() throws Exception { + String driver = "com.mysql.jdbc.Driver"; + String url = "jdbc:mysql://localhost/octopus"; + String username = "root"; + String password = "root"; + Class.forName(driver); // load MySQL driver + return DriverManager.getConnection(url, username, password); + } + + public static void main(String[] args) { + Connection conn = null; + try { + // + // Step-1: get a database connection + // + conn = getConnection(); + System.out.println("conn="+conn); + // + // Step-2: identify the stored procedure + // + String proc3StoredProcedure = "{ call simpleproc(?) }"; + // + // Step-3: prepare the callable statement + // + CallableStatement cs = conn.prepareCall(proc3StoredProcedure); + // + // Step-4: set input parameters ... NONE + // + // + // Step-5: register output parameters ... + // + cs.registerOutParameter(1, java.sql.Types.INTEGER); + // + // Step-6: execute the stored procedures: proc3 + // + cs.execute(); + // + // Step-7: extract the output parameters + // + int param1 = cs.getInt(1); + System.out.println("param1="+param1); + System.out.println("------------------------------------"); + // + // Step-8: get ParameterMetaData + // + ParameterMetaData pmeta = cs.getParameterMetaData(); + if (pmeta == null) { + System.out.println("Vendor does not support ParameterMetaData"); + } + else { + System.out.println(pmeta.getParameterType(1)); + } + } + catch(Exception e){ + e.printStackTrace(); + System.exit(1); + } + finally { + DatabaseUtil.close(conn); + } + } +} diff --git a/sourceMetadata/Chapter05/CreateParameterMetaData.class b/sourceMetadata/Chapter05/CreateParameterMetaData.class new file mode 100644 index 0000000000000000000000000000000000000000..c9973edd16f4bc625f9d8c919b7b11906e54d830 GIT binary patch literal 1650 zcmaJ?-*ekU5dJQaEk{=3)Q#J^q(p)Ka8f6311;b*Da36cU^@Y)fzpTeY#pu=SrU>Q zS{|6m@W2Bz@MrY7eMl3Sfk$TeqZsz&q;_h9J+ph-+g*M8-R|k{e}4M|z;!&(a27@a z(;D8w+euu+r6exn$_R3pNnlpPRpb+xOJW`c71uN*rTcZM7o>Pcigz{Kz)dOMQ}Mor z)A&H61Vt5#DsC~vZ&{8NE;9`0X0{lVl4}ZvRM~PwwcV-> zBky34ds#;XRfe;#bFxC`hKV9L0)hM}+LpzkS!X4g} z&_f9k>3`HfY{DrX>h^N(kB%Wbj zE=OpYRSuys+>DdqcO>t>gq|MV$5Ur}76#Kf~o>JWKWojts3L@}#G!Xw%->ErMiS19`wS}@=ftGi_Xp6ox6eUH{Z(fVgv|3aSt8WzGb HgsFc4U;w56 literal 0 HcmV?d00001 diff --git a/sourceMetadata/Chapter05/CreateParameterMetaData.java b/sourceMetadata/Chapter05/CreateParameterMetaData.java new file mode 100644 index 0000000..6ab2aec --- /dev/null +++ b/sourceMetadata/Chapter05/CreateParameterMetaData.java @@ -0,0 +1,41 @@ +import java.util.*; +import java.io.*; +import java.sql.*; + +import jcb.util.DatabaseUtil; +import jcb.db.VeryBasicConnectionManager; + +public class CreateParameterMetaData { + + public static void main(String[] args) { + String dbVendor = args[0]; // { mysql, oracle } + Connection conn = null; + PreparedStatement pstmt = null; + ParameterMetaData paramMetaData = null; + String query = "select badge_number, last_name " + + "from emps where badge_number > ? and dept = ?"; + try { + conn = VeryBasicConnectionManager.getConnection(dbVendor); + pstmt = conn.prepareStatement(query); + paramMetaData = pstmt.getParameterMetaData(); + if (paramMetaData == null) { + System.out.println("db vendor does NOT support ParameterMetaData"); + } + else { + System.out.println("db vendor supports ParameterMetaData"); + // find out the number of dynamic parameters + int paramCount = paramMetaData.getParameterCount(); + System.out.println("paramCount="+paramCount); + } + } + catch(Exception e){ + e.printStackTrace(); + System.exit(1); + } + finally { + // release database resources + DatabaseUtil.close(pstmt); + DatabaseUtil.close(conn); + } + } +} diff --git a/sourceMetadata/Chapter05/CreateParameterMetaData_Derby.class b/sourceMetadata/Chapter05/CreateParameterMetaData_Derby.class new file mode 100644 index 0000000000000000000000000000000000000000..05b57660697ea1ed24dd5dba402d48fc8a83b2fa GIT binary patch literal 2341 zcmaJ@+jA3D9R5y8vuU~%8rnjD!V0JbM~Cy{rg>Z|M~al-vEr_vnXD{ za0JOHQW%L~G>T(59>E(CoQT4}$qu}Uw=}#RMO5*n)t*tyDYcA6aT;ej@ea;*;vBN- zX}lBXaUp_>5nSrTWn78is^Xo9ViHqonO4h;hIgar$F(Re%xaj^a9tpL%64r3w7|B+ zz`Q^x>snG^$As<3scI=Fy*V>id6j==83z{H}tWTqVDlMj(2A zIWNnKt3rJx(3FnQBFPVo0ZA~*R#e-j9tS`9k1bifva_1!&f*M6|+<> z%7x&Nuq|W$?6vHrv)2-%BLhQ5#rGESZn1HBOkFzFQgCTI{(!)hiYyXB!?qgi8!UG` zx71?6cyL#GlFY_wR z-`JEV=4FF@ovX5$O~ZX19#|cnWtHlzTXp=vKVL&t#}Xc>WmzpN0=qT>YgCqwk8xPX zC-_vL|D{zUuyaFxI=4vhS>790*&@>}pxtr3DOR1ptBEZtwdpDlV43#?I#l)7t8LPB z%z}b@;Kd3y^-7a(vnv%}me_}Gl^*uiE!u8shP~pmW29N4)v#GEGaUlMFSfF|1}NCV zU&kS{-oab)M|`*5rUE_BTfK>q8tZv!^^ic8mA^&yeD78svgPY?txzx}^){RJIRHx1 zAq0KT%_`Q$Jq^bi$Tw~|pX9R4SABWCY*E7ttY2m|ls(C+lTD%{TRB?CUzwh%3s?;a zy0Ew5!X_&5;;7uBHx4w%vx(lS^#2o3pu1UV&@sWtW<>iFmtU61-o<<_RrPJwDMx9} ztjOy;sHsqND+Frydi1R*tJ!?8iLxooV0!Oq;%IsYDB&GJ9T2npy*ba!(@;n*+e~YS z?#}ZaXz;Io+rYt(!(5N>)X!aTZ$J7B;t3zvkX*yTWf&c5=AkWMO|G+c#oB7vb|V(L zdbEc2#|@b-ss>+!Vd#|Gjs#C3%JlOzfTMh(LGd}cI!O6TOo&M_CDNf-INcu8(%~8+ z6F;Kk7esG9LuX81#rDBfbgg2?Ds~R8p<7^bDBiw?SQ~B(#=~pa)rP6zHS`FiL-Ekx z=%RS6m)zeWsUG|I7!R#sx4=oQN%bD8?$uTiuj?MFVefDa`vz;+Psy|vC+$F}hJ&q? zo^+)7A|Cnu2?OlLLp)-TYJbYW9^u_rm$a02`J!O@S4IDly!#2oW>o0(f+#tKYLnF)EwFPSeef-m`b^A*2l9ueNJ3Gg=< ir0o>GC+!E)9+UQz=QW;x<@pbu|HN@7VvxSHVdy`t6lq2P literal 0 HcmV?d00001 diff --git a/sourceMetadata/Chapter05/CreateParameterMetaData_Derby.java b/sourceMetadata/Chapter05/CreateParameterMetaData_Derby.java new file mode 100644 index 0000000..55443fc --- /dev/null +++ b/sourceMetadata/Chapter05/CreateParameterMetaData_Derby.java @@ -0,0 +1,52 @@ +import java.util.*; +import java.io.*; +import java.sql.*; +import jcb.util.DatabaseUtil; + +public class CreateParameterMetaData_Derby { + public static Connection getConnection() throws Exception { + // in an embedded environment, loading + // the driver also starts Derby. + Class.forName("org.apache.derby.jdbc.EmbeddedDriver"); + // connect to the database. This will create the db + String dbURL = "jdbc:derby:myDB;create=true;user=me;password=mine"; + return DriverManager.getConnection(dbURL); + } + public static void main(String[] args) { + Connection conn = null; + Statement stmt = null; + PreparedStatement pstmt = null; + ParameterMetaData paramMetaData = null; + String create = "create table sample_table"+ + "(id VARCHAR(10), str_col VARCHAR(20), num_col int)"; + String query = "select id, str_col, num_col " + + "from sample_table where id > ? and num_col = ?"; + try { + conn = getConnection(); + System.out.println("conn="+conn); + stmt = conn.createStatement(); + stmt.executeUpdate(create); + pstmt = conn.prepareStatement(query); + paramMetaData = pstmt.getParameterMetaData(); + if (paramMetaData == null) { + System.out.println("db vendor does NOT support ParameterMetaData"); + } + else { + System.out.println("db vendor supports ParameterMetaData"); + // find out the number of dynamic parameters + int paramCount = paramMetaData.getParameterCount(); + System.out.println("paramCount="+paramCount); + } + } + catch(Exception e){ + e.printStackTrace(); + System.exit(1); + } + finally { + // release database resources + DatabaseUtil.close(stmt); + DatabaseUtil.close(pstmt); + DatabaseUtil.close(conn); + } + } +} \ No newline at end of file diff --git a/sourceMetadata/Chapter05/CreateParameterMetaData_HSQLDB.class b/sourceMetadata/Chapter05/CreateParameterMetaData_HSQLDB.class new file mode 100644 index 0000000000000000000000000000000000000000..737e388bf18640c66ce4633e9a4739053ce667bb GIT binary patch literal 2079 zcmah~-%}G;6#gzG*|4mF(Wv|oR;@NbLR8e&AW#Wdut~rMQEOYe$zH-@vKx0d)ON<{ zOCS2sht4p4=tF1PCtqtHFtju6V`utDb$aeDkU(OancN@ep7Y&vzH{!`zyJB|4**x; z%1{vxBOzlPNeNeE1jPQTn6HUpB8=-{+>mh-?}YJg7`J2$Bh`gT+zw+(s7%Y4!F%1f zgV}DRF&D;s7R z(w5E{dNPK|bG1r=+bde3Op;?I?xro%eeJl4Z>-CG)Orn5D@PU*tS1 zCmX7h4D$T*BCiTNhi<572HBsEJ!u0#9>{sCW*7NgL)>~XZF9}#%bKlKxXbM|bh-JR7a~+ z%Y4lhoT;C0aGR5|I<3yAnyDYCPN_2tl3rL_ryvFPWeFcE_ynIa1dBxSl<;Cr!e>OpC;nJH+&8t4ofXXbSRjWh_L*jo7{BqsPKN*Hy%NH@6itQC~b6r!ldhUtB z_RA`(nOaHIPPWZet##chdDByAq9*@^Rmk^4vHEQ8 zzr&^w8nODxI}Af)R|RO9-et5+K%z1Dc88xfWwL5>surGi>6KQvNseA=2jDv|te1TQ z{lJ1^=s#e$<&-i)ji*gb5A7$)13lUw4uc*&WjN6c>Q%be02dhsV~ed7(4a56Su7-L zu0e%BZK$9*`~hvmvn^W=)#~tG^zB0xM4oNZXzG&UsK?6!F;jfHVrxZ$3-IR#aT*|} zR;kSm(AKKqwyl`&e2SL3c=CWV6SLFFP_GbCzQ}78Vou-)hW*uI3MY#qx0eK z2t0m`U?j8yX_Wpu2uHdiavj~j9KgtA3Md2@!P~S75bPj<#xO!Fx}V)4P>D`{W*L@c zxrmYqM2^*QJo77h_HXDV^sybBpc{4&8S4w|;$#Q1@m-u^$R+;5aZ-*%>FgyEVtJaD ziCvswxEXB1IZHUv;12qHpm-hqV|5I?#N|}5kL2e9bqqD6y{XXtrZ4p8D{@|@9`%9( z5c4)U{Q}>3^ESTsW}iC~19a9$q4$%`00l2BhS5t27$NGf5&5?$_$gv~p7>oLYL@Bb x5k?7j0$aF_FL8s=6Zne0?_VQH_e|hhl7C0?ZCd|8>mO ? and num_col = ?"; + try { + conn = getConnection("db_file"); // db file name + System.out.println("conn="+conn); + pstmt = conn.prepareStatement(query); + paramMetaData = pstmt.getParameterMetaData(); + if (paramMetaData == null) { + System.out.println("db vendor does NOT support ParameterMetaData"); + } + else { + System.out.println("db vendor supports ParameterMetaData"); + // find out the number of dynamic parameters + int paramCount = paramMetaData.getParameterCount(); + System.out.println("paramCount="+paramCount); + } + } + catch(Exception e){ + e.printStackTrace(); + System.exit(1); + } + finally { + // release database resources + DatabaseUtil.close(pstmt); + DatabaseUtil.close(conn); + } + } +} diff --git a/sourceMetadata/Chapter05/CreateParameterMetaData_Oracle.class b/sourceMetadata/Chapter05/CreateParameterMetaData_Oracle.class new file mode 100644 index 0000000000000000000000000000000000000000..12dfbd944bf2325b2a3a5bc01823c9e2892c59d9 GIT binary patch literal 1707 zcmaJ?-BTM?6#rdFvLRUr4TLtRWofZZAh5LBs-Zw7{X&yK4Ml4on49c1F5T?L-A$wq zKKS5+GmH;DIHUhSpX&n!ol)PM@sDymcY}nF49UznXU{$N+;e{CoO}QI_qRU)+`zLK zE@3i?D=}QfR2*;Pnu6m6mxOtm{)Kk23793Dfv5+yerAA7;fV| zN#0lRK@6kF$H>8gf;$Qp86tN~+w_+h`ZL*0hETyV1Vf@|+M?WQRE4|2s}^ZO4Q|>D zW0_~gZQka(#qGLY@m(xX-uNTwb%p zob;d~jd6yeCoEC(wJJC2V#^MW%xM<){4JX{YhSodLlcdrr+xjUaK#BbZAn|!xNT^L zX!_cswya=D#WL=`zr3?zJdoT9^w&0 z&Zuf_VH=LC8IJI@^4f;xwVF-G^|dn@DOgqU5k6*^>TWx<_IjBYRg_R>xOf`Hm6mB4 z!exk4bi7e;TDHHaVh!t(JXY}uDhf7KJi(?UpE8Veeca!v5eBAXtN0A#DxTtVhRf%d zfnm7oV6D1MWnh@xu2prTs&5MS#R~V#TEVexS|QgZZu7c~aIh}?u9_j6>CqD%mG_mU zcTE@mkNKpU0%>-Na#RzB`SYEgsUrCv?-cl<@XyqV;d&-p?9mLTTa?@!L#6V9|?e=^MW@_VKfhmA#XzL{Cgp0gbFoz6frj1pMg-Z&g{N<=nC%Qr1uPIHxe;t72) zglm@L(cDiQ1{9=pddz}r;?gmTV|^iSkVJqNbwKU;1`VyebHt8Gu!kt@O-$k5cE3O*<UUf@aHRpkic`a>7JH+ zm!fUs+ko%lhk$qTYg1l8oa|M~br4Yu(N}{0N!mL?tE2RCr09(p!#n|Ziy&Jh(C!jC zj|h>+m>~ZdIP@5Jn5I*%V25^mgDE;MgYQWHJ?VEz{*mOLNd6f!gyaOB+XwAG6AZXs literal 0 HcmV?d00001 diff --git a/sourceMetadata/Chapter05/CreateParameterMetaData_Oracle.java b/sourceMetadata/Chapter05/CreateParameterMetaData_Oracle.java new file mode 100644 index 0000000..a8b82da --- /dev/null +++ b/sourceMetadata/Chapter05/CreateParameterMetaData_Oracle.java @@ -0,0 +1,44 @@ +import java.util.*; +import java.io.*; +import java.sql.*; + +import jcb.util.DatabaseUtil; +import jcb.db.VeryBasicConnectionManager; + +public class CreateParameterMetaData_Oracle { + + public static void main(String[] args) { + String dbVendor = args[0]; // { mysql, oracle } + Connection conn = null; + PreparedStatement pstmt = null; + ParameterMetaData paramMetaData = null; + String query = "select badge_number, last_name " + + "from emps where badge_number > ? and dept = ?"; + try { + conn = VeryBasicConnectionManager.getConnection(dbVendor); + pstmt = conn.prepareStatement(query); + oracle.jdbc.OraclePreparedStatement opstmt = (oracle.jdbc.OraclePreparedStatement) pstmt; + oracle.jdbc.OracleParameterMetaData oparamMetaData = opstmt.OracleGetParameterMetaData(); + paramMetaData = (ParameterMetaData) oparamMetaData; + //paramMetaData = pstmt.getParameterMetaData(); + if (paramMetaData == null) { + System.out.println("db vendor does NOT support ParameterMetaData"); + } + else { + System.out.println("db vendor supports ParameterMetaData"); + // find out the number of dynamic parameters + int paramCount = paramMetaData.getParameterCount(); + System.out.println("paramCount="+paramCount); + } + } + catch(Exception e){ + e.printStackTrace(); + System.exit(1); + } + finally { + // release database resources + DatabaseUtil.close(pstmt); + DatabaseUtil.close(conn); + } + } +} diff --git a/sourceMetadata/Chapter05/DemoDynamicParams.class b/sourceMetadata/Chapter05/DemoDynamicParams.class new file mode 100644 index 0000000000000000000000000000000000000000..ebd87d94c3014ce7ae47fdb0db4044626f91d128 GIT binary patch literal 1791 zcmaJ>TUQfT6#hB1qy|FH%VN z;yN-)Oh<4YHzK%+TT0wk;!ZC)^Y4}_ql(lTjofq)O6I%j-rK%|f`qwO5t~V+LS>H4YW$pwjhGh$k#JAUW zjqi<2*|1BQyj!>I(yR)M+}|t8nrl^UN5iVXfN43kveA4bokrQsOIP4rydCPiDrY*| z?cjX1Q7_6BOH~?KmX+#q(>5wral@z^73aFDsAB??0$E3vWzmgUW-3M(nTi=D8GBK$ zR${VJD_5IRIi7Ut z8XoJ|!juwUDe*+ZQytH+t>bI#==cWTYIv^0K!GQEmx{%PRW@avbZuMaoQ@()C3q@r zXIsIYBjY>Ugv^Ctx)&&Ec&Wp}u0UV9`zJ7XiV5=Sm3&axB@+T?y{%3Y1TO6s3mLPJ z*^>35>HW3hIUrD;&wm{;jLnoT+HO+IKJ+7*H>1`8UtuAXuUFKcG zl@)0d-t_+`-Dn4xoe1VW-#U@XeacGy9Oaax@yXNy$-PW9rc6oTGZkeJT$eog$0$c78D6iHt z;wITG+=2LNf;Xgxdiw$q8n;g0s}tSMHytv{WYq>!4!6CnDjBkDl}8#CG8ZyxHEEjy z>HlWEtGh?@%D{>DA@Iy$w|b0q=$PNGJe_$s35a7~Q}D`sIfmZ{XbYG4w2kux1pFWh zOj2H;roMvTVDc@*8!p%%%1~=Fj2^@o>T9|F#ZZm5rdSg>u^#o!1d{%nGr_Uo0sOht zSl|!=AJ)@>0rL<+KhnX03+=@rLIP{o4xrI!9~)QRHPRuRK0r_E0Fl=inhAApjD`Mq zLm>Tlf)YWLc$L++4Yz<%u65e`5WpG2k0OF$dXG|05dKA6$x@|iDDuTXzQy+M7CQI}aEzU0a|vFhv*gf3F}Gn zp!<+b1`pBaLoOL=>GQwf%x~y_`W6Gx!F@!>_i;8l#6^n#=rF~k+8N<}nUEo3P@eqq$Km|Uew+~nU1;3W2Z2$lO literal 0 HcmV?d00001 diff --git a/sourceMetadata/Chapter05/DemoDynamicParams.java b/sourceMetadata/Chapter05/DemoDynamicParams.java new file mode 100644 index 0000000..c6f5335 --- /dev/null +++ b/sourceMetadata/Chapter05/DemoDynamicParams.java @@ -0,0 +1,67 @@ +import java.sql.ResultSet; +import java.sql.PreparedStatement; +import java.sql.Connection; + +import jcb.util.DatabaseUtil; +import jcb.db.VeryBasicConnectionManager; + +public class DemoDynamicParams { + + public static void main(String[] args) throws Exception { + + ResultSet rs = null; + Connection conn = null; + PreparedStatement ps = null; + + // the following SQL query has two dynamic input parameters: + // first parameter is for “id” column and second one is for “age” column + String query = + "select id, name, age from employees where id < ? and age > ?"; + + String dbVendor = args[0]; + try { + // get a valid connection object + conn = VeryBasicConnectionManager.getConnection(dbVendor); + + // prepare a SQL statement, which can have parameters; note that + // a PreparedStatement object may be used any number of times + ps = conn.prepareStatement(query); + + // specify values for all input parameters + ps.setInt(1, 100); // set the first parameter: id + ps.setInt(2, 30); // set the second parameter: age + + // now, PreparedStatement object is ready to be executed. + rs = ps.executeQuery(); + // iterate the result set object + displayResultSet(rs); + + // NOTE: you may use PreparedStatement as many times as you want + // here we use it for another set of parameters: + ps.setInt(1, 110); // set the first parameter: id + ps.setInt(2, 70); // set the second parameter: age + + // now, PreparedStatement object is ready to be executed. + rs = ps.executeQuery(); + // iterate the result set object + displayResultSet(rs); + } + finally { + // close resources: ResultSet, PreparedStatement, Connection + DatabaseUtil.close(rs); + DatabaseUtil.close(ps); + DatabaseUtil.close(conn); + } + } + + public static void displayResultSet(ResultSet rs) throws Exception { + while (rs.next()) { + int id = rs.getInt(1); + String name = rs.getString(2); + int age = rs.getInt(3); + System.out.println("[id="+id+"][name="+name+"][age="+age+"]"); + } + System.out.println("-------------"); + + } +} diff --git a/sourceMetadata/Chapter05/ExamineParameterMetaData_HSQLDB.class b/sourceMetadata/Chapter05/ExamineParameterMetaData_HSQLDB.class new file mode 100644 index 0000000000000000000000000000000000000000..8847ef1e20383ed3bc7afb899656a8b14a9410ef GIT binary patch literal 3118 zcmai0S#uOs6#h<_%yfDhi6bL~wZoc(EbK@iAS3}I$t0Ks_t-Pj2_1U6$L^ja;D&+= z?zoGHR%ul%9xS!W5Y$r3vPw(z!3Qn<13viVi?5dFc26>s1(~Ypd;6U4?B|}_KmPmq zR{%EQT^XCPN5Wniw_;xe`(=d0d$U+u#G_Th0SO0X973Cf+aw&8S+2bd9Y{#%6p$_% zM{s)--ROy;7kv_rO1LA6J8_qUy9MGN3HM64Pmua0+%Hy5LQBqHnQUJKm?AAdblz>;6;#&V3-izZCHl4hcK_Ix{nZQw$nOcLAzn; ziCiYBJ3U&`WXk+O-D|cjOHX-*Z4s)g+K04Zt-;i+!G>vQTy^&x3fKd=+s-*D{eU5?u4x_BGVDs1=4ct+)1408(^@o7>p#?e zq`hT-z3@T77HlQNZD+9l7#mL~>xa_GREuK_>rMnC3Py2)uxO^g`*Vhw)*XT(;EjQ3 zqk@xoP{BiZm{8(s1Vr$Nf*p92aF?r_oB-8G*Q&1P^rvjIR<&{&u~7#cJEOWnic79wsV%}JMt3Yrn=cbZW13TGQy3+&~td1urMHUy;Sc+R##KpVa$64 zug>OKTxI6HCU`dnaw$`DT{X{mT__CPQ8PjhVVQSKSAD4HkM*ukR}EL~?Cq&1EWH-H zEy3Is*X9P|s|7$=|h(*nRRq- zG`-u?*jL?RM>o!;AaGttcLf6JDG82Y$y9b{ak(OVC3MXk%zUOM3*{@F$)B!tCYMir zu~L8J_*YXKAM~oW*&R?wUwN@$4-Xo?YFL5=r}-&3LG#Av(#P(_ixv4D9N?!J=Ds7K^1pZd?=M{$aw~LB41ER&DDGPMGSD$cA392pZ>XXEh@RV2vKx_3f2O@4Y)L^ z<2{a+62a-C1{YPt*oR8~u-MF>CBQt8xDNTbjo+5@$~PEFYc7L6;SFIsKf^vTj52Z6 zpu~qZ`JzB&tYiZ7j(&mAotIG>3y&jG!~bzev9g#vf#}CmYGf7#qO7hQJ9!skwe_sD z5xaQD_DlX@rSsY9AJk4Al!z&fq1gNh+|d3h7ED?wXYCutaU)w8M{Gky=n8HsK}YQs zEF>iAzQ+v=j>VZbM!MME%-gyvSj4fE7U@~cdg7(ys0b7ZrJu!`@43IYEr3PbGK*QJf}3UuWNy%MtUxtZa{H>>M3rd5 zDzsuXe>AT}7uMqrRKa1yNz~vBHsB&^@geH)EnEBv4fqoq@i#URe~!~aY@vGo7Tk($ zv>V%LFLqEXZlMnBq%Jg4A9m4w*i9Ptkb!;VVn2^qwJ*1=%O!iguY?=cTE3*=~sFG3-5pB{qO8CVK>KGf~Nlf2&6ck literal 0 HcmV?d00001 diff --git a/sourceMetadata/Chapter05/ExamineParameterMetaData_HSQLDB.java b/sourceMetadata/Chapter05/ExamineParameterMetaData_HSQLDB.java new file mode 100644 index 0000000..baa9ff5 --- /dev/null +++ b/sourceMetadata/Chapter05/ExamineParameterMetaData_HSQLDB.java @@ -0,0 +1,89 @@ +import java.util.*; +import java.io.*; +import java.sql.*; +import jcb.util.DatabaseUtil; + +public class ExamineParameterMetaData_HSQLDB { + public static Connection getConnection(String dbName) + throws Exception { + // load the HSQL Database Engine JDBC driver + // hsqldb.jar should be in the class path + Class.forName("org.hsqldb.jdbcDriver"); + // connect to the database. This will load the + // db files and start the database if it is not + // already running. dbName is used to open or + // create files that hold the state of the db. + return DriverManager.getConnection("jdbc:hsqldb:" + + dbName, // filename + "sa", // username + ""); // password + } + + public static void main(String[] args) { + Connection conn = null; + PreparedStatement pstmt = null; + ParameterMetaData paramMetaData = null; + String query = "select id, str_col, num_col " + + "from sample_table where id > ? and str_col = ? and num_col = ?"; + try { + conn = getConnection("db_file"); // db file name + System.out.println("conn="+conn); + pstmt = conn.prepareStatement(query); + paramMetaData = pstmt.getParameterMetaData(); + if (paramMetaData == null) { + System.out.println("db vendor does NOT support ParameterMetaData"); + } + else { + System.out.println("db vendor supports ParameterMetaData"); + // find out the number of dynamic parameters + int paramCount = paramMetaData.getParameterCount(); + System.out.println("paramCount="+paramCount); + System.out.println("-------------------"); + for (int param=1; param <= paramCount; param++) { + System.out.println("param number="+param); + int sqlTypeCode = paramMetaData.getParameterType(param); + System.out.println("param SQL type code="+ sqlTypeCode); + String paramTypeName = paramMetaData.getParameterTypeName(param); + System.out.println("param SQL type name="+ paramTypeName); + String paramClassName = paramMetaData.getParameterClassName(param); + System.out.println("param class name="+ paramClassName); + int paramMode = paramMetaData.getParameterMode(param); + System.out.println("param mode="+ paramMode); + if (paramMode == ParameterMetaData.parameterModeOut){ + System.out.println("the parameter's mode is OUT."); + } + else if (paramMode == ParameterMetaData.parameterModeIn){ + System.out.println("the parameter's mode is IN."); + } + else if (paramMode == ParameterMetaData.parameterModeInOut){ + System.out.println("the parameter's mode is INOUT."); + } + else { + System.out.println("the mode of a parameter is unknown."); + } + + int nullable = paramMetaData.isNullable(param); + if (nullable == ParameterMetaData.parameterNoNulls){ + System.out.println("parameter will not allow NULL values."); + } + else if (nullable == ParameterMetaData.parameterNullable){ + System.out.println("parameter will allow NULL values."); + } + else { + System.out.println("nullability of a parameter is unknown."); + } + System.out.println("-------------------"); + } + } + } + catch(Exception e){ + e.printStackTrace(); + System.exit(1); + } + finally { + // release database resources + DatabaseUtil.close(pstmt); + DatabaseUtil.close(conn); + } + } +} \ No newline at end of file diff --git a/sourceMetadata/Chapter05/ParameterMetaDataAsXML_HSQLDB.class b/sourceMetadata/Chapter05/ParameterMetaDataAsXML_HSQLDB.class new file mode 100644 index 0000000000000000000000000000000000000000..f50e22788e61887cf54ae62f90332f20c1cded7f GIT binary patch literal 3619 zcmai1S#(t89shk{GWW~mvN$qIAixk7lS~#sMF~li1dvEJOdtrgcxUD&+%Ow+XAlq@ ztxKzwu6CoX6>Y_?f^9><7Q55h*0-M1r@r-^zV)qd_4N0@Hhs=N9E_3#>X@s3*qB9UX90LX~YGe&`4_7f*REr z(>NhlM`K*$q+C-PX^o6VR-l~5DUG~_t5MJ>YMd7I6Qb&j##xPX0zav7UgIgbenMkH z<7v4*qwz_NXEmPFcwXZLjZbNOTI0nK_TZ%|dLZCaFv=x^3IvKma zn2y`|VJn^@X6cw+=+0&`cB0^9GYSp$z2nwtt2Je1##)C8c_%ZrtHDRPr&6u6th*FK zd(R~7oXEKfHB>Zc<*l?`u=9O(!P;XLtljRBzFvi`(@I6d0-loka*GCDqt9u}p+|Sr zA6vvF#uOUL7V`;vpCfV9Ezs-PKE8kGVDFx;7KzEkK0Krl$>zsePSBNPyk$HYPwdG% zr|rCfOD0~&8wz*MkH4$vq>^@C!4&p3U$o7{cko>kZ{o5-g=;Cmz*{CB#`g?--^35_ zLxt7tx%nB1CbGp$p`%X3e?-YTmMAjI7R_Z{M=~lLKgQcq$ims2O)jIo)w`Lvf~$<) z!}l}aq*ePg4>IwN(5u@MDa&=I8O-+9axmDQWxr9F*NJ(ibcmAa>g=tl7c_Q&m@FN&-M&npj_TgI4(mV*ELa3+p{=P=q9X`7@rcV zZg2HrF_0;yQqq?sUKe8JsFiYA-9RB<Po>hSfJv$}^L(lJ-hqsS$}j>e?xG zdDKZZMcqRFcp{r>ie`#wxkN|v*>u#k(z%p?*7CFLWLpRM2o+dS+e*{tIo;s*;UX`{Y_j~WpR0!Lm=mQbJ};3)N-i&^FE{ti zqr2Q>TrT!d!J@CWl&ti)mA6<~KQIR(kercV3}tOGpE|FGrTwL_uGGqlKcX^=iFj+V z;G|mR<&9geeTabUpj1|N==$kEJ^A@&cS*>r$~ej%dLb?M^2HbuCx`P^LORYq<1l(@ zyu;YQkCMIo0t3HUlsvQi-A`yOPri((Y`g|_l^2B`{sui{5LL1*QQ@(6V2Ov_5U!ZQ zl96{2c=Q@7!@)@yjr>0e9j*$8rcixlMooyKKsD8^Kre4%dpDJGL;6Z9Ztyf|_07gx zs8m;`mG(AXhpEsJ3ooVSkyz~{mW{;1%LS+nybc|swJU+nwY6`kL@d0*V_I9r)VTIK zZmYnKKr9^gh>?I#y?Wh@-=s5O<|5x%2Dy_3{nEWFC6N{BRH;~%R_OlxSs zh#1CeSQ-n{MPuYL8Y4!)gXxXHt0P9G2e0$tP%OM&Zn1FGKQ_oA4%Jbcjz#n&Hj=u@ zr*1A$w~$&Di&Xhh+~rg2OVkEZL$OH6r%E-bf;sXvH<4N$slF&~HVabRs`lM%@nO2v z>Pv0)k8N^1w?tk3@YPs&yN8pMmny3&@F4H2SkW3*cMX=I77=z+E!Lq9>(PKHTG(}W zV^W(k&HX4ya3`I2IJeu(=C0@c-enxM@MQq0#C?2^@8?^&6CY6PU$F~+Lp%PC4*Ub1_$Ph(7rO9obmKqRqk`D0mSUe;$&bo4 z*snIBN5$~4+KvNiCwf&E`cx0!>Ol;s5e%xwaZuTKM5QpKvKUrH98%|TSWV!FdI3k( z1sqeaV57Q-$J8Z8Q0nLbcJv?)vbQ-=s+nVAFgF)euj*6%;k(-c;d`cVZ|^(UQJR_i zm{6AIex`I1J7YD0>u9S$U(v=XrmT_m}Y$llBPhRbc49Lj9!p literal 0 HcmV?d00001 diff --git a/sourceMetadata/Chapter05/ParameterMetaDataAsXML_HSQLDB.java b/sourceMetadata/Chapter05/ParameterMetaDataAsXML_HSQLDB.java new file mode 100644 index 0000000..3a2d8c0 --- /dev/null +++ b/sourceMetadata/Chapter05/ParameterMetaDataAsXML_HSQLDB.java @@ -0,0 +1,126 @@ +import java.util.*; +import java.io.*; +import java.sql.*; +import jcb.util.DatabaseUtil; + +public class ParameterMetaDataAsXML_HSQLDB { + public static Connection getConnection(String dbName) + throws Exception { + // load the HSQL Database Engine JDBC driver + // hsqldb.jar should be in the class path + Class.forName("org.hsqldb.jdbcDriver"); + // connect to the database. This will load the + // db files and start the database if it is not + // already running. dbName is used to open or + // create files that hold the state of the db. + return DriverManager.getConnection("jdbc:hsqldb:" + + dbName, // filename + "sa", // username + ""); // password + } + +public static String getParameterMetaDataAsXML(ParameterMetaData metadata) +throws SQLException { +if (metadata == null) { +return null; +} +StringBuilder builder = new StringBuilder(); +int paramCount = metadata.getParameterCount(); +builder.append(""); +if (paramCount < 1) { +return builder.toString(); +} +for (int param=1; param <= paramCount; param++) { +builder.append(""); +int sqlTypeCode = metadata.getParameterType(param); +builder.append(""); +builder.append(sqlTypeCode); +builder.append(""); +String paramTypeName = metadata.getParameterTypeName(param); +builder.append(""); +builder.append(paramTypeName); +builder.append(""); + +String paramClassName = metadata.getParameterClassName(param); +builder.append(""); +builder.append(paramClassName); +builder.append(""); +builder.append(""); +int paramMode = metadata.getParameterMode(param); +if (paramMode == ParameterMetaData.parameterModeOut){ +builder.append("OUT"); +} +else if (paramMode == ParameterMetaData.parameterModeIn){ +builder.append("IN"); +} +else if (paramMode == ParameterMetaData.parameterModeInOut){ +builder.append("INOUT"); +} +else { +builder.append("UNKNOWN"); +} +builder.append(""); +builder.append(""); +boolean isSigned = metadata.isSigned(param); +builder.append(isSigned); +builder.append(""); +builder.append(""); +int precision = metadata.getPrecision(param); +builder.append(precision); +builder.append(""); +builder.append(""); +int scale = metadata.getScale(param); +builder.append(scale); +builder.append(""); +builder.append(""); +int nullable = metadata.isNullable(param); +if (nullable == ParameterMetaData.parameterNoNulls){ +builder.append("false"); +} +else if (nullable == ParameterMetaData.parameterNullable){ +builder.append("true"); +} +else { +builder.append("UNKOWN"); +} +builder.append(""); +builder.append(""); +} +builder.append(""); +return builder.toString(); +} +public static void main(String[] args) { +Connection conn = null; +PreparedStatement pstmt = null; +ParameterMetaData paramMetaData = null; +String query = "select id, str_col, num_col " + +"from sample_table where id > ? and str_col = ? and num_col = ?"; +try { +conn = getConnection("db_file"); // db file name +System.out.println("conn="+conn); +pstmt = conn.prepareStatement(query); +paramMetaData = pstmt.getParameterMetaData(); +if (paramMetaData == null) { +System.out.println("db vendor does NOT support ParameterMetaData"); +} +else { +String metadataAsXML = getParameterMetaDataAsXML(paramMetaData); +System.out.println("db vendor supports ParameterMetaData"); +System.out.println(metadataAsXML); +} +} +catch(Exception e){ +e.printStackTrace(); +System.exit(1); +} +finally { +// release database resources +DatabaseUtil.close(pstmt); +DatabaseUtil.close(conn); +} +} +} diff --git a/sourceMetadata/Chapter06/PrintDriverPropertyInfo.class b/sourceMetadata/Chapter06/PrintDriverPropertyInfo.class new file mode 100644 index 0000000000000000000000000000000000000000..366320217a1328c3b112e80019f691d2ffd460c1 GIT binary patch literal 2553 zcmai0+fx%~6#sqZvYTa5yAY9!8mnlCBq+98L9Gx_!2lX87Hms5$%;#p-MG7<(u=LF zReQHLXZqR~Uiwfwoj~i1eRQV%5BkTnJ>PC1iBQW-zRS6v-#O=7{`mX1M*t4tzJvq@ zL<~wuVo1cWgwr@9;;e`f5u+l`2}p?;lOSO{gbAGI%LTrq`7#;8MZ6?nN`k`eT;lu7 zBBuF1BjPgOUy<-CUK24Z;&pyhMPx)|CB%^vph?(`0SQ+yC*mrX*Bda8H$>z`6nK0F z56a}?MG@BoSORPYd2D*}LTYv>Ju)?%W>8Y|>Vn#nSB<%zNypNSxqgPmq-ofWYB*DB zzNFE8B0Z2y4X-J+j1CPZXD9eFm>wBAQ{@DY>xS-}Wbj41rWpK5Ge`PcQo5mymkJrp zx~OLIM3M5Qnj5n81sOVwg_EE)|QWXHA92yP!DHHj%J@=XiIChnO~rujugF)Asdk^rp3K{ zgKuSghr2TRah!TBzV=5D{6_;YY^{Pbk(t-BP94d^i%5iynzu*h4Aat*s!e6zu*YX; zG^z%ZdDW&y7bw7SwLm(Z8_h+{sJIF=uI;Xkjk}*_&~S|jm0B<~RmP=u1{g%EQc|i4 z#nq6j7NtJNMcdH|G~i~5k`H^~=q6Q(#*+Zh)B=SRREtIGK!*7L8eTb zNw(;is~|T=*9(#XZzSpiB2eAeBTr92z&+7Z@C0aMs-e#DE)UIVm1pLu6{x~ZPV2Jt z8l!)Gbd^COd9UhK6GS1e_0QVb4UqGYd15O1yPp33QEkb1rMsHyP+RRFfdqKZ(I+KN zUk<>BR`lQ?7=7%3P4Lsbx8^R;{cz1aL=ud@jI?2!bcrHD ze8|Zx7rjZ&xadGk*;Iz_d&r7^1%XRTI22QY6^h_dcEuF2LJ4`4#)pumm4;==zgOKP z&_D*8$W1f0AWYxJZD>aeWw#xBDe^eo4x@wI@5CuY&_~idehDIf4ZOfu6VU|XEXN+h z|G;;=J@)7a{1|KR{RNF)~#%7XL+UdN6qx{%W#tz?+U^o~jH=Q+xc9K>+9PC|H-f=6)mj3yxMq(GS zS_7;6wp)z&7priL5&*zHN@qU;h@lbP1Pliufjv~_161Tm0^|}EaF$A#p<2yTg&eBU zJ=*URBtMZ}87FI?3gHCZy&C>WH4KuEJ278x>c9#jF@NvaL+mCXo*nOA!Ja;UO}Kk` zxCBV2hefNuJN_&7`A`Sn{z^_2p&IpQMZK$x*jmo5ffXDeA%!4stES!ynZg>N)CZ}y nBXk?3)X$*}DN1$>FVa6_)3|^|0^kN_a2uCvQe?#E-GAy|0?T$u literal 0 HcmV?d00001 diff --git a/sourceMetadata/Chapter06/PrintDriverPropertyInfo.java b/sourceMetadata/Chapter06/PrintDriverPropertyInfo.java new file mode 100644 index 0000000..68274cb --- /dev/null +++ b/sourceMetadata/Chapter06/PrintDriverPropertyInfo.java @@ -0,0 +1,93 @@ +import java.sql.Driver; +import java.sql.Connection; +import java.sql.DriverManager; +import java.util.Properties; +import java.sql.DriverPropertyInfo; +import jcb.util.DatabaseUtil; + +public class PrintDriverPropertyInfo { + + // list of drivers to be tested. + public static final String MYSQL_DRIVER = + "com.mysql.jdbc.Driver"; + public static final String ORACLE_DRIVER = + "oracle.jdbc.driver.OracleDriver"; + public static final String JDBC_ODBC_BRIDGE_DRIVER = + "sun.jdbc.odbc.JdbcOdbcDriver"; + + public static void loadDriver(String dbVendor) throws Exception { + if (dbVendor.equalsIgnoreCase("mysql")) { + Class.forName(MYSQL_DRIVER); // load MySQL driver + } + else if (dbVendor.equalsIgnoreCase("oracle")) { + Class.forName(ORACLE_DRIVER); // load Oracle driver + } + else if (dbVendor.equalsIgnoreCase("jdbc-odbc")) { + // load JdbcOdbcDriver + Class.forName(JDBC_ODBC_BRIDGE_DRIVER); + } + else { + throw new Exception("db vendor not supported"); + } + } + + static void printDriverPropertyInfo(DriverPropertyInfo[] properties) + throws Exception { + // if the driver is poorly implemented, + // a null object may be returned. + if(properties == null) { + return; + } + // list all connection properties. + for (int i = 0; i < properties.length; i++) { + // get the property metadata + String name = properties[i].name; + String[] choices = properties[i].choices; + boolean required = properties[i].required; + String description = properties[i].description; + // printout property metadata + System.out.println("" + name + + " (Required: " + required + ")"); + if(choices == null) { + System.out.println(" No choices."); + } + else { + System.out.print(" Choices are: "); + for(int j = 0; j < choices.length; j++) { + System.out.print(" " + choices[j]); + } + } + System.out.println(" Description: " + description); + } + } + + public static void main(String[] args)throws Exception { + String dbVendor = args[0]; // { "mysql", "oracle", "jdbc-odbc"} + loadDriver(dbVendor); + // start with the least amount of information + // to see the full list of choices; we could also + // enter with a URL and Properties provided by a user. + // mysql URL = "jdbc:mysql://localhost/octopus"; + // oracle URL = "jdbc:oracle:thin:@localhost:1521:caspian"; + // JdbcOdbc URL = "jdbc:odbc:northwind"; + String url = args[1]; // database url + Properties info = new Properties(); + Driver driver = DriverManager.getDriver(url); + System.out.println("driver="+driver); + DriverPropertyInfo[] attributes = + driver.getPropertyInfo(url, info); + System.out.println("attributes="+attributes); + // zero length means a connection attempt can be made + System.out.println("Resolving properties for: " + + driver.getClass().getName()); + printDriverPropertyInfo(attributes); + // you can insert code here to process the array, e.g., + // display all options in a GUI and allow the user to + // pick and then set the attributes in info or URL. + // try the connection + // Connection conn = DriverManager.getConnection(url, info); + // System.out.println("conn="+conn); + System.out.println("----------"); + } +} + diff --git a/sourceMetadata/Chapter06/TestDriverPropertyInfo.class b/sourceMetadata/Chapter06/TestDriverPropertyInfo.class new file mode 100644 index 0000000000000000000000000000000000000000..d866e97e4750344a1d720f7846c120ee9e2752a1 GIT binary patch literal 2837 zcmai0+jA3D9R3b%x|?(hvZXDhMM4EENt@Urpe030%cag#eYNn&TiVIwu7DNx%_VDcfQ~EJK3NA{{A|E zHhdYvR_s^N8^QtHtD-N2ehjD>RB@k*gDQp;468U4LJ0RO7zv?Dnje<)ksyxZm>eEZ z@t}%_r0}?kQ7Jm1!cZ|Lmq`^V6{cLCR57mNlnP75X%%Nwq@~kD2zMf*zz$&(_J@$g zWDq$xDqN|~hcJbQD{&UnD$c2RL?->H%=9to__&HE6g;Wmynxn!bogN3XwOjZ$etkq zz3;R!WyI4)W;{OZ=B&*44uPs}JL9-U#vL)zd6WCWp|0+}J@Za=2YPmQj}FRV_fT)o zzM`fgVP!0Lr$AZr<`IGNZaYQ)6@6C59LP_MnYly8SelYh+BQ->Icv(y3Dh(%PC|Nz z_MA{Ct{u~b~-hd zjQM#fct*oTJS$LP=ZvI`z0P0wRw)mZ*r2ELT?B$MK&#C`pwY=^d{eoP9pEs?|2fm@ zVm;^K6R1m#g{RC+%Fcx|wi|Zx*{q#&&6G@i7u7{4p9H(}RyrkXQ=9M;8qF3^AGHYk zP7TlDc?BEp}pvGZ{ST0_ef+`dC25lD;+QJ&N3YZZ)tcN?2#9HL#AV=r`T)ZLN<&UK56GV!Wurq=Ni6{ z=kG>0d!TjxkHuJ;gaWq|>o+)d+Dy6&M1DyrVj+yQ(>tEAb7r^Uka|nD-Z6G;F<^Jv zaM*te^BZ7Q1vW0#t|blTIq(&!FtS-vPN4OF92QWHjt$=7OSdxHR&tAknWL3}V8V^f z#}+qvfyE3N@W{nNl#qybDzHbOy6}FKz5zVLwdb%~)x0=7l1xe7CR9!>ps9t#$+Ku8dF;p_3 z&SR>v0;{;HK?7=eyE<&ZYP2%@Em*@FHZqM{(M4;Se~2D@4E)5zV@xba&0mq95D-_c zq3Y;WEboizD`s%Z;j+%g$o0>0BhuLZEmjVAlfJDys#i;GwACB+Ro+xnK7*RWQN32~ zJj=R{KvZAtDeD8iY5lx%O-DskZ}61_fYJ2EdF9#;C92;lxAn@8XeryK)~NLgGg%+i z*ZDq5joR+Jh2?ZX6_@|{BdV|WWlf%J8D(8j{WecFgAG@BQNKnP2@|l9fNWyDB3O$aWOLO}`%Pg8Z%D=(pLap=&uUAj-qrBk^TI$PNTE9bU89D+bMlor`A{2~DH1UG_ z9W!X-(hov?eP9+uxP?o73+E#9+MzMIVS;xE{1WBvIQch9uALxE25CRWZ%-4`7{>*E QT)u?Kl8XvLBD-zhzfjxAcmMzZ literal 0 HcmV?d00001 diff --git a/sourceMetadata/Chapter06/TestDriverPropertyInfo.java b/sourceMetadata/Chapter06/TestDriverPropertyInfo.java new file mode 100644 index 0000000..bdd81ca --- /dev/null +++ b/sourceMetadata/Chapter06/TestDriverPropertyInfo.java @@ -0,0 +1,114 @@ +import java.sql.Driver; +import java.sql.Connection; +import java.sql.DriverManager; +import java.util.Properties; +import java.sql.DriverPropertyInfo; + +import jcb.util.DatabaseUtil; + +public class TestDriverPropertyInfo { + public static final String MYSQL_DRIVER = + "com.mysql.jdbc.Driver"; + public static final String ORACLE_DRIVER = + "oracle.jdbc.driver.OracleDriver"; + public static final String JDBC_ODBC_BRIDGE_DRIVER = + "sun.jdbc.odbc.JdbcOdbcDriver"; + + public static void loadDriver(String dbVendor) throws Exception { + if (dbVendor.equalsIgnoreCase("mysql")) { + Class.forName(MYSQL_DRIVER); // load MySQL driver + } + else if (dbVendor.equalsIgnoreCase("oracle")) { + Class.forName(ORACLE_DRIVER); // load Oracle driver + } + else if (dbVendor.equalsIgnoreCase("jdbc-odbc")) { + Class.forName(JDBC_ODBC_BRIDGE_DRIVER); // load JdbcOdbcDriver + } + else { + throw new Exception("db vendor not supported"); + } + } + + public static String getDriverPropertyInfoAsXML + (DriverPropertyInfo[] properties) throws Exception { + + // If the driver is poorly implemented, + // a null object may be returned. + if(properties == null) { + return null; + } + + // List all properties. + StringBuilder buffer = new StringBuilder(); + buffer.append(""); + for(int i = 0; i < properties.length; i++) { + // Get the property metadata + String name = properties[i].name; + boolean required = properties[i].required; + buffer.append(""); + + String value = properties[i].value; + buffer.append(""); + buffer.append(value); + buffer.append(""); + + String description = properties[i].description; + buffer.append(""); + buffer.append(description); + buffer.append(""); + + String[] choices = properties[i].choices; + buffer.append(""); + + if(choices != null) { + for(int j = 0; j < choices.length; j++) { + buffer.append(""); + buffer.append(choices[j]); + buffer.append(""); + } + } + buffer.append(""); + buffer.append(""); + + } + buffer.append(""); + return buffer.toString(); + } + + public static void main(String[] args)throws Exception { + String dbVendor = args[0]; // { "mysql", "oracle" } + loadDriver(dbVendor); + // start with the least amount of information + // to see the full list of choices; we could also + // enter with a URL and Properties provided by a user. + + // mysql URL = "jdbc:mysql://localhost/octopus"; + // oracle URL = "jdbc:oracle:thin:@localhost:1521:caspian"; + // JdbcOdbc URL = "jdbc:odbc:northwind"; + String url = args[1]; // database url + + Properties info = new Properties(); + Driver driver = DriverManager.getDriver(url); + System.out.println("driver="+driver); + DriverPropertyInfo[] attributes = driver.getPropertyInfo(url, info); + System.out.println("attributes="+attributes); + // zero length means a connection attempt can be made + + System.out.println("Resolving properties for: " + + driver.getClass().getName()); + System.out.println(getDriverPropertyInfoAsXML(attributes)); + + // you can insert code here to process the array, e.g., + // display all options in a GUI and allow the user to + // pick and then set the attributes in info or URL. + + // try the connection + // Connection conn = DriverManager.getConnection(url, info); + // System.out.println("conn="+conn); + System.out.println("----------"); + } +} diff --git a/sourceMetadata/Chapter06/TestDriverPropertyInfo_MySQL.class b/sourceMetadata/Chapter06/TestDriverPropertyInfo_MySQL.class new file mode 100644 index 0000000000000000000000000000000000000000..06353101d979adaf741b9eae042f15804bafc513 GIT binary patch literal 3410 zcma)9TW}j!8UEIiyeoN~%OfWOG~+xi-AH(OR-%tG*7?`!y7Zq@IZ%QrabV#12Y*Om}&XWu4Kuv z$zaXwIp@Ef|MLC+u7Cf*uigc)1Mh^8LRvva!I*->A>5B6Av}O_1xFPe3*k5>6r7N8 zQo*SZI`E*3PlT{W=$sboLqSa9Vev2&WEJEDF|WWBq%#Vp6r2@XOTn~)b7EUiP*hM- zU@IsqIIo~0l&T>N!%6|j1QM*(!bB<+~B=ki4)6>R`k*uCCB%6$338DQLa%NdbRe31bMt)z# znlUR9x}u&+!6;27$DN8*ni>|DZl-Nd=KhLZHY?8T!O|IfZ}mhbEnz77VDqAtQp0sO zT5U3nqG8d=?uKqFSKJsHw`-N0d7mXh+ji8fu5$lmW_J8YIw68oF#@Kj$F58zrly@l zv6v{%GVnwrvaQqkY)*G+dNNtCb4KB;U3HRn&auli=D}aFZAZrEReS+2%J`y+z4(%Z zo9&8`E0_tPp2)jtN*s1c4a))7sEjYG_zJ$tdU+ZWHn`b$16xWsUCd`AGiE7oS0W|b ziBxOlvR!e^yog{w*-a%c|M%9cLSEFSJLO$JS+190(qawnQt>ssB;)HUUdAgbzJXUI ztWPy$B9W3&G)MXfkG@ExVxF&A6*E85C$zpPp{r6l1h4872g(| z&Q#v4<|>v881mPolC1<4-@$h!1XH=Qwv{uht_5$;Z7`Kw+J_o@A=8mcHhko%hc?~Z zt_bcmd{4zbk(sDlK`*(wbJi;9_bioB-?3|Ghn_R4Wy>I{Ho8fyIaVQA$E#&lReT>m zknuwmbNCSh_AVR|nfS4cpQv~p`(^x8#n12t{WBcGKU;Im>Im`wfLXN*Gi--Q-D?_* zoUtoS;d>e&-?H(0h_lZ1aj;|DuxD^{$%_@#oPF$ig_^W3s{uUdm~^=Sl0x@ z;p{XUn|_##+Hb(Sv ziQv+-ySj{CX|~)9 zgDnfA1@@c=%%)GIFpTA?Kd?$6J@>Bb)#3gdzfzb*@wW3CV8gO3Hb5>@z-x=U|NmP( zXG9RoUYK3exopyPai8HBS)%qBXN&0af-MldseZ$CisC)C)=kj3W8}^qBz=QofVBHMFvpr*&A*-zYhLTJIp0#Z(M3buytapz zZo)={x!a5gwqQGY`RTM3Lp-&*!D;HbAw5RjAZ@%K`yB$(C2n41nqOj#U*!vHj#_Wv02Xl&S9$&o z()a^1_#^N6Grv;*iX+R4a)5F!M5P55MHKc!DIN0-Wr%=}NMo8$_iMN5fq^$PX)vxPu01ZV|iEEgHKi7H>7BeUx&9`kjm*Lx1-87omG+ zRS$|yI7poPiPHD*K3hku*91=SPj|hBf4i&Kyk0qvQEGzaJi+9hX8S$F2ApI+Jj}8h z?0_t8L5`)(BMFlQp5lC%X0guU5DKIeaULZ+$LH%T>^uwmYdnfS@xP4sa1npQCEorx g{*EW`4?IafF5+LLUE}&6t{>oOmha>Au?>g*3+aV)bpQYW literal 0 HcmV?d00001 diff --git a/sourceMetadata/Chapter06/TestDriverPropertyInfo_MySQL.java b/sourceMetadata/Chapter06/TestDriverPropertyInfo_MySQL.java new file mode 100644 index 0000000..dc0cf8a --- /dev/null +++ b/sourceMetadata/Chapter06/TestDriverPropertyInfo_MySQL.java @@ -0,0 +1,135 @@ +import java.sql.Driver; +import java.sql.Connection; +import java.sql.DriverManager; +import java.util.Properties; +import java.sql.DriverPropertyInfo; + +import jcb.util.DatabaseUtil; + +public class TestDriverPropertyInfo_MySQL { + + public static Connection getConnection() throws Exception { + String driver = "org.gjt.mm.mysql.Driver"; + String url = "jdbc:mysql://localhost/octopus"; + String username = "root"; + String password = "root"; + Class.forName(driver); // load MySQL driver + return DriverManager.getConnection(url, username, password); + } + + public static void loadDriver(String dbVendor) throws Exception { + String mysqlDriver = "org.gjt.mm.mysql.Driver"; + String oracleDriver = "oracle.jdbc.driver.OracleDriver"; + if (dbVendor.equalsIgnoreCase("mysql")) { + Class.forName(mysqlDriver); // load MySQL driver + } + else if (dbVendor.equalsIgnoreCase("oracle")) { + Class.forName(oracleDriver); // load Oracle driver + } + else { + throw new Exception("db vendor not supported"); + } + } + + public static String getDriverPropertyInfoAsXML + (DriverPropertyInfo[] properties) throws Exception { + + // If the driver is poorly implemented, + // a null object may be returned. + if(properties == null) { + return null; + } + + // List all properties. + StringBuilder buffer = new StringBuilder(); + buffer.append(""); + for(int i = 0; i < properties.length; i++) { + // Get the property metadata + String name = properties[i].name; + boolean required = properties[i].required; + buffer.append(""); + + String value = properties[i].value; + buffer.append(""); + buffer.append(value); + buffer.append(""); + + String description = properties[i].description; + buffer.append(""); + buffer.append(description); + buffer.append(""); + + String[] choices = properties[i].choices; + buffer.append(""); + + if(choices != null) { + for(int j = 0; j < choices.length; j++) { + buffer.append(""); + buffer.append(choices[j]); + buffer.append(""); + } + } + buffer.append(""); + buffer.append(""); + + } + buffer.append(""); + return buffer.toString(); + } + + public static void main(String[] args) { + Connection conn = null; + try { + String dbVendor = args[0]; // { "mysql", "oracle" } + loadDriver(dbVendor); + // start with the least amount of information + // to see the full list of choices + // we could also enter with a URL and Properties + // provided by a user. + String url = null; + String mysqlURL = "jdbc:mysql://localhost/octopus"; + String oracleURL = "jdbc:oracle:thin:@localhost:1521:caspian"; + if (dbVendor.equalsIgnoreCase("mysql")) { + url = mysqlURL; + } + else if (dbVendor.equalsIgnoreCase("oracle")) { + url = oracleURL; + } + else { + throw new Exception("db vendor not supported"); + } + + Properties info = new Properties(); + Driver driver = DriverManager.getDriver(url); + System.out.println("driver="+driver); + DriverPropertyInfo[] attributes = driver.getPropertyInfo(url, info); + System.out.println("attributes="+attributes); + // zero length means a connection attempt can be made + + System.out.println("Resolving properties for: " + + driver.getClass().getName()); + System.out.println(getDriverPropertyInfoAsXML(attributes)); + + // you can insert code here to process the array, e.g., + // display all options in a GUI and allow the user to + // pick and then set the attributes in info or URL. + + // try the connection + conn = DriverManager.getConnection(url, info); + System.out.println("conn="+conn); + System.out.println("----------"); + } + catch(Exception e){ + e.printStackTrace(); + System.exit(1); + } + finally { + DatabaseUtil.close(conn); + } + } + +} diff --git a/sourceMetadata/Chapter07/AgeFilter.class b/sourceMetadata/Chapter07/AgeFilter.class new file mode 100644 index 0000000000000000000000000000000000000000..a515c0ea956d6fe0f7c61689a0a1ee2e1e01fd82 GIT binary patch literal 1201 zcmbVMO-~b16g{t?S@0@$ieVHFWzkCHSkAi^?j3&{JF%@pAFs{Nx z0+R;UtbrU%9a9F9nAS1VhBnOV$m^KXF|T7mAYQ8-tUHj0^*KD_%-|`xcTP+agp5r=RQJ^ntS=Qx>+_r$WTCeba$A;s| z&E{T7HeT4J8Z&WqM^z-`pThc42ys=epHp+6{QQYm6%P&thW|gcIuHjY+T}Y?UtwIlaQ@Dz>K-8{Eb=;?8 zF@@V$66k6#yxFayE4g%sv{pdh?`G7-Kf<98Xixqb0-&gHzJ=<72F3VS* zQ+EZDf0`2LY;goO2n<|8f7*~0r|cUS%_=7^+zPB>O71u9+JRMd>kYYTA5eVg&|kAu z4kaAd+vX%#LO4E*cvX5-$Qfp>oP`lSt_~0q8Y0RpzQ>62%U|i1ztTFcG1k#E#(wVB zSr_9vV4g#mgQtj?nNvi~e(e;RIdqEHN1jrmszIFb3OU;OemfXDIf*XfqNRFf){npF?k97~}(om}D;k84QJYWZ1{NR-86JK|4d@4aTRwA$bO4N$b&=jJ!ja z{}FwUgjW23ShP5FLb#y4Q6%`?PoM!dIY@#GvLrBZ9W%IrJjQ&=>mg++q@2}?1dnCj z{uf`CC^;Bp>BbbsF^x&GnPi*Bg3mV`^1TlEmZrY5^Al=odmQ!E#y%qzK}%)(Z= this.lowAge) && (columnValue <= this.highAge)) { + evaluation = true; + } + else { + evaluation = false; + } + } + return evaluation; + } + + + public boolean evaluate(Object value, int columnNumber) { + boolean evaluation = true; + if (columnIndex == columnNumber) { + int columnValue = ((Integer)value).intValue(); + if ((columnValue >= this.lowAge) && (columnValue <= this.highAge)) { + evaluation = true; + } + else { + evaluation = false; + } + } + return evaluation; + } + + public boolean evaluate(RowSet rs) { + if (rs == null) { + return false; + } + + FilteredRowSet frs = (FilteredRowSet) rs; + boolean evaluation = false; + try { + int columnValue = frs.getInt(this.columnIndex); + if ((columnValue >= this.lowAge) && (columnValue <= this.highAge)) { + evaluation = true; + } + //System.out.println("3-evaluate: columnValue="+columnValue+" columnName="+columnName+" = "+evaluation); + } + catch (SQLException e) { + return false; + } + return evaluation; + } +} \ No newline at end of file diff --git a/sourceMetadata/Chapter07/CreateCustomRowSetMetaData.class b/sourceMetadata/Chapter07/CreateCustomRowSetMetaData.class new file mode 100644 index 0000000000000000000000000000000000000000..1b7ccb8c9d1e3c8c8e9ee578709f69215d6e34e9 GIT binary patch literal 1587 zcmZ`(TW=dh6#m9uUt(`!6lihM0NGq{6T48mfzkpRuSf0%d)Mrx zNl_(`A|8<7ckoJIXiOz|=SLyV>?U;$bS=%f&dhhdb3A|j{revPmhe>yc@$H)fKmci zQi!6MMi~ooSxiEc@~tG6q+CwoY7%d!@DARU_BFX&PvJdO5?D#$6|5$3BZWzM#v0yF z;sYr^l*@V&dJ-E_-ArIBfo+EPs%e?t8bh>D++$F5yDbG!s8p<;|v!H#UTGsbHC|oqtO+H z)aIcf`krZ9E*TBmcMP#*%KPT@;5^-TJ-au$Z&3nJ@haw2ypA_0*RXq<>sy**AGpHP zbZ$Hl?Qm1I*Y76qk%}sAs@TCCm9j*iie1!5=Us8Aq8|8{=_A)Zw?qQBRD6t2RNR)= zG|)`oj*2}r877AWJcqC1Q+dQC847DX!7>UxMDv-7yZD?TVzyP>Lrukfd_fmmyhoMC zzV(FbsrXXjn|(PA4A~)&TdjRzcntaf0C`uP$^5)29PYWeZ?v>_OWPC9qjm0@hHhIHp{1_ZxWzldVHocSZ|G(y zhR8<8EWAn%(lC{VC>x^Gea8`22y>hpa<23TG^K(@Yx?B4f9;huo{{K$&+KY)Vq4r5 zcgUbN7+u??c4YcA<6gt##@9`U8|0ZDay;5yh6$oqx4VAN(rw?Oekg^iykz{jzaI2> zXg44AWzP%MAWx;d;14I$aFJewJiQR07lFxnr*)pJJV{0}R(cBdgcL@pKs<1!F^1Q0 ziS&62EYQ{j#eObDmv>o>)mcS3Mx>%VL-g)bD7Es8GC(YX@&Iv$vXV;-kc^@n%Z-J~ z04egHM$@NJ^@Zq_V~p1+Wr7kH2FOIPaE$CPn61QSV!t65T52UOm6`aTPoN+T3qHM8 zQXUaNACCihgdYMKmSo{P#U>~}L*-?W40cSBb`I0@o5w6JQ;tSVT_;}Fh@%bi)`*Zj zqTxP@;8;Y5o=XcWaIi`@UBdxoKPLNovX4mqNb)D#p!4ZLK}1rA?*i6=?Pr)Is-|{I zu>sCRP*QSd2RIicB}*(!lM>6#gr3-`N6F0&a6Sl~D8JH?VNsW literal 0 HcmV?d00001 diff --git a/sourceMetadata/Chapter07/CreateCustomRowSetMetaData.java b/sourceMetadata/Chapter07/CreateCustomRowSetMetaData.java new file mode 100644 index 0000000..69b7a95 --- /dev/null +++ b/sourceMetadata/Chapter07/CreateCustomRowSetMetaData.java @@ -0,0 +1,79 @@ +import java.sql.Types; +import java.sql.Connection; +import javax.sql.RowSetMetaData; +import javax.sql.rowset.RowSetMetaDataImpl; +import javax.sql.rowset.CachedRowSet; +import com.sun.rowset.CachedRowSetImpl; + +import jcb.util.DatabaseUtil; +import jcb.db.VeryBasicConnectionManager; + +public class CreateCustomRowSetMetaData { + + public static void main(String[] args) { + String dbVendor = args[0]; // {"mysql", "oracle", "odbc"} + CachedRowSet crs = null; + Connection conn = null; + RowSetMetaData rsMD = null; + try { + // create a custom made RowSetMetaData object + rsMD = createRowSetMetaData(); + + // use a custom made RowSetMetaData object for CachedRowSet object + crs = new CachedRowSetImpl(); + crs.setMetaData(rsMD); + + crs.moveToInsertRow(); + crs.updateString(1, "1111"); + crs.updateString(2, "alex"); + crs.insertRow(); + + crs.moveToInsertRow(); + crs.updateString(1, "2222"); + crs.updateString(2, "jane"); + crs.insertRow(); + + // + // if you want to commit changes from a CachedRowSet + // object to your desired datasource, then you must + // create a Connection object. + // + conn = VeryBasicConnectionManager.getConnection(dbVendor); + + // moves the cursor to the remembered cursor position, usually + // the current row. This method has no effect if the cursor is + // not on the insert row. + crs.moveToCurrentRow(); + + // when the method acceptChanges() is executed, the CachedRowSet + // object's writer, a RowSetWriterImpl object, is called behind the + // scenes to write the changes made to the rowset to the underlying + // data source. The writer is implemented to make a connection to + // the data source and write updates to it. + crs.acceptChanges(conn); + } + catch (Exception e) { + e.printStackTrace(); + } + finally { + DatabaseUtil.close(conn); + } + } + + static RowSetMetaData createRowSetMetaData() + throws Exception { + // create a custom made RowSetMetaData object + RowSetMetaData rsMD = new RowSetMetaDataImpl(); + rsMD.setColumnCount(2); + rsMD.setColumnName(1, "id"); + rsMD.setColumnType(1, Types.VARCHAR); + rsMD.setColumnName(2, "name"); + rsMD.setColumnType(2, Types.VARCHAR); + // sets the designated column's table name, if any, to the given String. + rsMD.setTableName(1, "ztest"); + rsMD.setTableName(2, "ztest"); + return rsMD; + } +} + + diff --git a/sourceMetadata/Chapter07/CreateRowSetMetaData.class b/sourceMetadata/Chapter07/CreateRowSetMetaData.class new file mode 100644 index 0000000000000000000000000000000000000000..bbc459f384c95a984e5d41c50eb3a0203ea93c5f GIT binary patch literal 1779 zcmZ`)-%}e^6#gzGYzPaq&;UWeAc!GAwk=vUKve=%G=Y{-YN@|A$(0Fic4Kz8rJZ4X z>5DTRU!2iDp|92lT4Y9jbH+c)@w*9-Q0ZiH&;4=Ex#xW6J9q#2_xC>lTtP965hOHB zh0%gU7}JR7|Nz<{!=2T{NJ#G!_pI&NV@p#SAG z7yXh|lvROX)y*y~=*VGH4Yze{;f{vSblk`m+iFU+g{D*7aG3Q@fE%n=xu~>3X2X?B|CP@m(_;^KUO3RdDE4#Z+NFy zH4ER?wvx#t9psiX%jwNnBDS)zo{c^7q|3^*6Z@L^g1}J0DI2bD|F0IS<%*>vk8K?V z70ZQ2EbIAQ7E@q!w~#lAd1H%_ESheq&?s}(w9OrbRp*ZM8ruSs$E-L*pL2;KFxV*4 z%S;jIpyQLG35>++ysFV^L%P1@k%TAbnJeu>WG_?I3@=T&*;~oIwpN{&ouNyo>OllGWaBmCdc$xr@`3>1+kqS(`Kp+)}23{bzHgkwJfxn=og1;ej zgm$WhdpZuFM}r6GJV4h0x}(9r(Z%DQ3tT+KL^ODaivri$noN3V5@|a?@39HJUwVq6 zR8aZpQGF@PJ0Vx8~z28Q@>4AbX09`RAzCwku#lE+;C!1WW#pD2IE1OeisN30dL z76EIeoL8ClGt-`dOjCkUCOE}^J-;Ii5~* literal 0 HcmV?d00001 diff --git a/sourceMetadata/Chapter07/CreateRowSetMetaData.java b/sourceMetadata/Chapter07/CreateRowSetMetaData.java new file mode 100644 index 0000000..4b88527 --- /dev/null +++ b/sourceMetadata/Chapter07/CreateRowSetMetaData.java @@ -0,0 +1,53 @@ +import java.sql.Connection; +import javax.sql.RowSetMetaData; +import javax.sql.rowset.WebRowSet; +import com.sun.rowset.WebRowSetImpl; + +import jcb.util.DatabaseUtil; +import jcb.db.VeryBasicConnectionManager; + +public class CreateRowSetMetaData { + + public static void main(String[] args) { + String dbVendor = args[0]; // {"mysql", "oracle", "odbc"} + CreateRowSetMetaData wrse = new CreateRowSetMetaData(); + WebRowSet webRS=null; + Connection conn = null; + try { + // create and populate a row set object + conn = VeryBasicConnectionManager.getConnection(dbVendor); + webRS = populateRowSet(conn); + + // create RowSetMetaData object + RowSetMetaData rsMD = (RowSetMetaData) webRS.getMetaData(); + System.out.println("rsMD="+rsMD); + if (rsMD == null) { + System.out.println("vendor does not support RowSetMetaData"); + } + else { + int columnCount = rsMD.getColumnCount(); + System.out.println("columnCount="+columnCount); + } + } + catch (Exception e) { + e.printStackTrace(); + } + finally { + DatabaseUtil.close(conn); + } + } + + static WebRowSet populateRowSet(Connection conn) + throws Exception { + System.out.println("Querying database for track data..."); + String sqlQuery = "SELECT * FROM ztest"; + System.out.println("sqlQuery="+sqlQuery); + + WebRowSet webRS = new WebRowSetImpl(); + webRS.setCommand(sqlQuery); + webRS.execute(conn); + return webRS; + } +} + + diff --git a/sourceMetadata/Chapter07/CustomRowSetReader.class b/sourceMetadata/Chapter07/CustomRowSetReader.class new file mode 100644 index 0000000000000000000000000000000000000000..949c66ccbccc72cb27a65acb70ac71b3d5192293 GIT binary patch literal 2261 zcma)7+jA3D82_C%?QWCp#Xw7i0)bLUFKKM+jTR6HpwYHKQ>uWX+vHHTZg#_F(~EcU ze&NX{$5&^3ah%Z^i;)?}86O;d@xdn_^$$^hC)>2?MTeJjzVn^$`uo1~onQa{{s#a< zxE;m-Mw>8(V>*t9aRQI&IH}{5hSM5SVdxl*;0(^H<(!Vk)&7Kzw2mhu(D0OwakWqA zm{j|DwOr6~QSDPYGCHPpT+%V47*DI^nK1fsS;v(KuHsn@&xLV7Ik}2!ih5qh3u-qN zXI4j6?K#Df8m?=Y({Mwe@tEaU{t1Elc<+orDCOp)K)1-=Pc!KSE^L>-F%=kMc>jJR9+1XBB^2Cz>Ba2Vq3*VV_ACky;9b9y+I9m z0}fn)gNa09Tk%;rXE}p0UJG<@YtOW8>BX#K%qiLSAQ4#4-*Xp>(od$$>4uL_^fLW87N^PpofEP#K0n!1O~Q^%PS7jdDUt><`wg~ zSnrsDWh4b68Q-&o5u*MKi z_he((z^h0acug%2;}L<*?OaPI$I88K;0?UVUQlo*ZPS@c1}U8`SvDKOz%9IG;BCCa z_KhWCihS3=dw5?!j2id=9~$@w9}7gcIuU4FH+z0|USh*Ry{Em1!2(|{{iqA+*b8Y+V zt1(ohTl4OMoOaXIju9|Qg`DZjpk@M1!I86q^jc#P!$2`r@;vFNUSns?%ImJjQQ#FR zTq#uTxM7NpT;dIf))mgMIT@(&nC8(e6xculUBqEaW~;r!QY3;ov=Qq6k#C}#YA%QG zNtaGkY?X{xr`|?yj8^yEs?nYCt>KPwUib5BVYvKf>bZ0NaeaWN1nNiu&3$(uzCm5I zeg&bg$q@XIfEJ2_|4s-^Fc2np7$a1ns#xG%h_`X;$P=@cL;ej%uoMoZt zjxu)EW1t~aMmzV$Xh*;(W0$B%cPi;n^!`=3hN|4|O>%nzt6j8O#$K-9VP8NgpZirZ zYk1s3jC3;*X(1l1*oii@V+VGl0|(KGUQ)x@gHd!Lg?$*ueq5r?HQq{eBaa@=>LZ+( zaSobZ+(sWhVR1fVAwFkWzGPv(CAxQs{!c{u7d(jH@DP6Ip!)-l;!hkU2gF^FtE=%B zRD-iw@qn4WGGYRs;yk0jivz^}AX(i4D>xMGS;65x1@)0So)1Ukl`|3VRp&#iX96GG jub_|VfAP;(>j*?EH9y9FIF2ctWOk=&A`*-djOggUGjl55 literal 0 HcmV?d00001 diff --git a/sourceMetadata/Chapter07/CustomRowSetReader.java b/sourceMetadata/Chapter07/CustomRowSetReader.java new file mode 100644 index 0000000..54ad8e1 --- /dev/null +++ b/sourceMetadata/Chapter07/CustomRowSetReader.java @@ -0,0 +1,67 @@ +import java.sql.*; +import javax.sql.*; +import javax.sql.rowset.*; +import com.sun.rowset.*; + +public class CustomRowSetReader implements RowSetReader { + + public CustomRowSetReader() { + System.out.println("CustomRowSetReader: constructor."); + } + + public void readData(RowSetInternal caller) throws SQLException { + System.out.println("--- CustomRowSetReader: begin. ---"); + if (caller == null) { + System.out.println("CustomRowSetReader: caller is null."); + return; + } + + CachedRowSet crs = (CachedRowSet) caller; + //CachedRowSet crs = (CachedRowSet) caller.getOriginal(); + + RowSetMetaData rsmd = new RowSetMetaDataImpl(); + + rsmd.setColumnCount(3); + + rsmd.setColumnType(1, Types.VARCHAR); + rsmd.setColumnType(2, Types.INTEGER); + rsmd.setColumnType(3, Types.VARCHAR); + + rsmd.setColumnName(1, "col1"); + rsmd.setColumnName(2, "col2"); + rsmd.setColumnName(3, "col3"); + + crs.setMetaData( rsmd ); + System.out.println("CustomRowSetReader: crs.setMetaData( rsmd );"); + + crs.moveToInsertRow(); + + crs.updateString( 1, "StringCol11" ); + crs.updateInt( 2, 1 ); + crs.updateString( 3, "StringCol31" ); + crs.insertRow(); + System.out.println("CustomRowSetReader: crs.insertRow() 1"); + + crs.updateString( 1, "StringCol12" ); + crs.updateInt( 2, 2 ); + crs.updateString( 3, "StringCol32" ); + crs.insertRow(); + System.out.println("CustomRowSetReader: crs.insertRow() 2"); + + crs.moveToCurrentRow(); + crs.beforeFirst(); + displayRowSet(crs); + crs.beforeFirst(); + //crs.acceptChanges(); + System.out.println("CustomRowSetReader: end."); + } // end readData + + static void displayRowSet(RowSet rs) throws SQLException { + while (rs.next()) { + System.out.println(rs.getRow() + " - " + + rs.getString("col1") + ":" + + rs.getInt("col2") + ":" + rs.getString("col3")); + } + } + +} diff --git a/sourceMetadata/Chapter07/CustomRowSetWriter.class b/sourceMetadata/Chapter07/CustomRowSetWriter.class new file mode 100644 index 0000000000000000000000000000000000000000..a1b993c0c40bd0cdf43906c82be2cc1fba767896 GIT binary patch literal 722 zcmZvaO>Yx15QbkTOLh}BX-S$CS_0dakAx~&aV3aL0I5>=TvQ}(&ejU9Hs0d(lJcK= zfdfb!5H}=#6k?o}C{=r~J>!}8kv%iN|9t-e;68daRMD=YgLMyAYq*9D51SsYyXd;O z;o_!?fT8kGDrp`ulzaVs24|ce2!@r3RN{F)p9=kkPZPSSF0?e_F*lr{+nXHnkNh~y zJ|yAmbP)-&r;N~wC!_v5hT4tFE^hm{gS!mdgTdg!^r@IhH4G@suyY}gCyCI3%mS4s z$&h|_`Y)X>GGW3okKc=f;;QwJT(oPj-L8ede4{LV?;qh3q=P8iZQG8i6`!VH0g!p@>6yOaK2w-oBe(dMdfgn1=P!JDc6S_+A6uLv`!9fMRVI0C?rW^^=-P3$J zs^C}<$HSPzkUH;uOi%DB$%|Cb&y)dP1{D~*pWx-Bf|P48uzXyGp!d0 z8>Z_^tP>Dz0wr4w({LXrwKc1{1p+NrQVPtB8K!K{ru(GbrT3+XQkpcJOiCZ!p}RW4 z>>NqRjB8jXnHoszhAB{9b9kx+j2VtwSvw(H4aO zlVbeWRct|15O1h>6U{-qrQ&T|6qwg4-NYb8QtP*^w3f4~zCMU|R9wP&74PD*ik)ay z@g6RdK#$Z0^&zR*(#weE4oXd$NxJdOEXY7})<}^f0wGGOMtR(#sdyhBsQ3_9_;gjp zN4O?1ce|O?Olw%{(-S9$bvx1utl-?F7=w0Fs7k*d!a0mc2l5?Zywp^0lJk3l8F!9Q7H67aWzZa81S6xS?Vzr}Z1Qq-;WoYlfql z*;I$)zzQ^)!tkzker^2{6M+y8MZuH^$zFV;+DBs?W!%OS(c(!`r? zIL%%cwffyPE!Sm1!^u$sevgzGj_<`x&(*j~-Q8vD35sE{v}rDc$;f@uar6Nqh3Llv zBg!6TE?E&A)}3~*3E00jlcE+N);27m2V^rnnF0EzIY%qFlf0ek-P@@_XfKA~aZ76p zP_&XHiU4t@_6|g(=qD84N1*o(rp4-Rp(Ii?hG0+aeJH(kcM!UbaP5x>-$kjwEvS*{ zW0>I+W(r)P%Q4Kl@$X+gX*QX59jloyLVUE}#~ebQ8z~z@xz96CUS+%6-RgQYr$XTlCVmgTM|-(Ir&VI+s#Yju7TyHY%_Hl~{@SSc`>d z#3JHbjNPchUP}EzEX8pw!&ySOfEs$IR#B*GaSf|!lCHrIBz2FzrhdaZ{DF=5lZxeU zG>T$0iRsuXDrq1tq3PL7uW&nBL^t-3HM_(i>=sASCQc(pmeCVPr9wp`D!d{Bey!y& z2JWJ+2)D7?kLenY8mBu_?**W$AoEc_^Q-f|djQk!Vl4wSOa@pt1z^1o(2%bh51=Gx z!G_5I8>av~<^ycVTX2&i?MJ;Cv*>&PGtfzKj#Es#upHggEWPO9uSxn#;0XG06z8Dh zBKj!833||yxIxrkV4#%{0))4M^0tfe<24zf6mgRwbRV0j0~%xFO2ghoioRjf#N0+q HMcDHnlGnZN literal 0 HcmV?d00001 diff --git a/sourceMetadata/Chapter07/DemoCustomRowSet.java b/sourceMetadata/Chapter07/DemoCustomRowSet.java new file mode 100644 index 0000000..c14a07f --- /dev/null +++ b/sourceMetadata/Chapter07/DemoCustomRowSet.java @@ -0,0 +1,111 @@ +import java.util.Hashtable; +import java.sql.Types; +import java.sql.SQLException; +import javax.sql.RowSetReader; +import javax.sql.RowSetInternal; +import javax.sql.RowSetMetaData; +import javax.sql.rowset.RowSetMetaDataImpl; +import javax.sql.rowset.CachedRowSet; +import com.sun.rowset.CachedRowSetImpl; +import javax.sql.rowset.spi.SyncFactory; + +public class DemoCustomRowSet { + + CachedRowSet crs; + String stringColumn1; + String stringColumn3; + int intColumn2; + + + public DemoCustomRowSet() { + try { + SyncFactory.registerProvider("MySyncProvider"); + Hashtable env = new Hashtable(); + env.put(SyncFactory.ROWSET_SYNC_PROVIDER, "MySyncProvider"); + crs = new CachedRowSetImpl(env); + crs.execute(); // load data from custom RowSetReader + + System.out.println("Fetching from RowSet..."); + while(crs.next()) { + displayData(); + } + + if(crs.isAfterLast() == true) { + System.out.println("We have reached the end"); + System.out.println("crs row: " + crs.getRow()); + } + + System.out.println("And now backwards..."); + + while(crs.previous()) { + displayData(); + } // end while previous + + if(crs.isBeforeFirst()) { + System.out.println("We have reached the start"); + } + + crs.first(); + if(crs.isFirst()) { + System.out.println("We have moved to first"); + } + + System.out.println("crs row: " + crs.getRow()); + + if(!crs.isBeforeFirst()) { + System.out.println("We aren't before the first row."); + } + + crs.last(); + if(crs.isLast()) { + System.out.println("...and now we have moved to the last"); + } + + System.out.println("crs row: " + crs.getRow()); + + if(!crs.isAfterLast()) { + System.out.println("we aren't after the last."); + } + + } // end try + catch (SQLException e) { + e.printStackTrace(); + System.err.println("SQLException: " + e.getMessage()); + } + + } // end constructor + + + + public void displayData() throws SQLException { + stringColumn1 = crs.getString(1); + if(crs.wasNull()) { + System.out.println("stringColumn1 is null"); + } + else { + System.out.println("stringColumn1: " + stringColumn1); + } + + intColumn2 = crs.getInt(2); + if (crs.wasNull()) { + System.out.println("intColumn2 is null"); + } + else { + System.out.println("intColumn2: " + intColumn2); + } + + stringColumn3 = crs.getString(3); + if(crs.wasNull()) { + System.out.println("stringColumn3 is null"); + } + else { + System.out.println("stringColumn3: " + stringColumn3); + } + + } // end displayData + + public static void main(String args[]) { + DemoCustomRowSet test = new DemoCustomRowSet(); + } + +} // end class DemoCustomRowSet diff --git a/sourceMetadata/Chapter07/DemoFilteredRowSet.class b/sourceMetadata/Chapter07/DemoFilteredRowSet.class new file mode 100644 index 0000000000000000000000000000000000000000..59be41eb3ee02f9e74932f25e93dff9a3316d10b GIT binary patch literal 2491 zcma)8M{pZu6#jlUt>krVlpazx6}d@icCej-Bio6BTw>WNPAF^Xx4n+EtE^Top@tGV zq4$|fdEQ)f3O@e9OB__1#zA`6?F03%|nkLhtaDb5kMdM18Bq%AC3kP z#4$cT&clF$6ADi9@*V~E@_e6y`+3%R7~~Itaz$ix= z86V65suAUl#jC7>(>&V>a!hm-Rqz_QSZ_^3XnN7A}E97#B~VGg&jU`5KvWz+g(uQi^K zj=<88%Qq3polZwQqRSU(pGeBAV_0TRAds-~c2ag2Y+-qu%viK^q%BjPM3_yfxD!pJ zFllANnMqO?9!(7-PCT$-cRPhiV7FbW`kzC%4*w%PXI+2B%Vwr53g0L;i@!=5_ zkK(L~$8c6)Eo*Cb6*osBX)CFxN35I^v67CJ&F54+&RiQ4?eX?#pJt@$G*i#WI!zyz zT1RhprzT0YH7O;rKEYa_M3WEaR6K>J1yo5aB(R0AhsdyeuDqg^g0xMX_Y&`Q-P}F?XXHRO5r5R>U+Ky(*am|)V%TDFkjEeIN zUvX0tse1`83zW8+DO;*|1+S`jjjg=S!y7K!w(UCzr$cgRh#+?}%?V5#j^D_eK$wlT z+qPwEL-hCTQX$Nk)y55Hgz?$a*x-5aCaXR$8-a&`rVml9nqyD0kBDnpnlRD5WP9xE?IJg5slBQF8n;O5?S`vI2ZXaA$>Qe*poW z%L`CxE}%l-ODqajPNS;!3U0fK;PI-Cs#Mu!EbgS^B?7f|1uQLcxt7gvvBYv-7qEgD zN`fm3SXGSL(%|jhqO5A5fYn4PU=1-8u+|;dxuYkd&5Ep_6>0q!kttMlvBiyKv3?qx zJhzy#dB&e9DDm29+;Is-xPTw=6Fuj^ANZ5rau2kN2oWVn;4Q@>ETi9Yti=jCUx_eQ zVJGc&V;%0oCUg>Sg5L50)L{@24ACcxNgNIu=t*qEIm*^~$`f^WYJJUQaWAH@4_}aU z0j>B3`|%y3_yKL?ON_kfz|S~Yf~Fl7=BI&ENr$wq1<&cF{MtX zjt?-cPBR)F>*&CTF?@t4?f5u`r+B6zqoWha7-li2mQR$!yjq@j;8T3oju$$zSZK$h zh9wBtTF9UOn8ty@QISI%)|pz7~4HPhL;C+k=^eWd7?`2*CD;U+VYG4iP0%OI+ z++ubk?v&GU*Q&~N+}e}zrS+A3TviV%-m#RvhN6KDyd?i~Ue65yO8g>nQgKr7E;Kj>UV8ws%>TX%XcLu)4wm`R?*$tR&mw$iis9GTf4djkz zDn_;xO*KUUV_PWEwz>r7Mt_O0h&O!we|6jto^y`%%?Dt_s+U?W82IO>P zy=v8R%dGXbpzL(5nOk7sT8m%hP}6W-a|yfA``0e5c#wDc+3 zUqjDChoYy@Pw3jogkua82A^VJpo_t~8U8M{z5LzdE7nh-1GF8X^$^A}j3gycv(3bD zo=#X)8}~J#(q14YQ0Or-(aE9c1@1(UPrgAXQFXDL1q|ebqkiDL zOktVlJkP7tKBBi`zJoj8rDh>pETlzA6tur!{DONueW&O@=@}rggFC4+4CR$BeSzT! k>wbGR51{cp&2@$_9+Sf-WbY|?dd5_lYw0*1w2WZlU#Vq#%m4rY literal 0 HcmV?d00001 diff --git a/sourceMetadata/Chapter07/DemoWebRowSet.java b/sourceMetadata/Chapter07/DemoWebRowSet.java new file mode 100644 index 0000000..bca852a --- /dev/null +++ b/sourceMetadata/Chapter07/DemoWebRowSet.java @@ -0,0 +1,64 @@ +import java.io.*; +import java.sql.*; +import javax.sql.*; + +import javax.sql.rowset.WebRowSet; +import com.sun.rowset.WebRowSetImpl; + +import jcb.util.DatabaseUtil; +import jcb.db.VeryBasicConnectionManager; + +public class DemoWebRowSet { + WebRowSet webRS = null; + + public static void main(String[] args) { + String dbVendor = args[0]; // {"mysql", "oracle", "odbc"} + DemoWebRowSet demo = new DemoWebRowSet(); + Connection conn = null; + try { + conn = VeryBasicConnectionManager.getConnection(dbVendor); + demo.populateRowSet(conn); + // note that WebRowSet is a "disconnected" object + DatabaseUtil.close(conn); + demo.writeXML(); + } + catch (Exception e) { + e.printStackTrace(); + } + } + + void populateRowSet(Connection conn) throws Exception { + ResultSet rs = null; + Statement stmt = null; + try { + stmt = conn.createStatement(); + String query = "SELECT id, name, age FROM employees"; + rs = stmt.executeQuery(query); + + webRS = new WebRowSetImpl(); + webRS.setCommand(query); + webRS.execute(conn); + } + finally { + DatabaseUtil.close(rs); + DatabaseUtil.close(stmt); + } + } + + void writeXML() throws Exception { + if (webRS == null) { + System.out.println("No data found"); + return; + } + + String filename = "c:\\temp\\emps.xml"; // Windows + // String filename = "/home/alex/myrowset/emps.xml"; // UNIX + java.io.FileWriter writer = new java.io.FileWriter(filename); + webRS.writeXml(writer); + } +} + + + +// webrowset example: +//http://www-128.ibm.com/developerworks/db2/library/techarticle/dm-0503bhogal/ \ No newline at end of file diff --git a/sourceMetadata/Chapter07/ExampleListener.class b/sourceMetadata/Chapter07/ExampleListener.class new file mode 100644 index 0000000000000000000000000000000000000000..cd4b95f67e88fd5a1e030b7ec1ff542a64163717 GIT binary patch literal 859 zcmah{O-~y!5PeQUyeyjp64FvAbSWQA_~@$Yk*XI2r$DO)^}b0AHQLy8;{^CwZ~%z| zKcGLV>Ug&_B|~~utJ_=hAolLd+aZkqwdLTLs^R>olI0!F- z-p?rbrq7$g>62qoh8 zR@B23JdU>>R*30e(9KJlLzleJed1J;83$4aUt_6E)5Id| z?l4pm`Nzi${LF$PMZDCUv;ksCb&~i}9ql2pjKMKFMUf%3dRjDT{x28HaOgFWvGlZZ zl*u281==lAW|Sv3Zo#f-!BC`_PYx}#glUQv`VkrWfXX#8Cc<`|D%+{l9pD}8PjovCCVCdFf`;L6#S@R2R||N)v@>~U8tCayeLyu%>1kd6T2E- zfLs@0DX=w^@SGuJ@uHYzXie0A3>WLh)^fX)c7{k@lqzt?S+(6oyJF=}183;*RAjNT z4>M=vqq{~<&*$_lQQlwRj%n0uxxy{JBSBu+5pG?~Fjg!5xgPmwH%Px^zv7w&{XTbj zjyvKJZ74RQU^`U&9^aPVz_qTG{nlQh)^oEiH(qR(xj~vkGJ;PuI)g%;zqwzMog7_~ z22>KH>|&8y`BN_qU9E^cVN_hY)xq<5-~CA;sZScQog8|79<;AuE&}tGsg&QAE0T4t&SfexEfDX5sFvQ9RD54A;O76w7fxdDmW0VqV=4x zYbtbRKM?x+EkSC-Fk&=oZ4kwSqu7t=%RVtP1?Q0^`W2s!?;Xg zMF{UG-5x}oBuSFpCD{zg=81nme1`ZnFA+3#C?Xk|O%|J^x7abX?ePO#_ybCeBI#)Q z=Ll^9bhfX^ZTtuq1CZPiI+({Cqm%N`b%gE!>gl@#h0I+ekk<)X6hk!Pu9CY6jAM?V zjnio}IgcYj98JC&kYBv&0MC3MJq*8M;~jdB(MMkTI|r&5lt;lM3To9k=ipw`sWEIYpQtj0`%V4B*E9p>?aQ literal 0 HcmV?d00001 diff --git a/sourceMetadata/Chapter07/JdbcRowSetExample.java b/sourceMetadata/Chapter07/JdbcRowSetExample.java new file mode 100644 index 0000000..3f435f8 --- /dev/null +++ b/sourceMetadata/Chapter07/JdbcRowSetExample.java @@ -0,0 +1,55 @@ +import java.sql.ResultSet; +import java.sql.Connection; +import java.sql.SQLException; +import java.sql.DriverManager; + +import javax.sql.rowset.JdbcRowSet; +import com.sun.rowset.JdbcRowSetImpl; + +import jcb.util.DatabaseUtil; +import jcb.db.VeryBasicConnectionManager; + +public class JdbcRowSetExample { + + + JdbcRowSet jdbcRS; + + public static void main(String[] args) { + String dbVendor = args[0]; // {"mysql", "oracle", "odbc"} + JdbcRowSetExample jrse = new JdbcRowSetExample(); + Connection conn = null; + try { + conn = VeryBasicConnectionManager.getConnection(dbVendor); + jrse.populateRowSet(conn); + jrse.createEvents(); + } + catch (Exception e) { + // handle exception + e.printStackTrace(); + } + finally { + DatabaseUtil.close(jrse.jdbcRS); + DatabaseUtil.close(conn); + } + } + + void populateRowSet(Connection conn) + throws ClassNotFoundException, SQLException { + jdbcRS = new JdbcRowSetImpl(conn); + jdbcRS.setType(ResultSet.TYPE_SCROLL_INSENSITIVE); + String sql = "SELECT * FROM ztest"; + jdbcRS.setCommand(sql); + jdbcRS.execute(); + jdbcRS.addRowSetListener(new ExampleListener()); + } + + void createEvents() + throws SQLException, ClassNotFoundException { + while (jdbcRS.next()) { + //each call to next, generates a cursorMoved event + System.out.println("id="+jdbcRS.getString(1)); + System.out.println("name="+jdbcRS.getString(2)); + System.out.println("-----------"); + } + } +} diff --git a/sourceMetadata/Chapter07/MySyncProvider.class b/sourceMetadata/Chapter07/MySyncProvider.class new file mode 100644 index 0000000000000000000000000000000000000000..4dc1625fc57c043a2a88161d0a33a1e23a825c51 GIT binary patch literal 1696 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 r=qktSIBiYhTmHlT4%caI5%+O`pkKoFGjOE#@ literal 0 HcmV?d00001 diff --git a/sourceMetadata/Chapter07/WebRowSetMetaDataExample.java b/sourceMetadata/Chapter07/WebRowSetMetaDataExample.java new file mode 100644 index 0000000..c3fef76 --- /dev/null +++ b/sourceMetadata/Chapter07/WebRowSetMetaDataExample.java @@ -0,0 +1,65 @@ +import java.io.*; +import java.sql.*; +import javax.sql.*; + +import javax.sql.rowset.WebRowSet; +import com.sun.rowset.WebRowSetImpl; + +import jcb.util.DatabaseUtil; +import jcb.db.VeryBasicConnectionManager; + +public class WebRowSetMetaDataExample { + WebRowSet webRS; + + public static void main(String[] args) { + String dbVendor = args[0]; // {"mysql", "oracle", "odbc"} + WebRowSetMetaDataExample wrse = new WebRowSetMetaDataExample(); + Connection conn = null; + try { + conn = VeryBasicConnectionManager.getConnection(dbVendor); + wrse.populateRowSet(conn); + wrse.writeXml(); + } + catch (Exception e) { + e.printStackTrace(); + } + finally { + DatabaseUtil.close(conn); + } + } + + void populateRowSet(Connection conn) throws Exception { + System.out.println("Querying database for metadata only..."); + String sqlQuery = "SELECT * FROM ztest WHERE 1=0"; + System.out.println("sqlQuery="+sqlQuery); + + webRS = new WebRowSetImpl(); + webRS.setCommand(sqlQuery); + webRS.execute(conn); + } + + void writeXml() throws SQLException, IOException { + if (webRS == null) { + System.out.println("No data found."); + return; + } + FileWriter fw = null; + try { + File file = new File("metadata.xml"); + fw = new FileWriter(file); + System.out.println("Writing db data to file " + file.getAbsolutePath()); + webRS.writeXml(fw); + + // convert xml to a String object + StringWriter sw = new StringWriter(); + webRS.writeXml(sw); + System.out.println("=============="); + System.out.println(sw.toString()); + System.out.println("=============="); + } + finally { + fw.flush(); + fw.close(); + } + } +} diff --git a/sourceMetadata/Chapter08/GetColumns.class b/sourceMetadata/Chapter08/GetColumns.class new file mode 100644 index 0000000000000000000000000000000000000000..2f8ba0f1367bfbe115b4a192917a47839dd6ab88 GIT binary patch literal 5168 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"); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + while (columns.next()) { + buffer.append(""); + } + buffer.append("
CatalogSchemaTable NameColumn NameData TypeType NameColumn SizeIs Nullable?Is Nullable?Ordinal Position
"); + buffer.append(columns.getString("TABLE_CAT")); + buffer.append(""); + buffer.append(columns.getString("TABLE_SCHEM")); + buffer.append(""); + buffer.append(columns.getString("TABLE_NAME")); + buffer.append(""); + buffer.append(columns.getString("COLUMN_NAME")); + buffer.append(""); + buffer.append(columns.getShort("DATA_TYPE")); + buffer.append(""); + buffer.append(columns.getString("TYPE_NAME")); + buffer.append(""); + buffer.append(columns.getString("COLUMN_SIZE")); + buffer.append(""); + int nullable = columns.getInt("NULLABLE"); + if (nullable == DatabaseMetaData.columnNullable) { + buffer.append("true"); + } + else if (nullable == DatabaseMetaData.columnNoNulls) { + buffer.append("false"); + } + else { + buffer.append("unknown"); + } + buffer.append(""); + buffer.append(columns.getString("IS_NULLABLE")); + buffer.append(""); + buffer.append(columns.getString("ORDINAL_POSITION")); + buffer.append("
"); + out.println(buffer.toString()); + } + + private static void printXML(HttpServletResponse response, + ResultSet columns) + throws Exception { + response.setContentType("text/xml"); + PrintWriter out = response.getWriter(); + StringBuilder buffer = new StringBuilder(); + buffer.append(""); + buffer.append(""); + while (columns.next()) { + buffer.append(""); + buffer.append(columns.getString("TABLE_CAT")); + buffer.append(""); + buffer.append(columns.getString("TABLE_SCHEM")); + buffer.append(""); + buffer.append(columns.getString("TABLE_NAME")); + buffer.append(""); + buffer.append(columns.getString("COLUMN_NAME")); + buffer.append(""); + buffer.append(columns.getShort("DATA_TYPE")); + buffer.append(""); + buffer.append(columns.getString("TYPE_NAME")); + buffer.append(""); + buffer.append(columns.getString("COLUMN_SIZE")); + buffer.append(""); + int nullable = columns.getInt("NULLABLE"); + if (nullable == DatabaseMetaData.columnNullable) { + buffer.append("true"); + } + else if (nullable == DatabaseMetaData.columnNoNulls) { + buffer.append("false"); + } + else { + buffer.append("unknown"); + } + buffer.append(""); + buffer.append(columns.getString("IS_NULLABLE")); + buffer.append(""); + buffer.append(columns.getString("ORDINAL_POSITION")); + buffer.append(""); + } + buffer.append(""); + out.println(buffer.toString()); + } + + private static void printError(HttpServletResponse response, + String message) { + try { + PrintWriter out = response.getWriter(); + StringBuffer buffer = new StringBuffer(); + buffer.append(""); + buffer.append(message); + buffer.append(""); + out.println(buffer); + } + catch(Exception ignore) { + } + } + + + /** + * Retrieves a description of the given table's columns. + * @param conn the Connection object + * @param tableName name of a table in the database. + * @return the list of columns as a ResultSet object + * @exception Failed to get the table's columns. + */ + public static ResultSet getColumns(Connection conn, + String tableName) + throws Exception { + System.out.println("getColumns begin"); + if ((tableName == null) || (tableName.length() == 0)) { + return null; + } + + DatabaseMetaData meta = conn.getMetaData(); + if (meta == null) { + return null; + } + + // + // The Oracle database stores its table names as + // Upper-Case; if you pass a table name in lowercase + // characters, it will not work. MySQL database does + // not care if table name is uppercase/lowercase. + // + System.out.println("getColumns begin 2"); + ResultSet columns = meta.getColumns(null, null, tableName.toUpperCase(), null); + System.out.println("getColumns begin 3 columns ="+columns); + return columns; + } +} diff --git a/sourceMetadata/Chapter08/GetPKColumns.class b/sourceMetadata/Chapter08/GetPKColumns.class new file mode 100644 index 0000000000000000000000000000000000000000..496e96b446abc64f5190c360ae72bf1233286fb0 GIT binary patch literal 3985 zcmb7H`(G5-75|Pd%yk(>R}e5hkVFH*x)5WcFf0Mw1Of}lf@sochh>1peK|WzplQ>z ziG8P!G<}#p(?_tiX|)f8B#r6IwCOAT^tb-l{vU0>cV-rrKx+CC=id9h=bn4c_ndp~ z-M9Yz%Ig4H@HamqI3sYj43FSZKi-GO1kMSZ_v8IA{5Xkmfw;scI9fjNQsGJF6}2z*fBL$dp%z=s8% z68MO~M+Kgi*fVnJC4r9#d|coYa`Z_*K7~&Ud`93|fzJwjPT=zbUl4ds;EMv!3w%l7 z%PPL&N2}catFpZ;@Pb_UHR;LM%kT|+Q}(`9hHv9V72i?uT?M6jBAu|q3O3g_oL1oL z&PplWrYOHWrmk(@9| z@o`;>hxPHy#C%wH?5iEmSe$Ebsg0Y-WG-vO$!B}BGs+qh6V52C;Z?k*ph6!R4(lU5 z;cmk=l9?$z#6B}rLb3R?nKC?Nr$n4=tsO8@riXGlmpT*{!<7W&6F zqY+MZ5B85n2hO`AwJ&n^d@OQG!>{mb>GE$Bs6&0;tlw2BZBVdF4>|OO^^i-Z6A1G3 zTU=G~I}Nw6L<^k|G13Ye^$xbRv!<0}61La19BHnrrL!4_;kw?~VDR|yV<&fJ=7hA+OKfJy~k^`m*Dhq+lCIYYg7CJ_jc!WeRG=DJVI9(^L@;o3iipp-n|H}6Yz@T%AqP8wL~V=J6MDs{NH-L;!1O5 z;V~@oY)cOhxpi!#3R7Hk6l{MdM=bd)XDP<8zQHX?YZn}tiI0aS#zUt~Yrf0KCE}}9 zEo!8VDY^Sr8nX&3Xn1#PWNBU%ZDT3p`7@HNoR!6k2FGVuIolc@AubKb+lgf8B$II5 z$eE)Yu++tqnH-B`mA7tv(XTF=DcaMyaA>`!MbPHt!~%le-B-u1y>-A~w=f-?7lSnCQ477t?DPNo$!y+>E%!K5c^ z3@QYj4}#L9nVzzz9d~*QXJu{fu#h@Iv<;aT3icLwmSTleiJI;-w<@zUqvYG_W(Fy! zS)uTqq6+#q@L^pv-s_c)1AHY$`0NBqp~&l--yV+kvQ^lY9KHeNIy(w_Jt08j=wb9> zlN41d*lyw6Gs=L{>T3*aTE^y0ScI>&q%lykGAL~fl&%canvx}`t-cyxP3aQEK#dyM zvIzfWlr;sHP__UeTaEv>*7%mNZ2|SIB~3LYi`c$|9YyetRp%SaXx}-`dNc0?x3zZoW`Aa z6n9bMK0d|wQ*Rwo#4KWY_Mc$?DfXYnLG(LpZQ|Mi_~l#1V`~bVX(RBj!-2puc5cGq zWmG7LzKY7TH?V6U7^qrA^;j@a<2Jk9<_@>n<2HNUW}j>tm$6^LWn2mdY8|*Sa9|mA zG6GV~ogQ}A2H3$3utOVQcQ2z}>T4*{N3&PwDGZXPBkYApcr$+yw4f9BFr|+2{dX_U;22EYha~RDJdTst6L^+V&oeYH zLdO-f^XV7HYv|y`_yFGK>c684|3EkX$*h(E@G()#Nk89{9{tT8{cju&gf^zX+2yT8 zHbvat@NF(w{Ja;BjWs>J;igGiQOfW$%P>Meh+z`?PAA<L-K=rIEXr62wlb$G_;a?Jhjup)?5dXvIRUpC`!A?D B{S*KI literal 0 HcmV?d00001 diff --git a/sourceMetadata/Chapter08/GetPKColumns.java b/sourceMetadata/Chapter08/GetPKColumns.java new file mode 100644 index 0000000..8d77115 --- /dev/null +++ b/sourceMetadata/Chapter08/GetPKColumns.java @@ -0,0 +1,133 @@ +import java.sql.*; +import javax.servlet.*; +import javax.servlet.http.*; +import java.util.List; +import java.util.ArrayList; +import java.util.StringTokenizer; +import java.io.PrintWriter; +import java.io.IOException; +import jcb.util.DatabaseUtil; +import jcb.db.VeryBasicConnectionManager; + +public class GetPKColumns extends HttpServlet { + public void doGet(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + ResultSet primaryKeys = null; + Connection conn = null; + try { + String dbVendor = request.getParameter("vendor").trim(); + String table = request.getParameter("table").trim(); + String outputFormat = request.getParameter("format").trim(); + conn = VeryBasicConnectionManager.getConnection(dbVendor); + primaryKeys = getPrimaryKeys(conn, table); + if (outputFormat.equals("xml")) { + printXML(response, primaryKeys); + } + else { + printHTML(response, primaryKeys); + } + } + catch(Exception e) { + printError(response, e.getMessage()); + } + finally { + DatabaseUtil.close(primaryKeys); + DatabaseUtil.close(conn); + } + } // end doGet + + private static void printHTML(HttpServletResponse response, ResultSet primaryKeys) + throws Exception { + response.setContentType("text/html"); + PrintWriter out = response.getWriter(); + StringBuilder buffer = new StringBuilder(); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + while (primaryKeys.next()) { + buffer.append(""); + } + buffer.append("
CatalogSchemaTable NameColumn NameKey SequencePK Name
"); + buffer.append(primaryKeys.getString("TABLE_CAT")); + buffer.append(""); + buffer.append(primaryKeys.getString("TABLE_SCHEM")); + buffer.append(""); + buffer.append(primaryKeys.getString("TABLE_NAME")); + buffer.append(""); + buffer.append(primaryKeys.getString("COLUMN_NAME")); + buffer.append(""); + buffer.append(primaryKeys.getShort("KEY_SEQ")); + buffer.append(""); + buffer.append(primaryKeys.getString("PK_NAME")); + buffer.append("
"); + out.println(buffer.toString()); + } + + private static void printXML(HttpServletResponse response, ResultSet primaryKeys) + throws Exception { + response.setContentType("text/xml"); + PrintWriter out = response.getWriter(); + StringBuilder buffer = new StringBuilder(); + buffer.append(""); + buffer.append(""); + while (primaryKeys.next()) { + buffer.append(""); + buffer.append(primaryKeys.getString("TABLE_CAT")); + buffer.append(""); + buffer.append(primaryKeys.getString("TABLE_SCHEM")); + buffer.append(""); + buffer.append(primaryKeys.getString("TABLE_NAME")); + buffer.append(""); + buffer.append(primaryKeys.getString("COLUMN_NAME")); + buffer.append(""); + buffer.append(primaryKeys.getShort("KEY_SEQ")); + buffer.append(""); + buffer.append(primaryKeys.getString("PK_NAME")); + buffer.append(""); + } + buffer.append(""); + out.println(buffer.toString()); + } + + private static void printError(HttpServletResponse response, String message) { + try { + PrintWriter out = response.getWriter(); + StringBuffer buffer = new StringBuffer(); + buffer.append(""); + buffer.append(message); + buffer.append(""); + out.println(buffer); + } + catch(Exception ignore) { + } + } + + /** + * Retrieves a description of the given table's primary key columns. + * @param conn the Connection object + * @param tableName name of a table in the database. + * @return the list of PK columns as a ResultSet object + * @exception Failed to get the Primary Keys for a given table. + */ + public static ResultSet getPrimaryKeys(Connection conn, String tableName) + throws Exception { + if ((tableName == null) || (tableName.length() == 0)) { + return null; + } + DatabaseMetaData meta = conn.getMetaData(); + if (meta == null) { + return null; + } + // + // The Oracle database stores its table names as + // uppercase; if you pass a table name in lowercase + // characters, it will not work. MySQL database does + // not care if the table name is uppercase/lowercase. + // + return meta.getPrimaryKeys(null, null, tableName.toUpperCase()); + } +} diff --git a/sourceMetadata/Chapter08/GetSQLKeywords.class b/sourceMetadata/Chapter08/GetSQLKeywords.class new file mode 100644 index 0000000000000000000000000000000000000000..d40b654a6dc618bb770f0afa2f696b3279daa39f GIT binary patch literal 3558 zcmbVOYkL#N6@J&2y{q*aQh@;{ff%PYHj)q~ff!2`!5FX;U+@JSXxe5at!06>jKhgA^UCEYhC~c+Znb|orbI$vo zbLPza?Oz{!2%ralRuRX9g2^UKVOqsKIIG~CiWxknq7Ua4ToA&~h{5Bc`K*f1;qx+{ zP|*xsNKy*YO~}9y&8&>9ifuyWoal23E;iv3@(K!~H)U7~iV7}^SzCnzS3ya^yn-hc zEGSr1@RW=%sOS_*z9{-HDfqHj`E(P$g0D8=YxueV^^A;fsEA=g#y1swOC_Cei{?9` z`L3|`y&%4iA1L^tif7@hM{=eyRw|?ndslR}}Y^Hp{q;a`qIBxuo%bcQRI!0VrRZlLY zjiQ^QK*kF)UX&0l+Bwr5njRgI5Wlm{iZah=tmNkMv5_1>2<5@4T-Maxl1&!l|F5Qm zuQ{)q+1QjzXxVtu)2?_p9}_TD@AIT>TegJ$|It#dW`TN3)^MjLMjka5pS0|ZBVnJf zFy>s&$4*$LX{3d};@ul5ue$3_D{o1OET*iIoi1-!J~|yYb=N~E97Ooq2U*JQ^POuD+xQ-Hu@nMDCP1QgU;_wh~>#d z%E~Mz6RybMwiMlH*!?|iX(OL^ih7zc>_6y@ih3sFjglIc@M{Ts64R5(#Pm>-+}o-l zNW>^$Gntg}mWH?Sjs(SDILM9f;x`iR+6amMFpFjL2j9A1KYv3Rh~it`zRM&fMIH{uV0+_v>aaVjOWde%ItAGvAkl40ha5(cG+NU&uMEBHXeO`++JctysaG<=AU zXgs>^C*xzv)~6{0C=A@bMr~S9sa>o2R|TH4V#DJ#(vJVEw^IA)HJ;uxx~&%sS8(dA zoZWSYd~-!%`DJM-NZ8(0Io7osB<#JIPQ@~**g3;q9MGLydaVwO>ZYC*rkZJaO)R1N z_NF&f5*}WbZavRh(^9)>Jav(^Cfz7_qO}C8YBmL=Qct*X%UZ(v860q!t=^?M%$CLlwBg#QRoo^{v*lZ;NvaxH5@he* z$eR)(|0OJOG>K}RGpb>tul+-}KD-i|ya>3u2%Uu8RVRsM)o6|y{xo&_NAy;cbYtEy zv+ms5om88qo4n{c0Sp;n5=wTd3owxKK z>=n*sq_J?QZUyyqC?n7p2!|S02Mw)(Wi*aOmm&8xwl;*6GJ;p3MOqt|p)MileKc`e zTf&~cK%_NL#+GGl^(9)LEIwN0kFFy?YsWFfSET4K(C!eQprXHk$GzT1`UpalZRe^T z#JdysVi(%ciZ0xZLwp7HQWD1=>geDl+es~Zd5N}DR|j9Qoz&EUC)lUCV}P0(sp$j; zp^7UR^&a#0*f(%4yFYZ-3O-eb{VNDb7`=&Y=Wk&9STxj9#*Ue2Xs77vj|5r*;T7zX z@CNopL#^IixFxWHyX){V?(x^&E4pU_($Xh?kA`-OK_ptno-*!R3&Ro82cmTQ0g{W6 z-a%67A>>1Nfd4)`NHT{p!SM_p;?uhqvpDJz2{3rgIL-ZaB&~{P#%4Ngx2Ch#huAK< zjdbq!<~Gs!v=CS6bcn(2==76Ll5~!d&cl_+43NwT(itS3lcY01I;Tlzh;)W;Nrw+1 z5)>(1Ai;oe(`r;Y8I^sEN>>@(GtscuhW3k2UEbhY`Gx`#`>4(EGd9W=4ERw`!g0(mKZjAcIskIJg{tXmmklX+O literal 0 HcmV?d00001 diff --git a/sourceMetadata/Chapter08/GetSQLKeywords.java b/sourceMetadata/Chapter08/GetSQLKeywords.java new file mode 100644 index 0000000..04c459b --- /dev/null +++ b/sourceMetadata/Chapter08/GetSQLKeywords.java @@ -0,0 +1,119 @@ +import java.sql.*; +import javax.servlet.*; +import javax.servlet.http.*; + +import java.util.List; +import java.util.ArrayList; +import java.util.StringTokenizer; + +import java.io.PrintWriter; +import java.io.IOException; + +import jcb.util.DatabaseUtil; +import jcb.db.VeryBasicConnectionManager; + +public class GetSQLKeywords extends HttpServlet { + + public void doGet(HttpServletRequest request, + HttpServletResponse response) + throws ServletException, IOException { + Connection conn = null; + try { + String dbVendor = request.getParameter("vendor").trim(); + String outputFormat = request.getParameter("format").trim(); + conn = VeryBasicConnectionManager.getConnection(dbVendor); + List sqlKeywords = getSQLKeywords(conn); + if (outputFormat.equals("xml")) { + printXML(response, sqlKeywords); + } + else { + printHTML(response, sqlKeywords); + } + } + catch(Exception e) { + printError(response, e.getMessage()); + } + finally { + DatabaseUtil.close(conn); + } + + } // end doGet + + private static void printHTML(HttpServletResponse response, + List sqlKeywords) + throws Exception { + response.setContentType("text/html"); + PrintWriter out = response.getWriter(); + StringBuilder buffer = new StringBuilder(); + buffer.append(""); + buffer.append(""); + for (int i=0; i < sqlKeywords.size(); i++) { + buffer.append(""); + } + buffer.append("
SQL Keywords
"); + buffer.append(sqlKeywords.get(i)); + buffer.append("
"); + out.println(buffer.toString()); + } + private static void printXML(HttpServletResponse response, + List sqlKeywords) + throws Exception { + response.setContentType("text/xml"); + PrintWriter out = response.getWriter(); + StringBuilder buffer = new StringBuilder(); + buffer.append(""); + buffer.append(""); + for (int i=0; i < sqlKeywords.size(); i++) { + buffer.append(""); + buffer.append(sqlKeywords.get(i)); + buffer.append(""); + } + buffer.append(""); + out.println(buffer.toString()); + } + + private static void printError(HttpServletResponse response, + String message) { + try { + PrintWriter out = response.getWriter(); + StringBuffer buffer = new StringBuffer(); + buffer.append(""); + buffer.append(message); + buffer.append(""); + out.println(buffer); + } + catch(Exception ignore) { + } + } + + /** + * Get the table names for a given connection object. + * @param conn the Connection object + * @return the list of table names as a List. + * @exception Failed to get the table names from the database. + */ + public static List getSQLKeywords(Connection conn) + throws Exception { + DatabaseMetaData meta = conn.getMetaData(); + if (meta == null) { + return null; + } + + String sqlKeywords = meta.getSQLKeywords(); + if ((sqlKeywords == null) || (sqlKeywords.length() == 0)) { + return null; + } + + List list = new ArrayList(); + // SQL keywords are separated by "," + StringTokenizer st = new StringTokenizer(sqlKeywords, ","); + while(st.hasMoreTokens()) { + list.add(st.nextToken().trim()); + } + System.out.println("--------------"); + return list; + } +} + + + diff --git a/sourceMetadata/Chapter08/GetStoredProcedures.class b/sourceMetadata/Chapter08/GetStoredProcedures.class new file mode 100644 index 0000000000000000000000000000000000000000..194e05b0a205059eee5e0932086684dcb032490b GIT binary patch literal 3896 zcmb7HYkM2T6@JH&thKx$$r{^{b8`$y9ovc=3dONyr6hKU8(VfIIU(T^R?@~%BJV2F z%CSp<^ahjyg{Cb8C{Wtez0fx9#jzoU_UQ+n2fp{`w0&n+k|oPDPruCU%$zyrea|^_ zX7;mxfA}$gL-@NNLzq@@su`#8h#zNgR>7lwJch>=JR!&D6g;Uw_hS%A1t|q-1%@1* z_hSYZWRp>FQO;bFP1c85KU!fbu$qy>W!dC?DEQGKE!na!DwtDnr5W>BQ1A@}Psz`3 zDtKDKGxGCUsp_hNZz=e;-0&SgzKicEcuv9d3SLm~eFZNn_<@3#6uhk9m1g`9uQuZ~ z{7Aty1wU5s6CZx+!|MWj;)%)F=*YRL*yOR%k?Gjzx!7o8Iu?zyk57*$1hnys`kWrh z>gG%+Zs#-R%#gt5W0qO4b<;kjXN!hFN1dAJWJSY9Hl*%z)6tXB$4ygH1!N|{L4LfwfwsWBqY~t=j z%(z@M3ii+)#R@qRF@~g7|LA`q3iwjG zt!J$n0kKcTB&N8*%Ihg~nrvfU=HV>Q_-|GG4j-uaJ^mojzP86bK1Yk0Y}#Pl z2f|W35>8s_g-FaVt76~U# zL@HtLjOw#SIK(M|owX}6F3t*@Sj2}V6@S8?1r%4w2zT7IRs^CCO^mAe3*II%ZWy7N zbrOj)Q6x)YW0O_0`~J7yQmGVBd6=j4JRNAu?A%|fAJqqV z!!x~geS))q^PZR$xVwA94SO%9lA&}mbjrvt9Mub%)LMC(&`o_tTHj1CYtsS;z8KBA z0>?wn;;&~}0$Zy$O(rk01P&cI%XtZ)XlJsa5tfRiUNELPU>Qketpck=dsXSIE#cd% zR@UIT*9Q?#7=;4y(|LFDxqDSG;|dN>+c52N<=mk9vdA}4{pozh2~B(1uMG8+yrJ9$ z-ph@8F2|xN5Ui$Ny0+_sQ7T2;s5wEbxw9BXlQqq`l<71Hz*R&u{2nv8RO8{YnK5~` zt+K3JGi#BuNIMr`)+{G&Z4d>T9dFvY43NOCGGQrJj@g9aE)#vAf`0v?n@N=d$)p(H zz%%tOub(M-uf|0~*vqHb5MPU%_znwW7y=QF8t@>;N2B5;@|t6Nj5~I* z7wo+~w;-1IAuz(W(V1*!JBs5}OHpwR9yD?7a}gDTo?fkC6`LBc49}pqSMyc|jREfp z8lwTP=39nx9eaAUrplr(81QL+&A)=?LC+!vD5W}5yL+|GRZ>EVm4sUQw7XWYCE!`X z*5C@ZEd?4i&Do^($;p;QG&vu4S40-kJ?QNVc$d*uy>k)U29=6XK>1{eM7@~94Ze-9 z;=0qz@omzSW7*%pO{c%jN-W2&gPvmqfOfiOJ2iAb!w&4hPVA#cL)guj?7<1#gOj)y z)0|CWKW5RxXLldG!n%LjKMD-3vRIRFJ^|9YtQs(?W@?{fSy$Z1SUR0$C+E$ z5e;fPm$B<~P}}Wxdt}$UicTRR1hu`+bg$O6ihE>`rRcqmjJ9tT`y22TPq3BF|B}1Z zExX14{3ECxkY9blW%MkgcP*igV;j+oLSZ^>A?kJ_-c8K=h`EobAK+^z%$Lv@qL||2 z=`7ncZ}>}y!9*NIB=9snDfxOBgI2QT`>4eB^Ag)DJzC$!YzatGI4HX+njvSpmS(>r zvmwnxa>=22pZuz)c@$d-@GNOQN}7+6=HsOK1ZkebK|D#CI*(qGG*cv%=BmN=Jpb2b zNb>?yBU3|>PeYQG2Q^2k9`^lpf&8+|!D+Sot8p#DGqJ?|KrgMg@@s_O`<+v4vJhCr zm_r*bGja1w)&k|`C|P6*U!fG=uq6jaXj`UJ2dzIKFz5+*K807@40w9`f~!mhCTaO- zXb#So=!2KB8L!aBYc-tsY%6gZqIQX{rNjFk8np*+c6ekza8o literal 0 HcmV?d00001 diff --git a/sourceMetadata/Chapter08/GetStoredProcedures.java b/sourceMetadata/Chapter08/GetStoredProcedures.java new file mode 100644 index 0000000..9df5a2e --- /dev/null +++ b/sourceMetadata/Chapter08/GetStoredProcedures.java @@ -0,0 +1,161 @@ +import java.io.PrintWriter; +import java.io.IOException; + +import java.sql.*; +import javax.servlet.*; +import javax.servlet.http.*; + +import jcb.util.DatabaseUtil; +import jcb.db.VeryBasicConnectionManager; + +public class GetStoredProcedures extends HttpServlet { + + private static final String STORED_PROCEDURE_RETURNS_RESULT = + "procedureReturnsResult"; + private static final String STORED_PROCEDURE_NO_RESULT = + "procedureNoResult"; + private static final String STORED_PROCEDURE_RESULT_UNKNOWN = + "procedureResultUnknown"; + + public void doGet(HttpServletRequest request, + HttpServletResponse response) + throws ServletException, IOException { + Connection conn = null; + ResultSet storedProcedures = null; + try { + String dbVendor = request.getParameter("vendor").trim(); + String outputFormat = request.getParameter("format").trim(); + conn = VeryBasicConnectionManager.getConnection(dbVendor); + if (dbVendor.equals("mysql")) { + String catalog = request.getParameter("catalog").trim(); + storedProcedures = getStoredProcedures(conn, + catalog, // catalog, + "%", // schema Pattern, + "%"); // proc. Pattern + } + else if (dbVendor.equals("oracle")) { + String schema = request.getParameter("schema").trim(); + storedProcedures = getStoredProcedures(conn, + null, // catalog + schema, // schema Pattern, + "%"); // proc. Pattern + } + else { + printError(response, "unknown db vendor"); + return; + } + + if (outputFormat.equals("xml")) { + printXML(response, storedProcedures); + } + else { + printHTML(response, storedProcedures); + } + + } + catch(Exception e) { + printError(response, e.getMessage()); + } + finally { + DatabaseUtil.close(storedProcedures); + DatabaseUtil.close(conn); + } + + } // end doGet + + private static void printHTML(HttpServletResponse response, + ResultSet storedProcedures) + throws Exception { + response.setContentType("text/html"); + PrintWriter out = response.getWriter(); + StringBuilder buffer = new StringBuilder(); + buffer.append(""); + buffer.append(""); + buffer.append(""); + while (storedProcedures.next()) { + buffer.append(""); + } + buffer.append("
Procedure NameProcedure Type
"); + buffer.append(storedProcedures.getString("PROCEDURE_NAME")); + buffer.append(""); + int type = storedProcedures.getInt("PROCEDURE_TYPE"); + buffer.append(getStoredProcedureType(type)); + buffer.append("
"); + out.println(buffer.toString()); + } + + private static void printXML(HttpServletResponse response, + ResultSet storedProcedures) + throws Exception { + response.setContentType("text/xml"); + PrintWriter out = response.getWriter(); + StringBuilder buffer = new StringBuilder(); + buffer.append(""); + buffer.append(""); + while (storedProcedures.next()) { + buffer.append(""); + } + buffer.append(""); + out.println(buffer.toString()); + } + + private static void printError(HttpServletResponse response, + String message) { + try { + PrintWriter out = response.getWriter(); + StringBuilder buffer = new StringBuilder(); + buffer.append(""); + buffer.append(message); + buffer.append(""); + out.println(buffer.toString()); + } + catch(Exception ignore) { + } + } + + /** + * Get the stored-procedures names. + * @param conn the Connection object + * @catalog database catalog name + * @schemaPattern database schema pattern + * @procedureNamePattern database procedure name pattern + * @return a table of stored procedures names + * as a ResultSet object. + * Each element of XML document will have the name and + * type of a stored procedure. + * + */ + public static ResultSet getStoredProcedures + (java.sql.Connection conn, + String catalog, + String schemaPattern, + String procedureNamePattern) + throws Exception { + + DatabaseMetaData meta = conn.getMetaData(); + if (meta == null) { + return null; + } + + return meta.getProcedures(catalog, + schemaPattern, + procedureNamePattern); + } + + private static String getStoredProcedureType(int spType) { + if (spType == DatabaseMetaData.procedureReturnsResult) { + return STORED_PROCEDURE_RETURNS_RESULT; + } + else if (spType == DatabaseMetaData.procedureNoResult) { + return STORED_PROCEDURE_NO_RESULT; + } + else { + return STORED_PROCEDURE_RESULT_UNKNOWN; + } + } +} \ No newline at end of file diff --git a/sourceMetadata/Chapter08/GetTableTypes.class b/sourceMetadata/Chapter08/GetTableTypes.class new file mode 100644 index 0000000000000000000000000000000000000000..b275ae3e304cc892e0c05f14431dc80f6a3467bb GIT binary patch literal 3719 zcmbVPYgZfB72Q_|W{?Iul>=Cb?O+nyU?I!IiA{u%0|pyhUIuIunx+{^1D30oXGRpc zO_R26-B;T5>84GeX-nU>(-uSA#%VvKYxQ$~Kz>QmeP<*P0@rO}tvPe=J@?$R&pzke z(LdjR>umtt_`45LOsY8N#}uZ0co;J(&iilyvpzh9XH+~ZC+FngBl7W_4%8M$}eq6%GRb-^hD#)qGt0>6T%RZQ}RM;wtDi&3I zLdBAbl7cHf9F#^rDdneByeKt4?Z-=aSvv3;KR%1kDY)uG1e1;UJiegfnh#%u<;R!s zW%>Auim%EeUs3Tj1z%V2sz5_5olDzsfx3>)3j*F#`II5Bb2ObZ#*5j6Vb17@3}@<7 z`7?$sFx4@7Nng~LB9>t;W(+%W(Y6bbVLqnai7Df9(Xi~^`>I)me9kg@<*B}*rKC}? z)0|N74F%s6Xe^lNoIN}`B#Mdu*HX;2 zoY8X&k!hQ*E%e46>#F1DGty0;^Ezajc~hY8e>|z$vh=!X!LXgs&y)&=C2+{K7qKp9 zBB%1XoRO5_>g}vWydJIlX>N;%Ag1$0GijVoOVR_Re8Y(&l6Vchh%s#zja({kD)^R$ zZ{s@}zKiReozI(D-B$2D4X@$*8a@ohrEV#k(eMMju3;EM8U`_>;D;K1gdYp+l13vA z`t>Bx@Dp6uFoLsW&o-81l4UareyZVTctgX_@e6_0jg2lL1I2VEWia$TF{vJpCGx3K zJZ8)MZA;`$uJv`dC5=qRD(Fcv*mu+!74%ff8O1gH63YU6Vlz|m*vxR;f!-zwh($Q$ zV=AuTR~mke-w3F#+90?67QYjCpw=M#u4fJ^?*2WlEBJ$k8+e0O z9lVT~Kqz*SvTe~YEmGar-hJd~dz+C<<{fw2N2VvjJv~o874B|7$@%KLW9jK_Z)H*y+oS&Bg)T#q0gK|?~N3GX4a7)3P8vcksNh<%WU`6tMyF#f` zg#D(emt-X>SkDQQHS@e?e zxL+9EPEMjN2aRpyY?-h%o|SvB)8A=+)=WFmZmmR*>`lrG#9inmK)q04%Mu7z1FV?Y zLP)upaN`cAO4hFw5@n^Y&>h~FBYg63>Dov&Yvr)XV$QoKR3%lFTP#lJ%E;sdy8cVI zWQEeJZE0ex-FCW}UID+ufUQgF1ol>fB-JWxjv4MUZMRlYIb~SIj6H3*S833R#dh1+ z-m0x`Y}?!yOO|ag$?Nh(88tWR6{;91L(lSj7sKXh-bL$YuNx;9Io=Kq7fjJcqO63w zhLJMQ)MT^Aetx4x`LPEyfcGV0eD-m)mr_vHAHEH7i!TE4vJ$X^qmy_V9!K>(N|kFV zF&+wd)==lc3cOKoC{VvXs1JHq(J&rfg%WKD)(6xTG`o>{!K4cSegU@+GL;y#+5%>*wX!aIfv&Q>3Vt=0nY8BRx@^@1$)qn zcI-w6f_NMcp@$!?y@c71$1sEgw9xv0aKy{$icnf#0aO4aN>k>l5n0ToPGisAe>W#Ge|i7gmap3&JfP|3xhFtP-wL{~F~h Ql(iW-#`DK{vIi6Y2INGqD*ylh literal 0 HcmV?d00001 diff --git a/sourceMetadata/Chapter08/GetTableTypes.java b/sourceMetadata/Chapter08/GetTableTypes.java new file mode 100644 index 0000000..801cefa --- /dev/null +++ b/sourceMetadata/Chapter08/GetTableTypes.java @@ -0,0 +1,127 @@ +import java.sql.*; +import javax.servlet.*; +import javax.servlet.http.*; + +import java.util.List; +import java.util.ArrayList; + +import java.io.PrintWriter; +import java.io.IOException; + +import jcb.util.DatabaseUtil; +import jcb.db.VeryBasicConnectionManager; + +public class GetTableTypes extends HttpServlet { + + public void doGet(HttpServletRequest request, + HttpServletResponse response) + throws ServletException, IOException { + Connection conn = null; + try { + String dbVendor = request.getParameter("vendor").trim(); + String outputFormat = request.getParameter("format").trim(); + conn = VeryBasicConnectionManager.getConnection(dbVendor); + List tableTypes = getTableTypes(conn); + if (outputFormat.equals("xml")) { + printXML(response, tableTypes); + } + else { + printHTML(response, tableTypes); + } + } + catch(Exception e) { + printError(response, e.getMessage()); + } + finally { + DatabaseUtil.close(conn); + } + + } // end doGet + + private static void printHTML(HttpServletResponse response, + List tableTypes) + throws Exception { + response.setContentType("text/html"); + PrintWriter out = response.getWriter(); + StringBuilder buffer = new StringBuilder(); + buffer.append(""); + buffer.append(""); + for (int i=0; i < tableTypes.size(); i++) { + buffer.append(""); + } + buffer.append("
Table Type
"); + buffer.append(tableTypes.get(i)); + buffer.append("
"); + out.println(buffer.toString()); + } + private static void printXML(HttpServletResponse response, + List tableTypes) + throws Exception { + response.setContentType("text/xml"); + PrintWriter out = response.getWriter(); + StringBuilder buffer = new StringBuilder(); + buffer.append(""); + buffer.append(""); + for (int i=0; i < tableTypes.size(); i++) { + buffer.append(""); + buffer.append(tableTypes.get(i)); + buffer.append(""); + } + buffer.append(""); + out.println(buffer.toString()); + } + + private static void printError(HttpServletResponse response, + String message) { + try { + PrintWriter out = response.getWriter(); + StringBuffer buffer = new StringBuffer(); + buffer.append(""); + buffer.append(message); + buffer.append(""); + out.println(buffer); + } + catch(Exception ignore) { + } + } + + /** + * Get the table names for a given connection object. + * @param conn the Connection object + * @return the list of table names as a List. + * @exception Failed to get the table names from the database. + */ + public static List getTableTypes(Connection conn) + throws Exception { + ResultSet rs = null; + try { + DatabaseMetaData meta = conn.getMetaData(); + if (meta == null) { + return null; + } + + rs = meta.getTableTypes(); + if (rs == null) { + return null; + } + + List list = new ArrayList(); + System.out.println("getTableTypes(): --------------"); + while (rs.next()) { + String type = rs.getString(1); + System.out.println("type="+type); + if (type != null) { + list.add(type); + } + } + System.out.println("--------------"); + return list; + } + finally { + DatabaseUtil.close(rs); + } + } +} + + + diff --git a/sourceMetadata/Chapter08/GetTables.class b/sourceMetadata/Chapter08/GetTables.class new file mode 100644 index 0000000000000000000000000000000000000000..52a62a9f494f045321c4d15cba2226e34bbcc5dd GIT binary patch literal 4783 zcmbVQ`D0Yo75;9R$&HA=R4=V$vgjk z{Y?Pt@h>-;(4!+*gkD%~l%Y>YzZ-`U(lH>%A9te>VcA4v%xNDIK5D@Sq#zQpsnf{G5)@%bgDu;S2bpj)#lzB|IVx`Lb+IYk1U+4d^MtWB7`k z`D!5^#}hi9bmMEdSKj-SJoKEI)Pc`6?+9-jj>*8Ep84)t=3ee$4YdWJz>t| z_r`9tY=Mq)rGChtv=W11%l03(?YMs@n@(qGI6Msa}?G3B3uF^n6y6$cC)!~rsKC=xbsGxiwh!X6E; z8@PyX5|W8@$nwR&8#r%ZKW<^5ZEHyKF%s7Brh!YiY~Wk?w!p%PgH9ebq(b3di&5Gf zklX75J+a>5x_~XI?(K;sxK_K~8??gVWZVog@oLwpQQYk9Riios-@$hUmIS&w>H=Lm z>l6rH8Kr=qLpB|C8op=XEnE@Moo!7#_BOsRFn6j!BoB`?Ip+ix1pLYtjvdRCS3La= z&TIIAfp>A4T9v;9OQ15amC`$CC6eSr?TYnl*RAkc(O^uOyJA;on{V^xjaz){S8Qdf z>yD>Mb_)Vg+RTm?@TYr)>C5Hvf~kf!r26_Ka7He05{w^`3{$Or7eCVQV*@|IPX)Fm ztuX28jr9yrbj!=UeTi7an_?yDc4m{_qlc}8mDytt$1QKIceN^rt2O-0z|ZlXWWz6H z^UDk+RKC|I66UZ>dJVra@N4|Wz;E$84Zk<=2mFx$D@0|4YBl`Hz@H`Q{(`?6*oj>l z{$}9s_=mu2jK7 zddAsM%)hHGXLjX(*PAZKj2InjHxu;VmH}Lqt|XJ{&h#S37lAKNL|}e-y2#`n5LiAC z?D6;Z`1e|g;RZ7q3Qkm|7Bg!0%d2EDnV1%+xcb#o>KggU*Tf97@|ENsYEvAlsbJEV zNCOlBnoLI6Oj>(b{TYH_IF@9ET6C3)DPJAh)nX-+w32vS3r6RKVX%|R8{3N7UF7E! z%hK<(dUvRPUm~Q?UYJ3T(QB6vo3p_8yuggdSuF*8xejL3ObbZ5a`E6Cm73Y7j)6*s zj?o;xk@69J5#r)KeCY3RL}%X34TZt7Z(7e9n}$lf%o; zj9|htZL8B}6Ct21I2oYi*6chLd$J0$v*ffjWCc^UwL3-n36x*mR;jMTN~Xegr)5*! z!W>#m%*(Llu4J!LPyK`m*%L%P%11|`PBP9V>Rn8ih}E0HH$(Qx222V|I@pt+h2bP2 zq25?Z#?j$HhCDoAnGt&7pgMV)XZT796e)Jwrc4WgvRqs%KSAKAV$~`Xk}ZVCg-qiLp#-Rt0qXFnnVutS&f%LU!C-$oCXE3st2B zV=%a&I>bNwI(~I+NBY=Xv02!GZiZtr!@x=f|PM2lyvOB z1q(R0n7fv6ZyDRASb=3&Nx=N<5(>46ju8@A69FXC9ZKS$-`xoIeV8%andEuy#JohvrG=Ee53G= zV);a{HeoietzmEibhZ`?>DE$grF+|Gc0H=mKn^t0@NIN(JDuBsKJr95;$n!4v6npw ztXqDAPIqU;%7YBE?6uS6J#=R;-Pt#zJN!zfgEBf1I_RSGWusEgs8ld2YerGI&sV8hPn8tXCf^yj zT1HeFl%tY{IK*0oLMk}`4YzUbAZgZ3avdU_Oj4I#ZQYteO%utp znYhUmS)_=trPTEnldP1)sb&n%y#Kb3DU{Y%>N;DUpB?01q9rb-MT*v3j{zl9{6~Tu zJN_Lc+<;B6QrvkIMHs?-(tZ(+@!Wk3#QjX42YC7p`gtc4={Q+;7ejD2Jw8DMPNJXx zJs9BLDEB6~H^u(#>>p=;D(7w^Qv3;&M#{$ol1M!)nu!yOw1lUK^@i^F&Q=K_&LJ?4 z+I#|-vyj1z7?5JY*a0#J1bo~%B_I7I_X7;Gum z;vOYW;Xx%G5c^QdwMV%7G~IiY>G>GXjbI+m@#NzK@CmHKlhiRn5YJJ|)2u7cFm0b@ zT0TdvKhMhZ0s(xHA$W< tables = null; + + if (dbVendor.equals("oracle")) { + tables = getOracleTableNames(conn); + } + else { + tables = getTableNames(conn); + } + + if (outputFormat.equals("xml")) { + printXML(response, tables); + } + else { + printHTML(response, tables); + } + } + catch(Exception e) { + printError(response, e.getMessage()); + } + finally { + DatabaseUtil.close(conn); + } + + } // end doGet + + private static void printHTML(HttpServletResponse response, + List tables) + throws Exception { + response.setContentType("text/html"); + PrintWriter out = response.getWriter(); + StringBuilder buffer = new StringBuilder(); + buffer.append(""); + buffer.append(""); + for (int i=0; i < tables.size(); i++) { + buffer.append(""); + } + buffer.append("
Table Name
"); + buffer.append(tables.get(i)); + buffer.append("
"); + out.println(buffer.toString()); + } + private static void printXML(HttpServletResponse response, + List tables) + throws Exception { + response.setContentType("text/xml"); + PrintWriter out = response.getWriter(); + StringBuilder buffer = new StringBuilder(); + buffer.append(""); + buffer.append(""); + for (int i=0; i < tables.size(); i++) { + buffer.append(""); + buffer.append(tables.get(i)); + buffer.append(""); + } + buffer.append(""); + out.println(buffer.toString()); + } + + private static void printError(HttpServletResponse response, + String message) { + try { + PrintWriter out = response.getWriter(); + StringBuffer buffer = new StringBuffer(); + buffer.append(""); + buffer.append(message); + buffer.append(""); + out.println(buffer); + } + catch(Exception ignore) { + } + } + + + /** + * Get the Oracle table names for a given connection object. + * If you use the getTableNames() for an Oracle database, you + * will get lots of auxiliary tables, which belong to the user, + * but user is not interested in seeing them. + * + * @param conn the Connection object + * @return the list of table names as a List. + * @exception Failed to get the table names from the database. + */ + public static List getOracleTableNames(Connection conn) + throws Exception { + Statement stmt = null; + ResultSet rs = null; + try { + stmt = conn.createStatement(); + rs = stmt.executeQuery(ORACLE_TABLES); + if (rs == null) { + return null; + } + + List list = new ArrayList(); + while (rs.next()) { + String tableName = DatabaseUtil.getTrimmedString(rs, 1); + System.out.println("tableName="+tableName); + if (tableName != null) { + list.add(tableName); + } + } + + return list; + } + finally { + DatabaseUtil.close(rs); + DatabaseUtil.close(stmt); + } + } + + + /** + * Get the table names for a given connection object. + * @param conn the Connection object + * @return the list of table names as a List. + * @exception Failed to get the table names from the database. + */ + public static List getTableNames(Connection conn) + throws Exception { + ResultSet rs = null; + try { + DatabaseMetaData meta = conn.getMetaData(); + if (meta == null) { + return null; + } + + rs = meta.getTables(null, null, null, DB_TABLE_TYPES); + if (rs == null) { + return null; + } + + List list = new ArrayList(); + System.out.println("getTableNames(): --------------"); + while (rs.next()) { + String tableName = + DatabaseUtil.getTrimmedString(rs, COLUMN_NAME_TABLE_NAME); + System.out.println("tableName="+tableName); + if (tableName != null) { + list.add(tableName); + } + } + System.out.println("--------------"); + return list; + } + finally { + DatabaseUtil.close(rs); + } + } +} diff --git a/sourceMetadata/Chapter08/GetTablesAndViews.class b/sourceMetadata/Chapter08/GetTablesAndViews.class new file mode 100644 index 0000000000000000000000000000000000000000..4c0076f4f3453c0f358f498e888a3bb09fd6785e GIT binary patch literal 5264 zcmbVQX<$^<75-kBQY;v8{Mqn5)!FGv4z&QcCWRIZSB7A+n=`Iy>BL&EEL*5@7#Otx%Zs& zo#oz{7ytF_^8i-kA6_(LmxhE7yRpZMawIkMd67a|Lq^Q^da)6f_}Cg8L9<@;<9ZDP zVlpT`H>kMLi&=P+hMRo28MlbfJ{52FVy-y-RzcsQ;jKR0hTDC38{Y229k^3`-l5_y z4fp!62=7$!E)DmI;r$vO(D0zx_iis9!owOK(eS8-_h@)b!+SNnPs4r{2fSD%G#nK4 z{Te!%+>x8b(w+tKyh~d2Q`=4J}PQoptpsO&vXT(Z-&x=B6zj3j8g*jeaAXG*Uam z9gdYq?W|TXy&;{l9V6v*8Of~4?Tz*B*3q3ko!y(7xPA7vsrJupXlvQr8tsYJwdQon zp@JzE#6b#5B8gPOsZ}toVtJPWPeVFRy)#=9DKnbw>ou)Tqc=%TaXfvw=_qKgka`Eg zwrTYzO((p|aWdhJ{B*dCc5`pmw4Lg+irE?ZYE}!a-ll<=nQ;QtIu#$yrAPV_$(P|>A#LsIIY7#uZ}o+70i#eh1~iIwY7(2d4)E#ZH_kT z=)rX=KBwdJc##=C(3jM)9ouwVjcqKUu>u^;KOJ8Xx=S5%K%{nGQpFc_dS ztK+Nqnu3*)&i2|!=f+xzQ&t%nM~YefwVPoLFDl=6~EB&OZ-Y?@UO+^H>^A9 zgbeLQ!`{U{r{cFF?2P^I@OvG9z#nz|34hknil~ae==dxC#)wH(@;(rPe;?(z7eTRH z<_#beQ_G}^Rj^QKK6B@vB#^riMvE(-mWgz@xvhYE@qa%zccU;$>^PeYi%>fvX!*uB zu2oL%%XEp?YoCHS6}g^RxIw|<-Lc+qyf@rsT7&h5orsM!(N-g6>=de|Q}Y;G!SY-y zEj%fA_=Gmhw#5t4NV3e%FWl57^QLIBPjj}dX{l=Ap3RzjjZFOMFhw@KX1?gAez zB}OL02Cg7f=wSYsNdd`qO!3+o%VcIT8w3rq20O$vV^&_9#D%Q!;!;Kvh8d2yUFVJy zZ_e?#$3Lbb&t;p~W!OL(YnD zDd)U1IKBXF1^foiHx8^VdqwK z!zKruiV{#(I|IG0rz6TJ@oIRA^%b_3WkQT zYzP%&IZ#VvfO^KffulyuLle>3Kx8gw5^iLgH4}#`U^2ZNrs0i5=w>2x8&~dT(h0vk z%%EAghNB`}OYixFpX~kesl8v}T3;#1Ie8zH8-(|Te$p?3I1!VTf-Aibi_w|9@1*ye z>3tWy-$L)V()(`uel>mEMsKd6_t(<~O7HobhIojw>mwc>($Hwk zS25D4T1>U)*OPT^@uFW3Z~;MjzpO*MJc~~p~9k(Hvc|xn95lu zaX%`UjFlKb5I0bYzqxY2|C3Y|yOb8CmFm~Bg;e@49l^RHv<6ROrVV$rtZ zRKA2L3L3`_NnLlg6J@Ywif|_-?}Cp=&cQvHk9)aqKk+}nDm}>E_tCBUS)~skf(MzO z4>2YW6WK=@smFNsen#a0oj%CZ_cJO7SfK|e#Uw^x_&d}EMkz+I1SYGr5SBNx5{ZV7 z&5rJb4hI!Qc@lLas4pg71q*qIn4%J*rIr4MVKj=q*d*u_AiYeG#HkV>IUqP5x;>ML z1Dwy;3A&QWC1{ey3t9-$ tablesAndViews = null; + + if (dbVendor.equals("oracle")) { + tablesAndViews = getOracleTablesAndViews(conn); + } + else { + tablesAndViews = getTablesAndViews(conn); + } + + if (tablesAndViews == null) { + printError(response, "NO-TABLES-OR-VIEWS-FOUND"); + return; + } + + if (outputFormat.equals("xml")) { + printXML(response, tablesAndViews); + } + else { + printHTML(response, tablesAndViews); + } + } + catch(Exception e) { + printError(response, e.getMessage()); + } + finally { + DatabaseUtil.close(conn); + } + + } // end doGet + + private static void printHTML(HttpServletResponse response, + Map tablesAndViews) + throws Exception { + response.setContentType("text/html"); + PrintWriter out = response.getWriter(); + StringBuilder buffer = new StringBuilder(); + buffer.append(""); + buffer.append(""); + for (Map.Entry e : tablesAndViews.entrySet()) { + buffer.append(""); + } + buffer.append("
Table/View NameType
"); + buffer.append(e.getKey()); + buffer.append(""); + buffer.append(e.getValue()); + buffer.append("
"); + out.println(buffer.toString()); + } + private static void printXML(HttpServletResponse response, + Map tablesAndViews) + throws Exception { + response.setContentType("text/xml"); + PrintWriter out = response.getWriter(); + StringBuilder buffer = new StringBuilder(); + buffer.append(""); + buffer.append(""); + for (Map.Entry e : tablesAndViews.entrySet()) { + buffer.append(""); + buffer.append(e.getKey()); + buffer.append(""); + } + /* + buffer.append("BIG_SALARY"); + buffer.append("BONUS"); + buffer.append("EMP"); + buffer.append("DEPT"); + buffer.append("MY_VIEW"); + buffer.append("MYTABLE"); + buffer.append("SALGRADE"); + */ + + buffer.append(""); + out.println(buffer.toString()); + } + + private static void printError(HttpServletResponse response, + String message) { + try { + PrintWriter out = response.getWriter(); + StringBuffer buffer = new StringBuffer(); + buffer.append(""); + buffer.append(message); + buffer.append(""); + out.println(buffer); + } + catch(Exception ignore) { + } + } + + + /** + * Get the Oracle table names for a given connection object. + * If you use the getTableNames() for an Oracle database, you + * will get lots of auxiliary tables, which belong to the user, + * but user is not interested in seeing them. + * + * @param conn the Connection object + * @return the list of table names as a List. + * @exception Failed to get the table names from the database. + */ + public static Map getOracleTablesAndViews(Connection conn) + throws Exception { + Statement stmt = null; + ResultSet rs = null; + try { + stmt = conn.createStatement(); + rs = stmt.executeQuery(ORACLE_TABLES_AND_VIEWS); + if (rs == null) { + return null; + } + + Map list = new HashMap(); + while (rs.next()) { + String name = DatabaseUtil.getTrimmedString(rs, 1); + String type = DatabaseUtil.getTrimmedString(rs, 2); + //System.out.println("name="+name); + if (name != null) { + list.put(name, type); + } + } + + return list; + } + finally { + DatabaseUtil.close(rs); + DatabaseUtil.close(stmt); + } + } + + + /** + * Get the table names for a given connection object. + * @param conn the Connection object + * @return the list of table names as a List. + * @exception Failed to get the table names from the database. + */ + public static Map getTablesAndViews(Connection conn) + throws Exception { + ResultSet rs = null; + try { + DatabaseMetaData meta = conn.getMetaData(); + if (meta == null) { + return null; + } + + rs = meta.getTables(null, null, null, DB_TABLE_AND_VIEW_TYPES); + if (rs == null) { + return null; + } + + Map list = new HashMap(); + while (rs.next()) { + String name = + DatabaseUtil.getTrimmedString(rs, COLUMN_NAME_TABLE_NAME); + String type = + DatabaseUtil.getTrimmedString(rs, COLUMN_NAME_TABLE_TYPE); + if (name != null) { + list.put(name, type); + } + } + return list; + } + finally { + DatabaseUtil.close(rs); + } + } +} diff --git a/sourceMetadata/Chapter08/GetViews.class b/sourceMetadata/Chapter08/GetViews.class new file mode 100644 index 0000000000000000000000000000000000000000..71f19c6c31f5cc4c5b2ea3759c90431671cc0d45 GIT binary patch literal 4769 zcmbVQ`9oCK75**`yvOheb`%wjW+W~kjH6973d0Z(5=mJU5HySU7#=uwHs8EK&^9I} zsg1E|n>KAs(q?HInxu(}79lp#ZZS>MJ>B>Hzi9g1_hw*NtWEjhp1YoV&Ue0Z?i=3u z_v>#0*oc3*(STkRp#t>5aAP_8RSdYXA7K>-PDqdFcih{2zcvV1aYp>hZ z+}P9A)Y#o2;AuXf597Gg?#8Uc>Cvdn265 z?Tg=TSOV>3w)P=^(l7@jhUMRHSqcAkHXY7HyKyjOB(3UeZc8TUhfytWbvF)$jD!{D zgo4);oEFGW&|PbLXG^m{^|kLzD|0+gS>cGkIZPv@^8AkQKuot%CcS9;e>DYWV;Z!z ztG1oHrI~KK+i03`Q=sMp-jp3~`{QO*w-kIs!x%1bB5pgUVH^`0?!w&~_Tp~Ra3~tlup7HHbYho+ z*EL+kH_7U$Oqe8#hBt6t!yeqpC|kymBx5w9;7tvea9P8*@NI#`QwN!7e7+)V+}vSPX%g| zMubfD#(NJ?^vJus{boGsO|gdbII~Ibq5XzwWcFCY3Bz0CT`TM0S_MDT@N>K;neYqQ z{4zraJJIV*Qy-SuuHaW1evRK~_$_{?;P)E-fIpHM(j^(48U=sS@Mp=lzu>PLwxdbG z-!%Lk{}5P_P5H9&Dz9(aAA{6cSI^2U>!-ZnpY(d#4j+rBG?%f-qy@D~6t7+@XKhH= z&`E}891X|)O>J4TtN**+bPaYAd53P&c}vD_O}c(eD>kz$8$ID;6BSrkmM$&X2Lx6g z2=)5=di`C7Ib5$N!=b5K)S}1q0eMv+@tm3#D8KsEGpZSx$tOgQu-+ACA8NDdQ(ewv zFO~+_!Eex+EPB$|#gflQDinz)S(uhwrB2GHhIX|W$t0~L9@m1=c~%(er0tDm#H>zI zbB1NGVX=u4P?o$5P;%?!JQaIvcc;yg)5eeyN?FFv6zL~Wc6D3j!FD5=idY?n zMRkj_XfZV}!<4-Xi6lwLTfPM_u(zD@!KHoGldriH-rY+N&$(qcHv)KoI*+ss8) zP3e_<5}AfQb3iZoDPgY)tr%;eMdI2(+FZEKdT$~vtk~Wq7k=2 z;C7C3;OCenp8ch`BWu1ED);bPg>4I0ms1ML+;tZq&axxW$~MoQEMnV+9aP7yB9Bt# z+F{XJ;mMi6yc~YaxT;(gp4`bnZi#Cgd99)Q6r*Hhpu zRF>q8L*s(oDdh5XBUn-8sw{DhVg5KiBHZK38BTeAIn2KgTvv>jv!O zZ?!PTQH~RogOtO#h5IBvIcP@*-10k(;7ce^Q|3|*tn+v#upkHPCa{nwUqtbq3s}_Z z^DG|2l5U@;M2dNvUB#}72`m+O9&3G`W%gP{v1Hx&_kN-Be`@^s+Yf(4esniCC$l~U-b@>!cCdS zQ^!QJXyNti1)3{7{t0YgVpU#2k!Y3lRk@Rc+)K2?#fp%kHLGyI zmMQ-0K#m>%_7ZMzoI|?1FoXh9ejyHH36AjG2?pX3rqD^AzL$O;WlG#f=H1UQ9HYk% z(EEolfaBDC0x|A2xi`iB5%!O=Ka+F!5GnrjNh9TB0!gGE7tO?pMOwmBzd}k_! z5Tgi8peC09W-VkeBSxO!7`8I4Z0t5ycxuOS>jweviqug@9RyL{Y6EC@2%fAyMRWrE z|4ErG*VA1&K8Z(d>44ae63#ur-A~fJr? zoB6MiAYNo@j*#y!vGTl30AFEnUM2jm5#H0hYZMQ2|4GWnC})GIl9HLyzS`zHQ0RIC a%lFLl)OVaiV5(|3C4K?pzK_P{K>rUCgw-Yh literal 0 HcmV?d00001 diff --git a/sourceMetadata/Chapter08/GetViews.java b/sourceMetadata/Chapter08/GetViews.java new file mode 100644 index 0000000..9e6273a --- /dev/null +++ b/sourceMetadata/Chapter08/GetViews.java @@ -0,0 +1,184 @@ +import java.io.PrintWriter; +import java.io.IOException; + +import java.sql.*; +import javax.servlet.*; +import javax.servlet.http.*; + +import java.util.List; +import java.util.ArrayList; + +import jcb.util.DatabaseUtil; +import jcb.db.VeryBasicConnectionManager; +import jcb.meta.DatabaseMetaDataTool; + +public class GetViews extends HttpServlet { + + private static final String ORACLE_VIEWS = + "select object_name from user_objects where object_type = 'VIEW'"; + private static final String[] DB_VIEW_TYPES = + { "VIEW" }; + private static final String COLUMN_NAME_VIEW_NAME = + "TABLE_NAME"; + + public void doGet(HttpServletRequest request, + HttpServletResponse response) + throws ServletException, IOException { + Connection conn = null; + try { + String dbVendor = request.getParameter("vendor").trim(); + String outputFormat = request.getParameter("format").trim(); + conn = VeryBasicConnectionManager.getConnection(dbVendor); + List views = null; + + if (dbVendor.equals("oracle")) { + views = getOracleViewNames(conn); + } + else { + views = getViewNames(conn); + } + + if (outputFormat.equals("xml")) { + printXML(response, views); + } + else { + printHTML(response, views); + } + } + catch(Exception e) { + printError(response, e.getMessage()); + } + finally { + DatabaseUtil.close(conn); + } + + } // end doGet + + private static void printHTML(HttpServletResponse response, + List tables) + throws Exception { + response.setContentType("text/html"); + PrintWriter out = response.getWriter(); + StringBuilder buffer = new StringBuilder(); + buffer.append(""); + buffer.append(""); + for (int i=0; i < tables.size(); i++) { + buffer.append(""); + } + buffer.append("
View Name
"); + buffer.append(tables.get(i)); + buffer.append("
"); + out.println(buffer.toString()); + } + private static void printXML(HttpServletResponse response, + List tables) + throws Exception { + response.setContentType("text/xml"); + PrintWriter out = response.getWriter(); + StringBuilder buffer = new StringBuilder(); + buffer.append(""); + buffer.append(""); + for (int i=0; i < tables.size(); i++) { + buffer.append(""); + buffer.append(tables.get(i)); + buffer.append(""); + } + buffer.append(""); + out.println(buffer.toString()); + } + + private static void printError(HttpServletResponse response, + String message) { + try { + PrintWriter out = response.getWriter(); + StringBuffer buffer = new StringBuffer(); + buffer.append(""); + buffer.append(message); + buffer.append(""); + out.println(buffer); + } + catch(Exception ignore) { + } + } + + + /** + * Get the Oracle table names for a given connection object. + * If you use the getViewNames() for an Oracle database, you + * will get lots of auxiliary tables, which belong to the user, + * but user is not interested in seeing them. + * + * @param conn the Connection object + * @return the list of table names as a List. + * @exception Failed to get the table names from the database. + */ + public static List getOracleViewNames(Connection conn) + throws Exception { + Statement stmt = null; + ResultSet rs = null; + try { + stmt = conn.createStatement(); + rs = stmt.executeQuery(ORACLE_VIEWS); + if (rs == null) { + return null; + } + + List list = new ArrayList(); + while (rs.next()) { + String viewName = DatabaseUtil.getTrimmedString(rs, 1); + System.out.println("viewName="+viewName); + if (viewName != null) { + list.add(viewName); + } + } + + return list; + } + finally { + DatabaseUtil.close(rs); + DatabaseUtil.close(stmt); + } + } + + + /** + * Get the table names for a given connection object. + * @param conn the Connection object + * @return the list of table names as a List. + * @exception Failed to get the table names from the database. + */ + public static List getViewNames(Connection conn) + throws Exception { + ResultSet rs = null; + try { + DatabaseMetaData meta = conn.getMetaData(); + if (meta == null) { + return null; + } + + rs = meta.getTables(null, null, null, DB_VIEW_TYPES); + if (rs == null) { + return null; + } + + List list = new ArrayList(); + System.out.println("getViewNames(): --------------"); + while (rs.next()) { + String viewName = + DatabaseUtil.getTrimmedString(rs, COLUMN_NAME_VIEW_NAME); + System.out.println("viewName="+viewName); + if (viewName != null) { + list.add(viewName); + } + } + System.out.println("--------------"); + return list; + } + finally { + DatabaseUtil.close(rs); + } + } +} + + + diff --git a/sourceMetadata/Chapter08/MyDatabaseServlet.class b/sourceMetadata/Chapter08/MyDatabaseServlet.class new file mode 100644 index 0000000000000000000000000000000000000000..52da80b1a3ac774ca8fc30f11b0e79ed5132343e GIT binary patch literal 2712 zcmb7GS#uLd5dOwUS|P6i3w$U*5SJq#Vj&y>Sr)+u*ue)_#smlnD`~Lhth7Q}Id%fM zA@}i`UqDsfcoBA}O5XF3pOoaAUCRgNNNTHkW_o)1_`0WO|NQ&6-vJ!M&mqKcI*2nt zBpT6+WC(pog>V*cHsT!m8!>>v5MIMj2p|QI;vF@;8N|Elu69ATny2)sWL5 z1p>)@G4G@Vw!}K81$+Z`j@<2|`Jx=J7BaFtWo9gL{5kuAbOa`2qjToGxnNXedESza zG3z)bW0)lEF(&1ms;oG@FBPkl>|#asDyyNPg{&+&c``KI)-WTmtyInzok>}#T25LS zKKpXRD;izPM&*uWtRDBQxGIOrWxFiU_dnHHW^u+yJ9KKsQSR+xx+S<2w`>XVP$ENF@y~B33NJ z)9}5HAMm4qzCK;QW~pSspl$h8zU3zxQAb?cjbc7 z@fqn{GRuV4QP^~N744)y7aN*P=` zryAM%oizv5PW!qu>wa{YJjYgqFi7a_)=V_X4)T7S@Fe2I!8Qzys9IBWId~p;{VYJ z_qNlEJv|i*7tq{}ZxxkCoBdJPZ{Sa4=2+Ei@7T{5IL5~u@PW0A zF4AtU_Hq;){aueC9&tioNdqpkku;7YXi%b}nd4UO-3vF2i-b=k{2~$P4sTh8uK_jq z6Iw)DLLd={1eT!*B>WM7d>O$8Bz!#)-x9Ve5{mej&=?6UL4Sx739Toh)v#>|+c#~t zC4x`!BEdf%(SIFhaFM?iYMiA*7cuRQvzT*7FN6%*xwivb__Gi|n6B^Si5C7sv?7W& zV$hD`T%Ex_q{tZ{M#DHjZM*rSvWGhN;RgA)$d}~La&2?%aJ|U&T^xepLe+qy{7DL_ z_sfF{f6=POy$4;(*dZ|X1kKkTBRn1t@2p|h)p)o?4c*IV75D||Zr?K68gRQLd6NhpCH1cuY`Bku&2dW!`|?#oJIU3?yM!Cc>B1lA*!@K{O8wrc)yzU#A`TE z!@;$*o+4^s"); + buffer.append(""); + while (rs.next()) { + int id = rs.getInt(1); + String name = rs.getString(2); + int age = rs.getInt(3); + buffer.append(""); + } + buffer.append("
idnameage
"+id+""+name+""+age+"
"); + out.println(buffer.toString()); + } + + private static void printError(HttpServletResponse response, + String message) { + try { + PrintWriter out = response.getWriter(); + StringBuffer buffer = new StringBuffer(); + buffer.append(""); + buffer.append(message); + buffer.append(""); + out.println(buffer); + } + catch(Exception ignore) { + } + } +} diff --git a/sourceMetadata/Chapter09/GetBestRowIdentifier.class b/sourceMetadata/Chapter09/GetBestRowIdentifier.class new file mode 100644 index 0000000000000000000000000000000000000000..ecdbb90ab3c179ef8a7a665c80f2429868acd4fa GIT binary patch literal 5148 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 DpQ~F! literal 0 HcmV?d00001 diff --git a/sourceMetadata/Chapter09/GetBestRowIdentifier.java b/sourceMetadata/Chapter09/GetBestRowIdentifier.java new file mode 100644 index 0000000..5af194b --- /dev/null +++ b/sourceMetadata/Chapter09/GetBestRowIdentifier.java @@ -0,0 +1,229 @@ +import java.sql.*; +import javax.servlet.*; +import javax.servlet.http.*; +import java.io.PrintWriter; +import java.io.IOException; + +import jcb.util.DatabaseUtil; +import jcb.db.VeryBasicConnectionManager; + + +public class GetBestRowIdentifier extends HttpServlet { + public void doGet(HttpServletRequest request, + HttpServletResponse response) + throws ServletException, IOException { + ResultSet bestRowIdentifier = null; + Connection conn = null; + + try { + String dbVendor = request.getParameter("vendor").trim(); + String table = request.getParameter("table").trim(); + String outputFormat = request.getParameter("format").trim(); + String scope = request.getParameter("scope").trim(); + String nullable = request.getParameter("nullable").trim(); + + conn = VeryBasicConnectionManager.getConnection(dbVendor); + if (dbVendor.equals("mysql")) { + bestRowIdentifier = getBestRowIdentifier(conn, conn.getCatalog(), // catalog, + "", // schema + table, // table + scope, // scope + nullable); + } + else if (dbVendor.equals("oracle")) { + String schema = request.getParameter("schema").trim(); + + bestRowIdentifier = getBestRowIdentifier(conn, conn.getCatalog(), // catalog, + schema, // schema + table, // table + scope, // scope + nullable); + } + else { + printError(response, "unknown db vendor"); + return; + } + if (outputFormat.equals("xml")) { + printXML(response, bestRowIdentifier); + } + else { + printHTML(response, bestRowIdentifier); + } + } + catch (Exception e) { + e.printStackTrace(); + printError(response, e.getMessage()); + } + finally { + DatabaseUtil.close(bestRowIdentifier); + DatabaseUtil.close(conn); + } + } // end doGet + + private static void printHTML(HttpServletResponse response, + ResultSet bestRowIdentifier) + throws Exception { + response.setContentType("text/html"); + PrintWriter out = response.getWriter(); + StringBuilder buffer = new StringBuilder(); + + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + while (bestRowIdentifier.next()) { + buffer.append(""); + } + buffer.append("
ScopeColumn NameData TypeType NameColumn SizeDecimal DigitsPseudo Column
"); + short scope = bestRowIdentifier.getShort("SCOPE"); + + buffer.append(getScope(scope)); + buffer.append(""); + buffer.append(bestRowIdentifier.getString("COLUMN_NAME")); + buffer.append(""); + buffer.append(bestRowIdentifier.getInt("DATA_TYPE")); + buffer.append(""); + buffer.append(bestRowIdentifier.getString("TYPE_NAME")); + buffer.append(""); + buffer.append(bestRowIdentifier.getInt("COLUMN_SIZE")); + buffer.append(""); + buffer.append(bestRowIdentifier.getShort("DECIMAL_DIGITS")); + buffer.append(""); + short pseudoColumn = bestRowIdentifier.getShort("PSEUDO_COLUMN"); + + buffer.append(getPseudoColumn(pseudoColumn)); + buffer.append("
"); + out.println(buffer.toString()); + } + + private static void printXML(HttpServletResponse response, + ResultSet bestRowIdentifier) + throws Exception { + response.setContentType("text/xml"); + PrintWriter out = response.getWriter(); + StringBuilder buffer = new StringBuilder(); + + // buffer.append(""); + buffer.append(""); + buffer.append(""); + while (bestRowIdentifier.next()) { + buffer.append(""); + short scope = bestRowIdentifier.getShort("SCOPE"); + + buffer.append(getScope(scope)); + buffer.append(""); + buffer.append(bestRowIdentifier.getString("COLUMN_NAME")); + buffer.append(""); + buffer.append(bestRowIdentifier.getInt("DATA_TYPE")); + buffer.append(""); + buffer.append(bestRowIdentifier.getString("TYPE_NAME")); + buffer.append(""); + buffer.append(bestRowIdentifier.getInt("COLUMN_SIZE")); + buffer.append(""); + buffer.append(bestRowIdentifier.getShort("DECIMAL_DIGITS")); + buffer.append(""); + short pseudoColumn = bestRowIdentifier.getShort("PSEUDO_COLUMN"); + + buffer.append(getPseudoColumn(pseudoColumn)); + buffer.append(""); + } + buffer.append(""); + out.println(buffer.toString()); + } + + private static void printError(HttpServletResponse response, + String message) { + try { + PrintWriter out = response.getWriter(); + StringBuffer buffer = new StringBuffer(); + + buffer.append(""); + buffer.append(message); + buffer.append(""); + out.println(buffer); + } + catch (Exception ignore) { + } + } + + /** + * Retrieves a description of the given table's BestRowIdentifier. + * @param conn the Connection object + * @param catalog a catalog. + * @param schema a schema. + * @param table name of a table in the database. + * @param scope the scope of interest; use same values as SCOPE + * @param nullable include bestRowIdentifier that are nullable. + * @return the BestRowIdentifier as a ResultSet object + * @exception Failed to get the table's bestRowIdentifier. + */ + public static ResultSet getBestRowIdentifier(Connection conn, + String catalog, + String schema, + String table, + String scope, + String nullable) + throws Exception { + if ((table == null) || (table.length() == 0)) { + return null; + } + DatabaseMetaData meta = conn.getMetaData(); + + if (meta == null) { + return null; + } + int theScope = DatabaseMetaData.bestRowSession; + + if (scope.equals("bestRowTemporary")) { + theScope = DatabaseMetaData.bestRowTemporary; + } + else if (scope.equals("bestRowTransaction")) { + theScope = DatabaseMetaData.bestRowTransaction; + } + boolean isNullable = false; + + if (nullable.equals("true")) { + isNullable = true; + } + // + // The Oracle database stores its table names as + // Upper-Case; if you pass a table name in lowercase + // characters, it will not work. MySQL database does + // not care if table name is uppercase/lowercase. + // + return meta.getBestRowIdentifier(catalog, schema, table.toUpperCase(), + theScope, isNullable); + } + + public static String getScope(short scope) { + if (scope == DatabaseMetaData.bestRowSession) { + return "bestRowSession"; + } + else if (scope == DatabaseMetaData.bestRowTemporary) { + return "bestRowTemporary"; + } + else if (scope == DatabaseMetaData.bestRowTransaction) { + return "bestRowTransaction"; + } + else { + return "scope is unknown"; + } + } + + public static String getPseudoColumn(short pseudoColumn) { + if (pseudoColumn == DatabaseMetaData.bestRowNotPseudo) { + return "bestRowNotPseudo"; + } + else if (pseudoColumn == DatabaseMetaData.bestRowPseudo) { + return "bestRowPseudo"; + } + else { + return "bestRowUnknown"; + } + } +} + diff --git a/sourceMetadata/Chapter09/GetCatalogs.class b/sourceMetadata/Chapter09/GetCatalogs.class new file mode 100644 index 0000000000000000000000000000000000000000..46a1d5bfb2882b70fb0222957bbc7af3291df25f GIT binary patch literal 3493 zcmbVPX?Gjd8Gf!Jd&bgaL5brikkmF!Vp~=wPMS2aWM#1pcH$*iCI*)jM$%ZwjF!xd zT$?U*q0l8==mvCwE`VETOVXZW>~c=&r}mtF?hoKM^aqqacSceaJ89Z}nRo8?zR&Y+ zbLa2>`qQ5Q4B(F;oWvy+6JbnZDunwnt>SVBk6bX*GKi};d!d|8_Kih}1A zd{v+|Stu3Ul)$#0-YWvZ;d0It*f~)snN!tb#!t6G5!B)O8S~Dqm4cD;Bc}L)guT6KZS^99fR5G*DS&81wd>g*H*Umfg zA%%3gYG=)d3Nqxo81OoTqcZ3kPT`YGnI*H7E87abrs3=OhK6tAI%gNkcF|x~eoMo* z@f{5h;bCUga?#T8UA&}W80R#c#W@Av)9`)#Kw!62s(Z{E383MJxUOLYql}zuF3SWf zS_*!o;bpv{;Z^)tpySp-KNuIP1uJLL?WdD+dn%bJ=T=flSLSYKrfhRh2cayf65((n`fRA7H{b|#ga9ZS`TCv^_^m`N%4nTFT!x`66$8sVXz;}>+) zW;k>tkBs=|1okF%4++OUE{_vW{}R^~{7S~^*B+W9rY}j;}D}8XdR%f?W zA9u1V8z zh?4%emmB@Q%S3TJHm+H6XICmbc^k4?$Mm`})z8@l&)Xe!?=gCpWxMwm5+rC;Dr_$m<%(=}x11P;`lB)8S0Szo5^j;2t~m`>Gl)29F7 zi+aAe(=oQBX05l52}Bx)8nbj_iH+EEB6F*aPOSTBlPhZh;!gHebn)JEk{2kT6+(VG z_&m+g0ZKvH()S+3O}+@6scix@js}rHz}xyErOLIOn2JRL8`u`W8iIqtSfr&fXo&{b z(K;1hhceh2ZHcIBXnPe}f3$TSp;febFJUfgt2j6q?2iW5uwxxN{TXdgkuOo@gPRD_ z+Ifue&L-tN?T#Vs$$32CNgwG&M7Xw#yCT@h8`=ZdgKo5=2YYcG9Yns54E9q;7e=`< zM#>j)kh;1s$MHPnQuQc=-Ma($!|BlLb8LL4V>l)=$S<`^%(agsUC>+A_EFw&Ap zkipwd+MsJLkPbijTj_M(nNF7vv0IAGbRP89w$S;woUYS3BnNk+bB1&VNhd)%Nzxf2 zofLte9&c$QiGtwu8 z#1vaaaPlS(OV7sWBR`Q2qm45cq2Ln1O)z~XnM_kmi)rqg;m$|s`80R&GF9{BKWVy^ zrxwHnjrTJp`u~P7>th}9_>KMz92J;|HBG$_o!E{|F+BzZ?@tF}%!=ay3)PA^3>t*Z^fmS0<&n5rT+|b#Uj5VE~8Ag73z0bBrdf()Z%Ul#u)uK JPHO>N{5SMmYP|pe literal 0 HcmV?d00001 diff --git a/sourceMetadata/Chapter09/GetCatalogs.java b/sourceMetadata/Chapter09/GetCatalogs.java new file mode 100644 index 0000000..1ecd304 --- /dev/null +++ b/sourceMetadata/Chapter09/GetCatalogs.java @@ -0,0 +1,118 @@ +import java.io.PrintWriter; +import java.io.IOException; +import java.sql.*; +import javax.servlet.*; +import javax.servlet.http.*; +import java.util.List; +import java.util.ArrayList; + +import jcb.util.DatabaseUtil; +import jcb.db.VeryBasicConnectionManager; + +public class GetCatalogs extends HttpServlet { + public void doGet(HttpServletRequest request, + HttpServletResponse response) + throws ServletException, IOException { + Connection conn = null; + try { + String dbVendor = request.getParameter("vendor").trim(); + String outputFormat = request.getParameter("format").trim(); + conn = VeryBasicConnectionManager.getConnection(dbVendor); + List catalogs = getCatalogs(conn); + if (outputFormat.equals("xml")) { + printXML(response, catalogs); + } + else { + printHTML(response, catalogs); + } + } + catch(Exception e) { + printError(response, e.getMessage()); + } + finally { + DatabaseUtil.close(conn); + } + } // end doGet + + private static void printHTML(HttpServletResponse response, + List tables) + throws Exception { + response.setContentType("text/html"); + PrintWriter out = response.getWriter(); + StringBuilder buffer = new StringBuilder(); + buffer.append(""); + buffer.append(""); + for (int i=0; i < tables.size(); i++) { + buffer.append(""); + } + buffer.append("
Catalogs
"); + buffer.append(tables.get(i)); + buffer.append("
"); + out.println(buffer.toString()); + } + + private static void printXML(HttpServletResponse response, + List catalogs) + throws Exception { + response.setContentType("text/xml"); + PrintWriter out = response.getWriter(); + StringBuilder buffer = new StringBuilder(); + buffer.append(""); + buffer.append(""); + for (int i=0; i < catalogs.size(); i++) { + buffer.append(""); + buffer.append(catalogs.get(i)); + buffer.append(""); + } + buffer.append(""); + out.println(buffer.toString()); + } + + private static void printError(HttpServletResponse response, + String message) { + try { + PrintWriter out = response.getWriter(); + StringBuffer buffer = new StringBuffer(); + buffer.append(""); + buffer.append(message); + buffer.append(""); + out.println(buffer); + } + catch(Exception ignore) { + } + } + + /** + * Get Catalogs: Retrieves the catalog names available in + * this database. The results are ordered by catalog name. + * + * @param conn the Connection object + * @return list of all catalogs. + * @exception Failed to get the Get Catalogs. + */ + public static List getCatalogs(Connection conn) + throws Exception { + ResultSet catalogs = null; + try { + DatabaseMetaData meta = conn.getMetaData(); + if (meta == null) { + return null; + } + catalogs = meta.getCatalogs(); + if (catalogs == null) { + return null; + } + List list = new ArrayList(); + while (catalogs.next()) { + String catalog = catalogs.getString(1); //"TABLE_CATALOG" + if (catalog != null) { + list.add(catalog); + } + } + return list; + } + finally { + DatabaseUtil.close(catalogs); + } + } +} diff --git a/sourceMetadata/Chapter09/GetColumnPrivileges.class b/sourceMetadata/Chapter09/GetColumnPrivileges.class new file mode 100644 index 0000000000000000000000000000000000000000..823ea5aff9a14594d864b9a38933e4d5c740a894 GIT binary patch literal 4516 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 literal 0 HcmV?d00001 diff --git a/sourceMetadata/Chapter09/GetColumnPrivileges.java b/sourceMetadata/Chapter09/GetColumnPrivileges.java new file mode 100644 index 0000000..970ae39 --- /dev/null +++ b/sourceMetadata/Chapter09/GetColumnPrivileges.java @@ -0,0 +1,195 @@ +import java.sql.*; +import javax.servlet.*; +import javax.servlet.http.*; +import java.io.PrintWriter; +import java.io.IOException; + +import jcb.util.DatabaseUtil; +import jcb.db.VeryBasicConnectionManager; + + +public class GetColumnPrivileges extends HttpServlet { + public void doGet(HttpServletRequest request, + HttpServletResponse response) + throws ServletException, IOException { + ResultSet columnPrivileges = null; + Connection conn = null; + + try { + String dbVendor = request.getParameter("vendor").trim(); + String outputFormat = request.getParameter("format").trim(); + String table = request.getParameter("table").trim(); + + conn = VeryBasicConnectionManager.getConnection(dbVendor); + if (dbVendor.equals("mysql")) { + columnPrivileges = getColumnPrivileges(conn, conn.getCatalog(), // catalog, + null, // schema + table, // table + "%"); // all columns + } + else if (dbVendor.equals("oracle")) { + String schema = request.getParameter("schema").trim(); + + columnPrivileges = getColumnPrivileges(conn, conn.getCatalog(), // catalog, + schema, // schema + table, // table + "%"); // all columns + } + else { + printError(response, "unknown db vendor"); + return; + } + if (outputFormat.equals("xml")) { + printXML(response, columnPrivileges); + } + else { + printHTML(response, columnPrivileges); + } + } + catch (Exception e) { + e.printStackTrace(); + printError(response, e.getMessage()); + } + finally { + DatabaseUtil.close(columnPrivileges); + DatabaseUtil.close(conn); + } + } // end doGet + + private static void printHTML(HttpServletResponse response, + ResultSet columnPrivileges) + throws Exception { + response.setContentType("text/html"); + PrintWriter out = response.getWriter(); + StringBuilder buffer = new StringBuilder(); + + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + while (columnPrivileges.next()) { + buffer.append(""); + } + buffer.append("
CatalogSchemaTable NameColumn NameGrantorGranteePrivilegeIs Grantable
"); + buffer.append(columnPrivileges.getString("TABLE_CAT")); + buffer.append(""); + buffer.append(columnPrivileges.getString("TABLE_SCHEM")); + buffer.append(""); + buffer.append(columnPrivileges.getString("TABLE_NAME")); + buffer.append(""); + buffer.append(columnPrivileges.getString("COLUMN_NAME")); + buffer.append(""); + buffer.append(columnPrivileges.getString("GRANTOR")); + buffer.append(""); + buffer.append(columnPrivileges.getString("GRANTEE")); + buffer.append(""); + buffer.append(columnPrivileges.getString("PRIVILEGE")); + buffer.append(""); + buffer.append(columnPrivileges.getString("IS_GRANTABLE")); + buffer.append("
"); + out.println(buffer.toString()); + } + + private static void printXML(HttpServletResponse response, + ResultSet columnPrivileges) + throws Exception { + response.setContentType("text/xml"); + PrintWriter out = response.getWriter(); + StringBuilder buffer = new StringBuilder(); + + buffer.append(""); + buffer.append(""); + while (columnPrivileges.next()) { + buffer.append(""); + buffer.append(columnPrivileges.getString("TABLE_CAT")); + buffer.append(""); + buffer.append(columnPrivileges.getString("TABLE_SCHEM")); + buffer.append(""); + buffer.append(columnPrivileges.getString("TABLE_NAME")); + buffer.append(""); + buffer.append(columnPrivileges.getString("COLUMN_NAME")); + buffer.append(""); + buffer.append(columnPrivileges.getString("GRANTOR")); + buffer.append(""); + buffer.append(columnPrivileges.getString("GRANTEE")); + buffer.append(""); + buffer.append(columnPrivileges.getString("PRIVILEGE")); + buffer.append(""); + buffer.append(columnPrivileges.getString("IS_GRANTABLE")); + buffer.append(""); + } + buffer.append(""); + out.println(buffer.toString()); + } + + private static void printError(HttpServletResponse response, + String message) { + try { + PrintWriter out = response.getWriter(); + StringBuffer buffer = new StringBuffer(); + + buffer.append(""); + buffer.append(message); + buffer.append(""); + out.println(buffer); + } + catch (Exception ignore) { + } + } + + /** + * Get Column Privileges: retrieves a description of the access + * rights for each table available in a catalog. Note that a + * table privilege applies to one or more columnPrivileges in the table. + * It would be wrong to assume that this privilege applies to + * all columnPrivileges (this may be true for some systems but is not + * true for all.) The result is returned as a ResultSet object. + * + * In JDBC, Each privilege description has the following columnPrivileges: + * + * TABLE_CAT String => table catalog (may be null) + * TABLE_SCHEM String => table schema (may be null) + * TABLE_NAME String => table name + * COLUMN_NAME String => column name + * GRANTOR => grantor of access (may be null) + * GRANTEE String => grantee of access + * PRIVILEGE String => name of access (SELECT, INSERT, + * UPDATE, REFERENCES, ...) + * IS_GRANTABLE String => "YES" if grantee is permitted to grant + * to others; "NO" if not; null if unknown + * + * + * @param conn the Connection object + * @param catalog a catalog. + * @param schema a schema. + * @param table a table name + * @param columnNamePattern column name pattern; + * @return a ResultSet object + * @exception Failed to get the Get Column Privileges. + */ + public static ResultSet getColumnPrivileges(Connection conn, + String catalog, + String schema, + String table, + String columnNamePattern) + throws Exception { + if ((table == null) || (table.length() == 0)) { + return null; + } + DatabaseMetaData meta = conn.getMetaData(); + + if (meta == null) { + return null; + } + // The '_' character represents any single character. + // The '%' character represents any sequence of zero + // or more characters. + return meta.getColumnPrivileges(catalog, schema, table, + columnNamePattern); + } +} diff --git a/sourceMetadata/Chapter09/GetExportedKeys.class b/sourceMetadata/Chapter09/GetExportedKeys.class new file mode 100644 index 0000000000000000000000000000000000000000..1f8602c642f6de399f6fd6c9ad9141c3a2224616 GIT binary patch literal 6111 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 literal 0 HcmV?d00001 diff --git a/sourceMetadata/Chapter09/GetExportedKeys.java b/sourceMetadata/Chapter09/GetExportedKeys.java new file mode 100644 index 0000000..845e05b --- /dev/null +++ b/sourceMetadata/Chapter09/GetExportedKeys.java @@ -0,0 +1,273 @@ +import java.sql.*; +import javax.servlet.*; +import javax.servlet.http.*; + +import java.io.PrintWriter; +import java.io.IOException; + +import java.sql.*; +import javax.servlet.*; +import javax.servlet.http.*; + +import jcb.util.DatabaseUtil; +import jcb.db.VeryBasicConnectionManager; + +public class GetExportedKeys extends HttpServlet { + + public void doGet(HttpServletRequest request, + HttpServletResponse response) + throws ServletException, IOException { + Connection conn = null; + ResultSet exportedKeys = null; + try { + String dbVendor = request.getParameter("vendor").trim(); + String outputFormat = request.getParameter("format").trim(); + String table = request.getParameter("table").trim(); + conn = VeryBasicConnectionManager.getConnection(dbVendor); + + if (dbVendor.equals("mysql")) { + String catalog = request.getParameter("catalog").trim(); + exportedKeys = getExportedKeys(conn, + catalog, // catalog, + null, // schema + table); + } + else if (dbVendor.equals("oracle")) { + String schema = request.getParameter("schema").trim(); + exportedKeys = getExportedKeys(conn, + null, // catalog, + schema, // schema + table); + } + else { + printError(response, "unknown db vendor"); + return; + } + + if (outputFormat.equals("xml")) { + printXML(response, exportedKeys); + } + else { + printHTML(response, exportedKeys); + } + + } + catch(Exception e) { + e.printStackTrace(); + printError(response, e.getMessage()); + } + finally { + DatabaseUtil.close(exportedKeys); + DatabaseUtil.close(conn); + } + + } // end doGet + + + private static void printHTML(HttpServletResponse response, + ResultSet exportedKeys) + throws Exception { + response.setContentType("text/html"); + PrintWriter out = response.getWriter(); + StringBuilder buffer = new StringBuilder(); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + while (exportedKeys.next()) { + buffer.append(""); + } + buffer.append("
PK CatalogPK SchemaPK TablePK ColumnFK CatalogFK SchemaFK TableFK ColumnFK Seq.Update RuleDelete RuleFK NamePK NameDeferrability
"); + buffer.append(exportedKeys.getString("PKTABLE_CAT")); + buffer.append(""); + buffer.append(exportedKeys.getString("PKTABLE_SCHEM")); + buffer.append(""); + buffer.append(exportedKeys.getString("PKTABLE_NAME")); + buffer.append(""); + buffer.append(exportedKeys.getString("PKCOLUMN_NAME")); + buffer.append(""); + buffer.append(exportedKeys.getString("FKTABLE_CAT")); + buffer.append(""); + buffer.append(exportedKeys.getString("FKTABLE_SCHEM")); + buffer.append(""); + buffer.append(exportedKeys.getString("FKTABLE_NAME")); + buffer.append(""); + buffer.append(exportedKeys.getString("FKCOLUMN_NAME")); + buffer.append(""); + buffer.append(exportedKeys.getShort("KEY_SEQ")); + buffer.append(""); + short updateRule = exportedKeys.getShort("UPDATE_RULE"); + buffer.append(getUpdateRule(updateRule)); + buffer.append(""); + short deleteRule = exportedKeys.getShort("DELETE_RULE"); + buffer.append(getDeleteRule(deleteRule)); + buffer.append(""); + buffer.append(exportedKeys.getString("FK_NAME")); + buffer.append(""); + buffer.append(exportedKeys.getString("PK_NAME")); + buffer.append(""); + short deferrability = exportedKeys.getShort("DEFERRABILITY"); + buffer.append(getDeferrability(deferrability)); + buffer.append("
"); + out.println(buffer.toString()); + } + + private static void printXML(HttpServletResponse response, + ResultSet exportedKeys) + throws Exception { + response.setContentType("text/xml"); + PrintWriter out = response.getWriter(); + StringBuilder buffer = new StringBuilder(); + buffer.append(""); + buffer.append(""); + while (exportedKeys.next()) { + buffer.append(""); + buffer.append(exportedKeys.getString("PKTABLE_CAT")); + buffer.append(""); + buffer.append(exportedKeys.getString("PKTABLE_SCHEM")); + buffer.append(""); + buffer.append(exportedKeys.getString("PKTABLE_NAME")); + buffer.append(""); + buffer.append(exportedKeys.getString("PKCOLUMN_NAME")); + buffer.append(""); + buffer.append(exportedKeys.getString("FKTABLE_CAT")); + buffer.append(""); + buffer.append(exportedKeys.getString("FKTABLE_SCHEM")); + buffer.append(""); + buffer.append(exportedKeys.getString("FKTABLE_NAME")); + buffer.append(""); + buffer.append(exportedKeys.getString("FKCOLUMN_NAME")); + buffer.append(""); + buffer.append(exportedKeys.getString("KEY_SEQ")); + buffer.append(""); + short updateRule = exportedKeys.getShort("UPDATE_RULE"); + buffer.append(getUpdateRule(updateRule)); + buffer.append(""); + short deleteRule = exportedKeys.getShort("DELETE_RULE"); + buffer.append(getDeleteRule(deleteRule)); + buffer.append(""); + buffer.append(exportedKeys.getString("FK_NAME")); + buffer.append(""); + buffer.append(exportedKeys.getString("PK_NAME")); + buffer.append(""); + short deferrability = exportedKeys.getShort("DEFERRABILITY"); + buffer.append(getDeferrability(deferrability)); + buffer.append(""); + } + buffer.append(""); + out.println(buffer.toString()); + } + + private static void printError(HttpServletResponse response, + String message) { + try { + PrintWriter out = response.getWriter(); + StringBuilder buffer = new StringBuilder(); + buffer.append(""); + buffer.append(message); + buffer.append(""); + out.println(buffer.toString()); + } + catch(Exception ignore) { + } + } + + /** + * Get the stored-procedures names. + * @param conn the Connection object + * @catalog database catalog name + * @schemaPattern database schema pattern + * @procedureNamePattern database procedure name pattern + * @return a table of stored procedures names + * as a ResultSet object. + * Each element of XML document will have the name and + * type of a stored procedure. + * + */ + public static ResultSet getExportedKeys(Connection conn, + String catalog, + String schema, + String table) + throws Exception { + + if (table == null) { + return null; + } + + DatabaseMetaData meta = conn.getMetaData(); + if (meta == null) { + return null; + } + + return meta.getExportedKeys(catalog, schema, table.toUpperCase()); + } + + + private static String getUpdateRule(short updateRule) { + if (updateRule == DatabaseMetaData.importedKeyNoAction) { + return "importedKeyNoAction"; + } + else if (updateRule == DatabaseMetaData.importedKeyCascade) { + return "importedKeyCascade"; + } + else if (updateRule == DatabaseMetaData.importedKeySetNull) { + return "importedKeySetNull"; + } + else if (updateRule == DatabaseMetaData.importedKeySetDefault) { + return "importedKeySetDefault"; + } + else if (updateRule == DatabaseMetaData.importedKeyRestrict) { + return "importedKeyRestrict"; + } + else { + return "nobody knows"; + } + } + + private static String getDeleteRule(short deleteRule) { + if (deleteRule == DatabaseMetaData.importedKeyNoAction) { + return "importedKeyNoAction"; + } + else if (deleteRule == DatabaseMetaData.importedKeyCascade) { + return "importedKeyCascade"; + } + else if (deleteRule == DatabaseMetaData.importedKeySetNull) { + return "importedKeySetNull"; + } + else if (deleteRule == DatabaseMetaData.importedKeyRestrict) { + return "importedKeyRestrict"; + } + else if (deleteRule == DatabaseMetaData.importedKeySetDefault) { + return "importedKeySetDefault"; + } + else { + return "nobody knows"; + } + } + + private static String getDeferrability(short deferrability) { + if (deferrability == DatabaseMetaData.importedKeyInitiallyDeferred) { + return "importedKeyInitiallyDeferred"; + } + else if (deferrability == DatabaseMetaData.importedKeyInitiallyImmediate) { + return "importedKeyInitiallyImmediate"; + } + else if (deferrability == DatabaseMetaData.importedKeyNotDeferrable) { + return "importedKeyNotDeferrable"; + } + else { + return "nobody knows"; + } + } +} \ No newline at end of file diff --git a/sourceMetadata/Chapter09/GetForeignKeys.class b/sourceMetadata/Chapter09/GetForeignKeys.class new file mode 100644 index 0000000000000000000000000000000000000000..8736d9a70cdd944752719a2f9dbdf8698c2bcc2b GIT binary patch literal 6126 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 D;$Tnt literal 0 HcmV?d00001 diff --git a/sourceMetadata/Chapter09/GetForeignKeys.java b/sourceMetadata/Chapter09/GetForeignKeys.java new file mode 100644 index 0000000..203f1af --- /dev/null +++ b/sourceMetadata/Chapter09/GetForeignKeys.java @@ -0,0 +1,270 @@ +import java.sql.*; +import javax.servlet.*; +import javax.servlet.http.*; + +import java.io.PrintWriter; +import java.io.IOException; + +import java.sql.*; +import javax.servlet.*; +import javax.servlet.http.*; + +import jcb.util.DatabaseUtil; +import jcb.db.VeryBasicConnectionManager; + +public class GetForeignKeys extends HttpServlet { + + public void doGet(HttpServletRequest request, + HttpServletResponse response) + throws ServletException, IOException { + Connection conn = null; + ResultSet foreignKeys = null; + try { + String dbVendor = request.getParameter("vendor").trim(); + String outputFormat = request.getParameter("format").trim(); + String table = request.getParameter("table").trim(); + conn = VeryBasicConnectionManager.getConnection(dbVendor); + + if (dbVendor.equals("mysql")) { + String catalog = request.getParameter("catalog").trim(); + foreignKeys = getForeignKeys(conn, + catalog, // catalog, + null, // schema + table); + } + else if (dbVendor.equals("oracle")) { + String schema = request.getParameter("schema").trim(); + foreignKeys = getForeignKeys(conn, + null, // catalog, + schema, // schema + table); + } + else { + printError(response, "unknown db vendor"); + return; + } + + if (outputFormat.equals("xml")) { + printXML(response, foreignKeys); + } + else { + printHTML(response, foreignKeys); + } + + } + catch(Exception e) { + e.printStackTrace(); + printError(response, e.getMessage()); + } + finally { + DatabaseUtil.close(foreignKeys); + DatabaseUtil.close(conn); + } + + } // end doGet + + + private static void printHTML(HttpServletResponse response, + ResultSet foreignKeys) + throws Exception { + response.setContentType("text/html"); + PrintWriter out = response.getWriter(); + StringBuilder buffer = new StringBuilder(); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + while (foreignKeys.next()) { + buffer.append(""); + } + buffer.append("
PK CatalogPK SchemaPK TablePK ColumnFK CatalogFK SchemaFK TableFK ColumnFK Seq.Update RuleDelete RuleFK NamePK NameDeferrability
"); + buffer.append(foreignKeys.getString("PKTABLE_CAT")); + buffer.append(""); + buffer.append(foreignKeys.getString("PKTABLE_SCHEM")); + buffer.append(""); + buffer.append(foreignKeys.getString("PKTABLE_NAME")); + buffer.append(""); + buffer.append(foreignKeys.getString("PKCOLUMN_NAME")); + buffer.append(""); + buffer.append(foreignKeys.getString("FKTABLE_CAT")); + buffer.append(""); + buffer.append(foreignKeys.getString("FKTABLE_SCHEM")); + buffer.append(""); + buffer.append(foreignKeys.getString("FKTABLE_NAME")); + buffer.append(""); + buffer.append(foreignKeys.getString("FKCOLUMN_NAME")); + buffer.append(""); + buffer.append(foreignKeys.getShort("KEY_SEQ")); + buffer.append(""); + short updateRule = foreignKeys.getShort("UPDATE_RULE"); + buffer.append(getUpdateRule(updateRule)); + buffer.append(""); + short deleteRule = foreignKeys.getShort("DELETE_RULE"); + buffer.append(getDeleteRule(deleteRule)); + buffer.append(""); + buffer.append(foreignKeys.getString("FK_NAME")); + buffer.append(""); + buffer.append(foreignKeys.getString("PK_NAME")); + buffer.append(""); + short deferrability = foreignKeys.getShort("DEFERRABILITY"); + buffer.append(getDeferrability(deferrability)); + buffer.append("
"); + out.println(buffer.toString()); + } + + private static void printXML(HttpServletResponse response, + ResultSet foreignKeys) + throws Exception { + response.setContentType("text/xml"); + PrintWriter out = response.getWriter(); + StringBuilder buffer = new StringBuilder(); + buffer.append(""); + buffer.append(""); + while (foreignKeys.next()) { + buffer.append(""); + buffer.append(foreignKeys.getString("PKTABLE_CAT")); + buffer.append(""); + buffer.append(foreignKeys.getString("PKTABLE_SCHEM")); + buffer.append(""); + buffer.append(foreignKeys.getString("PKTABLE_NAME")); + buffer.append(""); + buffer.append(foreignKeys.getString("PKCOLUMN_NAME")); + buffer.append(""); + buffer.append(foreignKeys.getString("FKTABLE_CAT")); + buffer.append(""); + buffer.append(foreignKeys.getString("FKTABLE_SCHEM")); + buffer.append(""); + buffer.append(foreignKeys.getString("FKTABLE_NAME")); + buffer.append(""); + buffer.append(foreignKeys.getString("FKCOLUMN_NAME")); + buffer.append(""); + buffer.append(foreignKeys.getString("KEY_SEQ")); + buffer.append(""); + short updateRule = foreignKeys.getShort("UPDATE_RULE"); + buffer.append(getUpdateRule(updateRule)); + buffer.append(""); + short deleteRule = foreignKeys.getShort("DELETE_RULE"); + buffer.append(getDeleteRule(deleteRule)); + buffer.append(""); + buffer.append(foreignKeys.getString("FK_NAME")); + buffer.append(""); + buffer.append(foreignKeys.getString("PK_NAME")); + buffer.append(""); + short deferrability = foreignKeys.getShort("DEFERRABILITY"); + buffer.append(getDeferrability(deferrability)); + buffer.append(""); + } + buffer.append(""); + out.println(buffer.toString()); + } + + private static void printError(HttpServletResponse response, + String message) { + try { + PrintWriter out = response.getWriter(); + StringBuilder buffer = new StringBuilder(); + buffer.append(""); + buffer.append(message); + buffer.append(""); + out.println(buffer.toString()); + } + catch(Exception ignore) { + } + } + + /** + * Get the Foreign Keys. + * @param conn the Connection object + * @catalog database catalog name + * @schemaPattern database schema pattern + * @procedureNamePattern database procedure name pattern + * @return a table of Foreign Keys as a ResultSet object. + * + */ + public static ResultSet getForeignKeys(Connection conn, + String catalog, + String schema, + String table) + throws Exception { + + if (table == null) { + return null; + } + + DatabaseMetaData meta = conn.getMetaData(); + if (meta == null) { + return null; + } + + return meta.getImportedKeys(catalog, schema, table.toUpperCase()); + } + + + private static String getUpdateRule(short updateRule) { + if (updateRule == DatabaseMetaData.importedKeyNoAction) { + return "importedKeyNoAction"; + } + else if (updateRule == DatabaseMetaData.importedKeyCascade) { + return "importedKeyCascade"; + } + else if (updateRule == DatabaseMetaData.importedKeySetNull) { + return "importedKeySetNull"; + } + else if (updateRule == DatabaseMetaData.importedKeySetDefault) { + return "importedKeySetDefault"; + } + else if (updateRule == DatabaseMetaData.importedKeyRestrict) { + return "importedKeyRestrict"; + } + else { + return "nobody knows"; + } + } + + private static String getDeleteRule(short deleteRule) { + if (deleteRule == DatabaseMetaData.importedKeyNoAction) { + return "importedKeyNoAction"; + } + else if (deleteRule == DatabaseMetaData.importedKeyCascade) { + return "importedKeyCascade"; + } + else if (deleteRule == DatabaseMetaData.importedKeySetNull) { + return "importedKeySetNull"; + } + else if (deleteRule == DatabaseMetaData.importedKeyRestrict) { + return "importedKeyRestrict"; + } + else if (deleteRule == DatabaseMetaData.importedKeySetDefault) { + return "importedKeySetDefault"; + } + else { + return "nobody knows"; + } + } + + private static String getDeferrability(short deferrability) { + if (deferrability == DatabaseMetaData.importedKeyInitiallyDeferred) { + return "importedKeyInitiallyDeferred"; + } + else if (deferrability == DatabaseMetaData.importedKeyInitiallyImmediate) { + return "importedKeyInitiallyImmediate"; + } + else if (deferrability == DatabaseMetaData.importedKeyNotDeferrable) { + return "importedKeyNotDeferrable"; + } + else { + return "nobody knows"; + } + } +} diff --git a/sourceMetadata/Chapter09/GetRowSetMetaData.class b/sourceMetadata/Chapter09/GetRowSetMetaData.class new file mode 100644 index 0000000000000000000000000000000000000000..0409929522290d8b00fa37fd8cec44bcf7acfe29 GIT binary patch literal 2111 zcmah~YgZFj6x}x_Oc(}5p2qs9S}CtEK&!P0@|2g7K#7W?ZJi_+3{7U@%tY}=^mq8R ze2Gxks^9w?`dhlX?@R;*Ev&^o_nv#_oW1uw=jQK!|NINUC_EisV*xo?#r_D&F8*fH5WPLLdTkXQInpZKJl1Wb!<?%{euX;m2PUX=Df-sVjWiM7`TF~)b^#ci;k<| zp@DTg((u^82A)t%O60!Q@YKN1_{G2g1_k22-0{twN?F6N2A+XY@+fF18j!FwY#P|Y zbAb+(A!K+Un}HIZ7#KoQ;6lNvm|o2`UFVg@3tE@?5aLp$%Glcmep9i_DpqF@tK>A~ zTX##obPZHs8*o&_EybhzFk>k5Ol@;hQcGj}xnC(yjOU%=>j?u@ybw4&ZU)P7RtEPJ zc%D3aOeld%D(sgF>DYlrfgOZ?%BzR%X*mF+^_EauIJy!08%D-{k)IAht?mdf5rFo$k|{x73B(gZ|)65+6* zc{i*FCh?{1-+x_Y{dRpW3mdYTXu@I;==ng3I@5VrHLO)hatxVCZvl9D4@B>L>qC)LY4K^Ht(=#@@fo z2VVU}A=FF2@fuebX$5U;;4Q>1Cj#GaYzmxh9IvAnk>Kb*w9VWritJ!}WFMy@s3V$+ z4z|Y*7O_Nh4^7!*BDM!D)il%|-$!!<05LA{W>VJPmA!bRK89*TqvkID>Pzz#o*W90y2vjFeL( zJB@EKhdxHQhP&jK<9eOz4cce41@v>KSVy?(hprw!&XqvF(>BrG7MXWwd;At>v&q4I zv`3H}*hfbM@6btaS0+i4-K1Ja4~f-rE)o4B6$>V@_YA@h_^S&3-wbRBe;6(F4Rd#d zX-7$Bj3jOl_$@+8^P5R}r})JrsZ0eh)eW}tG+$QE6vzs{kJ2hg6q-mA#B@HJZ2zi` z3+u_jU~Ipr%uuq9OK%X(>;`w-N2aZusax+2?spy<7O3SSy0Jth?=rXPNj43n<# K^e|6HVEzY2%?J|! literal 0 HcmV?d00001 diff --git a/sourceMetadata/Chapter09/GetRowSetMetaData.java b/sourceMetadata/Chapter09/GetRowSetMetaData.java new file mode 100644 index 0000000..7bf33ff --- /dev/null +++ b/sourceMetadata/Chapter09/GetRowSetMetaData.java @@ -0,0 +1,81 @@ +import java.sql.*; +import javax.sql.*; +import javax.servlet.*; +import javax.servlet.http.*; + +import javax.sql.rowset.WebRowSet; +import com.sun.rowset.WebRowSetImpl; + +import java.io.StringWriter; +import java.io.PrintWriter; +import java.io.IOException; + +import jcb.util.DatabaseUtil; +import jcb.db.VeryBasicConnectionManager; + +public class GetRowSetMetaData extends HttpServlet { + + public void doGet(HttpServletRequest request, + HttpServletResponse response) + throws ServletException, IOException { + Connection conn = null; + try { + String dbVendor = request.getParameter("vendor").trim(); + String sqlQuery = request.getParameter("query").trim(); + conn = VeryBasicConnectionManager.getConnection(dbVendor); + + // create metadata + String metadata = getMetaData(conn, sqlQuery); + + // write xml to client + response.setContentType("text/xml"); + PrintWriter out = response.getWriter(); + out.println(metadata); + } + catch(Exception e) { + printError(response, e.getMessage()); + } + finally { + DatabaseUtil.close(conn); + } + } // end doGet + + private static String getMetaData(Connection conn, + String sqlQuery) + throws Exception { + StringWriter writer = null; + try { + WebRowSet webRS = new WebRowSetImpl(); + webRS.setCommand(sqlQuery); + webRS.execute(conn); + + // writer to hold and manipulate XML data. + writer = new StringWriter(); + + // generate the XML document + webRS.writeXml(writer); + + // Convert the writer object data to a XML String. + return writer.toString(); + } + finally { + // Close the Writer object. + writer.close(); + } + } + + private static void printError(HttpServletResponse response, + String message) { + try { + PrintWriter out = response.getWriter(); + StringBuffer buffer = new StringBuffer(); + buffer.append(""); + buffer.append(message); + buffer.append(""); + out.println(buffer); + } + catch(Exception ignore) { + } + } + +} diff --git a/sourceMetadata/Chapter09/GetSPColumns.class b/sourceMetadata/Chapter09/GetSPColumns.class new file mode 100644 index 0000000000000000000000000000000000000000..210ec3fc9e39b12e5cf0836ca564babe5ad565c0 GIT binary patch literal 5041 zcmb7Id3;<|75-kC$=oEbw0)4K6S_;HDX-Yat+ek8rGn1A@jgy&2JMCm% zc=M*T?3*kFipahw70|c=DPY=wKv@I|qM*2-2q=OJ3X1xN|ES-6@6BYg6!bU0-(Ai< z?=1H_=iGbeg?~TtIDnP-XBA>F1O}^d7R)N-VF?rjwpZb7>=4)~N#_WhD{x*FK8^DQ zE)clThl{E(1BPramdzysm&*0as_+F|E}JU^u9TFkWV6eMtE*6lYXq*X#%^3En=cAn zFYqOS8w73?xJlqjj3mjBXH%U^o+Z7`4!ql3ihQ8kD zDbemtQGpi~RD?6RjMbvxu==GN6?h^>T30ZmGn3P!g@JzEOeFiWqBtUAYY1LWPe})zeHjPtWVk0&mQLjvqk{S!g^8Vm zM5(4e?sAq}N~hyS!A$AvG7`#J1Tx;^+PPfDnu;^<8OFkPJ(o62AAYFfM|jzXS5*8M zKjFfehB=TV`b5Qb(}!18{1iW9WDM-2izU-RbfeN3HKZ6oh@NY zhI^pjFlo=~m4TF=&E^M_DJJ3S74~c}nNHg?=FE}dM64y8*w7MjybgyrX7)%@+;-Nb z)JjSzL;}&|fbOnP1V6W9=1^n_t;?-R?lvk5OeD&Axq#V{Gg`=Ir9bx9Y+@}wysP5( z_=5uB*xp8ar;pX5NNYmHAMrBxi~MbLPBP3GV~9sKw09{ue2fxp?P^z09qI1u?TYq| zpCwM~X;<+lyr*ItvJ~3ZnrQ8lRE}lm@{4G1XJ_l$PBOoSKaVMoQTgm}$Ofe)9C9GC zL8K>tQSmyh%sZk9b!j1L6lvwm@(Ag5>d+)L z?r~QtGsWVQF+v^PWz@wVZJm2u(kYhmp0TZ5;+`Jmb$rUwK69+(IhO?<;=D8r5dZoq zKUlam)gMathc@cw&b7&WCN*|AbtQAj%@RoGTq&Me3YH$)nhD1n%RDat$t+>2DgUUu ze=85b=B1~TAvrk6gGNEHoWZ^6Og7m)9C!y3mQi%EMmkZjGTD%pj`G-%UCao9ABz|-Vy z(7dHdMT1sRn)v+Q{qRNoUQLXk@-{4J(5gy{BIp-dwN||!YLjOO-Q=2Xa~mrzax=VqXC35D-pluq?B)C|ZiSr7{vckp`?q*4 zlXGVicVQ97M{)b+@{9S_fS<0R}uGxbLB6xW{R+Ci+ri#VA!M0opX~u?6Qziu|8xYkRdUoAWRQ*Eq_Nc4P1Jx+2z2qO z9Yrm=iER%SGb0AoWuOPf=RWT$#w@< z?q-rbK#WF+&jBLz0ug$J7`?$S-r=+1Lu|pnkWni59+{49%1quxYcZfKK+ZA=kvun1FuFl{GHXA`C!SdN`Io*=BnxlF+G2+#Qh z;{t5Oh5Y;HB91QRKR1`)I$X-wy$pLeyAPK$`L4i|xDwCfDn1=|;dNY%H*pQ##kEYb z-Q%F(TaTc~5<5spJnUCYO0D&dV|J@;DEDIsp02(89xMsV39VC5mY|Z98(6|`q)#_t zHg2Yuw=f`YCEp$7yd5FjNiIHIoj_n&@X7?oTx#!7(B$!Zo`Y8z_Inx{gIe_{KIO$Q z*BuR-ZRuX_+Jl&mhp1&_oL77Vxn6CfeA~V{&mL50rwrG5W#2hm=aYTcaGj8SbhxfU z_T9r;&zPF!sHV!tXxQUab%3g##7sPm8a#tJtZDP`90IIsi"); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + while (spColumns.next()) { + buffer.append(""); + } + buffer.append("
CatalogSchemaProcedure NameColumn NameColumn TypeData TypeType NameNullable
"); + buffer.append(spColumns.getString("PROCEDURE_CAT")); + buffer.append(""); + buffer.append(spColumns.getString("PROCEDURE_SCHEM")); + buffer.append(""); + buffer.append(spColumns.getString("PROCEDURE_NAME")); + buffer.append(""); + buffer.append(spColumns.getString("COLUMN_NAME")); + buffer.append(""); + short columnType = spColumns.getShort("COLUMN_TYPE"); + buffer.append(getColumnType(columnType)); + buffer.append(""); + buffer.append(spColumns.getString("DATA_TYPE")); + buffer.append(""); + buffer.append(spColumns.getString("TYPE_NAME")); + buffer.append(""); + buffer.append(spColumns.getShort("NULLABLE")); + buffer.append("
"); + out.println(buffer.toString()); + } + + private static void printXML(HttpServletResponse response, + ResultSet spColumns) + throws Exception { + response.setContentType("text/xml"); + PrintWriter out = response.getWriter(); + StringBuilder buffer = new StringBuilder(); + buffer.append(""); + buffer.append(""); + while (spColumns.next()) { + buffer.append(""); + buffer.append(spColumns.getString("PROCEDURE_CAT")); + buffer.append(""); + buffer.append(spColumns.getString("PROCEDURE_SCHEM")); + buffer.append(""); + buffer.append(spColumns.getString("PROCEDURE_NAME")); + buffer.append(""); + buffer.append(spColumns.getString("COLUMN_NAME")); + buffer.append(""); + short columnType = spColumns.getShort("COLUMN_TYPE"); + buffer.append(getColumnType(columnType)); + buffer.append(""); + buffer.append(spColumns.getString("COLUMN_NAME")); + buffer.append(""); + buffer.append(spColumns.getString("TYPE_NAME")); + buffer.append(""); + buffer.append(spColumns.getShort("NULLABLE")); + buffer.append(""); + } + buffer.append(""); + out.println(buffer.toString()); + } + + private static void printError(HttpServletResponse response, + String message) { + try { + PrintWriter out = response.getWriter(); + StringBuilder buffer = new StringBuilder(); + buffer.append(""); + buffer.append(message); + buffer.append(""); + out.println(buffer.toString()); + } + catch(Exception ignore) { + } + } + + /** + * Get the stored-procedures names. + * @param conn the Connection object + * @catalog database catalog name + * @schemaPattern database schema pattern + * @procedureNamePattern database procedure name pattern + * @return a table of stored procedures names + * as a ResultSet object. + * Each element of XML document will have the name and + * type of a stored procedure. + * + */ + public static ResultSet getStoredProcedureColumns + (java.sql.Connection conn, + String catalog, + String schemaPattern, + String procedureNamePattern) + throws Exception { + + DatabaseMetaData meta = conn.getMetaData(); + if (meta == null) { + return null; + } + + return meta.getProcedureColumns(catalog, + schemaPattern, + procedureNamePattern, + "%"); + } + + private static String getColumnType(short columnType) { + if (columnType == DatabaseMetaData.procedureColumnIn) { + return "IN parameter"; + } + else if (columnType == DatabaseMetaData.procedureColumnInOut) { + return "INOUT parameter"; + } + else if (columnType == DatabaseMetaData.procedureColumnOut) { + return "OUT parameter"; + } + else if (columnType == DatabaseMetaData.procedureColumnReturn) { + return "procedure return value"; + } + else if (columnType == DatabaseMetaData.procedureColumnResult) { + return "result column in ResultSet"; + } + else { + return "nobody knows"; + } + } +} \ No newline at end of file diff --git a/sourceMetadata/Chapter09/GetSchemas.class b/sourceMetadata/Chapter09/GetSchemas.class new file mode 100644 index 0000000000000000000000000000000000000000..4fe0642aac0cf65e07386e60fa36716198e9a4f6 GIT binary patch literal 3487 zcmbVPX;&N98Gf!jFoQHUiEK>N#4aYa4G4KmQacz4ImUJZHj9IZNod?;kOnNGjhPXJ zbWNJ>?vk!a*Q8BC(k*s-4uR&Jrk~n#`nf+Kzo9>%>2vQ$AcI}E{c_*Cz031%bLa2> z`qQ5Q^x=kpqG~gQW z4EQ>#VH}Y{mL&a@fn|AfC4%ShX=%V`BKRymr{nWsShyI$7x26sUXUujsN+Q)UlM3e z;X&Qfv79a@MK%d2Zk%2(!G!f_1iBDmhu{t7P|fxSOuJ)6HALA%aY~ z>Smos@-pJBjCaj~V>09>PU0aZ%#u^em0cZQHSslk-NZL=jk|MYw`embziHxI__m2h z@F;U?xmYmq9lT`XEFLy-8V~FEu8HsA`vQBVP)p(748MsV;F^hZIM2BG&azCeVnN3b zP5cNin|K937HHpM3_>wf%@=YGo!+04*VC!la&9G^@@3|B%$8lA4fb_pokGE@*jdJI z@VHu4>|9Q*(k6a_p9;iMQRV~__s`;Hy&>~Koi zva+>vBr}od?>})W(bsvJW!sYSf-K>@IaRWY4kvobs?BK1*7^SJrVdr-=A_@uM!!j4 zydkh>yS=aDO&zNy-oo25g1^@B8yV)`)+4E^?u_f&E3))-{LaMh@s5e>xMAWCc!_@5 z$|!+@(wN(~ksTLm?PW7n>T2_4Yh6}{5sp+YO&e*9TFq^;`pSWZhNNmRiv^`xd!Z!I`(K(R z3yW6WC!3%g_lNs5?nst4DLp363edy&;s7j#n-C87KJU#gs2@ z#m0WrD0PcXAiBx4xl1RO*o2i6nOiM1ukNR9uB-)!H`!Bhh%cTKd^!Qm5c0FZv7f60 zq=K}m=Us>!oCut%T>?z529QKZUHyR6;8{+L$D^SQ>I#}n(& z2byC|QDY4)ufXh$HLoMQiWW7A@Yr0%!2zu|rmbPmI$DDrb3m7qnEw6^Xw-HF!+fnt zIzzp~$S694rxXn=y?`jsT6ybkj#1pl_gN?Qp$lzz0Q+fqI}yYvqXXyZhGE{gK-d|s zr@5XXeTFnku9QL^!XVNJ%TFVADdg{vHt}q}CwkWg?hc`615tso_ptZLcd>6g5p7$; z{^>-tU6NfVwKgrjfqMi$C`S{~m^zEMX&d-R2!Fx7!QJ~Lc~KLqAO0f|Js=moi8UNt z!$-HmaFX!Bm!yHC1lL6<-8hII97Y@uqL;x*5X>GLBOzf0oJDmH~*$y}#liPJThvnjSa2_I@e!@9LI0J-}B%BoC404qw zoYRDpBAhdXGekINZwZGF5(1PdTqHn^G_e_#BaF&XMx|>F-P4J<8lyduNSorT(8g|% z8T4qJJ_-`)2wJ!^3>_mh?gCTiB2#4)_wx^<3zv9vf*ya2xA>5%dGeoB-At}IF-qmV zOo`sVA;S7tM10f7(G3~D~6EQ9y3}Jfp z!w(XyEQ*O~*9V%^r0IQC6s@>IjcrU schemas = getSchemas(conn); + if (outputFormat.equals("xml")) { + printXML(response, schemas); + } + else { + printHTML(response, schemas); + } + } + catch(Exception e) { + printError(response, e.getMessage()); + } + finally { + DatabaseUtil.close(conn); + } + } // end doGet + + private static void printHTML(HttpServletResponse response, List schemas) + throws Exception { + response.setContentType("text/html"); + PrintWriter out = response.getWriter(); + StringBuilder buffer = new StringBuilder(); + buffer.append(""); + buffer.append(""); + for (int i=0; i < schemas.size(); i++) { + buffer.append(""); + } + buffer.append("
Schemas
"); + buffer.append(schemas.get(i)); + buffer.append("
"); + out.println(buffer.toString()); + } + + private static void printXML(HttpServletResponse response, + List schemas) + throws Exception { + response.setContentType("text/xml"); + PrintWriter out = response.getWriter(); + StringBuilder buffer = new StringBuilder(); + buffer.append(""); + buffer.append(""); + for (int i=0; i < schemas.size(); i++) { + buffer.append(""); + buffer.append(schemas.get(i)); + buffer.append(""); + } + buffer.append(""); + out.println(buffer.toString()); + } + + private static void printError(HttpServletResponse response, + String message) { + try { + PrintWriter out = response.getWriter(); + StringBuffer buffer = new StringBuffer(); + buffer.append(""); + buffer.append(message); + buffer.append(""); + out.println(buffer); + } + catch(Exception ignore) { + } + } + + /** + * Get Schemas: Retrieves the catalog names available in + * this database. The results are ordered by catalog name. + * + * @param conn the Connection object + * @return list of all schemas. + * @exception Failed to get the Get Schemas. + */ + public static List getSchemas(Connection conn) + throws Exception { + ResultSet schemas = null; + try { + DatabaseMetaData meta = conn.getMetaData(); + if (meta == null) { + return null; + } + schemas = meta.getSchemas(); + if (schemas == null) { + return null; + } + List list = new ArrayList(); + while (schemas.next()) { + String schema = schemas.getString(1); //"TABLE_CATALOG" + if (schema != null) { + list.add(schema); + } + } + return list; + } + finally { + DatabaseUtil.close(schemas); + } + } +} diff --git a/sourceMetadata/Chapter09/GetTablePrivileges.class b/sourceMetadata/Chapter09/GetTablePrivileges.class new file mode 100644 index 0000000000000000000000000000000000000000..4214630eb4a4968aa40e77c071c6d7ed634e741e GIT binary patch literal 4319 zcmb7HYj_-08GfhT&7SN|n|9LMMq1KBFKM!!))vHMl9Hrp5=qjUgqETZC%cn$+r4#n zlBR00fNd2J5b@HYqNojuKw}|I3W5lNRijV&CpU>kze~P|mW_Gh_7OH>F z-O=COrC|G&b$Y@arF!mALhrS5BMH0DvKs|7IcPf*=#zipz;5doG??vdY?_x zh8?-uuw^?0?aszW;|Xin$|*2ip^h1?=~T*!%A2`_=*1FTYd;*RDRm{@qAxv?jaoaY zQ^9h2<}xcbNhhi3LN{GJYNcZ7Yydw~aSqP}@T`hSoae$&I-4}v zWFmlHtN0Brs`xElS8#(N!6suc9XrxwIM=EkOlN6SEG3xAGHxH-`(4}r?acAony7LZ@}3i#q+Ey zRhpq-nV~yuHW|9ht;0U;dsD?9aFO;oE}Xr@ON`27cq3Et@v4*-jan>yQCv zpqDHJt1btdjHv4X=Y*c07&*rW1eX}PH+GLoClFrhS?ElSVb>GHD-AtAaZ$_L?Vy|( z1$(%=%Ft(~Mm#s*?2=C5;%Y;mg?JigF663nh?)U&M3>D3v|Bz}MuvtgRv@)FU}fUG zrC{M~jwQiwt9S>0RPiqU6u_TlBECmH=jOeFRZ`Ojm*+Vfys}+LvwZT!(|YHwB6RJC z%k|1WFT|3#+sx7@w!GguuNW3rIj^P_LkbpM&JaIFEVN1bdqc?ss}Dp6_1K`k$I2dQ zF>~?gOs(xUQ|7SLzJSKezzS+U*c$oKnAzIEGRF^@nP5F%T6}2N-~rb2hMHURJk37G ztdT0+0HzExlVR~y5Gj_C|A5S?|6cv1a$%?4T~sgcIbz2X`VNX6G;`L?oUlko6X~4A z>hFo3`_)@fv{H06`NgeZkf-cE+l(IUXEmo7X?M4k%aJ&G?Mlvezqbt4oI|i}rR@GA z8J?U)R{o+?SWfYKvvDUTmggPH7~3uFa2I%O%?W~8H(?m0SnQn#3Q3o8^31qjiP=I} z+nlQ?^M0o3WeF=aZ0~n0=wyL)h_X%T4FxOncacWt9n@{P%M=4h#34M@2X=iA7q7%_J7P`zz}-Z3>lSX(o;=|)uTrUbc!{WsW66D7TzJR%h?H%3{;SJu@x)Oh$_;)l8mlm zg|5a?T!Uk{ma@0v9&Ez{xQ-gu<1{wlQPkiu)KcG8Ji)cITswzNcosS?U^De^tS^zut*7P zQwdBjfo(280)T%#B#fAEP?7 zkkwYyV+Ut#=)g|qMLQp-9T-3-67o-v33ZIAbdp|um>Kd2cRWt-KFy4Io?dvF9(aR3 zc$Yr-JH7A^K4Je!3ID=A{F@OV{p4eYh3O?eZapt`d0u*Zqjp_sFJ15Q`Z3uRaespY z&*uK)9#+hKy@wTZ-{4`z+#4QN%zdMW6?5O@Va42Umzcx-jdC=X`yt*MWK!^-y85U8g=Y9zz zcm<<;?jOcm7@Ng0e=NwhEP6?DEi)lf$be?nnigh2>m+vUjWA@{YHhNUw(lH=uX}=r z!PKm!>2AWWbIRdS1ZYwPLtz>2#8tS9X?-{Mo#4*n45X9X#Xlq0y$lH-ivzGe@+yK9 z-F_N=Mx IH4nG_7tl{@mjD0& literal 0 HcmV?d00001 diff --git a/sourceMetadata/Chapter09/GetTablePrivileges.java b/sourceMetadata/Chapter09/GetTablePrivileges.java new file mode 100644 index 0000000..77d2a50 --- /dev/null +++ b/sourceMetadata/Chapter09/GetTablePrivileges.java @@ -0,0 +1,185 @@ +import java.sql.*; +import javax.servlet.*; +import javax.servlet.http.*; +import java.io.PrintWriter; +import java.io.IOException; + +import jcb.util.DatabaseUtil; +import jcb.db.VeryBasicConnectionManager; + + +public class GetTablePrivileges extends HttpServlet { + public void doGet(HttpServletRequest request, + HttpServletResponse response) + throws ServletException, IOException { + ResultSet tablePrivileges = null; + Connection conn = null; + + try { + String dbVendor = request.getParameter("vendor").trim(); + String outputFormat = request.getParameter("format").trim(); + String table = request.getParameter("table").trim(); + + conn = VeryBasicConnectionManager.getConnection(dbVendor); + if (dbVendor.equals("mysql")) { + // String catalog = request.getParameter("catalog").trim(); + tablePrivileges = getTablePrivileges(conn, conn.getCatalog(), // catalog, + null, // schema Pattern, + "%"); // table. Pattern + } + else if (dbVendor.equals("oracle")) { + // String schema = request.getParameter("schema").trim(); + tablePrivileges = getTablePrivileges(conn, conn.getCatalog(), // catalog + "%", // schema Pattern, + table + "%"); // table. Pattern + } else { + printError(response, "unknown db vendor"); + return; + } + if (outputFormat.equals("xml")) { + printXML(response, tablePrivileges); + } + else { + printHTML(response, tablePrivileges); + } + } + catch (Exception e) { + e.printStackTrace(); + printError(response, e.getMessage()); + } + finally { + DatabaseUtil.close(tablePrivileges); + DatabaseUtil.close(conn); + } + } // end doGet + + private static void printHTML(HttpServletResponse response, + ResultSet tablePrivileges) + throws Exception { + response.setContentType("text/html"); + PrintWriter out = response.getWriter(); + StringBuilder buffer = new StringBuilder(); + + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + while (tablePrivileges.next()) { + buffer.append(""); + } + buffer.append("
CatalogSchemaTable NameGrantorGranteePrivilegeIs Grantable
"); + buffer.append(tablePrivileges.getString("TABLE_CAT")); + buffer.append(""); + buffer.append(tablePrivileges.getString("TABLE_SCHEM")); + buffer.append(""); + buffer.append(tablePrivileges.getString("TABLE_NAME")); + buffer.append(""); + buffer.append(tablePrivileges.getString("GRANTOR")); + buffer.append(""); + buffer.append(tablePrivileges.getString("GRANTEE")); + buffer.append(""); + buffer.append(tablePrivileges.getString("PRIVILEGE")); + buffer.append(""); + buffer.append(tablePrivileges.getString("IS_GRANTABLE")); + buffer.append("
"); + out.println(buffer.toString()); + } + + private static void printXML(HttpServletResponse response, + ResultSet tablePrivileges) + throws Exception { + response.setContentType("text/xml"); + PrintWriter out = response.getWriter(); + StringBuilder buffer = new StringBuilder(); + + buffer.append(""); + buffer.append(""); + while (tablePrivileges.next()) { + buffer.append(""); + buffer.append(tablePrivileges.getString("TABLE_CAT")); + buffer.append(""); + buffer.append(tablePrivileges.getString("TABLE_SCHEM")); + buffer.append(""); + buffer.append(tablePrivileges.getString("TABLE_NAME")); + buffer.append(""); + buffer.append(tablePrivileges.getString("GRANTOR")); + buffer.append(""); + buffer.append(tablePrivileges.getString("GRANTEE")); + buffer.append(""); + buffer.append(tablePrivileges.getString("PRIVILEGE")); + buffer.append(""); + buffer.append(tablePrivileges.getString("IS_GRANTABLE")); + buffer.append(""); + } + buffer.append(""); + out.println(buffer.toString()); + } + + private static void printError(HttpServletResponse response, + String message) { + try { + PrintWriter out = response.getWriter(); + StringBuffer buffer = new StringBuffer(); + + buffer.append(""); + buffer.append(message); + buffer.append(""); + out.println(buffer); + } + catch (Exception ignore){ + } + } + + /** + * Get Table Privileges: retrieves a description of the access + * rights for each table available in a catalog. Note that a + * table privilege applies to one or more tablePrivileges in the table. + * It would be wrong to assume that this privilege applies to + * all tablePrivileges (this may be true for some systems but is not + * true for all.) The result is returned as a ResultSet object. + * + * In JDBC, Each privilege description has the following tablePrivileges: + * + * TABLE_CAT String => table catalog (may be null) + * TABLE_SCHEM String => table schema (may be null) + * TABLE_NAME String => table name + * GRANTOR => grantor of access (may be null) + * GRANTEE String => grantee of access + * PRIVILEGE String => name of access (SELECT, INSERT, + * UPDATE, REFERENCES, ...) + * IS_GRANTABLE String => "YES" if grantee is permitted to grant + * to others; "NO" if not; null if unknown + * + * + * @param conn the Connection object + * @param catalogPattern a catalog pattern. + * @param schemaPattern a schema pattern. + * @param tableNamePattern a table name pattern; must match + * the table name as it is stored in the database. + * @return a ResultSet object + * @exception Failed to get the Get Table Privileges. + */ + public static ResultSet getTablePrivileges(Connection conn, + String catalog, + String schemaPattern, + String tableNamePattern) + throws Exception { + if ((tableNamePattern == null) || (tableNamePattern.length() == 0)) { + return null; + } + DatabaseMetaData meta = conn.getMetaData(); + + if (meta == null) { + return null; + } + // The '_' character represents any single character. + // The '%' character represents any sequence of zero + // or more characters. + return meta.getTablePrivileges(catalog, schemaPattern, tableNamePattern); + } +} + diff --git a/sourceMetadata/Chapter09/GetTypes.class b/sourceMetadata/Chapter09/GetTypes.class new file mode 100644 index 0000000000000000000000000000000000000000..bfdf3a66ff5308d2bf2292becd1dafdbbe7c29ae GIT binary patch literal 3143 zcmb7GTU#5~6FX=Q*0JO!MuHQ z#jg7!4^^vIJ-2R;$f?oEwW3}1%M@t%iiWQ$v{!3o*PqJgrWM8>erCg1aHv_o>6r6& zeZ}z?Y(F?a53F4hW6@wZS*v+9h0*`hvSYc+=7LXX%c0$6+t1&s+I59gXev1TjOV&` zQTUAXJqQv}EO;xmqJ6e3zTHdD237{ewFXY&IR<9cc1vDO!)pd!#~T{HX5j0%&4nee zRw&T>RR*}9MJs!-eR;d)svIgG6j}$sH`T1-nKa~~si5aV6XH3p`qzET0-%7|z zAY?P2)$n5jKfzBG^lG62-p9KHYjwtTG&wYQJejcFq8Cs~UdW$K zpGuC=vX=4XMsQ>Vql8Odqe)Jai4rLZBbn|=n$*#WqoLk;zn_Yf z?)UL44Zk+<8~j$ox`E%}_q4usvlNbq^^Z>5`xF}KynR)+E>PJs&(AhVkNtPMjdDN| zOqDsSMql{Csi%=HyD}=wm1dE`fqT8eBEnI~;+Gv$Zg9b> z+ZQ-t2`xHao$21yR4I0ssY6XGO=kurl8AG5y-xge-otzzmP6i>dcf1S-JrnSgSn}Y zwbT4!tsI1=Ys;?;^_*1Ua6zbB)her!Lb{pymYMsa*QgWR7!QKDt1dH)E(=cZMQb+@rdUwJ9amxCe*_|lL>vzc8Gk_GF}p*p5DR?nTM|Zv!&`0~NX3ySF*syBJ!Myg%@* zeFN?9AvTb{i|9IZ>0|s1QP{hV-r>kVcVq+m@8Up{_>p04d)BS}ThPCWg9^Dn zq2uz0cyuNm@7zGwVmf{(?7F2(ZQ?P-ihD90e>@PU;!kYiu((uIk2GXYHpvnqTmSdp z)A6G+8c1&-xq+v4;x>*0gfYlCnb?oxq&`HN&ydEmB!7Z|KS}V<@qzg~<{0U#jBkk% zUM4k{E2|_XBwHEzeWb|$eS_j(8x*Vk@sB;2;;|5Sk91Ako({yjx%D<=&D{D#7I5pA z(f!=AWCVFtoE7_tF|jLscgOs9f2Zb~PZj<2INcZZvSUOs;%MI>Q*(9ZS(G#"); + buffer.append(""); + buffer.append(""); + while (types.next()) { + buffer.append(""); + } + buffer.append("
Type NameData Type
"); + buffer.append(types.getString("TYPE_NAME")); + buffer.append(""); + buffer.append(types.getString("DATA_TYPE")); + buffer.append("
"); + out.println(buffer.toString()); + } + + private static void printXML(HttpServletResponse response, + ResultSet types) + throws Exception { + response.setContentType("text/xml"); + PrintWriter out = response.getWriter(); + StringBuilder buffer = new StringBuilder(); + buffer.append(""); + buffer.append(""); + while (types.next()) { + buffer.append(""); + } + buffer.append(""); + out.println(buffer.toString()); + } + + private static void printError(HttpServletResponse response, + String message) { + try { + PrintWriter out = response.getWriter(); + StringBuffer buffer = new StringBuffer(); + buffer.append(""); + buffer.append(message); + buffer.append(""); + out.println(buffer); + } + catch(Exception ignore) { + } + } + + /** + * Listing Available SQL Types Used by a Database. This method + * retrieves the SQL data types supported by a database and driver. + * + * @param conn the Connection object + * @return SQL Types as a ResultSet object. + * @exception Failed to get the Available SQL Types Used by a Database. + */ + public static ResultSet getTypes(Connection conn) + throws Exception { + + // Get database meta data + DatabaseMetaData meta = conn.getMetaData(); + if (meta == null) { + return null; + } + + // Get type infornmation + return meta.getTypeInfo(); + } +} diff --git a/sourceMetadata/Chapter10/tables.xml b/sourceMetadata/Chapter10/tables.xml new file mode 100644 index 0000000..1648480 --- /dev/null +++ b/sourceMetadata/Chapter10/tables.xml @@ -0,0 +1,26 @@ + + + + common + scott + table1 + TABLE + description of table1 + ... + + + common + scott + table2 + VIEW + description of table2 + ... + +. +. +. + \ No newline at end of file diff --git a/sourceMetadata/README.txt b/sourceMetadata/README.txt new file mode 100644 index 0000000..9400eab --- /dev/null +++ b/sourceMetadata/README.txt @@ -0,0 +1,78 @@ +Hello Reader, + +This archive contains the example source code (and +compiled .class files) for "JDBC Metadata, MySQL, and +Oracle Recipes: A Problem-Solution Approach", first +edition, by Mahmoud Parsian. + +1. I believe in "free" software and I do support + The Free Software Foundation's principle: + Free software is a matter of liberty not price. + You should think of "free" as in "free speech" + +2. All of the code in this package/zip has been + written by Mahmoud Parsian (unless otherwise + it is noted); each chapter has source code for + that chapter. Please feel free to cut-and-paste + my code in your JDBC applications. You do not + need to mention my name. + +3. The packages directory contains packages used by + the author for creating client programs; to compile + these, go to specific directories and use "javac" + (Java compiler). You may use JDK 1.4.2 or JDK 1.5 + for compiling provided programs (I do recommend using + JDK 1.5). + +4. I have included some extra programs in the "jcb" + package, which are not included in the book. For + compiling these extra programs, you need the + following JAR files in your CLASSPATH. When including + .jar files in your CLASSPATH, you must use the full + file name: + + Windows: set CLASSPATH=%CLASSPATH%;c:\myjars\jdom.jar;... + + Linux: export CLASSPATH=$CLASSPATH:/home/me/myjars/jdom.jar:... + + JAR File From Source + -------- ---------------------------- + dt.jar JDK installation + tools.jar JDK installation + jdom.jar www.jdom.org + mysql.jar http://dev.mysql.com/downloads + ojdbc14.jar www.oracle.com + servlet-api.jar Apache's Tomcat Lib + commons-digester-1.7.jar Apache's Common Digester + xercesImpl.jar Apache's Xerces + xml-apis.jar Apache's Xerces + resolver.jar Apache's Xerces + xalan.jar Apache's Xalan + serializer.jar Apache's Xalan + + +5. Make sure to use proper/valid Driver and database + user/password for provided programs. + +6. Make sure to include MySQL's/Oracle's driver package + (JDBC Driver .jar files) in your CLASSPATH (environment + variable). + +7. NOTE: do not install these examples in a folder whose + path name contains spaces. + +8. If you use my code for production systems, please make + sure that you replace getConnection() method with a + "production quality" pool management system such as + Apache's Excalibur (http://excalibur.apache.org/). + +9. If you encounter any problems in compiling/running + programs, please let me know by sending email to: + admin@jdbccookbook.com + +10. Happy reading! + +Best regards, +Mahmoud Parsian, Ph.D. +Principal Software Engineer +admin@jdbccookbook.com \ No newline at end of file diff --git a/sourceMetadata/jcb-package/src/conf/datasource.xml b/sourceMetadata/jcb-package/src/conf/datasource.xml new file mode 100644 index 0000000..148ab47 --- /dev/null +++ b/sourceMetadata/jcb-package/src/conf/datasource.xml @@ -0,0 +1,55 @@ + + + + + default + this is a mysql database + com.jeeves.connector.sql.SQLConnectionFactory + com.jeeves.connector.sql.SQLConnection + org.gjt.mm.mysql.Driver + jdbc:mysql://localhost/octopus + root + root + 1 + 1 + 10 + select 1 from dual + 100 + mysql + + + + mysql + this is a mysql database + com.jeeves.connector.sql.SQLConnectionFactory + com.jeeves.connector.sql.SQLConnection + org.gjt.mm.mysql.Driver + jdbc:mysql://localhost/octopus + root + root + 1 + 1 + 10 + select 1 from dual + 100 + mysql + + + + oracle + this is an oracle database + com.jeeves.connector.sql.SQLConnectionFactory + com.jeeves.connector.sql.SQLConnection + oracle.jdbc.driver.OracleDriver + jdbc:oracle:thin:@localhost:1521:maui + octopus + octopus + 1 + 1 + 10 + select 1 from dual + 100 + oracle + + + \ No newline at end of file diff --git a/sourceMetadata/jcb-package/src/jcb/db/DataSourceConfig.class b/sourceMetadata/jcb-package/src/jcb/db/DataSourceConfig.class new file mode 100644 index 0000000000000000000000000000000000000000..b0c6e80fc8cb52d1e9972f2c366e975bedad1446 GIT binary patch literal 3123 zcmd5;-Bue_7~O}2WD*7fv?-=71=`ZWv=pmoYYVjnq@qA+`LWfi9g-;wO)}|Z!jDy} zK7kir=qtFqs4j=DW!LfnTt0}mzJSYpW&(xD@!nkQ@65ONoH;q)+270`|NQnlfQ$Gh zjkB0f;S6p|xFcaf!lHyF3Cj{bkZ@PRJqaI5_(;Ni2_H-NB!y4$K!cga3i3%5(l~^9 z4VH`#C9G;#(_m{@*YHR~QA0^XS%agYqT#WWxEiV&JPoxZHj>yBh?mWhCD1vuZf=;v zMYFs*yx_TZdG)G5OTntGw(U>_C%2>flS^hm#w^MHE_44UoC5bhGh>&nxmsz(au>~& zA~VTV%bN>ob9i8|@&9noD45(|pcE6!^%}|XWW7uYj+gGtu$~;u?^Q@%E$x*q!>g$S zCF^8nB3iXpncP>n4qnekY8M+AWcAW@CMe+Eg{+~xSllgRbA^YE<>XD=jr4+3bMw}e zEq5S0X?kXu;5r`Ks~6-M)o~fKItDPP!;o-J!g&cp5-vy>mhh^CixOUw@H$3xydmLD z370UE#Fmb2d?s*YNcl_RiH^_lg+N!-9^*B;Sdb>@imviXuQbD$jxX_4$5$8=IMJxt zXDteHje^i^YA!S&xg(AD(UT;ODTsQl)$Fcw$@VnfyWh-IoNQD?{7q4}LbP{s$oDn! z2fIM9g-m-8!pd-Tc7gVn#lE$&&aQPJwXj|FtP)Rb z(1x<1HEm~jULIujPRlH@cODAnIGC1=Op1zZX<0?rk`73il?pv9Fr*SR^nv;@P+v=mu$hP^&{LGmJt`f)jT<~AV zaSAD%=Kt>JoA3;B+=U+QKtI=hjyrIXc!`Z3d3PTU1)0^nIl?6P2z}I)hmv*DC%-j3bC2enER@#|}CfU*OQa=Q!M%-N6xg;23t$ zb&z`{03Tsf#suz2 z$ja!!9Wl&En3d6oyK!3FlW_s}CFCT0EkhOv84oz}9Jj=NL9FLE=7n6~c*wEHQRGH@t9+Uqr~xq<0;28j&C@g3;3#xI9><`x`eWj6onvF$`4nKrgyY&oF(4 zWPV-W)U{?{+1h>GuLXM9Hm4bm&SaJ{tHt?8i`m)Ll|p{?ZZ1E|kZ8ee-KlEDz_Xkx zVF$CW;|IDEEbDgDBo7Oj#Y|y!skAU#WEgpR*qQ#DmSY9C8DirT%M86)w?Zd}^Oj@I zHS1;5TM~iLMqRfYhGXN0SP=(Ds%9{=e<2EF&8jj?jvw?nkzY5;TBWT07fv^bc};R6 z&u$rJBe3W;5~>nvbTz$FY2z7o4>5eu)&EVCqfaD@-!$wf?Q)9&cP)|RxTfF=(hAnGK~4@>*{jwC*Q;uJLpN%s zX1Mh_{;F6Wz`&2XmMrf+&8(C&za?)xuYuflM?i;Xqi z2wd+~)+Qvwr7kGLbsW$BFx&dpZvGK5JdaoERcEL1U*S_buFEe$w=>!a?--9cN z2mM}vzSSKNSas8Fl8dpK8(O`gm0fp3^F4!@=}LS~0WI zu{GSFHX0NI-Pl<2bb~4%qn<`}>ufbG>(kW3M7IuKTBM>D*=YLIs*;D{>CuZ8mep;$ zU+Jf%s;yE5-ENnG>4c+tUF7MnTvVG_+VhvH$>z($Z z8+HWOJqd`NrrUNKJ=kqqvGmFig?B2WM$bJ%Z-_q@%t@$?WH}YDI9K%!&vGUPHRF1O6xCztXZZjx4RH(-KgG{5QGiA^Gzz zWQt=TpQd9awt!!1ED;vDxo~14uAla2YisxJ|TnDewkSJfOTX Kd_|ZZWc~%%`@R+c literal 0 HcmV?d00001 diff --git a/sourceMetadata/jcb-package/src/jcb/db/DataSourceDigester.java b/sourceMetadata/jcb-package/src/jcb/db/DataSourceDigester.java new file mode 100644 index 0000000..45307de --- /dev/null +++ b/sourceMetadata/jcb-package/src/jcb/db/DataSourceDigester.java @@ -0,0 +1,131 @@ +package jcb.db; + +import java.io.IOException; +import java.util.Hashtable; +import org.apache.commons.digester.Digester; +import org.xml.sax.SAXException; + +/** + * This class reads "datasource.xml" file and creates + * DataSourceConfig objects. + * + */ + public class DataSourceDigester { + + private static Hashtable dataSources = new Hashtable(); + + private static final String DATA_SOURCE_XML_FILE = + "D:/mp/book/src/conf/datasource.xml"; + + private static final String[] PARAM_TYPES = { + "java.lang.String", // name + "java.lang.String", // description + "java.lang.String", // vendor + "java.lang.String", // driver + "java.lang.String", // url + "java.lang.String", // username + "java.lang.String", // password + "java.lang.String", // factoryClass + "java.lang.String", // connectionClass + "java.lang.String", // checkQuery + "java.lang.Integer", // poolGrowAmount + "java.lang.Integer", // poolMin + "java.lang.Integer", // poolMax + "java.lang.Integer" // timeout + }; + + + static { + DataSourceDigester dsDigester = new DataSourceDigester(); + + try { + dsDigester.run(); + } + catch(Exception e) { + e.printStackTrace(); + } + } + + public static void main(String[] args) { + + DataSourceDigester dsDigester = new DataSourceDigester(); + + try { + dsDigester.run(); + } + catch(Exception e) { + e.printStackTrace(); + } + + } + + + /** + * Get a data source configuration. + */ + public static DataSourceConfig getDataSourceConfig(String name) { + return (DataSourceConfig) dataSources.get(name); + } + + public void run() + throws IOException, SAXException { + + Digester digester = new Digester(); + + digester.push(this); + + + digester.addCallMethod("datasources/datasource", "addDataSource", 14, PARAM_TYPES); + digester.addCallParam("datasources/datasource/name", 0); + digester.addCallParam("datasources/datasource/description", 1); + digester.addCallParam("datasources/datasource/vendor", 2); + digester.addCallParam("datasources/datasource/driver", 3); + digester.addCallParam("datasources/datasource/url", 4); + digester.addCallParam("datasources/datasource/username", 5); + digester.addCallParam("datasources/datasource/password", 6); + digester.addCallParam("datasources/datasource/factoryClass", 7); + digester.addCallParam("datasources/datasource/connectionClass", 8); + digester.addCallParam("datasources/datasource/checkQuery", 9); + digester.addCallParam("datasources/datasource/poolGrowAmount", 10); + digester.addCallParam("datasources/datasource/poolMin", 11); + digester.addCallParam("datasources/datasource/poolMax", 12); + digester.addCallParam("datasources/datasource/timeout", 13); + + digester.parse(DATA_SOURCE_XML_FILE); + } + + public void addDataSource(String name, + String description, + String vendor, + String driver, + String url, + String username, + String password, + String factoryClass, + String connectionClass, + String checkQuery, + int poolGrowAmount, + int poolMin, + int poolMax, + int timeout) { + + DataSourceConfig dataSource = new DataSourceConfig + (name, + description, + vendor, + driver, + url, + username, + password, + factoryClass, + connectionClass, + checkQuery, + poolGrowAmount, + poolMin, + poolMax, + timeout); + //dataSource.print(); + dataSources.put(name, dataSource); + + } +} \ No newline at end of file diff --git a/sourceMetadata/jcb-package/src/jcb/db/DataSourceManager.class b/sourceMetadata/jcb-package/src/jcb/db/DataSourceManager.class new file mode 100644 index 0000000000000000000000000000000000000000..c1f6a5afe922958060a81329dfc5583ffcc3bbcc GIT binary patch literal 577 zcmZuvO;5r=5Pb`@#aaac`BJ{3F`#1O8RG@wslWl_#nZMdO$oGGii!V9FKRsa1N>3O zsbYxY9(LZ&zIpRzv+p0TZvakFRS`#8MF!h(WL4ylkE0MrQNfOaT?YBgah>3tAzE)- zF~r*5P%tD6#}&Q#)D-?DHz$-y+al=jfDgR6Z;7_&jvSkzSvSV~j_VWd+WH{y9oKF( zjIm|vLsS1tZ;||zJ1#@Ee*I4!wO7C8FPyMtb}7*1F1Lk$5;oJY230{x!v;1Pr0M
{ljxp&1!vvQ{Ob8hwpD6tPd41CraK`v_8>4ghu! literal 0 HcmV?d00001 diff --git a/sourceMetadata/jcb-package/src/jcb/db/DataSourceManager.java b/sourceMetadata/jcb-package/src/jcb/db/DataSourceManager.java new file mode 100644 index 0000000..09b9459 --- /dev/null +++ b/sourceMetadata/jcb-package/src/jcb/db/DataSourceManager.java @@ -0,0 +1,41 @@ +package jcb.db; + + +import java.util.*; + +import jcb.util.*; + + +/** + * DataSourceManager is a helper class for data sources. + * + *

+ * @author: Mahmoud Parsian + * @since JDK 1.4 + */ +public class DataSourceManager { + + + public static DataSourceConfig getDataSourceConfig(String dsn) { + return DataSourceDigester.getDataSourceConfig(dsn); + } + + /** + * For testing/debugging ONLY. + * + */ + public static void main(String[] args) { + + DataSourceConfig dsConfig1 = DataSourceDigester.getDataSourceConfig("mysql"); + dsConfig1.print(); + + DataSourceConfig dsConfig2 = DataSourceDigester.getDataSourceConfig("oracle"); + dsConfig2.print(); + + DataSourceConfig dsConfig3 = DataSourceDigester.getDataSourceConfig("default"); + dsConfig3.print(); + + } + +} + diff --git a/sourceMetadata/jcb-package/src/jcb/db/VeryBasicConnectionManager.class b/sourceMetadata/jcb-package/src/jcb/db/VeryBasicConnectionManager.class new file mode 100644 index 0000000000000000000000000000000000000000..08e3bdf47b6824085ac6b59f062ebb4967ae156e GIT binary patch literal 1695 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 literal 0 HcmV?d00001 diff --git a/sourceMetadata/jcb-package/src/jcb/meta/DatabaseMetaDataTool.java b/sourceMetadata/jcb-package/src/jcb/meta/DatabaseMetaDataTool.java new file mode 100644 index 0000000..7f6a9f8 --- /dev/null +++ b/sourceMetadata/jcb-package/src/jcb/meta/DatabaseMetaDataTool.java @@ -0,0 +1,2055 @@ +package jcb.meta; + +import java.util.*; +import java.io.*; +import java.sql.*; +import java.lang.reflect.*; + +import jcb.db.*; +import jcb.util.*; + +/** + * This class provides class-level methods + * for getting database metadata. + * + */ + public class DatabaseMetaDataTool { + + private static final String[] DB_TABLE_TYPES = { "TABLE" }; + private static final String[] DB_VIEW_TYPES = { "VIEW" }; + private static final String[] DB_MIXED_TYPES = { "TABLE", "VIEW" }; + + private static final String COLUMN_NAME_TABLE_NAME = "TABLE_NAME"; + private static final String COLUMN_NAME_COLUMN_NAME = "COLUMN_NAME"; + private static final String COLUMN_NAME_TYPE = "TYPE"; + private static final String COLUMN_NAME_DATA_TYPE = "DATA_TYPE"; + private static final String COLUMN_NAME_VIEW_NAME = "VIEW_NAME"; + private static final String COLUMN_NAME_TYPE_NAME = "TYPE_NAME"; + private static final String COLUMN_NAME_COLUMN_SIZE = "COLUMN_SIZE"; + private static final String COLUMN_NAME_NULLABLE = "NULLABLE"; + private static final String COLUMN_NAME_ORDINAL_POSITION = "ORDINAL_POSITION"; + private static final String COLUMN_NAME_TABLE_CATALOG = "TABLE_CAT"; + private static final String COLUMN_NAME_TABLE_SCHEMA = "TABLE_SCHEM"; + private static final String COLUMN_NAME_PRIVILEGE = "PRIVILEGE"; + private static final String COLUMN_NAME_GRANTOR = "GRANTOR"; + private static final String COLUMN_NAME_IS_GRANTABLE = "IS_GRANTABLE"; + private static final String COLUMN_NAME_GRANTEE = "GRANTEE"; + private static final String COLUMN_NAME_ASC_OR_DESC = "ASC_OR_DESC"; + private static final String COLUMN_NAME_CARDINALITY = "CARDINALITY"; + private static final String COLUMN_NAME_PAGES = "PAGES"; + private static final String COLUMN_NAME_FILTER_CONDITION = "FILTER_CONDITION"; + private static final String COLUMN_NAME_NON_UNIQUE = "NON_UNIQUE"; + private static final String COLUMN_NAME_INDEX_QUALIFIER = "INDEX_QUALIFIER"; + private static final String COLUMN_NAME_INDEX_NAME = "INDEX_NAME"; + private static final String COLUMN_NAME_SCOPE = "SCOPE"; + private static final String COLUMN_NAME_DECIMAL_DIGITS = "DECIMAL_DIGITS"; + private static final String COLUMN_NAME_PSEUDO_COLUMN = "PSEUDO_COLUMN"; + + private static final String ORACLE_VIEWS = + "select object_name from user_objects where object_type = 'VIEW'"; + private static final String ORACLE_TABLES = + "select object_name from user_objects where object_type = 'TABLE'"; + private static final String ORACLE_TABLES_AND_VIEWS = + "select object_name from user_objects where object_type = 'TABLE' or object_type = 'VIEW'"; + + private static final String STORED_PROCEDURE_RETURNS_RESULT = "procedureReturnsResult"; + private static final String STORED_PROCEDURE_NO_RESULT = "procedureNoResult"; + private static final String STORED_PROCEDURE_RESULT_UNKNOWN = "procedureResultUnknown"; + + static final Map JDBC_TYPE_NAME_MAP = new HashMap(); + static { + // Get all fields in java.sql.Types + Field[] fields = java.sql.Types.class.getFields(); + for (int i=0; i"); + sb.append(""); + + + // SQL keywords are separated by "," + StringTokenizer st = new StringTokenizer(sqlKeywords, ","); + while(st.hasMoreTokens()) { + sb.append(""); + sb.append(st.nextToken().trim()); + sb.append(""); + } + sb.append(""); + return sb.toString(); + } + catch(Exception e) { + e.printStackTrace(); + throw new Exception(e.toString()); + } + + } + + /** + * Get the table types for a database. + * @param conn the Connection object. + * @return the list of table types as a List. + * @exception Failed to get the table types from the database. + */ + public static java.util.List getTableTypes(java.sql.Connection conn) + throws Exception { + + ResultSet rs = null; + try { + DatabaseMetaData meta = conn.getMetaData(); + if (meta == null) { + return null; + } + + rs = meta.getTableTypes(); + if (rs == null) { + return null; + } + + java.util.List list = new java.util.ArrayList(); + //System.out.println("getTableTypes(): --------------"); + while (rs.next()) { + String tableType = DatabaseUtil.getTrimmedString(rs, 1); + //System.out.println("tableType="+tableType); + if (tableType != null) { + list.add(tableType); + } + } + //System.out.println("--------------"); + return list; + } + catch(Exception e) { + e.printStackTrace(); + throw new Exception(e.toString()); + } + finally { + DatabaseUtil.close(rs); + } + + } + + /** + * Get the table names for a given connection object. + * @param conn the Connection object + * @return the list of table names as a List. + * @exception Failed to get the table names from the database. + */ + public static java.util.List getTableNames(java.sql.Connection conn) + throws Exception { + + ResultSet rs = null; + try { + DatabaseMetaData meta = conn.getMetaData(); + if (meta == null) { + return null; + } + + rs = meta.getTables(null, null, null, DB_TABLE_TYPES); + if (rs == null) { + return null; + } + + java.util.List list = new java.util.ArrayList(); + //System.out.println("getTableNames(): --------------"); + while (rs.next()) { + String tableName = DatabaseUtil.getTrimmedString(rs, COLUMN_NAME_TABLE_NAME); + //System.out.println("tableName="+tableName); + if (tableName != null) { + list.add(tableName); + } + } + //System.out.println("--------------"); + return list; + } + catch(Exception e) { + e.printStackTrace(); + throw new Exception(e.toString()); + } + finally { + DatabaseUtil.close(rs); + } + + } + + /** + * Get the Oracle table names for a given connection object. + * If you use the getTableNames() for an Oracle database, you + * will get lots of auxiliary tables, which belong to the user, + * but user is not interested in seeing them. + * + * @param conn the Connection object + * @return the list of table names as a List. + * @exception Failed to get the table names from the database. + */ + public static java.util.List getOracleTableNames(java.sql.Connection conn) + throws Exception { + + Statement stmt = null; + ResultSet rs = null; + try { + + stmt = conn.createStatement(); + rs = stmt.executeQuery(ORACLE_TABLES); + + if (rs == null) { + return null; + } + + java.util.List list = new java.util.ArrayList(); + while (rs.next()) { + String tableName = DatabaseUtil.getTrimmedString(rs, 1); + //System.out.println("tableName="+tableName); + if (tableName != null) { + list.add(tableName); + } + } + + return list; + } + catch (Exception e ) { + e.printStackTrace(); + throw new Exception(e.toString()); + } + finally { + DatabaseUtil.close(rs); + DatabaseUtil.close(stmt); + } + + } + + + /** + * Get the view names for a given connection object. + * @param conn the Connection object + * @return the list of view names as a List. + * @exception Failed to get the view names from the database. + */ + public static java.util.List getViewNames(java.sql.Connection conn) + throws Exception { + + ResultSet rs = null; + try { + DatabaseMetaData meta = conn.getMetaData(); + if (meta == null) { + return null; + } + + rs = meta.getTables(null, null, null, DB_VIEW_TYPES); + if (rs == null) { + return null; + } + + java.util.List list = new java.util.ArrayList(); + while (rs.next()) { + String viewName = DatabaseUtil.getTrimmedString(rs, COLUMN_NAME_TABLE_NAME); + if (viewName != null) { + list.add(viewName); + } + + } + + return list; + } + catch(Exception e) { + e.printStackTrace(); + throw new Exception(e.toString()); + } + finally { + DatabaseUtil.close(rs); + } + + } + + + /** + * Get the Oracle view names for a given connection object. + * If you use the getViewNames() for an Oracle database, you + * will get lots of auxiliary views, which belong to the user, + * but user is not interested in seeing them. + * + * @param conn the Connection object + * @return the list of view names as a List. + * @exception Failed to get the view names from the database. + */ + public static java.util.List getOracleViewNames(java.sql.Connection conn) + throws Exception { + + Statement stmt = null; + ResultSet rs = null; + try { + + stmt = conn.createStatement(); + rs = stmt.executeQuery(ORACLE_VIEWS); + + if (rs == null) { + return null; + } + + java.util.List list = new java.util.ArrayList(); + while (rs.next()) { + String viewName = DatabaseUtil.getTrimmedString(rs, 1); + System.out.println("viewName="+viewName); + if (viewName != null) { + list.add(viewName); + } + } + + return list; + } + catch (Exception e ) { + e.printStackTrace(); + throw new Exception(e.toString()); + } + finally { + DatabaseUtil.close(rs); + DatabaseUtil.close(stmt); + } + + } + + /** + * Get the table and view names for a given connection object. + * @param conn the Connection object + * @return the list of table and view names as a List. + * @exception Failed to get the table and view names from the database. + */ + public static java.util.List getTableAndViewNames(java.sql.Connection conn) + throws Exception { + + ResultSet rs = null; + try { + DatabaseMetaData meta = conn.getMetaData(); + if (meta == null) { + return null; + } + + rs = meta.getTables(null, null, null, DB_MIXED_TYPES); + if (rs == null) { + return null; + } + + java.util.List list = new java.util.ArrayList(); + while (rs.next()) { + String tableOrViewName = DatabaseUtil.getTrimmedString(rs, COLUMN_NAME_TABLE_NAME); + System.out.println("getTableNames(): tableOrViewName="+tableOrViewName); + if (tableOrViewName != null) { + list.add(tableOrViewName); + } + } + + return list; + } + catch(Exception e) { + e.printStackTrace(); + throw new Exception(e.toString()); + } + finally { + DatabaseUtil.close(rs); + } + + } + + /** + * Get the Oracle table and view names for a given connection object. + * If you use the getTableAndViewNames() for an Oracle database, you + * will get lots of auxiliary tables and views, which belong to the user, + * but user is not interested in seeing them. + * + * @param conn the Connection object + * @return the list of table and view names as a List. + * @exception Failed to get the table and view names from the database. + */ + public static java.util.List getOracleTableAndViewNames(java.sql.Connection conn) + throws Exception { + + Statement stmt = null; + ResultSet rs = null; + try { + + stmt = conn.createStatement(); + rs = stmt.executeQuery(ORACLE_TABLES_AND_VIEWS); + + if (rs == null) { + return null; + } + + java.util.List list = new java.util.ArrayList(); + while (rs.next()) { + String tableOrViewName = DatabaseUtil.getTrimmedString(rs, 1); + System.out.println("tableOrViewName="+tableOrViewName); + if (tableOrViewName != null) { + list.add(tableOrViewName); + } + } + + return list; + } + catch (Exception e ) { + e.printStackTrace(); + throw new Exception(e.toString()); + } + finally { + DatabaseUtil.close(rs); + DatabaseUtil.close(stmt); + } + + } + + /** + * Retrieves the name of this JDBC driver for a given connection object. + * + * @param conn the Connection object. + * @return the name of this JDBC driver. + * @exception Failed to get the name of this JDBC driver from the database. + */ + public static String getDriverName(java.sql.Connection conn) + throws Exception { + + try { + DatabaseMetaData meta = conn.getMetaData(); + if (meta == null) { + return null; + } + + return meta.getDriverName(); + } + catch (Exception e ) { + e.printStackTrace(); + throw new Exception(e.toString()); + } + + } + /** + * Retrieves the JDBC driver version for a given connection object. + * + * @param conn the Connection object. + * @return the JDBC driver version. + * @exception Failed to get the the JDBC driver version from the database. + */ + public static String getDriverVersion(java.sql.Connection conn) + throws Exception { + + try { + DatabaseMetaData meta = conn.getMetaData(); + if (meta == null) { + return null; + } + + return meta.getDriverVersion(); + } + catch (Exception e ) { + e.printStackTrace(); + throw new Exception(e.toString()); + } + + } + + /** + * Retrieves a description of the given table's primary key columns. + * @param conn the Connection object + * @param tableName name of a table in the database. + * @return the list of column names (which form the Primary Key) as a List. + * @exception Failed to get the PrimaryKeys for a given table. + */ + public static java.util.List getPrimaryKeys(java.sql.Connection conn, + String tableName) + throws Exception { + + ResultSet rs = null; + try { + if ((tableName == null) || (tableName.length() == 0)) { + return null; + } + + DatabaseMetaData meta = conn.getMetaData(); + if (meta == null) { + return null; + } + + // + // The Oracle database stores its table names as Upper-Case, + // if you pass a table name in lowercase characters, it will not work. + // MySQL database does not care if table name is uppercase/lowercase. + // + rs = meta.getPrimaryKeys(null, null, tableName.toUpperCase()); + if (rs == null) { + return null; + } + + java.util.List list = new java.util.ArrayList(); + while (rs.next()) { + String columnName = DatabaseUtil.getTrimmedString(rs, COLUMN_NAME_COLUMN_NAME); + System.out.println("getPrimaryKeys(): columnName="+columnName); + if (columnName != null) { + list.add(columnName); + } + } + + return list; + } + catch(Exception e) { + e.printStackTrace(); + throw new Exception(e.toString()); + } + finally { + DatabaseUtil.close(rs); + } + + } + + /** + * Retrieves a description of the foreign key columns that + * reference the given table's primary key columns (the foreign + * keys exported by a table). They are ordered by FKTABLE_CAT, + * FKTABLE_SCHEM, FKTABLE_NAME, and KEY_SEQ. + * + * @param conn the Connection object + * @param catalog database catalog. + * @param schema database schema. + * @param tableName name of a table in the database. + * @return the list (as an XML string) of the foreign key columns + * that reference the given table's primary key columns + * + * @exception Failed to get the ExportedKeys for a given table. + */ + public static String getExportedKeys(java.sql.Connection conn, + String catalog, + String schema, + String tableName) + throws Exception { + + ResultSet rs = null; + try { + if ((tableName == null) || (tableName.length() == 0)) { + return null; + } + + DatabaseMetaData meta = conn.getMetaData(); + if (meta == null) { + return null; + } + + // + // The Oracle database stores its table names as Upper-Case, + // if you pass a table name in lowercase characters, it will not work. + // MySQL database does not care if table name is uppercase/lowercase. + // + rs = meta.getExportedKeys(catalog, schema, tableName.toUpperCase()); + if (rs == null) { + return null; + } + + StringBuffer buffer = new StringBuffer(); + buffer.append(""); + while (rs.next()) { + String fkTableName = DatabaseUtil.getTrimmedString(rs, "FKTABLE_NAME"); + String fkColumnName = DatabaseUtil.getTrimmedString(rs, "FKCOLUMN_NAME"); + int fkSequence = rs.getInt("KEY_SEQ"); + //System.out.println("getExportedKeys(): fkTableName="+fkTableName); + //System.out.println("getExportedKeys(): fkColumnName="+fkColumnName); + //System.out.println("getExportedKeys(): fkSequence="+fkSequence); + buffer.append(""); + buffer.append(""); + buffer.append(catalog); + buffer.append(""); + buffer.append(""); + buffer.append(schema); + buffer.append(""); + buffer.append(""); + buffer.append(tableName); + buffer.append(""); + buffer.append(""); + buffer.append(fkTableName); + buffer.append(""); + buffer.append(""); + buffer.append(fkColumnName); + buffer.append(""); + buffer.append(""); + buffer.append(fkSequence); + buffer.append(""); + buffer.append(""); + } + buffer.append(""); + return buffer.toString(); + } + catch(Exception e) { + e.printStackTrace(); + throw new Exception(e.toString()); + } + finally { + DatabaseUtil.close(rs); + } + + } + + /** + * Retrieves a description of the primary key columns that are + * referenced by a table's foreign key columns (the primary keys + * imported by a table). They are ordered by PKTABLE_CAT, + * PKTABLE_SCHEM, PKTABLE_NAME, and KEY_SEQ. + * + * @param conn the Connection object + * @param catalog database catalog. + * @param schema database schema. + * @param tableName name of a table in the database. + * @return the list (as an XML string) of the primary key columns + * that are referenced by a table's foreign key columns + * + * @exception Failed to get the ExportedKeys for a given table. + */ + public static String getImportedKeys(java.sql.Connection conn, + String catalog, + String schema, + String tableName) + throws Exception { + + ResultSet rs = null; + try { + if ((tableName == null) || (tableName.length() == 0)) { + return null; + } + + DatabaseMetaData meta = conn.getMetaData(); + if (meta == null) { + return null; + } + + // + // The Oracle database stores its table names as Upper-Case, + // if you pass a table name in lowercase characters, it will not work. + // MySQL database does not care if table name is uppercase/lowercase. + // + rs = meta.getImportedKeys(catalog, schema, tableName.toUpperCase()); + if (rs == null) { + return null; + } + + StringBuffer buffer = new StringBuffer(); + buffer.append(""); + while (rs.next()) { + + String pkTableName = DatabaseUtil.getTrimmedString(rs, "PKTABLE_NAME"); + String pkColumnName = DatabaseUtil.getTrimmedString(rs, "PKCOLUMN_NAME"); + String fkTableName = DatabaseUtil.getTrimmedString(rs, "FKTABLE_NAME"); + String fkColumnName = DatabaseUtil.getTrimmedString(rs, "FKCOLUMN_NAME"); + int fkSequence = rs.getInt("KEY_SEQ"); + + buffer.append(""); + buffer.append(""); + buffer.append(catalog); + buffer.append(""); + buffer.append(""); + buffer.append(schema); + buffer.append(""); + buffer.append(""); + buffer.append(tableName); + buffer.append(""); + buffer.append(""); + buffer.append(pkTableName); + buffer.append(""); + buffer.append(""); + buffer.append(pkColumnName); + buffer.append(""); + buffer.append(""); + buffer.append(fkTableName); + buffer.append(""); + buffer.append(""); + buffer.append(fkColumnName); + buffer.append(""); + buffer.append(""); + buffer.append(fkSequence); + buffer.append(""); + buffer.append(""); + } + buffer.append(""); + return buffer.toString(); + } + catch(Exception e) { + e.printStackTrace(); + throw new Exception(e.toString()); + } + finally { + DatabaseUtil.close(rs); + } + + } + + /** + * Get column names and their associated types. The result + * is returned as an Hashtable, where key is "column name" + * and value is "column type". If table name is null/empty + * it returns null. + * + * @param conn the Connection object + * @param tableName name of a table in the database. + * @return an Hashtable, where key is "column name" + * and value is "column type". + * @exception Failed to get the column names for a given table. + */ + public static java.util.Hashtable getColumnNames(java.sql.Connection conn, + String tableName) + throws Exception { + + ResultSet rsColumns = null; + try { + if ((tableName == null) || (tableName.length() == 0)) { + return null; + } + + DatabaseMetaData meta = conn.getMetaData(); + if (meta == null) { + return null; + } + + rsColumns = meta.getColumns(null, null, tableName.toUpperCase(), null); + Hashtable columns = new Hashtable(); + while (rsColumns.next()) { + String columnType = rsColumns.getString(COLUMN_NAME_TYPE_NAME); + String columnName = rsColumns.getString(COLUMN_NAME_COLUMN_NAME); + if (columnName != null) { + columns.put(columnName, columnType); + } + } + return columns; + } + catch(Exception e) { + throw new Exception("Error: could not get column names: "+e.toString()); + } + finally { + DatabaseUtil.close(rsColumns); + } + } + + /** + * Get column names and their associated attributes (type, + * size, nullable, ordinal position). The result is returned + * as an XML (as a string object); if table name is null/empty + * it returns null. + * + * @param conn the Connection object + * @param tableName name of a table in the database. + * @return an XML (column names and their associated attributes: + * type, size, nullable, ordinal position). + * @exception Failed to get the column details for a given table. + */ + public static String getColumnDetails(java.sql.Connection conn, + String tableName) + throws Exception { + + ResultSet rsColumns = null; + StringBuffer sb = new StringBuffer(); + try { + if ((tableName == null) || (tableName.length() == 0)) { + return null; + } + + DatabaseMetaData meta = conn.getMetaData(); + if (meta == null) { + return null; + } + + rsColumns = meta.getColumns(null, null, tableName.toUpperCase(), null); + sb.append(""); + while (rsColumns.next()) { + + String columnType = rsColumns.getString(COLUMN_NAME_TYPE_NAME); + String columnName = rsColumns.getString(COLUMN_NAME_COLUMN_NAME); + int size = rsColumns.getInt(COLUMN_NAME_COLUMN_SIZE); + int nullable = rsColumns.getInt(COLUMN_NAME_NULLABLE); + int position = rsColumns.getInt(COLUMN_NAME_ORDINAL_POSITION); + + sb.append(""); + sb.append(columnType); + sb.append(""); + sb.append(size); + sb.append(""); + if (nullable == DatabaseMetaData.columnNullable) { + sb.append("true"); + } + else { + sb.append("false"); + } + sb.append(""); + sb.append(position); + sb.append(""); + } + sb.append(""); + return sb.toString(); + } + catch(Exception e) { + throw new Exception("Error: could not get column names: "+e.toString()); + } + finally { + DatabaseUtil.close(rsColumns); + } + } + + /** + * Get column names and their associated attributes (type, + * size, nullable). The result is returned as an XML (as + * a string object); if table name is null/empty + * it returns null. + * + * @param conn the Connection object + * @param tableName name of a table in the database. + * @param includeType if true, then include type information. + * @param includeSize if true, then include size information. + * @param includeNullable if true, then include nullable information. + * @param includePosition if true, then include ordinal position information. + * @return an XML: column names and their associated attributes: type, + * size, nullable. + * @exception Failed to get the column details for a given table. + */ + public static String getColumnDetails(java.sql.Connection conn, + String tableName, + boolean includeType, + boolean includeSize, + boolean includeNullable, + boolean includePosition) + throws Exception { + + ResultSet rsColumns = null; + StringBuffer sb = new StringBuffer(); + try { + if ((tableName == null) || (tableName.length() == 0)) { + return null; + } + + DatabaseMetaData meta = conn.getMetaData(); + if (meta == null) { + return null; + } + + rsColumns = meta.getColumns(null, null, tableName.toUpperCase(), null); + sb.append(""); + while (rsColumns.next()) { + + String columnName = rsColumns.getString(COLUMN_NAME_COLUMN_NAME); + sb.append(""); + if (includeType) { + String columnType = rsColumns.getString(COLUMN_NAME_TYPE_NAME); + sb.append(""); + sb.append(columnType); + sb.append(""); + } + + if (includeSize) { + int size = rsColumns.getInt(COLUMN_NAME_COLUMN_SIZE); + sb.append(""); + sb.append(size); + sb.append(""); + } + + if (includeNullable) { + int nullable = rsColumns.getInt(COLUMN_NAME_NULLABLE);sb.append(""); + if (nullable == DatabaseMetaData.columnNullable) { + sb.append("true"); + } + else { + sb.append("false"); + } + sb.append(""); + } + + if (includePosition) { + int position = rsColumns.getInt(COLUMN_NAME_ORDINAL_POSITION); + sb.append(""); + sb.append(position); + sb.append(""); + } + + sb.append(""); + } + sb.append(""); + return sb.toString(); + } + catch(Exception e) { + throw new Exception("Error: could not get column names: "+e.toString()); + } + finally { + DatabaseUtil.close(rsColumns); + } + } + + /** + * Get Table Privileges: retrieves a description of the access + * rights for each table available in a catalog. Note that a + * table privilege applies to one or more columns in the table. + * It would be wrong to assume that this privilege applies to + * all columns (this may be true for some systems but is not + * true for all.) The result is returned as an XML (as a string + * object); if table name is null/empty it returns null. + * + * In JDBC, Each privilige description has the following columns: + * + * TABLE_CAT String => table catalog (may be null) + * TABLE_SCHEM String => table schema (may be null) + * TABLE_NAME String => table name + * GRANTOR => grantor of access (may be null) + * GRANTEE String => grantee of access + * PRIVILEGE String => name of access (SELECT, INSERT, + * UPDATE, REFRENCES, ...) + * IS_GRANTABLE String => "YES" if grantee is permitted to grant + * to others; "NO" if not; null if unknown + * + * + * @param conn the Connection object + * @param catalogPattern a catalog pattern. + * @param schemaPattern a schema pattern. + * @param tableNamePattern a table name pattern; must match + * the table name as it is stored in the database . + * @return an XML. + * @exception Failed to get the Get Table Privileges. + */ + public static String getTablePrivileges(java.sql.Connection conn, + String catalogPattern, + String schemaPattern, + String tableNamePattern) + throws Exception { + + ResultSet privileges = null; + StringBuffer sb = new StringBuffer(); + try { + if ((tableNamePattern == null) || + (tableNamePattern.length() == 0)) { + return null; + } + + DatabaseMetaData meta = conn.getMetaData(); + if (meta == null) { + return null; + } + + // The '_' character represents any single character. + // The '%' character represents any sequence of zero + // or more characters. + privileges = meta.getTablePrivileges(catalogPattern, + schemaPattern, + tableNamePattern); + sb.append(""); + while (privileges.next()) { + + String catalog = privileges.getString(COLUMN_NAME_TABLE_CATALOG); + String schema = privileges.getString(COLUMN_NAME_TABLE_SCHEMA); + String tableName = privileges.getString(COLUMN_NAME_TABLE_NAME); + String privilege = privileges.getString(COLUMN_NAME_PRIVILEGE); + String grantor = privileges.getString(COLUMN_NAME_GRANTOR); + String grantee = privileges.getString(COLUMN_NAME_GRANTEE); + String isGrantable = privileges.getString(COLUMN_NAME_IS_GRANTABLE); + + sb.append(""); + sb.append(catalog); + sb.append(""); + sb.append(schema); + sb.append(""); + sb.append(privilege); + sb.append(""); + sb.append(grantor); + sb.append(""); + sb.append(isGrantable); + sb.append(""); + sb.append(grantee); + sb.append("
"); + } + sb.append("
"); + return sb.toString(); + } + catch(Exception e) { + throw new Exception("Error: could not get table privileges: "+e.toString()); + } + finally { + DatabaseUtil.close(privileges); + } + } + + /** + * Get Table's Columns Privileges: retrieves a description + * of the access rights for a table's columns available in + * a catalog. The result is returned as an XML (as a string + * object); if table name is null/empty it returns null. + * + * In JDBC, Each privilige description has the following columns: + * + * TABLE_CAT String => table catalog (may be null) + * TABLE_SCHEM String => table schema (may be null) + * TABLE_NAME String => table name + * COLUMN_NAME String => column name + * GRANTOR => grantor of access (may be null) + * GRANTEE String => grantee of access + * PRIVILEGE String => name of access (SELECT, INSERT, + * UPDATE, REFRENCES, ...) + * IS_GRANTABLE String => "YES" if grantee is permitted to grant + * to others; "NO" if not; null if unknown + * + * + * @param conn the Connection object + * @param catalog a catalog. + * @param schema a schema. + * @param tableName a table name; must match + * the table name as it is stored in the database . + * @param columnNamePattern a column name pattern. + * @return an XML. + * @exception Failed to get the Get Table's Column Privileges. + */ + public static String getColumnPrivileges(java.sql.Connection conn, + String catalog, + String schema, + String tableName, + String columnNamePattern) + throws Exception { + + ResultSet privileges = null; + StringBuffer sb = new StringBuffer(); + try { + if ((tableName == null) || + (tableName.length() == 0)) { + return null; + } + + DatabaseMetaData meta = conn.getMetaData(); + if (meta == null) { + return null; + } + + // The '_' character represents any single character. + // The '%' character represents any sequence of zero + // or more characters. + privileges = meta.getColumnPrivileges(catalog, + schema, + tableName, + columnNamePattern); + sb.append(""); + while (privileges.next()) { + + String dbCatalog = privileges.getString(COLUMN_NAME_TABLE_CATALOG); + String dbSchema = privileges.getString(COLUMN_NAME_TABLE_SCHEMA); + String dbTable = privileges.getString(COLUMN_NAME_TABLE_NAME); + String dbColumn = privileges.getString(COLUMN_NAME_COLUMN_NAME); + String dbPrivilege = privileges.getString(COLUMN_NAME_PRIVILEGE); + String dbGrantor = privileges.getString(COLUMN_NAME_GRANTOR); + String dbGrantee = privileges.getString(COLUMN_NAME_GRANTEE); + String dbIsGrantable = privileges.getString(COLUMN_NAME_IS_GRANTABLE); + + sb.append(""); + sb.append(dbCatalog); + sb.append(""); + sb.append(dbSchema); + sb.append(""); + sb.append(dbPrivilege); + sb.append(""); + sb.append(dbGrantor); + sb.append(""); + sb.append(dbIsGrantable); + sb.append(""); + sb.append(dbGrantee); + sb.append(""); + } + sb.append(""); + return sb.toString(); + } + catch(Exception e) { + throw new Exception("Error: could not get table's column privileges: "+e.toString()); + } + finally { + DatabaseUtil.close(privileges); + } + } + + /** + * Retrieves a description of a table's optimal set of columns that + * uniquely identifies a row. They are ordered by SCOPE The result + * is returned as an XML (as a serialized string object); if table + * name is null/empty it returns null. + * + * @param conn the Connection object + * @param catalog a catalog name; must match the catalog name + * as it is stored in the database; "" retrieves those without + * a catalog; null means that the catalog name should not be + * used to narrow the search + * @param schema a schema name; must match the schema name as it + * is stored in the database; "" retrieves those without a + * schema; null means that the schema name should not be + * used to narrow the search + * @param table a table name; must match the table name as it + * is stored in the database + * @param scope the scope of interest; possible values are: + *

+	 *		bestRowTemporary - very temporary, while using row
+	 *		bestRowTransaction - valid for remainder of current transaction
+	 *		bestRowSession - valid for remainder of current session
+	 * 
+ * + * @param nullable include columns that are nullable. + * @return the result is returned as an XML (serialized as a String object) + * @exception Failed to get the Index Information. + */ + public static String getBestRowIdentifier(java.sql.Connection conn, + String catalog, + String schema, + String table, + int scope, + boolean nullable) + throws Exception { + + ResultSet rs = null; + try { + if ((table == null) || (table.length() == 0)) { + return null; + } + + DatabaseMetaData meta = conn.getMetaData(); + if (meta == null) { + return null; + } + + // The '_' character represents any single character. + // The '%' character represents any sequence of zero + // or more characters. + rs = meta.getBestRowIdentifier(catalog, + schema, + table, + scope, + nullable); + StringBuffer sb = new StringBuffer(""); + sb.append(""); + while (rs.next()) { + + short actualScope = rs.getShort(COLUMN_NAME_SCOPE); + String columnName = rs.getString(COLUMN_NAME_COLUMN_NAME); + int dataType = rs.getInt(COLUMN_NAME_DATA_TYPE); + String typeName = rs.getString(COLUMN_NAME_TYPE_NAME); + int columnSize = rs.getInt(COLUMN_NAME_COLUMN_SIZE); + short decimalDigits = rs.getShort(COLUMN_NAME_DECIMAL_DIGITS); + short pseudoColumn = rs.getShort(COLUMN_NAME_PSEUDO_COLUMN); + + sb.append(""); + appendXMLTag(sb, "scope", actualScope); + appendXMLTag(sb, "columnName", columnName); + appendXMLTag(sb, "dataType", dataType); + appendXMLTag(sb, "typeName", typeName); + appendXMLTag(sb, "columnSize", columnSize); + appendXMLTag(sb, "decimalDigits", decimalDigits); + appendXMLTag(sb, "pseudoColumn", pseudoColumn); + sb.append(""); + } + sb.append(""); + return sb.toString(); + } + catch(Exception e) { + throw new Exception("Error: could not get table's Best Row Identifier: "+e.toString()); + } + finally { + DatabaseUtil.close(rs); + } + } + + /** + * Retrieves a description of the given table's indices and + * statistics. The result is returned as an XML (as a string + * object); if table name is null/empty it returns null. + * + * + * @param conn the Connection object + * @param catalog a catalog. + * @param schema a schema. + * @param tableName a table name; must match + * the table name as it is stored in the database . + * @param unique when true, return only indices for unique values; + * when false, return indices regardless of whether unique or not + * @param approximate when true, result is allowed to reflect + * approximate or out of data values; when false, results are + * requested to be accurate + * @return an XML. + * @exception Failed to get the Index Information. + */ + public static String getIndexInformation(java.sql.Connection conn, + String catalog, + String schema, + String tableName, + boolean unique, + boolean approximate) + throws Exception { + + ResultSet indexInformation = null; + try { + if ((tableName == null) || + (tableName.length() == 0)) { + return null; + } + + DatabaseMetaData meta = conn.getMetaData(); + if (meta == null) { + return null; + } + + // The '_' character represents any single character. + // The '%' character represents any sequence of zero + // or more characters. + indexInformation = meta.getIndexInfo(catalog, + schema, + tableName, + unique, + approximate); + StringBuffer sb = new StringBuffer(""); + sb.append(""); + while (indexInformation.next()) { + + String dbCatalog = indexInformation.getString(COLUMN_NAME_TABLE_CATALOG); + String dbSchema = indexInformation.getString(COLUMN_NAME_TABLE_SCHEMA); + String dbTableName = indexInformation.getString(COLUMN_NAME_TABLE_NAME); + boolean dbNoneUnique = indexInformation.getBoolean(COLUMN_NAME_NON_UNIQUE); + String dbIndexQualifier = indexInformation.getString(COLUMN_NAME_INDEX_QUALIFIER); + String dbIndexName = indexInformation.getString(COLUMN_NAME_INDEX_NAME); + short dbType = indexInformation.getShort(COLUMN_NAME_TYPE); + short dbOrdinalPosition = indexInformation.getShort(COLUMN_NAME_ORDINAL_POSITION); + String dbColumnName = indexInformation.getString(COLUMN_NAME_COLUMN_NAME); + String dbAscOrDesc = indexInformation.getString(COLUMN_NAME_ASC_OR_DESC); + int dbCardinality = indexInformation.getInt(COLUMN_NAME_CARDINALITY); + int dbPages = indexInformation.getInt(COLUMN_NAME_PAGES); + String dbFilterCondition = indexInformation.getString(COLUMN_NAME_FILTER_CONDITION); + + sb.append(""); + appendXMLTag(sb, "catalog", dbCatalog); + appendXMLTag(sb, "schema", dbSchema); + appendXMLTag(sb, "nonUnique", dbNoneUnique); + appendXMLTag(sb, "indexQualifier", dbIndexQualifier); + appendXMLTag(sb, "type", getIndexType(dbType)); + appendXMLTag(sb, "ordinalPosition", dbOrdinalPosition); + appendXMLTag(sb, "ascendingOrDescending", dbAscOrDesc); + appendXMLTag(sb, "cardinality", dbCardinality); + appendXMLTag(sb, "pages", dbPages); + appendXMLTag(sb, "filterCondition", dbFilterCondition); + sb.append(""); + } + sb.append(""); + return sb.toString(); + } + catch(Exception e) { + throw new Exception("Error: could not get table's Index Information: "+e.toString()); + } + finally { + DatabaseUtil.close(indexInformation); + } + } + + private static String getIndexType(short type) { + + switch (type) { + case DatabaseMetaData.tableIndexClustered: + return "tableIndexClustered"; + case DatabaseMetaData.tableIndexHashed: + return "tableIndexHashed"; + case DatabaseMetaData.tableIndexOther: + return "tableIndexOther"; + case DatabaseMetaData.tableIndexStatistic: + return "tableIndexStatistic"; + default: + return"tableIndexOther"; + } + } + + /** + * Get Schemas(): Retrieves the schema names available + * in this database. The results are ordered by schema name. + * + * + * @param conn the Connection object. + * @return an XML. + * @exception Failed to get the Get Schemas. + */ + public static String getSchemas(java.sql.Connection conn) + throws Exception { + + ResultSet schemas = null; + StringBuffer sb = new StringBuffer(); + try { + DatabaseMetaData meta = conn.getMetaData(); + if (meta == null) { + return null; + } + + schemas = meta.getSchemas(); + sb.append(""); + while (schemas.next()) { + + String tableSchema = schemas.getString(1); // "TABLE_SCHEM" + //String tableCatalog = schemas.getString(2); //"TABLE_CATALOG" + + sb.append(""); + sb.append(tableSchema); + sb.append(""); + } + sb.append(""); + return sb.toString(); + } + catch(Exception e) { + throw new Exception("Error: could not get schemas: "+e.toString()); + } + finally { + DatabaseUtil.close(schemas); + } + } + /** + * Get Catalogs: Retrieves the catalog names available in + * this database. The results are ordered by catalog name. + * + * + * @param conn the Connection object + * @return an XML. + * @exception Failed to get the Get Catalogs. + */ + public static String getCatalogs(java.sql.Connection conn) + throws Exception { + + ResultSet catalogs = null; + StringBuffer sb = new StringBuffer(); + try { + DatabaseMetaData meta = conn.getMetaData(); + if (meta == null) { + return null; + } + + catalogs = meta.getCatalogs(); + sb.append(""); + while (catalogs.next()) { + String catalog = catalogs.getString(1); //"TABLE_CATALOG" + sb.append(""); + sb.append(catalog); + sb.append(""); + } + sb.append(""); + return sb.toString(); + } + catch(Exception e) { + throw new Exception("Error: could not get catalogs: "+e.toString()); + } + finally { + DatabaseUtil.close(catalogs); + } + } + + /** + * Listing Available SQL Types Used by a Database. This method + * retrieves the SQL data types supported by a database and driver. + * + * + * @param conn the Connection object + * @return an XML (as a String object). + * @exception Failed to get the Available SQL Types Used by a Database. + */ + public static String getAvailableSqlTypes(Connection conn) + throws Exception { + ResultSet rs = null; + try { + // Get database meta data + DatabaseMetaData meta = conn.getMetaData(); + if (meta == null) { + return null; + } + + // Get type infornmation + rs = meta.getTypeInfo(); + + // Retrieve type info from the result set + StringBuffer sb = new StringBuffer(); + sb.append(""); + while (rs.next()) { + // Get the database-specific type name + String typeName = rs.getString("TYPE_NAME"); + + // Get the java.sql.Types type to which this + // database-specific type is mapped + short dataType = rs.getShort("DATA_TYPE"); + + // Get the name of the java.sql.Types value. + String jdbcTypeName = getJdbcTypeName(dataType); + + sb.append(""); + } + sb.append(""); + return sb.toString(); + } + catch (SQLException e) { + throw new Exception("Error: could not the available SQL types used by a database.: "+e.toString()); + } + finally { + DatabaseUtil.close(rs); + } + } + + /** + * Listing Available ResultSet Types Used by a Database. This method + * retrieves the ResultSet Types supported by a database and driver. + * + * + * @param conn the Connection object + * @return an XML (as a String object). + * @exception Failed to get the Available ResultSet Types from Database. + */ + public static String getAvailableResultSetTypes(Connection conn) + throws Exception { + try { + // Get database meta data + DatabaseMetaData meta = conn.getMetaData(); + if (meta == null) { + return null; + } + + // Retrieve type info from the result set + StringBuffer sb = new StringBuffer(); + sb.append(""); + + if (meta.supportsResultSetType(ResultSet.TYPE_FORWARD_ONLY)) { + sb.append(""); + } + if (meta.supportsResultSetType(ResultSet.TYPE_SCROLL_INSENSITIVE)) { + sb.append(""); + } + if (meta.supportsResultSetType(ResultSet.TYPE_SCROLL_SENSITIVE)) { + sb.append(""); + } + + sb.append(""); + return sb.toString(); + } + catch (SQLException e) { + throw new Exception("Error: could not the available ResultSet types from database.: "+e.toString()); + } + } + + + /** + * Get the Name of a JDBC Type. This method implements a + * convenient method for converting a java.sql.Types integer + * value into a printable name. This method is useful for debugging. + * The method uses reflection to get all the field names from + * java.sql.Types. It then retrieves their values and creates a + * map of values to names. + * This method returns the name of a JDBC type. + * Returns null if jdbcType is not recognized. + * + * @param jdbcType the jdbc type as an interger + * @return the equivalent JDBC type name + */ + public static String getJdbcTypeName(int jdbcType) { + // Return the JDBC type name + return (String) JDBC_TYPE_NAME_MAP.get(new Integer(jdbcType)); + } + + private static String getMsSqlStoredProcedureNames(java.sql.Connection conn) { + + ResultSet rs = null; + try { + DatabaseMetaData meta = conn.getMetaData(); + if (meta == null) { + return null; + } + + rs = meta.getProcedures(null, null, "%"); + StringBuffer buffer = new StringBuffer(); + + //System.out.println("--------------------------- Stored Procedure Names"); + while (rs.next()) { + String spName = rs.getString("PROCEDURE_NAME"); + String spType = getStoredProcedureType(rs.getInt("PROCEDURE_TYPE")); + + //System.out.println("Stored Procedure Name: " + spName); + //System.out.println("Stored Procedure Type: " + spType); + // + // MS SQL Server appends ";number" to the end of the names + // so, we will chop it + // + buffer.append(""+chopSemicolon(spName)+""+spType+""); + } + + return buffer.toString(); + } + catch(Exception e) { + return null; + } + finally { + try { + if (rs != null) { + rs.close(); + } + } + catch(Exception e){ + // ignore + } + } + + } + + private static String chopSemicolon(String spName) { + if ((spName == null) || (spName.length() == 0)) { + return spName; + } + + int semicolonPosition = spName.indexOf(";"); + if (semicolonPosition == -1) { + // then semicolon not found + return spName; + } + else { + return spName.substring(0, semicolonPosition); + } + } + + /** + * Get database product name and version information. + * This method calls 4 methods (getDatabaseMajorVersion(), + * getDatabaseMinorVersion(), getDatabaseProductName(), + * getDatabaseProductVersion()) to get the required information + * and it represents the information as an XML. + * + * @param conn the Connection object + * @return database product name and version information + * as an XML document (represented as a String object). + * + */ + public static String getDatabaseInformation(java.sql.Connection conn) + throws Exception { + + try { + DatabaseMetaData meta = conn.getMetaData(); + if (meta == null) { + return null; + } + + StringBuffer sb = new StringBuffer(""); + sb.append(""); + + // Oracle (and some other vendors) do not support + // some the following methods; therefore, we need + // to use try-catch block. + try { + int majorVersion = meta.getDatabaseMajorVersion(); + appendXMLTag(sb, "majorVersion", majorVersion); + } + catch(Exception e) { + appendXMLTag(sb, "majorVersion", "unsupported feature"); + } + + try { + int minorVersion = meta.getDatabaseMinorVersion(); + appendXMLTag(sb, "minorVersion", minorVersion); + } + catch(Exception e) { + appendXMLTag(sb, "minorVersion", "unsupported feature"); + } + + String productName = meta.getDatabaseProductName(); + String productVersion = meta.getDatabaseProductVersion(); + appendXMLTag(sb, "productName", productName); + appendXMLTag(sb, "productVersion", productVersion); + sb.append(""); + + return sb.toString(); + } + catch(Exception e) { + e.printStackTrace(); + throw new Exception("could not get the database information:"+ + e.toString()); + } + } + + + /** + * Get driver name and version information. + * This method calls 4 methods (getDriverName(), + * getDriverVersion(), getJDBCMajorVersion(), + * getJDBCMinorVersion()) to get the required information + * and it returns the information as an XML. + * + * @param conn the Connection object + * @return driver name and version information + * as an XML document (represented as a String object). + * + */ + public static String getDriverInformation(java.sql.Connection conn) + throws Exception { + + try { + DatabaseMetaData meta = conn.getMetaData(); + if (meta == null) { + return null; + } + + StringBuffer sb = new StringBuffer(""); + sb.append(""); + + // Oracle (and some other vendors) do not support + // some the following methods; therefore, we need + // to use try-catch block. + try { + int jdbcMajorVersion = meta.getJDBCMajorVersion(); + appendXMLTag(sb, "jdbcMajorVersion", jdbcMajorVersion); + } + catch(Exception e) { + appendXMLTag(sb, "jdbcMajorVersion", "unsupported feature"); + } + + try { + int jdbcMinorVersion = meta.getJDBCMinorVersion(); + appendXMLTag(sb, "jdbcMinorVersion", jdbcMinorVersion); + } + catch(Exception e) { + appendXMLTag(sb, "jdbcMinorVersion", "unsupported feature"); + } + + String driverName = meta.getDriverName(); + String driverVersion = meta.getDriverVersion(); + appendXMLTag(sb, "driverName", driverName); + appendXMLTag(sb, "driverVersion", driverVersion); + sb.append(""); + + return sb.toString(); + } + catch(Exception e) { + e.printStackTrace(); + throw new Exception("could not get the database information:"+ + e.toString()); + } + } + + + /** + * Get the stored-procedures names. + * @param conn the Connection object + * @return a table of stored procedures names + * as an XML document (represented as a String object). + * Each element of XML document will have the name and + * type of a stored procedure. + * + */ + public static String getStoredProcedureNames + (java.sql.Connection conn, + String catalog, + String schemaPattern, + String procedureNamePattern) + throws Exception { + + ResultSet rs = null; + try { + DatabaseMetaData meta = conn.getMetaData(); + if (meta == null) { + return null; + } + + rs = meta.getProcedures(catalog, schemaPattern, procedureNamePattern); + StringBuffer sb = new StringBuffer(); + sb.append(""); + + while (rs.next()) { + String spName = rs.getString("PROCEDURE_NAME"); + String spType = getStoredProcedureType(rs.getInt("PROCEDURE_TYPE")); + sb.append(""); + } + sb.append(""); + return sb.toString(); + } + catch(Exception e) { + e.printStackTrace(); + throw new Exception("could not get the names of stored procedures:"+ + e.toString()); + } + finally { + DatabaseUtil.close(rs); + } + } + + private static String getStoredProcedureType(int spType) { + if (spType == DatabaseMetaData.procedureReturnsResult) { + return STORED_PROCEDURE_RETURNS_RESULT; + } + else if (spType == DatabaseMetaData.procedureNoResult) { + return STORED_PROCEDURE_NO_RESULT; + } + else { + return STORED_PROCEDURE_RESULT_UNKNOWN; + } + } + + /** + * Retrieves a description of the given catalog's stored + * procedure parameter and result columns. + * + * @param conn the Connection object + * @param catalog a catalog. + * @param schemaPattern a schema pattern. + * @param procedureNamePattern name of a stored procedure + * @param columnNamePattern a column name pattern. + * @return an XML. + * @throws Exception Failed to get the stored procedure's signature. + */ + public static String getStoredProcedureSignature( + java.sql.Connection conn, + String catalog, + String schemaPattern, + String procedureNamePattern, + String columnNamePattern) + + throws Exception { + + // Get DatabaseMetaData + DatabaseMetaData dbMetaData = conn.getMetaData(); + if (dbMetaData == null) { + return null; + } + + ResultSet rs = dbMetaData.getProcedureColumns(catalog, + schemaPattern, + procedureNamePattern, + columnNamePattern); + + StringBuffer sb = new StringBuffer(""); + sb.append(""); + while(rs.next()) { + // get stored procedure metadata + String procedureCatalog = rs.getString(1); + String procedureSchema = rs.getString(2); + String procedureName = rs.getString(3); + String columnName = rs.getString(4); + short columnReturn = rs.getShort(5); + int columnDataType = rs.getInt(6); + String columnReturnTypeName = rs.getString(7); + int columnPrecision = rs.getInt(8); + int columnByteLength = rs.getInt(9); + short columnScale = rs.getShort(10); + short columnRadix = rs.getShort(11); + short columnNullable = rs.getShort(12); + String columnRemarks = rs.getString(13); + + sb.append(""); + appendXMLTag(sb, "catalog", procedureCatalog); + appendXMLTag(sb, "schema", procedureSchema); + appendXMLTag(sb, "columnName", columnName); + appendXMLTag(sb, "columnReturn", getColumnReturn(columnReturn)); + appendXMLTag(sb, "columnDataType", columnDataType); + appendXMLTag(sb, "columnReturnTypeName", columnReturnTypeName); + appendXMLTag(sb, "columnPrecision", columnPrecision); + appendXMLTag(sb, "columnByteLength", columnByteLength); + appendXMLTag(sb, "columnScale", columnScale); + appendXMLTag(sb, "columnRadix", columnRadix); + appendXMLTag(sb, "columnNullable", columnNullable); + appendXMLTag(sb, "columnRemarks", columnRemarks); + sb.append(""); + + System.out.println("======================================"); + System.out.println("procedureCatalog=" + procedureCatalog); + System.out.println("procedureSchema=" + procedureSchema); + System.out.println("procedureName=" + procedureName); + System.out.println("columnName=" + columnName); + System.out.println("columnReturn=" + columnReturn); + System.out.println("columnDataType=" + columnDataType); + System.out.println("columnReturnTypeName=" + columnReturnTypeName); + System.out.println("columnPrecision=" + columnPrecision); + System.out.println("columnByteLength=" + columnByteLength); + System.out.println("columnScale=" + columnScale); + System.out.println("columnRadix=" + columnRadix); + System.out.println("columnNullable=" + columnNullable); + System.out.println("columnRemarks=" + columnRemarks); + System.out.println("======================================"); + } + sb.append(""); + + // Close database resources + rs.close(); + //conn.close(); + return sb.toString(); + } + + private static String getColumnReturn(short columnReturn) { + + switch(columnReturn) { + case DatabaseMetaData.procedureColumnIn: + return "In"; + case DatabaseMetaData.procedureColumnOut: + return "Out"; + case DatabaseMetaData.procedureColumnInOut: + return "In/Out"; + case DatabaseMetaData.procedureColumnReturn: + return "return value"; + case DatabaseMetaData.procedureColumnResult: + return "return ResultSet"; + default: + return "unknown"; + } + + } + + public static boolean indexExists(java.sql.Connection conn, + String catalog, + String schema, + String tableName, + String indexName) + throws Exception { + + if ((tableName == null) || (tableName.length() == 0) || + (indexName == null) || (indexName.length() == 0)) { + return false; + } + + DatabaseMetaData dbMetaData = conn.getMetaData(); + if (dbMetaData == null) { + return false; + } + + ResultSet rs = dbMetaData.getIndexInfo(catalog, + schema, + tableName, + false, + true); + while (rs.next()) { + String dbIndexName = rs.getString(COLUMN_NAME_INDEX_NAME); + if (indexName.equals(dbIndexName)) { + return true; + } + } + return false; + + } + + private static void appendXMLTag(StringBuffer buffer, + String tagName, + boolean value) { + buffer.append("<"); + buffer.append(tagName); + buffer.append(">"); + buffer.append(value); + buffer.append(""); + } + + private static void appendXMLTag(StringBuffer buffer, + String tagName, + int value) { + buffer.append("<"); + buffer.append(tagName); + buffer.append(">"); + buffer.append(value); + buffer.append(""); + } + + private static void appendXMLTag(StringBuffer buffer, + String tagName, + String value) { + buffer.append("<"); + buffer.append(tagName); + buffer.append(">"); + buffer.append(value); + buffer.append(""); + } +} diff --git a/sourceMetadata/jcb-package/src/jcb/meta/ResultSetMetaDataTool.class b/sourceMetadata/jcb-package/src/jcb/meta/ResultSetMetaDataTool.class new file mode 100644 index 0000000000000000000000000000000000000000..6b89ec57b405f3de991f128ceedce490e0d0e259 GIT binary patch literal 5897 zcmb7I33yc189g_dWFEBr;$-rG!CB%gEH1QG zx(HfZyP>F6!J@XcV%q@HLTweTwR>x8ZP8k_E?8}~d)1!*y*EpoQ0tfPd-t9H-h1x9 z-#2;e?FSA6Sfm=uFo+w<@fm!!9G}DI$KVUtso};l+=N{sxmm+40&bNxUzEpfWw;%8 z*s;3|6}UkjdoBd{rKM<#BHrzJ~iW?33|+4PUq8 z8)Z0I)c7Wb<+0z617(-@FT%L*6hE@~=y!McdfNR8 zPTz*$#$aP47+cpENF~Ctb6hAg9;Vkp_~b1n1uMmxo#F_oBkqEov2Iz5&qvre?e z?Q;bJC$z>oM~D=r7jSgDmiaO#R29s2c6r?1fVYFro?I{)aJziuEY!;z=y&yWcl3Mx z?k-Qe$KO4g{aobk>FV6EkJDWqS6hFF-^clr3J&Ldz~kz2uN3_i=8m?Y&9mI= z_jY@Hef_;%Uc=H8X!0J@{vIFWDCZQqNEGp|@O#=$;0d=Y;GwGifVbPbiVUSo!m)6w zRiU_c-YNx~J3go@RQkd(-JgyQ=!x#&K!lQt!E|(}OHZaFseqnh8PuBDp1d^Dm=!k* zMVV)FNFPdtnfG@5U198qou|=z>-3bt+ODU9ZNXHqC&^mr)d#xbn+)#eJZ_dxOb-cL zb76VSD-V8%{wPM-8?Gkcrv)-k#sbc+rDVD?V0Ij@2EVb!J#2N zHmI=F+ML%dmZjIO)f1zbS!kvBdBOW&@V?&-Ym7(+;^{<4UmlhOsLFaMV`6ta9$6qQ z&w(p&r5*op;Gg)H9shRVKX}WIw;gy#fqxBlr5vhA6+4tol_n4*c#Aoj)FaHYn!1{`iFmZep(d$H1xL-M^?E|DSya}NSm&AY?Q1~M&Kx;YxD*{COyEP|G~ixw=L%W|z*lE@Te zCLT2*BSGEqbS%{}OWa{RW-AoUYIR^cb_iQz!9KE$TVn3bQn4|Z64Kz43gb=G7ETUD zf?ERN%XEjDqfSvMHz$0-0X-sXuVVyEkv|yaqEjW{mZW>j5G8YE+gNjrNMs#5jwx_Q zg2|-0vsQMFNlE)L1@jESP(lxd#T5=!Crl;DP%uK;dI6Q;q${0@dt;%59@S$h2cA;n zM6K(oL^$bAClY!rw8epAk~@@0VB`b`o)O8!aI#HbD;-gfY{|_%YpwRDBN21;b8;H@ zcj>{wj#z|@FUT66?+zyQfF4VRQ{j!IeNn`Ya5A6=6QT9y=9fjLQ5Ieo)7cB`AvVEC ze4Rrzh>4}i(0V-@bg21)iW(W8qLx__MI*--u!C+04KzmCJ#(!$6FDhL#xs{q9RnMf z*$R^kk+kc;dA@8h@T(;&&lWhN%66AwanpE5 zs2JFiOzBZh#M7dv+3r|7o&1JMu^RMXl!utLJW|Z?56L3#D(r^FZInCRNKsihdS|v9 zM3ETpz?i<7jJy!nFafE(S&-sFx;>o=M;hhU8epJ%2&h9S5>M(1^GDO6pm|#@jTYrD zm0TTYsd(nNi5a)&-4WbnqXATG#%OlrxGN2F0;yo=lI}z>MD6l&B6C7%M31dYt!KPb z@g81G2}xcnoSPdZ+V5_4OnSCHcRU&m$}MKsH|wEvihHJ7w#%lxJ6o<1ZIg7r)lqtC zg0+fKG+Uw(BQvricS=WK;8QwHU~;gQ*&{O!k)>HVU6RY;tdvD(>2_XPPi)Cu_W8~n zEv-q{@PEe9xUTsXJ9;FnS^4&G8;v=yd74pV6;xzr%{G|Bk`lBmJD=^0w2VUI1IpYZ zurt#Y>2AV+^hB%l%-)it4;bCW#M5in6n>^y-yxXE-&2G9Q921#(6N>``8uK^oI$)k z51&sQ&chcHZ^*-E5nqyrn}{QMcnNVd51&mO%fl|>cph#g9?HXR;!E?ehd7akR}d%j zu$MTMhkeB9JlsvZF%PdM-js(si8tqAKk=44+(mp@9$rIyc^+PcGWwFAOnh#oN2@vV zqX;E+`=R#nMd3qymKs7Q#^A%aif)&sPoNk!j$7*vqDaA4{|IdR>JOq=p~co(J!3a! zSKIcW{C?P+CBrD?SYLe*_975$D^`2oIVMxuFvgIfOyNc>KEb{^?kgW<-`;l~&FQ!t z&uV*-}a;IlCoE}YKyCb+Q-D{wA+=t4XC;b-`L3{fZD6rdZr@e#7v zXz$guc3Z|;wTQA(&fJ-^R;xPz$G+kg)8fKmIs}7-}Z$HM?PqJACS31WH zqtd|R#gNKjIBB>cm{3I1OScuNZ8kdPaBjPEA{SNmoZPFCAA=F2SBTRSUjHLK@*;vlQyYOeb@*KKD7>|oYkPdDzO>~_lbFe@{ToI*!_ z6d$wF<~EL^-NkiB>7b)1qxREpLW#Q1a+;HdR#HgAE1f6tL8IFb;bc0r#y`K|AZ8X} zKBF*;!z1Rt*_@lxWSc*Y?mndm(`>^y^*)|q+O~ie0Xu2aE~dz>n2+0-Cbwe=?qE9X zW;*PF7k4os?#3G2GeYl=XZ4O-db{73-qdrhf}wV85t?k%YzHter&^VfQ-`VAgH-Jy zs`fDR^e9^J*a$WFS#G)SURIsB@1i=x_FOg^4y@~Q*6&9{dxLZSFc$P$nb|;BHug3+ z7m6&CrV|^OddWJcm0Z*ZO_pkWvv$Z6P0-GF1v{->$ybNsj6^VIYOR@O^w7B6EC zUO_#MV-a4(S$K_g_B!k7H9GSR^x@4sE6SKCJ4`Fot>i0ad`>-tI>zpFD!kY@+j++H z130t6c~;%@gZN+(4A3Nied7R{8=Ol7v{;~3z*1}3*#cNy#xj?HWfpJ?XtRJvz;bKP z3IQuE;1zI=fO8w1J^}3(@C)d$K&OE7EYKw&Ab?tT3+S9Q)5x7Dlu72z-%=Y3)Kv?s2ZH3=Ac*AVo){UQne6U z)nfkAYQj#{iaV7X_p6mSqT2De>cW$%mp>FPz#A&ap0D%AY?!|ZBWk9Kj))q6N3oEk zMh(;JSe^@d>zo%G0~1C-P=;JPo-ApqE<>rh92M#cOi)*%N^RwR!yj?~n~)8l v@kE5zkZ?N*caZQ}5?*HzUjLqi11BQfNx~aRcoPYCk?>|xeTqgF;nV*G??Jh# literal 0 HcmV?d00001 diff --git a/sourceMetadata/jcb-package/src/jcb/meta/ResultSetMetaDataTool.java b/sourceMetadata/jcb-package/src/jcb/meta/ResultSetMetaDataTool.java new file mode 100644 index 0000000..96f205b --- /dev/null +++ b/sourceMetadata/jcb-package/src/jcb/meta/ResultSetMetaDataTool.java @@ -0,0 +1,414 @@ +package jcb.meta; + +import java.util.*; +import java.io.*; +import java.sql.*; +import javax.sql.*; + +import javax.sql.rowset.WebRowSet; +import com.sun.rowset.WebRowSetImpl; + +import jcb.db.*; +import jcb.util.*; + +/** + * This class provides class-level methods for getting database metadata. + * + */ + public class ResultSetMetaDataTool { + + private static final String XML_METADATA_TAG_COLUMN = "column"; + private static final String XML_METADATA_TAG_CATALOG_NAME = "catalog"; + private static final String XML_METADATA_TAG_SCHEMA_NAME = "schema"; + private static final String XML_METADATA_TAG_COLUMN_DISPLAY_SIZE = "columnDisplaySize"; + private static final String XML_METADATA_TAG_COLUMN_LABEL = "columnLabel"; + private static final String XML_METADATA_TAG_COLUMN_NAME = "columnName"; + private static final String XML_METADATA_TAG_COLUMN_TYPE_NAME = "columnTypeName"; + private static final String XML_METADATA_TAG_COLUMN_CLASS_NAME = "columnClassName"; + private static final String XML_METADATA_TAG_COLUMN_TYPE = "columnType"; + private static final String XML_METADATA_TAG_TABLE_NAME = "tableName"; + private static final String XML_METADATA_TAG_PRECISION = "precision"; + private static final String XML_METADATA_TAG_SCALE = "scale"; + private static final String XML_METADATA_TAG_IS_AUTO_INCREMENT = "isAutoIncrement"; + private static final String XML_METADATA_TAG_IS_CURRENCY = "isCurrency"; + private static final String XML_METADATA_TAG_IS_READ_ONLY = "isReadOnly"; + private static final String XML_METADATA_TAG_IS_SEARCHABLE = "isSearchable"; + private static final String XML_METADATA_TAG_IS_DEFINITELY_WRITABLE = "isDefinitelyWritable"; + private static final String XML_METADATA_TAG_IS_WRITABLE = "isWritable"; + private static final String XML_METADATA_TAG_IS_NULLABLE = "isNullable"; + private static final String XML_METADATA_TAG_IS_SIGNED = "isSigned"; + private static final String XML_METADATA_TAG_IS_CASE_SENSITIVE = "isCaseSensitive"; + + + /** + * Dump ResultSet. For Debugging purposes. + * @param rs the ResultSet object + * @exception Failed to dump the ResultSet. + */ + public static void dumpResultSet(ResultSet rs) + throws SQLException { + + // Get the ResultSetMetaData. This will + // be used for the column headings + ResultSetMetaData rsmd = rs.getMetaData(); + if (rsmd == null) { + return; + } + + // Get the number of columns in the result set + int numberOfColumns = rsmd.getColumnCount(); + + // Display column headings + + for (int i=1; i<=numberOfColumns; i++) { + if (i > 1) System.out.print(","); + System.out.print(rsmd.getColumnLabel(i)); + } + System.out.println(""); + + // Display data, fetching until end of the result set + + while (rs.next ()) { + + // Loop through each column, getting the + // column data and displaying + + for (int i=1; i<=numberOfColumns; i++) { + if (i > 1) System.out.print(","); + System.out.print(rs.getString(i)); + } + System.out.println(""); + + // Fetch the next result set row + } + } + + /** + * Dump ResultSet. For Debugging purposes. + * @param rs the ResultSet object + * @exception Failed to dump the ResultSet. + */ + public static void dumpResultSet2(ResultSet rs) + throws Exception { + + try { + ResultSetMetaData meta = rs.getMetaData(); + if (meta == null) { + return; + } + + int numbers = 0; + int columns = meta.getColumnCount(); + for (int i=1; i<=columns; i++) { + System.out.println (meta.getColumnLabel(i) + "\t" + + meta.getColumnTypeName(i)); + if (meta.isSigned(i)) { + // is it a signed number? + numbers++; + } + } + System.out.println ("Columns: " + columns + " Numeric: " + numbers); + } + catch(Exception e) { + e.printStackTrace(); + throw new Exception(e.toString()); + } + finally { + DatabaseUtil.close(rs); + } + + } + + /** + * Get table's metadata (column names and their associated + * attributes (type, size, nullable). The result is returned + * as an XML (as a serialized string object); if table name + * is null/empty it returns null. + * + * This method uses the sun.jdbc.rowset.WebRowSet class to + * extract table's metadata according to the DTD defined at: + * http://java.sun.com/j2ee/dtds/RowSet.dtd + * The WebRowSet class is designed to return data & metadata + * for a ResultSet, but we will limit it just to return the + * meta data. We will pass the following query, which returns + * only metadata (zero number of data records returned). + * + * select * from TABLE-NAME where 1 = 0 + * + * By using the WebRowSet class, we donot need to hand craft + * the generated XML. + * + * @param conn the Connection object. + * @param tableName the table name. + * @return result set's meta data as an XML as string object; + * this meta data includes column names and their associated + * attributes: type, size, nullable. + * @exception Failed to get the result set's meta data as an XML. + */ + public static String getTableMetaDataUsingWebRowSet(Connection conn, + String tableName) + throws Exception { + + if ((conn == null) || + (tableName == null) || + (tableName.length() == 0)) { + return null; + } + + String query = "select * from "+ tableName.toUpperCase() + " where 1 = 0"; + + WebRowSet webRS = new WebRowSetImpl(); + webRS.setCommand(query); + webRS.execute(conn); + if (webRS == null) { + return null; + } + + // convert xml to a String object + StringWriter sw = new StringWriter(); + webRS.writeXml(sw); + return sw.toString(); + } + + /** + * Get table's metadata (column names and their associated attributes + * (type, size, nullable). The result is returned as an XML + * (as a string object); if table name is null/empty + * it returns null. + * + * @param conn the Connection object. + * @param tableName the table name. + * @return result set's meta data as an XML as string object; + * this meta data includes column names and their associated + * attributes: type, size, nullable. + * @exception Failed to get the result set's meta data as an XML. + */ + public static String getTableMetaData(Connection conn, + String tableName) + throws Exception { + + if ((conn == null) || + (tableName == null) || + (tableName.length() == 0)) { + return null; + } + + String query = "select * from "+ tableName.toUpperCase() + " where 1 = 0"; + Statement stmt = conn.createStatement(); + ResultSet rs = stmt.executeQuery(query); + + // retrieves the number, types and properties + // of this ResultSet object's columns. + return getResultSetMetaData(rs); + } + + + + /** + * Get column names and their associated attributes (type, + * size, nullable). The result is returned as an XML (as + * a string object); if the result set is null/empty + * it returns null. + * + * @param rs the result set (ResultSet) object. + * @return result set's meta data as an XML as string object; + * this meta data includes column names and their associated + * attributes: type, size, nullable. + * @exception Failed to get the result set's meta data as an XML. + */ + public static String getResultSetMetaData(ResultSet rs) + throws Exception { + + if (rs == null ) { + return null; + } + + // retrieves the number, types and properties + // of this ResultSet object's columns. + ResultSetMetaData rsMetaData = rs.getMetaData(); + if (rsMetaData == null ) { + return null; + } + + StringBuffer sb = new StringBuffer(""); + sb.append(""); + + for (int i=1; i<=numberOfColumns; i++) { + sb.append(getColumnMetaData(rsMetaData, i)); + } + + sb.append(""); + return sb.toString(); + + } + + /** + * Get specific column's associated attributes + * (type, size, nullable). The result is returned + * as an XML (represented as a String object). + * XML attributes (as constants) are prefixed + * with the "XML_METADATA_TAG_". + * + * @param rsMetaData the result set meta data object. + * @param columnNumber the column number. + * @return result set's meta data as an XML as + * string object; this meta data includes + * column names and their associated attributes: + * type, size, nullable. + * @exception Failed to get the result set's + * meta data as an XML. + */ + private static String getColumnMetaData + (ResultSetMetaData rsMetaData, + int columnNumber) + throws Exception { + + StringBuffer sb = new StringBuffer(); + sb.append(""); + return sb.toString(); + + } + + /** + * Append attribute=value to the string buffer denoted by sb. + * @param sb the string buffer. + * @param attribute the attribute name. + * @param value the value of the attribute. + */ + private static void append(StringBuffer sb, + String attribute, + String value) { + sb.append(attribute); + sb.append("=\""); + sb.append(value); + sb.append("\" "); + } + + /** + * Append attribute=value to the string buffer denoted by sb. + * @param sb the string buffer. + * @param attribute the attribute name. + * @param value the value of the attribute. + */ + private static void append(StringBuffer sb, + String attribute, + int value) { + sb.append(attribute); + sb.append("=\""); + sb.append(value); + sb.append("\" "); + } + + /** + * Append attribute=value to the string buffer denoted by sb. + * @param sb the string buffer. + * @param attribute the attribute name. + * @param value the value of the attribute. + */ + private static void append(StringBuffer sb, + String attribute, + boolean value) { + sb.append(attribute); + sb.append("=\""); + sb.append(value); + sb.append("\" "); + } + +} \ No newline at end of file diff --git a/sourceMetadata/jcb-package/src/jcb/util/DOM2Writer.class b/sourceMetadata/jcb-package/src/jcb/util/DOM2Writer.class new file mode 100644 index 0000000000000000000000000000000000000000..ca83c0b3f40aee6602e32ffbf542161a22a027f5 GIT binary patch literal 5250 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. + */ + +package jcb.util; + +import org.w3c.dom.Attr; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.io.Writer; + + +/** + * This class is a utility to serialize a DOM node as XML. This class + * uses the DOM Level 2 APIs. + * The main difference between this class and DOMWriter is that this class + * generates and prints out namespace declarations. + * + * @author Matthew J. Duftler (duftler@us.ibm.com) + * @author Joseph Kesselman + */ +public class DOM2Writer +{ + + private static final char NL = '\n'; + private static final char CR = '\r'; + + /** + * The prefered line separator + */ + private static final String LS = System.getProperty( + "line.separator", + (new Character(NL)).toString()); + + /** + * The namespaceURI represented by the prefix xmlns. + */ + private static String NS_URI_XMLNS = "http://www.w3.org/2000/xmlns/"; + private static String NS_URI_XML = "http://www.w3.org/XML/1998/namespace"; + + /** + * Return a string containing this node serialized as XML. + */ + public static String nodeToString(Node node, + boolean omitXMLDecl) + { + StringWriter sw = new StringWriter(); + + serializeAsXML(node, sw, omitXMLDecl); + + return sw.toString(); + } + + /** + * Serialize this node into the writer as XML. + */ + public static void serializeAsXML(Node node, + Writer writer, + boolean omitXMLDecl) + { + serializeAsXML(node, writer, omitXMLDecl, false); + } + + /** + * Serialize this node into the writer as XML. + */ + public static void serializeAsXML(Node node, + Writer writer, + boolean omitXMLDecl, + boolean pretty) + { + PrintWriter out = new PrintWriter(writer); + if (!omitXMLDecl) + out.println(""); + NSStack namespaceStack = new NSStack(); + print(node, namespaceStack, out, pretty, 0); + out.flush(); + } + + private static void print(Node node, + NSStack namespaceStack, + PrintWriter out, + boolean pretty, + int indent) + { + if (node == null) + { + return; + } + + boolean hasChildren = false; + int type = node.getNodeType(); + + switch (type) + { + case Node.DOCUMENT_NODE : + { + NodeList children = node.getChildNodes(); + + if (children != null) + { + int numChildren = children.getLength(); + + for (int i = 0; i < numChildren; i++) + { + print(children.item(i), namespaceStack, out, + pretty, indent); + } + } + break; + } + + case Node.ELEMENT_NODE : + { + namespaceStack.push(); + + if (pretty) { + for (int i = 0; i < indent; i++) + out.print(' '); + } + + out.print('<' + node.getNodeName()); + + String elPrefix = node.getPrefix(); + String elNamespaceURI = node.getNamespaceURI(); + + if (elPrefix != null && + elNamespaceURI != null && + elPrefix.length() > 0) + { + boolean prefixIsDeclared = false; + + try + { + String namespaceURI = namespaceStack.getNamespaceURI(elPrefix); + + if (elNamespaceURI.equals(namespaceURI)) + { + prefixIsDeclared = true; + } + } + catch (IllegalArgumentException e) + { + } + + if (!prefixIsDeclared) + { + printNamespaceDecl(node, namespaceStack, out); + } + } + + NamedNodeMap attrs = node.getAttributes(); + int len = (attrs != null) ? attrs.getLength() : 0; + + for (int i = 0; i < len; i++) + { + Attr attr = (Attr)attrs.item(i); + + out.print(' ' + attr.getNodeName() +"=\"" + + normalize(attr.getValue()) + '\"'); + + String attrPrefix = attr.getPrefix(); + String attrNamespaceURI = attr.getNamespaceURI(); + + if (attrPrefix != null && attrNamespaceURI != null) + { + boolean prefixIsDeclared = false; + + try + { + String namespaceURI = namespaceStack.getNamespaceURI(attrPrefix); + + if (attrNamespaceURI.equals(namespaceURI)) + { + prefixIsDeclared = true; + } + } + catch (IllegalArgumentException e) + { + } + + if (!prefixIsDeclared) + { + printNamespaceDecl(attr, namespaceStack, out); + } + } + } + + NodeList children = node.getChildNodes(); + + if (children != null) + { + int numChildren = children.getLength(); + + hasChildren = (numChildren > 0); + + if (hasChildren) + { + out.print('>'); + if (pretty) + out.print(LS); + } + + for (int i = 0; i < numChildren; i++) + { + print(children.item(i), namespaceStack, out, pretty, + indent + 1); + } + } + else + { + hasChildren = false; + } + + if (!hasChildren) + { + out.print("/>"); + if (pretty) + out.print(LS); + } + + namespaceStack.pop(); + break; + } + + case Node.ENTITY_REFERENCE_NODE : + { + out.print('&'); + out.print(node.getNodeName()); + out.print(';'); + break; + } + + case Node.CDATA_SECTION_NODE : + { + out.print(""); + break; + } + + case Node.TEXT_NODE : + { + out.print(normalize(node.getNodeValue())); + break; + } + + case Node.COMMENT_NODE : + { + out.print(""); + if (pretty) + out.print(LS); + break; + } + + case Node.PROCESSING_INSTRUCTION_NODE : + { + out.print(" 0) + { + out.print(' '); + out.print(data); + } + + out.println("?>"); + if (pretty) + out.print(LS); + break; + } + } + + if (type == Node.ELEMENT_NODE && hasChildren == true) + { + if (pretty) { + for (int i = 0; i < indent; i++) + out.print(' '); + } + out.print("'); + if (pretty) + out.print(LS); + hasChildren = false; + } + } + + private static void printNamespaceDecl(Node node, + NSStack namespaceStack, + PrintWriter out) + { + switch (node.getNodeType()) + { + case Node.ATTRIBUTE_NODE : + { + printNamespaceDecl(((Attr)node).getOwnerElement(), node, + namespaceStack, out); + break; + } + + case Node.ELEMENT_NODE : + { + printNamespaceDecl((Element)node, node, namespaceStack, out); + break; + } + } + } + + private static void printNamespaceDecl(Element owner, Node node, + NSStack namespaceStack, + PrintWriter out) + { + String namespaceURI = node.getNamespaceURI(); + String prefix = node.getPrefix(); + + if (!(namespaceURI.equals(NS_URI_XMLNS) && prefix.equals("xmlns")) && + !(namespaceURI.equals(NS_URI_XML) && prefix.equals("xml"))) + { + if (getNamespace(prefix, owner) == null) + { + out.print(" xmlns:" + prefix + "=\"" + namespaceURI + '\"'); + } + } + else + { + prefix = node.getLocalName(); + namespaceURI = node.getNodeValue(); + } + + namespaceStack.add(namespaceURI, prefix); + } + + public static String normalize(String s) + { + StringBuffer str = new StringBuffer(); + int len = (s != null) ? s.length() : 0; + + for (int i = 0; i < len; i++) + { + char ch = s.charAt(i); + + switch (ch) + { + case '<' : + { + str.append("<"); + break; + } + case '>' : + { + str.append(">"); + break; + } + case '&' : + { + str.append("&"); + break; + } + case '"' : + { + str.append("""); + break; + } + case NL : + { + if (i > 0) + { + char lastChar = str.charAt(str.length() - 1); + + if (lastChar != CR) + { + str.append(LS); + } + else + { + str.append(NL); + } + } + else + { + str.append(LS); + } + break; + } + default : + { + str.append(ch); + } + } + } + + return (str.toString()); + } + + public static String getNamespace(String prefix, Node e) { + while (e != null && (e.getNodeType() == Node.ELEMENT_NODE)) { + Attr attr = + ((Element)e).getAttributeNodeNS(NS_URI_XMLNS, prefix); + if (attr != null) return attr.getValue(); + e = e.getParentNode(); + } + return null; + } +} diff --git a/sourceMetadata/jcb-package/src/jcb/util/DataTypes.class b/sourceMetadata/jcb-package/src/jcb/util/DataTypes.class new file mode 100644 index 0000000000000000000000000000000000000000..cbd9bcf8e3b6b390c518a214017dfd9e91e2c906 GIT binary patch literal 770 zcmZ9J+iuf95QhKF(M^-IwB=Bsl+w}@P*dOzgp|Zi8_BXEb}IEMTE}kc$gGiLBlWSk zLgIo4;Gq!X#3?IocJ}*c_TSmr-+zAo0&t3VH5Bo@iv21M7?#?Xjy`lQKj{o>#)N<4 zYRJV{wUamy1E(ix4E45U8G6f{St~fE zn>y#MevU5~YF)!>IXS;%Sk|mT+nBea;1w0v=T?7Fa6*nf)6viLg@sCvhGm}R4zJ0< zcKW?r;dCwxItz<8S(m1!cYCI;<)_{5=4KiqIJmJpGSATkvjjWDsJf-hknDib*I2B0C*MVocfT?1$!?G_!4{!t<}F zZ*Q1TYuG`7ei~?C6D5>Er9=f(i4}>Lh-?4xvcz@DHzaNnuSmQ~d`IFn;&q8Pi0?{# zkNCdC4~RDW~W5d_q8rFN44Uk+vdveTOXZIX8GXT! z<7{DrT3RdWA1xz0C?^^~5FrH<0kk6|5R|^S4J|hjz@!YBQZTJxM!_3_Mmy}7khn92 z2HPRUk@o=JVpfvh1(3j;g82XzuqZF@spWnq9WUjUyW!MsYJW)YbLKKswj;5rjbyo@ z>rnSHaCZ(lXp1^#4z>zfh9BEnPA(7J?JP?!&{>YWwGX9{$R2K1K|qlb8#$KY1}}4i z!^?6XeRP*3ZwptJ*Y%yHP!G2xClD&_l3P`QzH9y6-U?ddFFj)oufI|`|`nA`B;6SI5ph<7RT7;P + * Date: October 2, 2002 + *

+ * @author Mahmoud Parsian + *

+ * @since 1.4 + *

+ */ +public class DatabaseUtil { + + public static void close(RowSet rs) { + try { + if (rs != null) { + rs.close(); + } + } + catch (Exception e) { + //ignore + e.printStackTrace(); + } + } + + public static void close(ResultSet rs) { + try { + if (rs != null) { + rs.close(); + } + } + catch (Exception e) { + //ignore + e.printStackTrace(); + } + } + + + public static void close(Statement stmt) { + try { + if (stmt != null) { + stmt.close(); + } + } + catch (Exception e) { + //ignore + e.printStackTrace(); + } + } + + + public static void close(PreparedStatement ps) { + try { + if (ps != null) { + ps.close(); + } + } + catch (Exception e) { + //ignore + e.printStackTrace(); + } + } + + + public static void close(Connection conn) { + try { + if (conn != null) { + conn.close(); + } + } + catch (Exception e) { + //ignore + e.printStackTrace(); + } + } + + public static java.sql.Date getJavaSqlDate() { + + java.util.Date javaUtilDate = new java.util.Date(); + return new java.sql.Date(javaUtilDate.getTime()); + } + + + public static String getTrimmedString(ResultSet resultSet, int index) + throws SQLException { + + String value = resultSet.getString(index); + + if (value != null) { + value = value.trim(); + } + + return value; + } + + + public static String getTrimmedString(ResultSet resultSet, String columnName) + throws SQLException { + + String value = resultSet.getString(columnName); + + if (value != null) { + value = value.trim(); + } + + return value; + } + +} diff --git a/sourceMetadata/jcb-package/src/jcb/util/DocumentManager.class b/sourceMetadata/jcb-package/src/jcb/util/DocumentManager.class new file mode 100644 index 0000000000000000000000000000000000000000..bc0289e01e8e2dfc5a748b214a23e6130ef08f28 GIT binary patch literal 33335 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 literal 0 HcmV?d00001 diff --git a/sourceMetadata/jcb-package/src/jcb/util/DocumentManager.java b/sourceMetadata/jcb-package/src/jcb/util/DocumentManager.java new file mode 100644 index 0000000..f564e46 --- /dev/null +++ b/sourceMetadata/jcb-package/src/jcb/util/DocumentManager.java @@ -0,0 +1,2136 @@ +package jcb.util; + +import org.xml.sax.InputSource; +import org.w3c.dom.*; + + +import javax.xml.transform.*; +import javax.xml.transform.dom.*; +import javax.xml.transform.stream.*; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; + +import org.apache.xml.serialize.OutputFormat; +import org.apache.xml.serialize.XMLSerializer; + +import org.jdom.transform.*; +import org.jdom.output.*; +import org.jdom.input.*; + + +import java.io.*; +import java.util.*; + + /** + * This class is a utility class; it provides + * methods for manipulation of XML documents. + *

+ * @author: Mahmoud Parsian + * @since JDK 1.4 + * + */ + public class DocumentManager { + + static DocumentBuilderFactory DOCUMENT_BUILDER_FACTORY = null; + + static { + try { + DOCUMENT_BUILDER_FACTORY = DocumentBuilderFactory.newInstance(); + DOCUMENT_BUILDER_FACTORY.setValidating(false); + } + catch(Exception e) { + // ignore for now. + } + } + + public static final String HTML_END_TAG_UPPERCASE = ""; + public static final String HTML_END_TAG_LOWERCASE = ""; + + public static final int UNDEFINED_POSITION_VALUE = -1; + + private static final String LIST_TAG_BEGIN = "<titleBlock/><titleBlock/>"; + private static final String LIST_TAG_SIMPLE_NULL = "<titleBlock/>"; + + private static final String LIST_TAG_BEGIN_SIMPLE_ONE_ELEMENT = "<titleBlock/>"; + private static final String LIST_TAG_BEGIN_COMPLEX_ONE_ELEMENT = "<titleBlock/>"; + + // + // this tag denotes the error tag beginning + // + private static final String INFO_TAG_BEGIN = ""; + private static final String ERROR_TAG_BEGIN = ""; + + // + // this tag denotes the error tag ending + // + private static final String INFO_TAG_END = ""; + private static final String ERROR_TAG_END = ""; + + public static String removeTrailingHTML(String text) { + if ((text == null) || (text.length() == 0)) { + return text; + } + + int indexOfHTML = text.lastIndexOf(HTML_END_TAG_LOWERCASE); + if (indexOfHTML == -1) { + // then it is not found. check for + indexOfHTML = text.lastIndexOf(HTML_END_TAG_UPPERCASE); + if (indexOfHTML == -1) { + // not found + } + else { + text = text.substring(0, indexOfHTML+7); + } + } + else { + text = text.substring(0, indexOfHTML+7); + } + + return text; + } + + public static String getErrorMessage(String error) { + return ERROR_TAG_BEGIN+error+ERROR_TAG_END; + } + + public static String getMessage(String message) { + return INFO_TAG_BEGIN+message+INFO_TAG_END; + } + + + public void print(Document doc) { + printNode( doc, "" ); + } + + private void printNode(Node n, String indent) { + switch(n.getNodeType()) { + case Node.DOCUMENT_NODE: + NodeList children = n.getChildNodes(); + if( children != null ) + { + for( int i = 0; i < children.getLength(); i++ ) + { + printNode(children.item(i), indent + " " ); + } + } + break; + + case Node.ELEMENT_NODE: + log( indent + getElementStart(n) ); + getElementChildren(n,indent) ; + log( indent + getElementEnd(n) ); + break; + + case Node.TEXT_NODE: + String text = getTextNode(n); + if( text.length() > 0 ) + { + log( indent + " " + text ); + } + break; + + case Node.PROCESSING_INSTRUCTION_NODE: + log( indent + getProcessingInstructionNode(n) ); + break; + + case Node.COMMENT_NODE: + log( indent + getCommentNode(n) ); + break; + } + } + + private void log(String msg){ + System.out.println("DocumentManager: " + msg); + } + + + private String getElementStart(Node e){ + StringBuffer buf = new StringBuffer(); + buf.append( "<" + e.getNodeName() ); + buf.append( getElementAttributes(e) ); + buf.append( ">" ); + return buf.toString(); + } + + private void getElementChildren(Node e, String indent){ + NodeList children = e.getChildNodes(); + if( children != null ){ + for( int i = 0; i < children.getLength(); i++ ) + printNode(children.item(i), indent + " "); + } + } + + private String getElementEnd(Node e){ + return ""; + } + + private String getElementAttributes(Node e){ + StringBuffer buf = new StringBuffer(); + NamedNodeMap attributes = e.getAttributes(); + for( int i = 0; i < attributes.getLength(); i++ ){ + Node n = attributes.item(i); + buf.append( " " ); + buf.append( n.getNodeName() ); + buf.append( "=" ); + buf.append( n.getNodeValue() ); + } + return buf.toString(); + } + + private String getTextNode(Node t){ + return t.getNodeValue().trim(); + } + + private String getProcessingInstructionNode(Node pi){ + return ""; + } + + private String getCommentNode(Node c){ + return "comment: " + c.getNodeValue(); + } + + public static Document stringToDOM(StringBuffer sb) { + return stringToDOM(new String(sb)); + } + + + public static Document stringToDOM(String s) { + //System.out.println("DocumentManager: stringToDOM(): begin -----------------"); + //System.out.println(s); + //System.out.println("DocumentManager: stringToDOM(): end -----------------"); + + if ((s == null) || (s.length() ==0)) { + return null; + } + + Document doc = null; + try { + //DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + //factory.setValidating(false); + DocumentBuilder builder = DOCUMENT_BUILDER_FACTORY.newDocumentBuilder(); + //builder.setErrorHandler(null); + //builder.setEntityResolver(null); + InputSource is = new InputSource(new StringReader(s)); + doc = builder.parse( is ); + } + catch( Exception e){ + e.printStackTrace(); + } + + return doc; + } + + + + + + /**** + public static Document stringToDOM(String s) { + // mp: this is the NEW one + if ((s == null) || (s.length() ==0)) { + return null; + } + + Document doc = null; + + try { + InputSource source = new InputSource(new StringReader(s)); + DOMParser parser = new DOMParser(); + //parser.setValidating(false); + parser.parse(source); + doc = parser.getDocument(); + } + catch (Exception e) { + e.printStackTrace(); + } + + return doc; + } + ****/ + + + + + /*** + private static String getParameter(String parameterName, Document parameters) { + try { + NodeList list = parameters.getElementsByTagName(parameterName); + Node node = (Node) list.item(0); + Text result = (Text) node.getFirstChild(); + String value = result.getNodeValue(); + System.out.println("sqladapter: getParameter(): parameterName="+parameterName+"\tparameterValue="+value); + return value; + } + catch (Exception e) { + return null; + } + } + ***/ + + /** + * Return an Element given an XML document, tag name, and index + * + * @param doc XML docuemnt + * @param tagName a tag name + * @param index a index + * @return an Element + */ + public static Element getElement(Document doc, String tagName, int index ){ + + NodeList rows = doc.getDocumentElement().getElementsByTagName( tagName ); + //printNodeTypes( rows ); + return (Element)rows.item( index ); + } + + /** + * Return an Element given an XML document, tag name, and index + * + * @param element XML Element + * @param tagName a tag name + * @param index a index + * @return an Element + */ + public static Element getElement(Element element, String tagName, int index ){ + + NodeList rows = element.getElementsByTagName( tagName ); + //printNodeTypes( rows ); + return (Element)rows.item( index ); + } + + /** + * Return an Element given an XML document, tag name, and index + * + * @param doc XML docuemnt + * @param tagName a tag name + * @param index a index + * @return an Element + */ + public static Element getElement(SimpleXML xml, String tagName, int index ){ + return getElement(xml.getDocument(), tagName, index ); + } + + /** + * Return the number of document in an XML document + * (given an XML document and a tag name, return the number of ocurances) + * + * @param element XML Element + * @param tagName a tag name + * @return the number of document in an XML document + */ + public static int getSize( Element element, String tagName ){ + + NodeList rows = element.getElementsByTagName( tagName ); + if (rows == null) { + return 0; + } + + return rows.getLength(); + } + + /** + * Return the number of document in an XML document + * (given an XML document and a tag name, return the number of ocurances) + * + * @param doc XML document + * @param tagName a tag name + * @return the number of document in an XML document + */ + public static int getSize( Document doc , String tagName ){ + + NodeList rows = doc.getDocumentElement().getElementsByTagName( tagName ); + if (rows == null) { + return 0; + } + + return rows.getLength(); + } + + /** + * Return the number of document in an XML document + * (given an XML document and a tag name, return the number of ocurances) + * + * @param doc XML document + * @param tagName a tag name + * @return the number of document in an XML document + */ + public static int getSize( SimpleXML xml , String tagName ){ + return getSize(xml.getDocument(), tagName); + } + + /** + * Given a document element, must get the element specified + * by the tagName, then must traverse that Node to get the value. + * Step1) get Element of name tagName from e + * Step2) cast element to Node and then traverse it for its non-whitespace, cr/lf value. + * Step3) return it! + * + * NOTE: Element is a subclass of Node + * + * @param e an Element + * @param tagName a tag name + * @return s the value of a Node + */ + public static String getValue( Element e , String tagName ){ + try{ + //get node lists of a tag name from a Element + NodeList elements = e.getElementsByTagName( tagName ); + if (elements == null) { + return null; + } + //printNodeTypes(elements); + + Node node = elements.item( 0 ); + if (node == null) { + return null; + } + + NodeList nodes = node.getChildNodes(); + //printNodeTypes(nodes); + + //find a value whose value is non-whitespace + String s; + for( int i=0; i"); + buffer.append(date); + buffer.append(""); + buffer.append(LIST_TAG_END); + return stringToDOM(buffer); + } + + public static Document toDocument(java.sql.Date date) { + if (date == null) { + return stringToDOM(LIST_TAG_SIMPLE_NULL); + } + + StringBuffer buffer = new StringBuffer(LIST_TAG_BEGIN_SIMPLE_ONE_ELEMENT); + buffer.append(""); + buffer.append(date); + buffer.append(""); + buffer.append(LIST_TAG_END); + return stringToDOM(buffer); + } + + public static Document toDocument(java.lang.Void input) { + StringBuffer buffer = new StringBuffer(LIST_TAG_BEGIN_SIMPLE_ONE_ELEMENT); + buffer.append("void"); + buffer.append(LIST_TAG_END); + return stringToDOM(buffer); + } + + // + // String + // + public static String toStringXML(java.lang.String str) { + if (str == null) { + return LIST_TAG_SIMPLE_NULL; + } + else { + StringBuffer buffer = new StringBuffer(LIST_TAG_BEGIN_SIMPLE_ONE_ELEMENT); + buffer.append(""); + buffer.append(str); + buffer.append(""); + buffer.append(LIST_TAG_END); + return buffer.toString(); + } + } + + public static Document toDocument(java.lang.StringBuffer sb) { + return stringToDOM(toStringXML(sb.toString())); + } + + public static Document toDocument(java.lang.String str) { + return stringToDOM(toStringXML(str)); + } + + public static Document toDocument(org.w3c.dom.Document doc) { + return doc; + } + + // + // char and Character + // + public static String toStringXML(char input) { + StringBuffer buffer = new StringBuffer(LIST_TAG_BEGIN_SIMPLE_ONE_ELEMENT); + buffer.append(""); + buffer.append(input); + buffer.append(""); + buffer.append(LIST_TAG_END); + return buffer.toString(); + } + + public static String toStringXML(java.lang.Character input) { + if (input == null) { + return LIST_TAG_SIMPLE_NULL; + } + else { + return toStringXML(input.charValue()); + } + } + + public static Document toDocument(java.lang.Character input) { + return stringToDOM(toStringXML(input)); + } + + public static Document toDocument(char input) { + return stringToDOM(toStringXML(input)); + } + + + // + // boolean and Boolean + // + public static String toStringXML(boolean input) { + StringBuffer buffer = new StringBuffer(LIST_TAG_BEGIN_SIMPLE_ONE_ELEMENT); + buffer.append(""); + buffer.append(input); + buffer.append(""); + buffer.append(LIST_TAG_END); + return buffer.toString(); + } + + public static String toStringXML(java.lang.Boolean input) { + if (input == null) { + return LIST_TAG_SIMPLE_NULL; + } + else { + return toStringXML(input.booleanValue()); + } + } + + public static Document toDocument(java.lang.Boolean input) { + return stringToDOM(toStringXML(input)); + } + + public static Document toDocument(boolean input) { + return stringToDOM(toStringXML(input)); + } + + + // + // short and Short + // + public static String toStringXML(short input) { + StringBuffer buffer = new StringBuffer(LIST_TAG_BEGIN_SIMPLE_ONE_ELEMENT); + buffer.append(""); + buffer.append(input); + buffer.append(""); + buffer.append(LIST_TAG_END); + return buffer.toString(); + } + + public static String toStringXML(java.lang.Short input) { + if (input == null) { + return LIST_TAG_SIMPLE_NULL; + } + else { + return toStringXML(input.shortValue()); + } + } + + public static Document toDocument(java.lang.Short input) { + return stringToDOM(toStringXML(input)); + } + + public static Document toDocument(short input) { + return stringToDOM(toStringXML(input)); + } + + // + // int and Integer + // + public static String toStringXML(int input) { + StringBuffer buffer = new StringBuffer(LIST_TAG_BEGIN_SIMPLE_ONE_ELEMENT); + buffer.append(""); + buffer.append(input); + buffer.append(""); + buffer.append(LIST_TAG_END); + return buffer.toString(); + } + + public static String toStringXML(java.lang.Integer input) { + if (input == null) { + return LIST_TAG_SIMPLE_NULL; + } + else { + return toStringXML(input.intValue()); + } + } + + public static Document toDocument(java.lang.Integer input) { + return stringToDOM(toStringXML(input)); + } + + public static Document toDocument(int input) { + return stringToDOM(toStringXML(input)); + } + + + // + // long and Long + // + public static String toStringXML(long input) { + StringBuffer buffer = new StringBuffer(LIST_TAG_BEGIN_SIMPLE_ONE_ELEMENT); + buffer.append(""); + buffer.append(input); + buffer.append(""); + buffer.append(LIST_TAG_END); + return buffer.toString(); + } + + public static String toStringXML(java.lang.Long input) { + if (input == null) { + return LIST_TAG_SIMPLE_NULL; + } + else { + return toStringXML(input.longValue()); + } + } + + public static Document toDocument(java.lang.Long input) { + return stringToDOM(toStringXML(input)); + } + + public static Document toDocument(long input) { + return stringToDOM(toStringXML(input)); + } + + + // + // float and Float + // + public static String toStringXML(float input) { + StringBuffer buffer = new StringBuffer(LIST_TAG_BEGIN_SIMPLE_ONE_ELEMENT); + buffer.append(""); + buffer.append(input); + buffer.append(""); + buffer.append(LIST_TAG_END); + return buffer.toString(); + } + + public static String toStringXML(java.lang.Float input) { + if (input == null) { + return LIST_TAG_SIMPLE_NULL; + } + else { + return toStringXML(input.floatValue()); + } + } + + public static Document toDocument(java.lang.Float input) { + return stringToDOM(toStringXML(input)); + } + + public static Document toDocument(float input) { + return stringToDOM(toStringXML(input)); + } + + + // + // double and Double + // + public static String toStringXML(double input) { + StringBuffer buffer = new StringBuffer(LIST_TAG_BEGIN_SIMPLE_ONE_ELEMENT); + buffer.append(""); + buffer.append(input); + buffer.append(""); + buffer.append(LIST_TAG_END); + return buffer.toString(); + } + + public static String toStringXML(java.lang.Double input) { + if (input == null) { + return LIST_TAG_SIMPLE_NULL; + } + else { + return toStringXML(input.doubleValue()); + } + } + + public static Document toDocument(java.lang.Double input) { + return stringToDOM(toStringXML(input)); + } + + public static Document toDocument(double input) { + return stringToDOM(toStringXML(input)); + } + + + + // + // byte and Byte + // + public static String toStringXML(byte input) { + StringBuffer buffer = new StringBuffer(LIST_TAG_BEGIN_SIMPLE_ONE_ELEMENT); + buffer.append(""); + buffer.append(input); + buffer.append(""); + buffer.append(LIST_TAG_END); + return buffer.toString(); + } + + public static String toStringXML(java.lang.Byte input) { + if (input == null) { + return LIST_TAG_SIMPLE_NULL; + } + else { + return toStringXML(input.byteValue()); + } + } + + public static Document toDocument(java.lang.Byte input) { + return stringToDOM(toStringXML(input)); + } + + public static Document toDocument(byte input) { + return stringToDOM(toStringXML(input)); + } + + + + public static String getObjectType(Object value) { + if (value == null) { + return DataTypes.STRING_TYPE; + } + else if (value instanceof java.lang.Byte) { + return DataTypes.BYTE_TYPE; + } + else if (value instanceof java.lang.Boolean) { + return DataTypes.BOOLEAN_TYPE; + } + else if (value instanceof java.lang.String) { + return DataTypes.STRING_TYPE; + } + else if (value instanceof java.lang.Long) { + return DataTypes.LONG_TYPE; + } + else if (value instanceof java.lang.Integer) { + return DataTypes.INTEGER_TYPE; + } + else if (value instanceof java.lang.Short) { + return DataTypes.SHORT_TYPE; + } + else if (value instanceof java.lang.Float) { + return DataTypes.FLOAT_TYPE; + } + else if (value instanceof java.lang.Double) { + return DataTypes.DOUBLE_TYPE; + } + else if (value instanceof java.lang.Character) { + return DataTypes.CHAR_TYPE; + } + else if (value instanceof java.sql.Date) { + return DataTypes.SQL_DATE_TYPE; + } + else if (value instanceof java.util.Date) { + return DataTypes.UTIL_DATE_TYPE; + } + else if (value instanceof java.util.Hashtable) { + return DataTypes.STRUCT_TYPE; + } + else if (value instanceof java.util.List) { + return DataTypes.STRUCT_TYPE; + } + else { + return DataTypes.UNDEFINED_TYPE; + } + } + + public static String nullToXML() { + return LIST_TAG_COMPLEX_NULL; + } + + + public static Document toDocument(java.util.List list) { + return stringToDOM(collectionToXML((java.util.Collection)list)); + } + + public static Document toDocument(java.util.AbstractList list) { + return stringToDOM(collectionToXML((java.util.Collection)list)); + } + + public static Document toDocument(java.util.ArrayList list) { + return stringToDOM(collectionToXML((java.util.Collection)list)); + } + + public static Document toDocument(java.util.LinkedList list) { + return stringToDOM(collectionToXML((java.util.Collection)list)); + } + + public static Document toDocument(java.util.AbstractSequentialList list) { + return stringToDOM(collectionToXML((java.util.Collection)list)); + } + + public static Document toDocument(java.util.Vector list) { + return stringToDOM(collectionToXML((java.util.Collection)list)); + } + + + public static Document toDocument(java.util.Collection collection) { + return stringToDOM(collectionToXML(collection)); + } + + public static Document toDocument(java.util.AbstractCollection acollection) { + return stringToDOM(collectionToXML((java.util.Collection)acollection)); + } + + public static Document toDocument(java.util.Set set) { + return stringToDOM(collectionToXML((java.util.Collection)set)); + } + + public static Document toDocument(java.util.SortedSet sset) { + return stringToDOM(collectionToXML((java.util.Collection)sset)); + } + + public static Document toDocument(java.util.AbstractSet set) { + return stringToDOM(collectionToXML((java.util.Collection)set)); + } + + public static Document toDocument(java.util.HashSet set) { + return stringToDOM(collectionToXML((java.util.Collection)set)); + } + + public static Document toDocument(java.util.LinkedHashSet set) { + return stringToDOM(collectionToXML((java.util.Collection)set)); + } + + public static Document toDocument(java.util.TreeSet set) { + return stringToDOM(collectionToXML((java.util.Collection)set)); + } + + public static String collectionToXML(java.util.Collection collection) { + if (collection == null) { + return LIST_TAG_SIMPLE_NULL; + } + + int size = collection.size(); + if (size == 0) { + return LIST_TAG_SIMPLE_NULL; + } + + StringBuffer buffer = new StringBuffer(LIST_TAG_BEGIN); + buffer.append(" of=\"simple\" numResults=\""); + buffer.append(size); + buffer.append("\" totalResults=\""); + buffer.append(size); + buffer.append("\">"); + + Iterator iterator = collection.iterator(); + while (iterator.hasNext()) { + buffer.append(""); + buffer.append((String)iterator.next()); + buffer.append(""); + } + + buffer.append(LIST_TAG_END); + return buffer.toString(); + } + + + public static Document toDocument(java.util.Map map) { + return stringToDOM(mapToXML(map)); + } + + public static Document toDocument(java.util.SortedMap smap) { + return stringToDOM(mapToXML((java.util.Map)smap)); + } + + public static Document toDocument(java.util.Hashtable map) { + return stringToDOM(mapToXML((java.util.Map)map)); + } + + public static Document toDocument(java.util.Properties map) { + return stringToDOM(mapToXML((java.util.Map)map)); + } + + public static Document toDocument(java.util.AbstractMap map) { + return stringToDOM(mapToXML((java.util.Map)map)); + } + + public static Document toDocument(java.util.HashMap map) { + return stringToDOM(mapToXML((java.util.Map)map)); + } + + public static Document toDocument(java.util.WeakHashMap map) { + return stringToDOM(mapToXML((java.util.Map)map)); + } + + public static Document toDocument(java.util.IdentityHashMap map) { + return stringToDOM(mapToXML((java.util.Map)map)); + } + + public static Document toDocument(java.util.TreeMap map) { + return stringToDOM(mapToXML((java.util.Map)map)); + } + + public static String mapToXML(java.util.SortedMap smap) { + return mapToXML( (java.util.Map) smap ); + } + + public static String mapToXML(java.util.Map map) { + if (map == null) { + return LIST_TAG_COMPLEX_NULL; + } + + int size = map.size(); + if (size == 0) { + return LIST_TAG_COMPLEX_NULL; + } + + Set keys = map.keySet(); + if ((keys == null) || (keys.size() == 0)) { + return LIST_TAG_COMPLEX_NULL; + } + + StringBuffer buffer = new StringBuffer(LIST_TAG_BEGIN); + buffer.append(" of=\"complex\" numResults=\""); + buffer.append(size); + buffer.append("\" totalResults=\""); + buffer.append(size); + buffer.append("\">"); + + Iterator iterator = keys.iterator(); + while (iterator.hasNext()) { + + Object key = iterator.next(); + Object value = map.get(key); + + buffer.append(""); + buffer.append(key); + buffer.append(""); + buffer.append(value); + buffer.append(""); + } + buffer.append(LIST_TAG_END); + return buffer.toString(); + } + + public static String toStringXML(Character[] array) { + if ((array == null) || (array.length == 0)) { + return LIST_TAG_SIMPLE_NULL; + } + else { + StringBuffer buffer = new StringBuffer(LIST_TAG_BEGIN); + buffer.append(" of=\"simple\" numResults=\""); + buffer.append(array.length); + buffer.append("\" totalResults=\""); + buffer.append(array.length); + buffer.append("\">"); + for (int i=0; i < array.length; i++) { + buffer.append(""); + if (array[i] != null) { + buffer.append(array[i].charValue()); + } + buffer.append(""); + } + buffer.append(LIST_TAG_END); + return buffer.toString(); + } + } + + public static String toStringXML(char[] array) { + if ((array == null) || (array.length == 0)) { + return LIST_TAG_SIMPLE_NULL; + } + else { + StringBuffer buffer = new StringBuffer(LIST_TAG_BEGIN); + buffer.append(" of=\"simple\" numResults=\""); + buffer.append(array.length); + buffer.append("\" totalResults=\""); + buffer.append(array.length); + buffer.append("\">"); + for (int i=0; i < array.length; i++) { + buffer.append(""); + buffer.append(array[i]); + buffer.append(""); + } + buffer.append(LIST_TAG_END); + return buffer.toString(); + } + } + + public static Document toDocument(Character[] array) { + return stringToDOM(toStringXML(array) ); + } + + public static Document toDocument(char[] array) { + return stringToDOM(toStringXML(array) ); + } + + + public static String toStringXML(boolean[] array) { + if ((array == null) || (array.length == 0)) { + return LIST_TAG_SIMPLE_NULL; + } + else { + StringBuffer buffer = new StringBuffer(LIST_TAG_BEGIN); + buffer.append(" of=\"simple\" numResults=\""); + buffer.append(array.length); + buffer.append("\" totalResults=\""); + buffer.append(array.length); + buffer.append("\">"); + for (int i=0; i < array.length; i++) { + buffer.append(""); + buffer.append(array[i]); + buffer.append(""); + } + buffer.append(LIST_TAG_END); + return buffer.toString(); + } + } + + public static String toStringXML(Boolean[] array) { + if ((array == null) || (array.length == 0)) { + return LIST_TAG_SIMPLE_NULL; + } + else { + StringBuffer buffer = new StringBuffer(LIST_TAG_BEGIN); + buffer.append(" of=\"simple\" numResults=\""); + buffer.append(array.length); + buffer.append("\" totalResults=\""); + buffer.append(array.length); + buffer.append("\">"); + for (int i=0; i < array.length; i++) { + buffer.append(""); + if (array[i] != null) { + buffer.append(array[i].booleanValue()); + } + buffer.append(""); + } + buffer.append(LIST_TAG_END); + return buffer.toString(); + } + } + + public static Document toDocument(Boolean[] array) { + return stringToDOM(toStringXML(array) ); + } + + public static Document toDocument(boolean[] array) { + return stringToDOM(toStringXML(array) ); + } + + public static String toStringXML(byte[] array) { + if ((array == null) || (array.length == 0)) { + return LIST_TAG_SIMPLE_NULL; + } + else { + StringBuffer buffer = new StringBuffer(LIST_TAG_BEGIN); + buffer.append(" of=\"simple\" numResults=\""); + buffer.append(array.length); + buffer.append("\" totalResults=\""); + buffer.append(array.length); + buffer.append("\">"); + for (int i=0; i < array.length; i++) { + buffer.append(""); + buffer.append(array[i]); + buffer.append(""); + } + buffer.append(LIST_TAG_END); + return buffer.toString(); + } + } + + public static String toStringXML(Byte[] array) { + if ((array == null) || (array.length == 0)) { + return LIST_TAG_SIMPLE_NULL; + } + else { + StringBuffer buffer = new StringBuffer(LIST_TAG_BEGIN); + buffer.append(" of=\"simple\" numResults=\""); + buffer.append(array.length); + buffer.append("\" totalResults=\""); + buffer.append(array.length); + buffer.append("\">"); + for (int i=0; i < array.length; i++) { + buffer.append(""); + if (array[i] != null) { + buffer.append(array[i].byteValue()); + } + buffer.append(""); + } + buffer.append(LIST_TAG_END); + return buffer.toString(); + } + } + + public static Document toDocument(Byte[] array) { + return stringToDOM(toStringXML(array)); + } + + public static Document toDocument(byte[] array) { + return stringToDOM(toStringXML(array)); + } + + public static String toStringXML(short[] array) { + if ((array == null) || (array.length == 0)) { + return LIST_TAG_SIMPLE_NULL; + } + else { + StringBuffer buffer = new StringBuffer(LIST_TAG_BEGIN); + buffer.append(" of=\"simple\" numResults=\""); + buffer.append(array.length); + buffer.append("\" totalResults=\""); + buffer.append(array.length); + buffer.append("\">"); + for (int i=0; i < array.length; i++) { + buffer.append(""); + buffer.append(array[i]); + buffer.append(""); + } + buffer.append(LIST_TAG_END); + return buffer.toString(); + } + } + + public static String toStringXML(Short[] array) { + if ((array == null) || (array.length == 0)) { + return LIST_TAG_SIMPLE_NULL; + } + else { + StringBuffer buffer = new StringBuffer(LIST_TAG_BEGIN); + buffer.append(" of=\"simple\" numResults=\""); + buffer.append(array.length); + buffer.append("\" totalResults=\""); + buffer.append(array.length); + buffer.append("\">"); + for (int i=0; i < array.length; i++) { + buffer.append(""); + if (array[i] != null) { + buffer.append(array[i].shortValue()); + } + buffer.append(""); + } + buffer.append(LIST_TAG_END); + return buffer.toString(); + } + } + + public static Document toDocument(Short[] array) { + return stringToDOM(toStringXML(array)); + } + + public static Document toDocument(short[] array) { + return stringToDOM(toStringXML(array)); + } + + + public static String toStringXML(int[] array) { + if ((array == null) || (array.length == 0)) { + return LIST_TAG_SIMPLE_NULL; + } + else { + StringBuffer buffer = new StringBuffer(LIST_TAG_BEGIN); + buffer.append(" of=\"simple\" numResults=\""); + buffer.append(array.length); + buffer.append("\" totalResults=\""); + buffer.append(array.length); + buffer.append("\">"); + for (int i=0; i < array.length; i++) { + buffer.append(""); + buffer.append(array[i]); + buffer.append(""); + } + buffer.append(LIST_TAG_END); + return buffer.toString(); + } + } + + public static String toStringXML(Integer[] array) { + if ((array == null) || (array.length == 0)) { + return LIST_TAG_SIMPLE_NULL; + } + else { + StringBuffer buffer = new StringBuffer(LIST_TAG_BEGIN); + buffer.append(" of=\"simple\" numResults=\""); + buffer.append(array.length); + buffer.append("\" totalResults=\""); + buffer.append(array.length); + buffer.append("\">"); + for (int i=0; i < array.length; i++) { + buffer.append(""); + if (array[i] != null) { + buffer.append(array[i].intValue()); + } + buffer.append(""); + } + buffer.append(LIST_TAG_END); + return buffer.toString(); + } + } + + public static Document toDocument(Integer[] array) { + return stringToDOM(toStringXML(array)); + } + + public static Document toDocument(int[] array) { + return stringToDOM(toStringXML(array)); + } + + + public static String toStringXML(long[] array) { + if ((array == null) || (array.length == 0)) { + return LIST_TAG_SIMPLE_NULL; + } + else { + StringBuffer buffer = new StringBuffer(LIST_TAG_BEGIN); + buffer.append(" of=\"simple\" numResults=\""); + buffer.append(array.length); + buffer.append("\" totalResults=\""); + buffer.append(array.length); + buffer.append("\">"); + for (int i=0; i < array.length; i++) { + buffer.append(""); + buffer.append(array[i]); + buffer.append(""); + } + buffer.append(LIST_TAG_END); + return buffer.toString(); + } + } + + public static String toStringXML(Long[] array) { + if ((array == null) || (array.length == 0)) { + return LIST_TAG_SIMPLE_NULL; + } + else { + StringBuffer buffer = new StringBuffer(LIST_TAG_BEGIN); + buffer.append(" of=\"simple\" numResults=\""); + buffer.append(array.length); + buffer.append("\" totalResults=\""); + buffer.append(array.length); + buffer.append("\">"); + for (int i=0; i < array.length; i++) { + buffer.append(""); + if (array[i] != null) { + buffer.append(array[i].longValue()); + } + buffer.append(""); + } + buffer.append(LIST_TAG_END); + return buffer.toString(); + } + } + + public static Document toDocument(Long[] array) { + return stringToDOM(toStringXML(array)); + } + + public static Document toDocument(long[] array) { + return stringToDOM(toStringXML(array)); + } + + public static String toStringXML(float[] array) { + if ((array == null) || (array.length == 0)) { + return LIST_TAG_SIMPLE_NULL; + } + else { + StringBuffer buffer = new StringBuffer(LIST_TAG_BEGIN); + buffer.append(" of=\"simple\" numResults=\""); + buffer.append(array.length); + buffer.append("\" totalResults=\""); + buffer.append(array.length); + buffer.append("\">"); + for (int i=0; i < array.length; i++) { + buffer.append(""); + buffer.append(array[i]); + buffer.append(""); + } + buffer.append(LIST_TAG_END); + return buffer.toString(); + } + } + + public static String toStringXML(Float[] array) { + if ((array == null) || (array.length == 0)) { + return LIST_TAG_SIMPLE_NULL; + } + else { + StringBuffer buffer = new StringBuffer(LIST_TAG_BEGIN); + buffer.append(" of=\"simple\" numResults=\""); + buffer.append(array.length); + buffer.append("\" totalResults=\""); + buffer.append(array.length); + buffer.append("\">"); + for (int i=0; i < array.length; i++) { + buffer.append(""); + if (array[i] != null) { + buffer.append(array[i].floatValue()); + } + buffer.append(""); + } + buffer.append(LIST_TAG_END); + return buffer.toString(); + } + } + + public static Document toDocument(Float[] array) { + return stringToDOM(toStringXML(array)); + } + public static Document toDocument(float[] array) { + return stringToDOM(toStringXML(array)); + } + + public static String toStringXML(double[] array) { + if ((array == null) || (array.length == 0)) { + return LIST_TAG_SIMPLE_NULL; + } + else { + StringBuffer buffer = new StringBuffer(LIST_TAG_BEGIN); + buffer.append(" of=\"simple\" numResults=\""); + buffer.append(array.length); + buffer.append("\" totalResults=\""); + buffer.append(array.length); + buffer.append("\">"); + for (int i=0; i < array.length; i++) { + buffer.append(""); + buffer.append(array[i]); + buffer.append(""); + } + buffer.append(LIST_TAG_END); + return buffer.toString(); + } + } + + public static String toStringXML(Double[] array) { + if ((array == null) || (array.length == 0)) { + return LIST_TAG_SIMPLE_NULL; + } + else { + StringBuffer buffer = new StringBuffer(LIST_TAG_BEGIN); + buffer.append(" of=\"simple\" numResults=\""); + buffer.append(array.length); + buffer.append("\" totalResults=\""); + buffer.append(array.length); + buffer.append("\">"); + for (int i=0; i < array.length; i++) { + buffer.append(""); + if (array[i] != null) { + buffer.append(array[i].doubleValue()); + } + buffer.append(""); + } + buffer.append(LIST_TAG_END); + return buffer.toString(); + } + } + + public static Document toDocument(Double[] array) { + return stringToDOM(toStringXML(array)); + } + public static Document toDocument(double[] array) { + return stringToDOM(toStringXML(array)); + } + + public static String toStringXML(String[] array) { + if ((array == null) || (array.length == 0)) { + return LIST_TAG_SIMPLE_NULL; + } + else { + StringBuffer buffer = new StringBuffer(LIST_TAG_BEGIN); + buffer.append(" of=\"simple\" numResults=\""); + buffer.append(array.length); + buffer.append("\" totalResults=\""); + buffer.append(array.length); + buffer.append("\">"); + for (int i=0; i < array.length; i++) { + buffer.append(""); + buffer.append(array[i]); + buffer.append(""); + } + buffer.append(LIST_TAG_END); + return buffer.toString(); + } + } + + public static Document toDocument(String[] array) { + return stringToDOM(toStringXML(array)); + } + + public static String toStringXML(StringBuffer[] array) { + if ((array == null) || (array.length == 0)) { + return LIST_TAG_SIMPLE_NULL; + } + else { + StringBuffer buffer = new StringBuffer(LIST_TAG_BEGIN); + buffer.append(" of=\"simple\" numResults=\""); + buffer.append(array.length); + buffer.append("\" totalResults=\""); + buffer.append(array.length); + buffer.append("\">"); + for (int i=0; i < array.length; i++) { + buffer.append(""); + buffer.append(array[i]); + buffer.append(""); + } + buffer.append(LIST_TAG_END); + return buffer.toString(); + } + } + + public static Document toDocument(StringBuffer[] array) { + return stringToDOM(toStringXML(array)); + } + + + + public static Document toDocument(java.sql.Date[] array) { + return stringToDOM(toStringXML(array)); + } + + public static Document toDocument(java.util.Date[] array) { + return stringToDOM(toStringXML(array)); + } + + public static String toStringXML(java.sql.Date[] array) { + if ((array == null) || (array.length == 0)) { + return LIST_TAG_SIMPLE_NULL; + } + else { + StringBuffer buffer = new StringBuffer(LIST_TAG_BEGIN); + buffer.append(" of=\"simple\" numResults=\""); + buffer.append(array.length); + buffer.append("\" totalResults=\""); + buffer.append(array.length); + buffer.append("\">"); + for (int i=0; i < array.length; i++) { + buffer.append(""); + buffer.append(array[i]); + buffer.append(""); + } + buffer.append(LIST_TAG_END); + return buffer.toString(); + } + } + + public static String toStringXML(java.util.Date[] array) { + if ((array == null) || (array.length == 0)) { + return LIST_TAG_SIMPLE_NULL; + } + else { + StringBuffer buffer = new StringBuffer(LIST_TAG_BEGIN); + buffer.append(" of=\"simple\" numResults=\""); + buffer.append(array.length); + buffer.append("\" totalResults=\""); + buffer.append(array.length); + buffer.append("\">"); + for (int i=0; i < array.length; i++) { + buffer.append(""); + buffer.append(array[i]); + buffer.append(""); + } + buffer.append(LIST_TAG_END); + return buffer.toString(); + } + } + + + public static void main( String [] args ) throws Exception { + + String s = "mysqlmysql"; + Document d = stringToDOM(s); + + DocumentManager mgr = new DocumentManager(); + mgr.print(d); + + + java.util.Date javaUtilDate = new java.util.Date(); + java.sql.Date javaSqlDate = new java.sql.Date(javaUtilDate.getTime()); + + Document utildate = toDocument(javaUtilDate); + mgr.print(utildate); + + Document sqldate = toDocument(javaSqlDate); + mgr.print(sqldate); + } + + + public static Document toDocument(java.lang.Object input) + throws Exception { + + if (input == null) { + // return an empty result set + return stringToDOM(nullToXML()); + } + + + if (input instanceof org.w3c.dom.Document) { + return (org.w3c.dom.Document) input; + } + else if (input instanceof java.lang.Void) { + return toDocument( (java.lang.Void) input ); + } + else if (input instanceof java.sql.Date) { + return toDocument( (java.sql.Date) input ); + } + else if (input instanceof java.util.Date) { + return toDocument( (java.util.Date) input ); + } + else if (input instanceof java.lang.StringBuffer) { + return toDocument( (java.lang.StringBuffer) input ); + } + else if (input instanceof java.lang.String) { + return toDocument( (java.lang.String) input ); + } + else if (input instanceof java.lang.Boolean) { + return toDocument( (java.lang.Boolean) input ); + } + else if (input instanceof java.lang.Character) { + return toDocument( (java.lang.Character) input ); + } + else if (input instanceof java.lang.Short) { + return toDocument( (java.lang.Short) input ); + } + else if (input instanceof java.lang.Integer) { + return toDocument( (java.lang.Integer) input ); + } + else if (input instanceof java.lang.Long) { + return toDocument( (java.lang.Long) input ); + } + else if (input instanceof java.lang.Float) { + return toDocument( (java.lang.Float) input ); + } + else if (input instanceof java.lang.Double) { + return toDocument( (java.lang.Double) input ); + } + else if (input instanceof java.lang.Byte) { + return toDocument( (java.lang.Byte) input ); + } + else if (input instanceof java.sql.Date[]) { + return toDocument( (java.sql.Date[]) input ); + } + else if (input instanceof java.util.Date[]) { + return toDocument( (java.util.Date[]) input ); + } + else if (input instanceof java.lang.StringBuffer[]) { + return toDocument( (java.lang.StringBuffer[]) input ); + } + else if (input instanceof java.lang.String[]) { + return toDocument( (java.lang.String[]) input ); + } + else if (input instanceof java.lang.Boolean[]) { + return toDocument( (java.lang.Boolean[]) input ); + } + else if (input instanceof java.lang.Character[]) { + return toDocument( (java.lang.Character[]) input ); + } + else if (input instanceof java.lang.Short[]) { + return toDocument( (java.lang.Short[]) input ); + } + else if (input instanceof java.lang.Integer[]) { + return toDocument( (java.lang.Integer[]) input ); + } + else if (input instanceof java.lang.Long) { + return toDocument( (java.lang.Long) input ); + } + else if (input instanceof java.lang.Float[]) { + return toDocument( (java.lang.Float[]) input ); + } + else if (input instanceof java.lang.Double[]) { + return toDocument( (java.lang.Double[]) input ); + } + else if (input instanceof java.lang.Byte[]) { + return toDocument( (java.lang.Byte[]) input ); + } + else if (input instanceof char[]) { + return toDocument( (char[]) input ); + } + else if (input instanceof boolean[]) { + return toDocument( (boolean[]) input ); + } + else if (input instanceof byte[]) { + return toDocument( (byte[]) input ); + } + else if (input instanceof short[]) { + return toDocument( (short[]) input ); + } + else if (input instanceof int[]) { + return toDocument( (int[]) input ); + } + else if (input instanceof long[]) { + return toDocument( (long[]) input ); + } + else if (input instanceof double[]) { + return toDocument( (double[]) input ); + } + else if (input instanceof float[]) { + return toDocument( (float[]) input ); + } + else if (input instanceof java.util.Properties) { + return toDocument( (java.util.Properties) input ); + } + else if (input instanceof java.util.Hashtable) { + return toDocument( (java.util.Hashtable) input ); + } + else if (input instanceof java.util.LinkedList) { + return toDocument( (java.util.LinkedList) input ); + } + else if (input instanceof java.util.Vector) { + return toDocument( (java.util.Vector) input ); + } + else if (input instanceof java.util.ArrayList) { + return toDocument( (java.util.ArrayList) input ); + } + else if (input instanceof java.util.AbstractSequentialList) { + return toDocument( (java.util.AbstractSequentialList) input ); + } + else if (input instanceof java.util.AbstractSet) { + return toDocument( (java.util.AbstractSet) input ); + } + else if (input instanceof java.util.AbstractList) { + return toDocument( (java.util.AbstractList) input ); + } + else if (input instanceof java.util.AbstractCollection) { + return toDocument( (java.util.AbstractCollection) input ); + } + else if (input instanceof java.util.HashSet) { + return toDocument( (java.util.HashSet) input ); + } + else if (input instanceof java.util.LinkedHashSet) { + return toDocument( (java.util.LinkedHashSet) input ); + } + else if (input instanceof java.util.TreeSet) { + return toDocument( (java.util.TreeSet) input ); + } + else if (input instanceof java.util.HashMap) { + return toDocument( (java.util.HashMap) input ); + } + else if (input instanceof java.util.WeakHashMap) { + return toDocument( (java.util.WeakHashMap) input ); + } + else if (input instanceof java.util.IdentityHashMap) { + return toDocument( (java.util.IdentityHashMap) input ); + } + else if (input instanceof java.util.TreeMap) { + return toDocument( (java.util.TreeMap) input ); + } + else if (input instanceof java.util.AbstractMap) { + return toDocument( (java.util.AbstractMap) input ); + } + else if (input instanceof java.util.SortedSet) { + return toDocument( (java.util.SortedSet) input ); + } + else if (input instanceof java.util.Set) { + return toDocument( (java.util.Set) input ); + } + else if (input instanceof java.util.List) { + return toDocument( (java.util.List) input ); + } + else if (input instanceof java.util.Collection) { + return toDocument( (java.util.Collection) input ); + } + else if (input instanceof java.util.SortedMap) { + return toDocument( (java.util.SortedMap) input ); + } + else if (input instanceof java.util.Map) { + return toDocument( (java.util.Map) input ); + } + else { + // + // it is an undefined type + // + return toDocument( (java.lang.String) input ); + } + + } + + /** + * Convert document to string. + * Does work very well with all types of XML + * @param document the document object. + * @return String. + */ + public static String documentToString(org.w3c.dom.Document document) + throws Exception { + + String result = null; + if(document != null) { + OutputFormat format = new OutputFormat(document); + StringWriter strWriter = new StringWriter(); + XMLSerializer xmlSerializer = new XMLSerializer(strWriter, format); + xmlSerializer.serialize(document.getDocumentElement()); + result = strWriter.toString(); + } + return result; + } + + /** + * Convert element to string. + * Does work very well with all types of XML + * @param element the Element object. + * @return String. + */ + public static String documentToString(org.w3c.dom.Element element) + throws Exception { + + String result = null; + if(element != null) { + OutputFormat format = new OutputFormat(); + StringWriter strWriter = new StringWriter(); + XMLSerializer xmlSerializer = new XMLSerializer(strWriter,format); + xmlSerializer.serialize(element); + result = strWriter.toString(); + } + return result; + } + + /** + * Does not work very well with all types of XML + */ + public static String document2String(Document document) + throws Exception { + + //System.out.println("document2String(): begin..."); + + if (document == null) { + return null; + } + + String result = null; + StringWriter strWtr = new StringWriter(); + StreamResult strResult = new StreamResult(strWtr); + TransformerFactory tfac = TransformerFactory.newInstance(); + Transformer trans = tfac.newTransformer(); + trans.transform(new DOMSource(document.getDocumentElement()), strResult); + result = strResult.getWriter().toString(); + //System.out.println("document2String: result="+result); + return result; + } + + public static Element getRootElement(Document doc) { + if (doc == null) { + return null; + } + else { + return (Element) doc.getFirstChild(); + } + } + + public static org.jdom.Document toJDOM(org.w3c.dom.Document dom) + throws Exception { + if (dom == null) { + return null; + } + else { + org.jdom.input.DOMBuilder builder = new org.jdom.input.DOMBuilder(); + org.jdom.Document jdomDoc = builder.build(dom); + return jdomDoc; + } + } + + public static org.jdom.Document toJDOM(String str) + throws Exception { + if ((str == null) || (str.length() == 0)) { + return null; + } + else { + java.io.InputStream stream = new java.io.StringBufferInputStream( str ); + org.jdom.Document jdomDoc = new org.jdom.input.SAXBuilder().build( stream ); + return jdomDoc; + } + } + + public static String xmlToString(org.jdom.Document doc) throws Exception { + StringWriter writer = new StringWriter(); + org.jdom.output.XMLOutputter xmlOutputter + //= new org.jdom.output.XMLOutputter("", false); + = new org.jdom.output.XMLOutputter(); + + xmlOutputter.output(doc, writer); + return writer.toString(); + } + + public static String xmlToString(org.jdom.Element ele) throws Exception { + return xmlToString(ele, false); + } + + public static String xmlToString(org.jdom.Element ele, boolean inner) + throws Exception { + StringWriter writer = new StringWriter(); + org.jdom.output.XMLOutputter xmlOutputter + //= new org.jdom.output.XMLOutputter("", false); + = new org.jdom.output.XMLOutputter(); + + if( inner == true ) { + xmlOutputter.outputElementContent(ele, writer); + } + else { + xmlOutputter.output(ele, writer); + } + return writer.toString(); + } + + + /** + * return the element as an XML stream + */ + public static String xmlToString(org.w3c.dom.Element element) + throws Exception { + + return documentToString(element); + } + + /** + * return the element as an XML stream. If inner=true, then only inner + * components of element are returned. For example if element represents + * the following: + * + * tag-value + * .... + * ... + * ... + * + * + * then the result will be: + * + * tag-value + * .... + * ... + * ... + * + */ + public static String xmlToString(org.w3c.dom.Element element, boolean inner) + throws Exception { + + if(!inner) { + return documentToString(element); + } + + // here inner=true + if (element == null) { + return null; + } + + StringBuffer buffer = new StringBuffer(); + String nodeValue = element.getNodeValue(); + if (nodeValue != null) { + buffer.append(nodeValue); + } + + NodeList list = element.getChildNodes(); + if (list == null) { + return buffer.toString(); + } + + int length = list.getLength(); + if (length < 1) { + return buffer.toString(); + } + + for (int i=0; i < length; i++) { + Node node = list.item(i); + if (node != null) { + buffer.append(DOM2Writer.nodeToString(node, true)); + } + } + + return buffer.toString(); + } + + public static String transform(org.w3c.dom.Element element, + java.lang.String stylesheetFileName) + throws Exception { + + if (element == null) { + return null; + } + + if ((stylesheetFileName == null) || + (stylesheetFileName.length() == 0)) { + throw new Exception("Document Manager: style sheet filename can not be null/empty."); + } + + String xmlString = documentToString(element); + javax.xml.transform.Source xml = + new javax.xml.transform.stream.StreamSource(new StringReader(xmlString)); + + File xsltFile = new File(stylesheetFileName); + javax.xml.transform.Source xslt = + new javax.xml.transform.stream.StreamSource(xsltFile); + + return transformToString(xml, xslt); + } + + public static String transform(org.w3c.dom.Document doc, + java.lang.String stylesheetFileName) + throws Exception { + + if (doc == null) { + return null; + } + + if ((stylesheetFileName == null) || + (stylesheetFileName.length() == 0)) { + throw new Exception("Document Manager: style sheet filename can not be null/empty."); + } + + String xmlString = documentToString(doc); + javax.xml.transform.Source xml = + new javax.xml.transform.stream.StreamSource(new StringReader(xmlString)); + + File xsltFile = new File(stylesheetFileName); + javax.xml.transform.Source xslt = + new javax.xml.transform.stream.StreamSource(xsltFile); + + return transformToString(xml, xslt); + } + + public static String transform(org.jdom.Element ele, + String stylesheetFileName) + throws Exception { + + String xmlString = xmlToString(ele); + javax.xml.transform.Source xml = + new javax.xml.transform.stream.StreamSource(new StringReader(xmlString)); + + File xsltFile = new File(stylesheetFileName); + javax.xml.transform.Source xslt = + new javax.xml.transform.stream.StreamSource(xsltFile); + + return transformToString(xml, xslt); + } + + public static String transform(org.jdom.Document jdom, + String stylesheetFileName) + throws Exception { + + String xmlString = xmlToString(jdom); + javax.xml.transform.Source xml = + new javax.xml.transform.stream.StreamSource(new StringReader(xmlString)); + + File xsltFile = new File(stylesheetFileName); + javax.xml.transform.Source xslt = + new javax.xml.transform.stream.StreamSource(xsltFile); + + return transformToString(xml, xslt); + } + + public static String transformToString(String xmlString, + String xsltString) + throws Exception { + + javax.xml.transform.Source xml = + new javax.xml.transform.stream.StreamSource(new StringReader(xmlString)); + + javax.xml.transform.Source xslt = + new javax.xml.transform.stream.StreamSource(new StringReader(xsltString)); + + StringWriter writer = transform(xml, xslt); + + return writer.toString(); + } + + public static StringWriter transform(String xmlString, + String xsltString) + throws Exception { + + javax.xml.transform.Source xml = + new javax.xml.transform.stream.StreamSource(new StringReader(xmlString)); + + javax.xml.transform.Source xslt = + new javax.xml.transform.stream.StreamSource(new StringReader(xsltString)); + + return transform(xml, xslt); + } + + public static String transformToString(File xmlFile, + File xsltFile) + throws Exception { + + javax.xml.transform.Source xml = + new javax.xml.transform.stream.StreamSource(xmlFile); + + javax.xml.transform.Source xslt = + new javax.xml.transform.stream.StreamSource(xsltFile); + + StringWriter writer = transform(xml, xslt); + + return writer.toString(); + } + + public static StringWriter transform(File xmlFile, + File xsltFile) + throws Exception { + + javax.xml.transform.Source xml = + new javax.xml.transform.stream.StreamSource(xmlFile); + + javax.xml.transform.Source xslt = + new javax.xml.transform.stream.StreamSource(xsltFile); + + return transform(xml, xslt); + } + + public static StringWriter transform(javax.xml.transform.Source xml, + javax.xml.transform.Source xslt) + throws Exception { + + // provide output medium + StringWriter sw = new StringWriter(); + javax.xml.transform.Result result = + new javax.xml.transform.stream.StreamResult(sw); + + // create an instance of TransformerFactory + javax.xml.transform.TransformerFactory transFact = + javax.xml.transform.TransformerFactory.newInstance(); + + javax.xml.transform.Transformer trans = + transFact.newTransformer(xslt); + + trans.transform(xml, result); + + return sw; + } + + public static String transformToString(javax.xml.transform.Source xml, + javax.xml.transform.Source xslt) + throws Exception { + + StringWriter writer = transform(xml, xslt); + return writer.toString(); + } +} \ No newline at end of file diff --git a/sourceMetadata/jcb-package/src/jcb/util/DriverManagerTool.class b/sourceMetadata/jcb-package/src/jcb/util/DriverManagerTool.class new file mode 100644 index 0000000000000000000000000000000000000000..d238a7e780f28bc19c8a7a3244b03f04a9f4f616 GIT binary patch literal 2940 zcmb7GX;%|h7=A9>3}Gx9L5o{)K@c!e+gfF_tV&G)fr{WdBtr})GjV3ZQnj1i?7sK( z7ub)r9}w#~J^kDt(x1`xxif)8l4JGc@B2RQ`@Bo$uYZ331He)I6hH_=HK@et z0M1}oE^jC}Ta5^!3Pu7@Fr;Es?qhN}CztU6CNLSmn>epvO2vf$YB8;1M(!7Da0!>? zaz({eX`kYUaZQCTug6u)s))(QxC%q=b1D*2a!`HY)Tkzzh#<6%uQOR zz*tLUUSH6|&dpSKz)mh0cBg-k(#=G8!nKoTB6pH?ld15SZDkDGO&U(;p}c0^Vy8f0 za4BYFqAN#cbNMPc~$VPhWGHkz;^GZfW5wK zG8H#$fyVVzbu`AkYG_P4jiYBnxnJEH?&1Tve5m0gbSwB+!zZ|>;8P8s;d6RfY+I7f ztaY7QN~aoGU=AyzyZLD7NOO;L{vMOumGV-2)yH&reivUT_)^1H_*%m^G9JyB@mbK& zgI<9xUEvLy0-}pw&%(C?WnE!u>pKQ**@;kM-VLSGq4YA#J+x-&HJlLGH6Ndib$AyY zVH%C;sq2>GhK+P)ppX4zTNb;l&WmnCBk(rs7`BG*@q>Vx(H&>evf~;0kOM;sB@F&~=^dq#bi3Q|mN@_M7Q^K4szdhbYf?8Ldqx-n)iFFI^Gu5P+X zUAAFqk^U4N9kJXYD{IC}iwvhyMnX^Z#$tx!6o@D?CeM`;J@A~eDF!5Pyvw>%Z_WLIV-KKq|mAL>*|0V_ytp+#R;ncaVJ5kFv22)1bFkOQ3 z4{63r(UO}x6xi7^Q;HC8Jj>hRr`(ojWYSI)x|`#;z}ph6uNOkC$L55q$8Jp8dd$FH z{-=ic5&)jyGWr{;9z&Ua2sK!}f+baZATvcAgzORRFH%hNJBlb_b|35MiwUi zF?w*4J_IveV?sw~F#2Mi1he4Ou^e)S)xU%*Xv uflW^wXmGI^Sv0W3_F)n2SYjzGQ|At~Zjq$hnBp7BTKP*m1GG?v!T$g&?B2%! literal 0 HcmV?d00001 diff --git a/sourceMetadata/jcb-package/src/jcb/util/DriverManagerTool.java b/sourceMetadata/jcb-package/src/jcb/util/DriverManagerTool.java new file mode 100644 index 0000000..f3214e1 --- /dev/null +++ b/sourceMetadata/jcb-package/src/jcb/util/DriverManagerTool.java @@ -0,0 +1,127 @@ +package jcb.util; + +import java.util.*; +import java.io.*; +import java.sql.*; + + +/** + * This class provides methods to support + * JDBC driver-related functions. + */ + public class DriverManagerTool { + + /** + * Get a new database connection from a given driver, url, + * and properties (includer "user" and "password" properties). + * @param driver the JDBC driver. + * @param url a database URL. + * @param props the database properties. + * @return a new database connection object. + * @throws SQLException Failed to create a new database connection. + */ + public static java.sql.Connection getConnection(java.sql.Driver driver, + String url, + Properties props) + throws SQLException { + + return driver.connect(url, props); + } + + public static java.sql.Driver getDriver(String driverClassName) + throws InstantiationException, + ClassNotFoundException, + IllegalAccessException { + + Class driverClass = Class.forName(driverClassName); + java.sql.Driver driver = (java.sql.Driver) driverClass.newInstance(); + System.out.println("getDriver: driver is OK. driver=" + driver); + return driver; + } + + /** + * Retrieves an XML with all of the currently loaded + * JDBC drivers to which the current caller has access. + * @return all loaded JDBC drivers as an XML (serialized + * as a String object). + */ + public static String getLoadedDrivers() { + + java.util.Enumeration e = java.sql.DriverManager.getDrivers(); + StringBuffer sb = new StringBuffer(""); + sb.append(""); + while (e.hasMoreElements()) { + Object driver = e.nextElement(); + //System.out.println("JDBC Driver="+driver); + appendXMLTag(sb, "loadedDriver", driver.toString()); + } + sb.append(""); + return sb.toString(); + } + + private static void appendXMLTag(StringBuffer buffer, + String tagName, + boolean value) { + buffer.append("<"); + buffer.append(tagName); + buffer.append(">"); + buffer.append(value); + buffer.append(""); + } + + private static void appendXMLTag(StringBuffer buffer, + String tagName, + int value) { + buffer.append("<"); + buffer.append(tagName); + buffer.append(">"); + buffer.append(value); + buffer.append(""); + } + + private static void appendXMLTag(StringBuffer buffer, + String tagName, + String value) { + buffer.append("<"); + buffer.append(tagName); + buffer.append(">"); + buffer.append(value); + buffer.append(""); + } + + /** + * + * Print out all loaded JDBC drivers. + * + */ + public static void main(String[] args) throws Exception { + + try { + // register two drivers + //Class.forName("org.gjt.mm.mysql.Driver"); + //Class.forName("oracle.jdbc.driver.OracleDriver"); + + // get loaded drivers + //System.out.println(getLoadedDrivers()); + + java.sql.Driver mysqlDriver = getDriver("org.gjt.mm.mysql.Driver"); + String url = "jdbc:mysql://localhost/empDB"; + String username = "root"; + String password = "root"; + java.util.Properties props = new java.util.Properties(); + props.put("user", username); + props.put("password", password); + java.sql.Connection conn = getConnection(mysqlDriver, url, props); + System.out.println("conn="+conn); + } + catch(Exception e) { + e.printStackTrace(); + } + } +} diff --git a/sourceMetadata/jcb-package/src/jcb/util/IOUtil.class b/sourceMetadata/jcb-package/src/jcb/util/IOUtil.class new file mode 100644 index 0000000000000000000000000000000000000000..a3c0f46e2f971179ca1a130da628551ff4eda52e GIT binary patch literal 1362 zcmaJ>+fGwK6kS7GPB}dwcPN4gUg*VAK;;hFVjCM9NT4MFV#sMZkV8sK%Bev73xB{z zUf~6Z7=6>kkMR@KHLbK%gqPVfv-e(W&)PHdf z(iS~~au!t4h#@%}RxlzLPn~$CLc?|34!ML zw*F2JX7ub*{vyo`ngOw*Pi45{NM~|;w4I(3nVAd5vbzO~e1^U=C3AZ!uBe$Y z77A9izrW%SA6iBzpVtqs1+|+M)I_cvC*ZDRR}rs;1=Pqv+Ss*Bo>;-SKuZ-!NfH6? z4G8~JPhH9t@@Ye!gVMzol9rhnlqzfJgj>OchHkjYR8hWMgMvwlQFKtH@)52cRl^jf zHOydE;`C~GftLb}6|hpx8t$Wy+9wmyz_?@%u{GQ2RItEuf~Bge(iT$NM%ub8OZI4? zT-MdyipK2dWu^Z%jkkfl-5|ebE$ofa?&nR5dMI4SVzT8f>uQVa9kd8w)&)1mE=Kgw3R;Kn4B~_nfx8@K5SUm;31x^3 zouRFvt@nL{;yXpn5$y4kVxSW)*f^7^?Qn1$;0y4;i2yx*KD5Ci)V&*^?6*OU5^9W4 z(}bEN)Jzeo_Xa4(ZBP+HMG5tWP%%Qq3B_wrR1Nq*udIF6_Z<##e1Y1PGbr&UJ3c$- zeSuRrS7vHHqTU~{b)TZ{==V?mIn*O)lXf|A+rRox;W{Q-EB~Y+A`M}rXiLhBkP%oR z%PIwaiw3MSQb#XRc#Jf2HmTPZGd3|wI{_2@%#eS{16KMFkN#FV$vxSMb`fVYnl7NN l_|8$^+;GP4#eYmsiLse+z&>LS$aqM$_g4@FS>=rx_ya-548#Bc literal 0 HcmV?d00001 diff --git a/sourceMetadata/jcb-package/src/jcb/util/IOUtil.java b/sourceMetadata/jcb-package/src/jcb/util/IOUtil.java new file mode 100644 index 0000000..7853e1c --- /dev/null +++ b/sourceMetadata/jcb-package/src/jcb/util/IOUtil.java @@ -0,0 +1,127 @@ +package jcb.util; + +import java.io.*; + +/** + * + * This utility class provides methods for closing InputStream + * and FileOutputStream objects. Also, this class provides + * some utility methods for converting InputStream into a + * String object. + * + * + *

+ * Date: October 2, 2002 + *

+ * @author Mahmoud Parsian + *

+ * @since 1.4 + *

+ */ +public class IOUtil { + + /** + * Default character set for creating strings + */ + private static final String DEFAULT_CHARACTER_SET = "UTF-8"; + + /** + * Size of the buffer to read files + */ + private static final int BUFFER_SIZE = 1024; + + /** + * This method closes a given InputStream + * @param in InputStream to close + */ + public static void close(InputStream in) { + try { + if (in != null) { + in.close(); + } + } + catch (Exception e) { + //ignore + } + } + + /** + * This method closes a given FileOutputStream + * @param out FileOutputStream to close + */ + public static void close(FileOutputStream out) { + try { + if (out != null) { + out.close(); + } + } + catch (Exception e) { + //ignore + } + } + + /** + * This method closes a given ByteArrayOutputStream + * @param out ByteArrayOutputStream to close + */ + public static void close(ByteArrayOutputStream out) { + try { + if (out != null) { + out.close(); + } + } + catch (Exception e) { + //ignore + } + } + + /** + * This method reads all the data from a given InputStream + * and returns that data in a byte array (byte[]). + * + * @param input InputStream to convert to a byte[] + * @return byte[] - converted byte array + * @throws IOException Failed to convert InputStream to a byte[] + */ + public static byte[] inputStreamToByteArray(final InputStream input) + throws IOException { + + if (input == null) { + return null; + } + + ByteArrayOutputStream output = new ByteArrayOutputStream(); + int length; + byte[] buffer = new byte[BUFFER_SIZE]; + try { + while ((length = input.read(buffer)) != -1) { + output.write(buffer, 0, length); + } + } + finally { + close(output); + } + + return output.toByteArray(); + } + + + /** + * This method converts the data read from an InputStream + * to a java.lang.String object. + * + * @param input InputStream to convert to String + * @return String - resulting from conversion of InputStream + * @throws IOException Failed to read InputStream + */ + public static String inputStreamToString(final InputStream input) + throws IOException { + String result = null; + if (input != null) { + result = new String(inputStreamToByteArray(input), DEFAULT_CHARACTER_SET); + } + return result; + } + + +} diff --git a/sourceMetadata/jcb-package/src/jcb/util/Mapping.class b/sourceMetadata/jcb-package/src/jcb/util/Mapping.class new file mode 100644 index 0000000000000000000000000000000000000000..a4a167baa3f09e492638ff07c335d87b07854a74 GIT binary patch literal 942 zcmZvaU31bv7=_Px>uv0DqL@*(4$cZqB>Bd-mknclq`E$4>w^al?Xz4GTqF(sH>-xuWH&g=^TAnt2|{$-aP~F+Upn@6|^E zD_+Dq`8z65;a!2v+G5aRr~XnPdvEy87jSk|;J2m+9e=zhI|JS6`C;onxN5Dwm?5w- zZ;UxIwK^G{NjhP536_Q^GU9o1q0(#}XBC<9ch71Mr{k`_tu&zhRE|cRP*ac0Mg`Yx zoX1%kXSCQT*(k#?(X`=V&BluE9EU^Vez)UILpAV{2;G{^{aL5)cSC_{)KWvQ?T?il zs88`+csCNy`QvvIDD3lf^fa--N46kv3|SbOgnti1!$g%FQ6&niNnZsgs8#;DMPG*1 zalb>jTSqY5#t|}K*%DZ#Ru~D~r#|3Ewi)`6J121}30P+pbmZJ`$bOj}%SX*8)YDj_ z>Tk_kbDvYz7EPREVr>%3prh. + */ + +package jcb.util; +//package org.apache.axis.utils; + +import java.io.Serializable; + +public class Mapping implements Serializable { + private String namespaceURI; + private int namespaceHash; + + private String prefix; + private int prefixHash; + + public Mapping (String namespaceURI, String prefix) { + setPrefix(prefix); + setNamespaceURI(namespaceURI); + } + + public String getNamespaceURI() { + return namespaceURI; + } + + public int getNamespaceHash() { + return namespaceHash; + } + + public void setNamespaceURI (String namespaceURI) { + this.namespaceURI = namespaceURI; + this.namespaceHash = namespaceURI.hashCode(); + } + + public String getPrefix() { + return prefix; + } + + public int getPrefixHash() { + return prefixHash; + } + + public void setPrefix (String prefix) { + this.prefix = prefix; + this.prefixHash = prefix.hashCode(); + } +} diff --git a/sourceMetadata/jcb-package/src/jcb/util/NSStack.class b/sourceMetadata/jcb-package/src/jcb/util/NSStack.class new file mode 100644 index 0000000000000000000000000000000000000000..13827747a5cce5a66096c1680b267149687a8dec GIT binary patch literal 2649 zcmZuz?{8CO6n@_J_9qt@+d3$2fWTmDCxgKzZZL-6VA2(&{BT2*yY8}eY+Y$P0)9}V zOEfXY_`wjsz%<7BaZ@M;0)7L7N{ku<;$Pqg4JIZ=4D&g+m$ksYyzjYh-}9Vvp68r* zyK(>0RRC*X`0)hR`>+tt$kHrJiw7HI-{?mxHu-6_`QgH5Kc2-F54QR-3+v_hIkDQs z+9tnkms=h3`Mg*=yoktgr+h?Z*(u8|x$uGqyFG|0xH4HIeng?{Kx81^Q$LbT4AyrV zsZ=7_*P`Ie4yP1Uhk`eeHPc3RIIU0;A4#XpWOl20*cchiMv3CykVq!7t#qiV-KU^! z8SXU|=0*}pGdeQVW2W~QJ%c>aQX`pu-bx9qKR!5|G~3h05Pz9pQyUpDjv4t3HmB3Z ziAW-oWe&V%8fp8Qp9$?eY=4xC&*MpJN%MG?L5$vBg_SjV*g+%NS0Br!rLM)Ho0Mw3BSWMiFcSjv@yCWo(s8pr zA;js?SWJXkB^>Ekie)+$VX=-SvOI~!l;u$>bX20sgFQO-VxNwX_^if$4_?&Kg>Gs- z1K~QtsME0u2Xs6o)=Od?M5B%s0uoiDS zdj`xn#VI<9oycU(A@XmC=<(sy358HGCwZTijw0C}9Ce6rRvS!5ur+=-grz&%bkI!p zWu*aYYAL`&%-fK)rkR8*X8`$11BwDdFUck$aw({S)3uq1!$p?C0F3O0C(s-+)fpn zsdXKj4yCT}=SLz^s6vWm|maGaF9 zN;+Oc5U+D!-r%eHCN|?O?7%3Zc$@R_F81LACRu}8t|Gz#66EAwZwGcXT!%|dT*j=f zi_jyX9An#_7#TwJ{!a%<7PkAia`j&PnDhlAMC&B$hDd z6v3U6av|GNk_1e^i%Dwt1+l**HeUccLMuB)dU6qw1>NzfuwjJ}#BK|+p@28XBJUCf zxQyAjLf=)Wx3TV#8R6zF!D*GHNfV@i2;FE~l$p$yoU$UyPvIQq1+-QkQhaZyilR@B zYE$D=*I7xacnQ*FxVpl17f}|IFZ*_-b$cA;&8}kipzG^Nrs={uHYwNLsl#HPBjl8g;CJb5Ly;C-elv(;qohSPt&e zauI?g26*{B`JHq%yMnIkG9<@>t{mo9jbTWP3SyH~Lu_BOyYdv~1lY z4R{0E7~Da(C3C=AfUF95#DBpU%7ShSDWAwVe4}0}@{OfSRu$S|AGrhmU@QEIxwwmR z{LLx+hs^zp2<~wL|08qv!GAAsLMgnXTzFr(@uBkIobuvx<->&XMYg?hgA*D zT2QknTolw;ZRHpOV)*hD`oyl77. + */ +//package org.apache.axis.utils; +package jcb.util; + +//import org.apache.axis.components.logger.LogFactory; +//import org.apache.commons.logging.Log; + +import java.util.ArrayList; + +/** + * The abstraction this class provides is a push down stack of variable + * length frames of prefix to namespace mappings. Used for keeping track + * of what namespaces are active at any given point as an XML document is + * traversed or produced. + * + * From a performance point of view, this data will both be modified frequently + * (at a minimum, there will be one push and pop per XML element processed), + * and scanned frequently (many of the "good" mappings will be at the bottom + * of the stack). The one saving grace is that the expected maximum + * cardinalities of the number of frames and the number of total mappings + * is only in the dozens, representing the nesting depth of an XML document + * and the number of active namespaces at any point in the processing. + * + * Accordingly, this stack is implemented as a single array, will null + * values used to indicate frame boundaries. + * + * @author James Snell + * @author Glen Daniels (gdaniels@macromedia.com) + * @author Sam Ruby (rubys@us.ibm.com) + */ +public class NSStack { + //protected static Log log = + //LogFactory.getLog(NSStack.class.getName()); + + private Mapping[] stack; + private int top = 0; + private int iterator = 0; + private int currentDefaultNS = -1; + + public NSStack() { + stack = new Mapping[32]; + stack[0] = null; + } + + /** + * Create a new frame at the top of the stack. + */ + public void push() { + top ++; + + if (top >= stack.length) { + Mapping newstack[] = new Mapping[stack.length*2]; + System.arraycopy (stack, 0, newstack, 0, stack.length); + stack = newstack; + } + + //if (log.isTraceEnabled()) + //log.trace("NSPush (" + stack.length + ")"); + + stack[top] = null; + } + + /** + * Remove the top frame from the stack. + */ + public void pop() { + clearFrame(); + + top--; + + // If we've moved below the current default NS, figure out the new + // default (if any) + if (top < currentDefaultNS) { + while (currentDefaultNS > 0) { + if (stack[currentDefaultNS] != null && + stack[currentDefaultNS].getPrefix().length() == 0) + break; + currentDefaultNS--; + } + } + + if (top == 0) { + //if (log.isTraceEnabled()) + // log.trace("NSPop (" + Messages.getMessage("empty00") + ")"); + + return; + } + + //if (log.isTraceEnabled()){ + // log.trace("NSPop (" + stack.length + ")"); + //} + } + + /** + * Return a copy of the current frame. Returns null if none are present. + */ + public ArrayList cloneFrame() { + if (stack[top] == null) return null; + + ArrayList clone = new ArrayList(); + + for (Mapping map=topOfFrame(); map!=null; map=next()) { + clone.add(map); + } + + return clone; + } + + /** + * Remove all mappings from the current frame. + */ + private void clearFrame() { + while (stack[top] != null) top--; + } + + /** + * Reset the embedded iterator in this class to the top of the current + * (i.e., last) frame. Note that this is not threadsafe, nor does it + * provide multiple iterators, so don't use this recursively. Nor + * should you modify the stack while iterating over it. + */ + public Mapping topOfFrame() { + iterator = top; + while (stack[iterator] != null) iterator--; + iterator++; + return next(); + } + + /** + * Return the next namespace mapping in the top frame. + */ + public Mapping next() { + if (iterator > top) { + return null; + } else { + return stack[iterator++]; + } + } + + /** + * Add a mapping for a namespaceURI to the specified prefix to the top + * frame in the stack. If the prefix is already mapped in that frame, + * remap it to the (possibly different) namespaceURI. + */ + public void add(String namespaceURI, String prefix) { + int idx = top; + try { + // Replace duplicate prefixes (last wins - this could also fault) + for (int cursor=top; stack[cursor]!=null; cursor--) { + if (stack[cursor].getPrefix().equals(prefix)) { + stack[cursor].setNamespaceURI(namespaceURI); + idx = cursor; + return; + } + } + + push(); + stack[top] = new Mapping(namespaceURI, prefix); + idx = top; + } finally { + // If this is the default namespace, note the new in-scope + // default is here. + if (prefix.length() == 0) { + currentDefaultNS = idx; + } + } + } + + /** + * Return an active prefix for the given namespaceURI. NOTE : This + * may return null even if the namespaceURI was actually mapped further + * up the stack IF the prefix which was used has been repeated further + * down the stack. I.e.: + * + * + * + * *here's where we're looking* + * + * + * + * If we look for a prefix for "namespace" at the indicated spot, we won't + * find one because "pre" is actually mapped to "otherNamespace" + */ + public String getPrefix(String namespaceURI, boolean noDefault) { + if ((namespaceURI == null) || (namespaceURI.equals(""))) + return null; + + int hash = namespaceURI.hashCode(); + + // If defaults are OK, and the given NS is the current default, + // return "" as the prefix to favor defaults where possible. + if (!noDefault && currentDefaultNS > 0 && stack[currentDefaultNS] != null && + namespaceURI.equals( + stack[currentDefaultNS].getNamespaceURI())) + return ""; + + for (int cursor=top; cursor>0; cursor--) { + Mapping map = stack[cursor]; + if (map == null) continue; + + if (map.getNamespaceHash() == hash && + map.getNamespaceURI().equals(namespaceURI)) { + String possiblePrefix = map.getPrefix(); + if (noDefault && possiblePrefix.length() == 0) continue; + + // now make sure that this is the first occurance of this + // particular prefix + int ppHash = possiblePrefix.hashCode(); + for (int cursor2=top; true; cursor2--) { + if (cursor2 == cursor) return possiblePrefix; + map = stack[cursor2]; + if (map == null) continue; + if (ppHash == map.getPrefixHash() && + possiblePrefix.equals(map.getPrefix())) break; + } + } + } + + return null; + } + + /** + * Return an active prefix for the given namespaceURI, including + * the default prefix (""). + */ + public String getPrefix(String namespaceURI) { + return getPrefix(namespaceURI, false); + } + + /** + * Given a prefix, return the associated namespace (if any). + */ + public String getNamespaceURI(String prefix) { + if (prefix == null) + prefix = ""; + + int hash = prefix.hashCode(); + + for (int cursor=top; cursor>0; cursor--) { + Mapping map = stack[cursor]; + if (map == null) continue; + + if (map.getPrefixHash() == hash && map.getPrefix().equals(prefix)) + return map.getNamespaceURI(); + } + + return null; + } + + /** + * Produce a trace dump of the entire stack, starting from the top and + * including frame markers. + */ + public void dump(String dumpPrefix) + { + for (int cursor=top; cursor>0; cursor--) { + Mapping map = stack[cursor]; + + //if (map == null) { + // log.trace(dumpPrefix + Messages.getMessage("stackFrame00")); + //} else { + // log.trace(dumpPrefix + map.getNamespaceURI() + " -> " + map.getPrefix()); + //} + } + } +} diff --git a/sourceMetadata/jcb-package/src/jcb/util/RandomGUID.class b/sourceMetadata/jcb-package/src/jcb/util/RandomGUID.class new file mode 100644 index 0000000000000000000000000000000000000000..fc14a536e453ee664fdc920e57c824552e7d8b10 GIT binary patch literal 2886 zcmZ`*`EyfM6#gDf`;wPenzp1+3R)F0-H3otEg*D3TDqu|MXZWx@)}Z;_iFOe#f?P~ zP(cM`aknn$xUp#3u`|xN;xf*tKd3YQ;*8t)Pl(@rFEnXWe>wNQbI$$Fx!*bGCg1$~ z(Z>LmVpPEjv^&w^LKQlN=u#+dmT`-M0%5sT!6tOe*zCdvLX#A?b&iX@rDpc6w*42!QGCq~42pN#uO+;$lch^Pt!Rm+}F>jQR=d0Q(!O?7lGzmo=5nby_#(K5*=0IR>dTjM8l+ z<3a7FhzMPj3AjYCqhbx1Fsr)~^(w9xq6v*ep3YrUvae5z^KPU~#x51Ru}8vU%Waa7 zE~7gc+}Rin8{}taZ2fRh8!#gV%e+^`!+1o(++5s9G$erK_3^k7Z>UtU50475Uqv%o zWE@a&5Rb`tT*VVOq~b81RIv)HRXinjH=sdyKP^FOka0vDIx6Fsif3?K#R;5LaZ2p= z;aM5asdyeQNLXm4p=+jpi++!84C$>#!kkQ3LV=x(iWkwM;w8LH^g6NO+0y=CuRp6# z?1~h1Yg&jsR%zF84Qmh&3<(>z?hNhxQZrx6)~Hwy7JvR!BC|V7g2ysug%o9b<&xfN z@SA)4wV)}XVk%CjmPiD`T1zCXC1`cCf!g$h8PJ1lhNZq4nrB*zPXXXW*s0hvHIgv3 z7(2p9654AYj2Qk~IBF(Y&;nwF3IYQIni#OU|Bse6qD@Jw9e8kxzkR(`xl@txFSTwy zH9os)Kx7l;taxXN&rz9UofEClM$s4w#mO0qM5;QBU?3_wL&CgE6FJS1i5BxUh-Nbs5ZTQkd z<@L4Yo@ZM0+QPcWn*#}kbtRI$iF9^lzP6cxED$~Npi*hZ$Zp19^fU@c_NYy2?K17}+9o2bb$UjSqgmuD>e9A%M-$}%~;K2~Q z7`Ct)v#@3f-yE!p8L)O|VeKK-US`54)W(utLmmo6aH(?w1>46Uca=ED;p#k%%Nrc$ z;GTd=ZDGmm6pG3nDR@#SPN8HRr45d8%&E_J)yoy9F#8<5DU{XAr{O+_xhc%6m+ORo zc?$El)s<9OOIiLn7EDpdX+?Ei3JXa}ZS@DpOX0EGrzIT_2BP zNx94GUS5og53N+as>d@5ce&!ZHiav;l`CF#99N1EkGQ4N7r(DAS1e%1^!qHDdY`jo zMIqazlz#k%-*FX55f#~sO3DMYAEfOG`aDUmLuB$WJ&)iz9A)K?vF69=e*&#IiFQ8e z-56yJUquM7LC5Pz;tlM=o7j)Hcy@OZqF6Da|!~6IWXYd2Rf5v&nA7cg|;!mV- z5#!8+zchBmXmzk=fI+6n@6{b?hB|9&@;uHI7K_W*mRw^kH6Eu&&C!vw9G%BACr3w( z&w?R^XBg5ZWEp>rfluJXrzGPuEWqa^>kC}VE7aox6a9(=e2v@i4R+vL^y53Y#IH#D z0_#YnXy17gsA6kXw~LE()LcNmbf$(E%0#k<;YUXLiB0-5it!7n|CMMrVM7{CG_XJ$ zPNQ{X^(@hfYOH=Lvb#3R#_kd}GMH;)FBb9al9_CND#yWQOCQUO?tK1h1k2{cA6UfF zt;1jZL;5!d_#f(8C!c~w7EoloZ~{wt|7GXlwTEZz1eR~VYz)_($J`8T3EhDxdoM-; Pbkc3`>TT4`!p8pqr_8wo literal 0 HcmV?d00001 diff --git a/sourceMetadata/jcb-package/src/jcb/util/RandomGUID.java b/sourceMetadata/jcb-package/src/jcb/util/RandomGUID.java new file mode 100644 index 0000000..ea47be1 --- /dev/null +++ b/sourceMetadata/jcb-package/src/jcb/util/RandomGUID.java @@ -0,0 +1,234 @@ +package jcb.util; + +/* + * RandomGUID + * @version 1.2 01/29/02 + * @author Marc A. Mnich + * + * From www.JavaExchange.com, Open Software licensing + * + * 01/29/02 -- Bug fix: Improper seeding of nonsecure Random object + * caused duplicate GUIDs to be produced. Random object + * is now only created once per JVM. + * 01/19/02 -- Modified random seeding and added new constructor + * to allow secure random feature. + * 01/14/02 -- Added random function seeding with JVM run time + * + */ +import java.net.*; +import java.util.*; +import java.security.*; + +/* + * In the multitude of java GUID generators, I found none that + * guaranteed randomness. GUIDs are guaranteed to be globally unique + * by using ethernet MACs, IP addresses, time elements, and sequential + * numbers. GUIDs are not expected to be random and most often are + * easy/possible to guess given a sample from a given generator. + * SQL Server, for example generates GUID that are unique but + * sequencial within a given instance. + * + * GUIDs can be used as security devices to hide things such as + * files within a filesystem where listings are unavailable (e.g. files + * that are served up from a Web server with indexing turned off). + * This may be desireable in cases where standard authentication is not + * appropriate. In this scenario, the RandomGUIDs are used as directories. + * Another example is the use of GUIDs for primary keys in a database + * where you want to ensure that the keys are secret. Random GUIDs can + * then be used in a URL to prevent hackers (or users) from accessing + * records by guessing or simply by incrementing sequential numbers. + * + * There are many other possiblities of using GUIDs in the realm of + * security and encryption where the element of randomness is important. + * This class was written for these purposes but can also be used as a + * general purpose GUID generator as well. + * + * RandomGUID generates truly random GUIDs by using the system's + * IP address (name/IP), system time in milliseconds (as an integer), + * and a very large random number joined together in a single String + * that is passed through an MD5 hash. The IP address and system time + * make the MD5 seed globally unique and the random number guarantees + * that the generated GUIDs will have no discernable pattern and + * cannot be guessed given any number of previously generated GUIDs. + * It is generally not possible to access the seed information (IP, time, + * random number) from the resulting GUIDs as the MD5 hash algorithm + * provides one way encryption. + * + * ----> Security of RandomGUID: <----- + * RandomGUID can be called one of two ways -- with the basic java Random + * number generator or a cryptographically strong random generator + * (SecureRandom). The choice is offered because the secure random + * generator takes about 3.5 times longer to generate its random numbers + * and this performance hit may not be worth the added security + * especially considering the basic generator is seeded with a + * cryptographically strong random seed. + * + * Seeding the basic generator in this way effectively decouples + * the random numbers from the time component making it virtually impossible + * to predict the random number component even if one had absolute knowledge + * of the System time. Thanks to Ashutosh Narhari for the suggestion + * of using the static method to prime the basic random generator. + * + * Using the secure random option, this class compies with the statistical + * random number generator tests specified in FIPS 140-2, Security + * Requirements for Cryptographic Modules, secition 4.9.1. + * + * I converted all the pieces of the seed to a String before handing + * it over to the MD5 hash so that you could print it out to make + * sure it contains the data you expect to see and to give a nice + * warm fuzzy. If you need better performance, you may want to stick + * to byte[] arrays. + * + * I believe that it is important that the algorithm for + * generating random GUIDs be open for inspection and modification. + * This class is free for all uses. + * + * + * - Marc + * + * Revised by: Mahmoud Parsian + */ +public class RandomGUID extends Object { + + public String valueBeforeMD5 = ""; + public String valueAfterMD5 = ""; + + private static Random myRand; + private static SecureRandom mySecureRand; + + /* + * Static block to take care of one time secureRandom seed. + * It takes a few seconds to initialize SecureRandom. You might + * want to consider removing this static block or replacing + * it with a "time since first loaded" seed to reduce this time. + * This block will run only once per JVM instance. + */ + + static { + mySecureRand = new SecureRandom(); + long secureInitializer = mySecureRand.nextLong(); + myRand = new Random(secureInitializer); + } + + + /* + * Default constructor. With no specification of security option, + * this constructor defaults to lower security, high performance. + */ + public RandomGUID() { + getRandomGUID(false); + } + + /* + * Constructor with security option. Setting secure true + * enables each random number generated to be cryptographically + * strong. Secure false defaults to the standard Random function seeded + * with a single cryptographically strong random number. + */ + public RandomGUID(boolean secure) { + getRandomGUID(secure); + } + + /* + * Method to generate the random GUID + */ + private void getRandomGUID(boolean secure) { + MessageDigest md5=null; + StringBuffer sbValueBeforeMD5 = new StringBuffer(); + + try { + md5 = MessageDigest.getInstance("MD5"); + } catch (NoSuchAlgorithmException e) { + System.out.println("Error: " + e); + } + + try { + InetAddress id = InetAddress.getLocalHost(); + long time = System.currentTimeMillis(); + long rand = 0; + + if(secure) { + rand = mySecureRand.nextLong(); + } else { + rand = myRand.nextLong(); + } + + // This StringBuffer can be a long as you need; the MD5 + // hash will always return 128 bits. You can change + // the seed to include anything you want here. + // You could even stream a file through the MD5 making + // the odds of guessing it at least as great as that + // of guessing the contents of the file! + sbValueBeforeMD5.append(id.toString()); + sbValueBeforeMD5.append(":"); + sbValueBeforeMD5.append(Long.toString(time)); + sbValueBeforeMD5.append(":"); + sbValueBeforeMD5.append(Long.toString(rand)); + + valueBeforeMD5 = sbValueBeforeMD5.toString(); + md5.update(valueBeforeMD5.getBytes()); + + byte [] array = md5.digest(); + StringBuffer sb = new StringBuffer(); + for(int j=0; j + */ +public class SimpleXML { + + static DocumentBuilderFactory _dbf = null; + static boolean _ignoreWhitespace = false; + static boolean _ignoreComments = false; + static boolean _putCDATAIntoText = false; + static boolean _createEntityRefs = false; + static boolean _validation = false; + // + // Changed _out from an OutputStream to a Writer - + // since JSP tags MUST use Writers instead of OutputStreams + // OutputStream _out = null; + // + Writer _out = null; + Document _doc = null; + String xmlFilename = ""; + + synchronized static DocumentBuilderFactory getDocumentBuilder() { + if (_dbf == null) { + try { + _dbf = DocumentBuilderFactory.newInstance(); + _dbf.setValidating(_validation); + } + catch (Exception e){ + System.out.println("DocumentBuilderFactory:" + e.toString()); + } + } + return _dbf; + } + + /** + * Constructs a class which holds Document from specified filename. + * + * @param file input file handle + * @exception Exception if specified file is not a valid XML file + */ + public SimpleXML(File file) throws Exception { + // parse the input file + try { + xmlFilename = file.getAbsolutePath(); + DocumentBuilder db = getDocumentBuilder().newDocumentBuilder(); + _doc = db.parse(file); + } + catch (SAXException se){ + System.out.println("SAXException:" + se.getMessage()); + throw new Exception (se.getMessage()); + } + catch (IOException ioe){ + System.out.println("IOException:" + ioe.toString()); + throw new Exception (ioe.getMessage()); + } + catch (Exception e) { + System.out.println("Exception:" + e.toString()); + throw new Exception(e.toString()); + } + } + + /** + * Constructs a class which holds Document from specified document. + * Throw exception + * if specified file is not a valid XML file. + * + * @param doc input document + * @exception Exception if docment is not valid + */ + public SimpleXML(Document doc) throws Exception { + _doc = doc; + } + + + /** + * Constrcuts a class which holds document from input string. + * @param str string which contains the entire XML + * @param notRoot dummy boolean to distinguish it from the other String constructor + * @exception Exception if input string is not valid XML. + */ + public SimpleXML(String str, boolean notRoot) throws Exception { + try { + if ((str.equals("")) || (str==null)) + throw new Exception("Empty XML string"); + StringReader sr = new StringReader(str); + InputSource is = new InputSource(sr); + DocumentBuilder db = getDocumentBuilder().newDocumentBuilder(); + _doc = db.parse(is); + } + catch (SAXException se) { + System.out.println("SAXException:" + se.getMessage()); + throw new Exception (se.getMessage()); + } + catch (IOException ioe) { + System.out.println("IOException:" + ioe.toString()); + throw new Exception (ioe.getMessage()); + } + catch (Exception e) { + System.out.println("Exception:" + e.toString()); + throw new Exception(e.toString()); + } + } + + + + /** + * Constructs a XML class which holds Document from input stream. + * + * @param inputStream + * @exception Exception if input stream is not valid XML + */ + public SimpleXML(InputStream inputStream) throws Exception { + // parse the input file + try { + DocumentBuilder db = getDocumentBuilder().newDocumentBuilder(); + // Set an ErrorHandler before parsing + // OutputStreamWriter errorWriter = new OutputStreamWriter(System.err, outputEncoding); + // db.setErrorHandler(new XMLErrorHandler(new PrintWriter(errorWriter, true))); + _doc = db.parse(inputStream); + } + catch (SAXException se) { + System.out.println("SAXException:" + se.getMessage()); + throw new Exception (se.getMessage()); + } + catch (IOException ioe) { + System.out.println("IOException:" + ioe.toString()); + throw new Exception (ioe.getMessage()); + } + catch (Exception e) { + System.out.println("Exception:" + e.toString()); + throw new Exception(e.toString()); + } + } + + /** + * Constructs new empty XML class with specified name as root tag name. + * + * @param rootTag root tag name + * @exception Exception error to create Document from root tag. + */ + public SimpleXML(String rootTag) throws Exception { + this(rootTag, new Hashtable()); // use an empty hashtable + } + + /** + * Constructs new XML Document with specified name and attributes + * for root tag. + * + * @param rootTag name of root tag + * @param attrs hashtable which holds name/value pairs associated with the root tag. + */ + public SimpleXML(String rootTag, Hashtable attrs) throws Exception { + try { + DocumentBuilder db = getDocumentBuilder().newDocumentBuilder(); + _doc = db.newDocument(); + createRootNode(rootTag, attrs); + } + catch (ParserConfigurationException pce) { + throw new Exception(pce.toString()); + } + } + + /** + * Create root node with specified name + * @param elementName name of root node. + */ + public Node createRootNode(String elementName) { + return createRootNode(elementName, null); + } + + /** + * Create root node with specified name and attributes + * @param elementName name of root tag + * @param attrs attributes associated with the root tag. + */ + public Node createRootNode(String elementName, Hashtable attrs) { + + System.out.println("Creating root: " + elementName); + Element elementNode = _doc.createElement(elementName); + if (attrs != null) { + Enumeration names = attrs.keys(); + while (names.hasMoreElements()) { + String name = (String) names.nextElement(); + String value = (String) attrs.get(name); + elementNode.setAttribute(name, value); + } + } + _doc.appendChild(elementNode); + return elementNode; + } + + + /** + * Create a node with specified name and value + * @param elementName name of the element + * @param value value for the tag + */ + public Node createNode(String elementName, String value) + { + if (value == null) { + value = ""; + } + Element elementNode = _doc.createElement(elementName); + Text textNode = _doc.createTextNode(value); + elementNode.appendChild(textNode); + return elementNode; + } + + /** + * Create a node with specified element tag and attribute name and value + * @param elementName name of the element tag + * @param elementValue texzt value of the element tag + * @param attrName name of the attribute + * @param attrValue value for the attribute + */ + public Node createNode(String elementName, + String elementValue, + String attrName, + String attrValue) { + + if (elementValue == null) { + elementValue = ""; + } + Element elementNode = _doc.createElement(elementName); + Text textNode = _doc.createTextNode(elementValue); + if (attrValue != null) { + elementNode.appendChild(textNode); + elementNode.setAttribute(attrName, attrValue); + } + return elementNode; + } + + /** + * Create a node with specified name and attributes + * @param elementName name of the element + * @param attrs hashtable which holds all name/value pairs as attributes for the element. + */ + public Node createNode(String elementName, Hashtable attrs) + { + Element elementNode = _doc.createElement(elementName); + Enumeration names = attrs.keys(); + while (names.hasMoreElements()) { + String name = (String) names.nextElement(); + String value = (String) attrs.get(name); + elementNode.setAttribute(name, value); + } + return elementNode; + } + + /** + * Create a node with specified name, value and attributes + * @param elementName name of the element + * @param elementValue text value of the element + * @param attrs hashtable which holds all name/value pairs as attributes for the element. + */ + public Node createNode(String elementName, + String elementValue, + Hashtable attrs) { + Element elementNode = _doc.createElement(elementName); + Text textNode = _doc.createTextNode(elementValue); + elementNode.appendChild(textNode); + Enumeration names = attrs.keys(); + while (names.hasMoreElements()) { + String name = (String) names.nextElement(); + String value = (String) attrs.get(name); + elementNode.setAttribute(name, value); + } + + return elementNode; + } + + /** + * Create a node with specified name, value and attributes + * @param elementName name of the element + * @param elementValue text value of the element + * @param attrs array of attribute names + * @param values array of attribute values + */ + public Node createNode(String elementName, + String elementValue, + String[] attrs, + String[] values) { + Element elementNode = _doc.createElement(elementName); + Text textNode = _doc.createTextNode(elementValue); + elementNode.appendChild(textNode); + for (int i=0; i < attrs.length; i++) { + elementNode.setAttribute(attrs[i], values[i]); + } + return elementNode; + } + + /** + * Create a node with specified name and attributes + * @param elementName name of the element + * @param attrs array of attribute names + * @param values array of attribute values + */ + public Node createNode(String elementName, + String[] attrs, + String[] values) { + Element elementNode = _doc.createElement(elementName); + //Text textNode = _doc.createTextNode(elementValue); + //elementNode.appendChild(textNode); + for (int i=0; i < attrs.length; i++) { + elementNode.setAttribute(attrs[i], values[i]); + } + return elementNode; + } + + /** + * Create a node with specified element name + * @param elementName name of the element + */ + public Node createNode(String elementName) { + return _doc.createElement(elementName); + } + + /** + * Append a node to the end of list. + * @param child node to append + */ + public Node add(Node child) { + getRootNode().appendChild(child); + return child; + } + + /** + * Append a node to the end of list. + * @param elementName name of the node to append + * @param value text value set for the node + */ + public Node add(String elementName, String value) { + Node node = createNode(elementName, value); + getRootNode().appendChild(node); + return node; + } + + /** + * Append a node to an existing node + * @param parenetNode node to append child node + * @param elementName name of child node to append + * @param value value for the child node. + */ + public Node add(Node parentNode, String elementName, String value) { + Node node = createNode(elementName, value); + parentNode.appendChild(node); + return node; + } + + /** + * Append a node to an existing node + */ + public Node add(Node parentNode, String elementName, Hashtable attrs) { + Node node = createNode(elementName, attrs); + parentNode.appendChild(node); + return node; + } + + /** + * Get current Document object stored in the class + */ + public Document getDocument() { + return _doc; + } + + /** + * Get root node of the XML document + */ + public Node getRootNode() { + return _doc.getFirstChild(); + } + + /** + * Get list of child name from specified node + * @param node input node + */ + public String [] getChildren(Node node) { + Vector v = new Vector(); + for (Node child = node.getFirstChild(); child != null; child = child.getNextSibling()) { + if (child.getNodeType() == Node.ELEMENT_NODE) { + v.addElement(child.getNodeName()); + } + } + + String [] list = new String[v.size()]; + for (int i = 0; i < v.size(); i++) { + list[i] = (String) v.elementAt(i); + } + return list; + } + + + /** + * Get list of top first level children names + */ + String [] getChildren() { + return getChildren(_doc); + } + + + /** + * Get list of child node in vector from specified node + * @param node input node + */ + public Vector getChildrenNodes(Node node) { + Vector v = new Vector(); + for (Node child = node.getFirstChild(); child != null; child = child.getNextSibling()) { + if (child.getNodeType() == Node.ELEMENT_NODE) { + v.addElement(child); + } + } + + return v; + } + + /** + * Get immediate child from the node base name + * @param node input node + * @param name name of child node + */ + public Node getChild(Node node, String name) { + for (Node child = node.getFirstChild(); child != null; child = child.getNextSibling()) { + if (child.getNodeType() == Node.ELEMENT_NODE) { + if (child.getNodeName().compareTo(name) == 0) { + return child; + } + } + } + return null; + } + + + /** + * Search node with specified tag name + * @param elementName name of element node + */ + Node searchNode(String elementName) { + NodeList nodeList = _doc.getElementsByTagName(elementName); + if (nodeList.getLength() > 0) { + return nodeList.item(0); + } + return null; + } + + + /** + * Get attribute value from its name under the specified node + * @param elemNode input node + * @param attrName name of the target attribute + */ + public static String getAttrText(Node elemNode, String attrName) { + if (elemNode.hasAttributes() == false) { + return null; + } + + NamedNodeMap atts = elemNode.getAttributes(); + for (int i = 0; i < atts.getLength(); i++) { + Node attrNode = atts.item(i); + String name = attrNode.getNodeName(); + if (attrName.compareToIgnoreCase(name) == 0) { + return attrNode.getNodeValue(); + } + } + return null; + } + + + /** + * get attribute value of the node + * @param elemNode input node + * @param attrName name of the target attribute + */ + public String getAttrValue(Node elemNode, String attrName) { + return getAttrText(elemNode,attrName); + } + + /** + * Get list of attribute name/value as a string on specified node + */ + String getAttrNameValues(Node elemNode) { + if (elemNode.hasAttributes() == false) { + return null; + } + + StringBuffer output = new StringBuffer(); + NamedNodeMap atts = elemNode.getAttributes(); + for (int i = 0; i < atts.getLength(); i++) { + Node attrNode = atts.item(i); + String name = attrNode.getNodeName(); + output.append(" " + name + "=" + "\"" + attrNode.getNodeValue() + "\""); + } + return output.toString(); + } + + /** + * Get text value from current node + * @param elemNode input node + */ + public String getTextElementValue(Node elemNode) { + return getText(elemNode); + } + + /** + * Get text value from a node + * @param elemNode input node + * @return text value, null if there is no value + */ + public static String getText(Node elemNode) { + if (elemNode.hasChildNodes()) { + for (Node child = elemNode.getFirstChild(); child != null; child = child.getNextSibling()) { + if (child.getNodeType() == Node.TEXT_NODE) { + String s = child.getNodeValue(); + if (s != null) { + return s.trim(); + } + return null; + } + } + } + return null; + + } + + /** + * Get text value of document location. Location is specified through + * xPath. + *

+ * + * getPathValue("/server/db/action") returns first + * text value of under . + *

+ * getPathValue("/server/db[@source="oracle"]/action") + * returns text value of under oracle database + * + * @param path xPath value + * @return text value of the node. + */ + + public String getPathValue(String path) { + return getPathValue(getDocument(),path); + } + + /** + * Get node value of document location. + * @param path xPath to specify location of the node + */ + public Node getPathNode(String path) { + NodeIterator nl = null; + Node n; + try { + //Use the XPathAPI class from Xalan to evaluate the expression + nl = XPathAPI.selectNodeIterator(getDocument(), path); + //Iterate over the resulting Node set, printing out the top-level results + while ((n = nl.nextNode())!= null) { + return n; + } + } + catch (TransformerException e) { + System.out.println("getPathValue:" + path + ":" + e.toString()); + e.printStackTrace(); + } + return null; + } + + + /** + * Get text node value based on specified location under given node. This is static version. + * Path is following XPath syntax. + *

+ * getPathValue("/server/db/action") returns first + * text value of under . + *

+ * getPathValue("/server/db[@source="oracle"]/action") + * returns text value of under oracle database + * + * @param node input node + * @param path xPath to locate return node. + */ + + public static String getPathValue(Node node, String path) { + NodeIterator nl = null; + Node n; + try { + //Use the XPathAPI class from Xalan to evaluate the expression + nl = XPathAPI.selectNodeIterator(node, path); + //Iterate over the resulting Node set, printing out the top-level results + while ((n = nl.nextNode())!= null) { + return getText(n); + } + } + catch (TransformerException e) { + System.out.println("getPathValue:" + path + ":" + e.toString()); + e.printStackTrace(); + } + return null; + } + + + + /** + * Get list of text values matching specified xPath. + * @param path xPath to find nodes in the xml document. + */ + public String[] getPathValues(String path) { + NodeIterator nl = null; + Node n; + try { + //Use the XPathAPI class from Xalan to evaluate the expression + nl = XPathAPI.selectNodeIterator(getDocument(), path); + Vector v = new Vector(); + //Iterate over the resulting Node set, return as a String array + while ((n = nl.nextNode())!= null) { + String value = getTextElementValue(n); + if (value != null) { + v.add(getTextElementValue(n)); + } + } + + if (v.size() > 0) { + String [] list = new String[v.size()]; + for (int i = 0; i < v.size(); i++) { + list[i] = (String) v.elementAt(i); + } + return list; + } + } + catch (TransformerException e) { + System.out.println("getPathValues:" + path + ":" + e.toString()); + e.printStackTrace(); + } + return null; + } + + /** + * Return value of attribute which resides on first node of + * specified xPath. + * + * @param path xPath to locate node + * @param attrName input attribute name + * + */ + public String getPathAttrValue(String path, String attrName) { + NodeIterator nl = null; + Node n; + try { + //Use the XPathAPI class from Xalan to evaluate the expression + nl = XPathAPI.selectNodeIterator(getDocument(), path); + //Iterate over the resulting Node set, return first one on the list + while ((n = nl.nextNode())!= null) { + return getAttrValue(n, attrName); + } + } + catch (TransformerException e) { + System.out.println("getPathAttrValue:" + path + ":" + attrName + ":" + e.toString()); + e.printStackTrace(); + } + return null; + } + + /** + * Get list of attribue values from specified xPath and attribute + * name + * @param path xPath to locate nodes + * @param attrName input attribute name + * + **/ + public String [] getPathAttrValues(String path, String attrName) { + NodeIterator nl = null; + Node n; + try { + //Use the XPathAPI class from Xalan to evaluate the expression + nl = XPathAPI.selectNodeIterator(getDocument(), path); + Vector v = new Vector(); + //Iterate over the resulting Node set, return as a String array + while ((n = nl.nextNode())!= null) { + String value = getAttrValue(n, attrName); + if (value != null) { + v.add(value); + } + } + + if (v.size() > 0) { + String [] list = new String[v.size()]; + for (int i = 0; i < v.size(); i++) { + list[i] = (String) v.elementAt(i); + } + return list; + } + } + catch (TransformerException e) { + System.out.println("getPathAttrValues:" + path + ":" + attrName + ":" + e.toString()); + e.printStackTrace(); + } + return null; + } + + /** + * Convenience method to select a list of nodes matching a given xpath, + * relative to the root. + * + * @param XPath to search for + * @exception javax.transform.TransformerException + */ + + public NodeList selectNodeList(String xpath) throws TransformerException { + return XPathAPI.selectNodeList(_doc.getDocumentElement(),xpath); + } + + /** + * Convenience method to select a node matching a given xpath, relative to the root. + * Returns null if there are none. + * + * @param XPath to search for + * @exception javax.transform.TransformerException + */ + public Node selectSingleNode(String xpath) throws TransformerException { + return XPathAPI.selectSingleNode(_doc.getDocumentElement(),xpath); + } + + + /** + * Get property of xPath node. + */ + public String getProperty(String xPath) { + return getPathValue(xPath); + } + + + /** + * Set text value to the element + */ + public void setTextElementValue(Node node, String value) throws java.io.IOException { + setText(node,value); + } + + /** + * Set an element's text value, static version + */ + public static void setText(Node node, String value) throws java.io.IOException { + for (Node child = node.getFirstChild(); + child != null; + child = child.getNextSibling()) { + + if (child.getNodeType() == Node.TEXT_NODE) { + child.setNodeValue(value); + return; + } + } + // throw new java.io.IOException("No text element under the node"); + Text tnode = node.getOwnerDocument().createTextNode(value); + node.appendChild(tnode); + } + + + void outputIndent(int level) { + for (int i = 0; i < level; i++) { + print(" "); + } + } + + void print(String text) { + try { + if (_out == null) { + System.out.print(text); + } + else { + //_out.write(text.getBytes()); + _out.write(text); + } + } + catch (java.io.IOException e) { + System.out.println("OctoXML.print:" + e.toString()); + } + } + + void println(String line) { + try { + if (_out == null) { + System.out.println(line); + } + else { + //_out.write(line.getBytes()); + _out.write(line); + _out.write('\n'); + } + } + catch (java.io.IOException e) { + System.out.println("OctoXML.println:" + e.toString()); + } + } + + void outputOpenTag(int level, String tag, String value) { + //System.out.println("output tag:" + tag, 9); + outputIndent(level); + if (value != null) { + println("<" + tag + ">" + value); + } + else { + println("<" + tag + ">"); + } + } + + void outputOpenTag(int level, String tag, String attrList, String value) { + //System.out.println("output tag:" + tag, 9); + outputIndent(level); + if (value != null) { + println("<" + tag + attrList + ">" + value); + } + else { + println("<" + tag + attrList + ">"); + } + } + + void outputCloseTag(int level, String tag) { + outputIndent(level); + println(""); + } + + void printTree(Node node, int level) { + String text = getTextElementValue(node); + text = cleanup(text); + String name = node.getNodeName(); + String attrList = getAttrNameValues(node); + //System.out.println("printTree:" + name + ":" + text, 9); + if (attrList != null) { + outputOpenTag(level, name, attrList, text); + } + else { + outputOpenTag(level, name, text); + } + + + for (Node child = node.getFirstChild(); child != null; child = child.getNextSibling()) { + if (child.getNodeType() == Node.ELEMENT_NODE) { + printTree(child, level + 1); + } + } + outputCloseTag(level, name); + } + + public void printTree() { + Node node = getRootNode(); + printTree(node, 0); + } + + /** + * Output XML to OutputStream. + * @param out output stream to hold xml data + */ + public void printTree(OutputStream out) { + OutputStreamWriter outwriter = new OutputStreamWriter(out); + printTree(outwriter); + } + + /** + * Output XML to OutputStream. + * @param node current node + * @param out output stream to hold node XML. + */ + public void printTree(Node node, OutputStream out) { + OutputStreamWriter outwriter = new OutputStreamWriter(out); + printTree(node, outwriter); + } + + /** + * Output XML to Writer. + * @param out output stream to hold text xml document. + */ + public void printTree(Writer out) { + _out = out; + try { + printTree(); + _out.flush(); + } + catch (Exception e) { + System.out.println("printTree:" + e.toString()); + } + _out = null; + } + + /** + * Output XML to Writer. + * @param node current node + * @param out output stream to hold text xml + */ + public void printTree(Node node, Writer out) { + _out = out; + try { + printTree(node, 0); + _out.flush(); + } + catch (Exception e) { + System.out.println("printTree:" + e.toString()); + } + _out = null; + } + + /** + * Output XML + XSL to OutputStream + * + * @param Output stream to write xml to + * @param Name of XSL file to write it to + * @exception java.io.IOException + */ + public void printTree(OutputStream out, String xslFile) throws java.io.IOException { + _out = new OutputStreamWriter(out); + printTreeXSL(xslFile); + _out = null; + } + + + /** + * Output XML + XSL to Writer + * @param out output stream which holds text xml document + * @param xslFile xsl filename for style sheet transform. + */ + public void printTree(Writer out, String xslFile) throws java.io.IOException { + _out = out; + printTreeXSL(xslFile); + _out = null; + } + + void printTreeXSL(String xslFile) throws IOException { + //System.out.println("Generate HTML from XML + " + xslFile, 9); + try { + _out.write(TransformUtil.transform(xslFile,_doc)); + } + catch (Exception e) { + //e.printStackTrace(); + String errorMsg = "

Fail to generate HTML from XML:" + e.toString() + "

"; + _out.write(errorMsg); + } + + } + + /** + * Output XML to a String + */ + public String xml() { + StringWriter sw = new StringWriter(); + printTree(sw); + return sw.toString(); + } + + + /** + * Prints out the tree as a single long line, no indentation or beautification + */ + public void printNoIndent(Writer out) { + _out = out; + printNodeNoIndent(getRootNode()); + } + + + void printNodeNoIndent(Node node) { + String text = getTextElementValue(node); + text = cleanup(text); + String name = node.getNodeName(); + String attrList = getAttrNameValues(node); + //System.out.println("printNoIndent:" + name + ":" + text, 9); + if (attrList != null) { + openTagNoIndent(name, attrList, text); + } + else { + openTagNoIndent(name, text); + } + + + for (Node child = node.getFirstChild(); child != null; child = child.getNextSibling()) { + if (child.getNodeType() == Node.ELEMENT_NODE) { + printNodeNoIndent(child); + } + } + closeTagNoIndent(name); + } + + + void openTagNoIndent(String tag, String value) { + //System.out.println("output tag:" + tag, 9); + if (value != null) { + print("<" + tag + ">" + value); + } + else { + print("<" + tag + ">"); + } + } + + void openTagNoIndent( String tag, String attrList, String value) { + //System.out.println("output tag:" + tag, 9); + if (value != null) { + print("<" + tag + attrList + ">" + value); + } + else { + print("<" + tag + attrList + ">"); + } + } + + void closeTagNoIndent(String tag) { + print(""); + } + + /** + * Escape string data to follow XML standard. + * @param data input string for xml + */ + public static String escapeData(String data) { + if (data == null) { + return data; + } + StringBuffer newData = new StringBuffer(); + for (int i = 0; i < data.length(); i++) { + char ch = data.charAt(i); + if (ch == '<') { + newData.append("<"); + } + else if (ch == '&') { + newData.append("&"); + } + else if (ch == '>') { + newData.append(">"); + } + else if (ch == '"') { + newData.append("""); + } + else if (ch == '\'') { + newData.append("'"); + } + else { + newData.append(ch); + } + } + return newData.toString(); + } + + /** + * Print out the xml document + */ + public void print(Document doc) { + printNode( doc, "" ); + } + + /** + * Print out the xml document under specified node + * @param n input node + */ + public void printNode(Node n, String indent) { + switch(n.getNodeType()) { + + case Node.DOCUMENT_NODE: + NodeList children = n.getChildNodes(); + if( children != null ){ + for( int i = 0; i < children.getLength(); i++ ){ + printNode(children.item(i), indent + " " ); + } + } + break; + case Node.ELEMENT_NODE: + log( indent + getElementStart(n) ); + getElementChildren(n,indent) ; + log( indent + getElementEnd(n) ); + break; + case Node.TEXT_NODE: + String text = getTextNode(n); + if( text.length() > 0 ){ + log( indent + " " + text ); + } + break; + case Node.PROCESSING_INSTRUCTION_NODE: + log( indent + getProcessingInstructionNode(n) ); + break; + case Node.COMMENT_NODE: + log( indent + getCommentNode(n) ); + break; + } + } + + /** + * Logging message + */ + public void log(String msg){ + System.out.println("DocumentManager: " + msg); + } + + /** + * Get starting node in String + * @param e input node + */ + protected String getElementStart(Node e){ + StringBuffer buf = new StringBuffer(); + buf.append( "<" + e.getNodeName() ); + buf.append( getElementAttributes(e) ); + buf.append( ">" ); + return buf.toString(); + } + + /** + * Print out children of the node + */ + protected void getElementChildren(Node e, String indent){ + NodeList children = e.getChildNodes(); + if( children != null ){ + for( int i = 0; i < children.getLength(); i++ ) + printNode(children.item(i), indent + " "); + } + } + + protected String getElementEnd(Node e){ + return ""; + } + + protected String getElementAttributes(Node e){ + StringBuffer buf = new StringBuffer(); + NamedNodeMap attributes = e.getAttributes(); + for( int i = 0; i < attributes.getLength(); i++ ){ + Node n = attributes.item(i); + buf.append( " " ); + buf.append( n.getNodeName() ); + buf.append( "=" ); + buf.append( n.getNodeValue() ); + } + return buf.toString(); + } + + protected String getTextNode(Node t){ + return t.getNodeValue().trim(); + } + + protected String getProcessingInstructionNode(Node pi){ + return ""; + } + + protected String getCommentNode(Node c){ + return "comment: " + c.getNodeValue(); + } + + /** + * Constructs a Document object from input string + */ + public static Document stringToDOM(String s) { + + if ((s == null) || (s.length() ==0)) { + return null; + } + + Document doc = null; + try { + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + DocumentBuilder builder = factory.newDocumentBuilder(); + InputSource is = new InputSource(new StringReader(s)); + doc = builder.parse( is ); + } + catch( Exception e){ + e.printStackTrace(); + } + return doc; + } + + + /** + * Makes a string XML-safe by substituting escape sequences + */ + + public static String cleanup(String input) + { + if (input==null) { + return null; + } + + String output = input.replaceAll("#","#"); + output = output.replaceAll("&","&"); + output = output.replaceAll("&#35;","#"); + output = output.replaceAll("<","<"); + output = output.replaceAll(">",">"); + return output; + } + + + void test() { + Node rootNode = getRootNode(); + Node node = createNode("html"); + rootNode.appendChild(node); + printTree(); + } + + + /** + * create a file in runtime. + */ + void testCreate() { + Node htmlNode = getRootNode(); + Node node = getRootNode(); + Node bodyNode = createNode("body"); + Node h1Node = createNode("h1", "title is octopus!"); + Node h2Node = createNode("h2", "company overview!"); + htmlNode.appendChild(bodyNode); + bodyNode.appendChild(h1Node); + bodyNode.appendChild(h2Node); + printTree(); + } + + /**** + note: removed for javadoc + + + public static void main(String[] args) throws Exception { + try { + SimpleXML xml = new SimpleXML(new File(args[0])); + Node node = xml.getPathNode(args[1]); + + System.out.println("node = " + node); + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + xml.printTree(node, out); + System.out.println("size = " + out.size()); + + // System.out.println("out = " + out.toString()); + SimpleXML xml2 = new SimpleXML(out.toString(), true); + xml2.printTree(); + } + catch (Exception e) { + System.out.println("error:" + e.toString()); + } + + } + ***/ + +} diff --git a/sourceMetadata/jcb-package/src/jcb/util/SqlUtil.class b/sourceMetadata/jcb-package/src/jcb/util/SqlUtil.class new file mode 100644 index 0000000000000000000000000000000000000000..5e44e7da11daee0098da816f24f3280a9c6a24f0 GIT binary patch literal 5243 zcmaKwTXY*&6^8%Oj5T9fNhIa&G{m{vPGaYNvy&jnN~}bd97(ouo79nQ#gQvZjwI*O zgi@MPS|}-{7w82N3T>eT$OW9VX-e9Z1_Crm+mr|1cwzCv3v01fDRi;-j7B<=Okc+H zf3wd%=j^lho{?{S_QqQPR^ekC+&Es1FXGE89=`rYq+T4l7`n+yrJTVZLPp+nDw~U?a^11ySX_d$FsRcViS&fRZ4xH$ba%V^BD({9 z(cVs9M8b5#(^xK%Y;KQb59DI~$v8Qi8TNJi!VzCvU-^isC7{n84!e6LOe>`x{|Mx z`MmxPcR)h97k?z`4|*#%*cR&Y1jtWWkhTXxZZa<04MoVegO77|=^Awv^6d2S1anHC z1wz3c-R`i*Zv?VzWd7-d;RtpGXd`7y2zGV&!hUbXfo-$6l}SvniTNYvfYS+Q!0eXs7lY=jV)vVGDMBPeBgO6&0l zcU0_2ckT*>-QIw&&)XG_gu;5kNU*jhQief7j>B??p$^Z<32mKgF|0zW&TtyJ`~UJ(<^qo zh2PN1icgJ3Cqd00rX5%DwjJ%*VaGeTX2-jDn>vm@K<{V8Ez&`aWqDWB^?!@^XqBU} zZ1!+EGpORa9lyix?YMzI&_U{>iyKt&M?3z6_bEBc7vdR9BnR2&qVnL?H`FDvb)j8N zb>zqh)D}B#;uc?S+wlResrb;2k8pv_bkhBl>n%bnHU+EM1{9<4tA$cm3&mY6l=D=h7Mt|9R+CYYRE%c%%6h>%h6nna^^?!% zT1onZ`iJ8KIWyq;tFw^06i})=s%M$bQo<53_lqz$rdOhiVg5E$nCg_c%`vtv;^njo@lO7aw3+cF^TS@O1 zv`TtN&|66#5cD?E2|;gxO1VQXHo7J$JLb|~dgGv~@gk&ibR%Jeu2vn|P>mGQbkC;S zpisgAbI!wZ8FFv!MJVH_x(aJx*>zZ5>e*#y3l3al44i-q57V!bM`#s~k+V@8%sbnf zcUC*0vnu(Fa;D7JN%Hjs`Faww@U*_LOx{t$<_g=)Lj>hYl zvfMSx&r_cWKIhXO&|DR3vv=;&Eqj7%eJ>(~hK;yJYZ${J+8c*IKr7I9DFqrY!8MMlS1~Pc9@8&l2CZqPYt}es(`2>d zm@|&MD$e448hsO!a0^Rt8;8lGLc2Rc>o{s=Llwn}IFx5EV=npp!UaC*{9Seaq@3!9 zbnvcu0V5P(ztfNeGk$gzjXCXwuAvRNemX3`>( z|1xP6iJgfml7BJTVvuUrJnj=l!kB12BRyeEvOp)CFeX{36HXYDEHWH%!kB2WZo~;= zk|j(yVN9^p7{v)=qI!K4CyYrNbixT^l13(c@+Mej_~C>x(Qm~1 zd)R2$aKe~2n{-EVy-X>G5v+U zmHq+xR{;H{bD>>Y2*0!*JEeB)l6n!4hS4D%Lr^-2kaQZI(gp06-bGmYGa}O85tTkg zmt_*VE%VT0S%qGU7kez-*lRg}doA~)&+<6-SxzBlIfs7BI~cIs!Jy@Dh+96ve%Xd0 zc`gpf%}B^@49j8MC&!VL4`W1r6e;;Rq~+HzDqq1t`6e>*Uy+sniJW4^m@*58ltvs@ gT5&`P;;6C@$CM0?D<|-P@(doNK7K#N!-8Y~13GNIfB*mh literal 0 HcmV?d00001 diff --git a/sourceMetadata/jcb-package/src/jcb/util/SqlUtil.java b/sourceMetadata/jcb-package/src/jcb/util/SqlUtil.java new file mode 100644 index 0000000..896c789 --- /dev/null +++ b/sourceMetadata/jcb-package/src/jcb/util/SqlUtil.java @@ -0,0 +1,212 @@ +package jcb.util; + + +import java.util.*; + + +/** + * SqlUtility is a helper class for SQL Adapter. + */ +public class SqlUtil { + + private static final String DATABASE_USER = "user"; + private static final String DATABASE_PASSWORD = "password"; + + private static final Hashtable JAVA_SQL_TYPES = new Hashtable(); + private static final Hashtable REVERSED_JAVA_SQL_TYPES = new Hashtable(); + + public static final String JAVA_SQL_TYPE_ARRAY = "ARRAY"; + public static final String JAVA_SQL_TYPE_BIGINT = "BIGINT"; + public static final String JAVA_SQL_TYPE_BINARY = "BINARY"; + public static final String JAVA_SQL_TYPE_BIT = "BIT"; + public static final String JAVA_SQL_TYPE_BLOB = "BLOB"; + public static final String JAVA_SQL_TYPE_BOOLEAN = "BOOLEAN"; + public static final String JAVA_SQL_TYPE_CHAR = "CHAR"; + public static final String JAVA_SQL_TYPE_CLOB = "CLOB"; + public static final String JAVA_SQL_TYPE_DATALINK = "DATALINK"; + public static final String JAVA_SQL_TYPE_DATE = "DATE"; + public static final String JAVA_SQL_TYPE_DECIMAL = "DECIMAL"; + public static final String JAVA_SQL_TYPE_DISTINCT = "DISTINCT"; + public static final String JAVA_SQL_TYPE_DOUBLE = "DOUBLE"; + public static final String JAVA_SQL_TYPE_FLOAT = "FLOAT"; + public static final String JAVA_SQL_TYPE_INTEGER = "INTEGER"; + public static final String JAVA_SQL_TYPE_JAVA_OBJECT = "JAVA_OBJECT"; + public static final String JAVA_SQL_TYPE_LONGVARBINARY = "LONGVARBINARY"; + public static final String JAVA_SQL_TYPE_LONGVARCHAR = "LONGVARCHAR"; + public static final String JAVA_SQL_TYPE_NULL = "NULL"; + public static final String JAVA_SQL_TYPE_NUMERIC = "NUMERIC"; + public static final String JAVA_SQL_TYPE_OTHER = "OTHER"; + public static final String JAVA_SQL_TYPE_REAL = "REAL"; + public static final String JAVA_SQL_TYPE_REF = "REF"; + public static final String JAVA_SQL_TYPE_SMALLINT = "SMALLINT"; + public static final String JAVA_SQL_TYPE_STRUCT = "STRUCT"; + public static final String JAVA_SQL_TYPE_TIME = "TIME"; + public static final String JAVA_SQL_TYPE_TIMESTAMP = "TIMESTAMP"; + public static final String JAVA_SQL_TYPE_TINYINT = "TINYINT"; + public static final String JAVA_SQL_TYPE_VARBINARY = "VARBINARY"; + public static final String JAVA_SQL_TYPE_VARCHAR = "VARCHAR"; + + public static final String JAVA_SQL_TYPE_STRING = "STRING"; // added for convenience + public static final String JAVA_SQL_TYPE_INT = "INT"; // added for convenience + + // + // Oracle CURSOR type for handling ResultSets + // + public static final String ORACLE_CURSOR_TYPE = "ORACLE.TYPES.CURSOR"; + + static { + JAVA_SQL_TYPES.put(new Integer(java.sql.Types.ARRAY), JAVA_SQL_TYPE_ARRAY); + JAVA_SQL_TYPES.put(new Integer(java.sql.Types.BIGINT), JAVA_SQL_TYPE_BIGINT); + JAVA_SQL_TYPES.put(new Integer(java.sql.Types.BINARY), JAVA_SQL_TYPE_BINARY); + JAVA_SQL_TYPES.put(new Integer(java.sql.Types.BIT), JAVA_SQL_TYPE_BIT); + JAVA_SQL_TYPES.put(new Integer(java.sql.Types.BLOB), JAVA_SQL_TYPE_BLOB); + JAVA_SQL_TYPES.put(new Integer(java.sql.Types.BOOLEAN), JAVA_SQL_TYPE_BOOLEAN); + JAVA_SQL_TYPES.put(new Integer(java.sql.Types.CHAR), JAVA_SQL_TYPE_CHAR); + JAVA_SQL_TYPES.put(new Integer(java.sql.Types.CLOB), JAVA_SQL_TYPE_CLOB); + JAVA_SQL_TYPES.put(new Integer(java.sql.Types.DATALINK), JAVA_SQL_TYPE_DATALINK); + JAVA_SQL_TYPES.put(new Integer(java.sql.Types.DATE), JAVA_SQL_TYPE_DATE); + JAVA_SQL_TYPES.put(new Integer(java.sql.Types.DECIMAL), JAVA_SQL_TYPE_DECIMAL); + JAVA_SQL_TYPES.put(new Integer(java.sql.Types.DISTINCT), JAVA_SQL_TYPE_DISTINCT); + JAVA_SQL_TYPES.put(new Integer(java.sql.Types.DOUBLE), JAVA_SQL_TYPE_DOUBLE); + JAVA_SQL_TYPES.put(new Integer(java.sql.Types.FLOAT), JAVA_SQL_TYPE_FLOAT); + JAVA_SQL_TYPES.put(new Integer(java.sql.Types.INTEGER), JAVA_SQL_TYPE_INTEGER); + JAVA_SQL_TYPES.put(new Integer(java.sql.Types.JAVA_OBJECT), JAVA_SQL_TYPE_JAVA_OBJECT); + JAVA_SQL_TYPES.put(new Integer(java.sql.Types.LONGVARBINARY), JAVA_SQL_TYPE_LONGVARBINARY); + JAVA_SQL_TYPES.put(new Integer(java.sql.Types.LONGVARCHAR), JAVA_SQL_TYPE_LONGVARCHAR); + JAVA_SQL_TYPES.put(new Integer(java.sql.Types.NULL), JAVA_SQL_TYPE_NULL); + JAVA_SQL_TYPES.put(new Integer(java.sql.Types.NUMERIC), JAVA_SQL_TYPE_NUMERIC); + JAVA_SQL_TYPES.put(new Integer(java.sql.Types.OTHER), JAVA_SQL_TYPE_OTHER); + JAVA_SQL_TYPES.put(new Integer(java.sql.Types.REAL), JAVA_SQL_TYPE_REAL); + JAVA_SQL_TYPES.put(new Integer(java.sql.Types.REF), JAVA_SQL_TYPE_REF); + JAVA_SQL_TYPES.put(new Integer(java.sql.Types.SMALLINT), JAVA_SQL_TYPE_SMALLINT); + JAVA_SQL_TYPES.put(new Integer(java.sql.Types.STRUCT), JAVA_SQL_TYPE_STRUCT); + JAVA_SQL_TYPES.put(new Integer(java.sql.Types.TIME), JAVA_SQL_TYPE_TIME); + JAVA_SQL_TYPES.put(new Integer(java.sql.Types.TIMESTAMP), JAVA_SQL_TYPE_TIMESTAMP); + JAVA_SQL_TYPES.put(new Integer(java.sql.Types.TINYINT), JAVA_SQL_TYPE_TINYINT); + JAVA_SQL_TYPES.put(new Integer(java.sql.Types.VARBINARY), JAVA_SQL_TYPE_VARBINARY); + JAVA_SQL_TYPES.put(new Integer(java.sql.Types.VARCHAR), JAVA_SQL_TYPE_VARCHAR); + + JAVA_SQL_TYPES.put(new Integer(oracle.jdbc.driver.OracleTypes.CURSOR), ORACLE_CURSOR_TYPE); + + + REVERSED_JAVA_SQL_TYPES.put(JAVA_SQL_TYPE_ARRAY, new Integer(java.sql.Types.ARRAY)); + REVERSED_JAVA_SQL_TYPES.put(JAVA_SQL_TYPE_BIGINT, new Integer(java.sql.Types.BIGINT)); + REVERSED_JAVA_SQL_TYPES.put(JAVA_SQL_TYPE_BINARY, new Integer(java.sql.Types.BINARY)); + REVERSED_JAVA_SQL_TYPES.put(JAVA_SQL_TYPE_BIT, new Integer(java.sql.Types.BIT)); + REVERSED_JAVA_SQL_TYPES.put(JAVA_SQL_TYPE_BLOB, new Integer(java.sql.Types.BLOB)); + REVERSED_JAVA_SQL_TYPES.put(JAVA_SQL_TYPE_BOOLEAN, new Integer(java.sql.Types.BOOLEAN)); + REVERSED_JAVA_SQL_TYPES.put(JAVA_SQL_TYPE_CHAR, new Integer(java.sql.Types.CHAR)); + REVERSED_JAVA_SQL_TYPES.put(JAVA_SQL_TYPE_CLOB, new Integer(java.sql.Types.CLOB)); + REVERSED_JAVA_SQL_TYPES.put(JAVA_SQL_TYPE_DATALINK, new Integer(java.sql.Types.DATALINK)); + REVERSED_JAVA_SQL_TYPES.put(JAVA_SQL_TYPE_DATE, new Integer(java.sql.Types.DATE)); + REVERSED_JAVA_SQL_TYPES.put(JAVA_SQL_TYPE_DECIMAL, new Integer(java.sql.Types.DECIMAL)); + REVERSED_JAVA_SQL_TYPES.put(JAVA_SQL_TYPE_DISTINCT, new Integer(java.sql.Types.DISTINCT)); + REVERSED_JAVA_SQL_TYPES.put(JAVA_SQL_TYPE_DOUBLE, new Integer(java.sql.Types.DOUBLE)); + REVERSED_JAVA_SQL_TYPES.put(JAVA_SQL_TYPE_FLOAT, new Integer(java.sql.Types.FLOAT)); + REVERSED_JAVA_SQL_TYPES.put(JAVA_SQL_TYPE_INTEGER, new Integer(java.sql.Types.INTEGER)); + REVERSED_JAVA_SQL_TYPES.put(JAVA_SQL_TYPE_JAVA_OBJECT, new Integer(java.sql.Types.JAVA_OBJECT)); + REVERSED_JAVA_SQL_TYPES.put(JAVA_SQL_TYPE_LONGVARBINARY, new Integer(java.sql.Types.LONGVARBINARY)); + REVERSED_JAVA_SQL_TYPES.put(JAVA_SQL_TYPE_LONGVARCHAR, new Integer(java.sql.Types.LONGVARCHAR)); + REVERSED_JAVA_SQL_TYPES.put(JAVA_SQL_TYPE_NULL, new Integer(java.sql.Types.NULL)); + REVERSED_JAVA_SQL_TYPES.put(JAVA_SQL_TYPE_NUMERIC, new Integer(java.sql.Types.NUMERIC)); + REVERSED_JAVA_SQL_TYPES.put(JAVA_SQL_TYPE_OTHER, new Integer(java.sql.Types.OTHER)); + REVERSED_JAVA_SQL_TYPES.put(JAVA_SQL_TYPE_REAL, new Integer(java.sql.Types.REAL)); + REVERSED_JAVA_SQL_TYPES.put(JAVA_SQL_TYPE_REF, new Integer(java.sql.Types.REF)); + REVERSED_JAVA_SQL_TYPES.put(JAVA_SQL_TYPE_SMALLINT, new Integer(java.sql.Types.SMALLINT)); + REVERSED_JAVA_SQL_TYPES.put(JAVA_SQL_TYPE_STRUCT, new Integer(java.sql.Types.STRUCT)); + REVERSED_JAVA_SQL_TYPES.put(JAVA_SQL_TYPE_TIME, new Integer(java.sql.Types.TIME)); + REVERSED_JAVA_SQL_TYPES.put(JAVA_SQL_TYPE_TIMESTAMP, new Integer(java.sql.Types.TIMESTAMP)); + REVERSED_JAVA_SQL_TYPES.put(JAVA_SQL_TYPE_TINYINT, new Integer(java.sql.Types.TINYINT)); + REVERSED_JAVA_SQL_TYPES.put(JAVA_SQL_TYPE_VARBINARY, new Integer(java.sql.Types.VARBINARY)); + REVERSED_JAVA_SQL_TYPES.put(JAVA_SQL_TYPE_VARCHAR, new Integer(java.sql.Types.VARCHAR)); + + REVERSED_JAVA_SQL_TYPES.put(JAVA_SQL_TYPE_STRING, new Integer(java.sql.Types.VARCHAR)); // added for convenience + REVERSED_JAVA_SQL_TYPES.put(JAVA_SQL_TYPE_INT, new Integer(java.sql.Types.INTEGER)); // added for convenience + + REVERSED_JAVA_SQL_TYPES.put(ORACLE_CURSOR_TYPE, new Integer(oracle.jdbc.driver.OracleTypes.CURSOR)); + + } + + public static String getColumnType(int columnType) { + String type = (String) JAVA_SQL_TYPES.get(new Integer(columnType)); + if (type == null) { + // it means it is a non-existent java.sql.Types.XXX type. + return "VARCHAR"; + } + else { + return type; + } + } + + public static boolean isJavaSqlType(int columnType) { + String type = (String) JAVA_SQL_TYPES.get(new Integer(columnType)); + if (type == null) { + // it means it is a non-existing type + return false; + } + else { + return true; + } + } + + + public static int getColumnType(String columnType) { + + if ((columnType == null) || (columnType.length() == 0)) { + return java.sql.Types.VARCHAR; + } + + Integer type = (Integer) REVERSED_JAVA_SQL_TYPES.get(columnType.toUpperCase()); + if (type == null) { + // it is a non-existent type + return java.sql.Types.VARCHAR; + } + + return type.intValue(); + } + + + + /** + * get properties with user/password + * + * @param user the db username + * @param password the db password + * + */ + public static java.util.Properties getDatabaseProperties(String user, String password) { + + java.util.Properties props = new java.util.Properties(); + + if (user == null) { + props.put(DATABASE_USER, ""); + } + else { + props.put(DATABASE_USER, user); + } + + if (password == null) { + props.put(DATABASE_PASSWORD, ""); + } + else { + props.put(DATABASE_PASSWORD, password); + } + + return props; + + } + + /** + * get a java.sql.Driver for a given driver name. + * + * @param driver the name of JDBC driver + * + */ + public static java.sql.Driver getJavaSqlDriver(String driver) throws Exception { + java.sql.Driver sqlDriver = null; + sqlDriver = (java.sql.Driver) Class.forName(driver).newInstance(); + System.out.println("getJavaSqlDriver() is OK. sqlDriver=" + sqlDriver); + return sqlDriver; + } +} + diff --git a/sourceMetadata/jcb-package/src/jcb/util/TransformUtil.class b/sourceMetadata/jcb-package/src/jcb/util/TransformUtil.class new file mode 100644 index 0000000000000000000000000000000000000000..42ebb9ff575e66a35a355714e9c90e2c07d47136 GIT binary patch literal 3194 zcmb7HX?GJ<7=DH%opcx|gss6=!XDC=u!um4fGpKQ6PB{IxJ}b(J0;1KnF%effGa8r zs3;&HDBw2%k7>0>Jbv+mKg#2CXVSERX!Ycrd*|N!F3-E(n?L{hzx2w=C2eF|jkm(i}E8V3{{#36BVSPVzR&>^F<8b|R$5HBit2`|fdMZqi~ zP!n^Pf*Pd77s+eTEkh5YN5OotIbW=M6+DSP8HR!g`ehtbum~9i8p{E`#G8WXEg7d|oR$#m zHq-g6o^vG3Z8NRj_~6=fyxYvicNF)VB~)!Pa)z^6f-kz_kOcpBvs;%?(`MxKR6g6K zTL-kR40oy>OUv0krj?b@9&PK_PH02%p=>5z+K=0grEA%EyF0a;c`L0qS5~{i<&S5y zT(2NEa=k<{t0bw#GPB;cgiW5VGTQ$kbYmrU0lrLNXGK68{u6ISR)1DAa`bxi=;M|O zH!GfdS`6XZ(19`69(0V%N`X$rGhj@ZnrBqJjdxVMi}xhVc99!q(P@V*!_h4X3oAv# zjq{$Qr%1?qU&8WAg!aU+?bq#m#u4Nn$T+LwS$wGCBWzajG0v&@M4(z%NlM8E-P&&E zdW_z@r8$O~+c}ih2gHYrPgR`91qt;^EEbtSA8FCjj%l5Y=$2(#GA^q444+Gw=UO`< zNw(#UOt&!D7l}kve1S_Uz7(*&!et53Nnn+bNT@AC;NtX@GYeg%baCsR5`&5>!tO`B zzhBn~M!1StC->}lAg&6xZj+#nsS;@*9lU!hTA2=MQM@8&IGU)Rz%6ZQUVA-5@xv0 zaE;m1)vu@7vzCdiN1IHEO}C0^BVlSzA8gIpj+RTaoMKV0Bq!%&)0s}z2_hwIsodL& z?QBxX6geka)}K;rsLi70XBFECbIU7ScXz=gMoMV@S40&%u~)^e{6J48Z};&oaLlom zI=kqgvKA;Ikj|Jk{Wl>J?I&$VXT$fIdB$Uo*UN~1FI%=lacuXZal4@_-+cC(7OD5WZ!MwxM?x*%7L3#i@E z(#IHaktq`*;uW(CYvy>IL}9vn^C}?h>=aR*O7&ycDH{v5|HDP=V|U~Ist*}-r9av# zm}|#XO?0U^sv@E7*zUdDiG{q@6MW1tj-mnZOXfH42##C0s^`q>0)f~tr28)6R*qHf zW{6B|I3B5V6h5wj-$GN8Bk-k~Vg>jU{!s)vhEbIWj6&{c7)CHrHHzwva9|ipLJs@G zRbjb+so_8Ysu-pv#W?*ghEfkOBQ&#s5a&_MqLkU8IR(sZDqtR`0&02Il<;#M{sYxw zO8D<$tIPL9MZUU6`072rdchY=QNn`8do;s`op_#aE-|0tTT9F%d}~P%##^Z480Kyr zy;YCtJekKA*h2mqu^8+4YD!=kX`|$Oj*?<%<;gxiwz61-0j$9wpI2}2>=f4HG-Gg< z9JlHB@9Fg)$oUh`Mz8}vqXoZ`yBgcM@?x@qn*BsjJBmmL(N@^6* zjs}0-Fjge|VSfR!AJGtd077a^-DR-d&6Q2}$m+uaK1`d6Fc-ObljH7jI^Cu-9i9)8 zB9A3FffX2Xm9`X>E+FL;DwSgm{t?8-?e)^~42gx;J#YO^UkQYU)FvgRRP15k25KH) zRcJLcgzRfZLHm7c=z%u((=R@gcQH)>CSd_jH59P!3Z@FKr^(egzFhC68Tn)WH6z%- z<$Wry!b<)>SX;DjGpz#7arZn_T)=ExL@i$#i*bo`S4nx9v{zVw*H}&0u?shuEVt0X Pl<319N@*qk6zuvNhO0dN literal 0 HcmV?d00001 diff --git a/sourceMetadata/jcb-package/src/jcb/util/TransformUtil.java b/sourceMetadata/jcb-package/src/jcb/util/TransformUtil.java new file mode 100644 index 0000000..d2a2649 --- /dev/null +++ b/sourceMetadata/jcb-package/src/jcb/util/TransformUtil.java @@ -0,0 +1,169 @@ +package jcb.util; + + +import java.io.*; + +import javax.xml.parsers.*; +import org.xml.sax.*; +import org.w3c.dom.*; + +import javax.xml.transform.*; +import javax.xml.transform.dom.*; +import javax.xml.transform.stream.*; + +/** + * This class provides helper methods to invoke XSLT + * transformations, and manipulate their output. + */ +public class TransformUtil { + + // Global value so it can be ref'd by the tree-adapter + static Document document; + + static String transform(StreamSource stylesource,Document doc) + { + String transformResult = ""; + try { + // Use a Transformer for output + TransformerFactory tFactory = TransformerFactory.newInstance(); + Transformer transformer = tFactory.newTransformer(stylesource); + StringWriter out = new StringWriter(); + + DOMSource source = new DOMSource(doc); + StreamResult result = new StreamResult(out); + + transformer.transform(source, result); + + out.flush(); + transformResult = out.toString(); + + out.close(); + } + catch (TransformerConfigurationException tce) { + // Error generated by the parser + System.out.println ("\n** Transformer Factory error"); + System.out.println(" " + tce.getMessage() ); + + // Use the contained exception, if any + Throwable x = tce; + + if (tce.getException() != null) + x = tce.getException(); + // x.printStackTrace(); + + } + catch (TransformerException te) { + // Error generated by the parser + System.out.println ("\n** Transformation error"); + System.out.println(" " + te.getMessage() ); + + // Use the contained exception, if any + Throwable x = te; + + if (te.getException() != null) + x = te.getException(); + //x.printStackTrace(); + + } + catch (IOException ioe) { + // I/O error + ioe.printStackTrace(); + } + + return transformResult; + + + } + + /** + Carry out a transformation and return the result in string form. + @param xslstr XSL string + @param doc Document to be transformed + */ + public static String transformFromString(String xslstr,Document doc) + { + StringReader xslread = new StringReader(xslstr); + StreamSource stylesource = new StreamSource(xslread); + return transform(stylesource,doc); + } + + /** + Carry out a transformation and return the result in string form. + @param xslstr Name of XSL file + @param doc Document to be transformed + */ + public static String transform(String xslFilename, Document doc) + { + File stylesheet = new File(xslFilename); + StreamSource stylesource = new StreamSource(stylesheet); + return transform(stylesource,doc); + } + + /** + Carry out a transformation and return the result in string form. + @param xslFilename Name of XSL file + @param xmlFilename Name of XML file to be transformed + @validate Whether or not to validate the XML file first + */ + public static String transform(String xslFilename, String xmlFilename, boolean validate) { + + String transformResult = ""; + + try { + XMLValidator validator = new XMLValidator(xmlFilename, true, validate); + + document = validator.getDocument(); + transformResult = transform(xslFilename,document); + } catch (Throwable e) { + e.printStackTrace(); + } + return transformResult; + + } // main + + /** + Carry out a transformation and return the result in string form. + @param xslFilename Name of XSL file + @param xmlFilename Name of XML file to be transformed + */ + public static String transform(String xslFilename, String xmlFilename) { + return transform(xslFilename, xmlFilename, true); + } // main + + + + /** + When run from the command line, this method uses the stylesheet + passed in as the first argument to transform the xmlfile passed in + as the second argument. + */ + public static void main(String args[]) { + File xsl = null, xml = null, dtd = null; + + try { + if (args.length != 2) { + System.err.println ("Usage: java TransformUtil stylesheet xmlfile"); + System.exit (1); + } + + xsl = new File(args[0]); + xml = new File(args[1]); + + } + catch (Exception e) { + e.printStackTrace(System.err); + } + + if (!(xsl.exists())) { + System.err.println("stylesheet is not accessible"); + } + + if (!(xml.exists())) { + System.err.println("xmlfile is not accessible"); + } + + System.out.println(transform(args[0], args[1])); + } + + +} diff --git a/sourceMetadata/jcb-package/src/jcb/util/XMLValidator.class b/sourceMetadata/jcb-package/src/jcb/util/XMLValidator.class new file mode 100644 index 0000000000000000000000000000000000000000..c3a03a1178e8b78089fbf6a2ade1be0a830ea647 GIT binary patch literal 6397 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"); + } + + public void endDocument() + throws SAXException + { + nl(); + emit("END DOCUMENT"); + try { + nl(); + out.flush(); + } + catch (IOException e) { + throw new SAXException("I/O error", e); + } + } + + public void startElement(String namespaceURI, + String lName, // local name + String qName, // qualified name + Attributes attrs) + throws SAXException + { + indentLevel++; + nl(); + emit("ELEMENT: "); + String eName = lName; // element name + + if ("".equals(eName)) eName = qName; // namespaceAware = false + emit("<" + eName); + if (attrs != null) { + for (int i = 0; i < attrs.getLength(); i++) { + String aName = attrs.getLocalName(i); // Attr name + + if ("".equals(aName)) aName = attrs.getQName(i); + nl(); + emit(" ATTR: "); + emit(aName); + emit("\t\""); + emit(attrs.getValue(i)); + emit("\""); + } + } + if (attrs.getLength() > 0) nl(); + emit(">"); + } + + public void endElement(String namespaceURI, + String sName, // simple name + String qName // qualified name + ) + throws SAXException + { + nl(); + emit("END_ELM: "); + emit(""); + indentLevel--; + } + + public void characters(char buf[], int offset, int len) + throws SAXException + { + nl(); + emit("CHARS: "); + String s = new String(buf, offset, len); + + if (!s.trim().equals("")) emit(s); + } + + public void ignorableWhitespace(char buf[], int offset, int len) + throws SAXException + { + // Ignore it + } + + public void processingInstruction(String target, String data) + throws SAXException + { + nl(); + emit("PROCESS: "); + emit(""); + } + + //=========================================================== + // SAX ErrorHandler methods + //=========================================================== + + // treat validation errors as fatal + public void error(SAXParseException e) + throws SAXParseException + { + throw e; + } + + // dump warnings too + public void warning(SAXParseException err) + throws SAXParseException + { + System.out.println("** Warning" + + ", line " + err.getLineNumber() + + ", uri " + err.getSystemId()); + System.out.println(" " + err.getMessage()); + } + + //=========================================================== + // LexicalEventListener methods + //=========================================================== + + public void comment(char[] ch, int start, int length) + throws SAXException + { + } + + public void startCDATA() + throws SAXException + { + nl(); + emit("START CDATA SECTION"); + } + + public void endCDATA() + throws SAXException + { + nl(); + emit("END CDATA SECTION"); + } + + public void startEntity(java.lang.String name) + throws SAXException + { + nl(); + emit("START ENTITY: " + name); + } + + public void endEntity(java.lang.String name) + throws SAXException + { + nl(); + emit("END ENTITY: " + name); + } + + public void startDTD(String name, String publicId, String systemId) + throws SAXException + { + nl(); + emit("START DTD: " + name + + "\n publicId=" + publicId + + "\n systemId=" + systemId); + } + + public void endDTD() + throws SAXException + { + nl(); + emit("END DTD"); + } + + //=========================================================== + // Utility Methods ... + //=========================================================== + + // Wrap I/O exceptions in SAX exceptions, to + // suit handler signature requirements + private void emit(String s) + throws SAXException + { + try { + print(s); + out.flush(); + } + catch (IOException e) { + throw new SAXException("I/O error", e); + } + } + + // Start a new line + // and indent the next line appropriately + private void nl() + throws SAXException + { + String lineEnd = System.getProperty("line.separator"); + + try { + print(lineEnd); + for (int i = 0; i < indentLevel; i++) print(indentString); + } + catch (IOException e) { + throw new SAXException("I/O error", e); + } + } +} diff --git a/sourceMetadata/jcb-package/src/servlets/Base64.class b/sourceMetadata/jcb-package/src/servlets/Base64.class new file mode 100644 index 0000000000000000000000000000000000000000..051c76eee23688858d75227788751f261e10c93a GIT binary patch literal 2418 zcmaKtU1*zC7{~u_-_NG$`gH5tt?lNV)0w2{x-D(iuI;v_TlZl zF4e9VLvR;@7rKFhc%dt3MFhVf6E}v}UU(&52%;c@s33v}dSU&aH(6V(c=J2YIp=wv zbKd9wL}9l=r-MCe+^c-{*@y)YRNFP^ z3NWDCMmzw)ezn}A(5rAjt@Wvl{Wb<{9MoVNWPeaX_1ZUZm*$`*_`C`6ACp{FN z&|nNr=jhllk}rB=a~G$)*<>Zu@`_o1t2uNg5gs|8c_!0Y$P~|Zo-WPii)Z_oDd*kw zSic?iPcBSPUznTWDWRb-Z{qZ43)RyDr>Ey;v)*uCU9&Ecx#Y#WcB?~z*oJ#F$iEK^ zq6MuQHvfA)F_$moyxAZQ;jqG>1{NiOp&*Xn=-otfrF@}t!poMX={byJK|Fw68aAwE zOI$8_>g?k|oWRK-9>UQeMlc%07{-HW!&ZKA<(_ww`sEm(I?uG+%goGp#hiwY(0^28 z-BR`1EaO(z=6|-G(sZTb8k$1u9hD9RuXwg}&R6sVr`dCv*+JgO2%QL1a3hpZLI*Or z+|hz}(JOMxU3rn3?yAcSr)BZF!|wDdl`0z z9=l$Kv$0m$#v0pPV_UvmMquQsqc8pabNdG?1-_2^Y1hJ`Ed}l1)JD*b zM(o2zbaS-_P3Ys!AT>QkRUf6IlhiazMf23OKov`jTA)m?Qoc7R+9G9p3p?=+&-s8q zuQGPwOFW1l5W-Ig<5xuRJ5Tu&Q7s11da;|g*-39-?3z0Ei4uD}Qbt|>Ed=@D^`lgL zjEWyndQ&AOwcWOeW%35BCHxU_?J_pRtrkOftxwR9bZujjd-XC9w~V;CgnGIdlT|09 z;?$wjKW5Ii7)Fd*UQ0%ALDDSoO*EFV(Y4L>Im}89m%6-x_7=merZW5_Ol8K*)l|kx zDrarFsV-ri_7sFALMYOiqt`l{gGMYYv zl;I|?I@;3m_bv8n1H4NCfH=#%pR)H*?p{iKfYJ_7u7i~35G5I;M}pQ6g+HQRLB4;( zc$l*@IF1}2$2pwD^W1rn&*MuN#dUhTf^jy%DZEY3_wfim!)bhh6u!a)zGnM;gU9e4 z(rkps@f$P!g(tKCp47HrK-+d^^%c^-fWh?87Ul45 z=VKTg%(O0psk9-9RN9oGRN9gwskALeQ)x$rQ)#i}7-`FK(vcHnt(+tS@(@`kBV= i.length ) { + ch = 0; + eof = true; + break; + } else + ch = i[n]; + dChunk[0]= (byte)ch; + eChunk[0] = btable[( ( dChunk[0] & 0xFF ) >> 2 )]; + if ( n + 1 >= i.length ) { + ch = 0; + eof = eof1 = true; + } else + ch = i[n+1]; + dChunk[1] = (byte)ch; + eChunk[1] = btable[( ( ( ( dChunk[0] & 0xff ) & 3 ) << 4 ) | ( ( dChunk[1] & 0xFF ) >> 4 ) )]; + if ( n + 2 >= i.length ) { + ch = 0; + eof =true; + } else + ch = i[n+2]; + dChunk[2] = (byte)ch; + eChunk[2] = btable[( ( ( ( dChunk[1] & 0xFF ) & 0xF ) << 2 ) | ( ( dChunk[2] & 0xFF ) >> 6 ) )]; + eChunk[3] = btable[( ( dChunk[2] & 0xFF ) & 0x3F )]; + if ( eof1 ) + eChunk[2] =(byte)'='; + if ( eof ) + eChunk[3] = (byte)'='; + s += (char)eChunk[0] + "" + (char)eChunk[1] + "" + (char)eChunk[2] + "" + (char)eChunk[3]; + } + return s; + } + + + /** + * Decodes a base64 String into a byte array (binary data) + */ + public static byte[] decode( String i ) { + int ilen = i.length(); + Vector v = new Vector(); + byte[] dChunk = new byte[3]; + byte[] eChunk = new byte[4]; + boolean eof = false; + char ch; + + for (int n = 0, idx = 0; n < ilen; n+=4, idx+=3) { + if ( n >= ilen ) // decode 0 + break; + else + ch = i.charAt( n ); + eChunk[0] = lookup( ch ); + if ( n + 1 >= ilen ) { // decode 1 + ch = '='; + eof = true; + } else + ch = i.charAt( n + 1 ); + eChunk[1] = lookup( ch ); + dChunk[0] = (byte)( ( eChunk[0] << 2 ) | ( eChunk[1] >> 4 ) ); + v.addElement( new Byte(dChunk[0]) ); + if ( n + 2 >= ilen ) { // decode 2 + ch = '='; + eof = true; + } else + ch = i.charAt( n + 2 ); + if ( ch != '=' ) { + eChunk[2] = lookup( ch ); + dChunk[1] = (byte)( ( eChunk[1] << 4 ) | (eChunk[2] >> 2 ) ); + v.addElement( new Byte(dChunk[1]) ); + } + if ( n + 3 >= ilen ) { // decode 3 + ch = '='; + eof = true; + } else + ch = i.charAt( n + 3 ); + if ( ch != '=' ) { + eChunk[3] = lookup( ch ); + dChunk[2] = (byte)( ( eChunk[2] << 6 ) | eChunk[3] ); + v.addElement( new Byte(dChunk[2]) ); + } + } + + byte[] o = new byte[ v.size() ]; + for ( int j = 0; j < v.size(); j++ ) + o[j] = ((Byte)v.elementAt(j)).byteValue(); + + return o; + } + + + private static byte[] btable=new byte[64]; + + private static char[] ctable= {'A','B','C','D','E','F','G','H','I','J','K','L','M', + 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z', + 'a','b','c','d','e','f','g','h','i','j','k','l','m', + 'n','o','p','q','r','s','t','u','v','w','x','y','z', + '0','1','2','3','4','5','6','7','8','9','+','/'}; + + static { + for (int i = 0; i < 64; i++ ) + btable[i] = (byte)ctable[i]; + } + + private static byte lookup(char b) { + for ( byte i = 0 ; i < btable.length ; i++ ) + if ( b == btable[i] ) + return i; + return -1; + } + +} diff --git a/sourceMetadata/jcb-package/src/servlets/BlobServletMySql.class b/sourceMetadata/jcb-package/src/servlets/BlobServletMySql.class new file mode 100644 index 0000000000000000000000000000000000000000..71d8fe0570f622838663aed1ceb2160241ef7b4a GIT binary patch literal 3925 zcmb7HYj6|S75?rbY1ivD27#dpgf2;NZDU)ICQguzOLzr?ZES2zcqOc)l`JFg3TcHg zeLwQ*D@~g|NRy^XQ)o-m0&N6NXlR=mCT*vGI_YFO!}L#QI{njsndvk?+J1Ls%d#3`q()MMts{j48qyj@Ymvd2j^oH` z7_Wr`w-z~^s6`$H`S3IpHJp?`Csdr0ixX08Lc?S&PUE8*J|^kMHGD#P{G^6Y>G(80 zqv5j}J|{grs^KxonvgG#Yj{FOBc9aoc@KdDMyBWT~A&z!XL z0&B*S@kGq$#iG%yo3OH@#2uGqn_!eOmEaS<1A@2Q!wS`zs@F&7gH(f7BZ)8$yRaIz%THI zfHslOc&r?g4QR$EJ-cAw8h$CD$_3AM4E#z0Z5(FDRnq}=I!mcy-JPxUQepgh>BP2SA8)%0633wCI-;MwDxtZtFh zsiACx(GRexz4AU2S-E@XvKe7c3S~KH8x{a4Cw1e0&-OmMJSSNutgXF8FISxQDU()4 zKf71cNv{?ow2+m{*-lcRZ6ORdP-Anw8E$9uwPhnxWrj*Nqewp=O+c4 zZjDnavL=dIZ^-uMn5%G!)!_-?e+nF83Cfwoi9^>-Jyqo{c{C7AWZeSOURS|Y7MA5! zJ<6&+6=df-l{%!2keqMcsPA#N!0L*hs?DFRs!FF+8IcDvPbb1@I=r>Hhg42D!czI( z(<2)tn93Fl^q~`2pIs=h@3EF&Zk_z*0|F58n}E-5zTHkLNP{hxAujTVz(@ED`Ai)( z@`Q%si}qp>f?Qi2R`!G!^@am|;Xr@O6$B5gZ*9ARP%ID$T&P%B1C_rQQ>UKRmeA5t z82mC^isgu)0b98$p)BM7Hf*2vaVO;$aYb!e-&%q?3rME`u!^Qu`>G+n@4!wf^FySp z97xmP5=`DvfN-?)nauKJyKV~hJzio$_t2ANpGAn7QVY2zszDVQnyHY`0%-Z|3)IYM>6#i z?u`UX=y<>Jy%ggnJ@3afvxoQ5mo#`kX?Rn`F?~hk{=Z)jTcn51*y8zmO#0l+*GJ}M zzCN<}+C|oK1Mb0nq`$)-@JC)eZs0HYE9u|xF8+aK;=H&dUPYt0D&7>=N#7E0i+3ph z7_N&OlzUH{l~k!ymMbes*C^|hCejwAL)lc8Q)JsxPEv70(Ii!ND80&F%8e*Tm1CrF z#ZgXRnbNIn@#X!l7CSLW-8-P+F6dat3sfT!H{muk6ZhRjz8;&<%8qYiYqj$>7{z{U zz!6>*kD>#|D3QSZyp?St;>~!9bKzOeiqi+eF3Vi**|7!rrDUyNczJdOk6X*?vJ z!6ES+4vQCYM4UxZoQEwgBPFgPE#AVI_&tt`x8X9Qj`$OD%;dx3&v=BB!%{RPl{(l; z1Sw?=(n<@)lqilX9dMahN9jb4nMx`Database Error"); + out.println("

Could not get a database connection.

"); + return; + } + + + //Connection conn = CacheConnection.checkOut(); + Statement statement = null; + ResultSet rs = null; + String id = request.getParameter("id").trim(); + String sql = "select photo from zPerson where id = "+id; + + + try { + statement = conn.createStatement(); + rs = statement.executeQuery(sql); + if (rs.next()) { + photo = rs.getBlob(1); + } + else { + response.setContentType("text/html"); + out.println("Person Photo"); + out.println("

No data found

"); + return; + } + response.setContentType("image/gif"); + + InputStream in = photo.getBinaryStream(); + System.out.println("after getBinaryStream"); + + int length = (int)photo.length(); + System.out.println("lenght of the blob is " + length); + + int bufferSize = 1024; + System.out.println("buffer size is " + bufferSize); + + byte[] buffer = new byte[bufferSize]; + + while ((length = in.read(buffer)) != -1) { + System.out.println("writing " + length + " bytes"); + out.write(buffer, 0, length); + } + + System.out.println("written"); + in.close(); + out.flush(); + } + catch (SQLException e) { + System.out.println("TestBlobServlet.doGet() SQLException: " + + e.getMessage() + "executing "); + System.out.println(sql); + } + finally { + if (rs != null) + try { rs.close(); } catch (SQLException ignore) { } + if (statement != null) + try { statement.close(); } catch (SQLException ignore) { } + + try { + if (conn != null) { + conn.close(); + } + } + catch (Exception ignore) { + } + } + + } + +} diff --git a/sourceMetadata/jcb-package/src/servlets/DeleteBlobFromMySqlServlet.class b/sourceMetadata/jcb-package/src/servlets/DeleteBlobFromMySqlServlet.class new file mode 100644 index 0000000000000000000000000000000000000000..d100015127e7283689f5354a731bdaaf9abd0a92 GIT binary patch literal 2600 zcmai0>r)d~6#p%R?6NG1LDW!%D5AVVL~9=*Mk}CF2_PWWzU(HshNVe1>~46}zTeM( z!7u&bjMERbGeu};+VB0NI{n>jcnQ>DxaaP<=lMJ5o|}LE{o^kH1NcctCtlX@iiTG; z#B~fJq2m&g^|*{H8eY?J6+;?^8!&=vIhMSU(X-Mf9$B>TGn9wlUfLoYq zz%*v$a$Ci$j-%4S9ZBENa97edb-abQ$(TwHIVlFoAIaV<@NTDIS=z3<+n>F)gp&*#Bik6pDP}|i#s~|9B zXURP{W);PFxsVpljG4}p)0h(;Rf{6yS$0vu(XMXayt|N(Z5_~qKC+w!4eAQLIgvCHNdYFdo#ZC^VxJJUg5=KvAmrz^K*0)vooGuDl@f!W80pJoPjx5D&`GD@xF?@fdU9nS2P-p z>>orVEpk>dLLn8lff5!J)L2;+jsX|6TQ;zWB^ApCR`7v>dQU7%*a~#;KuY%~L)&vw++vX#$DxFU(Pon2ux7m~jDY@{Tkh%8y& z9F1Nw@D;vR(9CcyBoi@Tx{^=Qz&A3}Zw-8h@8$9X<+eO+_LG994KD-95y!C|TKy4A zzSV(UR?lHTLF@iCkVR%I?BA3dVOVx-bYfc=&!|=VYMa2pt>}mHrps& z`d4Acy{z7)%2ll>@E#qh*pS!DZ^@KdG;Qd#>?b)rJkAhd78sddo1JWCSdv0{wtmYV0m|Xh`TuBFM}Pu@vu4tCh?XbwJ+qg& z-RZGAwk1-Tcf6#e%;)gNwAwig&pa<6f7oyyGNOsHS1MOQkX7{I+-ja`7i6IK&G95APnJf|wDmb@4G*WxgSIBN^Frd~7NPC`g z$S_*}sbK$gjqV0nma$PRi%i)Qw@XIfl(rNfh}EMfZ(xaZ5jwU?X|qzY+W&r>K*DhhpEgB7NZdO1+3CPl|ki#pQdp_-ea z+Obd|6$*^^tfB5sZ(no`!FV7X_;u4l8&vL_sB?(cLbTKj11u66G!hp#j#L$6|LbqE}<8=tl~Je!+|xNU=nSQ za3!v8$ws8Cx{8xh{M26JhvM3%a#;KO36mOt%?GT#LLW1k2Y3icALEw_RUjcw;~3XA zXq40uK_hF{ic|dSV0BJY`z$W9YL{89QF3mv2sXJM&SM!DXf=wDSe%FC{Y>5?@*Z>l zg!|vQU!%4JIY?;F^IO4-JoQW2L6~cKruOvqt)gSA?m7j)pL{_io>9I?ehpsw50D+L A00000 literal 0 HcmV?d00001 diff --git a/sourceMetadata/jcb-package/src/servlets/DeleteBlobFromMySqlServlet.java b/sourceMetadata/jcb-package/src/servlets/DeleteBlobFromMySqlServlet.java new file mode 100644 index 0000000..8cda155 --- /dev/null +++ b/sourceMetadata/jcb-package/src/servlets/DeleteBlobFromMySqlServlet.java @@ -0,0 +1,63 @@ +import java.io.*; +import java.sql.*; + +import javax.servlet.*; +import javax.servlet.http.*; + +import jcb.util.DatabaseUtil; +import jcb.util.IOUtil; + +public class DeleteBlobFromMySqlServlet extends HttpServlet { + + private static final String DELETE_RECORD = + "delete from MyPictures where id = ?"; + + public static Connection getConnection() throws Exception { + String driver = "org.gjt.mm.mysql.Driver"; + String url = "jdbc:mysql://localhost/octopus"; + String username = "root"; + String password = "root"; + + Class.forName(driver); // load MySQL driver + Connection conn = DriverManager.getConnection(url, username, password); + return conn; + } + + public void doGet(HttpServletRequest request, + HttpServletResponse response) + throws IOException, ServletException { + + System.out.println("--- DeleteBlobFromMySqlServlet begin ---"); + Connection conn = null; + PreparedStatement pstmt = null; + String id = request.getParameter("id").trim(); + ServletOutputStream out = response.getOutputStream(); + response.setContentType("text/html"); + out.println("Delete Photo"); + + try { + conn = getConnection(); + pstmt = conn.prepareStatement(DELETE_RECORD); + pstmt.setString(1, id); + pstmt.executeUpdate(); + out.println("

deleted photo with id="+id+"

"); + } + catch (Exception e) { + out.println("

Error="+e.getMessage()+"

"); + } + finally { + DatabaseUtil.close(pstmt); + DatabaseUtil.close(conn); + } + + } + + public void doPost( + HttpServletRequest request, + HttpServletResponse response) + throws IOException, ServletException { + doGet(request, response); + } + + +} diff --git a/sourceMetadata/jcb-package/src/servlets/DeleteBlobFromOracleServlet.class b/sourceMetadata/jcb-package/src/servlets/DeleteBlobFromOracleServlet.class new file mode 100644 index 0000000000000000000000000000000000000000..b438ee4ea3ac8114ccb6a7832e9f63f53c37e366 GIT binary patch literal 2625 zcmai0=~ok16#q>K%rFcUqo{F#xPWXSBDG71(F#$iYyx8KW+%xLh9;RfGeM}`_r3o? zzx0FWc>1CCoFcU6wBP$j_4M~zd!#5(1)LNwBscWFKb9@ z7|@W?aUN+M7jUs2ui%n~K^;TLXt>;fE4Zp-7_Tatlo`oP zXKqhs2FE9d6hubm%>^@2FiW$EDbKM=vjY?wv`emMmb@9WP!S61QdY_G(h6!iI%gDw z2kkt$dq%917^@Vs!kIR+1#%i^g-6wr$a$7sQgE=NGcfPoEhIKJ=t0jc=0sUaxe99Y z_7&kNnC$SS7Za{<77D^k%z0ipah1zdz?c+wE5h{#o+;**X;=(&&ZwAGF~&-jXf^d2R z;UWJ;L7Uu424YEX&MGA@7EQvrnCv@uwlA48-Lhp8kx;Qr6pQ7vDl7x@cvnTiKrf0a zN(O9jw=*7(KP|9WR?J$Z7^PI)HQ;~bjq{5f=CBQ#3tr!&rT%*UMk^BsQ6HZm{4#s@8cD_L$G3_OA}Vk zt2n}q-J27Rh*|mA`Pc;&9~t-T6MVLiK78GYIn;Dj+P=V*8d4~Yy$Z2~z+SS3Jz~BU$ zFdd@h$$Z;)GPgZFw#TMK{3*yON6LKmug$QnBeMNj0Rh_dO3DbHk)Xi&kK-Jy}%6M;g0 zU4sD~_CeZlms5t(1{VnXuVZ*S$g+%$Vo~HOp14uYGZ6ni8Rl>{%Vkl@D~RtN(c|Mm-R6L6+%rcIB(N--t>e6r_n*$$+r;pBg|)B7hHSDIYz3G)^w*!dc zAkJ`Ch7#kSb1d+oj8eXyJFCA#i_|YeSH_fNxI5CY3L}JNG$w0%R`HyIWL-~W&nlWi zh}K2+E+evnePi*+{#7)GAR`G!Ygcig2GQ^;4l1}At@{gyZaqdca(Ed>qP1KiN4YHH z7`3C}6|^vk)(5zlR5xUgOIdXpC#3kvoy7MhwRPpF_Rk|G)yEt1J`>?gA?}OwM)I%qG_(Sc~YV)j03T zUfS-%FXTNS?;)Qb@%axvuTWcpTt{g8@jPKZw+1sk)bIzWUEMv)IJHrCox;EXl~PYA Kzd(KnFa8e@IJA-g literal 0 HcmV?d00001 diff --git a/sourceMetadata/jcb-package/src/servlets/DeleteBlobFromOracleServlet.java b/sourceMetadata/jcb-package/src/servlets/DeleteBlobFromOracleServlet.java new file mode 100644 index 0000000..d31aa42 --- /dev/null +++ b/sourceMetadata/jcb-package/src/servlets/DeleteBlobFromOracleServlet.java @@ -0,0 +1,63 @@ +import java.io.*; +import java.sql.*; + +import javax.servlet.*; +import javax.servlet.http.*; + +import jcb.util.DatabaseUtil; +import jcb.util.IOUtil; + +public class DeleteBlobFromOracleServlet extends HttpServlet { + + private static final String DELETE_RECORD = + "delete from MyPictures where id = ?"; + + public static Connection getConnection() throws Exception { + String driver = "oracle.jdbc.driver.OracleDriver"; + String url = "jdbc:oracle:thin:@matrix:1521:caspian"; + String username = "mp"; + String password = "mp2"; + + Class.forName(driver); // load Oracle driver + Connection conn = DriverManager.getConnection(url, username, password); + return conn; + } + + public void doGet(HttpServletRequest request, + HttpServletResponse response) + throws IOException, ServletException { + + System.out.println("--- DeleteBlobFromOracleServlet begin ---"); + Connection conn = null; + PreparedStatement pstmt = null; + String id = request.getParameter("id").trim(); + ServletOutputStream out = response.getOutputStream(); + response.setContentType("text/html"); + out.println("Delete Photo"); + + try { + conn = getConnection(); + pstmt = conn.prepareStatement(DELETE_RECORD); + pstmt.setString(1, id); + pstmt.executeUpdate(); + out.println("

deleted photo with id="+id+"

"); + } + catch (Exception e) { + out.println("

Error="+e.getMessage()+"

"); + } + finally { + DatabaseUtil.close(pstmt); + DatabaseUtil.close(conn); + } + + } + + public void doPost( + HttpServletRequest request, + HttpServletResponse response) + throws IOException, ServletException { + doGet(request, response); + } + + +} diff --git a/sourceMetadata/jcb-package/src/servlets/DeleteClobFromMySqlServlet.class b/sourceMetadata/jcb-package/src/servlets/DeleteClobFromMySqlServlet.class new file mode 100644 index 0000000000000000000000000000000000000000..279aeba5b09e7a4ceb857b8844afe5b1b9141c1c GIT binary patch literal 2441 zcmai0Yf}?f7=9K48^Tf{3L2{zZ9(pm3b5`whQGBfS`4|?ksFr&=mZG>H!zp~CbUe`UsgBPy#3v@RlZ%s&#@pEsDH!yrPEVef<^n!J2E<4rn1Zxsewo#T961vc20vYMAc} zxi`!}`0K8a=8BXh^A4AV3SnNXl|>-O-pCe|s922kFX{MP#}`Ckdvjhu8?gni?B~TT zNBMhZLePvDcfH&#-z!XSF08p#QzI%Y271s-7@og8vb-us3WbrvCb5i6_|CfUHFU4q zxqK?5rA*WH@|L?oGp3i9Ua3rI5#RHqj)w*w;Y%IV*pHls2FKQsH(*2Pcx+%9D>@tl ztN2Poixe9Qd%-o}qM%_ktzI(e6=B(#v~;8^G8NC0DwoN5k@tK%ZB|awX2_?bXuv~3 zSsc)C&JLj_9}{PC!jhJXK#+X0B7Bi_?BvztH60}bYw&dh1|-S`*71bsUoDWEWyiG@ z`rdTTvp4D2Xr`jwuK44J{v@9`a)qj|8rZ<5hNEoS{C~lj@0}d zcddZQ)*pNRj8$M^^;9bPKwDK?A?&nJfNjtf>QLQLsi3x$!l@{idp+~c2 zSt?5^78W)3R5jLeT20P=HU{^tAe=^06y@S(iCO8ahlca)>_K1ZXk%_moQ=}uP^;AE z!HLHDEcv2j`C>s@QWR)X!-ab0Dk)Raa}@!5Pl7I=48vIWlyiZ2c7xm1H&rM3#L^}< zM7}J=y^>8w!ihb_@n@AvqG)RvKHR5$`Kfj|9g0eC*JS5vK4+Gt!&>F|$XS87#}`iT zyz2#Om{wKS^`4_x!-;(y`)&hu6l0dBMG&z1d0{5`2N({V!#mvHrdYXW{8O}2dO_Dh}%PgIvWDi5p%MYCMxIylz zP?yOY>;g*s5(*f$GQ;&0CVnFAXVRYW`8PiQ&gbX26b81L+DAxd|LlgAHPFZ(pbrcV YZQ)EU*D*2!mzkw2uLxfxy#bg013YAVDF6Tf literal 0 HcmV?d00001 diff --git a/sourceMetadata/jcb-package/src/servlets/DeleteClobFromMySqlServlet.java b/sourceMetadata/jcb-package/src/servlets/DeleteClobFromMySqlServlet.java new file mode 100644 index 0000000..bdd9c36 --- /dev/null +++ b/sourceMetadata/jcb-package/src/servlets/DeleteClobFromMySqlServlet.java @@ -0,0 +1,59 @@ +import java.io.*; +import java.sql.*; + +import javax.servlet.*; +import javax.servlet.http.*; + +import jcb.util.DatabaseUtil; +import jcb.util.IOUtil; + +public class DeleteClobFromMySqlServlet extends HttpServlet { + + private static final String DELETE_CLOB_RECORD = + "delete from DataFiles where id = ?"; + + public static Connection getConnection() throws Exception { + String driver = "org.gjt.mm.mysql.Driver"; + String url = "jdbc:mysql://localhost/octopus"; + String username = "root"; + String password = "root"; + Class.forName(driver); // load MySQL driver + Connection conn = DriverManager.getConnection(url, username, password); + return conn; + } + + public void doGet(HttpServletRequest request, + HttpServletResponse response) + throws IOException, ServletException { + + Connection conn = null; + PreparedStatement pstmt = null; + String id = request.getParameter("id").trim(); + ServletOutputStream out = response.getOutputStream(); + response.setContentType("text/html"); + out.println("Delete CLOB Record"); + + try { + conn = getConnection(); + pstmt = conn.prepareStatement(DELETE_CLOB_RECORD); + pstmt.setString(1, id); + pstmt.executeUpdate(); + out.println("

deleted CLOB record with id="+id+"

"); + } + catch (Exception e) { + out.println("

Error="+e.getMessage()+"

"); + } + finally { + DatabaseUtil.close(pstmt); + DatabaseUtil.close(conn); + } + } + + public void doPost( + HttpServletRequest request, + HttpServletResponse response) + throws IOException, ServletException { + doGet(request, response); + } + +} diff --git a/sourceMetadata/jcb-package/src/servlets/DeleteClobFromOracleServlet.class b/sourceMetadata/jcb-package/src/servlets/DeleteClobFromOracleServlet.class new file mode 100644 index 0000000000000000000000000000000000000000..3c8888ebd8628c880f42be622dd3112c0a09e227 GIT binary patch literal 2473 zcmai0+fx%)82_D+WW%y3L_wnh(H6=*YO!jF5e-qP;Zi`Xy=XVtBU!p+*WDAu-rGOI zmp*jH=}e~&ozWMBcBXyrAJyr1b^{3-bTV@;-}&yB-{#-{{`?!jIsByJ3?^c@5W@#C zT#Vt8ipxl=m_#OqD{aW)s){LGYr}QqVwjeDK871AZsL}T)0m0j!#3PTp$)T`lgqq< z1r=RV?MHH7jA2Rc%PQ_*MJ{(0d>q3)6+QSw>iAT_X9_-Nh)?GW`Q`kBTw(tDgT;Jq zesP+Jg*AOcPg#0pHMJyMv$8tL(4Mm^p3o~|MYpP)A(}BOrpPk13=XX@gmbn*)WZd{ z!sn{%MeZ)^MT;oyt6Y$1g_neBR~U{B4h8DHM^>u-Ko->eW{EqJ%VUTb_DwDr76*Oq z&6LO84U3CZSqLX}imiP@* z`kS2QWQOM~yLiL3*XLcmWbvA7HZil$3~9vITh(5#}m)6?~yVM^QmZ!!QhnkZCC3 z8XjU*L0N-|H3eU4u&~b1D)^?%%etkZ0-IqXBQM!Znd?S2BTQlOY!Fpa);YPzOSWrd zQo&0mG?G`6R~5J#JO~9<4I6l@ zVG~cNz^^vX^{QzZ++`TZ6m8=P`8AOZv>SmxuJ2Fsu_?-=`ih3H@HN8`a%>`-Nd+=~ zd|3_O$jHCd@EyLF%MZj?x3||o3>|e_dDpdF()uITG>l=K;p7`?%+M?R=A$s)FBf406PW^BKZM-Enw@kZ0^*pBm~@8*y?dChT34U2COc zswzzCRl<*=?(sWxA&@IswnvuwYO0%hPdLqRyn&o}H$TDnRML zJ9wA&e!7Lwi7=fBt!W)3N)PRf_Q>!{uou3-5Uo+4sG?OOABjoU0$LEE{Zu@3JKj== zhiBuFx#4X@?~aU)Z9_?i6XEB38hWA7xr1anNn4yW9f5|Ubn8L_-58};>56oK04T7* zt`UDLy}V#^EFB(+$9B*f!WPtYWON5@4C&}-T-!l=2#IL?&=wAFqhoF?-noN#2-1Ua zBC>-cEl7lSaFpS0BKjA)?!82J{MZ(bCnB`O6SQpM1W6~t+c-(ipZX0`X{FBFD|wYI z^c~3FnU3uVCu0A+pkRiuO4#4y@6RX*4^JWYXZY3M8NC4aag5d;3b>cj*+;2KQjKJ_ z&d_^5C1U^=sXo^z=`+5r6n)dq!l8dk9u=cXse6hPekR&4M0-Z(-|74ZouA{ppV%mA nPZ5m~t(IEqf)@G#%J9hO7LxT^tHcakqAFc}Mfg0?LwNsx%twXS literal 0 HcmV?d00001 diff --git a/sourceMetadata/jcb-package/src/servlets/DeleteClobFromOracleServlet.java b/sourceMetadata/jcb-package/src/servlets/DeleteClobFromOracleServlet.java new file mode 100644 index 0000000..8b0d36e --- /dev/null +++ b/sourceMetadata/jcb-package/src/servlets/DeleteClobFromOracleServlet.java @@ -0,0 +1,59 @@ +import java.io.*; +import java.sql.*; + +import javax.servlet.*; +import javax.servlet.http.*; + +import jcb.util.DatabaseUtil; +import jcb.util.IOUtil; + +public class DeleteClobFromOracleServlet extends HttpServlet { + + private static final String DELETE_CLOB_RECORD = + "delete from DataFiles where id = ?"; + + public static Connection getConnection() throws Exception { + String driver = "oracle.jdbc.driver.OracleDriver"; + String url = "jdbc:oracle:thin:@localhost:1521:caspian"; + String username = "scott"; + String password = "tiger"; + Class.forName(driver); // load Oracle driver + Connection conn = DriverManager.getConnection(url, username, password); + return conn; + } + + public void doGet(HttpServletRequest request, + HttpServletResponse response) + throws IOException, ServletException { + + Connection conn = null; + PreparedStatement pstmt = null; + String id = request.getParameter("id").trim(); + ServletOutputStream out = response.getOutputStream(); + response.setContentType("text/html"); + out.println("Delete CLOB Record"); + + try { + conn = getConnection(); + pstmt = conn.prepareStatement(DELETE_CLOB_RECORD); + pstmt.setString(1, id); + pstmt.executeUpdate(); + out.println("

deleted CLOB record with id="+id+"

"); + } + catch (Exception e) { + out.println("

Error="+e.getMessage()+"

"); + } + finally { + DatabaseUtil.close(pstmt); + DatabaseUtil.close(conn); + } + } + + public void doPost( + HttpServletRequest request, + HttpServletResponse response) + throws IOException, ServletException { + doGet(request, response); + } + +} diff --git a/sourceMetadata/jcb-package/src/servlets/DisplayMySqlBlobAsURLServlet.class b/sourceMetadata/jcb-package/src/servlets/DisplayMySqlBlobAsURLServlet.class new file mode 100644 index 0000000000000000000000000000000000000000..eb13428fcd4c148bf879731a39529d2998a53c93 GIT binary patch literal 4138 zcma)9YjhM>9sk{AcV{vgUJEHK1-g_+^Ij+rVF_y+l0ZscB)qGolieZNba!XjnFSW8 zwQ9A#-)O70V%4ZsgsLHd+WJQ8`+54sFMiSEIezhr=Wsmg@6Kc&34yxj?7egE{O|wq z`@iPC_MdC70N9K_Y1oeaDuz@Ht2m(HAP#9bj3XM3;+PyB*6 zH{qOu^C}+K@HR>OL@nNqCu{Kzyt5YX!c%g1w~F_ucv=#_SH=5OykEr!G<*;rlEa7P z@DUXsRq-(m_u}J{?h^_=so;XZ!j9g7j^mv@LtVQM3=AC=2=I1mZYyIuM#ed0r1GYUPYI~*!GlA+Dn2c+*j;t^^mZK|9O~-sIilhjfk1mQlXPMN z)%6XB1bn-#gekD7H<>Z}^XU;Ycfc4)ac9A(=}RTRqz>_ov;Qin=-UvE1!#--AQTW+Rmh%O&Nv0 z!tlvdN$nY7trBz{52AzCTe;EJ(Q&6Woo-DR2tjLSE_uq#39K1UjKrhvUNjO(S#cvZ zMnMrP?pWD85%J|L%Te%I9iPK<3ZB=|h0iOvsN)NGK@MM3@Fg8z#stO8^>ar)nMz18 z_a&kc$4bWyCvw^xF|t{^C?PUJTsxCFcW%+~6?|34*D#^rMIB$qHw0F=T$5Hr8aG(FjqhnIq+$7Pjv?;oM)22=Hi&bz{#}uXo+8P@h z!*_x;JYtR}Gc9v|3a;t6j!Obn$%KNJb$l1ED0o%J_arb4wwYoihO=XqV}(!TtaP}q zFqn)x`J8EoPmh^7GaODP!n?u>zOUm4_@O|JW1f*AluqgRk+ic5-2zL?5SQXsptW7n z#oEVABN1zNl1|Eu4VpRI%7h1{$o7c0*B)^x6#Q6VNBfACDDceYSf}9_BZh5;%ZU*l z%vnsNbSsZ+jMEHc2BQj*LbY4w!}u52@P7p?Yk`+4#aLis z^bAzQ!W>;@szC+8qH+lBP8l|HTp`H)Mw%66!%V@eEO3=I&pp7Rd6&yW)>5yK^cfjr zR3>`gJPd9v|F`bkt~xIokB>z1PBKL!4{~B4#Z#6|RaeYNlJ;jxHGwr#V0HP`+?wIO zUs_^1WMmRnde6b0PNKlt?>#LmHj7Fa2t4bSnMnw=%wuFFN?wzjDSkvtbu4d-eW?VT ztk>*Zvf(5%My}x1w2DqO$1s7q`NY!PK+4RFI%956e5f)k%CN{f&e}lq>L2cCUkvt&E6*CtRzaY z^=^<1Z=W19P0{PUgGP>V=*URgIG?q*2F`4S-LDH8%b9v_d?U$TpY^;@*;!;Fcn&S= zJ(Eb4WHf%E?S5xCX2v;C$P&=Cvt`b6s)*R^FA*vcr;8kO*x`^SKW14m4kc-6pHhRa zk7n%>Kl6+k&pYP+yqPNq)ZZRId2qkIn&8>iqu+|=AMg+SC7@?9=*SObO6D|jYEZY#;@Zs-)Z1Z%i+ z5BBh_k5caCH$I!9Cqo?Lp2jzqM6c*;yn#icziA3e^AyyU%TuW7zYgu_Rn!LcNi1mL ze-aC$zQ$=1qPOV=mWZgocp&7zd>xCAhJ07Cq>m&)fv4O2OMGYx)CFEvqe@dqnZ(kg zZT_m~v8XwuRM+_@v25bMe{Y^dT~W|o6@t_fYxQ!prnIPem0C-^FH-YmbcCF{alxH0 z;stm1a6L=wf%UX@15eaLMFY=uVIk>*#AF#-h*>MgP1wqt({|iXeqD57H+`^&<2DSU zjW?$4c!Z8m(6uK?ah8sMoQ{8zlov?z*2n9&hP=)?bO;KE9 zQCzS|dSVK6&Vt~K>&bWmo6E$lCE^I57#mW7z!Wxx{8Oa!P2v74bJi2s@9Mh6)wL*f zt7N22Vw)6pdtTAnIov|EuU=u2bQ9iwhW2s1j+@>rw$kx8#d^5nnah-&1;dK5$h&Wcu? z6I*beS{4MuOFY1J7uS1vX_kQ$VEFW+j|tpg3?-~%C{^>F(%3{NwUw)hMq*H{0G^t2 Kc!2v=82ld)fI_(d literal 0 HcmV?d00001 diff --git a/sourceMetadata/jcb-package/src/servlets/DisplayMySqlBlobAsURLServlet.java b/sourceMetadata/jcb-package/src/servlets/DisplayMySqlBlobAsURLServlet.java new file mode 100644 index 0000000..5d8d57d --- /dev/null +++ b/sourceMetadata/jcb-package/src/servlets/DisplayMySqlBlobAsURLServlet.java @@ -0,0 +1,136 @@ +import java.io.*; +import java.sql.*; + +import javax.servlet.*; +import javax.servlet.http.*; + +import jcb.util.DatabaseUtil; +import jcb.util.IOUtil; +import jcb.util.RandomGUID; + +public class DisplayMySqlBlobAsURLServlet extends HttpServlet { + + // directory where blob data will be placed as files. + private static final String BLOB_DIRECTORY = + "d:/tomcat/webapps/octopus/blobDir"; + + // BLOB_DIRECTORY as a URL + private static final String BLOB_URL = + "http://localhost:8000/octopus/blobDir"; + + private static final String BLOB_FILE_PREFIX = "/blob-"; + + public static Connection getConnection() throws Exception { + String driver = "org.gjt.mm.mysql.Driver"; + String url = "jdbc:mysql://localhost/octopus"; + String username = "root"; + String password = "root"; + + Class.forName(driver); // load MySQL driver + Connection conn = DriverManager.getConnection(url, username, password); + return conn; + } + + private static String getBlobAsURL(Blob blob) throws Exception { + + InputStream in = null; + FileOutputStream out = null; + try { + + if (blob == null) { + return null; + } + + // get a random GUID for blob filename + String guid = RandomGUID.getGUID(); + String blobFile = BLOB_DIRECTORY + BLOB_FILE_PREFIX + guid; + + in = blob.getBinaryStream(); + if (in == null) { + return null; + } + + out = new FileOutputStream(blobFile); + int length = (int) blob.length(); + + int bufferSize = 1024; + byte[] buffer = new byte[bufferSize]; + while ((length = in.read(buffer)) != -1) { + out.write(buffer, 0, length); + } + out.flush(); + + return BLOB_URL + BLOB_FILE_PREFIX + guid; + } + //catch (Exception e) { + // return null; + //} + finally { + IOUtil.close(in); + IOUtil.close(out); + } + + } + + public void doGet(HttpServletRequest request, + HttpServletResponse response) + throws IOException, ServletException { + + System.out.println("*** DisplayMySqlBlobAsURLServlet begin----------------"); + + Blob photo = null; + Connection conn = null; + Statement stmt = null; + ResultSet rs = null; + + String id = request.getParameter("id").trim(); + String query = "select photo from MyPictures where id = "+id; + ServletOutputStream out = response.getOutputStream(); + response.setContentType("text/html"); + + try { + conn = getConnection(); + } + catch(Exception e) { + out.println("Person Photo"); + out.println("

Database Connection Problem.

"); + return; + } + + try { + stmt = conn.createStatement(); + rs = stmt.executeQuery(query); + out.println("Person Photo"); + + if (rs.next()) { + photo = rs.getBlob(1); + out.println("

photo id="+id+"

"+ + getBlobAsURL(photo)+""); + } + else { + out.println("

No photo found for id="+id+"

"); + return; + } + } + catch (Exception e) { + out.println("Error: Person Photo"); + out.println("

Error="+e.getMessage()+"

"); + return; + } + finally { + DatabaseUtil.close(rs); + DatabaseUtil.close(stmt); + DatabaseUtil.close(conn); + } + + } + + public void doPost( + HttpServletRequest request, + HttpServletResponse response) + throws IOException, ServletException { + doGet(request, response); + } + + +} diff --git a/sourceMetadata/jcb-package/src/servlets/DisplayMySqlBlobServlet.class b/sourceMetadata/jcb-package/src/servlets/DisplayMySqlBlobServlet.class new file mode 100644 index 0000000000000000000000000000000000000000..e02b2c4b592048e23e10f74c6a3cf89d12201bd8 GIT binary patch literal 3479 zcma)9*?SvT75`mX){IBvI8oxH18zE@P4TM1ElELk++sUU+}Ms{Cw81bgO+P)%t)im zj1mhdW$VUX2&7?Yfrc6=OI)a8w`F;u-vZA>J^SyR zBmeE)H~$D=5Pwi`1miM}%b1XHLcvK)DtH{H+AxJ_88Zq_BQE1i7_*pDa2Dqz%qwUY zObcQ^FP6nHF5seq598w!J|W`?alRzulL``oJsCy{=`c8!!pI;i7E{Kuj87@BkP}N@ zEVhh77?zP# zGlYiCyy=ZFv~>5(GX%%%G-v3TGV^?| z5{7%(G8z{{49fA96fcNZE<3;!is5qSip4!6>v;v^BrS6l!YsdBn53k(4>E#ccLzJqHL zzN_MUxK5_}v9=QVj4|gqW~fOuV%T! zb=^$s$8;4h;)aUv4?QICJ=Z>Mx<0~RhIZMS$!m#MDIE)Nuc_KYB z?3td$N8;RZ?Ytfr%7={#ZP@T%NO+myqr*u%T_T>rk@19=NG4paH_)QT9h=aVixSJ= z$goj)>+2km@M9G}!A~W;qT(igCgD{TtN6K!U*MMvdPDGxU31CV;YP+>l5k7K8eUiNJN%wuzs2*Jtf$*cx|ij8l2D|Zt{=xY zB$QR$#yW$1)iFKFh)z({lO>P4DmL&Yl}zm-ZRdGZD0@W3TLO5U^~#w$Gu0IGBilsy zxZ~JPOutK@8Fn{<;Xgm7;%!`4aST-02X?@rKsnXI&Lvp`hG`p&CR zo!ZszhOu)c*W)>Ag?5qJNoPd{c^{{O^Qi22B3G}L&1CYhARbxN89TQzP_)*=caL_p z0Wzr6Y2yipqU8yHAKXsdo$e6`njG<41a&Fe$)A0-UfmoaLTjQ>;Q2Je!2hM9+HoiX zvS(MC5Lx$LPF319O%(F#bkQpmtAP|qsHCI;z$%iOpOLm*u0MG^p7+j{3Iw4;n{{r( zRYUIP*+fR9D2E=O^JvMDJc3y*G~#KUPFf>=G&fNxHGGAqiXJ~xxTB&!{-LKdr(l=`66Hcj82SRMsNYNhh^}Ld)A<;Iy ztnb+4G>Pl(G{LU{rpoZyEJVy#8ZzWv_r=kkN!mp#B`+m9PfiL0TbHb&OF9%XY?`|+ zH3uA`FE&T$I~x!L6C4H@(1KRF>xu+U zMOvmJ!RbhFrgt5!3w`|q>j=eyTJTm~!a+#%c^C0?khI+-X%AHFrF9=PbYhrpg(>^! zk9u)MN8sN?>mVaGUWXKs%V=XWEEZ(3Ru&8OMU)MM11Lj{NpGQj@iulvI?C9sNwk!) zCnooAAi@x9TgTp5a1~uKr9aZSf&Bq!ZIJ_I+(Vm2+nN^K!29TBtJbQ?8+d;Jv5*$p zKo`RebZ8;EzBhoGRXlcwfSTrmHO-OxD(Z#!&^mOjbsdMa;5t6A)*rdw*FLa;2S}Sj z`(cLXj)uv-nw$rTyE9zI2gw6+cux>V)lT(oIo7TzT6-DYi$}wOmti!q^wd})y*1Ts zTASA1BINX~{`apUdi^9!Q_2|7+RBJ-v1}EKn_}}JKQ=X!21%-5eTeqEco*BXMXI*z zPivI+5sYDi5_<_{mZWdh@36SPi}OuNyExO%lI)tl-(;`)^a}L;5ECqd6KoJC*$^h#2u`sH zOtDj#W^v53b68*(aGqVlB6)Y3r4eTq&M+6V>>AzQp!=8T{uR2vN$1z-e2dO+(0Lsf t{Q?LP>>nk)jPzDZfV^y>UqI^ZqZB^es7Zw$gZ^a+A-RQll;{DB{SO*YkzW7+ literal 0 HcmV?d00001 diff --git a/sourceMetadata/jcb-package/src/servlets/DisplayMySqlBlobServlet.java b/sourceMetadata/jcb-package/src/servlets/DisplayMySqlBlobServlet.java new file mode 100644 index 0000000..3047d86 --- /dev/null +++ b/sourceMetadata/jcb-package/src/servlets/DisplayMySqlBlobServlet.java @@ -0,0 +1,101 @@ +import java.io.*; +import java.sql.*; + +import javax.servlet.*; +import javax.servlet.http.*; + +import jcb.util.DatabaseUtil; + + +public class DisplayMySqlBlobServlet extends HttpServlet { + + public static Connection getConnection() throws Exception { + + String driver = "org.gjt.mm.mysql.Driver"; + String url = "jdbc:mysql://localhost/octopus"; + String username = "root"; + String password = "root"; + + Class.forName(driver); // load MySQL driver + Connection conn = DriverManager.getConnection(url, username, password); + return conn; + } + + public void doGet(HttpServletRequest request, + HttpServletResponse response) + throws IOException, ServletException { + + System.out.println("*** DisplayMySqlBlobServlet begin----------------"); + + Blob photo = null; + Connection conn = null; + Statement stmt = null; + ResultSet rs = null; + + String id = request.getParameter("id").trim(); + String query = "select photo from MyPictures where id = "+id; + ServletOutputStream out = response.getOutputStream(); + + try { + conn = getConnection(); + } + catch(Exception e) { + response.setContentType("text/html"); + out.println("Person Photo"); + out.println("

Database Connection Problem.

"); + return; + } + + try { + stmt = conn.createStatement(); + rs = stmt.executeQuery(query); + if (rs.next()) { + photo = rs.getBlob(1); + } + else { + response.setContentType("text/html"); + out.println("Person Photo"); + out.println("

No photo found for id="+id+"

"); + return; + } + + response.setContentType("image/gif"); + InputStream in = photo.getBinaryStream(); + int length = (int)photo.length(); + System.out.println("lenght of the blob is " + length); + + int bufferSize = 1024; + byte[] buffer = new byte[bufferSize]; + + while ((length = in.read(buffer)) != -1) { + System.out.println("writing " + length + " bytes"); + out.write(buffer, 0, length); + } + + System.out.println("writing done."); + in.close(); + out.flush(); + } + catch (SQLException e) { + response.setContentType("text/html"); + out.println("Error: Person Photo"); + out.println("

Error="+e.getMessage()+"

"); + return; + } + finally { + DatabaseUtil.close(rs); + DatabaseUtil.close(stmt); + DatabaseUtil.close(conn); + } + + } + + public void doPost( + HttpServletRequest request, + HttpServletResponse response) + throws IOException, ServletException { + doGet(request, response); + } + + +} diff --git a/sourceMetadata/jcb-package/src/servlets/DisplayMySqlClobAsURLServlet.class b/sourceMetadata/jcb-package/src/servlets/DisplayMySqlClobAsURLServlet.class new file mode 100644 index 0000000000000000000000000000000000000000..087cf43b99c4c0fe82cf4c9415fcd5e49fb56070 GIT binary patch literal 3933 zcma)9>3SByEFP1?ISnH?ui%0PO>#ai=a0zYi7+nWNd<<6 zbr_Y4q=pnsxg3+jxQYoC=`b$gqZ%w^RAj@jky9}#XGevr!9!j{GcGH*qGC$Lw1%Cy zs^Y0Ip2jm_d<@Tq@o_vShfk>Zq>4{T{!gp;jEc`{cpjgV!{_Dj1r;yI%`YnWl7cS_ ztm)_-XusImGt|{_dSGZoAkuruxNO8NBRd`+_MCKfyhUJjhn;mjBkP?tth}k>D*|dk z@XS!JimwW+E3CSEdb=(T4s~_+oKx{NflzBYoA%lSR@Ky=6$o_LDN|r=Z#rxC=QE?G zbJ`fSNLf8@dbE%=lU~}+3T&>a^}TQ>t$2BZj%Zy|Ni!$8TmfB*S@!5Lmu?8`s;Lkn zxuvLN=~03y`?%=|4Efwsao2P%Tc#JE@Vs37Q4YgCVaS}!o37VVPqnu<28XT1+8g2E)PAB_i}lUS!5a+dAJ!JKfzBG{7lE|__>Z> z;0+zWlxMD&=vSU8@yNb?`&Kq9P?b(8xUORszf$mP9lw$1sdr6_2^1Tn;dVPU9UF7( zOsv!J4C#s+yE0)qW-OLY#SX_5{8q;tZU|I+=9G+m#?mp58G*J|x!`CTskT-x?OA5q z{UX;I_jy|51qlTUI^L8gZAXW|hBC;DnM+q&N9iDKG`C6rMh(}DmD4;n=-4caOcPZ$ zvv>lMPsdGp$PEQrYuuMF_}!-9EgiqZ+X`;!_&xrh;Ey`~gg@)}3;xQ2E*U$}CZQn! zhXsPvbAU>_(9IsORG+{@C6VT~emf@Ni;da&Y>J~JW~rk}T^urNz|1}eg`%$H(mRxqqBN3+8+ zTo#-{MEZ>k%X@dR`&4$D$_7*rU!W5>|7{Oy)iFRNi!^1#0dMs}vkE-Mr-uo8A(2i&Ta^%Zs6q z8Rz{3_p>fi(^FY+@|nT>TC9pvJNFB2bJ2&T24&7v?vzg^cS^-6Wy*H~i;s`KX1+y% zRoIGy_%H+>;i?LUxK328TexnmSRY1^ynI@4JW7e}oCW7#-3^FYeh3`n7%C9MsFpVu z)gC3Slg0v^w?wK=MppGk0)3G{f89KSkJUFc&Lec4d%pBm%9D@$QGRWumIt9@8`jfY zCwBtm+sQXEFC1UDI8U0!oi{|U=&QSpwW7a%9!kSJ)W+-csP4ZBZR7^R5q%D;8~Hzn zHHkpo0vXX;e;eyXB3KfL2Cv`5x{+w$2G;kHB_i`-cl1veN>slhLMB8 zs#mbKA*!s}6r97xnfLBA%wbc>&;u2Q)J4_m^+fgJqWTuSmVRHO=Nr*dn7jGflIv@H z3dz|=7E(4RO1+ z3jJk8byAUZBvQ|T8OLy~juexD8fUP-%-podTs9dE%_ANS&SPIRFpvGS%hoeEA>A+e z{XwbWZoiia%_hRjDADk(Sr%CrPN0ujK7~6%FV07Zw=UvB&PT*CIT!QeHPrI^1Y>iO zvc1fYK7=vAoET(AoMP06ShT~`dX`*|bN3u~N4PqVE4V-_7nuW3;suN{50ZS;r|=HO z@DEJj4m0JSaPTj<_&0w*{)g-L;D`WRQ4NpYSz-+`B92MXO!^_x+ekmcbvM^1xgO+t u82Lgjh3I7uy%6-Zm`%*;Rr~{#x_UDisplayMySqlClobAsURLServlet"); + + try { + conn = getConnection(); + } + catch(Exception e) { + out.println("

Database Connection Problem.

"); + out.println("

"+e.getMessage()+"

"); + return; + } + + try { + stmt = conn.createStatement(); + rs = stmt.executeQuery(query); + + if (rs.next()) { + clob = rs.getClob(1); + out.println("

file id="+id+"

"+ + getClobAsURL(clob)+""); + } + else { + out.println("

No File found for id="+id+"

"); + return; + } + } + catch (Exception e) { + out.println("

Error="+e.getMessage()+"

"); + return; + } + finally { + DatabaseUtil.close(rs); + DatabaseUtil.close(stmt); + DatabaseUtil.close(conn); + } + } + + public void doPost( + HttpServletRequest request, + HttpServletResponse response) + throws IOException, ServletException { + doGet(request, response); + } +} diff --git a/sourceMetadata/jcb-package/src/servlets/DisplayMySqlClobServlet.class b/sourceMetadata/jcb-package/src/servlets/DisplayMySqlClobServlet.class new file mode 100644 index 0000000000000000000000000000000000000000..a81874fd09c4e98acec9b5afea20117542e6e43e GIT binary patch literal 3207 zcma)8TX!2*75t~XQ%X#WtcVgjcU!ijT-pFFBk9DJJJKkl zQDSpzxfEK;ozj+Dxnt-P=E1dLEm(_3Ui!idFZ7Wgz#9)NzB95ecI*^;`5d2p_T}6A zd}p8e+kgM~X8<3>+Xf!PM|C`<<6}C`7?{AMfwMT*gY&qc*c)kuG)ErlD>KAPq>weEchk2B5-i%9jm=DE?}Hp zD#)tRstI%#-Sg5HxH1%IFIhF|-EpLEE%<)by1*gV5L}VB>$2vLzpq-YO2=~i0F*49hL}Zne(5!k+8;8a`vG)CEt;miK&@0 z@v}>Ix$4NY)sUsFKtsd#1V++%f}+i-jKY++Yck#@NPO0FNvLv?CZ|ZdaC%`ZW8yWH z@_x$3GHI(}A3)4#_`ZqP@rH&sP5b~q)bJw{KgLf?yoH|%Jk$=Bb%Tn;Z@KkKk)y{F zoNhQhb&u1ZnfN(=p@v_o;a3`dZQ?grG4WgcP9Pd2dDkoXEPTA^R%B9OpvCvx+*C)A z#&#&uS8JHFX00#RVVMlsl`XXDyU+ZB6W z5qx?F2aRUa>GEF5ZXIcF8*Fa5=F2j>om*$e7-;xl_OrZUKJS^d%S6_=3|qy_u&R_C zHot)#0IKeJ;{Mg%>~R7no9V3Wv0A>$_tBl)-J2d6(~(Hf6L^0(GoJ&^cHCJZ_C~u} zC2a%}|5u337Q+hYzT4Ip(9P@O~sAP>cSrW*H15dVPYSD zqj-Wl3c?`&*dZIfLwC_lU5MxZ04=Jop+{szDlAgnA{7~l8XM>hVGU+V`xE+}c?Wx< z{cG48(>SbQUrHa{KvW>rGaB8$fde6|V;~h?!C1o^|kUdJP`@H$ScCN}V>z!OHo7&Knqzz4!enX#Uj$W&?SH zB!3MU6@!ikVc;+i{0I;FDE1@H-(w`s!^q$SqYN>Q#Yn@L#RzU-6we}o7m#G+$MFj3 z^%`mS7Rk0ktG7vvRZ`2quCH-@lk4ZW&SO?AVlJR#gd|L1oPCLOB Example"); + out.println("

Database Connection Problem.

"); + out.println("
"+e.getMessage()+"
"); + return; + } + + try { + stmt = conn.createStatement(); + rs = stmt.executeQuery(query); + if (rs.next()) { + fileAsCLOB = rs.getClob(1); + } + else { + out.println("CLOB Example"); + out.println("

No file found for id="+id+"

"); + return; + } + + // Materialize the CLOB as a String object (get the whole clob). + long length = fileAsCLOB.length(); + // note that the first character is at position 1 + String fileAsString = fileAsCLOB.getSubString(1, (int) length); + + // write it for display + out.println(fileAsString); + System.out.println("CLOB writing done."); + } + catch (SQLException e) { + out.println("Error: CLOB Example"); + out.println("

Error="+e.getMessage()+"

"); + return; + } + finally { + DatabaseUtil.close(rs); + DatabaseUtil.close(stmt); + DatabaseUtil.close(conn); + } + System.out.println("*** DisplayMySqlClobServlet end----------------"); + } + + public void doPost( + HttpServletRequest request, + HttpServletResponse response) + throws IOException, ServletException { + doGet(request, response); + } +} \ No newline at end of file diff --git a/sourceMetadata/jcb-package/src/servlets/DisplayOracleBlobAsURLServlet.class b/sourceMetadata/jcb-package/src/servlets/DisplayOracleBlobAsURLServlet.class new file mode 100644 index 0000000000000000000000000000000000000000..9a17c966bafe190260c42242d11eb446623dd61b GIT binary patch literal 4163 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 literal 0 HcmV?d00001 diff --git a/sourceMetadata/jcb-package/src/servlets/DisplayOracleBlobAsURLServlet.java b/sourceMetadata/jcb-package/src/servlets/DisplayOracleBlobAsURLServlet.java new file mode 100644 index 0000000..48fae6c --- /dev/null +++ b/sourceMetadata/jcb-package/src/servlets/DisplayOracleBlobAsURLServlet.java @@ -0,0 +1,137 @@ +import java.io.*; +import java.sql.*; + +import javax.servlet.*; +import javax.servlet.http.*; + +import jcb.util.DatabaseUtil; +import jcb.util.IOUtil; +import jcb.util.RandomGUID; + +public class DisplayOracleBlobAsURLServlet extends HttpServlet { + + // directory where blob data will be placed as files. + private static final String BLOB_DIRECTORY = + "d:/tomcat/webapps/octopus/blobDir"; + + // BLOB_DIRECTORY as a URL + private static final String BLOB_URL = + "http://localhost:8000/octopus/blobDir"; + + private static final String BLOB_FILE_PREFIX = "/blob-"; + + public static Connection getConnection() throws Exception { + + String driver = "oracle.jdbc.driver.OracleDriver"; + String url = "jdbc:oracle:thin:@matrix:1521:caspian"; + String username = "mp"; + String password = "mp2"; + + Class.forName(driver); // load Oracle driver + Connection conn = DriverManager.getConnection(url, username, password); + return conn; + } + + private static String getBlobAsURL(Blob blob) throws Exception { + + InputStream in = null; + FileOutputStream out = null; + try { + + if (blob == null) { + return null; + } + + // get a random GUID for blob filename + String guid = RandomGUID.getGUID(); + String blobFile = BLOB_DIRECTORY + BLOB_FILE_PREFIX + guid; + + in = blob.getBinaryStream(); + if (in == null) { + return null; + } + + out = new FileOutputStream(blobFile); + int length = (int) blob.length(); + + int bufferSize = 1024; + byte[] buffer = new byte[bufferSize]; + while ((length = in.read(buffer)) != -1) { + out.write(buffer, 0, length); + } + out.flush(); + + return BLOB_URL + BLOB_FILE_PREFIX + guid; + } + //catch (Exception e) { + // return null; + //} + finally { + IOUtil.close(in); + IOUtil.close(out); + } + + } + + public void doGet(HttpServletRequest request, + HttpServletResponse response) + throws IOException, ServletException { + + System.out.println("*** DisplayOracleBlobAsURLServlet begin----------------"); + + Blob photo = null; + Connection conn = null; + Statement stmt = null; + ResultSet rs = null; + + String id = request.getParameter("id").trim(); + String query = "select photo from MyPictures where id = "+id; + ServletOutputStream out = response.getOutputStream(); + response.setContentType("text/html"); + + try { + conn = getConnection(); + } + catch(Exception e) { + out.println("Person Photo"); + out.println("

Database Connection Problem.

"); + return; + } + + try { + stmt = conn.createStatement(); + rs = stmt.executeQuery(query); + out.println("Person Photo"); + + if (rs.next()) { + photo = rs.getBlob(1); + out.println("

photo id="+id+"

"+ + getBlobAsURL(photo)+""); + } + else { + out.println("

No photo found for id="+id+"

"); + return; + } + } + catch (Exception e) { + out.println("Error: Person Photo"); + out.println("

Error="+e.getMessage()+"

"); + return; + } + finally { + DatabaseUtil.close(rs); + DatabaseUtil.close(stmt); + DatabaseUtil.close(conn); + } + + } + + public void doPost( + HttpServletRequest request, + HttpServletResponse response) + throws IOException, ServletException { + doGet(request, response); + } + + +} diff --git a/sourceMetadata/jcb-package/src/servlets/DisplayOracleBlobServlet.class b/sourceMetadata/jcb-package/src/servlets/DisplayOracleBlobServlet.class new file mode 100644 index 0000000000000000000000000000000000000000..c52482910fc57dd1605ed89c6a20613f85926ac9 GIT binary patch literal 3504 zcma)9*?SvT75`mX(u_xAJ5k~!0wgoCgY@xQ!>UCJb}{+CNNo#DNM^qDma4~8M6_b#W@A%aY4dG z1&u;(PVAS&ayf#J;}Z&w;zfvS1$$_loN|-o)=s$LnvdPfZ7r;RO}n z!FNf&k&$py#rN=i2|rNrB9^HJegRC~T8Ph*Pu9Y4!7wx2VQ6=`NtM#_S=+O?G+sEYB#dn;hJV-v}2lzAL2(UevD-aKT+`#UKVZ-GVG};uN0J_-s6j+csWzW zPlaPWgW@nWnB{tAXwWk}lMf}i z$ER!D+#uw2SuNxj`OJRxSk`=O6{_lOcCY< zlSu=jc^e1Cz-_&Mwl~HigG%!^sXLS{PsIDscIxg8k5Et(h(9A}#?wym>@835+6)m~ z^?aUN8HVov%f!aWp$y2LU7AAV-TMVq8shZMP*l?eFJIV5q(DNcBvk-zAgPv(tTnp+ zd*pG;JG+!82p!pMa~r90kv6|r_ln&Qhrl zYQ7eT@nBWzO0I^*-1M@3U{5f#RKlr&UlmN1cB)ZAsi8s9|I6_}{`svFY5CjwNKCO?@=^*Wl_E5(iuvPlNkf1f}6BX2p zXAl9Obpmw=(OpY4a5`Ey5e-g8LsK1V2w&*z>RyAC2*!f9D;f?#qR)*a(?r^Kk*3{H zv4_^Zh@lzB=vKJWOn)?tOEv=kCR!6YvHm*bXnhe1n_`I|ON3Y=+!>9mLk*yahJZr_CW0$yNhn>>ee2jCK&(D`pokc4AE0eD7F@>% zi8B-n#pHFg1ds^F!s|H5u#Bcyn63{6Ftvi?_b4b^K3ujO)k@}t`tTZ##6oNMP%OBH z2UfeH5Bk=-*U?JW6xttRc&;f{(g(S>eEZm z`Hpz{EIdXP}uN*3D4Mx3m4;1oKML>Dfg8&9H#to9*`hw0yf zNAMJ({#lZEp78zx>3xyFU8Mg_?h^N(aS?yP9Nr~ueXSq4dF;tX>!!*0_3GTpyK_pi|X zEjqtO=i79CgU)NX>^DG|V1Jx!G7OhnfTFCUUqI^U>?-1sYELS}4CvHNsV%}IL=Rx} Ee`leYhyVZp literal 0 HcmV?d00001 diff --git a/sourceMetadata/jcb-package/src/servlets/DisplayOracleBlobServlet.java b/sourceMetadata/jcb-package/src/servlets/DisplayOracleBlobServlet.java new file mode 100644 index 0000000..7d16df1 --- /dev/null +++ b/sourceMetadata/jcb-package/src/servlets/DisplayOracleBlobServlet.java @@ -0,0 +1,101 @@ +import java.io.*; +import java.sql.*; + +import javax.servlet.*; +import javax.servlet.http.*; + +import jcb.util.DatabaseUtil; + + +public class DisplayOracleBlobServlet extends HttpServlet { + + public static Connection getConnection() throws Exception { + + String driver = "oracle.jdbc.driver.OracleDriver"; + String url = "jdbc:oracle:thin:@matrix:1521:caspian"; + String username = "mp"; + String password = "mp2"; + + Class.forName(driver); // load Oracle driver + Connection conn = DriverManager.getConnection(url, username, password); + return conn; + } + + public void doGet(HttpServletRequest request, + HttpServletResponse response) + throws IOException, ServletException { + + System.out.println("*** DisplayOracleBlobServlet begin----------------"); + + Blob photo = null; + Connection conn = null; + Statement stmt = null; + ResultSet rs = null; + + String id = request.getParameter("id").trim(); + String query = "select photo from MyPictures where id = "+id; + ServletOutputStream out = response.getOutputStream(); + + try { + conn = getConnection(); + } + catch(Exception e) { + response.setContentType("text/html"); + out.println("Person Photo"); + out.println("

Database Connection Problem.

"); + return; + } + + try { + stmt = conn.createStatement(); + rs = stmt.executeQuery(query); + if (rs.next()) { + photo = rs.getBlob(1); + } + else { + response.setContentType("text/html"); + out.println("Person Photo"); + out.println("

No photo found for id="+id+"

"); + return; + } + + response.setContentType("image/gif"); + InputStream in = photo.getBinaryStream(); + int length = (int)photo.length(); + System.out.println("lenght of the blob is " + length); + + int bufferSize = 1024; + byte[] buffer = new byte[bufferSize]; + + while ((length = in.read(buffer)) != -1) { + System.out.println("writing " + length + " bytes"); + out.write(buffer, 0, length); + } + + System.out.println("writing done."); + in.close(); + out.flush(); + } + catch (SQLException e) { + response.setContentType("text/html"); + out.println("Error: Person Photo"); + out.println("

Error="+e.getMessage()+"

"); + return; + } + finally { + DatabaseUtil.close(rs); + DatabaseUtil.close(stmt); + DatabaseUtil.close(conn); + } + + } + + public void doPost( + HttpServletRequest request, + HttpServletResponse response) + throws IOException, ServletException { + doGet(request, response); + } + + +} diff --git a/sourceMetadata/jcb-package/src/servlets/DisplayOracleClobAsURLServlet.class b/sourceMetadata/jcb-package/src/servlets/DisplayOracleClobAsURLServlet.class new file mode 100644 index 0000000000000000000000000000000000000000..6aceac5b86f6425b1424b2de91558781919289ae GIT binary patch literal 3974 zcma)9Yhx5w8GcUK-I>e|Nm-z$T&3(C~2unyxZZwb^NuUH;aI!ljgS$J+&MXA9 zYQ0vicST#ZNY%z#t;9=6N-f^8wf+&l_{A^!!TOw?y(I+dhdpP`nfG>{_j%tl`|f|= zd>g<{{6oVY45=7aaa6^Kict+?IHut^p3-mv<8nBu;S`=$@Qj9_6h1BIGjjNF5C$d` z#5Jr!LM}`VXE7<4Q*y9WoKx|UAd*OFNW)f<3F17mDjYexDsmbw;G%}dF|FW|ipwfK zs$nZWrsCNkK8{ZW@ku-v#Ha9SIebRNXH|So%70$P^D4fe;fwf^9A1#amsNa4zWl0! zuPOMtKuuTwQ0JNMzLB1;v7wQ1fl&WBnJ& zm`hEV*)d}x$(@yxrb`cLGwxb;T3}sWy%&XZJ{c{)U?5u0bll8HDMvt;YDs(Ipu;c( zw$)WAaeIHk$l{~;6ZRp~6&UfPr=yOUy^u8B=#=YbqEB)d^)^P#^EuOT_vek?Pt3_M z8gqaBaRuL2aD~TC*u%C%AKIv$%f`)KOCEA-x8-D##-*XG5l@<>xC`D|Bdr3&>g21KCl+(3taR*&q#ZYsQ*;~K`S`A#vAE%6EQ473 zow)5X7Qbsvnpp+k(eYipsNf|XUHG1Y@9X#hUY5gE1wYhr4X-c(OF7V)vyurjEAUu6 z7Ip1Z+;F28%?TruaiVtIwKF*<8Ykx6RyIF3>-Z6Vtm7wmMZv2&X7E#i^?9q79hHC# z<=jlpCBsZ3CC~kuj-TOm1wYsE3%sG@m$ILJGZTwO%O~8sW5 z@oW4>!EbfU$@4TiW|HKJoTcMVJ8>y;HfyIM-G*z(P@KrcDKl$EB32@DAfn)gj(IEy zRJ-Q17FAl?2knT& zFLKt-r4t;pQeVM4l1=Z*;qP*IkL{tX)055G*#kPBM4!OM`=TeXNg{Ob+7sCFfpiqu z{(td@W$Q7wm>2T2Z>SIh|ce!(oF`2+5$4V)1V;^rp&QRN0>L3hZwW z=55Hf=au?^kv3Si0t3q!xVux|y>qWdT6-=&5zV<)l7~FTiCJg;It+Dv!IM0Hx>TZU zZ%kMDmCSo(3FqIhE*Tv$(g{0t=vW_VuCPsePiu;Oy%Gij&o*MF69Uc49I_H6?>;K@ zBBG_bwztJAqy(JotfVcS9(3ZC<#m{fJ7vka1lBI+m8T6P&Ge)@mA}0XSF)mv3hR&k zi;?^5PIcCk(Ef{A%O!{k*L{5wGymCS&Y_X*_os5k2U}b|^Vh`KEj_`KDN$Qm1?=u=ucrUv+!<)w%*3@FDDlz&@_35aW7(#k!5_0~PCb z_$kZp4vq(@v5~Xj>~FXMG0O*mPL6^6W)Ri#>Y`aG+D~VG&JTyGj)Ye9hkOGe|6s#B z0#7wIHP1td`NF>IB@3IN@OeFT!nC%5mL7smcdM|8JDbtNw?2B=3QgWTo)2-7dm7)o zA^OEY!)?@x!Nz&0P4lR3zCI6a@Fs%eH=u`B&Y`B6zd6*#d<_eDK%l?zHdcw4zo-!Q zU%!b}<6++oga#3GrTb|C}KXsCt`ud(E0_0tN1asA*K|8 zc!)qq!19o*O$&HfAXeQJ+PHvCRR~vyHqRk4k1a9Z3|e9uH@0yjTwTih zsAq=)vti!?9-}FL*dJCGP)802!hr?U3%rPZ;Q(JZRAI1es8Je{frOZ+8ZuAvAk@Nv zWT3?v>?{jMx$Oy;U4{em*b(;6Q_eS!U9(HpGdL{6FUGxFTDUvzB}%ig;F6ti@YXEr zr3Z&GK$cJAj?fEp2l3WLRLHqQ9F%i`AFq-RveK%kJx!^TlsLtIs88b}o}m|m9GJihWX2VkxXM4E?_dh=;T-P3!9U^RU&!I#{G0h7 zuHT0%e8`DvTwru*Q3G2<;fPl5@8fQ69z-M&4g!6Sk2} dEBH=nXk>C)%MC@NFi6n=|HLj<9^gLn`#+HY2$BE* literal 0 HcmV?d00001 diff --git a/sourceMetadata/jcb-package/src/servlets/DisplayOracleClobAsURLServlet.java b/sourceMetadata/jcb-package/src/servlets/DisplayOracleClobAsURLServlet.java new file mode 100644 index 0000000..3d86c02 --- /dev/null +++ b/sourceMetadata/jcb-package/src/servlets/DisplayOracleClobAsURLServlet.java @@ -0,0 +1,127 @@ +import java.io.*; +import java.sql.*; + +import javax.servlet.*; +import javax.servlet.http.*; + +import jcb.util.DatabaseUtil; +import jcb.util.IOUtil; +import jcb.util.RandomGUID; + +public class DisplayOracleClobAsURLServlet extends HttpServlet { + + // directory where clob data will be placed as files. + private static final String CLOB_DIRECTORY = + "c:/tomcat/webapps/octopus/clobDir"; + + // CLOB_DIRECTORY as a URL + private static final String CLOB_URL = + "http://localhost:8000/octopus/clobDir"; + + private static final String CLOB_FILE_PREFIX = "/clob-"; + + public static Connection getConnection() throws Exception { + String driver = "oracle.jdbc.driver.OracleDriver"; + String url = "jdbc:oracle:thin:@localhost:1521:caspian"; + String username = "scott"; + String password = "tiger"; + //String password = "tiger222"; // wrong password + Class.forName(driver); // load Oracle driver + Connection conn = DriverManager.getConnection(url, username, password); + return conn; + } + + private static String getClobAsURL(Clob Clob) throws Exception { + + InputStream in = null; + FileOutputStream out = null; + try { + + if (Clob == null) { + return null; + } + + // get a random GUID for Clob filename + String guid = RandomGUID.getGUID(); + String ClobFile = CLOB_DIRECTORY + CLOB_FILE_PREFIX + guid; + + in = Clob.getAsciiStream(); + if (in == null) { + return null; + } + + out = new FileOutputStream(ClobFile); + int length = (int) Clob.length(); + + int bufferSize = 1024; + byte[] buffer = new byte[bufferSize]; + while ((length = in.read(buffer)) != -1) { + out.write(buffer, 0, length); + } + out.flush(); + + return CLOB_URL + CLOB_FILE_PREFIX + guid; + } + finally { + IOUtil.close(in); + IOUtil.close(out); + } + + } + + public void doGet(HttpServletRequest request, + HttpServletResponse response) + throws IOException, ServletException { + + Clob clob = null; + Connection conn = null; + Statement stmt = null; + ResultSet rs = null; + + String id = request.getParameter("id").trim(); + String query = "select fileBody from DataFiles where id = "+id; + ServletOutputStream out = response.getOutputStream(); + response.setContentType("text/html"); + out.println("DisplayOracleClobAsURLServlet"); + + try { + conn = getConnection(); + } + catch(Exception e) { + out.println("

Database Connection Problem.

"); + out.println("

"+e.getMessage()+"

"); + return; + } + + try { + stmt = conn.createStatement(); + rs = stmt.executeQuery(query); + + if (rs.next()) { + clob = rs.getClob(1); + out.println("

file id="+id+"

"+ + getClobAsURL(clob)+""); + } + else { + out.println("

No File found for id="+id+"

"); + return; + } + } + catch (Exception e) { + out.println("

Error="+e.getMessage()+"

"); + return; + } + finally { + DatabaseUtil.close(rs); + DatabaseUtil.close(stmt); + DatabaseUtil.close(conn); + } + } + + public void doPost( + HttpServletRequest request, + HttpServletResponse response) + throws IOException, ServletException { + doGet(request, response); + } +} diff --git a/sourceMetadata/jcb-package/src/servlets/DisplayOracleClobServlet.class b/sourceMetadata/jcb-package/src/servlets/DisplayOracleClobServlet.class new file mode 100644 index 0000000000000000000000000000000000000000..b7cbeb0b402b2290c3437d5f2d2f24fca87cba4a GIT binary patch literal 3227 zcma)9*;gCa8UI}wX@+4iwrsGK1V?t_6azx_LX!$vaSh%cQIh^mr1zgl|$-pG0bQHTVjTr-%aYe(d zft`x)s+zB<;d&RI!LvG^Q}Yc2@5Ki-d`QQK4SYngKd>=-z5 zU7%y!tw@2MNxLSCjcQ4HSFMu6o$fgqjJvg(EC;q*6WBL!WOBi}ZDsviPPTP0CSaUd zEX%s0@&)1*_nZs_t_+0Ki&B(LZS z`FUwo3i-ee99bBjoIagCvuIW8j?8DHy?i#L(C{sRp?rx(k>^A~*;KN8nQoycJ>$7V zTXlpiCy2?8{QPLa#J82pd$>1R$Y&$|(8Pj<@0j>5-q7$p6W_-VH2l!SkMLs?KfzC# z-lnqSg`yiqBz@Cu)G8c3hTvo*^!PnOe`ez6_=OsNsfJ%^ST^x%{Kmwa_^m)Pbn=d8 z2Mm0=;@0GdK<{QT%wC>s3)1L)f^^37TrZb?K&%9IwQLW`Y3!i~0Y}oUOvc3fkrUXz z9lit(C_A?=!)C5+H+x~a&5gU*HfpJjpr-|qamVsm`WmBLw5qJd!%^{P+weNJ(LKVg zkb#|}Z!?Bb`Au0hi=`wmbsqsy_h}b-@6L8DYFEqH*(E=aRklC3!P@POWYGH=R#m{- zl2(fz1D*Yj?%1me=X9EsZ3Mb~8 zaZ;q4`!pdLhIY#?^CTB#xe>_A4e2fMcGy0Mit&o{8%{7QgDv7VcbTgiyKQ*&-XNN2 zzPhKVdf-Aka=AwVy$j`1wh`D)w%ItZalz}R?6^K1-nU`PR>ca0?I$e{)ye)go>mv; z-OBrZ)BVV%gd=Nn!F*`!#R#yojZza5eFGPpCb#1a2l>=E$`=#R0io_(jwiV4=PWqK z2j7BN;SYgPj)`!y6P@bXK`bPlzz#A4`;)Ot$sLo)j;Un4IJkzyGeg6fHE6%zS&QKdktTRXoBu*&oRv!Ah!Q9S0~Xo{FdRbvznFE|E&CBQ5X-dQu4^6jHfmw zH$@&&B9%$W$2R4q5^H!o6<@>QRL2^gSjnv8JpxY}8Kcj5bsYm8$eF3mlu6af^CR^9 zE|z6n4!s!KV*aqwMe{QcR+sC(OIoV?FG|k{^{ha{SzJPqsdx!*i@ki5z9VActky*) zO07AIy`m7#MKKfZMCLOB Example"); + out.println("

Database Connection Problem.

"); + out.println("
"+e.getMessage()+"
"); + return; + } + + try { + stmt = conn.createStatement(); + rs = stmt.executeQuery(query); + if (rs.next()) { + fileAsCLOB = rs.getClob(1); + } + else { + out.println("CLOB Example"); + out.println("

No file found for id="+id+"

"); + return; + } + + // Materialize the CLOB as a String object (get the whole clob). + long length = fileAsCLOB.length(); + // note that the first character is at position 1 + String fileAsString = fileAsCLOB.getSubString(1, (int) length); + + // write it for display + out.println(fileAsString); + System.out.println("CLOB writing done."); + } + catch (SQLException e) { + out.println("Error: CLOB Example"); + out.println("

Error="+e.getMessage()+"

"); + return; + } + finally { + DatabaseUtil.close(rs); + DatabaseUtil.close(stmt); + DatabaseUtil.close(conn); + } + System.out.println("-- DisplayOracleClobServlet end --"); + } + + public void doPost( + HttpServletRequest request, + HttpServletResponse response) + throws IOException, ServletException { + doGet(request, response); + } +} diff --git a/sourceMetadata/jcb-package/src/servlets/GetColumns.class b/sourceMetadata/jcb-package/src/servlets/GetColumns.class new file mode 100644 index 0000000000000000000000000000000000000000..2f8ba0f1367bfbe115b4a192917a47839dd6ab88 GIT binary patch literal 5168 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"); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + while (columns.next()) { + buffer.append(""); + } + buffer.append("
CatalogSchemaTable NameColumn NameData TypeType NameColumn SizeIs Nullable?Is Nullable?Ordinal Position
"); + buffer.append(columns.getString("TABLE_CAT")); + buffer.append(""); + buffer.append(columns.getString("TABLE_SCHEM")); + buffer.append(""); + buffer.append(columns.getString("TABLE_NAME")); + buffer.append(""); + buffer.append(columns.getString("COLUMN_NAME")); + buffer.append(""); + buffer.append(columns.getShort("DATA_TYPE")); + buffer.append(""); + buffer.append(columns.getString("TYPE_NAME")); + buffer.append(""); + buffer.append(columns.getString("COLUMN_SIZE")); + buffer.append(""); + int nullable = columns.getInt("NULLABLE"); + if (nullable == DatabaseMetaData.columnNullable) { + buffer.append("true"); + } + else if (nullable == DatabaseMetaData.columnNoNulls) { + buffer.append("false"); + } + else { + buffer.append("unknown"); + } + buffer.append(""); + buffer.append(columns.getString("IS_NULLABLE")); + buffer.append(""); + buffer.append(columns.getString("ORDINAL_POSITION")); + buffer.append("
"); + out.println(buffer.toString()); + } + + private static void printXML(HttpServletResponse response, + ResultSet columns) + throws Exception { + response.setContentType("text/xml"); + PrintWriter out = response.getWriter(); + StringBuilder buffer = new StringBuilder(); + buffer.append(""); + buffer.append(""); + while (columns.next()) { + buffer.append(""); + buffer.append(columns.getString("TABLE_CAT")); + buffer.append(""); + buffer.append(columns.getString("TABLE_SCHEM")); + buffer.append(""); + buffer.append(columns.getString("TABLE_NAME")); + buffer.append(""); + buffer.append(columns.getString("COLUMN_NAME")); + buffer.append(""); + buffer.append(columns.getShort("DATA_TYPE")); + buffer.append(""); + buffer.append(columns.getString("TYPE_NAME")); + buffer.append(""); + buffer.append(columns.getString("COLUMN_SIZE")); + buffer.append(""); + int nullable = columns.getInt("NULLABLE"); + if (nullable == DatabaseMetaData.columnNullable) { + buffer.append("true"); + } + else if (nullable == DatabaseMetaData.columnNoNulls) { + buffer.append("false"); + } + else { + buffer.append("unknown"); + } + buffer.append(""); + buffer.append(columns.getString("IS_NULLABLE")); + buffer.append(""); + buffer.append(columns.getString("ORDINAL_POSITION")); + buffer.append(""); + } + buffer.append(""); + out.println(buffer.toString()); + } + + private static void printError(HttpServletResponse response, + String message) { + try { + PrintWriter out = response.getWriter(); + StringBuffer buffer = new StringBuffer(); + buffer.append(""); + buffer.append(message); + buffer.append(""); + out.println(buffer); + } + catch(Exception ignore) { + } + } + + + /** + * Retrieves a description of the given table's columns. + * @param conn the Connection object + * @param tableName name of a table in the database. + * @return the list of columns as a ResultSet object + * @exception Failed to get the table's columns. + */ + public static ResultSet getColumns(Connection conn, + String tableName) + throws Exception { + System.out.println("getColumns begin"); + if ((tableName == null) || (tableName.length() == 0)) { + return null; + } + + DatabaseMetaData meta = conn.getMetaData(); + if (meta == null) { + return null; + } + + // + // The Oracle database stores its table names as + // Upper-Case; if you pass a table name in lowercase + // characters, it will not work. MySQL database does + // not care if table name is uppercase/lowercase. + // + System.out.println("getColumns begin 2"); + ResultSet columns = meta.getColumns(null, null, tableName.toUpperCase(), null); + System.out.println("getColumns begin 3 columns ="+columns); + return columns; + } +} diff --git a/sourceMetadata/jcb-package/src/servlets/GetExportedKeys.class b/sourceMetadata/jcb-package/src/servlets/GetExportedKeys.class new file mode 100644 index 0000000000000000000000000000000000000000..1f8602c642f6de399f6fd6c9ad9141c3a2224616 GIT binary patch literal 6111 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 literal 0 HcmV?d00001 diff --git a/sourceMetadata/jcb-package/src/servlets/GetExportedKeys.java b/sourceMetadata/jcb-package/src/servlets/GetExportedKeys.java new file mode 100644 index 0000000..845e05b --- /dev/null +++ b/sourceMetadata/jcb-package/src/servlets/GetExportedKeys.java @@ -0,0 +1,273 @@ +import java.sql.*; +import javax.servlet.*; +import javax.servlet.http.*; + +import java.io.PrintWriter; +import java.io.IOException; + +import java.sql.*; +import javax.servlet.*; +import javax.servlet.http.*; + +import jcb.util.DatabaseUtil; +import jcb.db.VeryBasicConnectionManager; + +public class GetExportedKeys extends HttpServlet { + + public void doGet(HttpServletRequest request, + HttpServletResponse response) + throws ServletException, IOException { + Connection conn = null; + ResultSet exportedKeys = null; + try { + String dbVendor = request.getParameter("vendor").trim(); + String outputFormat = request.getParameter("format").trim(); + String table = request.getParameter("table").trim(); + conn = VeryBasicConnectionManager.getConnection(dbVendor); + + if (dbVendor.equals("mysql")) { + String catalog = request.getParameter("catalog").trim(); + exportedKeys = getExportedKeys(conn, + catalog, // catalog, + null, // schema + table); + } + else if (dbVendor.equals("oracle")) { + String schema = request.getParameter("schema").trim(); + exportedKeys = getExportedKeys(conn, + null, // catalog, + schema, // schema + table); + } + else { + printError(response, "unknown db vendor"); + return; + } + + if (outputFormat.equals("xml")) { + printXML(response, exportedKeys); + } + else { + printHTML(response, exportedKeys); + } + + } + catch(Exception e) { + e.printStackTrace(); + printError(response, e.getMessage()); + } + finally { + DatabaseUtil.close(exportedKeys); + DatabaseUtil.close(conn); + } + + } // end doGet + + + private static void printHTML(HttpServletResponse response, + ResultSet exportedKeys) + throws Exception { + response.setContentType("text/html"); + PrintWriter out = response.getWriter(); + StringBuilder buffer = new StringBuilder(); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + while (exportedKeys.next()) { + buffer.append(""); + } + buffer.append("
PK CatalogPK SchemaPK TablePK ColumnFK CatalogFK SchemaFK TableFK ColumnFK Seq.Update RuleDelete RuleFK NamePK NameDeferrability
"); + buffer.append(exportedKeys.getString("PKTABLE_CAT")); + buffer.append(""); + buffer.append(exportedKeys.getString("PKTABLE_SCHEM")); + buffer.append(""); + buffer.append(exportedKeys.getString("PKTABLE_NAME")); + buffer.append(""); + buffer.append(exportedKeys.getString("PKCOLUMN_NAME")); + buffer.append(""); + buffer.append(exportedKeys.getString("FKTABLE_CAT")); + buffer.append(""); + buffer.append(exportedKeys.getString("FKTABLE_SCHEM")); + buffer.append(""); + buffer.append(exportedKeys.getString("FKTABLE_NAME")); + buffer.append(""); + buffer.append(exportedKeys.getString("FKCOLUMN_NAME")); + buffer.append(""); + buffer.append(exportedKeys.getShort("KEY_SEQ")); + buffer.append(""); + short updateRule = exportedKeys.getShort("UPDATE_RULE"); + buffer.append(getUpdateRule(updateRule)); + buffer.append(""); + short deleteRule = exportedKeys.getShort("DELETE_RULE"); + buffer.append(getDeleteRule(deleteRule)); + buffer.append(""); + buffer.append(exportedKeys.getString("FK_NAME")); + buffer.append(""); + buffer.append(exportedKeys.getString("PK_NAME")); + buffer.append(""); + short deferrability = exportedKeys.getShort("DEFERRABILITY"); + buffer.append(getDeferrability(deferrability)); + buffer.append("
"); + out.println(buffer.toString()); + } + + private static void printXML(HttpServletResponse response, + ResultSet exportedKeys) + throws Exception { + response.setContentType("text/xml"); + PrintWriter out = response.getWriter(); + StringBuilder buffer = new StringBuilder(); + buffer.append(""); + buffer.append(""); + while (exportedKeys.next()) { + buffer.append(""); + buffer.append(exportedKeys.getString("PKTABLE_CAT")); + buffer.append(""); + buffer.append(exportedKeys.getString("PKTABLE_SCHEM")); + buffer.append(""); + buffer.append(exportedKeys.getString("PKTABLE_NAME")); + buffer.append(""); + buffer.append(exportedKeys.getString("PKCOLUMN_NAME")); + buffer.append(""); + buffer.append(exportedKeys.getString("FKTABLE_CAT")); + buffer.append(""); + buffer.append(exportedKeys.getString("FKTABLE_SCHEM")); + buffer.append(""); + buffer.append(exportedKeys.getString("FKTABLE_NAME")); + buffer.append(""); + buffer.append(exportedKeys.getString("FKCOLUMN_NAME")); + buffer.append(""); + buffer.append(exportedKeys.getString("KEY_SEQ")); + buffer.append(""); + short updateRule = exportedKeys.getShort("UPDATE_RULE"); + buffer.append(getUpdateRule(updateRule)); + buffer.append(""); + short deleteRule = exportedKeys.getShort("DELETE_RULE"); + buffer.append(getDeleteRule(deleteRule)); + buffer.append(""); + buffer.append(exportedKeys.getString("FK_NAME")); + buffer.append(""); + buffer.append(exportedKeys.getString("PK_NAME")); + buffer.append(""); + short deferrability = exportedKeys.getShort("DEFERRABILITY"); + buffer.append(getDeferrability(deferrability)); + buffer.append(""); + } + buffer.append(""); + out.println(buffer.toString()); + } + + private static void printError(HttpServletResponse response, + String message) { + try { + PrintWriter out = response.getWriter(); + StringBuilder buffer = new StringBuilder(); + buffer.append(""); + buffer.append(message); + buffer.append(""); + out.println(buffer.toString()); + } + catch(Exception ignore) { + } + } + + /** + * Get the stored-procedures names. + * @param conn the Connection object + * @catalog database catalog name + * @schemaPattern database schema pattern + * @procedureNamePattern database procedure name pattern + * @return a table of stored procedures names + * as a ResultSet object. + * Each element of XML document will have the name and + * type of a stored procedure. + * + */ + public static ResultSet getExportedKeys(Connection conn, + String catalog, + String schema, + String table) + throws Exception { + + if (table == null) { + return null; + } + + DatabaseMetaData meta = conn.getMetaData(); + if (meta == null) { + return null; + } + + return meta.getExportedKeys(catalog, schema, table.toUpperCase()); + } + + + private static String getUpdateRule(short updateRule) { + if (updateRule == DatabaseMetaData.importedKeyNoAction) { + return "importedKeyNoAction"; + } + else if (updateRule == DatabaseMetaData.importedKeyCascade) { + return "importedKeyCascade"; + } + else if (updateRule == DatabaseMetaData.importedKeySetNull) { + return "importedKeySetNull"; + } + else if (updateRule == DatabaseMetaData.importedKeySetDefault) { + return "importedKeySetDefault"; + } + else if (updateRule == DatabaseMetaData.importedKeyRestrict) { + return "importedKeyRestrict"; + } + else { + return "nobody knows"; + } + } + + private static String getDeleteRule(short deleteRule) { + if (deleteRule == DatabaseMetaData.importedKeyNoAction) { + return "importedKeyNoAction"; + } + else if (deleteRule == DatabaseMetaData.importedKeyCascade) { + return "importedKeyCascade"; + } + else if (deleteRule == DatabaseMetaData.importedKeySetNull) { + return "importedKeySetNull"; + } + else if (deleteRule == DatabaseMetaData.importedKeyRestrict) { + return "importedKeyRestrict"; + } + else if (deleteRule == DatabaseMetaData.importedKeySetDefault) { + return "importedKeySetDefault"; + } + else { + return "nobody knows"; + } + } + + private static String getDeferrability(short deferrability) { + if (deferrability == DatabaseMetaData.importedKeyInitiallyDeferred) { + return "importedKeyInitiallyDeferred"; + } + else if (deferrability == DatabaseMetaData.importedKeyInitiallyImmediate) { + return "importedKeyInitiallyImmediate"; + } + else if (deferrability == DatabaseMetaData.importedKeyNotDeferrable) { + return "importedKeyNotDeferrable"; + } + else { + return "nobody knows"; + } + } +} \ No newline at end of file diff --git a/sourceMetadata/jcb-package/src/servlets/GetForeignKeys.class b/sourceMetadata/jcb-package/src/servlets/GetForeignKeys.class new file mode 100644 index 0000000000000000000000000000000000000000..8736d9a70cdd944752719a2f9dbdf8698c2bcc2b GIT binary patch literal 6126 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 D;$Tnt literal 0 HcmV?d00001 diff --git a/sourceMetadata/jcb-package/src/servlets/GetForeignKeys.java b/sourceMetadata/jcb-package/src/servlets/GetForeignKeys.java new file mode 100644 index 0000000..203f1af --- /dev/null +++ b/sourceMetadata/jcb-package/src/servlets/GetForeignKeys.java @@ -0,0 +1,270 @@ +import java.sql.*; +import javax.servlet.*; +import javax.servlet.http.*; + +import java.io.PrintWriter; +import java.io.IOException; + +import java.sql.*; +import javax.servlet.*; +import javax.servlet.http.*; + +import jcb.util.DatabaseUtil; +import jcb.db.VeryBasicConnectionManager; + +public class GetForeignKeys extends HttpServlet { + + public void doGet(HttpServletRequest request, + HttpServletResponse response) + throws ServletException, IOException { + Connection conn = null; + ResultSet foreignKeys = null; + try { + String dbVendor = request.getParameter("vendor").trim(); + String outputFormat = request.getParameter("format").trim(); + String table = request.getParameter("table").trim(); + conn = VeryBasicConnectionManager.getConnection(dbVendor); + + if (dbVendor.equals("mysql")) { + String catalog = request.getParameter("catalog").trim(); + foreignKeys = getForeignKeys(conn, + catalog, // catalog, + null, // schema + table); + } + else if (dbVendor.equals("oracle")) { + String schema = request.getParameter("schema").trim(); + foreignKeys = getForeignKeys(conn, + null, // catalog, + schema, // schema + table); + } + else { + printError(response, "unknown db vendor"); + return; + } + + if (outputFormat.equals("xml")) { + printXML(response, foreignKeys); + } + else { + printHTML(response, foreignKeys); + } + + } + catch(Exception e) { + e.printStackTrace(); + printError(response, e.getMessage()); + } + finally { + DatabaseUtil.close(foreignKeys); + DatabaseUtil.close(conn); + } + + } // end doGet + + + private static void printHTML(HttpServletResponse response, + ResultSet foreignKeys) + throws Exception { + response.setContentType("text/html"); + PrintWriter out = response.getWriter(); + StringBuilder buffer = new StringBuilder(); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + while (foreignKeys.next()) { + buffer.append(""); + } + buffer.append("
PK CatalogPK SchemaPK TablePK ColumnFK CatalogFK SchemaFK TableFK ColumnFK Seq.Update RuleDelete RuleFK NamePK NameDeferrability
"); + buffer.append(foreignKeys.getString("PKTABLE_CAT")); + buffer.append(""); + buffer.append(foreignKeys.getString("PKTABLE_SCHEM")); + buffer.append(""); + buffer.append(foreignKeys.getString("PKTABLE_NAME")); + buffer.append(""); + buffer.append(foreignKeys.getString("PKCOLUMN_NAME")); + buffer.append(""); + buffer.append(foreignKeys.getString("FKTABLE_CAT")); + buffer.append(""); + buffer.append(foreignKeys.getString("FKTABLE_SCHEM")); + buffer.append(""); + buffer.append(foreignKeys.getString("FKTABLE_NAME")); + buffer.append(""); + buffer.append(foreignKeys.getString("FKCOLUMN_NAME")); + buffer.append(""); + buffer.append(foreignKeys.getShort("KEY_SEQ")); + buffer.append(""); + short updateRule = foreignKeys.getShort("UPDATE_RULE"); + buffer.append(getUpdateRule(updateRule)); + buffer.append(""); + short deleteRule = foreignKeys.getShort("DELETE_RULE"); + buffer.append(getDeleteRule(deleteRule)); + buffer.append(""); + buffer.append(foreignKeys.getString("FK_NAME")); + buffer.append(""); + buffer.append(foreignKeys.getString("PK_NAME")); + buffer.append(""); + short deferrability = foreignKeys.getShort("DEFERRABILITY"); + buffer.append(getDeferrability(deferrability)); + buffer.append("
"); + out.println(buffer.toString()); + } + + private static void printXML(HttpServletResponse response, + ResultSet foreignKeys) + throws Exception { + response.setContentType("text/xml"); + PrintWriter out = response.getWriter(); + StringBuilder buffer = new StringBuilder(); + buffer.append(""); + buffer.append(""); + while (foreignKeys.next()) { + buffer.append(""); + buffer.append(foreignKeys.getString("PKTABLE_CAT")); + buffer.append(""); + buffer.append(foreignKeys.getString("PKTABLE_SCHEM")); + buffer.append(""); + buffer.append(foreignKeys.getString("PKTABLE_NAME")); + buffer.append(""); + buffer.append(foreignKeys.getString("PKCOLUMN_NAME")); + buffer.append(""); + buffer.append(foreignKeys.getString("FKTABLE_CAT")); + buffer.append(""); + buffer.append(foreignKeys.getString("FKTABLE_SCHEM")); + buffer.append(""); + buffer.append(foreignKeys.getString("FKTABLE_NAME")); + buffer.append(""); + buffer.append(foreignKeys.getString("FKCOLUMN_NAME")); + buffer.append(""); + buffer.append(foreignKeys.getString("KEY_SEQ")); + buffer.append(""); + short updateRule = foreignKeys.getShort("UPDATE_RULE"); + buffer.append(getUpdateRule(updateRule)); + buffer.append(""); + short deleteRule = foreignKeys.getShort("DELETE_RULE"); + buffer.append(getDeleteRule(deleteRule)); + buffer.append(""); + buffer.append(foreignKeys.getString("FK_NAME")); + buffer.append(""); + buffer.append(foreignKeys.getString("PK_NAME")); + buffer.append(""); + short deferrability = foreignKeys.getShort("DEFERRABILITY"); + buffer.append(getDeferrability(deferrability)); + buffer.append(""); + } + buffer.append(""); + out.println(buffer.toString()); + } + + private static void printError(HttpServletResponse response, + String message) { + try { + PrintWriter out = response.getWriter(); + StringBuilder buffer = new StringBuilder(); + buffer.append(""); + buffer.append(message); + buffer.append(""); + out.println(buffer.toString()); + } + catch(Exception ignore) { + } + } + + /** + * Get the Foreign Keys. + * @param conn the Connection object + * @catalog database catalog name + * @schemaPattern database schema pattern + * @procedureNamePattern database procedure name pattern + * @return a table of Foreign Keys as a ResultSet object. + * + */ + public static ResultSet getForeignKeys(Connection conn, + String catalog, + String schema, + String table) + throws Exception { + + if (table == null) { + return null; + } + + DatabaseMetaData meta = conn.getMetaData(); + if (meta == null) { + return null; + } + + return meta.getImportedKeys(catalog, schema, table.toUpperCase()); + } + + + private static String getUpdateRule(short updateRule) { + if (updateRule == DatabaseMetaData.importedKeyNoAction) { + return "importedKeyNoAction"; + } + else if (updateRule == DatabaseMetaData.importedKeyCascade) { + return "importedKeyCascade"; + } + else if (updateRule == DatabaseMetaData.importedKeySetNull) { + return "importedKeySetNull"; + } + else if (updateRule == DatabaseMetaData.importedKeySetDefault) { + return "importedKeySetDefault"; + } + else if (updateRule == DatabaseMetaData.importedKeyRestrict) { + return "importedKeyRestrict"; + } + else { + return "nobody knows"; + } + } + + private static String getDeleteRule(short deleteRule) { + if (deleteRule == DatabaseMetaData.importedKeyNoAction) { + return "importedKeyNoAction"; + } + else if (deleteRule == DatabaseMetaData.importedKeyCascade) { + return "importedKeyCascade"; + } + else if (deleteRule == DatabaseMetaData.importedKeySetNull) { + return "importedKeySetNull"; + } + else if (deleteRule == DatabaseMetaData.importedKeyRestrict) { + return "importedKeyRestrict"; + } + else if (deleteRule == DatabaseMetaData.importedKeySetDefault) { + return "importedKeySetDefault"; + } + else { + return "nobody knows"; + } + } + + private static String getDeferrability(short deferrability) { + if (deferrability == DatabaseMetaData.importedKeyInitiallyDeferred) { + return "importedKeyInitiallyDeferred"; + } + else if (deferrability == DatabaseMetaData.importedKeyInitiallyImmediate) { + return "importedKeyInitiallyImmediate"; + } + else if (deferrability == DatabaseMetaData.importedKeyNotDeferrable) { + return "importedKeyNotDeferrable"; + } + else { + return "nobody knows"; + } + } +} diff --git a/sourceMetadata/jcb-package/src/servlets/GetRowSetMetaData.class b/sourceMetadata/jcb-package/src/servlets/GetRowSetMetaData.class new file mode 100644 index 0000000000000000000000000000000000000000..0409929522290d8b00fa37fd8cec44bcf7acfe29 GIT binary patch literal 2111 zcmah~YgZFj6x}x_Oc(}5p2qs9S}CtEK&!P0@|2g7K#7W?ZJi_+3{7U@%tY}=^mq8R ze2Gxks^9w?`dhlX?@R;*Ev&^o_nv#_oW1uw=jQK!|NINUC_EisV*xo?#r_D&F8*fH5WPLLdTkXQInpZKJl1Wb!<?%{euX;m2PUX=Df-sVjWiM7`TF~)b^#ci;k<| zp@DTg((u^82A)t%O60!Q@YKN1_{G2g1_k22-0{twN?F6N2A+XY@+fF18j!FwY#P|Y zbAb+(A!K+Un}HIZ7#KoQ;6lNvm|o2`UFVg@3tE@?5aLp$%Glcmep9i_DpqF@tK>A~ zTX##obPZHs8*o&_EybhzFk>k5Ol@;hQcGj}xnC(yjOU%=>j?u@ybw4&ZU)P7RtEPJ zc%D3aOeld%D(sgF>DYlrfgOZ?%BzR%X*mF+^_EauIJy!08%D-{k)IAht?mdf5rFo$k|{x73B(gZ|)65+6* zc{i*FCh?{1-+x_Y{dRpW3mdYTXu@I;==ng3I@5VrHLO)hatxVCZvl9D4@B>L>qC)LY4K^Ht(=#@@fo z2VVU}A=FF2@fuebX$5U;;4Q>1Cj#GaYzmxh9IvAnk>Kb*w9VWritJ!}WFMy@s3V$+ z4z|Y*7O_Nh4^7!*BDM!D)il%|-$!!<05LA{W>VJPmA!bRK89*TqvkID>Pzz#o*W90y2vjFeL( zJB@EKhdxHQhP&jK<9eOz4cce41@v>KSVy?(hprw!&XqvF(>BrG7MXWwd;At>v&q4I zv`3H}*hfbM@6btaS0+i4-K1Ja4~f-rE)o4B6$>V@_YA@h_^S&3-wbRBe;6(F4Rd#d zX-7$Bj3jOl_$@+8^P5R}r})JrsZ0eh)eW}tG+$QE6vzs{kJ2hg6q-mA#B@HJZ2zi` z3+u_jU~Ipr%uuq9OK%X(>;`w-N2aZusax+2?spy<7O3SSy0Jth?=rXPNj43n<# K^e|6HVEzY2%?J|! literal 0 HcmV?d00001 diff --git a/sourceMetadata/jcb-package/src/servlets/GetRowSetMetaData.java b/sourceMetadata/jcb-package/src/servlets/GetRowSetMetaData.java new file mode 100644 index 0000000..7bf33ff --- /dev/null +++ b/sourceMetadata/jcb-package/src/servlets/GetRowSetMetaData.java @@ -0,0 +1,81 @@ +import java.sql.*; +import javax.sql.*; +import javax.servlet.*; +import javax.servlet.http.*; + +import javax.sql.rowset.WebRowSet; +import com.sun.rowset.WebRowSetImpl; + +import java.io.StringWriter; +import java.io.PrintWriter; +import java.io.IOException; + +import jcb.util.DatabaseUtil; +import jcb.db.VeryBasicConnectionManager; + +public class GetRowSetMetaData extends HttpServlet { + + public void doGet(HttpServletRequest request, + HttpServletResponse response) + throws ServletException, IOException { + Connection conn = null; + try { + String dbVendor = request.getParameter("vendor").trim(); + String sqlQuery = request.getParameter("query").trim(); + conn = VeryBasicConnectionManager.getConnection(dbVendor); + + // create metadata + String metadata = getMetaData(conn, sqlQuery); + + // write xml to client + response.setContentType("text/xml"); + PrintWriter out = response.getWriter(); + out.println(metadata); + } + catch(Exception e) { + printError(response, e.getMessage()); + } + finally { + DatabaseUtil.close(conn); + } + } // end doGet + + private static String getMetaData(Connection conn, + String sqlQuery) + throws Exception { + StringWriter writer = null; + try { + WebRowSet webRS = new WebRowSetImpl(); + webRS.setCommand(sqlQuery); + webRS.execute(conn); + + // writer to hold and manipulate XML data. + writer = new StringWriter(); + + // generate the XML document + webRS.writeXml(writer); + + // Convert the writer object data to a XML String. + return writer.toString(); + } + finally { + // Close the Writer object. + writer.close(); + } + } + + private static void printError(HttpServletResponse response, + String message) { + try { + PrintWriter out = response.getWriter(); + StringBuffer buffer = new StringBuffer(); + buffer.append(""); + buffer.append(message); + buffer.append(""); + out.println(buffer); + } + catch(Exception ignore) { + } + } + +} diff --git a/sourceMetadata/jcb-package/src/servlets/GetSPColumns.class b/sourceMetadata/jcb-package/src/servlets/GetSPColumns.class new file mode 100644 index 0000000000000000000000000000000000000000..210ec3fc9e39b12e5cf0836ca564babe5ad565c0 GIT binary patch literal 5041 zcmb7Id3;<|75-kC$=oEbw0)4K6S_;HDX-Yat+ek8rGn1A@jgy&2JMCm% zc=M*T?3*kFipahw70|c=DPY=wKv@I|qM*2-2q=OJ3X1xN|ES-6@6BYg6!bU0-(Ai< z?=1H_=iGbeg?~TtIDnP-XBA>F1O}^d7R)N-VF?rjwpZb7>=4)~N#_WhD{x*FK8^DQ zE)clThl{E(1BPramdzysm&*0as_+F|E}JU^u9TFkWV6eMtE*6lYXq*X#%^3En=cAn zFYqOS8w73?xJlqjj3mjBXH%U^o+Z7`4!ql3ihQ8kD zDbemtQGpi~RD?6RjMbvxu==GN6?h^>T30ZmGn3P!g@JzEOeFiWqBtUAYY1LWPe})zeHjPtWVk0&mQLjvqk{S!g^8Vm zM5(4e?sAq}N~hyS!A$AvG7`#J1Tx;^+PPfDnu;^<8OFkPJ(o62AAYFfM|jzXS5*8M zKjFfehB=TV`b5Qb(}!18{1iW9WDM-2izU-RbfeN3HKZ6oh@NY zhI^pjFlo=~m4TF=&E^M_DJJ3S74~c}nNHg?=FE}dM64y8*w7MjybgyrX7)%@+;-Nb z)JjSzL;}&|fbOnP1V6W9=1^n_t;?-R?lvk5OeD&Axq#V{Gg`=Ir9bx9Y+@}wysP5( z_=5uB*xp8ar;pX5NNYmHAMrBxi~MbLPBP3GV~9sKw09{ue2fxp?P^z09qI1u?TYq| zpCwM~X;<+lyr*ItvJ~3ZnrQ8lRE}lm@{4G1XJ_l$PBOoSKaVMoQTgm}$Ofe)9C9GC zL8K>tQSmyh%sZk9b!j1L6lvwm@(Ag5>d+)L z?r~QtGsWVQF+v^PWz@wVZJm2u(kYhmp0TZ5;+`Jmb$rUwK69+(IhO?<;=D8r5dZoq zKUlam)gMathc@cw&b7&WCN*|AbtQAj%@RoGTq&Me3YH$)nhD1n%RDat$t+>2DgUUu ze=85b=B1~TAvrk6gGNEHoWZ^6Og7m)9C!y3mQi%EMmkZjGTD%pj`G-%UCao9ABz|-Vy z(7dHdMT1sRn)v+Q{qRNoUQLXk@-{4J(5gy{BIp-dwN||!YLjOO-Q=2Xa~mrzax=VqXC35D-pluq?B)C|ZiSr7{vckp`?q*4 zlXGVicVQ97M{)b+@{9S_fS<0R}uGxbLB6xW{R+Ci+ri#VA!M0opX~u?6Qziu|8xYkRdUoAWRQ*Eq_Nc4P1Jx+2z2qO z9Yrm=iER%SGb0AoWuOPf=RWT$#w@< z?q-rbK#WF+&jBLz0ug$J7`?$S-r=+1Lu|pnkWni59+{49%1quxYcZfKK+ZA=kvun1FuFl{GHXA`C!SdN`Io*=BnxlF+G2+#Qh z;{t5Oh5Y;HB91QRKR1`)I$X-wy$pLeyAPK$`L4i|xDwCfDn1=|;dNY%H*pQ##kEYb z-Q%F(TaTc~5<5spJnUCYO0D&dV|J@;DEDIsp02(89xMsV39VC5mY|Z98(6|`q)#_t zHg2Yuw=f`YCEp$7yd5FjNiIHIoj_n&@X7?oTx#!7(B$!Zo`Y8z_Inx{gIe_{KIO$Q z*BuR-ZRuX_+Jl&mhp1&_oL77Vxn6CfeA~V{&mL50rwrG5W#2hm=aYTcaGj8SbhxfU z_T9r;&zPF!sHV!tXxQUab%3g##7sPm8a#tJtZDP`90IIsi"); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + while (spColumns.next()) { + buffer.append(""); + } + buffer.append("
CatalogSchemaProcedure NameColumn NameColumn TypeData TypeType NameNullable
"); + buffer.append(spColumns.getString("PROCEDURE_CAT")); + buffer.append(""); + buffer.append(spColumns.getString("PROCEDURE_SCHEM")); + buffer.append(""); + buffer.append(spColumns.getString("PROCEDURE_NAME")); + buffer.append(""); + buffer.append(spColumns.getString("COLUMN_NAME")); + buffer.append(""); + short columnType = spColumns.getShort("COLUMN_TYPE"); + buffer.append(getColumnType(columnType)); + buffer.append(""); + buffer.append(spColumns.getString("DATA_TYPE")); + buffer.append(""); + buffer.append(spColumns.getString("TYPE_NAME")); + buffer.append(""); + buffer.append(spColumns.getShort("NULLABLE")); + buffer.append("
"); + out.println(buffer.toString()); + } + + private static void printXML(HttpServletResponse response, + ResultSet spColumns) + throws Exception { + response.setContentType("text/xml"); + PrintWriter out = response.getWriter(); + StringBuilder buffer = new StringBuilder(); + buffer.append(""); + buffer.append(""); + while (spColumns.next()) { + buffer.append(""); + buffer.append(spColumns.getString("PROCEDURE_CAT")); + buffer.append(""); + buffer.append(spColumns.getString("PROCEDURE_SCHEM")); + buffer.append(""); + buffer.append(spColumns.getString("PROCEDURE_NAME")); + buffer.append(""); + buffer.append(spColumns.getString("COLUMN_NAME")); + buffer.append(""); + short columnType = spColumns.getShort("COLUMN_TYPE"); + buffer.append(getColumnType(columnType)); + buffer.append(""); + buffer.append(spColumns.getString("COLUMN_NAME")); + buffer.append(""); + buffer.append(spColumns.getString("TYPE_NAME")); + buffer.append(""); + buffer.append(spColumns.getShort("NULLABLE")); + buffer.append(""); + } + buffer.append(""); + out.println(buffer.toString()); + } + + private static void printError(HttpServletResponse response, + String message) { + try { + PrintWriter out = response.getWriter(); + StringBuilder buffer = new StringBuilder(); + buffer.append(""); + buffer.append(message); + buffer.append(""); + out.println(buffer.toString()); + } + catch(Exception ignore) { + } + } + + /** + * Get the stored-procedures names. + * @param conn the Connection object + * @catalog database catalog name + * @schemaPattern database schema pattern + * @procedureNamePattern database procedure name pattern + * @return a table of stored procedures names + * as a ResultSet object. + * Each element of XML document will have the name and + * type of a stored procedure. + * + */ + public static ResultSet getStoredProcedureColumns + (java.sql.Connection conn, + String catalog, + String schemaPattern, + String procedureNamePattern) + throws Exception { + + DatabaseMetaData meta = conn.getMetaData(); + if (meta == null) { + return null; + } + + return meta.getProcedureColumns(catalog, + schemaPattern, + procedureNamePattern, + "%"); + } + + private static String getColumnType(short columnType) { + if (columnType == DatabaseMetaData.procedureColumnIn) { + return "IN parameter"; + } + else if (columnType == DatabaseMetaData.procedureColumnInOut) { + return "INOUT parameter"; + } + else if (columnType == DatabaseMetaData.procedureColumnOut) { + return "OUT parameter"; + } + else if (columnType == DatabaseMetaData.procedureColumnReturn) { + return "procedure return value"; + } + else if (columnType == DatabaseMetaData.procedureColumnResult) { + return "result column in ResultSet"; + } + else { + return "nobody knows"; + } + } +} \ No newline at end of file diff --git a/sourceMetadata/jcb-package/src/servlets/GetSQLKeywords.class b/sourceMetadata/jcb-package/src/servlets/GetSQLKeywords.class new file mode 100644 index 0000000000000000000000000000000000000000..d40b654a6dc618bb770f0afa2f696b3279daa39f GIT binary patch literal 3558 zcmbVOYkL#N6@J&2y{q*aQh@;{ff%PYHj)q~ff!2`!5FX;U+@JSXxe5at!06>jKhgA^UCEYhC~c+Znb|orbI$vo zbLPza?Oz{!2%ralRuRX9g2^UKVOqsKIIG~CiWxknq7Ua4ToA&~h{5Bc`K*f1;qx+{ zP|*xsNKy*YO~}9y&8&>9ifuyWoal23E;iv3@(K!~H)U7~iV7}^SzCnzS3ya^yn-hc zEGSr1@RW=%sOS_*z9{-HDfqHj`E(P$g0D8=YxueV^^A;fsEA=g#y1swOC_Cei{?9` z`L3|`y&%4iA1L^tif7@hM{=eyRw|?ndslR}}Y^Hp{q;a`qIBxuo%bcQRI!0VrRZlLY zjiQ^QK*kF)UX&0l+Bwr5njRgI5Wlm{iZah=tmNkMv5_1>2<5@4T-Maxl1&!l|F5Qm zuQ{)q+1QjzXxVtu)2?_p9}_TD@AIT>TegJ$|It#dW`TN3)^MjLMjka5pS0|ZBVnJf zFy>s&$4*$LX{3d};@ul5ue$3_D{o1OET*iIoi1-!J~|yYb=N~E97Ooq2U*JQ^POuD+xQ-Hu@nMDCP1QgU;_wh~>#d z%E~Mz6RybMwiMlH*!?|iX(OL^ih7zc>_6y@ih3sFjglIc@M{Ts64R5(#Pm>-+}o-l zNW>^$Gntg}mWH?Sjs(SDILM9f;x`iR+6amMFpFjL2j9A1KYv3Rh~it`zRM&fMIH{uV0+_v>aaVjOWde%ItAGvAkl40ha5(cG+NU&uMEBHXeO`++JctysaG<=AU zXgs>^C*xzv)~6{0C=A@bMr~S9sa>o2R|TH4V#DJ#(vJVEw^IA)HJ;uxx~&%sS8(dA zoZWSYd~-!%`DJM-NZ8(0Io7osB<#JIPQ@~**g3;q9MGLydaVwO>ZYC*rkZJaO)R1N z_NF&f5*}WbZavRh(^9)>Jav(^Cfz7_qO}C8YBmL=Qct*X%UZ(v860q!t=^?M%$CLlwBg#QRoo^{v*lZ;NvaxH5@he* z$eR)(|0OJOG>K}RGpb>tul+-}KD-i|ya>3u2%Uu8RVRsM)o6|y{xo&_NAy;cbYtEy zv+ms5om88qo4n{c0Sp;n5=wTd3owxKK z>=n*sq_J?QZUyyqC?n7p2!|S02Mw)(Wi*aOmm&8xwl;*6GJ;p3MOqt|p)MileKc`e zTf&~cK%_NL#+GGl^(9)LEIwN0kFFy?YsWFfSET4K(C!eQprXHk$GzT1`UpalZRe^T z#JdysVi(%ciZ0xZLwp7HQWD1=>geDl+es~Zd5N}DR|j9Qoz&EUC)lUCV}P0(sp$j; zp^7UR^&a#0*f(%4yFYZ-3O-eb{VNDb7`=&Y=Wk&9STxj9#*Ue2Xs77vj|5r*;T7zX z@CNopL#^IixFxWHyX){V?(x^&E4pU_($Xh?kA`-OK_ptno-*!R3&Ro82cmTQ0g{W6 z-a%67A>>1Nfd4)`NHT{p!SM_p;?uhqvpDJz2{3rgIL-ZaB&~{P#%4Ngx2Ch#huAK< zjdbq!<~Gs!v=CS6bcn(2==76Ll5~!d&cl_+43NwT(itS3lcY01I;Tlzh;)W;Nrw+1 z5)>(1Ai;oe(`r;Y8I^sEN>>@(GtscuhW3k2UEbhY`Gx`#`>4(EGd9W=4ERw`!g0(mKZjAcIskIJg{tXmmklX+O literal 0 HcmV?d00001 diff --git a/sourceMetadata/jcb-package/src/servlets/GetSQLKeywords.java b/sourceMetadata/jcb-package/src/servlets/GetSQLKeywords.java new file mode 100644 index 0000000..04c459b --- /dev/null +++ b/sourceMetadata/jcb-package/src/servlets/GetSQLKeywords.java @@ -0,0 +1,119 @@ +import java.sql.*; +import javax.servlet.*; +import javax.servlet.http.*; + +import java.util.List; +import java.util.ArrayList; +import java.util.StringTokenizer; + +import java.io.PrintWriter; +import java.io.IOException; + +import jcb.util.DatabaseUtil; +import jcb.db.VeryBasicConnectionManager; + +public class GetSQLKeywords extends HttpServlet { + + public void doGet(HttpServletRequest request, + HttpServletResponse response) + throws ServletException, IOException { + Connection conn = null; + try { + String dbVendor = request.getParameter("vendor").trim(); + String outputFormat = request.getParameter("format").trim(); + conn = VeryBasicConnectionManager.getConnection(dbVendor); + List sqlKeywords = getSQLKeywords(conn); + if (outputFormat.equals("xml")) { + printXML(response, sqlKeywords); + } + else { + printHTML(response, sqlKeywords); + } + } + catch(Exception e) { + printError(response, e.getMessage()); + } + finally { + DatabaseUtil.close(conn); + } + + } // end doGet + + private static void printHTML(HttpServletResponse response, + List sqlKeywords) + throws Exception { + response.setContentType("text/html"); + PrintWriter out = response.getWriter(); + StringBuilder buffer = new StringBuilder(); + buffer.append(""); + buffer.append(""); + for (int i=0; i < sqlKeywords.size(); i++) { + buffer.append(""); + } + buffer.append("
SQL Keywords
"); + buffer.append(sqlKeywords.get(i)); + buffer.append("
"); + out.println(buffer.toString()); + } + private static void printXML(HttpServletResponse response, + List sqlKeywords) + throws Exception { + response.setContentType("text/xml"); + PrintWriter out = response.getWriter(); + StringBuilder buffer = new StringBuilder(); + buffer.append(""); + buffer.append(""); + for (int i=0; i < sqlKeywords.size(); i++) { + buffer.append(""); + buffer.append(sqlKeywords.get(i)); + buffer.append(""); + } + buffer.append(""); + out.println(buffer.toString()); + } + + private static void printError(HttpServletResponse response, + String message) { + try { + PrintWriter out = response.getWriter(); + StringBuffer buffer = new StringBuffer(); + buffer.append(""); + buffer.append(message); + buffer.append(""); + out.println(buffer); + } + catch(Exception ignore) { + } + } + + /** + * Get the table names for a given connection object. + * @param conn the Connection object + * @return the list of table names as a List. + * @exception Failed to get the table names from the database. + */ + public static List getSQLKeywords(Connection conn) + throws Exception { + DatabaseMetaData meta = conn.getMetaData(); + if (meta == null) { + return null; + } + + String sqlKeywords = meta.getSQLKeywords(); + if ((sqlKeywords == null) || (sqlKeywords.length() == 0)) { + return null; + } + + List list = new ArrayList(); + // SQL keywords are separated by "," + StringTokenizer st = new StringTokenizer(sqlKeywords, ","); + while(st.hasMoreTokens()) { + list.add(st.nextToken().trim()); + } + System.out.println("--------------"); + return list; + } +} + + + diff --git a/sourceMetadata/jcb-package/src/servlets/GetStoredProcedures.class b/sourceMetadata/jcb-package/src/servlets/GetStoredProcedures.class new file mode 100644 index 0000000000000000000000000000000000000000..194e05b0a205059eee5e0932086684dcb032490b GIT binary patch literal 3896 zcmb7HYkM2T6@JH&thKx$$r{^{b8`$y9ovc=3dONyr6hKU8(VfIIU(T^R?@~%BJV2F z%CSp<^ahjyg{Cb8C{Wtez0fx9#jzoU_UQ+n2fp{`w0&n+k|oPDPruCU%$zyrea|^_ zX7;mxfA}$gL-@NNLzq@@su`#8h#zNgR>7lwJch>=JR!&D6g;Uw_hS%A1t|q-1%@1* z_hSYZWRp>FQO;bFP1c85KU!fbu$qy>W!dC?DEQGKE!na!DwtDnr5W>BQ1A@}Psz`3 zDtKDKGxGCUsp_hNZz=e;-0&SgzKicEcuv9d3SLm~eFZNn_<@3#6uhk9m1g`9uQuZ~ z{7Aty1wU5s6CZx+!|MWj;)%)F=*YRL*yOR%k?Gjzx!7o8Iu?zyk57*$1hnys`kWrh z>gG%+Zs#-R%#gt5W0qO4b<;kjXN!hFN1dAJWJSY9Hl*%z)6tXB$4ygH1!N|{L4LfwfwsWBqY~t=j z%(z@M3ii+)#R@qRF@~g7|LA`q3iwjG zt!J$n0kKcTB&N8*%Ihg~nrvfU=HV>Q_-|GG4j-uaJ^mojzP86bK1Yk0Y}#Pl z2f|W35>8s_g-FaVt76~U# zL@HtLjOw#SIK(M|owX}6F3t*@Sj2}V6@S8?1r%4w2zT7IRs^CCO^mAe3*II%ZWy7N zbrOj)Q6x)YW0O_0`~J7yQmGVBd6=j4JRNAu?A%|fAJqqV z!!x~geS))q^PZR$xVwA94SO%9lA&}mbjrvt9Mub%)LMC(&`o_tTHj1CYtsS;z8KBA z0>?wn;;&~}0$Zy$O(rk01P&cI%XtZ)XlJsa5tfRiUNELPU>Qketpck=dsXSIE#cd% zR@UIT*9Q?#7=;4y(|LFDxqDSG;|dN>+c52N<=mk9vdA}4{pozh2~B(1uMG8+yrJ9$ z-ph@8F2|xN5Ui$Ny0+_sQ7T2;s5wEbxw9BXlQqq`l<71Hz*R&u{2nv8RO8{YnK5~` zt+K3JGi#BuNIMr`)+{G&Z4d>T9dFvY43NOCGGQrJj@g9aE)#vAf`0v?n@N=d$)p(H zz%%tOub(M-uf|0~*vqHb5MPU%_znwW7y=QF8t@>;N2B5;@|t6Nj5~I* z7wo+~w;-1IAuz(W(V1*!JBs5}OHpwR9yD?7a}gDTo?fkC6`LBc49}pqSMyc|jREfp z8lwTP=39nx9eaAUrplr(81QL+&A)=?LC+!vD5W}5yL+|GRZ>EVm4sUQw7XWYCE!`X z*5C@ZEd?4i&Do^($;p;QG&vu4S40-kJ?QNVc$d*uy>k)U29=6XK>1{eM7@~94Ze-9 z;=0qz@omzSW7*%pO{c%jN-W2&gPvmqfOfiOJ2iAb!w&4hPVA#cL)guj?7<1#gOj)y z)0|CWKW5RxXLldG!n%LjKMD-3vRIRFJ^|9YtQs(?W@?{fSy$Z1SUR0$C+E$ z5e;fPm$B<~P}}Wxdt}$UicTRR1hu`+bg$O6ihE>`rRcqmjJ9tT`y22TPq3BF|B}1Z zExX14{3ECxkY9blW%MkgcP*igV;j+oLSZ^>A?kJ_-c8K=h`EobAK+^z%$Lv@qL||2 z=`7ncZ}>}y!9*NIB=9snDfxOBgI2QT`>4eB^Ag)DJzC$!YzatGI4HX+njvSpmS(>r zvmwnxa>=22pZuz)c@$d-@GNOQN}7+6=HsOK1ZkebK|D#CI*(qGG*cv%=BmN=Jpb2b zNb>?yBU3|>PeYQG2Q^2k9`^lpf&8+|!D+Sot8p#DGqJ?|KrgMg@@s_O`<+v4vJhCr zm_r*bGja1w)&k|`C|P6*U!fG=uq6jaXj`UJ2dzIKFz5+*K807@40w9`f~!mhCTaO- zXb#So=!2KB8L!aBYc-tsY%6gZqIQX{rNjFk8np*+c6ekza8o literal 0 HcmV?d00001 diff --git a/sourceMetadata/jcb-package/src/servlets/GetStoredProcedures.java b/sourceMetadata/jcb-package/src/servlets/GetStoredProcedures.java new file mode 100644 index 0000000..9df5a2e --- /dev/null +++ b/sourceMetadata/jcb-package/src/servlets/GetStoredProcedures.java @@ -0,0 +1,161 @@ +import java.io.PrintWriter; +import java.io.IOException; + +import java.sql.*; +import javax.servlet.*; +import javax.servlet.http.*; + +import jcb.util.DatabaseUtil; +import jcb.db.VeryBasicConnectionManager; + +public class GetStoredProcedures extends HttpServlet { + + private static final String STORED_PROCEDURE_RETURNS_RESULT = + "procedureReturnsResult"; + private static final String STORED_PROCEDURE_NO_RESULT = + "procedureNoResult"; + private static final String STORED_PROCEDURE_RESULT_UNKNOWN = + "procedureResultUnknown"; + + public void doGet(HttpServletRequest request, + HttpServletResponse response) + throws ServletException, IOException { + Connection conn = null; + ResultSet storedProcedures = null; + try { + String dbVendor = request.getParameter("vendor").trim(); + String outputFormat = request.getParameter("format").trim(); + conn = VeryBasicConnectionManager.getConnection(dbVendor); + if (dbVendor.equals("mysql")) { + String catalog = request.getParameter("catalog").trim(); + storedProcedures = getStoredProcedures(conn, + catalog, // catalog, + "%", // schema Pattern, + "%"); // proc. Pattern + } + else if (dbVendor.equals("oracle")) { + String schema = request.getParameter("schema").trim(); + storedProcedures = getStoredProcedures(conn, + null, // catalog + schema, // schema Pattern, + "%"); // proc. Pattern + } + else { + printError(response, "unknown db vendor"); + return; + } + + if (outputFormat.equals("xml")) { + printXML(response, storedProcedures); + } + else { + printHTML(response, storedProcedures); + } + + } + catch(Exception e) { + printError(response, e.getMessage()); + } + finally { + DatabaseUtil.close(storedProcedures); + DatabaseUtil.close(conn); + } + + } // end doGet + + private static void printHTML(HttpServletResponse response, + ResultSet storedProcedures) + throws Exception { + response.setContentType("text/html"); + PrintWriter out = response.getWriter(); + StringBuilder buffer = new StringBuilder(); + buffer.append(""); + buffer.append(""); + buffer.append(""); + while (storedProcedures.next()) { + buffer.append(""); + } + buffer.append("
Procedure NameProcedure Type
"); + buffer.append(storedProcedures.getString("PROCEDURE_NAME")); + buffer.append(""); + int type = storedProcedures.getInt("PROCEDURE_TYPE"); + buffer.append(getStoredProcedureType(type)); + buffer.append("
"); + out.println(buffer.toString()); + } + + private static void printXML(HttpServletResponse response, + ResultSet storedProcedures) + throws Exception { + response.setContentType("text/xml"); + PrintWriter out = response.getWriter(); + StringBuilder buffer = new StringBuilder(); + buffer.append(""); + buffer.append(""); + while (storedProcedures.next()) { + buffer.append(""); + } + buffer.append(""); + out.println(buffer.toString()); + } + + private static void printError(HttpServletResponse response, + String message) { + try { + PrintWriter out = response.getWriter(); + StringBuilder buffer = new StringBuilder(); + buffer.append(""); + buffer.append(message); + buffer.append(""); + out.println(buffer.toString()); + } + catch(Exception ignore) { + } + } + + /** + * Get the stored-procedures names. + * @param conn the Connection object + * @catalog database catalog name + * @schemaPattern database schema pattern + * @procedureNamePattern database procedure name pattern + * @return a table of stored procedures names + * as a ResultSet object. + * Each element of XML document will have the name and + * type of a stored procedure. + * + */ + public static ResultSet getStoredProcedures + (java.sql.Connection conn, + String catalog, + String schemaPattern, + String procedureNamePattern) + throws Exception { + + DatabaseMetaData meta = conn.getMetaData(); + if (meta == null) { + return null; + } + + return meta.getProcedures(catalog, + schemaPattern, + procedureNamePattern); + } + + private static String getStoredProcedureType(int spType) { + if (spType == DatabaseMetaData.procedureReturnsResult) { + return STORED_PROCEDURE_RETURNS_RESULT; + } + else if (spType == DatabaseMetaData.procedureNoResult) { + return STORED_PROCEDURE_NO_RESULT; + } + else { + return STORED_PROCEDURE_RESULT_UNKNOWN; + } + } +} \ No newline at end of file diff --git a/sourceMetadata/jcb-package/src/servlets/GetTableTypes.class b/sourceMetadata/jcb-package/src/servlets/GetTableTypes.class new file mode 100644 index 0000000000000000000000000000000000000000..b275ae3e304cc892e0c05f14431dc80f6a3467bb GIT binary patch literal 3719 zcmbVPYgZfB72Q_|W{?Iul>=Cb?O+nyU?I!IiA{u%0|pyhUIuIunx+{^1D30oXGRpc zO_R26-B;T5>84GeX-nU>(-uSA#%VvKYxQ$~Kz>QmeP<*P0@rO}tvPe=J@?$R&pzke z(LdjR>umtt_`45LOsY8N#}uZ0co;J(&iilyvpzh9XH+~ZC+FngBl7W_4%8M$}eq6%GRb-^hD#)qGt0>6T%RZQ}RM;wtDi&3I zLdBAbl7cHf9F#^rDdneByeKt4?Z-=aSvv3;KR%1kDY)uG1e1;UJiegfnh#%u<;R!s zW%>Auim%EeUs3Tj1z%V2sz5_5olDzsfx3>)3j*F#`II5Bb2ObZ#*5j6Vb17@3}@<7 z`7?$sFx4@7Nng~LB9>t;W(+%W(Y6bbVLqnai7Df9(Xi~^`>I)me9kg@<*B}*rKC}? z)0|N74F%s6Xe^lNoIN}`B#Mdu*HX;2 zoY8X&k!hQ*E%e46>#F1DGty0;^Ezajc~hY8e>|z$vh=!X!LXgs&y)&=C2+{K7qKp9 zBB%1XoRO5_>g}vWydJIlX>N;%Ag1$0GijVoOVR_Re8Y(&l6Vchh%s#zja({kD)^R$ zZ{s@}zKiReozI(D-B$2D4X@$*8a@ohrEV#k(eMMju3;EM8U`_>;D;K1gdYp+l13vA z`t>Bx@Dp6uFoLsW&o-81l4UareyZVTctgX_@e6_0jg2lL1I2VEWia$TF{vJpCGx3K zJZ8)MZA;`$uJv`dC5=qRD(Fcv*mu+!74%ff8O1gH63YU6Vlz|m*vxR;f!-zwh($Q$ zV=AuTR~mke-w3F#+90?67QYjCpw=M#u4fJ^?*2WlEBJ$k8+e0O z9lVT~Kqz*SvTe~YEmGar-hJd~dz+C<<{fw2N2VvjJv~o874B|7$@%KLW9jK_Z)H*y+oS&Bg)T#q0gK|?~N3GX4a7)3P8vcksNh<%WU`6tMyF#f` zg#D(emt-X>SkDQQHS@e?e zxL+9EPEMjN2aRpyY?-h%o|SvB)8A=+)=WFmZmmR*>`lrG#9inmK)q04%Mu7z1FV?Y zLP)upaN`cAO4hFw5@n^Y&>h~FBYg63>Dov&Yvr)XV$QoKR3%lFTP#lJ%E;sdy8cVI zWQEeJZE0ex-FCW}UID+ufUQgF1ol>fB-JWxjv4MUZMRlYIb~SIj6H3*S833R#dh1+ z-m0x`Y}?!yOO|ag$?Nh(88tWR6{;91L(lSj7sKXh-bL$YuNx;9Io=Kq7fjJcqO63w zhLJMQ)MT^Aetx4x`LPEyfcGV0eD-m)mr_vHAHEH7i!TE4vJ$X^qmy_V9!K>(N|kFV zF&+wd)==lc3cOKoC{VvXs1JHq(J&rfg%WKD)(6xTG`o>{!K4cSegU@+GL;y#+5%>*wX!aIfv&Q>3Vt=0nY8BRx@^@1$)qn zcI-w6f_NMcp@$!?y@c71$1sEgw9xv0aKy{$icnf#0aO4aN>k>l5n0ToPGisAe>W#Ge|i7gmap3&JfP|3xhFtP-wL{~F~h Ql(iW-#`DK{vIi6Y2INGqD*ylh literal 0 HcmV?d00001 diff --git a/sourceMetadata/jcb-package/src/servlets/GetTableTypes.java b/sourceMetadata/jcb-package/src/servlets/GetTableTypes.java new file mode 100644 index 0000000..801cefa --- /dev/null +++ b/sourceMetadata/jcb-package/src/servlets/GetTableTypes.java @@ -0,0 +1,127 @@ +import java.sql.*; +import javax.servlet.*; +import javax.servlet.http.*; + +import java.util.List; +import java.util.ArrayList; + +import java.io.PrintWriter; +import java.io.IOException; + +import jcb.util.DatabaseUtil; +import jcb.db.VeryBasicConnectionManager; + +public class GetTableTypes extends HttpServlet { + + public void doGet(HttpServletRequest request, + HttpServletResponse response) + throws ServletException, IOException { + Connection conn = null; + try { + String dbVendor = request.getParameter("vendor").trim(); + String outputFormat = request.getParameter("format").trim(); + conn = VeryBasicConnectionManager.getConnection(dbVendor); + List tableTypes = getTableTypes(conn); + if (outputFormat.equals("xml")) { + printXML(response, tableTypes); + } + else { + printHTML(response, tableTypes); + } + } + catch(Exception e) { + printError(response, e.getMessage()); + } + finally { + DatabaseUtil.close(conn); + } + + } // end doGet + + private static void printHTML(HttpServletResponse response, + List tableTypes) + throws Exception { + response.setContentType("text/html"); + PrintWriter out = response.getWriter(); + StringBuilder buffer = new StringBuilder(); + buffer.append(""); + buffer.append(""); + for (int i=0; i < tableTypes.size(); i++) { + buffer.append(""); + } + buffer.append("
Table Type
"); + buffer.append(tableTypes.get(i)); + buffer.append("
"); + out.println(buffer.toString()); + } + private static void printXML(HttpServletResponse response, + List tableTypes) + throws Exception { + response.setContentType("text/xml"); + PrintWriter out = response.getWriter(); + StringBuilder buffer = new StringBuilder(); + buffer.append(""); + buffer.append(""); + for (int i=0; i < tableTypes.size(); i++) { + buffer.append(""); + buffer.append(tableTypes.get(i)); + buffer.append(""); + } + buffer.append(""); + out.println(buffer.toString()); + } + + private static void printError(HttpServletResponse response, + String message) { + try { + PrintWriter out = response.getWriter(); + StringBuffer buffer = new StringBuffer(); + buffer.append(""); + buffer.append(message); + buffer.append(""); + out.println(buffer); + } + catch(Exception ignore) { + } + } + + /** + * Get the table names for a given connection object. + * @param conn the Connection object + * @return the list of table names as a List. + * @exception Failed to get the table names from the database. + */ + public static List getTableTypes(Connection conn) + throws Exception { + ResultSet rs = null; + try { + DatabaseMetaData meta = conn.getMetaData(); + if (meta == null) { + return null; + } + + rs = meta.getTableTypes(); + if (rs == null) { + return null; + } + + List list = new ArrayList(); + System.out.println("getTableTypes(): --------------"); + while (rs.next()) { + String type = rs.getString(1); + System.out.println("type="+type); + if (type != null) { + list.add(type); + } + } + System.out.println("--------------"); + return list; + } + finally { + DatabaseUtil.close(rs); + } + } +} + + + diff --git a/sourceMetadata/jcb-package/src/servlets/GetTables.class b/sourceMetadata/jcb-package/src/servlets/GetTables.class new file mode 100644 index 0000000000000000000000000000000000000000..52a62a9f494f045321c4d15cba2226e34bbcc5dd GIT binary patch literal 4783 zcmbVQ`D0Yo75;9R$&HA=R4=V$vgjk z{Y?Pt@h>-;(4!+*gkD%~l%Y>YzZ-`U(lH>%A9te>VcA4v%xNDIK5D@Sq#zQpsnf{G5)@%bgDu;S2bpj)#lzB|IVx`Lb+IYk1U+4d^MtWB7`k z`D!5^#}hi9bmMEdSKj-SJoKEI)Pc`6?+9-jj>*8Ep84)t=3ee$4YdWJz>t| z_r`9tY=Mq)rGChtv=W11%l03(?YMs@n@(qGI6Msa}?G3B3uF^n6y6$cC)!~rsKC=xbsGxiwh!X6E; z8@PyX5|W8@$nwR&8#r%ZKW<^5ZEHyKF%s7Brh!YiY~Wk?w!p%PgH9ebq(b3di&5Gf zklX75J+a>5x_~XI?(K;sxK_K~8??gVWZVog@oLwpQQYk9Riios-@$hUmIS&w>H=Lm z>l6rH8Kr=qLpB|C8op=XEnE@Moo!7#_BOsRFn6j!BoB`?Ip+ix1pLYtjvdRCS3La= z&TIIAfp>A4T9v;9OQ15amC`$CC6eSr?TYnl*RAkc(O^uOyJA;on{V^xjaz){S8Qdf z>yD>Mb_)Vg+RTm?@TYr)>C5Hvf~kf!r26_Ka7He05{w^`3{$Or7eCVQV*@|IPX)Fm ztuX28jr9yrbj!=UeTi7an_?yDc4m{_qlc}8mDytt$1QKIceN^rt2O-0z|ZlXWWz6H z^UDk+RKC|I66UZ>dJVra@N4|Wz;E$84Zk<=2mFx$D@0|4YBl`Hz@H`Q{(`?6*oj>l z{$}9s_=mu2jK7 zddAsM%)hHGXLjX(*PAZKj2InjHxu;VmH}Lqt|XJ{&h#S37lAKNL|}e-y2#`n5LiAC z?D6;Z`1e|g;RZ7q3Qkm|7Bg!0%d2EDnV1%+xcb#o>KggU*Tf97@|ENsYEvAlsbJEV zNCOlBnoLI6Oj>(b{TYH_IF@9ET6C3)DPJAh)nX-+w32vS3r6RKVX%|R8{3N7UF7E! z%hK<(dUvRPUm~Q?UYJ3T(QB6vo3p_8yuggdSuF*8xejL3ObbZ5a`E6Cm73Y7j)6*s zj?o;xk@69J5#r)KeCY3RL}%X34TZt7Z(7e9n}$lf%o; zj9|htZL8B}6Ct21I2oYi*6chLd$J0$v*ffjWCc^UwL3-n36x*mR;jMTN~Xegr)5*! z!W>#m%*(Llu4J!LPyK`m*%L%P%11|`PBP9V>Rn8ih}E0HH$(Qx222V|I@pt+h2bP2 zq25?Z#?j$HhCDoAnGt&7pgMV)XZT796e)Jwrc4WgvRqs%KSAKAV$~`Xk}ZVCg-qiLp#-Rt0qXFnnVutS&f%LU!C-$oCXE3st2B zV=%a&I>bNwI(~I+NBY=Xv02!GZiZtr!@x=f|PM2lyvOB z1q(R0n7fv6ZyDRASb=3&Nx=N<5(>46ju8@A69FXC9ZKS$-`xoIeV8%andEuy#JohvrG=Ee53G= zV);a{HeoietzmEibhZ`?>DE$grF+|Gc0H=mKn^t0@NIN(JDuBsKJr95;$n!4v6npw ztXqDAPIqU;%7YBE?6uS6J#=R;-Pt#zJN!zfgEBf1I_RSGWusEgs8ld2YerGI&sV8hPn8tXCf^yj zT1HeFl%tY{IK*0oLMk}`4YzUbAZgZ3avdU_Oj4I#ZQYteO%utp znYhUmS)_=trPTEnldP1)sb&n%y#Kb3DU{Y%>N;DUpB?01q9rb-MT*v3j{zl9{6~Tu zJN_Lc+<;B6QrvkIMHs?-(tZ(+@!Wk3#QjX42YC7p`gtc4={Q+;7ejD2Jw8DMPNJXx zJs9BLDEB6~H^u(#>>p=;D(7w^Qv3;&M#{$ol1M!)nu!yOw1lUK^@i^F&Q=K_&LJ?4 z+I#|-vyj1z7?5JY*a0#J1bo~%B_I7I_X7;Gum z;vOYW;Xx%G5c^QdwMV%7G~IiY>G>GXjbI+m@#NzK@CmHKlhiRn5YJJ|)2u7cFm0b@ zT0TdvKhMhZ0s(xHA$W< tables = null; + + if (dbVendor.equals("oracle")) { + tables = getOracleTableNames(conn); + } + else { + tables = getTableNames(conn); + } + + if (outputFormat.equals("xml")) { + printXML(response, tables); + } + else { + printHTML(response, tables); + } + } + catch(Exception e) { + printError(response, e.getMessage()); + } + finally { + DatabaseUtil.close(conn); + } + + } // end doGet + + private static void printHTML(HttpServletResponse response, + List tables) + throws Exception { + response.setContentType("text/html"); + PrintWriter out = response.getWriter(); + StringBuilder buffer = new StringBuilder(); + buffer.append(""); + buffer.append(""); + for (int i=0; i < tables.size(); i++) { + buffer.append(""); + } + buffer.append("
Table Name
"); + buffer.append(tables.get(i)); + buffer.append("
"); + out.println(buffer.toString()); + } + private static void printXML(HttpServletResponse response, + List tables) + throws Exception { + response.setContentType("text/xml"); + PrintWriter out = response.getWriter(); + StringBuilder buffer = new StringBuilder(); + buffer.append(""); + buffer.append(""); + for (int i=0; i < tables.size(); i++) { + buffer.append(""); + buffer.append(tables.get(i)); + buffer.append(""); + } + buffer.append(""); + out.println(buffer.toString()); + } + + private static void printError(HttpServletResponse response, + String message) { + try { + PrintWriter out = response.getWriter(); + StringBuffer buffer = new StringBuffer(); + buffer.append(""); + buffer.append(message); + buffer.append(""); + out.println(buffer); + } + catch(Exception ignore) { + } + } + + + /** + * Get the Oracle table names for a given connection object. + * If you use the getTableNames() for an Oracle database, you + * will get lots of auxiliary tables, which belong to the user, + * but user is not interested in seeing them. + * + * @param conn the Connection object + * @return the list of table names as a List. + * @exception Failed to get the table names from the database. + */ + public static List getOracleTableNames(Connection conn) + throws Exception { + Statement stmt = null; + ResultSet rs = null; + try { + stmt = conn.createStatement(); + rs = stmt.executeQuery(ORACLE_TABLES); + if (rs == null) { + return null; + } + + List list = new ArrayList(); + while (rs.next()) { + String tableName = DatabaseUtil.getTrimmedString(rs, 1); + System.out.println("tableName="+tableName); + if (tableName != null) { + list.add(tableName); + } + } + + return list; + } + finally { + DatabaseUtil.close(rs); + DatabaseUtil.close(stmt); + } + } + + + /** + * Get the table names for a given connection object. + * @param conn the Connection object + * @return the list of table names as a List. + * @exception Failed to get the table names from the database. + */ + public static List getTableNames(Connection conn) + throws Exception { + ResultSet rs = null; + try { + DatabaseMetaData meta = conn.getMetaData(); + if (meta == null) { + return null; + } + + rs = meta.getTables(null, null, null, DB_TABLE_TYPES); + if (rs == null) { + return null; + } + + List list = new ArrayList(); + System.out.println("getTableNames(): --------------"); + while (rs.next()) { + String tableName = + DatabaseUtil.getTrimmedString(rs, COLUMN_NAME_TABLE_NAME); + System.out.println("tableName="+tableName); + if (tableName != null) { + list.add(tableName); + } + } + System.out.println("--------------"); + return list; + } + finally { + DatabaseUtil.close(rs); + } + } +} diff --git a/sourceMetadata/jcb-package/src/servlets/GetTablesAndViews.class b/sourceMetadata/jcb-package/src/servlets/GetTablesAndViews.class new file mode 100644 index 0000000000000000000000000000000000000000..4c0076f4f3453c0f358f498e888a3bb09fd6785e GIT binary patch literal 5264 zcmbVQX<$^<75-kBQY;v8{Mqn5)!FGv4z&QcCWRIZSB7A+n=`Iy>BL&EEL*5@7#Otx%Zs& zo#oz{7ytF_^8i-kA6_(LmxhE7yRpZMawIkMd67a|Lq^Q^da)6f_}Cg8L9<@;<9ZDP zVlpT`H>kMLi&=P+hMRo28MlbfJ{52FVy-y-RzcsQ;jKR0hTDC38{Y229k^3`-l5_y z4fp!62=7$!E)DmI;r$vO(D0zx_iis9!owOK(eS8-_h@)b!+SNnPs4r{2fSD%G#nK4 z{Te!%+>x8b(w+tKyh~d2Q`=4J}PQoptpsO&vXT(Z-&x=B6zj3j8g*jeaAXG*Uam z9gdYq?W|TXy&;{l9V6v*8Of~4?Tz*B*3q3ko!y(7xPA7vsrJupXlvQr8tsYJwdQon zp@JzE#6b#5B8gPOsZ}toVtJPWPeVFRy)#=9DKnbw>ou)Tqc=%TaXfvw=_qKgka`Eg zwrTYzO((p|aWdhJ{B*dCc5`pmw4Lg+irE?ZYE}!a-ll<=nQ;QtIu#$yrAPV_$(P|>A#LsIIY7#uZ}o+70i#eh1~iIwY7(2d4)E#ZH_kT z=)rX=KBwdJc##=C(3jM)9ouwVjcqKUu>u^;KOJ8Xx=S5%K%{nGQpFc_dS ztK+Nqnu3*)&i2|!=f+xzQ&t%nM~YefwVPoLFDl=6~EB&OZ-Y?@UO+^H>^A9 zgbeLQ!`{U{r{cFF?2P^I@OvG9z#nz|34hknil~ae==dxC#)wH(@;(rPe;?(z7eTRH z<_#beQ_G}^Rj^QKK6B@vB#^riMvE(-mWgz@xvhYE@qa%zccU;$>^PeYi%>fvX!*uB zu2oL%%XEp?YoCHS6}g^RxIw|<-Lc+qyf@rsT7&h5orsM!(N-g6>=de|Q}Y;G!SY-y zEj%fA_=Gmhw#5t4NV3e%FWl57^QLIBPjj}dX{l=Ap3RzjjZFOMFhw@KX1?gAez zB}OL02Cg7f=wSYsNdd`qO!3+o%VcIT8w3rq20O$vV^&_9#D%Q!;!;Kvh8d2yUFVJy zZ_e?#$3Lbb&t;p~W!OL(YnD zDd)U1IKBXF1^foiHx8^VdqwK z!zKruiV{#(I|IG0rz6TJ@oIRA^%b_3WkQT zYzP%&IZ#VvfO^KffulyuLle>3Kx8gw5^iLgH4}#`U^2ZNrs0i5=w>2x8&~dT(h0vk z%%EAghNB`}OYixFpX~kesl8v}T3;#1Ie8zH8-(|Te$p?3I1!VTf-Aibi_w|9@1*ye z>3tWy-$L)V()(`uel>mEMsKd6_t(<~O7HobhIojw>mwc>($Hwk zS25D4T1>U)*OPT^@uFW3Z~;MjzpO*MJc~~p~9k(Hvc|xn95lu zaX%`UjFlKb5I0bYzqxY2|C3Y|yOb8CmFm~Bg;e@49l^RHv<6ROrVV$rtZ zRKA2L3L3`_NnLlg6J@Ywif|_-?}Cp=&cQvHk9)aqKk+}nDm}>E_tCBUS)~skf(MzO z4>2YW6WK=@smFNsen#a0oj%CZ_cJO7SfK|e#Uw^x_&d}EMkz+I1SYGr5SBNx5{ZV7 z&5rJb4hI!Qc@lLas4pg71q*qIn4%J*rIr4MVKj=q*d*u_AiYeG#HkV>IUqP5x;>ML z1Dwy;3A&QWC1{ey3t9-$ tablesAndViews = null; + + if (dbVendor.equals("oracle")) { + tablesAndViews = getOracleTablesAndViews(conn); + } + else { + tablesAndViews = getTablesAndViews(conn); + } + + if (tablesAndViews == null) { + printError(response, "NO-TABLES-OR-VIEWS-FOUND"); + return; + } + + if (outputFormat.equals("xml")) { + printXML(response, tablesAndViews); + } + else { + printHTML(response, tablesAndViews); + } + } + catch(Exception e) { + printError(response, e.getMessage()); + } + finally { + DatabaseUtil.close(conn); + } + + } // end doGet + + private static void printHTML(HttpServletResponse response, + Map tablesAndViews) + throws Exception { + response.setContentType("text/html"); + PrintWriter out = response.getWriter(); + StringBuilder buffer = new StringBuilder(); + buffer.append(""); + buffer.append(""); + for (Map.Entry e : tablesAndViews.entrySet()) { + buffer.append(""); + } + buffer.append("
Table/View NameType
"); + buffer.append(e.getKey()); + buffer.append(""); + buffer.append(e.getValue()); + buffer.append("
"); + out.println(buffer.toString()); + } + private static void printXML(HttpServletResponse response, + Map tablesAndViews) + throws Exception { + response.setContentType("text/xml"); + PrintWriter out = response.getWriter(); + StringBuilder buffer = new StringBuilder(); + buffer.append(""); + buffer.append(""); + for (Map.Entry e : tablesAndViews.entrySet()) { + buffer.append(""); + buffer.append(e.getKey()); + buffer.append(""); + } + /* + buffer.append("BIG_SALARY"); + buffer.append("BONUS"); + buffer.append("EMP"); + buffer.append("DEPT"); + buffer.append("MY_VIEW"); + buffer.append("MYTABLE"); + buffer.append("SALGRADE"); + */ + + buffer.append(""); + out.println(buffer.toString()); + } + + private static void printError(HttpServletResponse response, + String message) { + try { + PrintWriter out = response.getWriter(); + StringBuffer buffer = new StringBuffer(); + buffer.append(""); + buffer.append(message); + buffer.append(""); + out.println(buffer); + } + catch(Exception ignore) { + } + } + + + /** + * Get the Oracle table names for a given connection object. + * If you use the getTableNames() for an Oracle database, you + * will get lots of auxiliary tables, which belong to the user, + * but user is not interested in seeing them. + * + * @param conn the Connection object + * @return the list of table names as a List. + * @exception Failed to get the table names from the database. + */ + public static Map getOracleTablesAndViews(Connection conn) + throws Exception { + Statement stmt = null; + ResultSet rs = null; + try { + stmt = conn.createStatement(); + rs = stmt.executeQuery(ORACLE_TABLES_AND_VIEWS); + if (rs == null) { + return null; + } + + Map list = new HashMap(); + while (rs.next()) { + String name = DatabaseUtil.getTrimmedString(rs, 1); + String type = DatabaseUtil.getTrimmedString(rs, 2); + //System.out.println("name="+name); + if (name != null) { + list.put(name, type); + } + } + + return list; + } + finally { + DatabaseUtil.close(rs); + DatabaseUtil.close(stmt); + } + } + + + /** + * Get the table names for a given connection object. + * @param conn the Connection object + * @return the list of table names as a List. + * @exception Failed to get the table names from the database. + */ + public static Map getTablesAndViews(Connection conn) + throws Exception { + ResultSet rs = null; + try { + DatabaseMetaData meta = conn.getMetaData(); + if (meta == null) { + return null; + } + + rs = meta.getTables(null, null, null, DB_TABLE_AND_VIEW_TYPES); + if (rs == null) { + return null; + } + + Map list = new HashMap(); + while (rs.next()) { + String name = + DatabaseUtil.getTrimmedString(rs, COLUMN_NAME_TABLE_NAME); + String type = + DatabaseUtil.getTrimmedString(rs, COLUMN_NAME_TABLE_TYPE); + if (name != null) { + list.put(name, type); + } + } + return list; + } + finally { + DatabaseUtil.close(rs); + } + } +} diff --git a/sourceMetadata/jcb-package/src/servlets/GetTypes.class b/sourceMetadata/jcb-package/src/servlets/GetTypes.class new file mode 100644 index 0000000000000000000000000000000000000000..bfdf3a66ff5308d2bf2292becd1dafdbbe7c29ae GIT binary patch literal 3143 zcmb7GTU#5~6FX=Q*0JO!MuHQ z#jg7!4^^vIJ-2R;$f?oEwW3}1%M@t%iiWQ$v{!3o*PqJgrWM8>erCg1aHv_o>6r6& zeZ}z?Y(F?a53F4hW6@wZS*v+9h0*`hvSYc+=7LXX%c0$6+t1&s+I59gXev1TjOV&` zQTUAXJqQv}EO;xmqJ6e3zTHdD237{ewFXY&IR<9cc1vDO!)pd!#~T{HX5j0%&4nee zRw&T>RR*}9MJs!-eR;d)svIgG6j}$sH`T1-nKa~~si5aV6XH3p`qzET0-%7|z zAY?P2)$n5jKfzBG^lG62-p9KHYjwtTG&wYQJejcFq8Cs~UdW$K zpGuC=vX=4XMsQ>Vql8Odqe)Jai4rLZBbn|=n$*#WqoLk;zn_Yf z?)UL44Zk+<8~j$ox`E%}_q4usvlNbq^^Z>5`xF}KynR)+E>PJs&(AhVkNtPMjdDN| zOqDsSMql{Csi%=HyD}=wm1dE`fqT8eBEnI~;+Gv$Zg9b> z+ZQ-t2`xHao$21yR4I0ssY6XGO=kurl8AG5y-xge-otzzmP6i>dcf1S-JrnSgSn}Y zwbT4!tsI1=Ys;?;^_*1Ua6zbB)her!Lb{pymYMsa*QgWR7!QKDt1dH)E(=cZMQb+@rdUwJ9amxCe*_|lL>vzc8Gk_GF}p*p5DR?nTM|Zv!&`0~NX3ySF*syBJ!Myg%@* zeFN?9AvTb{i|9IZ>0|s1QP{hV-r>kVcVq+m@8Up{_>p04d)BS}ThPCWg9^Dn zq2uz0cyuNm@7zGwVmf{(?7F2(ZQ?P-ihD90e>@PU;!kYiu((uIk2GXYHpvnqTmSdp z)A6G+8c1&-xq+v4;x>*0gfYlCnb?oxq&`HN&ydEmB!7Z|KS}V<@qzg~<{0U#jBkk% zUM4k{E2|_XBwHEzeWb|$eS_j(8x*Vk@sB;2;;|5Sk91Ako({yjx%D<=&D{D#7I5pA z(f!=AWCVFtoE7_tF|jLscgOs9f2Zb~PZj<2INcZZvSUOs;%MI>Q*(9ZS(G#"); + buffer.append(""); + buffer.append(""); + while (types.next()) { + buffer.append(""); + } + buffer.append("
Type NameData Type
"); + buffer.append(types.getString("TYPE_NAME")); + buffer.append(""); + buffer.append(types.getString("DATA_TYPE")); + buffer.append("
"); + out.println(buffer.toString()); + } + + private static void printXML(HttpServletResponse response, + ResultSet types) + throws Exception { + response.setContentType("text/xml"); + PrintWriter out = response.getWriter(); + StringBuilder buffer = new StringBuilder(); + buffer.append(""); + buffer.append(""); + while (types.next()) { + buffer.append(""); + } + buffer.append(""); + out.println(buffer.toString()); + } + + private static void printError(HttpServletResponse response, + String message) { + try { + PrintWriter out = response.getWriter(); + StringBuffer buffer = new StringBuffer(); + buffer.append(""); + buffer.append(message); + buffer.append(""); + out.println(buffer); + } + catch(Exception ignore) { + } + } + + /** + * Listing Available SQL Types Used by a Database. This method + * retrieves the SQL data types supported by a database and driver. + * + * @param conn the Connection object + * @return SQL Types as a ResultSet object. + * @exception Failed to get the Available SQL Types Used by a Database. + */ + public static ResultSet getTypes(Connection conn) + throws Exception { + + // Get database meta data + DatabaseMetaData meta = conn.getMetaData(); + if (meta == null) { + return null; + } + + // Get type infornmation + return meta.getTypeInfo(); + } +} diff --git a/sourceMetadata/jcb-package/src/servlets/GetViews.class b/sourceMetadata/jcb-package/src/servlets/GetViews.class new file mode 100644 index 0000000000000000000000000000000000000000..71f19c6c31f5cc4c5b2ea3759c90431671cc0d45 GIT binary patch literal 4769 zcmbVQ`9oCK75**`yvOheb`%wjW+W~kjH6973d0Z(5=mJU5HySU7#=uwHs8EK&^9I} zsg1E|n>KAs(q?HInxu(}79lp#ZZS>MJ>B>Hzi9g1_hw*NtWEjhp1YoV&Ue0Z?i=3u z_v>#0*oc3*(STkRp#t>5aAP_8RSdYXA7K>-PDqdFcih{2zcvV1aYp>hZ z+}P9A)Y#o2;AuXf597Gg?#8Uc>Cvdn265 z?Tg=TSOV>3w)P=^(l7@jhUMRHSqcAkHXY7HyKyjOB(3UeZc8TUhfytWbvF)$jD!{D zgo4);oEFGW&|PbLXG^m{^|kLzD|0+gS>cGkIZPv@^8AkQKuot%CcS9;e>DYWV;Z!z ztG1oHrI~KK+i03`Q=sMp-jp3~`{QO*w-kIs!x%1bB5pgUVH^`0?!w&~_Tp~Ra3~tlup7HHbYho+ z*EL+kH_7U$Oqe8#hBt6t!yeqpC|kymBx5w9;7tvea9P8*@NI#`QwN!7e7+)V+}vSPX%g| zMubfD#(NJ?^vJus{boGsO|gdbII~Ibq5XzwWcFCY3Bz0CT`TM0S_MDT@N>K;neYqQ z{4zraJJIV*Qy-SuuHaW1evRK~_$_{?;P)E-fIpHM(j^(48U=sS@Mp=lzu>PLwxdbG z-!%Lk{}5P_P5H9&Dz9(aAA{6cSI^2U>!-ZnpY(d#4j+rBG?%f-qy@D~6t7+@XKhH= z&`E}891X|)O>J4TtN**+bPaYAd53P&c}vD_O}c(eD>kz$8$ID;6BSrkmM$&X2Lx6g z2=)5=di`C7Ib5$N!=b5K)S}1q0eMv+@tm3#D8KsEGpZSx$tOgQu-+ACA8NDdQ(ewv zFO~+_!Eex+EPB$|#gflQDinz)S(uhwrB2GHhIX|W$t0~L9@m1=c~%(er0tDm#H>zI zbB1NGVX=u4P?o$5P;%?!JQaIvcc;yg)5eeyN?FFv6zL~Wc6D3j!FD5=idY?n zMRkj_XfZV}!<4-Xi6lwLTfPM_u(zD@!KHoGldriH-rY+N&$(qcHv)KoI*+ss8) zP3e_<5}AfQb3iZoDPgY)tr%;eMdI2(+FZEKdT$~vtk~Wq7k=2 z;C7C3;OCenp8ch`BWu1ED);bPg>4I0ms1ML+;tZq&axxW$~MoQEMnV+9aP7yB9Bt# z+F{XJ;mMi6yc~YaxT;(gp4`bnZi#Cgd99)Q6r*Hhpu zRF>q8L*s(oDdh5XBUn-8sw{DhVg5KiBHZK38BTeAIn2KgTvv>jv!O zZ?!PTQH~RogOtO#h5IBvIcP@*-10k(;7ce^Q|3|*tn+v#upkHPCa{nwUqtbq3s}_Z z^DG|2l5U@;M2dNvUB#}72`m+O9&3G`W%gP{v1Hx&_kN-Be`@^s+Yf(4esniCC$l~U-b@>!cCdS zQ^!QJXyNti1)3{7{t0YgVpU#2k!Y3lRk@Rc+)K2?#fp%kHLGyI zmMQ-0K#m>%_7ZMzoI|?1FoXh9ejyHH36AjG2?pX3rqD^AzL$O;WlG#f=H1UQ9HYk% z(EEolfaBDC0x|A2xi`iB5%!O=Ka+F!5GnrjNh9TB0!gGE7tO?pMOwmBzd}k_! z5Tgi8peC09W-VkeBSxO!7`8I4Z0t5ycxuOS>jweviqug@9RyL{Y6EC@2%fAyMRWrE z|4ErG*VA1&K8Z(d>44ae63#ur-A~fJr? zoB6MiAYNo@j*#y!vGTl30AFEnUM2jm5#H0hYZMQ2|4GWnC})GIl9HLyzS`zHQ0RIC a%lFLl)OVaiV5(|3C4K?pzK_P{K>rUCgw-Yh literal 0 HcmV?d00001 diff --git a/sourceMetadata/jcb-package/src/servlets/GetViews.java b/sourceMetadata/jcb-package/src/servlets/GetViews.java new file mode 100644 index 0000000..9e6273a --- /dev/null +++ b/sourceMetadata/jcb-package/src/servlets/GetViews.java @@ -0,0 +1,184 @@ +import java.io.PrintWriter; +import java.io.IOException; + +import java.sql.*; +import javax.servlet.*; +import javax.servlet.http.*; + +import java.util.List; +import java.util.ArrayList; + +import jcb.util.DatabaseUtil; +import jcb.db.VeryBasicConnectionManager; +import jcb.meta.DatabaseMetaDataTool; + +public class GetViews extends HttpServlet { + + private static final String ORACLE_VIEWS = + "select object_name from user_objects where object_type = 'VIEW'"; + private static final String[] DB_VIEW_TYPES = + { "VIEW" }; + private static final String COLUMN_NAME_VIEW_NAME = + "TABLE_NAME"; + + public void doGet(HttpServletRequest request, + HttpServletResponse response) + throws ServletException, IOException { + Connection conn = null; + try { + String dbVendor = request.getParameter("vendor").trim(); + String outputFormat = request.getParameter("format").trim(); + conn = VeryBasicConnectionManager.getConnection(dbVendor); + List views = null; + + if (dbVendor.equals("oracle")) { + views = getOracleViewNames(conn); + } + else { + views = getViewNames(conn); + } + + if (outputFormat.equals("xml")) { + printXML(response, views); + } + else { + printHTML(response, views); + } + } + catch(Exception e) { + printError(response, e.getMessage()); + } + finally { + DatabaseUtil.close(conn); + } + + } // end doGet + + private static void printHTML(HttpServletResponse response, + List tables) + throws Exception { + response.setContentType("text/html"); + PrintWriter out = response.getWriter(); + StringBuilder buffer = new StringBuilder(); + buffer.append(""); + buffer.append(""); + for (int i=0; i < tables.size(); i++) { + buffer.append(""); + } + buffer.append("
View Name
"); + buffer.append(tables.get(i)); + buffer.append("
"); + out.println(buffer.toString()); + } + private static void printXML(HttpServletResponse response, + List tables) + throws Exception { + response.setContentType("text/xml"); + PrintWriter out = response.getWriter(); + StringBuilder buffer = new StringBuilder(); + buffer.append(""); + buffer.append(""); + for (int i=0; i < tables.size(); i++) { + buffer.append(""); + buffer.append(tables.get(i)); + buffer.append(""); + } + buffer.append(""); + out.println(buffer.toString()); + } + + private static void printError(HttpServletResponse response, + String message) { + try { + PrintWriter out = response.getWriter(); + StringBuffer buffer = new StringBuffer(); + buffer.append(""); + buffer.append(message); + buffer.append(""); + out.println(buffer); + } + catch(Exception ignore) { + } + } + + + /** + * Get the Oracle table names for a given connection object. + * If you use the getViewNames() for an Oracle database, you + * will get lots of auxiliary tables, which belong to the user, + * but user is not interested in seeing them. + * + * @param conn the Connection object + * @return the list of table names as a List. + * @exception Failed to get the table names from the database. + */ + public static List getOracleViewNames(Connection conn) + throws Exception { + Statement stmt = null; + ResultSet rs = null; + try { + stmt = conn.createStatement(); + rs = stmt.executeQuery(ORACLE_VIEWS); + if (rs == null) { + return null; + } + + List list = new ArrayList(); + while (rs.next()) { + String viewName = DatabaseUtil.getTrimmedString(rs, 1); + System.out.println("viewName="+viewName); + if (viewName != null) { + list.add(viewName); + } + } + + return list; + } + finally { + DatabaseUtil.close(rs); + DatabaseUtil.close(stmt); + } + } + + + /** + * Get the table names for a given connection object. + * @param conn the Connection object + * @return the list of table names as a List. + * @exception Failed to get the table names from the database. + */ + public static List getViewNames(Connection conn) + throws Exception { + ResultSet rs = null; + try { + DatabaseMetaData meta = conn.getMetaData(); + if (meta == null) { + return null; + } + + rs = meta.getTables(null, null, null, DB_VIEW_TYPES); + if (rs == null) { + return null; + } + + List list = new ArrayList(); + System.out.println("getViewNames(): --------------"); + while (rs.next()) { + String viewName = + DatabaseUtil.getTrimmedString(rs, COLUMN_NAME_VIEW_NAME); + System.out.println("viewName="+viewName); + if (viewName != null) { + list.add(viewName); + } + } + System.out.println("--------------"); + return list; + } + finally { + DatabaseUtil.close(rs); + } + } +} + + + diff --git a/sourceMetadata/jcb-package/src/servlets/InsertClobToMySqlServlet.class b/sourceMetadata/jcb-package/src/servlets/InsertClobToMySqlServlet.class new file mode 100644 index 0000000000000000000000000000000000000000..1b72a913fe15f2a0ee622755f7ab722c605ca6dc GIT binary patch literal 3307 zcma)8*;gCa9sUL+jTi=F%d6bjmXnwQ5=<6%v8*Vu@q%h02w-D3>mZF`h@_Ecu2`J3 zX}Tp%lQv0rcTd{7NnY$10?9eeTOayI<>b3FLJ|h*9MHWp_qTt)<<9@U`1C&j9>vER zhH*ZM3sGE*VpKy8-_dXh`6$M^QNXx{AxuQ^bQF`_n8I`vm*svXiWv=8aZS>{E0<^F z@~n#IH0+ZapO^a!QM@R3Q^l-?!ze~klDj3DuSYT0jd|GJSinniDQl>ps>0FmFlutS zp}~bG7onk!MY$|#SjLK6ZmM`$#VZQBbA_q%lhZGZZ$9Fzc* zomr2;3acv4cmbvg`WmL%fo_1)enbqJgvx~JniWe}E*+k7>Tc1xU`v3H9Y4TpDt@TroA{A}4!fk{$2xw3Gdj-V3>mBRkK1*+rQ)YLUdI~> zx`eeXvsNkV_!-_*kj}`LY-ZjvOWBODMcK;k6hg)b=o!Q3R`GKkZ{bbp!nbrhB~54X zB*VM6V9(a=a!H1l%FH^Y6mzVBHbzr;HvwG1_@RmZy$;yo=(=Uvxv(+M5#;T;{PkXDclEYktuBub_* zB}!huT}mb7lY}mKl12v-i?YeQME{eig!~^+@hcs_#&1;oR>$w~dmVqkEfs&%@hALQ zf$qCiWqVwn%*&J$qQBs;D*mS9?|59t`}jb`KXm*P|B@oNRs37Whq$HVBN^7Aof07H zgH^P1`)xpCJ4SB23CR|*MoG3Y^tO;3DVrV(O}*~81;2z&+@~>o0Zxnqz7E-`K{bz= zRdY^eeQX;AU#VXMrh9r{!HNG5LSqIo5A5}}KJB}oSTK_~HYqn=7qz}CsBzefGN*LJtktY)Nx{%|>b5}H zXgB&370$+Z+qW_4HxIL3-^i3Oi!V*PW|1yyjDF1WJmzkroHl1b!S0%C)lAo-n6N4g zR>31XdnTnP0)bLfg3cXo*2@+u2NjXraQ#4kZcB{3IXH=}Wvf^h*5w*|nBMa8%MtU1 z;;c~@HtUd`J!^W_WxntdE0!IPT*n%&Zts`WyUQWmt=o{UZh+Tl>K3h8_gg4TU@^F9 zsgRiFs%-_;ymw`%wg}YL+w?v+9{9c2ZZS+Z^EuFn;vNOt-dKlr;AN=0{Uo&21gnh$ za8Atg?vNK9j`QPYn4ediOEB;V_ec5Gfn!kl%=?V%NuC_xu5b?zegfsLFYpbn5&uv_ zm%Jq?CRy|7M40;nv5rfz&U`F177G;y*ASjbriRuKNr&R0J53EoX$aU&nLX4Nqo%#k z`5Cqc`w_<`ENDCS%A1DPS9ZJU3bwoR`hOTrt8Pl3Ckz}m9`J$%Q zq4Q3RreZzo*wuk}G}gO{-D}uGm((@H3WM=bJRFY99ofu!myVBM2{-)^Bxn~HoJ6z(M;S(fK_4gH44^Unk9>ZYIy>q3DOx>6H|4HCLNJVOu31u_LJ!U`&u0mN4Eh}TFS43O z$$gR3QJ&`7s-R1LiZpzEneq|pF_ipgc=#Gi^TZethYf>>UOq zAHttgTvm7=Mf=e2?}1x`eo+-jouGqHvn(fBic>7aY4Xny*{kH9VLq<5xunT&G6p7# r|1s{ePhx}rg*Lc~c+ literal 0 HcmV?d00001 diff --git a/sourceMetadata/jcb-package/src/servlets/InsertClobToMySqlServlet.java b/sourceMetadata/jcb-package/src/servlets/InsertClobToMySqlServlet.java new file mode 100644 index 0000000..7abc47d --- /dev/null +++ b/sourceMetadata/jcb-package/src/servlets/InsertClobToMySqlServlet.java @@ -0,0 +1,99 @@ +import java.io.*; +import java.sql.*; + +import javax.servlet.*; +import javax.servlet.http.*; + +import jcb.util.DatabaseUtil; +import jcb.util.IOUtil; + +public class InsertClobToMySqlServlet extends HttpServlet { + + static final String INSERT_CLOB = + "insert into datafiles(id, filename, filebody) values (?, ?, ?)"; + + public static Connection getConnection() throws Exception { + String driver = "org.gjt.mm.mysql.Driver"; + String url = "jdbc:mysql://localhost/octopus"; + String username = "root"; + String password = "root"; + Class.forName(driver); // load MySQL driver + Connection conn = DriverManager.getConnection(url, username, password); + return conn; + } + + public void doGet(HttpServletRequest request, + HttpServletResponse response) + throws IOException, ServletException { + + String fileContent = null; + Connection conn = null; + + String id = trimParameter(request.getParameter("id")); + String name = trimParameter(request.getParameter("name")); + String fileAsURL = trimParameter(request.getParameter("file")); + ServletOutputStream out = response.getOutputStream(); + + response.setContentType("text/html"); + out.println("InsertClobToMySqlServlet"); + + try { + conn = getConnection(); + fileContent = getClobsContentAsString(fileAsURL); + insertCLOB(conn, id, name, fileContent); + out.println("

OK: inserted a new record with id="+id+"

"); + } + catch(Exception e) { + e.printStackTrace(); + out.println("

Error: "+e.getMessage()+"

"); + } + } + + public void doPost( + HttpServletRequest request, + HttpServletResponse response) + throws IOException, ServletException { + doGet(request, response); + } + + public void insertCLOB(Connection conn, String id, String name, String fileContent) + throws Exception { + + PreparedStatement pstmt = null; + try { + pstmt = conn.prepareStatement(INSERT_CLOB); + pstmt.setString(1, id); + pstmt.setString(2, name); + pstmt.setString(3, fileContent); + pstmt.executeUpdate(); + } + finally { + DatabaseUtil.close(pstmt); + } + } + + + public static String getClobsContentAsString(String urlAsString) + throws Exception { + InputStream content = null; + try { + java.net.URL url = new java.net.URL(urlAsString); + java.net.URLConnection urlConn = url.openConnection(); + urlConn.connect(); + content = urlConn.getInputStream(); + return IOUtil.inputStreamToString(content); + } + finally { + IOUtil.close(content); + } + } + + private static String trimParameter(String s) { + if ((s == null) || (s.length() == 0)) { + return s; + } + else { + return s.trim(); + } + } +} diff --git a/sourceMetadata/jcb-package/src/servlets/InsertClobToOracleServlet.class b/sourceMetadata/jcb-package/src/servlets/InsertClobToOracleServlet.class new file mode 100644 index 0000000000000000000000000000000000000000..2540a384797785ba1b4904b52a6567b05bd173e8 GIT binary patch literal 3340 zcma)8X;&N98Gc4c8ZivUmThchvE?LCAqf<_PTR2gl|g+Oyo^Q|BHqk8(>86kmzItO&OcYogZzIXof-+%rK zz;XOTLk{O+I3L4!45b*ps^J348YWPQVX_BPcv`~yrMA9G;cKH&i^Q;hDlMT%9EoC;^k|`vXQG9 z^@ZGw=UDZHQwn;=?7Hh2b?=fpP?qJpl}&?N=oG27&6U)idQN^@ymIJ3rl zjVHYe!lP(iR6WbCD>#%I3e>yTYq<`A7PPY~Rnd@Ku7ZeZpBJ8j>6FjCl5>T#ToYby z(eoO)aSk)V!L+#E6s~vbo@{P|ip8m+ODevt;yaAMw5M#BHZ+R_#|wh51O{_=xwjpX z&vPP?IV1t7+4C-g^+er!$_+48FxWD+8R!-`n~#Vgldv>pIL4CjghPjC?50x{=PU{E zky7A2P0ZSpj!~_N7BnL=jXJ)FlM0U7K4s*ZIbR(y9cx)QBLVXnf1@BJN%?>+?=4#O z{OOuqHEN5*D1ZF16UXya!);gwa~N@}wnyM1p0ywx6))@fF21MY`#QdiA1DY}rixc| zyoymBV_->z>-3$|Rl2O=hdO?QA1mng#EQ)5QccHC@S1{C1-U5}7KLFJ3!dfGL~+;f z3b}xxkn`D9{8Y!!@S61DD>|N%wx7glCgARB9&K7RQ{tE{%-iNonmbvXypT@@WgyI? zk*tdwNk>#|$4uU^yv3wtKB431_=SS~G40Y^O~W%JOm50Dvq`y<*aa(TbSSwjZ=jn@J(*3){~;B> z(eYcnq2hNsevdbG`~h#N_@jo|D&c*4nEC)jLHr`S3u8#L`QpaELzKRcY z+{TAe$6MmkmL^ zYC9Fbhz9O)ZF~Wu+VAU-_c$o=38QYXTop|0px|@e=78z0&Y)o6|AWx#P)r0n!KPb0 zcrUS_W3j1HZnEh$njSlcFqUYs)kHhUw;3 zKOtO~x!WkGtr<|Tx8aC};RuR(Vu`^jcyxEqr1VrEV74Xb+4ZCNxX1nA%+H!Sgzogzh zHsS8Pm2`CjywA?=J<1@hHE-6rA8Lgd|k1 z`PgxMj3*CrRyaq}pFp|e3w()V)IZeFEuRUBN!BvD5aIklJai%6RgQ-z;*m;v4bizw zc6beHKAZ@D+}3b}hJd}4*+*@0YT6GS2e>m52i#t+3? zeh3n@a|})*8p08Vkz~-va1;+Ai-(E#016nS#1O`jMg{^hbBnopiP?IYnR=Ib zlF&q{rGO`BqqqSMwRG_hP}7<0DvoxtrI8uTQ?p0JT9?ssI20 literal 0 HcmV?d00001 diff --git a/sourceMetadata/jcb-package/src/servlets/InsertClobToOracleServlet.java b/sourceMetadata/jcb-package/src/servlets/InsertClobToOracleServlet.java new file mode 100644 index 0000000..edca573 --- /dev/null +++ b/sourceMetadata/jcb-package/src/servlets/InsertClobToOracleServlet.java @@ -0,0 +1,99 @@ +import java.io.*; +import java.sql.*; + +import javax.servlet.*; +import javax.servlet.http.*; + +import jcb.util.DatabaseUtil; +import jcb.util.IOUtil; + +public class InsertClobToOracleServlet extends HttpServlet { + + static final String INSERT_CLOB = + "insert into datafiles(id, filename, filebody) values (?, ?, ?)"; + + public static Connection getConnection() throws Exception { + String driver = "oracle.jdbc.driver.OracleDriver"; + String url = "jdbc:oracle:thin:@localhost:1521:caspian"; + String username = "scott"; + String password = "tiger"; + Class.forName(driver); // load Oracle driver + Connection conn = DriverManager.getConnection(url, username, password); + return conn; + } + + public void doGet(HttpServletRequest request, + HttpServletResponse response) + throws IOException, ServletException { + + String fileContent = null; + Connection conn = null; + + String id = trimParameter(request.getParameter("id")); + String name = trimParameter(request.getParameter("name")); + String fileAsURL = trimParameter(request.getParameter("file")); + ServletOutputStream out = response.getOutputStream(); + + response.setContentType("text/html"); + out.println("InsertClobToOracleServlet"); + + try { + conn = getConnection(); + fileContent = getClobsContentAsString(fileAsURL); + insertCLOB(conn, id, name, fileContent); + out.println("

OK: inserted a new record with id="+id+"

"); + } + catch(Exception e) { + e.printStackTrace(); + out.println("

Error: "+e.getMessage()+"

"); + } + } + + public void doPost( + HttpServletRequest request, + HttpServletResponse response) + throws IOException, ServletException { + doGet(request, response); + } + + public void insertCLOB(Connection conn, String id, String name, String fileContent) + throws Exception { + + PreparedStatement pstmt = null; + try { + pstmt = conn.prepareStatement(INSERT_CLOB); + pstmt.setString(1, id); + pstmt.setString(2, name); + pstmt.setString(3, fileContent); + pstmt.executeUpdate(); + } + finally { + DatabaseUtil.close(pstmt); + } + } + + + public static String getClobsContentAsString(String urlAsString) + throws Exception { + InputStream content = null; + try { + java.net.URL url = new java.net.URL(urlAsString); + java.net.URLConnection urlConn = url.openConnection(); + urlConn.connect(); + content = urlConn.getInputStream(); + return IOUtil.inputStreamToString(content); + } + finally { + IOUtil.close(content); + } + } + + private static String trimParameter(String s) { + if ((s == null) || (s.length() == 0)) { + return s; + } + else { + return s.trim(); + } + } +} diff --git a/sourceMetadata/jcb-package/src/servlets/JDBCDemoCreate.class b/sourceMetadata/jcb-package/src/servlets/JDBCDemoCreate.class new file mode 100644 index 0000000000000000000000000000000000000000..7a6a618f45c8a795513c6044f5a083e6feb280a1 GIT binary patch literal 1312 zcmZ`&?^6?36g@8>yDS@_Q4mn-q6HH|6Mj^&AXo^|(g}8^piZYVoq5^3hQ;h|`m#~^ zi~3c+_@mDF2lS8X^t@n5nCgdY_P%%TIp>~x_n&|N{s>?hdk#i1?;wp^Bgi6WV_^h& zEL!;1!4L{IiVl{rY#u8%RvmnY+ZOJaig^ob0`^hdN+KC5flTFCK9|LYjOxXMLqgEoLAFhD7%4vq;z;01Hg~G3^=G5lyP&Ya zPzFqx$o}?!*@nV7h}+s%4*~;w>8IVD(yj{Ql2$TN1=FaDYnXB2Vb;Qii+k7`%?qN$Yw94B`ow#tP8L1Wrsp3?on5(|^KurpT-?VGWa@cX ze(9^GX~V@fX4p%t>xKGpQV7FBc*2GXyE=HTw1piPCG5H=gv*+Vy$}LxV+i5dcN!OX7|OyL(|lc0vFFWEil&8_H*@^77GlY;nPvWAdsq6 zyKS5|o%8ZL_8lbjFjNuiC;I1ecFyr+I$Q?e?3B}0FO}a;)Z-=>hhrJfer9%ir+|`1BK2agv&;tZa#wk0-%tHu(!`nW z)8XvPNY<4W$bFgRyiFUJ<<~XJ@ACqtF@~=|HyEXGiSgyWc%1P>Uwnn}WM4eRc)BmX ziUDGAYx(?|h`$qafd4lZ-a_z~s^s5eKwy6{Gx#1CQh53o?ES?zuwJub7*nhr;@fpo z1Dnq@2B~zI`o^ekifXP=;S9#v!z9u9aeU&6`ER&xX6$zuegnr~SMtObmCVRHxRowf z{uK*BP?ux|v`4xChc`34o8|3w(tB(#$E-Z_R+zcO+hyLaGUo"+value+""; + } + + public String getHTMLOption(String selectedKey) { + + if (key.equals(selectedKey)) { + return ""; + } + else { + return ""; + } + } +} + diff --git a/sourceMetadata/jcb-package/src/servlets/MakeList.class b/sourceMetadata/jcb-package/src/servlets/MakeList.class new file mode 100644 index 0000000000000000000000000000000000000000..218b97a545ffc19b4ce58bb5d9312a9f919664eb GIT binary patch literal 2514 zcmbVNO-~zF6g`8DJs9&57f2vDxCsF>HV{Zd_;eBo5Qwp9pimN3t-*sciDOfLv<*?S zDN>bwsEe*hTd9gvkw{(8jZun+T#<2AnAc>C$`}*obs6I_CS*)nal?u!36^0krloumOzw^a3FfhQSd~!Y*J5fQ z{a{&5%!ihv^qhDQy02bO#Mi>{4`Y5Und+6$>h|9YeGuwSr?hCd@C|ij9nnxM(mj_- zXtBtUgubG*;;fPjYY*3yP%m6dYBCTn#3G^1s8LwCS6zsEA?%;95$H$0XFb3)AwdwuIK!)L2-8_gK=)&WqchE>1UM;{0_MM@t+k zV^G{pPQ|l`c#@-PERwoQKGgTqp=fd{5{oC)u~3qI*O%Is#9OkdhY}1bI&R~2H1kpt z9~(tTQS#~Ho0GrPCCZf@NI%h#m%L7UyWY=z9bcZ!KU_`3-jECCVf`g~ego z-i3K-2jza#NORWx3{Iu_B`jt571n^KGXpt;ip7mGY3rZAc41rc?4WX+TV;!#g-pAJ z7oH2XEO!d$(TX~&G^ImiDm2LB%)(Q_gHb9w%4 zgJzxnQ=4e<=DKfW=Z)t5_P5ZSj|pZ9V;f>*FN#OjMX(-hIUAPa&?i;x=eXQ_&`_9%n1EvRAC<~z(SH_C>kR+V!D1Ci z!;X(ohjpI6N7T_ehVfX3&|yG$P6*;yMN2@?nIwd1#o0^ck~&wO9zh-5`(U=<%m)Q` z2ZB0znPT!3-Uq-ZM6^MqpAzX4BK@37`hrUPl1lpu@6fk`ubHFdb-zk|3DkoQ(@_#P zW=!0*jwU_~mHTzlUU~L4*Tm}v*yJF-K@Gk|6TU+)?S6dEnx6k#^Ynk${DC#MSo1k+ SzF^HQ*8Guk@e)rNI{yU#^DP + * @author: Mahmoud Parsian + *

+ * Description: This class is a utility class for servlet programmers. + * It generates HTML lists and elements from specific data structures + * extracted from users and databases. Each method returns a String + * object, which will be inserted into an HTML form provides by the + * PreparedHTML class. + * + * + * This Java class is free. No license is necessary. If you have any + * ideas on how to improve it please send email to mparsian@yahoo.com. + */ + +import java.io.*; +import java.util.*; + + +import javax.servlet.*; +import javax.servlet.http.*; + + + +public class MakeList { + + + public static String makeDropdownList2(java.util.List list) { + + if ((list == null) || (list.size() == 0)) { + return ""; + } + + StringBuffer selectionList = new StringBuffer(); + + for (int i=0; i < list.size(); i++) { + KeyValuePair kvp = (KeyValuePair) list.get(i); + selectionList.append(kvp.getHTMLOption()); + } + + return new String(selectionList); + } + + public static String makeDropdownList2(java.util.List list, String selectedKey) { + + if ((list == null) || (list.size() == 0)) { + return ""; + } + + StringBuffer selectionList = new StringBuffer(); + + for (int i=0; i < list.size(); i++) { + KeyValuePair kvp = (KeyValuePair) list.get(i); + selectionList.append(kvp.getHTMLOption(selectedKey)); + } + + return new String(selectionList); + } + + public static String makeDropdownList(java.util.List list) { + + if ((list == null) || (list.size() == 0)) { + return ""; + } + + StringBuffer selectionList = new StringBuffer(); + + for (int i=0; i < list.size(); i++) { + String s = (String) list.get(i); + selectionList.append("

  • " + s; + } + + return bulletList; + } + + public static String makeNumberedList(java.util.List list) { + + String numberedList = ""; + + for (int i=0; i < list.size(); i++) { + String s = (String) list.get(i); + numberedList = numberedList + "
  • " + s; + } + + return numberedList; + } + + +} + + + + + + diff --git a/sourceMetadata/jcb-package/src/servlets/MyDatabaseServlet.class b/sourceMetadata/jcb-package/src/servlets/MyDatabaseServlet.class new file mode 100644 index 0000000000000000000000000000000000000000..52da80b1a3ac774ca8fc30f11b0e79ed5132343e GIT binary patch literal 2712 zcmb7GS#uLd5dOwUS|P6i3w$U*5SJq#Vj&y>Sr)+u*ue)_#smlnD`~Lhth7Q}Id%fM zA@}i`UqDsfcoBA}O5XF3pOoaAUCRgNNNTHkW_o)1_`0WO|NQ&6-vJ!M&mqKcI*2nt zBpT6+WC(pog>V*cHsT!m8!>>v5MIMj2p|QI;vF@;8N|Elu69ATny2)sWL5 z1p>)@G4G@Vw!}K81$+Z`j@<2|`Jx=J7BaFtWo9gL{5kuAbOa`2qjToGxnNXedESza zG3z)bW0)lEF(&1ms;oG@FBPkl>|#asDyyNPg{&+&c``KI)-WTmtyInzok>}#T25LS zKKpXRD;izPM&*uWtRDBQxGIOrWxFiU_dnHHW^u+yJ9KKsQSR+xx+S<2w`>XVP$ENF@y~B33NJ z)9}5HAMm4qzCK;QW~pSspl$h8zU3zxQAb?cjbc7 z@fqn{GRuV4QP^~N744)y7aN*P=` zryAM%oizv5PW!qu>wa{YJjYgqFi7a_)=V_X4)T7S@Fe2I!8Qzys9IBWId~p;{VYJ z_qNlEJv|i*7tq{}ZxxkCoBdJPZ{Sa4=2+Ei@7T{5IL5~u@PW0A zF4AtU_Hq;){aueC9&tioNdqpkku;7YXi%b}nd4UO-3vF2i-b=k{2~$P4sTh8uK_jq z6Iw)DLLd={1eT!*B>WM7d>O$8Bz!#)-x9Ve5{mej&=?6UL4Sx739Toh)v#>|+c#~t zC4x`!BEdf%(SIFhaFM?iYMiA*7cuRQvzT*7FN6%*xwivb__Gi|n6B^Si5C7sv?7W& zV$hD`T%Ex_q{tZ{M#DHjZM*rSvWGhN;RgA)$d}~La&2?%aJ|U&T^xepLe+qy{7DL_ z_sfF{f6=POy$4;(*dZ|X1kKkTBRn1t@2p|h)p)o?4c*IV75D||Zr?K68gRQLd6NhpCH1cuY`Bku&2dW!`|?#oJIU3?yM!Cc>B1lA*!@K{O8wrc)yzU#A`TE z!@;$*o+4^s"); + buffer.append(""); + while (rs.next()) { + int id = rs.getInt(1); + String name = rs.getString(2); + int age = rs.getInt(3); + buffer.append(""); + } + buffer.append("
    idnameage
    "+id+""+name+""+age+"
    "); + out.println(buffer.toString()); + } + + private static void printError(HttpServletResponse response, + String message) { + try { + PrintWriter out = response.getWriter(); + StringBuffer buffer = new StringBuffer(); + buffer.append(""); + buffer.append(message); + buffer.append(""); + out.println(buffer); + } + catch(Exception ignore) { + } + } +} diff --git a/sourceMetadata/jcb-package/src/servlets/PreparedHTML$PlaceHolder.class b/sourceMetadata/jcb-package/src/servlets/PreparedHTML$PlaceHolder.class new file mode 100644 index 0000000000000000000000000000000000000000..c71b05d3de75f9f2d0cabbf1fd274522cc7e4fc3 GIT binary patch literal 666 zcmZWmT~8B16g{`w?b>B13j$We51^Q`RnZ3%6NoP)rcJ7n(D>lnv^#+%+bPa&jemvz zz>A61#0LYf{0P*>ChJTPgymbk zhEA2q2!(7fPAiWIrRKI#2hymh-g?<&p~7aY-N6tWE*R53I0y6Z#wElY^SG3eLb=_7ARp#Ai#>i zH53H|iXJM2^5|$~JCPk#?Mqt!;2vT=`~;_V442_E3Wsp>N6yhd fwGtf8f1!+XEZ~Aq&U2l^4cuk)S<}TL?f`!P7fFoN literal 0 HcmV?d00001 diff --git a/sourceMetadata/jcb-package/src/servlets/PreparedHTML.class b/sourceMetadata/jcb-package/src/servlets/PreparedHTML.class new file mode 100644 index 0000000000000000000000000000000000000000..bb63127d3586b66f39453093950b7bc0729dfab9 GIT binary patch literal 2844 zcmai0S!^3s6g}fiGWK+mwr&k^8t6hx61%S18XzfKHxh6b($HYmI`K>5)UnNYTml73 zq3lq$LJ=yUB0)eP1XAPBntcbceISIy7hgzx!awD_nMpkGH#GxH)^te~dVJ{9OYPmS*VOg`Q( zDMMz)5~h7YOJ|A%hX6($p{aOLn7gvVijP}XA>PGhn?o27#R6Rv_C3FqcaTxAw6)FS z%n7{wrbwl?5>p1aEnhN6gmYNjZ;C?76zQ(Pp2Rwt2m=>lqk;3V-at1t(qFI0Y7Z1r za<_qVaIS&dafg9BvB$vW=rV8@)-x@3UKyq|C51Z-oR16Sve&@fxW~XgX=RgSw9Bu1 zrM)F{*F5NGxX-}-ctC1-P~Ohki{6BQ!l-8 zh*Ik#a(Pt2BAe|gMg#lNrJ#Ak%2>>c#5xZW8Xl7nJZ|6#JZa!5+{2{DVl2OKRh^TI z!Te5<%iJbCQ5g1xIAGvu3E49^NRm$2yjJEMvcq&r%Y#sN--%*Xu)a0nz1jKCGWaJ& z)}@xorNva=C^7R^wp+*DZQTk2A}c0E&bo}{8*1(LR+uYBx5wFwgZXaOr0LW=+fXes zRJ#GFrM_T_5m9a1+R<#OIIiGKiP8U8I-7M&SbZg{P_l@nNKGnO<5qk1w%ZWc+ohLV?pn!CG(lZs&MIbx2M#w>#PKU2xQAma_>#FS;1A!k7vjrNSqBonJmV9qgT5Ywv7p?iv&pbO-sJJe|Yc$Gssk3ndbrfsY?GZ4o5yCEk=BksU*?7>=2%nPuW@$cbq+cysf4m%fz0{xQyZ15Uf<24wK9l@e97Rz1d zZrlDTN|B(Xma*hyKlT&%#}LNjMB)jwaoEKu|gDrE2*glUXcwt^7d>Y(HcDs>WUO{7W7U6_9qLzP&sAlmwota+AJ#(tx*cK7WvF4T zCghhQfeKoa;Xtr$7Lg7;%;ZLg?6o5x;j%j;9EcGNc1Ia&=Nz2ILfWOpAbCwg)5o_* zq|gk4)tu$9j1U}QMb7Y7BK=@u<9LTvaFpGAj5(|zfp^h|_b`C>*|Q(8S3hLee8e~Z zV?NBE;2=K5VSI)+@i{ep!5d%V2YiK}@il(IH~0 where placeHolderName + * is the name used to set the value of the place holder. Below is an example + * of a simple PreparedHTML file that contains a place holder called tableRows. + * + * Some Table + * + * + *
    + * + * + * To use this PreparedHTML file, construct a PreparedHTML object passing in + * the file name, call setPlaceHolder(String name, Object value) with the String + * "tableRows" and the value that you want inserted into the HTML (value.toString() + * will be used). Then call the print method passing in a PrintWriter object + * and the expanded HTML will be sent to the web browser. This HTML file could + * be handed to a web page designer for artistic improvements. + * + * PreparedHTML supports multiple occurrences of a place holder name in the same + * file and you only have to call the setPlaceHolder(...) method once. Also, feel + * free to put place holders anywhere, such as on the same line or inside quotes. + * + * If the setPlaceHolder(String name, Object value) method is called and the name + * is unknown nothing happens. If the place holder of that name already has a + * value the old value will be lost. If multiple place holders with that name + * exist, then each place holder will get the value. If a place holder's + * value has not been set then the String "null" will be inserted for that + * place holder. + * + * A PreparedHTML object can be created once and reused by calling the reset() + * method after each usage. This method checks if the file has been modified + * and reads it again if it has changed. This way changes to the HTML file + * can be viewed immediately. + * + * This Java class is free. No license is necessary. If you have ideas on how + * to improve it please send email to garth_fisher@excite.com. + */ + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.FileReader; +import java.io.File; +import java.io.PrintWriter; +import java.util.StringTokenizer; +import java.util.Vector; + +import javax.servlet.*; +import javax.servlet.http.*; + + +public class PreparedHTML { + + private Vector placeHolders; // holds all PlaceHolder objects + private String fileName; // name of file passed to c'tor + private String endingHtml; // the html following the last PlaceHolder + private long lastModified; // used to check if the file as changed + + + /** + * Constructs a PreparedHTML object + * @param fileName - the name of the file containing HTML with + * special place holder tags + */ + public PreparedHTML(String fileName) throws IOException { + this.fileName = fileName; + readFile(); + } + + + /** + * Call this method to set the value of a place holder + * @param name - the name of the place holder + * @param value - the place holder is set to value.toString() + */ + public void setPlaceHolder(String name, Object value) { + PlaceHolder ph = new PlaceHolder(name, null); + int i = -1; + while ((i = placeHolders.indexOf(ph, i + 1)) != -1) { + ph = (PlaceHolder)placeHolders.elementAt(i); + ph.htmlToInsert = value.toString(); + } + } + + + /** + * Call this method before reusing a PreparedHTML instance. If + * the file has changed it will be read again. This method + * removes any previous place holder's values. + */ + public void reset() throws IOException { + File file = new File(fileName); + if (lastModified < file.lastModified()) + readFile(); + else { + for (int i = 0; i < placeHolders.size(); i++) { + PlaceHolder ph = (PlaceHolder)placeHolders.elementAt(i); + ph.htmlToInsert = null; + } + } + } + + + /** + * Writes the HTML using a PrintWriter. The value of each + * place holder is written where that place holder exists + * in the HTML file (the file's name was passed to the c'tor). + * @param out - the PrintWriter used to write the HTML + */ + public void print(PrintWriter out) { + for (int i = 0; i < placeHolders.size(); i++) { + PlaceHolder ph = (PlaceHolder)placeHolders.elementAt(i); + out.print(ph.precedingHtml); + out.print(ph.htmlToInsert); + } + out.print(endingHtml); + out.flush(); + } + + /** + * Writes the HTML using a HttpServletResponse. + * @param response - the HttpServletResponse used to write the HTML + */ + public void display(HttpServletResponse response) throws IOException { + PrintWriter out = new PrintWriter(response.getOutputStream()); + print(out); + } + + /** + * Provides the value of a PreparedHTML instance as a String, which + * can be very helpful when debuging. + */ + public String toString() { + StringBuffer html = new StringBuffer(); + for (int i = 0; i < placeHolders.size(); i++) { + PlaceHolder ph = (PlaceHolder)placeHolders.elementAt(i); + html.append(ph.precedingHtml); + html.append(ph.htmlToInsert); + } + html.append(endingHtml); + return html.toString(); + } + + + /** + * Reads the HTML file (the file's name was passed the the c'tor). + */ + private void readFile() throws IOException { + File file = new File(fileName); + lastModified = file.lastModified(); + BufferedReader br = new BufferedReader(new FileReader(file)); + placeHolders = new Vector(); + StringBuffer strBuf = new StringBuffer(); + String line = null; + boolean foundPlaceHolder = false; + while (foundPlaceHolder || (line = br.readLine()) != null) { + foundPlaceHolder = false; + int index = 0; + if ((index = line.indexOf(""); + line = s.substring(endIndex + 3, s.length()); + String name = s.substring(0, endIndex); + StringTokenizer toker = new StringTokenizer(name, ":"); + toker.nextToken(); + name = toker.nextToken(); + placeHolders.addElement(new PlaceHolder(name, strBuf.toString())); + strBuf = new StringBuffer(); + } + else + strBuf.append(line).append("\n"); + } + endingHtml = strBuf.toString(); + } + + + + /** + * PlaceHolder is a helper class used by PreparedHTML objects. It does + * not have scope outside of this file. + */ + class PlaceHolder { + String name; + int htmlIndex; + String precedingHtml; + String htmlToInsert; + + + PlaceHolder(String name, String precedingHtml) { + this.name = name; + this.precedingHtml = precedingHtml; + } + + public boolean equals(Object obj) { + if (obj instanceof PlaceHolder && + name.equals(((PlaceHolder)obj).name)) + return true; + return false; + } + } + +} + + diff --git a/sourceMetadata/jcb-package/src/servlets/UpdateBlobToMySqlServlet.class b/sourceMetadata/jcb-package/src/servlets/UpdateBlobToMySqlServlet.class new file mode 100644 index 0000000000000000000000000000000000000000..da00dec3c3adcb57b5ba0b82b4b201208329e4b1 GIT binary patch literal 3389 zcmai0`*#z^75>(iwDNjwKwyI?5D{u(Tb4y#N?IXIZDYW-WK_QhX_Is%P2_bYtyrzV z?kj!2-)WOJZPWBg-v!bNE1c8*)*t%s^!J{Avnxw7*yZSGW_IS@JNJI~HUIwaJO2Ri z9z4`Afe!^SA4DpMw1x#-(~!Z3d$5S5AeJ?(U^R&Ay?72cG;%y2#7BDZQM?eui*kM` zh>vM7uqqF;a>&UcuR>@Tl(Juzb0LT|Ih!ihgZQ|HV<<|xQZLG|dbp~{)lCgHs=aVf zlfx}J+?EF$8aD9>6`#~Ff=|ie(;7a5SLE>OjC*^@xJ#kp z4XI;7#|$p%n8Gyee>A$MYi2Po?H@{Jt^6j1pPjrmpNM#2l8@LTXW9A4ZPQtcnE4Aj zeuAGWILIr`PA20Xi>u?Lj-TO89<^_1#khh4ZRxYNZP|&4j-TUA9Z6hJ@s^HX;Fmhy zi?cd@gT$-*o&P=XBKZK*g4hhGcz5>NniIVz6`oD zWNv%$oi@rwLAp7;i-5gyzBBLkDrEcH$}VkI9Z_PDv}&vc1FgD|VHMr38y%o@Y}3Mu zBr39I4(y_!tTsdcAMIvoWJs_ob(WPUv3aG^t7g|~POHR8tUaUKE^hj&lZ;sRGk%&S zaCx&rC!O4R=Pq2V!$zed%6SE`-RynLBh57BZ9&KK`jUb}+wG;(QS2>5AT6p@I(!@M zokgC-mnu)y9BalZl}tLzH~hTBcz?wf6~h)w4qHUYE$L_WR!<7ecntX#2Q~C6z|Mlt zYQ|(Si(a2(8=X^d)D4|orO+MJaM~;z_NLcyNIpE*3aQRkG$%FhA^A2egWH6iut=gl zu_1CbM|desALN?m53J|1@tR{YTMWm@8db5v4_4${(W(-}rOjry6*-4`H95I1Y7l(ZFd1*P{(Qqws4B!*|e^@Vl$9|DX3LyPFX) zMY&TnNzMu+3={ON-0SA9hD-GIECIQUD6Y`RtK^xdc_~uN^DD(M-4Ovj@|n`qTgvcJ zR`?-CZZIfEQ_(u2X#z0De{3Pv4zWQu99I}HtLVpd2HSHCup1qMHTk@viZaqCILk;6 zjs6STXdUBkFzD}c5pPTEckzA!y?BwHH0aeUtxP%La??|xGjHQ$+ZkS}^zrm6rFUWO Ee>%ctwEzGB literal 0 HcmV?d00001 diff --git a/sourceMetadata/jcb-package/src/servlets/UpdateBlobToMySqlServlet.java b/sourceMetadata/jcb-package/src/servlets/UpdateBlobToMySqlServlet.java new file mode 100644 index 0000000..a10f7ae --- /dev/null +++ b/sourceMetadata/jcb-package/src/servlets/UpdateBlobToMySqlServlet.java @@ -0,0 +1,100 @@ +import java.io.*; +import java.sql.*; + +import javax.servlet.*; +import javax.servlet.http.*; + +import jcb.util.DatabaseUtil; +import jcb.util.IOUtil; + + +public class UpdateBlobToMySqlServlet extends HttpServlet { + + static String UPDATE_PICTURE = + "update MyPictures set photo = ? where id = ?"; + + public static Connection getConnection() throws Exception { + + String driver = "org.gjt.mm.mysql.Driver"; + String url = "jdbc:mysql://localhost/octopus"; + String username = "root"; + String password = "root"; + + Class.forName(driver); // load MySQL driver + Connection conn = DriverManager.getConnection(url, username, password); + return conn; + } + + public void doGet(HttpServletRequest request, + HttpServletResponse response) + throws IOException, ServletException { + + System.out.println("--- UpdateBlobToMySqlServlet begin---"); + + InputStream photoContent = null; + Connection conn = null; + + String id = trimParameter(request.getParameter("id")); + String photoAsURL = trimParameter(request.getParameter("photo")); + ServletOutputStream out = response.getOutputStream(); + + response.setContentType("text/html"); + out.println("Person Photo"); + + try { + conn = getConnection(); + photoContent = getBlobsContent(photoAsURL); + update(conn, id, photoContent); + out.println("

    OK: updated record with id="+id+"

    "); + } + catch(Exception e) { + out.println("

    Error: "+e.getMessage()+"

    "); + } + } + + public void doPost( + HttpServletRequest request, + HttpServletResponse response) + throws IOException, ServletException { + doGet(request, response); + } + + public void update(Connection conn, String id, InputStream photo) + throws Exception { + + PreparedStatement pstmt = null; + try { + conn.setAutoCommit(false); + pstmt = conn.prepareStatement(UPDATE_PICTURE); + pstmt.setBinaryStream(1, photo, photo.available()); + pstmt.setString(2, id); + pstmt.executeUpdate(); + conn.commit(); + } + finally { + DatabaseUtil.close(pstmt); + } + } + + public static InputStream getBlobsContent(String urlAsString) + throws Exception { + + // we assume that the urlAsString is a URL as a string object + // urlAsString is like: "http://www.geocities.com/mparsian/tiger1.jpg" + + java.net.URL url = new java.net.URL(urlAsString); + java.net.URLConnection urlConn = url.openConnection(); + urlConn.connect(); + InputStream content = urlConn.getInputStream(); + return content; + } + + private static String trimParameter(String s) { + if ((s == null) || (s.length() == 0)) { + return s; + } + else { + return s.trim(); + } + } +} diff --git a/sourceMetadata/jcb-package/src/servlets/UpdateBlobToOracleServlet.class b/sourceMetadata/jcb-package/src/servlets/UpdateBlobToOracleServlet.class new file mode 100644 index 0000000000000000000000000000000000000000..a5a7cd4a6e8aaa209ee1c97899391addeeeb3542 GIT binary patch literal 4401 zcmai2YhV;t75*m4?o2iVf#ubu6qZsT$+B6JLZC|$AStvdd65JVs?y2skSy%(EVHwa zP_;h#)Yi6YtD?19ZBeTTs39p>s@7WDYKxEhsE;aEZLL;Ywe{8d-I?9&CL!`8_s%`{ zoO93pzH`sL*~eag;6VU2lH@@fbOpN<^eO095c6O+_IMCSq7+FO3Q`{Ig{dH21`8Pv zTCq>Tei;KElnc{A(H{`a)e7ELhPUG#3a%0TI~BakgLez#_b9klm|mygdePsY;6~Bk zq~N^@-lyPZ8Mk8P=`+|_>2el;ywk3ME_X@pY!1JxZi^>;ESR;EQW^_d`Wmb;=xfI z6U~=pe8qze_^N1zJUEVF(TsTT08WVJq>Qi0cu+!lXG?R>maYvuTRWQ9_jGhg@V4&O z_GzKGmh204TV^cTw?@L0W+R!lw4}9Fi)VBR?)q3VW;IGEuBhB9p`_V}Qd-^`OX}^J zM6Yi4XuWYtru69+O_O@WiWx}>b1Etw_vyXyP=10dcs2|~^pwy_OK?Sv%XCXZSB0%T z5K8OjzPN6M`YkIJx|~h7Bk0oiX7seR=A3Hj6dmhpD!0lwCF3FPAZm0PX|CbUq@tR| zSl2p>g~o+85e`QZGeRxNRK_Akx|X14?w`ADiW|LY?#$AYbY7YDS%_v9fpPZ4ieM)? zHB(FImTpQ|GP!M`J3`lOWXy=ZF(we7zs25;2&2d7Fttcr&tg?AcvZ0(Bzb{h&s6V@ z_C~6sW^A8sRy)d<+5-uT#Z=f)3tRoMWO!XdV}t|Ynw7OR;fR(_#WXTnlt?iP5~*4l zUsv%Bd{f55Dz@NTG9FR!Z9FPrX)qY{Pa2lLSMQ4@{nU~19Tkt^aXO7fWjvwcyXaM+ zp_dtv>NhNd2{b-An=-L@RKPX)#>4(tv_Zx9@T7{TaGHCYJQ#bK_315Ltqn51ui^*z zp@dRP9}u~hh^zRKh_AX{3>xeEbuHRhZ^f**-q@*|X(Q?H6miyv99ezH){ybE1eGAz zXfax;`ULeui!OmF3%9wiEzrSBMbwA_sH~823 zcNu0jY=6?&uf;4CKgTa@S9JVK6~Dr>_J|1l8o#kWSI9V{;lz zr$bIocj@U&-0Ifp_ILQbtzReO4=SF=3-)N0ia+8-`*XF7KdJaLUXt+_6@SIcDqay- za95Y8_#3)p{9TCtA(~gog$-YlwTU?+PS@iqUc*0S{7c2Z(WT-)_^*uDRlI>0RS6>f ze3Pahvsk#Byx!&L62+rql&%S8*%M!&P@ZSGIj*HyV`YNg&RWC#IY*(f4OpUQ+df2j zbc#fqmel&h(Q7-4gUQNfVdpBRpQ9y%D|ts( z8kKS{N!|&}%Zkb!%rtTFw{|oMT3aexvxP|b5mLG+A17i;3X@n;GY1Rlk#Jrv3Lf#o z89EVsvSwFF6O)v0w=o3kqf?5+^jK8azJv*B`me zZ8}>=^K;y`Q+6iIFzSf&vZO;IQ}7rocxR5qh29Eli~YLgUgLVQ&*~>=;su6iETF}7qDkRhpXy1q@%V$4_mh_oQhI$r_)TRwxSp=_Vc_& zo4m!X-jX)2tG#L%?rni(!C}bZ5?{%YQ4jOE5V&|TeDpS#p3aBL<)&jkB@3{Pvn5>R zBL49vcGi$A%1Sx&+A%2J(jj=Hb}3vE@Rp50Ey6ISgk1se)X{;PY9~;>{Wzw1rw_sF zbFmr13>p^9%oH>3(V1li!*$-o0xI_pq;K1h| z#{70MTEJ12uf*pH4#6)33&pgYi{ipu6y8O-1$~DQ2rE8i2#fQ2ON1UpOW7Bw9wizF z@C2T;aS=@P5<_4K6jZ>2N=!k3XfDH2Qn?=0xDp{mP=h_Fg^3lkuH(OXt8fEW<5paP zI}pZQScCgekHcu7?;Sz_; zaCW%nq!LzyNj(L{b)`W;M#J{H(xSUDjr1zTvzUI3hu(PJM_+46_Bx@xp4x#Cutxe^ z!)O+1ap@s=!;B&~^m$GlB?R+`?ip_X44$)l34+Z#v6yWK+3X}Zn=zFKaXL@eOwP{Z zNn1oX13V8a$w348*hog&$;dXonRgP}KDGv~BFh?Cj^ZZhxSi62{H5R?=D@xDvEUdI zILY4&PB9-IMjDUuw}PjTVLStP27`E()@S(r0>5A4_sh82Ceb;KrQ*fzP{`~kCW(OW z1U77Ef!Np@7{X<3Wa@JMwX_HG$9=Y48m{Hxy^fo@9$qHk9Nbvo*dzW2VtR>EQp;Xc n9dFemJWWHm;vfsq5q@mSdz@;g-pz#R7AE~|)Q`}j2+{umSPhs- literal 0 HcmV?d00001 diff --git a/sourceMetadata/jcb-package/src/servlets/UpdateBlobToOracleServlet.java b/sourceMetadata/jcb-package/src/servlets/UpdateBlobToOracleServlet.java new file mode 100644 index 0000000..55d2577 --- /dev/null +++ b/sourceMetadata/jcb-package/src/servlets/UpdateBlobToOracleServlet.java @@ -0,0 +1,147 @@ +import java.io.*; +import java.sql.*; + +import javax.servlet.*; +import javax.servlet.http.*; + +import jcb.util.DatabaseUtil; +import jcb.util.IOUtil; + +// add these imports for access to the required Oracle classes +import oracle.jdbc.driver.*; +import oracle.sql.BLOB; + +public class UpdateBlobToOracleServlet extends HttpServlet { + + // to write LOB data, the application must acquire a write lock + // on the LOB object; one way to accomplish this is through a + // SELECT FOR UPDATE; also, disable auto-commit mode. + static final String PICTURE_LOCATOR = + "select photo from MyPictures where id = ? for update nowait"; + + public static Connection getConnection() throws Exception { + + String driver = "oracle.jdbc.driver.OracleDriver"; + String url = "jdbc:oracle:thin:@matrix:1521:caspian"; + String username = "mp"; + String password = "mp2"; + + Class.forName(driver); // load Oracle driver + Connection conn = DriverManager.getConnection(url, username, password); + return conn; + } + + public void doGet(HttpServletRequest request, + HttpServletResponse response) + throws IOException, ServletException { + + System.out.println("--- UpdateBlobToOracleServlet begin ---"); + + InputStream photoContent = null; + Connection conn = null; + + String id = trimParameter(request.getParameter("id")); + String photoAsURL = trimParameter(request.getParameter("photo")); + System.out.println("UpdateBlobToOracleServlet: id="+id); + System.out.println("UpdateBlobToOracleServlet photoAsURL="+ photoAsURL); + ServletOutputStream out = response.getOutputStream(); + + response.setContentType("text/html"); + out.println("Person Photo"); + + System.out.println("-- doGet() 0"); + try { + System.out.println("-- doGet() 1"); + conn = getConnection(); + System.out.println("-- doGet() 2"); + photoContent = getBlobsContent(photoAsURL); + System.out.println("-- doGet() 3"); + update(conn, id, photoContent); + System.out.println("-- doGet() 4"); + out.println("

    OK: updated record with id="+id+"

    "); + } + catch(Exception e) { + e.printStackTrace(); + out.println("

    Error: "+e.getMessage()+"

    "); + } + } + + public void doPost( + HttpServletRequest request, + HttpServletResponse response) + throws IOException, ServletException { + doGet(request, response); + } + + public void update(Connection conn, String id, InputStream photo) + throws Exception { + + System.out.println("--0.1"); + OutputStream out = null; + java.sql.ResultSet rs = null; + java.sql.PreparedStatement pstmt = null; + oracle.sql.BLOB oracleBlob = null; + System.out.println("--0.2"); + try { + conn.setAutoCommit(false); + System.out.println("--1"); + pstmt = conn.prepareStatement(PICTURE_LOCATOR); + System.out.println("--2"); + pstmt.setString(1, id); + System.out.println("--3"); + rs = pstmt.executeQuery(); + System.out.println("--4"); + rs.next(); + System.out.println("--5"); + oracleBlob = ((OracleResultSet)rs).getBLOB(1); + System.out.println("--6"); + + // Now that we have the locator, lets store the photo + out = oracleBlob.getBinaryOutputStream(); + System.out.println("--7"); + //int photoLength = photo.available(); + byte[] buffer = new byte[oracleBlob.getBufferSize()]; + //photo.read(buffer, 0, photoLength); + //out.write(buffer); + System.out.println("--8"); + int length = 0; + while ((length = photo.read(buffer)) != -1) { + out.write(buffer, 0, length); + } + + // You've got to close the output stream before + // you commit, or the changes are lost! + out.close(); + photo.close(); + System.out.println("--9"); + conn.commit(); + } + finally { + DatabaseUtil.close(rs); + DatabaseUtil.close(pstmt); + } + } + + + public static InputStream getBlobsContent(String urlAsString) + throws Exception { + + // we assume that the urlAsString is a URL as a string object + // urlAsString is like: "http://www.geocities.com/mparsian/tiger1.jpg" + + java.net.URL url = new java.net.URL(urlAsString); + java.net.URLConnection urlConn = url.openConnection(); + urlConn.connect(); + InputStream content = urlConn.getInputStream(); + return content; + } + + private static String trimParameter(String s) { + if ((s == null) || (s.length() == 0)) { + return s; + } + else { + return s.trim(); + } + } +} diff --git a/sourceMetadata/jcb-package/src/servlets/UpdateMySqlClobServlet.class b/sourceMetadata/jcb-package/src/servlets/UpdateMySqlClobServlet.class new file mode 100644 index 0000000000000000000000000000000000000000..e0444cccf22b85a18feef0d95024fca66d70125c GIT binary patch literal 3225 zcmai0S$h-L8Ggr>H1c?iK?Z}efC#~{yGjqMLMK$HX zRk*IV7%(&`O7culWl%$3&2TfVH7c5y$QUUv&f30R6jJzvH|JISyg275Iv-pJu}-bc zU3ZnA8Ve&TVkzKI{;w23n~O~I=~qvLH8@8Fh(4k=bu zYKpFjck!NvXS3>KG`lS9!e~}H(iNjSBhOmZ-K-VL>UiJ85AmMz{IrQv%Hv6}%=X`1 zlVcUfEvTp-&n|j}HTpU}I&&eDswT6LvP&tk>I9PIoAO28^9!k)j$BSTg_9ORGSvK2=` zDiAWI-jtVxcH9pqy8xx=4w;Ie4LWw26a51M+ zOHO`=-|P5;i9g~A6Mw>=b^OJ|U-37k@^>BoFmW3noA{>+p?7D#RTZ#S?tP%Pf_FS? za;6@9i(0MlngqHVoQ=D7z;e>Bdj2%aSi{l#6o06|9?%=wP-m}Nvr~4-UQ$V(+QC5U z32a@tSF<_#|4FEI6=s3wx#=wS-A}FBW!MO*H&c=2isbnhc2QAK#nNEDMq#rUDcHq= zsWp%JwKBQew?pWv)g0cAWe01_K$-1Zy6n3#yIdBff`;Lp%(W0#J6*&Rm)=$j+q>1f zw>PZr(8-*%^VjBmJ5R_4qn{E%z}#(>)AoL!oFvU5QL?LGSIKY>AO~0lTeO75R!3)zcDQXOrZ7CBJA@q{BMoL0+^2vA_>r zOL^A|7}KE|)SYoDySqHn-MHTfb&I^(k#6kO>%L`&3CvgTP8uYqlclDDs^6sQq&7Ba zt-FqXa;A#A$7u-6*Yi10i{dT=JKjnM?jg%icZW%6stHz`D@sdpnHPn+%y5{$E5rO- z(r^GHus9#%R~rsO=R0pLj!$ysVa^)oX!7)ncS=yE1R>8jZK88lzMuB=O)T z4$%SA6B*t_svXHllmvz^n>eiDax$`kM{c7l6Aj;z(J$`MQab~&XvHE-HEU2or(tkB z$=y@v!fB@R41*q{>;!A>93>|h_&El0zA4Ea>c^sn?ltNvbe5L;97nFO@*bUHj7O)L zu0B4GUpdateMySqlClobServlet"); + + try { + conn = getConnection(); + fileContent = getClobsContentAsString(fileAsURL); + updateCLOB(conn, id, fileContent); + out.println("

    OK: updated an existing record with id="+id+"

    "); + } + catch(Exception e) { + e.printStackTrace(); + out.println("

    Error: "+e.getMessage()+"

    "); + } + } + + public void doPost( + HttpServletRequest request, + HttpServletResponse response) + throws IOException, ServletException { + doGet(request, response); + } + + public void updateCLOB(Connection conn, String id, String fileContent) + throws Exception { + + PreparedStatement pstmt = null; + try { + pstmt = conn.prepareStatement(UPDATE_CLOB); + pstmt.setString(1, fileContent); + pstmt.setString(2, id); + pstmt.executeUpdate(); + } + finally { + DatabaseUtil.close(pstmt); + } + } + + public static String getClobsContentAsString(String urlAsString) + throws Exception { + InputStream content = null; + try { + java.net.URL url = new java.net.URL(urlAsString); + java.net.URLConnection urlConn = url.openConnection(); + urlConn.connect(); + content = urlConn.getInputStream(); + return IOUtil.inputStreamToString(content); + } + finally { + IOUtil.close(content); + } + } + + private static String trimParameter(String s) { + if ((s == null) || (s.length() == 0)) { + return s; + } + else { + return s.trim(); + } + } +} \ No newline at end of file diff --git a/sourceMetadata/jcb-package/src/servlets/UpdateOracleClobServlet.class b/sourceMetadata/jcb-package/src/servlets/UpdateOracleClobServlet.class new file mode 100644 index 0000000000000000000000000000000000000000..38d3d61c4fa199def9babdab5b6aa81caf6ab199 GIT binary patch literal 3258 zcmai1S$h-L8Ggr>H1c?ijR1ov!6F1>%gbOw(nc00#u(xvFY!i6+N5LYU=PSMVrB%U z>6WEwo1|@;rAcXRx7UKh8&6-R$;4f zG(3Tl9ByiG;mN_*P{u7e+}5y$J97AzidR&8TS4o>%!SeU@t4PP)8`c=a@WmUrcpHQ zWn<2FEqi%bLED&Pd%kJ=i)OJb6vVQYZTTY#ntOT|6-36I0(aYUmMx~rt4qS2H*#4*&BB-FdBDfyb3KaEQM2wKH&X}&bDtzJ6yg8@r=EX%z!g*vN zuyxus^F<*QRbUvDA=7ahPb%ngg44n4g{Ayp!L@D)cQ9nQ5PT@;kw=-3EaR_OcIMfl zlQ)Yi#3M8G)ajv2-t^l>cumLCcwIr0RZ#JUjvruD z$9ar06|T`z6>sYJA%3Kw#TRQbY^y~bKgL@Mp2^COk?e{v3nN+I@{3|*7q7BLc$_r? zVij-ecn5Du)nC@}tW-IIb42~&ggsxjiUkSYPj$26Gw)~ZpRXD5TC-|v?ebjkoBx{81f&C*oeuj5>RMS>XSsg!@(C@9O8+TpD z&7^d^hj(>6gN%Z7s6NGPGbKn~$`gJ{uB4W;=Tf&j*_&xrh;*UE1gg;A`dn*2--XaR1$VU z!N5-98i1>m7ww7r&Q^olzt!2dx3l&@$((QIZ_KkV(PWL@PYTat?6%Trd$(24QF2Ae zbOqUbvC2NG;MDGxN$#1Dp-|h$XkJIk~D{AL^&TxG+jf!LM4{(%jsnMg8nzbfG<6#*UO*-L2& zO4~}o+c#KMEg2AHn5jg#5RzaN+%=9=)gMmCDqTd|LSKrkmy{;!DN&};t+>* zB*}3PeVKSNzK$=|=#EG_Zauc0^Z_k>ns37!fz1-7^Yl+b*o31*CPgog5#YyhlCMMq zCrI6cVf11YX})0l$a{+11AI^p^7UxoeFjD15Tk@)WGVk_6^Y|Su9;_Qy03p7M{A+c zNDKxgM%L}jytXSazDd>?sWJhGU7JWXL53$Xu!&>MNJgRrFj#EjaRpbBkqsQbhqg>K zSS6!hJfNgzI$}_YK{Ms7Ksud<#_=pq&!LU)g-*KHMJP^U9R0XR%5ge=kwLu_*cS%5 zMZPR5*1b}(&QNln}#8u5Saq4F3ig#rq7sTtvShyG-D2s_!PU za;`Ti$I~guzXu(dVWvILJewu`0*+&m)C)9kvCbq-KCLK0=JsjMvJ4XGe?d#Hqwg*& c;yxGswT#|Fvw;_=;YB+B66weI-GmGO19vw-k^lez literal 0 HcmV?d00001 diff --git a/sourceMetadata/jcb-package/src/servlets/UpdateOracleClobServlet.java b/sourceMetadata/jcb-package/src/servlets/UpdateOracleClobServlet.java new file mode 100644 index 0000000..1e91d66 --- /dev/null +++ b/sourceMetadata/jcb-package/src/servlets/UpdateOracleClobServlet.java @@ -0,0 +1,97 @@ +import java.io.*; +import java.sql.*; + +import javax.servlet.*; +import javax.servlet.http.*; + +import jcb.util.IOUtil; +import jcb.util.DatabaseUtil; + +public class UpdateOracleClobServlet extends HttpServlet { + + static final String UPDATE_CLOB = + "update datafiles set filebody=? where id=?"; + + public static Connection getConnection() throws Exception { + String driver = "oracle.jdbc.driver.OracleDriver"; + String url = "jdbc:oracle:thin:@localhost:1521:caspian"; + String username = "scott"; + String password = "tiger"; + Class.forName(driver); // load Oracle driver + Connection conn = DriverManager.getConnection(url, username, password); + return conn; + } + + public void doGet(HttpServletRequest request, + HttpServletResponse response) + throws IOException, ServletException { + + String fileContent = null; + Connection conn = null; + + String id = trimParameter(request.getParameter("id")); + String fileAsURL = trimParameter(request.getParameter("file")); + ServletOutputStream out = response.getOutputStream(); + + response.setContentType("text/html"); + out.println("UpdateOracleClobServlet"); + + try { + conn = getConnection(); + fileContent = getClobsContentAsString(fileAsURL); + updateCLOB(conn, id, fileContent); + out.println("

    OK: updated an existing record with id="+id+"

    "); + } + catch(Exception e) { + e.printStackTrace(); + out.println("

    Error: "+e.getMessage()+"

    "); + } + } + + public void doPost( + HttpServletRequest request, + HttpServletResponse response) + throws IOException, ServletException { + doGet(request, response); + } + + public void updateCLOB(Connection conn, String id, String fileContent) + throws Exception { + + PreparedStatement pstmt = null; + try { + pstmt = conn.prepareStatement(UPDATE_CLOB); + pstmt.setString(1, fileContent); + pstmt.setString(2, id); + pstmt.executeUpdate(); + } + finally { + DatabaseUtil.close(pstmt); + } + } + + + public static String getClobsContentAsString(String urlAsString) + throws Exception { + InputStream content = null; + try { + java.net.URL url = new java.net.URL(urlAsString); + java.net.URLConnection urlConn = url.openConnection(); + urlConn.connect(); + content = urlConn.getInputStream(); + return IOUtil.inputStreamToString(content); + } + finally { + IOUtil.close(content); + } + } + + private static String trimParameter(String s) { + if ((s == null) || (s.length() == 0)) { + return s; + } + else { + return s.trim(); + } + } +} \ No newline at end of file