ALF-11516: Load schema ref. file using same location and mechanism as for db create scripts

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@32049 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Matt Ward
2011-11-17 11:28:07 +00:00
parent d80f8c136a
commit d111a38a56
2 changed files with 101 additions and 45 deletions

View File

@@ -48,6 +48,7 @@ import java.sql.Savepoint;
import java.sql.Statement;
import java.sql.Struct;
import java.sql.Types;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
@@ -112,6 +113,7 @@ import org.springframework.extensions.surf.util.AbstractLifecycleBean;
import org.springframework.extensions.surf.util.I18NUtil;
import org.springframework.orm.hibernate3.LocalSessionFactoryBean;
/**
* Bootstraps the schema and schema update. The schema is considered missing if the applied patch table
* is not present, and the schema is considered empty if the applied patch table is empty.
@@ -121,7 +123,7 @@ import org.springframework.orm.hibernate3.LocalSessionFactoryBean;
public class SchemaBootstrap extends AbstractLifecycleBean
{
/** The placeholder for the configured <code>Dialect</code> class name: <b>${db.script.dialect}</b> */
private static final String PLACEHOLDER_SCRIPT_DIALECT = "\\$\\{db\\.script\\.dialect\\}";
private static final String PLACEHOLDER_DIALECT = "\\$\\{db\\.script\\.dialect\\}";
/** The global property containing the default batch size used by --FOREACH */
private static final String PROPERTY_DEFAULT_BATCH_SIZE = "system.upgrade.default.batchsize";
@@ -226,6 +228,7 @@ public class SchemaBootstrap extends AbstractLifecycleBean
private boolean stopAfterSchemaBootstrap;
private List<String> preCreateScriptUrls;
private List<String> postCreateScriptUrls;
private String schemaReferenceUrl;
private List<SchemaUpgradeScriptPatch> validateUpdateScriptPatches;
private List<SchemaUpgradeScriptPatch> preUpdateScriptPatches;
private List<SchemaUpgradeScriptPatch> postUpdateScriptPatches;
@@ -304,7 +307,7 @@ public class SchemaBootstrap extends AbstractLifecycleBean
*
* @param postCreateScriptUrls file URLs
*
* @see #PLACEHOLDER_SCRIPT_DIALECT
* @see #PLACEHOLDER_DIALECT
*/
public void setPreCreateScriptUrls(List<String> preUpdateScriptUrls)
{
@@ -316,13 +319,28 @@ public class SchemaBootstrap extends AbstractLifecycleBean
*
* @param postCreateScriptUrls file URLs
*
* @see #PLACEHOLDER_SCRIPT_DIALECT
* @see #PLACEHOLDER_DIALECT
*/
public void setPostCreateScriptUrls(List<String> postUpdateScriptUrls)
{
this.postCreateScriptUrls = postUpdateScriptUrls;
}
/**
* Specifies the schema reference file that will be used to validate the repository
* schema whenever changes have been made. The database dialect placeholder will be
* resolved so that the correct reference file is loaded for the current database
* type (e.g. PostgreSQL)
*
* @param schemaReferenceUrl the schemaReferenceUrl to set
* @see #PLACEHOLDER_DIALECT
*/
public void setSchemaReferenceUrl(String schemaReferenceUrl)
{
this.schemaReferenceUrl = schemaReferenceUrl;
}
/**
* Set the schema script patches that must have been applied. These will not be
* applied to the database. These can be used where the script <u>cannot</u> be
@@ -940,11 +958,46 @@ public class SchemaBootstrap extends AbstractLifecycleBean
try { scriptInputStream.close(); } catch (Throwable e) {} // usually a duplicate close
}
// now execute it
String dialectScriptUrl = scriptUrl.replaceAll(PLACEHOLDER_SCRIPT_DIALECT, dialect.getClass().getName());
String dialectScriptUrl = scriptUrl.replaceAll(PLACEHOLDER_DIALECT, dialect.getClass().getName());
// Replace the script placeholders
executeScriptFile(cfg, connection, tempFile, dialectScriptUrl);
}
/**
* Replaces the dialect placeholder in the resource URL and attempts to find a file for
* it. If not found, the dialect hierarchy will be walked until a compatible resource is
* found. This makes it possible to have resources that are generic to all dialects.
*
* @return The Resource, otherwise null
*/
private Resource getDialectResource(Class dialectClass, String resourceUrl)
{
// replace the dialect placeholder
String dialectResourceUrl = resourceUrl.replaceAll(PLACEHOLDER_DIALECT, dialectClass.getName());
// get a handle on the resource
Resource resource = rpr.getResource(dialectResourceUrl);
if (!resource.exists())
{
// it wasn't found. Get the superclass of the dialect and try again
Class superClass = dialectClass.getSuperclass();
if (Dialect.class.isAssignableFrom(superClass))
{
// we still have a Dialect - try again
return getDialectResource(superClass, resourceUrl);
}
else
{
// we have exhausted all options
return null;
}
}
else
{
// we have a handle to it
return resource;
}
}
/**
* Replaces the dialect placeholder in the script URL and attempts to find a file for
* it. If not found, the dialect hierarchy will be walked until a compatible script is
@@ -954,30 +1007,7 @@ public class SchemaBootstrap extends AbstractLifecycleBean
*/
private InputStream getScriptInputStream(Class dialectClazz, String scriptUrl) throws Exception
{
// replace the dialect placeholder
String dialectScriptUrl = scriptUrl.replaceAll(PLACEHOLDER_SCRIPT_DIALECT, dialectClazz.getName());
// get a handle on the resource
Resource resource = rpr.getResource(dialectScriptUrl);
if (!resource.exists())
{
// it wasn't found. Get the superclass of the dialect and try again
Class superClazz = dialectClazz.getSuperclass();
if (Dialect.class.isAssignableFrom(superClazz))
{
// we still have a Dialect - try again
return getScriptInputStream(superClazz, scriptUrl);
}
else
{
// we have exhausted all options
return null;
}
}
else
{
// we have a handle to it
return resource.getInputStream();
}
return getDialectResource(dialectClazz, scriptUrl).getInputStream();
}
/**
@@ -998,6 +1028,9 @@ public class SchemaBootstrap extends AbstractLifecycleBean
StringBuilder executedStatements = executedStatementsThreadLocal.get();
if (executedStatements == null)
{
// Validate the schema, pre-upgrade
validateSchema("Alfresco-{0}-Validation-Pre-Upgrade-");
// Dump the normalized, pre-upgrade Alfresco schema. We keep the file for later reporting.
xmlPreSchemaOutputFile = dumpSchema(
this.dialect,
@@ -1494,11 +1527,13 @@ public class SchemaBootstrap extends AbstractLifecycleBean
setBootstrapCompleted(connection);
}
validateSchema();
// Report normalized dumps
if (executedStatements != null)
{
// Validate the schema, post-upgrade
validateSchema("Alfresco-{0}-Validation-Post-Upgrade-");
// Dump the normalized, post-upgrade Alfresco schema.
File xmlPostSchemaOutputFile = dumpSchema(
this.dialect,
@@ -1598,20 +1633,16 @@ public class SchemaBootstrap extends AbstractLifecycleBean
* Collate differences and validation problems with the schema with respect to an appropriate
* reference schema.
*/
private void validateSchema()
private void validateSchema(String outputFileNameTemplate)
{
Date startTime = new Date();
String referenceFileName = dialect.getClass().getSimpleName() + "-Reference.xml";
Resource referenceResource = rpr.getResource("classpath:org/alfresco/util/schemacomp/reference/"
+ referenceFileName);
Resource referenceResource = getDialectResource(dialect.getClass(), schemaReferenceUrl);
if (!referenceResource.exists())
{
logger.info("No reference schema file, expected: " + referenceResource);
logger.debug("No reference schema file, expected: " + referenceResource);
return;
}
logger.info("Comparing database schema with reference schema: " + referenceResource);
InputStream is = null;
try
@@ -1638,10 +1669,13 @@ public class SchemaBootstrap extends AbstractLifecycleBean
Results differences = schemaComparator.getDifferences();
List<ValidationResult> validationResults = schemaComparator.getValidationResults();
File outputFile = TempFileProvider.createTempFile(
"Alfresco-" + dialect.getClass().getSimpleName() + "-Validation", ".txt");
String outputFileName = MessageFormat.format(
outputFileNameTemplate,
new Object[] { dialect.getClass().getSimpleName() });
File outputFile = TempFileProvider.createTempFile(outputFileName, ".txt");
logger.info("Writing schema validation results to: " + outputFile);
PrintWriter pw = null;
try
@@ -1660,20 +1694,27 @@ public class SchemaBootstrap extends AbstractLifecycleBean
.append(" (diff): ")
.append(difference.getWhere());
sb.append(" reference: ");
sb.append(" reference path:");
if (difference.getLeft() != null)
{
sb.append(difference.getLeft().getPath());
sb.append(" (value: ")
.append(difference.getLeft().getPropertyValue())
.append(")");
}
else
{
sb.append("null");
}
sb.append(" target: ");
sb.append(" target path:");
if (difference.getRight() != null)
{
sb.append(difference.getRight().getPath());
sb.append(" (value: ")
.append(difference.getRight().getPropertyValue())
.append(")");
}
else
{
@@ -1688,19 +1729,31 @@ public class SchemaBootstrap extends AbstractLifecycleBean
StringBuffer sb = new StringBuffer();
sb.append(validationResult.getStrength())
.append(" (validation): ")
.append("target: ")
.append("target path:")
.append(validationResult.getDbProperty().getPath())
.append(" value: ")
.append(validationResult.getValue());
.append(" (value: ")
.append(validationResult.getValue())
.append(")");
pw.println(sb);
}
pw.close();
if (validationResults.size() == 0 && differences.size() == 0)
{
logger.info("Compared database schema with reference schema (all OK): " + referenceResource);
}
else
{
int numProblems = validationResults.size() + differences.size();
logger.warn("Schema validation found " + numProblems +
" potential problems, results written to: "
+ outputFile);
}
Date endTime = new Date();
long durationMillis = endTime.getTime() - startTime.getTime();
logger.info("Schema validation took " + durationMillis + "ms");
logger.debug("Schema validation took " + durationMillis + "ms");
}
/**