implement datasource type inference for external datasources: #3910
authorAndreas M��ller <a.mueller@bgbm.org>
Tue, 5 May 2015 12:50:32 +0000 (12:50 +0000)
committerAndreas M��ller <a.mueller@bgbm.org>
Tue, 5 May 2015 12:50:32 +0000 (12:50 +0000)
.gitattributes
cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/database/CdmPersistentDataSource.java
cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/database/DatabaseTypeEnum.java
cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/database/WrappedCdmDataSource.java
cdmlib-persistence/src/test/java/eu/etaxonomy/cdm/database/DatabaseEnumTest.java
cdmlib-persistence/src/test/java/eu/etaxonomy/cdm/database/WrappedCdmDataSourceTest.java [new file with mode: 0644]

index 26d0e9abc0905aa5b25fb33a101f2d4754ff9b3f..66c1faaa21eaec75c5e71eaaf2409ac48d6ea91d 100644 (file)
@@ -1592,6 +1592,7 @@ cdmlib-persistence/src/test/java/eu/etaxonomy/cdm/database/DatabaseEnumTest.java
 cdmlib-persistence/src/test/java/eu/etaxonomy/cdm/database/PersistentTermInitializerTest.java -text
 cdmlib-persistence/src/test/java/eu/etaxonomy/cdm/database/TestingTermInitializer.java -text
 cdmlib-persistence/src/test/java/eu/etaxonomy/cdm/database/TestingTermInitializerTest.java -text
+cdmlib-persistence/src/test/java/eu/etaxonomy/cdm/database/WrappedCdmDataSourceTest.java -text
 cdmlib-persistence/src/test/java/eu/etaxonomy/cdm/database/types/ODBCDatabaseTypeTest.java -text
 cdmlib-persistence/src/test/java/eu/etaxonomy/cdm/database/types/OracleDatabaseTypeTest.java -text
 cdmlib-persistence/src/test/java/eu/etaxonomy/cdm/database/types/PostgreSQLDatabaseTypeTest.java -text
index 3c11fb4ceb7b2d8c39f01c0347022a7924a2a564..4ffb078e18cf117f854120f5c777a5557a444b0a 100644 (file)
@@ -238,7 +238,7 @@ public class CdmPersistentDataSource extends CdmDataSourceBase implements ICdmPe
        @Override\r
        public DatabaseTypeEnum getDatabaseType(){\r
                String strDriverClass = getCdmSourceProperty(CdmSourceProperties.DRIVER_CLASS);\r
-               DatabaseTypeEnum dbType = DatabaseTypeEnum.getDatabaseEnumByDriverClass(strDriverClass);\r
+               DatabaseTypeEnum dbType = DatabaseTypeEnum.byDriverClass(strDriverClass);\r
                return dbType;\r
        }\r
                \r
