From: <fg...@us...> - 2008-02-21 21:01:16
|
Revision: 682 http://openutils.svn.sourceforge.net/openutils/?rev=682&view=rev Author: fgiust Date: 2008-02-21 13:00:56 -0800 (Thu, 21 Feb 2008) Log Message: ----------- ready for 2.0.3 Modified Paths: -------------- trunk/openutils-dbmigration/src/main/java/it/openutils/migration/oracle/OracleSequenceCreationTask.java trunk/openutils-dbmigration/src/main/java/it/openutils/migration/task/setup/ExcelConfigurationTask.java trunk/openutils-dbmigration/src/site/changes/changes.xml Added Paths: ----------- trunk/openutils-dbmigration/src/main/java/it/openutils/migration/oracle/OracleViewCreateOrUpdateTask.java Modified: trunk/openutils-dbmigration/src/main/java/it/openutils/migration/oracle/OracleSequenceCreationTask.java =================================================================== --- trunk/openutils-dbmigration/src/main/java/it/openutils/migration/oracle/OracleSequenceCreationTask.java 2008-02-21 14:57:33 UTC (rev 681) +++ trunk/openutils-dbmigration/src/main/java/it/openutils/migration/oracle/OracleSequenceCreationTask.java 2008-02-21 21:00:56 UTC (rev 682) @@ -45,6 +45,8 @@ private String creationQuery; + private String dropQuery; + private String selectUserSequences; private String selectAllSequences; @@ -70,6 +72,15 @@ } /** + * Sets the dropQuery. + * @param dropQuery the dropQuery to set + */ + public void setDropQuery(String dropQuery) + { + this.dropQuery = dropQuery; + } + + /** * Sets the selectAllSequences. * @param selectAllSequences the selectAllSequences to set */ Added: trunk/openutils-dbmigration/src/main/java/it/openutils/migration/oracle/OracleViewCreateOrUpdateTask.java =================================================================== --- trunk/openutils-dbmigration/src/main/java/it/openutils/migration/oracle/OracleViewCreateOrUpdateTask.java (rev 0) +++ trunk/openutils-dbmigration/src/main/java/it/openutils/migration/oracle/OracleViewCreateOrUpdateTask.java 2008-02-21 21:00:56 UTC (rev 682) @@ -0,0 +1,242 @@ +package it.openutils.migration.oracle; + +import it.openutils.migration.task.setup.DbTask; + +import java.io.IOException; +import java.io.InputStream; +import java.text.MessageFormat; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.sql.DataSource; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.io.Resource; +import org.springframework.jdbc.core.simple.SimpleJdbcTemplate; + + +/** + * <p> + * Db tasks that handles the initial setup of views. + * </p> + * <p> + * Limitations: + * </p> + * <ol> + * <li> * not supported in field list</li> + * <li> fields must be enclosed in quotes</li> + * </ol> + * @author albertoq + * @version $Id$ + */ +public class OracleViewCreateOrUpdateTask implements DbTask +{ + + /** + * Logger. + */ + private Logger log = LoggerFactory.getLogger(OracleViewCreateOrUpdateTask.class); + + /** + * Script list to execute + */ + protected List<Resource> scripts; + + /** + * Query to verify view existence + */ + private String selectUserViewExistence; + + /** + * Query to retrieve view ddl + */ + private String selectUserViewDDL; + + /** + * Statement to drop a view + */ + private String dropView; + + /** + * {@inheritDoc} + */ + public void execute(DataSource dataSource) + { + + SimpleJdbcTemplate jdbcTemplate = new SimpleJdbcTemplate(dataSource); + for (Resource script : scripts) + { + String viewName = this.objectNameFromFileName(script); + + int result = jdbcTemplate.queryForInt(getSelectUserViewExistence(), viewName); + + String scriptContent = readFully(script); + + if (scriptContent == null) + { + continue; + } + + if (result == 0) + { + log.info("View {} not existing. Creating new view", viewName); + + createView(jdbcTemplate, scriptContent); + } + else + { + String scriptBody = extractViewBody(scriptContent); + if (scriptBody == null) + { + continue; + } + + String previousDDl = (String) jdbcTemplate.getJdbcOperations().queryForObject( + getSelectUserViewDDL(), + new Object[]{viewName}, + String.class); + + if (!StringUtils.equals(previousDDl.trim(), scriptBody.trim())) + { + log.info( + "Previous definition of view {} differs from actual. Dropping and recreating view", + new Object[]{viewName}); + + jdbcTemplate.update(MessageFormat.format(getDropView(), new Object[]{viewName})); + + createView(jdbcTemplate, scriptContent); + } + } + } + + } + + /** + * @param script The script resource + * @return The script name + */ + protected String objectNameFromFileName(Resource script) + { + return StringUtils.substringBeforeLast(script.getFilename(), "."); + } + + /** + * @param scriptContent + * @return + */ + private String extractViewBody(String scriptContent) + { + Pattern pattern = Pattern.compile(".*\\s+AS\\s+(.*)", Pattern.CASE_INSENSITIVE | Pattern.DOTALL); + Matcher matcher = pattern.matcher(scriptContent); + boolean bodyFound = matcher.find(); + if (bodyFound) + { + return matcher.group(1); + } + else + { + return null; + } + } + + /** + * @param jdbcTemplate + * @param script + * @return + */ + private void createView(SimpleJdbcTemplate jdbcTemplate, String script) + { + + String[] ddls = StringUtils.split(script, ";"); + + for (String ddl : ddls) + { + if (StringUtils.isNotBlank(ddl)) + { + log.debug("Executing:\n{}", ddl); + jdbcTemplate.update(ddl); + } + } + } + + /** + * @param script + * @return + */ + private String readFully(Resource script) + { + if (script == null || !script.exists()) + { + log.error("Unable to execute db task \"{}\", script \"{}\" not found.", getDescription(), script); + return null; + } + + String scriptContent; + InputStream is = null; + + try + { + is = script.getInputStream(); + scriptContent = IOUtils.toString(is, "UTF8"); + } + catch (IOException e) + { + log.error("Unable to execute db task \"{}\", script \"{}\" can't be read.", getDescription(), script); + return null; + } + finally + { + IOUtils.closeQuietly(is); + } + return scriptContent; + } + + public String getDescription() + { + return "Checking Views"; + } + + public List<Resource> getScripts() + { + return scripts; + } + + public void setScripts(List<Resource> scripts) + { + this.scripts = scripts; + } + + public String getSelectUserViewExistence() + { + return selectUserViewExistence; + } + + public void setSelectUserViewExistence(String selectUserViewExistence) + { + this.selectUserViewExistence = selectUserViewExistence; + } + + public String getSelectUserViewDDL() + { + return selectUserViewDDL; + } + + public void setSelectUserViewDDL(String selectUserViewDDL) + { + this.selectUserViewDDL = selectUserViewDDL; + } + + public String getDropView() + { + return dropView; + } + + public void setDropView(String dropView) + { + this.dropView = dropView; + } +} Property changes on: trunk/openutils-dbmigration/src/main/java/it/openutils/migration/oracle/OracleViewCreateOrUpdateTask.java ___________________________________________________________________ Name: svn:mime-type + text/plain Name: svn:keywords + Author Date Id Revision Name: svn:eol-style + native Modified: trunk/openutils-dbmigration/src/main/java/it/openutils/migration/task/setup/ExcelConfigurationTask.java =================================================================== --- trunk/openutils-dbmigration/src/main/java/it/openutils/migration/task/setup/ExcelConfigurationTask.java 2008-02-21 14:57:33 UTC (rev 681) +++ trunk/openutils-dbmigration/src/main/java/it/openutils/migration/task/setup/ExcelConfigurationTask.java 2008-02-21 21:00:56 UTC (rev 682) @@ -21,7 +21,10 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Types; +import java.text.ParseException; +import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Iterator; import java.util.List; import java.util.Map; @@ -65,12 +68,22 @@ private Map<String, ExcelConfigurationTask.QueryConfig> config; /** + * Enable this task. + */ + private boolean enabled = true; + + /** * If true, when a record already exists and an updated query is defined it will be updated. Set it to false to only * insert new records. */ private boolean updateEnabled = true; /** + * Date format for ISO dates + */ + private SimpleDateFormat isodateformat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.S"); + + /** * Sets the script. * @param script the script to set */ @@ -89,6 +102,15 @@ } /** + * Sets the enabled. + * @param enabled the enabled to set + */ + public void setEnabled(boolean enabled) + { + this.enabled = enabled; + } + + /** * Sets the updateEnabled. * @param updateEnabled the updateEnabled to set */ @@ -102,6 +124,11 @@ */ public void execute(DataSource dataSource) { + if (!enabled) + { + return; + } + if (script == null || !script.exists()) { log.error("Unable to execute db task \"{}\", script \"{}\" not found.", getDescription(), script); @@ -123,7 +150,7 @@ QueryConfig conf = config.get(tableName); if (conf == null) { - log.error("Unable to handle table {}", tableName); + suggestSheetConfig(sheet, tableName, conf, dataSource); continue; } processSheet(sheet, tableName, conf, dataSource); @@ -142,6 +169,85 @@ } + public void suggestSheetConfig(HSSFSheet sheet, final String tableName, QueryConfig con, DataSource dataSource) + { + log.error("Unable to handle table {}", tableName); + + if (!log.isDebugEnabled()) + { + return; + } + + final List<String> columns = new ArrayList<String>(); + + HSSFRow row = sheet.getRow(0); + for (short k = 0; k < row.getLastCellNum(); k++) + { + HSSFCell cell = row.getCell(k); + if (cell != null) + { + String columnName = cell.getStringCellValue(); + if (StringUtils.isNotBlank(columnName)) + { + columns.add(StringUtils.trim(columnName)); + } + else + { + break; + } + } + } + + if (columns.isEmpty()) + { + return; + } + + StringBuffer buffer = new StringBuffer(); + + buffer.append(" <entry key=\""); + buffer.append(tableName); + buffer.append("\">\n" + + " <bean class=\"it.openutils.migration.task.setup.ExcelConfigurationTask$QueryConfig\">\n" + + " <property name=\"checkQuery\">\n" + + " <value>"); + + String initialCol = columns.get(0); + buffer.append("select count(" + initialCol + ") from " + tableName + " where " + initialCol + " = ?"); + buffer.append("</value>\n" + + " </property>\n" + + " <property name=\"insertQuery\">\n" + + " <value>"); + + buffer.append("INSERT INTO "); + buffer.append(tableName); + buffer.append(" ("); + + StringBuffer colNames = new StringBuffer(); + StringBuffer parNames = new StringBuffer(); + + for (Iterator<String> iterator = columns.iterator(); iterator.hasNext();) + { + String string = iterator.next(); + colNames.append(string); + parNames.append("?"); + if (iterator.hasNext()) + { + colNames.append(", "); + parNames.append(", "); + } + + } + + buffer.append(colNames); + buffer.append(") VALUES ("); + buffer.append(parNames); + buffer.append(")"); + buffer.append("</value>\n" + " </property>\n" + " </bean>\n" + " </entry>"); + + log.debug("You can use the following suggested config as template:\n{}", buffer.toString()); + } + /** * @param sheet * @param tableName @@ -312,6 +418,40 @@ { Object[] insertParams = ArrayUtils.subarray(values.toArray(), 0, insertNum); int[] insertTypes = ArrayUtils.subarray(types, 0, insertNum); + + // empty strings must be converted to nulls if the columns is numeric or date + // Cannot convert class java.lang.String to SQL type requested due to java.lang.NumberFormatException - + // For input string: "" + for (int j = 0; j < insertTypes.length; j++) + { + int tip = insertTypes[j]; + if (tip != Types.CHAR + && tip != Types.LONGNVARCHAR + && tip != Types.LONGVARCHAR + && tip != Types.NCHAR + && tip != Types.NVARCHAR + && tip != Types.VARCHAR + && "".equals(insertParams[j])) + { + insertParams[j] = null; + } + + if (tip == Types.DATE || tip == Types.TIME || tip == Types.TIMESTAMP && insertParams[j] != null) + { + synchronized (isodateformat) + { + try + { + insertParams[j] = isodateformat.parse((String) insertParams[j]); + } + catch (ParseException e) + { + log.debug("Cannot parse date \"{}\"", insertParams[j]); + } + } + } + } + if (log.isDebugEnabled()) { log.debug("Missing record with key {}; inserting {}", ArrayUtils.toString(checkParams), ArrayUtils @@ -323,7 +463,7 @@ log.warn("Invalid number of param/type for table {}. Params: {}, types: {}", new Object[]{ tableName, insertParams.length, - insertTypes.length }); + insertTypes.length}); } try @@ -340,7 +480,7 @@ rowNum + 1, insertStatement, ArrayUtils.toString(insertParams), - bsge.getMessage() }); + bsge.getMessage()}); continue; } } @@ -391,7 +531,7 @@ log.warn("Invalid number of param/type for table {}. Params: {}, types: {}", new Object[]{ tableName, updateParams.length, - insertTypes.length }); + insertTypes.length}); } try @@ -416,7 +556,7 @@ rowNum + 1, insertStatement, ArrayUtils.toString(updateParams), - bsge.getMessage() }); + bsge.getMessage()}); continue; } } Modified: trunk/openutils-dbmigration/src/site/changes/changes.xml =================================================================== --- trunk/openutils-dbmigration/src/site/changes/changes.xml 2008-02-21 14:57:33 UTC (rev 681) +++ trunk/openutils-dbmigration/src/site/changes/changes.xml 2008-02-21 21:00:56 UTC (rev 682) @@ -8,6 +8,15 @@ <author email="fgiust(at)users.sourceforge.net">Fabrizio Giustina</author> </properties> <body> + <release version="2.0.3" date="2008-02-21" description="2.0.3"> + <action type="add" dev="fgiust">New it.openutils.migration.oracle.OracleViewCreateOrUpdateTask</action> + <action type="fix" dev="fgiust">Fix handling of empty strings for numeric types in ExcelConfigurationTask</action> + <action type="update" dev="fgiust"> + Dates are now always processed using an ISO8601 date format in ExcelConfigurationTask (previously the parsing + was left to the jdbc driver, leading to different results with different drivers) + </action> + <action type="add" dev="fgiust">Added a new "enabled" flag in ExcelConfigurationTask</action> + </release> <release version="2.0.2" date="2008-02-11" description="2.0.2"> <action type="add" dev="fgiust">New it.openutils.migration.oracle.OracleSequenceCreationTask</action> <action type="update" dev="fgiust"> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |