From: Aron Roberts Date: Sat, 8 Jan 2011 01:45:40 +0000 (+0000) Subject: CSPACE-2496,CSPACE-3550: Initial preparation for using database product-specific... X-Git-Url: https://git.aero2k.de/?a=commitdiff_plain;h=38ed1e8c16198692162389da69c5580228d19f5f;p=tmp%2Fjakarta-migration.git CSPACE-2496,CSPACE-3550: Initial preparation for using database product-specific SQL commands, datatypes, etc. in post-init handlers. Declared additional singly repeatable fields in CollectionObject as large text fields, in tenant bindings. --- diff --git a/services/common/src/main/config/services/tenant-bindings.xml b/services/common/src/main/config/services/tenant-bindings.xml index dea3ab26d..15deeec2c 100644 --- a/services/common/src/main/config/services/tenant-bindings.xml +++ b/services/common/src/main/config/services/tenant-bindings.xml @@ -58,12 +58,36 @@ org.collectionspace.services.collectionobject.nuxeo.CollectionObjectValidatorHandler - org.collectionspace.services.common.init.MakeLargeTextFields + org.collectionspace.services.common.init.ModifyFieldDatatypes + + nuxeo.collectionobjects_common_briefdescriptions + item + LARGETEXT + + nuxeo.collectionobjects_common_comments item - TEXT + LARGETEXT + + + + nuxeo.collectionobjects_common_objectproductionreasons + item + LARGETEXT + + + + nuxeo.collectionobjects_common_ownersreferences + item + LARGETEXT + + + + nuxeo.collectionobjects_common_viewersreferences + item + LARGETEXT @@ -1649,6 +1673,41 @@ org.collectionspace.services.collectionobject.nuxeo.CollectionObjectValidatorHandler + + org.collectionspace.services.common.init.ModifyFieldDatatypes + + + nuxeo.collectionobjects_common_briefdescriptions + item + LARGETEXT + + + + nuxeo.collectionobjects_common_comments + item + LARGETEXT + + + + nuxeo.collectionobjects_common_objectproductionreasons + item + LARGETEXT + + + + nuxeo.collectionobjects_common_ownersreferences + item + LARGETEXT + + + + nuxeo.collectionobjects_common_viewersreferences + item + LARGETEXT + + + + objectNamePropertyobjectName objectNumberPropertyobjectNumber diff --git a/services/common/src/main/java/org/collectionspace/services/common/init/AddIndices.java b/services/common/src/main/java/org/collectionspace/services/common/init/AddIndices.java index 018e7082b..1a340fa82 100755 --- a/services/common/src/main/java/org/collectionspace/services/common/init/AddIndices.java +++ b/services/common/src/main/java/org/collectionspace/services/common/init/AddIndices.java @@ -20,32 +20,47 @@ package org.collectionspace.services.common.init; import org.collectionspace.services.common.service.ServiceBindingType; import org.collectionspace.services.common.service.InitHandler.Params.Field; import org.collectionspace.services.common.service.InitHandler.Params.Property; +import org.collectionspace.services.common.storage.DatabaseProductType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.sql.ResultSet; import java.util.List; /** - * User: laramie - * $LastChangedRevision: $ - * $LastChangedDate: $ + * AddIndices, post-init action to add indexes to the database. + * + * $LastChangedRevision: $ + * $LastChangedDate: $ */ public class AddIndices extends InitHandler implements IInitHandler { final Logger logger = LoggerFactory.getLogger(AddIndices.class); + private final static String INDEX_SUFFIX = "_idx"; + @Override public void onRepositoryInitialized(ServiceBindingType sbt, List fields, List properties) throws Exception { //todo: all post-init tasks for services, or delegate to services that override. - - // call something like this: int rows = 0; + String sql = ""; + if (logger.isInfoEnabled()) { + logger.info("Modifying field datatypes for " + sbt.getName() + + " for repository domain " + sbt.getRepositoryDomain().trim() + "..."); + } + DatabaseProductType databaseProductType = getDatabaseProductType(); for (Field field : fields) { try { - // MySQL - String addIndex_SQL = "CREATE INDEX " + field.getCol() + "_idx ON " + field.getTable() + " (" + field.getCol() + ")"; - rows = executeUpdate(addIndex_SQL); + // TODO: Consider refactoring this 'if' statement to a general-purpose + // mechanism for retrieving and populating catalog/DDL-type SQL statements + // appropriate to a particular database product. + if (databaseProductType == DatabaseProductType.MYSQL) { + sql = "CREATE INDEX " + field.getCol() + INDEX_SUFFIX + " ON " + field.getTable() + " (" + field.getCol() + ")"; + } else if (databaseProductType == DatabaseProductType.POSTGRESQL) { + sql = "CREATE INDEX ON " + field.getTable() + " (" + field.getCol() + ")"; + } else { + throw new Exception("Unrecognized database system " + databaseProductType); + } + rows = executeUpdate(sql); } catch (Exception e) { throw e; } diff --git a/services/common/src/main/java/org/collectionspace/services/common/init/InitHandler.java b/services/common/src/main/java/org/collectionspace/services/common/init/InitHandler.java index fc0f40880..9ab73478f 100755 --- a/services/common/src/main/java/org/collectionspace/services/common/init/InitHandler.java +++ b/services/common/src/main/java/org/collectionspace/services/common/init/InitHandler.java @@ -17,6 +17,7 @@ */ package org.collectionspace.services.common.init; +import org.collectionspace.services.common.storage.DatabaseProductType; import org.collectionspace.services.common.storage.JDBCTools; import org.collectionspace.services.common.service.ServiceBindingType; import org.collectionspace.services.common.service.InitHandler.Params.Field; @@ -78,4 +79,8 @@ public class InitHandler implements IInitHandler { public int executeUpdate(String sql) throws Exception { return JDBCTools.executeUpdate(sql); } + + public DatabaseProductType getDatabaseProductType() throws Exception { + return JDBCTools.getDatabaseProductType(); + } } diff --git a/services/common/src/main/java/org/collectionspace/services/common/init/MakeLargeTextFields.java b/services/common/src/main/java/org/collectionspace/services/common/init/MakeLargeTextFields.java deleted file mode 100644 index 549106f7a..000000000 --- a/services/common/src/main/java/org/collectionspace/services/common/init/MakeLargeTextFields.java +++ /dev/null @@ -1,59 +0,0 @@ -/** - * This document is a part of the source code and related artifacts - * for CollectionSpace, an open source collections management system - * for museums and related institutions: - * - * http://www.collectionspace.org - * http://wiki.collectionspace.org - * - * Copyright © 2009 Regents of the University of California - * - * Licensed under the Educational Community License (ECL), Version 2.0. - * You may not use this file except in compliance with this License. - * - * You may obtain a copy of the ECL 2.0 License at - * https://source.collectionspace.org/collection-space/LICENSE.txt - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.collectionspace.services.common.init; - -import java.util.List; -import org.collectionspace.services.common.service.ServiceBindingType; -import org.collectionspace.services.common.service.InitHandler.Params.Field; -import org.collectionspace.services.common.service.InitHandler.Params.Property; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * MakeLargeTextFields, post-init action to configure text fields - * that must hold large amounts of text. - * - * $LastChangedRevision: $ - * $LastChangedDate: $ - */ -public class MakeLargeTextFields extends InitHandler implements IInitHandler { - - final Logger logger = LoggerFactory.getLogger(MakeLargeTextFields.class); - - @Override - public void onRepositoryInitialized(ServiceBindingType sbt, List fields, List properties) throws Exception { - //todo: all post-init tasks for services, or delegate to services that override. - int rows = 0; - try { - for (Field field : fields) { - // MySQL - String sql = "ALTER TABLE " + field.getTable() + " MODIFY COLUMN " + field.getCol() + " " + field.getType(); - // PostgreSQL - // String sql = "ALTER TABLE " + field.getTable() + " ALTER COLUMN " + field.getCol() + " " + field.getType(); - rows = executeUpdate(sql); - } - } catch (Exception e) { - throw e; - } - } -} diff --git a/services/common/src/main/java/org/collectionspace/services/common/init/ModifyFieldDatatypes.java b/services/common/src/main/java/org/collectionspace/services/common/init/ModifyFieldDatatypes.java new file mode 100644 index 000000000..c0fcea3d7 --- /dev/null +++ b/services/common/src/main/java/org/collectionspace/services/common/init/ModifyFieldDatatypes.java @@ -0,0 +1,95 @@ +/** + * This document is a part of the source code and related artifacts + * for CollectionSpace, an open source collections management system + * for museums and related institutions: + * + * http://www.collectionspace.org + * http://wiki.collectionspace.org + * + * Copyright © 2009 Regents of the University of California + * + * Licensed under the Educational Community License (ECL), Version 2.0. + * You may not use this file except in compliance with this License. + * + * You may obtain a copy of the ECL 2.0 License at + * https://source.collectionspace.org/collection-space/LICENSE.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.collectionspace.services.common.init; + +import java.util.List; +import org.collectionspace.services.common.service.ServiceBindingType; +import org.collectionspace.services.common.service.InitHandler.Params.Field; +import org.collectionspace.services.common.service.InitHandler.Params.Property; +import org.collectionspace.services.common.storage.DatabaseProductType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * ModifyFieldDatatypes, post-init action to configure the database + * datatypes of individual fields. + * + * $LastChangedRevision: $ + * $LastChangedDate: $ + */ +public class ModifyFieldDatatypes extends InitHandler implements IInitHandler { + + final Logger logger = LoggerFactory.getLogger(ModifyFieldDatatypes.class); + + @Override + public void onRepositoryInitialized(ServiceBindingType sbt, List fields, List properties) throws Exception { + //todo: all post-init tasks for services, or delegate to services that override. + int rows = 0; + String sql = ""; + if (logger.isInfoEnabled()) { + logger.info("Modifying field datatypes for " + sbt.getName() + + " for repository domain " + sbt.getRepositoryDomain().trim() + "..."); + } + try { + DatabaseProductType databaseProductType = getDatabaseProductType(); + String datatype = ""; + for (Field field : fields) { + datatype = getDatatypeFromLogicalType(databaseProductType, field.getType()); + // TODO: Consider refactoring this 'if' statement to a general-purpose + // mechanism for retrieving and populating catalog/DDL-type SQL statements + // appropriate to a particular database product. + if (databaseProductType == DatabaseProductType.MYSQL) { + sql = "ALTER TABLE " + field.getTable() + " MODIFY COLUMN " + field.getCol() + " " + datatype; + } else if (databaseProductType == DatabaseProductType.POSTGRESQL) { + sql = "ALTER TABLE " + field.getTable() + " ALTER COLUMN " + field.getCol() + " " + datatype; + } else { + throw new Exception("Unrecognized database system."); + } + rows = executeUpdate(sql); + } + } catch (Exception e) { + throw e; + } + } + + // TODO: Refactor this method to a general-purpose mechanism for retrieving + // datatypes appropriate to a particular database product, that corresponds + // to logical datatypes such as "LARGETEXT". + // + // Currently, this is hard-coded to a single logical datatype. + private String getDatatypeFromLogicalType(DatabaseProductType databaseProductType, String logicalDatatype) throws Exception { + final String LARGE_TEXT_DATATYPE = "LARGETEXT"; + String datatype = ""; + if (!logicalDatatype.equalsIgnoreCase(LARGE_TEXT_DATATYPE)) { + throw new Exception("Unrecognized logical datatype " + logicalDatatype); + } + if (databaseProductType == DatabaseProductType.MYSQL) { + datatype = "TEXT"; + } else if (databaseProductType == DatabaseProductType.POSTGRESQL) { + datatype = "TEXT"; + } else { + throw new Exception("Unrecognized database system " + databaseProductType); + } + return datatype; + } +} diff --git a/services/common/src/main/java/org/collectionspace/services/common/storage/DatabaseProductType.java b/services/common/src/main/java/org/collectionspace/services/common/storage/DatabaseProductType.java new file mode 100644 index 000000000..20adc5550 --- /dev/null +++ b/services/common/src/main/java/org/collectionspace/services/common/storage/DatabaseProductType.java @@ -0,0 +1,48 @@ +/** + * This document is a part of the source code and related artifacts + * for CollectionSpace, an open source collections management system + * for museums and related institutions: + + * http://www.collectionspace.org + * http://wiki.collectionspace.org + + * Copyright 2009 University of California at Berkeley + + * Licensed under the Educational Community License (ECL), Version 2.0. + * You may not use this file except in compliance with this License. + + * You may obtain a copy of the ECL 2.0 License at + + * https://source.collectionspace.org/collection-space/LICENSE.txt + */ +package org.collectionspace.services.common.storage; + +/** + * $LastChangedRevision: $ + * $LastChangedDate: $ + */ +public class DatabaseProductType { + + private final String name; + private final String propertiesFileName; + private static final String PROPERTIES_FILE_SUFFIX = ".properties"; + + private DatabaseProductType(String name) { + this.name = name; + propertiesFileName = name + PROPERTIES_FILE_SUFFIX; + } + + @Override + public String toString() { + return name; + } + + public String getPropertiesFileName() { + return propertiesFileName; + } + + public static final DatabaseProductType MYSQL = new DatabaseProductType("mysql"); + public static final DatabaseProductType POSTGRESQL = new DatabaseProductType("postgresql"); + + public static final DatabaseProductType UNRECOGNIZED = new DatabaseProductType("unrecognized"); +} diff --git a/services/common/src/main/java/org/collectionspace/services/common/storage/JDBCTools.java b/services/common/src/main/java/org/collectionspace/services/common/storage/JDBCTools.java index 2fb7c16f4..ae74f1644 100755 --- a/services/common/src/main/java/org/collectionspace/services/common/storage/JDBCTools.java +++ b/services/common/src/main/java/org/collectionspace/services/common/storage/JDBCTools.java @@ -15,7 +15,6 @@ * https://source.collectionspace.org/collection-space/LICENSE.txt */ - package org.collectionspace.services.common.storage; import org.collectionspace.services.common.ServiceMain; @@ -43,8 +42,8 @@ public class JDBCTools { final static Logger logger = LoggerFactory.getLogger(JDBCTools.class); public static Connection getConnection(String repositoryName) throws LoginException, SQLException { - if (Tools.isEmpty(repositoryName)){ - repositoryName = ServiceMain.DEFAULT_REPOSITORY_NAME; + if (Tools.isEmpty(repositoryName)) { + repositoryName = getDefaultRepositoryName(); } InitialContext ctx = null; Connection conn = null; @@ -72,15 +71,15 @@ public class JDBCTools { public static ResultSet executeQuery(String sql) throws Exception { Connection conn = null; - Statement stmt = null; + Statement stmt = null; try { - conn = JDBCTools.getConnection(ServiceMain.DEFAULT_REPOSITORY_NAME); - stmt = conn.createStatement(); - ResultSet rs = stmt.executeQuery(sql); - stmt.close(); + conn = getConnection(getDefaultRepositoryName()); + stmt = conn.createStatement(); + ResultSet rs = stmt.executeQuery(sql); + stmt.close(); return rs; //don't call rs.close() here ... Let caller close and catch any exceptions. } catch (RuntimeException rte) { - logger.debug("Exception in createDefaultAccounts: "+rte.getLocalizedMessage()); + logger.debug("Exception in createDefaultAccounts: " + rte.getLocalizedMessage()); logger.debug(rte.getStackTrace().toString()); throw rte; } catch (SQLException sqle) { @@ -90,30 +89,33 @@ public class JDBCTools { tempException = tempException.getNextException(); } logger.debug(sqle.getStackTrace().toString()); - throw new RuntimeException("SQL problem in openResultSet: ", sqle); + throw new RuntimeException("SQL problem in executeQuery: ", sqle); } finally { - try { - if(conn!=null) conn.close(); - if(stmt!=null) stmt.close(); + try { + if (conn != null) { + conn.close(); + } + if (stmt != null) { + stmt.close(); + } } catch (SQLException sqle) { - logger.debug("SQL Exception closing statement/connection in openResultSet: "+ sqle.getLocalizedMessage()); + logger.debug("SQL Exception closing statement/connection in executeQuery: " + sqle.getLocalizedMessage()); return null; - } + } } - } public static int executeUpdate(String sql) throws Exception { Connection conn = null; Statement stmt = null; try { - conn = JDBCTools.getConnection(ServiceMain.DEFAULT_REPOSITORY_NAME); + conn = getConnection(getDefaultRepositoryName()); stmt = conn.createStatement(); int rows = stmt.executeUpdate(sql); stmt.close(); return rows; } catch (RuntimeException rte) { - logger.debug("Exception in update: " + rte.getLocalizedMessage()); + logger.debug("Exception in executeUpdate: " + rte.getLocalizedMessage()); logger.debug(rte.getStackTrace().toString()); throw rte; } catch (SQLException sqle) { @@ -123,7 +125,7 @@ public class JDBCTools { tempException = tempException.getNextException(); } logger.debug(sqle.getStackTrace().toString()); - throw new RuntimeException("SQL problem in update: ", sqle); + throw new RuntimeException("SQL problem in executeUpdate: ", sqle); } finally { try { if (conn != null) { @@ -133,11 +135,50 @@ public class JDBCTools { stmt.close(); } } catch (SQLException sqle) { - logger.debug("SQL Exception closing statement/connection in openResultSet: " + sqle.getLocalizedMessage()); + logger.debug("SQL Exception closing statement/connection in executeUpdate: " + sqle.getLocalizedMessage()); return -1; } } + } + public static String getDatabaseProductName() { + String productName = ""; + Connection conn = null; + try { + conn = getConnection(getDefaultRepositoryName()); + productName = conn.getMetaData().getDatabaseProductName(); + } catch (Exception e) { + } finally { + try { + if (conn != null) { + conn.close(); + } + } catch (SQLException sqle) { + logger.debug("SQL Exception closing statement/connection in getDatabaseProductName: " + sqle.getLocalizedMessage()); + return productName; + } + } + return productName; } + + public static DatabaseProductType getDatabaseProductType() throws Exception { + DatabaseProductType productType = DatabaseProductType.UNRECOGNIZED; + try { + String productName = getDatabaseProductName(); + if (productName.matches("(?i).*mysql.*")) { + productType = DatabaseProductType.MYSQL; + } else if (productName.matches("(?i).*postgresql.*")) { + productType = DatabaseProductType.POSTGRESQL; + } else { + throw new Exception("Unrecognized database system " + productName); + } + } catch (Exception e) { + throw e; + } + return productType; + } + public static String getDefaultRepositoryName() { + return ServiceMain.DEFAULT_REPOSITORY_NAME; + } }