Schema bootstrap changes

- More precise origins of scripts
 - All executed statements are recorded in a single file


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@5660 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Derek Hulley
2007-05-10 16:17:37 +00:00
parent 2afe43dad1
commit 3d47482757
2 changed files with 73 additions and 30 deletions

View File

@@ -1,9 +1,12 @@
# Schema update messages # Schema update messages
schema.update.msg.bypassing=Bypassing schema update checks. schema.update.msg.bypassing=Bypassing schema update checks.
schema.update.msg.executing_script=Executing database script: {0} schema.update.msg.all_statements=All executed statements written to file {0}.
schema.update.msg.no_changes=No changes were made to the schema.
schema.update.msg.executing_generated_script=Executing database script {0} (Generated).
schema.update.msg.executing_copied_script=Executing database script {0} (Copied from {1}).
schema.update.msg.executing_statement= Executing statement: {0}
schema.update.msg.optional_statement_failed=Optional statement execution failed:\n SQL: {0}\n Error: {1}\n File: {2}\n Line: {3} schema.update.msg.optional_statement_failed=Optional statement execution failed:\n SQL: {0}\n Error: {1}\n File: {2}\n Line: {3}
schema.update.msg.dumping_schema_create=Generating unmodified schema creation script: {0}
schema.update.err.statement_failed=Statement execution failed:\n SQL: {0}\n Error: {1}\n File: {2}\n Line: {3} schema.update.err.statement_failed=Statement execution failed:\n SQL: {0}\n Error: {1}\n File: {2}\n Line: {3}
schema.update.err.update_failed=Schema auto-update failed schema.update.err.update_failed=Schema auto-update failed
schema.update.err.validation_failed=Schema validation failed schema.update.err.validation_failed=Schema validation failed

View File