@@ -256,7 +256,7 @@ public class CdmPersistentDataSource extends CdmDataSourceBase implements ICdmPe
        @Override\r
        public BeanDefinition getDatasourceBean(){\r
                DatabaseTypeEnum dbtype = \r
-                               DatabaseTypeEnum.getDatabaseEnumByDriverClass(getCdmSourceProperty(CdmSourceProperties.DRIVER_CLASS));\r
+                               DatabaseTypeEnum.byDriverClass(getCdmSourceProperty(CdmSourceProperties.DRIVER_CLASS));\r
                \r
                AbstractBeanDefinition bd = new RootBeanDefinition(dbtype.getDataSourceClass());\r
                //attributes\r
index 957e891e4a3cbfd7d1ce86877204e8c0f1892002..abc7216c1c4e4ba019608a5cd4afc05596b43deb 100644 (file)
@@ -1,14 +1,16 @@
 /**\r
 * Copyright (C) 2007 EDIT\r
-* European Distributed Institute of Taxonomy \r
+* European Distributed Institute of Taxonomy\r
 * http://www.e-taxonomy.eu\r
-* \r
+*\r
 * The contents of this file are subject to the Mozilla Public License Version 1.1\r
 * See LICENSE.TXT at the top of this package for the full license terms.\r
 */\r
 \r
 package eu.etaxonomy.cdm.database;\r
 \r
+import java.sql.DatabaseMetaData;\r
+import java.sql.SQLException;\r
 import java.util.ArrayList;\r
 import java.util.List;\r
 \r
@@ -44,12 +46,12 @@ public enum DatabaseTypeEnum {
        ;\r
 \r
        /**\r
-        * \r
+        *\r
         */\r
        private static final String P6SPY_DRIVER_CLASS_NAME = "com.p6spy.engine.spy.P6SpyDriver";\r
        private boolean useP6Spy = false;\r
-       \r
-       \r
+\r
+\r
        /**\r
         * @return the useP6Spy\r
         */\r
@@ -93,35 +95,35 @@ public enum DatabaseTypeEnum {
                 //TODO Exception\r
         }\r
        }\r
-       \r
+\r
        public IDatabaseType getDatabaseType(){\r
                return dbType;\r
        }\r
-       \r
+\r
        //Logger\r
        private static final Logger logger = Logger.getLogger(DatabaseTypeEnum.class);\r
        protected IDatabaseType dbType;\r
-       \r
-          \r
+\r
+\r
     /**\r
      * @return\r
      */\r
     public String getName(){\r
        return dbType.getName();\r
     }\r
-    \r
+\r
        /**\r
         * @return\r
         */\r
        public String getDriverClassName(){\r
                if(useP6Spy){\r
                        return P6SPY_DRIVER_CLASS_NAME;\r
-                       \r
+\r
                } else {\r
-                       return dbType.getClassString();                 \r
+                       return dbType.getClassString();\r
                }\r
        }\r
-    \r
+\r
        /**\r
         * Returns the DataSource class that the datasource needs to create a spring bean\r
         * @return the DataSource class\r
@@ -129,21 +131,21 @@ public enum DatabaseTypeEnum {
        public Class<? extends DataSource> getDataSourceClass(){\r
                return dbType.getDataSourceClass();\r
        }\r
-       \r
+\r
        /**\r
         * @return\r
         */\r
        public String getUrl(){\r
                return dbType.getUrlString();\r
        }\r
-       \r
+\r
        /**\r
         * @return\r
         */\r
        public String getHibernateDialectCanonicalName(){\r
                return dbType.getHibernateDialectCanonicalName();\r
        }\r
-          \r
+\r
     /**\r
      * @return\r
      */\r
@@ -152,7 +154,7 @@ public enum DatabaseTypeEnum {
     }\r
 \r
        /**\r
-     * returns the connection string \r
+     * returns the connection string\r
      * @param server the server, e.g. IP-Address\r
      * @param database the database name on the server (e.g. "testDB")\r
      * @param port the port number\r
@@ -160,10 +162,10 @@ public enum DatabaseTypeEnum {
      */\r
     public String getConnectionString(ICdmDataSource cdmDataSource){\r
        String result = dbType.getConnectionString(cdmDataSource);\r
-       logger.debug("Connection String: " + result);   \r
+       logger.debug("Connection String: " + result);\r
         return result;\r
     }\r
-       \r
+\r
     /**\r
      * Returns the {@link Dialect hibernate dialect} used for this database type.\r
         * @return hibernate dialect\r
@@ -179,20 +181,20 @@ public enum DatabaseTypeEnum {
         */\r
     public String getInitMethod(){\r
        String result = dbType.getInitMethod();\r
-       logger.debug("InitMethod: " + result);  \r
+       logger.debug("InitMethod: " + result);\r
         return result;\r
     }\r
-    \r
+\r
        /**\r
         * Returns the Name of the destroying method to be used when a hibernate datasource representing this database is destroyed\r
         * @return String name of the destroy method\r
         */\r
     public String getDestroyMethod(){\r
        String result = dbType.getDestroyMethod();\r
-       logger.debug("DestroyMethod: " + result);       \r
+       logger.debug("DestroyMethod: " + result);\r
         return result;\r
     }\r
-    \r
+\r
     /**\r
      * Returns a List of all available DatabaseEnums.\r
      * @return List of DatabaseEnums\r
@@ -210,18 +212,74 @@ public enum DatabaseTypeEnum {
      * @param strDriverClass\r
      * @return the according DatabaseTypeEnum. Null if the driver class does not exist.\r
      */\r
-    public static DatabaseTypeEnum getDatabaseEnumByDriverClass(String strDriverClass){\r
-       for (DatabaseTypeEnum dbEnum : DatabaseTypeEnum.values()){\r
+    public static DatabaseTypeEnum byDriverClass(String strDriverClass){\r
+       if (strDriverClass == null){\r
+           return null;\r
+       }\r
+        for (DatabaseTypeEnum dbEnum : DatabaseTypeEnum.values()){\r
                if (dbEnum.getDriverClassName().equals(strDriverClass)){\r
                        return dbEnum;\r
                }\r
        }\r
-       logger.warn("Unknown driver class " + strDriverClass==null ? "null" : strDriverClass);\r
+       logger.info("Unknown driver class: " + strDriverClass);\r
        return null;\r
     }\r
-    \r
-    \r
 \r
\r
+    /**\r
+     * @param metaData\r
+     * @return\r
+     */\r
+    public static DatabaseTypeEnum byDatabaseMetaData(DatabaseMetaData metaData) {\r
+        if (metaData == null){\r
+            return null;\r
+        }\r
+\r
+        //driver\r
+        String driver = null;\r
+        try {\r
+            driver = metaData.getDriverName();\r
+        } catch (SQLException e) {\r
+            //do nothing\r
+        }\r
+        DatabaseTypeEnum result = byDriverClass(driver);\r
+        if (result != null){\r
+            return result;\r
+        }\r
+\r
+        //product\r
+        String product = null;\r
+        try {\r
+            product = metaData.getDatabaseProductName();\r
+        } catch (SQLException e) {\r
+            //do nothing\r
+        }\r
+        if (product == null){\r
+            return null;\r
+        }\r
+        if (product.toLowerCase().matches("\\.*mysql\\.*")){\r
+            return MySQL;\r
+        }else if (product.toLowerCase().matches("\\.*hsqldb\\.*")) {\r
+            return HSqlDb;\r
+        }else if (product.toLowerCase().matches("\\.*oracle\\.*")) {\r
+            return Oracle;\r
+        }else if (product.toLowerCase().matches("\\.*sybase\\.*")) {\r
+            return Sybase;\r
+        }else if (product.toLowerCase().matches("\\.*odbc\\.*")) {\r
+            return ODBC;\r
+        }else if (product.toLowerCase().matches("\\.*postgresql\\.*")) {\r
+            return PostgreSQL;\r
+        }else if (product.toLowerCase().matches("\\.*sqlserver\\.*")) {\r
+            //TODO we need to distinguish versions here once we have sql server 2008 database enum\r
+//            metaData.getDatabaseProductVersion()\r
+            return SqlServer2005;\r
+        }else if (product.toLowerCase().matches("\\.*h2\\.*")) {\r
+            return H2;\r
+        }\r
+        return null;\r
+    }\r
+\r
+\r
+\r
+\r
 }\r
 \r
index 13fed3ca63a451ff76aa75323818ecfeb8e78fac..a1b7b8a093ad6b64b24fcb93387e220c016be825 100644 (file)
@@ -1,5 +1,5 @@
 /**\r
- * \r
+ *\r
  */\r
 package eu.etaxonomy.cdm.database;\r
 \r
@@ -24,29 +24,29 @@ import eu.etaxonomy.cdm.model.name.NomenclaturalCode;
 \r
 /**\r
  * This class is a wrapper class to wrap an {@link javax.sql.DataSource} to an\r
- * {@link ICdmDataSource}. As the former is a very limited interface it is not possible \r
+ * {@link ICdmDataSource}. As the former is a very limited interface it is not possible\r
  * to implement all methods of {@link ICdmDataSource}. However, the aim is\r
  * to implement all those methods which are usually needed to work with a datasource\r
  * which represents a connection to a database such as transaction handling and\r
  * sending queries.\r
  * Those methods which are not supported by this wrapper class will throw an xxx\r
  * exception.\r
- * \r
- *  \r
+ *\r
+ *\r
  * @author a.mueller\r
  */\r
\r
+\r
 //FIXME this class replicates lots of code in CdmDataSourceBase, we may want to merge it\r
 //in a common helper class to avoid redundant code\r
 public class WrappedCdmDataSource implements ICdmDataSource {\r
        private static final Logger logger = Logger.getLogger(WrappedCdmDataSource.class);\r
 \r
 \r
-       private DataSource datasource;\r
-       \r
+       private final DataSource datasource;\r
+\r
        private Connection connection;\r
-       \r
-       \r
+\r
+\r
        public WrappedCdmDataSource(DataSource datasource) {\r
                if (datasource == null){\r
                        throw new NullPointerException("datasource must not be null for WrappedCdmDataSource");\r
@@ -63,7 +63,7 @@ public class WrappedCdmDataSource implements ICdmDataSource {
                        return datasource.getConnection();\r
                }\r
        }\r
-       \r
+\r
        public Connection getExistingConnection(){\r
                return this.connection;\r
        }\r
@@ -161,7 +161,7 @@ public class WrappedCdmDataSource implements ICdmDataSource {
                try {\r
                        return (String)getSingleValue(MetaDataPropertyName.DB_SCHEMA_VERSION.getSqlQuery());\r
                } catch (SQLException e) {\r
-                       throw new CdmSourceException(e.getMessage());   \r
+                       throw new CdmSourceException(e.getMessage());\r
                }\r
        }\r
 \r
@@ -169,7 +169,7 @@ public class WrappedCdmDataSource implements ICdmDataSource {
        @Override\r
        public boolean isDbEmpty() throws CdmSourceException {\r
                // Any CDM DB should have a schema version\r
-               String dbSchemaVersion = (String) getDbSchemaVersion();\r
+               String dbSchemaVersion = getDbSchemaVersion();\r
                return (dbSchemaVersion == null || dbSchemaVersion.equals(""));\r
        }\r
 \r
@@ -178,9 +178,9 @@ public class WrappedCdmDataSource implements ICdmDataSource {
                try {\r
                        return testConnection();\r
                } catch (ClassNotFoundException e) {\r
-                       throw new CdmSourceException(e.getMessage());                   \r
+                       throw new CdmSourceException(e.getMessage());\r
                } catch (SQLException e) {\r
-                       throw new CdmSourceException(e.getMessage());   \r
+                       throw new CdmSourceException(e.getMessage());\r
                }\r
        }\r
 \r
@@ -226,7 +226,7 @@ public class WrappedCdmDataSource implements ICdmDataSource {
        }\r
 \r
        @Override\r
-       public BeanDefinition getHibernatePropertiesBean(DbSchemaValidation hbm2dll, \r
+       public BeanDefinition getHibernatePropertiesBean(DbSchemaValidation hbm2dll,\r
                        Boolean showSql, Boolean formatSql, Boolean registerSearchListener,\r
                        Class<? extends RegionFactory> cacheProviderClass) {\r
                //TODO is it possible/required to build a properties bean here?\r
@@ -279,13 +279,42 @@ public class WrappedCdmDataSource implements ICdmDataSource {
                throw new UnsupportedOperationException("setDatabase(String) not supported by WrappedCdmDataSource");\r
        }\r
 \r
-       /* (non-Javadoc)\r
-        * @see eu.etaxonomy.cdm.database.ICdmDataSource#getDatabaseType()\r
-        */\r
        @Override\r
        public DatabaseTypeEnum getDatabaseType() {\r
-               // TODO is it possible to retrieve this data from connection MetaData?\r
-               throw new UnsupportedOperationException("getDatabaseType(String) not supported by WrappedCdmDataSource");\r
+           if (this.datasource instanceof ICdmDataSource){\r
+               return ((ICdmDataSource)this.datasource).getDatabaseType();\r
+           }\r
+\r
+           try {\r
+            getConnection();\r
+        } catch (SQLException e1) {\r
+            throw new RuntimeException("SQL Exception while trying to establish connection to datasource");\r
+        }\r
+\r
+           String driverName = null;\r
+        if (connection != null){\r
+            DatabaseMetaData metaData = null;\r
+            try {\r
+                metaData = connection.getMetaData();\r
+            } catch (SQLException e) {\r
+                throw new RuntimeException("SQL Exception while trying to read datasource metadata");\r
+            }\r
+\r
+            try {\r
+                driverName = metaData != null ? metaData.getDriverName() : null;\r
+            } catch (SQLException e) {\r
+                //throw exception at end\r
+            }\r
+            if (metaData != null){\r
+                DatabaseTypeEnum type = DatabaseTypeEnum.byDatabaseMetaData(metaData);\r
+                if (type != null){\r
+                    return type;\r
+                }\r
+            }\r
+            throw new IllegalStateException("datasource type (MySQL, SQL Server, ...) could not be retrieved from generic datasource");\r
+\r
+        }\r
+               throw new IllegalStateException("datasource type (MySQL, SQL Server, ...) could not be retrieved from generic datasource");\r
        }\r
 \r
        @Override\r
index 37b2a4266006315d24d2317f86af8e223979e6a0..105edc39a82e527deeabc82a0d865b3edf940019 100644 (file)
@@ -120,7 +120,7 @@ public class DatabaseEnumTest {
        \r
 \r
        /**\r
-        * Test method for {@link eu.etaxonomy.cdm.database.DatabaseTypeEnum#getDatabaseEnumByDriverClass(java.lang.String)}.\r
+        * Test method for {@link eu.etaxonomy.cdm.database.DatabaseTypeEnum#byDriverClass(java.lang.String)}.\r
         */\r
        @Test\r
        public void testGetDatabaseEnumByDriverClass() {\r
@@ -128,8 +128,8 @@ public class DatabaseEnumTest {
                //does not work anymore as SQLServer driver is ambigous\r
                //assertEquals(DatabaseTypeEnum.SqlServer2000, DatabaseTypeEnum.getDatabaseEnumByDriverClass("com.microsoft.sqlserver.jdbc.SQLServerDriver"));\r
                //assertEquals(DatabaseTypeEnum.SqlServer2005, DatabaseTypeEnum.getDatabaseEnumByDriverClass("com.microsoft.sqlserver.jdbc.SQLServerDriver"));\r
-               assertEquals(DatabaseTypeEnum.MySQL, DatabaseTypeEnum.getDatabaseEnumByDriverClass("com.mysql.jdbc.Driver"));\r
-               assertEquals(null, DatabaseTypeEnum.getDatabaseEnumByDriverClass("com.microsoft.xxx")); \r
+               assertEquals(DatabaseTypeEnum.MySQL, DatabaseTypeEnum.byDriverClass("com.mysql.jdbc.Driver"));\r
+               assertEquals(null, DatabaseTypeEnum.byDriverClass("com.microsoft.xxx"));        \r
        }\r
 \r
 }\r
diff --git a/cdmlib-persistence/src/test/java/eu/etaxonomy/cdm/database/WrappedCdmDataSourceTest.java b/cdmlib-persistence/src/test/java/eu/etaxonomy/cdm/database/WrappedCdmDataSourceTest.java
new file mode 100644 (file)
index 0000000..9f23141
--- /dev/null
@@ -0,0 +1,48 @@
+// $Id$\r
+/**\r
+* Copyright (C) 2015 EDIT\r
+* European Distributed Institute of Taxonomy\r
+* http://www.e-taxonomy.eu\r
+*\r
+* The contents of this file are subject to the Mozilla Public License Version 1.1\r
+* See LICENSE.TXT at the top of this package for the full license terms.\r
+*/\r
+package eu.etaxonomy.cdm.database;\r
+\r
+import java.io.FileNotFoundException;\r
+\r
+import org.junit.Before;\r
+import org.junit.Ignore;\r
+import org.junit.Test;\r
+import org.unitils.spring.annotation.SpringBeanByType;\r
+\r
+import eu.etaxonomy.cdm.persistence.dao.agent.IAgentDao;\r
+import eu.etaxonomy.cdm.test.integration.CdmIntegrationTest;\r
+\r
+/**\r
+ * @author a.mueller\r
+ * @date 05.05.2015\r
+ *\r
+ */\r
+public class WrappedCdmDataSourceTest extends CdmIntegrationTest {\r
+\r
+    @SpringBeanByType\r
+    private IAgentDao agentDao;\r
+\r
+    /**\r
+     * @throws java.lang.Exception\r
+     */\r
+    @Before\r
+    public void setUp() throws Exception {\r
+    }\r
+\r
+    @Test\r
+    @Ignore\r
+    public void testByDatabaseMetaData() {\r
+//        still needs to be implemented\r
+    }\r
+\r
+    @Override\r
+    public void createTestDataSet() throws FileNotFoundException {};\r
+\r
+}\r