@@ -42,7 +42,6 @@ import java.util.List;
import java.util.Properties; import java.util.Properties;
import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.i18n.I18NUtil;
import org.alfresco.repo.admin.patch.impl.SchemaUpgradeScriptPatch; import org.alfresco.repo.admin.patch.impl.SchemaUpgradeScriptPatch;
import org.alfresco.repo.content.filestore.FileContentWriter; import org.alfresco.repo.content.filestore.FileContentWriter;
import org.alfresco.service.ServiceRegistry; import org.alfresco.service.ServiceRegistry;
@@ -51,6 +50,7 @@ import org.alfresco.service.descriptor.Descriptor;
import org.alfresco.service.descriptor.DescriptorService; import org.alfresco.service.descriptor.DescriptorService;
import org.alfresco.util.AbstractLifecycleBean; import org.alfresco.util.AbstractLifecycleBean;
import org.alfresco.util.ApplicationContextHelper; import org.alfresco.util.ApplicationContextHelper;
import org.alfresco.util.LogUtil;
import org.alfresco.util.TempFileProvider; import org.alfresco.util.TempFileProvider;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
@@ -83,9 +83,12 @@ public class SchemaBootstrap extends AbstractLifecycleBean
private static final String PLACEHOLDER_SCRIPT_DIALECT = "\\$\\{db\\.script\\.dialect\\}"; private static final String PLACEHOLDER_SCRIPT_DIALECT = "\\$\\{db\\.script\\.dialect\\}";
private static final String MSG_BYPASSING_SCHEMA_UPDATE = "schema.update.msg.bypassing"; private static final String MSG_BYPASSING_SCHEMA_UPDATE = "schema.update.msg.bypassing";
private static final String MSG_EXECUTING_SCRIPT = "schema.update.msg.executing_script"; private static final String MSG_NO_CHANGES = "schema.update.msg.no_changes";
private static final String MSG_ALL_STATEMENTS = "schema.update.msg.all_statements";
private static final String MSG_EXECUTING_GENERATED_SCRIPT = "schema.update.msg.executing_generated_script";
private static final String MSG_EXECUTING_COPIED_SCRIPT = "schema.update.msg.executing_copied_script";
private static final String MSG_EXECUTING_STATEMENT = "schema.update.msg.executing_statement";
private static final String MSG_OPTIONAL_STATEMENT_FAILED = "schema.update.msg.optional_statement_failed"; private static final String MSG_OPTIONAL_STATEMENT_FAILED = "schema.update.msg.optional_statement_failed";
private static final String MSG_DUMPING_SCHEMA_CREATE = "schema.update.msg.dumping_schema_create";
private static final String ERR_STATEMENT_FAILED = "schema.update.err.statement_failed"; private static final String ERR_STATEMENT_FAILED = "schema.update.err.statement_failed";
private static final String ERR_UPDATE_FAILED = "schema.update.err.update_failed"; private static final String ERR_UPDATE_FAILED = "schema.update.err.update_failed";
private static final String ERR_VALIDATION_FAILED = "schema.update.err.validation_failed"; private static final String ERR_VALIDATION_FAILED = "schema.update.err.validation_failed";
@@ -103,6 +106,8 @@ public class SchemaBootstrap extends AbstractLifecycleBean
private List<SchemaUpgradeScriptPatch> preUpdateScriptPatches; private List<SchemaUpgradeScriptPatch> preUpdateScriptPatches;
private List<SchemaUpgradeScriptPatch> postUpdateScriptPatches; private List<SchemaUpgradeScriptPatch> postUpdateScriptPatches;
private ThreadLocal<StringBuilder> executedStatementsThreadLocal = new ThreadLocal<StringBuilder>();
public SchemaBootstrap() public SchemaBootstrap()
{ {
postCreateScriptUrls = new ArrayList<String>(1); postCreateScriptUrls = new ArrayList<String>(1);
@@ -192,13 +197,8 @@ public class SchemaBootstrap extends AbstractLifecycleBean
* Helper method to generate a schema creation SQL script from the given Hibernate * Helper method to generate a schema creation SQL script from the given Hibernate
* configuration. * configuration.
*/ */
public static void dumpSchemaCreate(Configuration cfg, File schemaOutputFile) private static void dumpSchemaCreate(Configuration cfg, File schemaOutputFile)
{ {
if (logger.isInfoEnabled())
{
String msg = I18NUtil.getMessage(MSG_DUMPING_SCHEMA_CREATE, schemaOutputFile);
logger.info(msg);
}
// if the file exists, delete it // if the file exists, delete it
if (schemaOutputFile.exists()) if (schemaOutputFile.exists())
{ {
@@ -357,8 +357,8 @@ public class SchemaBootstrap extends AbstractLifecycleBean
// the applied patch table is missing - we assume that all other tables are missing // the applied patch table is missing - we assume that all other tables are missing
// perform a full update using Hibernate-generated statements // perform a full update using Hibernate-generated statements
File tempFile = TempFileProvider.createTempFile("AlfrescoSchemaCreate-" + dialectStr + "-", ".sql"); File tempFile = TempFileProvider.createTempFile("AlfrescoSchemaCreate-" + dialectStr + "-", ".sql");
dumpSchemaCreate(cfg, tempFile); SchemaBootstrap.dumpSchemaCreate(cfg, tempFile);
executeScriptFile(cfg, connection, tempFile, tempFile.getPath()); executeScriptFile(cfg, connection, tempFile, null);
// execute post-create scripts (not patches) // execute post-create scripts (not patches)
for (String scriptUrl : this.postCreateScriptUrls) for (String scriptUrl : this.postCreateScriptUrls)
{ {
@@ -400,7 +400,7 @@ public class SchemaBootstrap extends AbstractLifecycleBean
// execute if there were changes raised by Hibernate // execute if there were changes raised by Hibernate
if (tempFile != null) if (tempFile != null)
{ {
executeScriptFile(cfg, connection, tempFile, tempFile.getPath()); executeScriptFile(cfg, connection, tempFile, null);
} }
// Execute any post-auto-update scripts // Execute any post-auto-update scripts
@@ -473,7 +473,9 @@ public class SchemaBootstrap extends AbstractLifecycleBean
try { scriptInputStream.close(); } catch (Throwable e) {} // usually a duplicate close try { scriptInputStream.close(); } catch (Throwable e) {} // usually a duplicate close
} }
// now execute it // now execute it
executeScriptFile(cfg, connection, tempFile, scriptUrl); String dialectScriptUrl = scriptUrl.replaceAll(PLACEHOLDER_SCRIPT_DIALECT, dialect.getClass().getName());
// Replace the script placeholders
executeScriptFile(cfg, connection, tempFile, dialectScriptUrl);
} }
/** /**
@@ -512,13 +514,27 @@ public class SchemaBootstrap extends AbstractLifecycleBean
} }
} }
/**
* @param cfg the Hibernate configuration
* @param connection the DB connection to use
* @param scriptFile the file containing the statements
* @param scriptUrl the URL of the script to report. If this is null, the script
* is assumed to have been auto-generated.
*/
private void executeScriptFile( private void executeScriptFile(
Configuration cfg, Configuration cfg,
Connection connection, Connection connection,
File scriptFile, File scriptFile,
String scriptUrl) throws Exception String scriptUrl) throws Exception
{ {
logger.info(I18NUtil.getMessage(MSG_EXECUTING_SCRIPT, scriptUrl)); if (scriptUrl == null)
{
LogUtil.info(logger, MSG_EXECUTING_GENERATED_SCRIPT, scriptFile);
}
else
{
LogUtil.info(logger, MSG_EXECUTING_COPIED_SCRIPT, scriptFile, scriptUrl);
}
InputStream scriptInputStream = new FileInputStream(scriptFile); InputStream scriptInputStream = new FileInputStream(scriptFile);
BufferedReader reader = new BufferedReader(new InputStreamReader(scriptInputStream, "UTF8")); BufferedReader reader = new BufferedReader(new InputStreamReader(scriptInputStream, "UTF8"));
@@ -597,22 +613,26 @@ public class SchemaBootstrap extends AbstractLifecycleBean
{ {
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
{ {
logger.debug("Executing statement: " + sql); LogUtil.debug(logger, MSG_EXECUTING_STATEMENT, sql);
} }
stmt.execute(sql); stmt.execute(sql);
// Write the statement to the file, if necessary
StringBuilder executedStatements = executedStatementsThreadLocal.get();
if (executedStatements != null)
{
executedStatements.append(sql).append(";\n");
}
} }
catch (SQLException e) catch (SQLException e)
{ {
if (optional) if (optional)
{ {
// it was marked as optional, so we just ignore it // it was marked as optional, so we just ignore it
String msg = I18NUtil.getMessage(MSG_OPTIONAL_STATEMENT_FAILED, sql, e.getMessage(), file.getAbsolutePath(), line); LogUtil.debug(logger, MSG_OPTIONAL_STATEMENT_FAILED, sql, e.getMessage(), file.getAbsolutePath(), line);
logger.debug(msg);
} }
else else
{ {
String err = I18NUtil.getMessage(ERR_STATEMENT_FAILED, sql, e.getMessage(), file.getAbsolutePath(), line); LogUtil.error(logger, ERR_STATEMENT_FAILED, sql, e.getMessage(), file.getAbsolutePath(), line);
logger.error(err);
throw e; throw e;
} }
} }
@@ -640,18 +660,37 @@ public class SchemaBootstrap extends AbstractLifecycleBean
cfg.setProperty(Environment.CONNECTION_PROVIDER, SchemaBootstrapConnectionProvider.class.getName()); cfg.setProperty(Environment.CONNECTION_PROVIDER, SchemaBootstrapConnectionProvider.class.getName());
SchemaBootstrapConnectionProvider.setBootstrapConnection(connection); SchemaBootstrapConnectionProvider.setBootstrapConnection(connection);
// dump the schema, if required
if (schemaOuputFilename != null)
{
File schemaOutputFile = new File(schemaOuputFilename);
dumpSchemaCreate(cfg, schemaOutputFile);
}
// update the schema, if required // update the schema, if required
if (updateSchema) if (updateSchema)
{ {
// Allocate buffer for executed statements
executedStatementsThreadLocal.set(new StringBuilder(1024));
updateSchema(cfg, session, connection); updateSchema(cfg, session, connection);
// Copy the executed statements to the output file
File schemaOutputFile = null;
if (schemaOuputFilename != null)
{
schemaOutputFile = new File(schemaOuputFilename);
}
else
{
schemaOutputFile = TempFileProvider.createTempFile("AlfrescoSchemaUpdate-All_Statements-", ".sql");
}
String executedStatements = executedStatementsThreadLocal.get().toString();
if (executedStatements.length() == 0)
{
LogUtil.info(logger, MSG_NO_CHANGES);
}
else
{
FileContentWriter writer = new FileContentWriter(schemaOutputFile);
writer.setEncoding("UTF-8");
writer.putContent(executedStatements);
LogUtil.info(logger, MSG_ALL_STATEMENTS, schemaOutputFile.getPath());
}
// verify that all patches have been applied correctly // verify that all patches have been applied correctly
checkSchemaPatchScripts(cfg, session, connection, validateUpdateScriptPatches, false); // check scripts checkSchemaPatchScripts(cfg, session, connection, validateUpdateScriptPatches, false); // check scripts
checkSchemaPatchScripts(cfg, session, connection, preUpdateScriptPatches, false); // check scripts checkSchemaPatchScripts(cfg, session, connection, preUpdateScriptPatches, false); // check scripts
@@ -659,7 +698,7 @@ public class SchemaBootstrap extends AbstractLifecycleBean
} }
else else
{ {
logger.info(I18NUtil.getMessage(MSG_BYPASSING_SCHEMA_UPDATE)); LogUtil.info(logger, MSG_BYPASSING_SCHEMA_UPDATE);
} }
// Reset the configuration // Reset the configuration
@@ -670,6 +709,7 @@ public class SchemaBootstrap extends AbstractLifecycleBean
} }
catch (Throwable e) catch (Throwable e)
{ {
LogUtil.error(logger, e, ERR_UPDATE_FAILED);
try { transaction.rollback(); } catch (Throwable ee) {} try { transaction.rollback(); } catch (Throwable ee) {}
if (updateSchema) if (updateSchema)
{ {
@@ -776,7 +816,7 @@ public class SchemaBootstrap extends AbstractLifecycleBean
} }
catch (Throwable e) catch (Throwable e)
{ {
logger.error("SchemaBootstrap script dump failed", e); LogUtil.error(logger, e, "SchemaBootstrap script dump failed");
exitCode = 1; exitCode = 1;
} }
// We can exit // We can exit