(4);
@@ -207,7 +216,34 @@ public class SchemaBootstrap extends AbstractLifecycleBean
}
/**
- * Set the scripts that must be executed after the schema has been created.
+ * Set whether this component should terminate the bootstrap process after running all the
+ * usual checks and scripts. This has the additional effect of dumping a final schema
+ * structure file just before exiting.
+ *
+ * WARNING: USE FOR DEBUG AND UPGRADE TESTING ONLY
+ *
+ * @param stopAfterSchemaBootstrap true to terminate (with exception) after
+ * running all the usual schema updates and checks.
+ */
+ public void setStopAfterSchemaBootstrap(boolean stopAfterSchemaBootstrap)
+ {
+ this.stopAfterSchemaBootstrap = stopAfterSchemaBootstrap;
+ }
+
+ /**
+ * Set the scripts that must be executed before the schema has been created.
+ *
+ * @param postCreateScriptUrls file URLs
+ *
+ * @see #PLACEHOLDER_SCRIPT_DIALECT
+ */
+ public void setPreCreateScriptUrls(List preUpdateScriptUrls)
+ {
+ this.preCreateScriptUrls = preUpdateScriptUrls;
+ }
+
+ /**
+ * Set the scripts that must be executed after the schema has been created.
*
* @param postCreateScriptUrls file URLs
*
@@ -345,6 +381,23 @@ public class SchemaBootstrap extends AbstractLifecycleBean
{
private static final long serialVersionUID = 5574280159910824660L;
}
+
+ /**
+ * Used to indicate a forced stop of the bootstrap.
+ *
+ * @see SchemaBootstrap#setStopAfterSchemaBootstrap(boolean)
+ *
+ * @author Derek Hulley
+ * @since 3.1.1
+ */
+ private static class BootstrapStopException extends RuntimeException
+ {
+ private static final long serialVersionUID = 4250016675538442181L;
+ private BootstrapStopException()
+ {
+ super(I18NUtil.getMessage(ERR_FORCED_STOP));
+ }
+ }
/**
* Count applied patches. This fails if multiple applied patch tables are found,
@@ -618,13 +671,18 @@ public class SchemaBootstrap extends AbstractLifecycleBean
}
// Get the dialect
final Dialect dialect = Dialect.getDialect(cfg.getProperties());
- String dialectStr = dialect.getClass().getName();
+ String dialectStr = dialect.getClass().getSimpleName();
if (create)
{
+ // execute pre-create scripts (not patches)
+ for (String scriptUrl : this.preCreateScriptUrls)
+ {
+ executeScriptUrl(cfg, connection, scriptUrl);
+ }
// the applied patch table is missing - we assume that all other tables are missing
// perform a full update using Hibernate-generated statements
- File tempFile = TempFileProvider.createTempFile("AlfrescoSchemaCreate-" + dialectStr + "-", ".sql");
+ File tempFile = TempFileProvider.createTempFile("AlfrescoSchema-" + dialectStr + "-Update-", ".sql");
SchemaBootstrap.dumpSchemaCreate(cfg, tempFile);
executeScriptFile(cfg, connection, tempFile, null);
// execute post-create scripts (not patches)
@@ -649,7 +707,7 @@ public class SchemaBootstrap extends AbstractLifecycleBean
String[] sqls = cfg.generateSchemaUpdateScript(dialect, metadata);
if (sqls.length > 0)
{
- tempFile = TempFileProvider.createTempFile("AlfrescoSchemaUpdate-" + dialectStr + "-", ".sql");
+ tempFile = TempFileProvider.createTempFile("AlfrescoSchema-" + dialectStr + "-Update-", ".sql");
writer = new BufferedWriter(new FileWriter(tempFile));
for (String sql : sqls)
{
@@ -743,7 +801,7 @@ public class SchemaBootstrap extends AbstractLifecycleBean
private void executeScriptUrl(Configuration cfg, Connection connection, String scriptUrl) throws Exception
{
Dialect dialect = Dialect.getDialect(cfg.getProperties());
- String dialectStr = dialect.getClass().getName();
+ String dialectStr = dialect.getClass().getSimpleName();
InputStream scriptInputStream = getScriptInputStream(dialect.getClass(), scriptUrl);
// check that it exists
if (scriptInputStream == null)
@@ -754,7 +812,7 @@ public class SchemaBootstrap extends AbstractLifecycleBean
File tempFile = null;
try
{
- tempFile = TempFileProvider.createTempFile("AlfrescoSchemaUpdate-" + dialectStr + "-", ".sql");
+ tempFile = TempFileProvider.createTempFile("AlfrescoSchema-" + dialectStr + "-Update-", ".sql");
ContentWriter writer = new FileContentWriter(tempFile);
writer.putContent(scriptInputStream);
}
@@ -1115,6 +1173,15 @@ public class SchemaBootstrap extends AbstractLifecycleBean
// Update the schema, if required.
if (updateSchema)
{
+ // Dump the normalized, pre-upgrade Alfresco schema. We keep the file for later reporting.
+ File xmlPreSchemaOutputFile = dumpSchema(
+ connection,
+ dialect,
+ TempFileProvider.createTempFile(
+ "AlfrescoSchema-" + dialect.getClass().getSimpleName() + "-",
+ "-Startup.xml").getPath(),
+ "Failed to dump normalized, pre-upgrade schema to file.");
+
// Retries are required here as the DB lock will be applied lazily upon first statement execution.
// So if the schema is up to date (no statements executed) then the LockFailException cannot be
// thrown. If it is thrown, the the update needs to be rerun as it will probably generate no SQL
@@ -1150,8 +1217,11 @@ public class SchemaBootstrap extends AbstractLifecycleBean
}
else
{
- schemaOutputFile = TempFileProvider.createTempFile("AlfrescoSchemaUpdate-All_Statements-", ".sql");
+ schemaOutputFile = TempFileProvider.createTempFile(
+ "AlfrescoSchema-" + dialect.getClass().getSimpleName() + "-All_Statements-",
+ ".sql");
}
+
StringBuilder executedStatements = executedStatementsThreadLocal.get();
if (executedStatements == null)
{
@@ -1179,11 +1249,61 @@ public class SchemaBootstrap extends AbstractLifecycleBean
// Remove the flag indicating a running bootstrap
setBootstrapCompleted(connection);
}
+
+ // Dump the normalized, post-upgrade Alfresco schema.
+ File xmlPostSchemaOutputFile = dumpSchema(
+ connection,
+ dialect,
+ TempFileProvider.createTempFile(
+ "AlfrescoSchema-" + dialect.getClass().getSimpleName() + "-",
+ ".xml").getPath(),
+ "Failed to dump normalized, post-upgrade schema to file.");
+
+ // Report normalized dumps
+ if (createdSchema)
+ {
+ // This is a new schema
+ if (xmlPostSchemaOutputFile != null)
+ {
+ LogUtil.info(logger, MSG_NORMALIZED_SCHEMA, xmlPostSchemaOutputFile.getPath());
+ }
+ }
+ else if (executedStatements != null)
+ {
+ // We upgraded, so have to report pre- and post- schema dumps
+ if (xmlPreSchemaOutputFile != null)
+ {
+ LogUtil.info(logger, MSG_NORMALIZED_SCHEMA_PRE, xmlPreSchemaOutputFile.getPath());
+ }
+ if (xmlPostSchemaOutputFile != null)
+ {
+ LogUtil.info(logger, MSG_NORMALIZED_SCHEMA_POST, xmlPostSchemaOutputFile.getPath());
+ }
+ }
}
else
{
LogUtil.info(logger, MSG_BYPASSING_SCHEMA_UPDATE);
}
+
+ if (stopAfterSchemaBootstrap)
+ {
+ // We have been forced to stop, so we do one last dump of the schema and throw an exception to
+ // escape further startup procedures
+ File xmlStopSchemaOutputFile = dumpSchema(
+ connection,
+ dialect,
+ TempFileProvider.createTempFile(
+ "AlfrescoSchema-" + dialect.getClass().getSimpleName() + "-",
+ "-ForcedExit.xml").getPath(),
+ "Failed to dump normalized, post-upgrade, forced-exit schema to file.");
+ if (xmlStopSchemaOutputFile != null)
+ {
+ LogUtil.info(logger, MSG_NORMALIZED_SCHEMA, xmlStopSchemaOutputFile);
+ }
+ LogUtil.error(logger, ERR_FORCED_STOP);
+ throw new BootstrapStopException();
+ }
// Reset the configuration
cfg.setProperty(Environment.CONNECTION_PROVIDER, defaultConnectionProviderFactoryClass);
@@ -1191,6 +1311,11 @@ public class SchemaBootstrap extends AbstractLifecycleBean
// all done successfully
((ApplicationContext) event.getSource()).publishEvent(new SchemaAvailableEvent(this));
}
+ catch (BootstrapStopException e)
+ {
+ // We just let this out
+ throw e;
+ }
catch (Throwable e)
{
LogUtil.error(logger, e, ERR_UPDATE_FAILED);
@@ -1221,6 +1346,33 @@ public class SchemaBootstrap extends AbstractLifecycleBean
}
}
+
+ /**
+ * @return Returns the file that was written to or null if it failed
+ */
+ private File dumpSchema(Connection connection, Dialect dialect, String fileName, String err)
+ {
+ File xmlSchemaOutputFile = new File(fileName);
+ try
+ {
+ Main xmlSchemaOutputMain = new Main(connection, dialect);
+ xmlSchemaOutputMain.execute(xmlSchemaOutputFile);
+ }
+ catch (Throwable e)
+ {
+ xmlSchemaOutputFile = null;
+ // Don't fail the upgrade on this
+ if (logger.isDebugEnabled())
+ {
+ logger.debug(err, e);
+ }
+ else
+ {
+ logger.error(err + " Error: " + e.getMessage());
+ }
+ }
+ return xmlSchemaOutputFile;
+ }
@Override
protected void onShutdown(ApplicationEvent event)
diff --git a/source/java/org/alfresco/repo/model/filefolder/FileFolderServiceImpl.java b/source/java/org/alfresco/repo/model/filefolder/FileFolderServiceImpl.java
index 332ea30736..0bc5abad58 100644
--- a/source/java/org/alfresco/repo/model/filefolder/FileFolderServiceImpl.java
+++ b/source/java/org/alfresco/repo/model/filefolder/FileFolderServiceImpl.java
@@ -544,6 +544,8 @@ public class FileFolderServiceImpl implements FileFolderService
newName = beforeFileInfo.getName();
}
+ boolean nameChanged = (newName.equals(beforeFileInfo.getName()) == false);
+
// we need the current association type
ChildAssociationRef assocRef = nodeService.getPrimaryParent(sourceNodeRef);
if (targetParentRef == null)
@@ -570,9 +572,21 @@ public class FileFolderServiceImpl implements FileFolderService
}
}
- QName qname = QName.createQName(
- NamespaceService.CONTENT_MODEL_1_0_URI,
- QName.createValidLocalName(newName));
+ QName qname;
+ if (nameChanged)
+ {
+ // Change the localname to match the new name
+ qname = QName.createQName(
+ assocRef.getQName().getNamespaceURI(),
+ QName.createValidLocalName(newName));
+ }
+ else
+ {
+ // Keep the localname
+ qname = QName.createQName(
+ assocRef.getQName().getNamespaceURI(),
+ assocRef.getQName().getLocalName());
+ }
QName targetParentType = nodeService.getType(targetParentRef);
diff --git a/source/java/org/alfresco/repo/model/ml/EditionServiceImpl.java b/source/java/org/alfresco/repo/model/ml/EditionServiceImpl.java
index f9e8e1a791..3f3dcf2c2e 100644
--- a/source/java/org/alfresco/repo/model/ml/EditionServiceImpl.java
+++ b/source/java/org/alfresco/repo/model/ml/EditionServiceImpl.java
@@ -46,6 +46,7 @@ import org.alfresco.service.cmr.model.FileNotFoundException;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
+import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.version.Version;
import org.alfresco.service.cmr.version.VersionHistory;
import org.alfresco.service.cmr.version.VersionService;
@@ -222,6 +223,11 @@ public class EditionServiceImpl implements EditionService
public Map getVersionedMetadatas(Version version)
{
NodeRef frozenNodeRef = version.getFrozenStateNodeRef();
+ if (frozenNodeRef.getStoreRef().getIdentifier().equals("lightWeightVersionStore"))
+ {
+ // The data stored belonged to the old version store
+ Map versionProps = version.getVersionProperties();
+ }
if(ContentModel.TYPE_MULTILINGUAL_CONTAINER.equals(nodeService.getType(frozenNodeRef)))
{
diff --git a/source/java/org/alfresco/repo/model/ml/MultilingualContentServiceImpl.java b/source/java/org/alfresco/repo/model/ml/MultilingualContentServiceImpl.java
index 6689558ec3..354c5cea38 100644
--- a/source/java/org/alfresco/repo/model/ml/MultilingualContentServiceImpl.java
+++ b/source/java/org/alfresco/repo/model/ml/MultilingualContentServiceImpl.java
@@ -51,6 +51,7 @@ import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.security.PermissionService;
+import org.alfresco.service.cmr.version.VersionService;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern;
@@ -89,6 +90,7 @@ public class MultilingualContentServiceImpl implements MultilingualContentServic
private PermissionService permissionService;
private ContentFilterLanguagesService contentFilterLanguagesService;
private FileFolderService fileFolderService;
+ private VersionService versionService;
private BehaviourFilter policyBehaviourFilter;
@@ -259,6 +261,11 @@ public class MultilingualContentServiceImpl implements MultilingualContentServic
private NodeRef makeTranslationImpl(NodeRef mlContainerNodeRef, NodeRef contentNodeRef, Locale locale)
{
+ // Previous versions of the document are not compatible with the versioning requirements
+ // dictated by the aspects about to be added. A version has to be forced if the aspect
+ // already exists.
+ // https://issues.alfresco.com/jira/browse/ETHREEOH-1657
+ boolean forceNewVersion = nodeService.hasAspect(contentNodeRef, ContentModel.ASPECT_VERSIONABLE);
// Add the aspect using the given locale, of necessary
if (!nodeService.hasAspect(contentNodeRef, ContentModel.ASPECT_MULTILINGUAL_DOCUMENT))
{
@@ -272,6 +279,11 @@ public class MultilingualContentServiceImpl implements MultilingualContentServic
// The aspect is present, so just ensure that the locale is correct
nodeService.setProperty(contentNodeRef, ContentModel.PROP_LOCALE, locale);
}
+
+ if (forceNewVersion)
+ {
+ versionService.createVersion(contentNodeRef, null);
+ }
// Do we make use of an existing container?
if (mlContainerNodeRef == null)
@@ -963,6 +975,11 @@ public class MultilingualContentServiceImpl implements MultilingualContentServic
this.fileFolderService = fileFolderService;
}
+ public void setVersionService(VersionService versionService)
+ {
+ this.versionService = versionService;
+ }
+
public void setPolicyBehaviourFilter(BehaviourFilter policyBehaviourFilter)
{
this.policyBehaviourFilter = policyBehaviourFilter;
diff --git a/source/java/org/alfresco/repo/version/BaseVersionStoreTest.java b/source/java/org/alfresco/repo/version/BaseVersionStoreTest.java
index ce59ebe6d8..501722b025 100644
--- a/source/java/org/alfresco/repo/version/BaseVersionStoreTest.java
+++ b/source/java/org/alfresco/repo/version/BaseVersionStoreTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005-2008 Alfresco Software Limited.
+ * Copyright (C) 2005-2009 Alfresco Software Limited.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -28,6 +28,7 @@ import java.io.InputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Date;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
@@ -122,7 +123,6 @@ public abstract class BaseVersionStoreTest extends BaseSpringTest
* Test user details
*/
private static final String PWD = "admin";
-// private static final String USER_NAME = "admin";
/**
* Sets the meta model dao
@@ -254,6 +254,11 @@ public abstract class BaseVersionStoreTest extends BaseSpringTest
ContentWriter contentWriter = this.contentService.getWriter(nodeRef, ContentModel.PROP_CONTENT, true);
contentWriter.putContent(TEST_CONTENT);
+ // Set author
+ Map authorProps = new HashMap(1, 1.0f);
+ authorProps.put(ContentModel.PROP_AUTHOR, "Charles Dickens");
+ this.dbNodeService.addAspect(nodeRef, ContentModel.ASPECT_AUTHOR, authorProps);
+
// Add some children to the node
NodeRef child1 = this.dbNodeService.createNode(
nodeRef,
@@ -323,8 +328,8 @@ public abstract class BaseVersionStoreTest extends BaseSpringTest
int nextVersion = peekNextVersionNumber();
String nextVersionLabel = peekNextVersionLabel(versionableNode, nextVersion, versionProperties);
- // Snap-shot the date-time
- long beforeVersionTime = System.currentTimeMillis();
+ // Snap-shot the node created date-time
+ long beforeVersionTime = ((Date)nodeService.getProperty(versionableNode, ContentModel.PROP_CREATED)).getTime();
// Now lets create a new version for this node
Version newVersion = versionService.createVersion(versionableNode, this.versionProperties);
@@ -340,8 +345,8 @@ public abstract class BaseVersionStoreTest extends BaseSpringTest
int nextVersion = peekNextVersionNumber();
String nextVersionLabel = peekNextVersionLabel(versionableNode, nextVersion, versionProperties);
- // Snap-shot the date-time
- long beforeVersionTime = System.currentTimeMillis();
+ // Snap-shot the node created date-time
+ long beforeVersionTime = ((Date)nodeService.getProperty(versionableNode, ContentModel.PROP_CREATED)).getTime();
// Now lets create new version for this node (optionally with children)
Collection versions = versionService.createVersion(versionableNode, this.versionProperties, versionChildren);
diff --git a/source/java/org/alfresco/repo/version/Version2ServiceImpl.java b/source/java/org/alfresco/repo/version/Version2ServiceImpl.java
index cc948cc05d..f8c96ba01b 100644
--- a/source/java/org/alfresco/repo/version/Version2ServiceImpl.java
+++ b/source/java/org/alfresco/repo/version/Version2ServiceImpl.java
@@ -110,9 +110,6 @@ public class Version2ServiceImpl extends VersionServiceImpl implements VersionSe
return new StoreRef(StoreRef.PROTOCOL_WORKSPACE, Version2Model.STORE_ID);
}
- /* (non-Javadoc)
- * @see org.alfresco.repo.service.cmr.version.VersionService#createVersion(org.alfresco.service.cmr.repository.NodeRef, java.util.Map)
- */
public Version createVersion(
NodeRef nodeRef,
Map versionProperties)
@@ -343,14 +340,11 @@ public class Version2ServiceImpl extends VersionServiceImpl implements VersionSe
VersionHistory versionHistory = null;
- // get version history, if the 'live' (versioned) node exists
- if (this.nodeService.exists(nodeRef) == true)
+ // Get the version history regardless of whether the node is still 'live' or not
+ NodeRef versionHistoryRef = getVersionHistoryNodeRef(nodeRef);
+ if (versionHistoryRef != null)
{
- NodeRef versionHistoryRef = getVersionHistoryNodeRef(nodeRef);
- if (versionHistoryRef != null)
- {
- versionHistory = buildVersionHistory(versionHistoryRef, nodeRef);
- }
+ versionHistory = buildVersionHistory(versionHistoryRef, nodeRef);
}
return versionHistory;
diff --git a/source/java/org/alfresco/repo/version/VersionMigratorTest.java b/source/java/org/alfresco/repo/version/VersionMigratorTest.java
index 51d9d210bf..484b6200de 100644
--- a/source/java/org/alfresco/repo/version/VersionMigratorTest.java
+++ b/source/java/org/alfresco/repo/version/VersionMigratorTest.java
@@ -111,8 +111,8 @@ public class VersionMigratorTest extends BaseVersionStoreTest
int nextVersion = peekNextVersionNumber();
String nextVersionLabel = peekNextVersionLabel(versionableNode, nextVersion, versionProperties);
- // Snap-shot the date-time
- Date beforeVersionDate = new Date();
+ // Snap-shot the node created date-time
+ Date beforeVersionDate = (Date)nodeService.getProperty(versionableNode, ContentModel.PROP_CREATED);
long beforeVersionTime = beforeVersionDate.getTime();
logger.info("beforeVersion Date/Time: " + beforeVersionDate + " [" + beforeVersionTime + "]");
@@ -205,7 +205,9 @@ public class VersionMigratorTest extends BaseVersionStoreTest
// Get the next version number, next version label and snapshot the date-time
int nextVersion1 = peekNextVersionNumber();
String nextVersionLabel1 = peekNextVersionLabel(versionableNode, nextVersion1, versionProperties);
- long beforeVersionTime1 = System.currentTimeMillis();
+
+ // Snap-shot the node created date-time
+ long beforeVersionTime1 = ((Date)nodeService.getProperty(versionableNode, ContentModel.PROP_CREATED)).getTime();
Version version1 = createVersion(versionableNode);
logger.info(version1);
@@ -213,7 +215,9 @@ public class VersionMigratorTest extends BaseVersionStoreTest
// Get the next version number, next version label and snapshot the date-time
int nextVersion2 = peekNextVersionNumber();
String nextVersionLabel2 = peekNextVersionLabel(versionableNode, nextVersion2, versionProperties);
- long beforeVersionTime2 = System.currentTimeMillis();
+
+ // Snap-shot the node created date-time
+ long beforeVersionTime2 = ((Date)nodeService.getProperty(versionableNode, ContentModel.PROP_CREATED)).getTime();
Version version2 = createVersion(versionableNode);
logger.info(version2);
@@ -221,7 +225,9 @@ public class VersionMigratorTest extends BaseVersionStoreTest
// Get the next version number, next version label and snapshot the date-time
int nextVersion3 = peekNextVersionNumber();
String nextVersionLabel3 = peekNextVersionLabel(versionableNode, nextVersion3, versionProperties);
- long beforeVersionTime3 = System.currentTimeMillis();
+
+ // Snap-shot the node created date-time
+ long beforeVersionTime3 = ((Date)nodeService.getProperty(versionableNode, ContentModel.PROP_CREATED)).getTime();
Version version3 = createVersion(versionableNode);
logger.info(version3);
diff --git a/source/java/org/alfresco/repo/version/VersionServiceImplTest.java b/source/java/org/alfresco/repo/version/VersionServiceImplTest.java
index bf375eda54..f4979a964a 100644
--- a/source/java/org/alfresco/repo/version/VersionServiceImplTest.java
+++ b/source/java/org/alfresco/repo/version/VersionServiceImplTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005-2008 Alfresco Software Limited.
+ * Copyright (C) 2005-2009 Alfresco Software Limited.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -27,6 +27,7 @@ package org.alfresco.repo.version;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
@@ -144,7 +145,9 @@ public class VersionServiceImplTest extends BaseVersionStoreTest
// Snap shot data
int expectedVersionNumber = peekNextVersionNumber();
String expectedVersionLabel = peekNextVersionLabel(versionableNode, expectedVersionNumber, versionProperties);
- long beforeVersionTime = System.currentTimeMillis();
+
+ // Snap-shot the node created date-time
+ long beforeVersionTime = ((Date)nodeService.getProperty(versionableNode, ContentModel.PROP_CREATED)).getTime();
// Version the node and its children
Collection versions = this.versionService.createVersion(
@@ -167,8 +170,10 @@ public class VersionServiceImplTest extends BaseVersionStoreTest
// Snap shot data
int expectedVersionNumber = peekNextVersionNumber();
- String expectedVersionLabel = peekNextVersionLabel(versionableNode, expectedVersionNumber, versionProperties);
- long beforeVersionTime = System.currentTimeMillis();
+ String expectedVersionLabel = peekNextVersionLabel(versionableNode, expectedVersionNumber, versionProperties);
+
+ // Snap-shot the node created date-time
+ long beforeVersionTime = ((Date)nodeService.getProperty(versionableNode, ContentModel.PROP_CREATED)).getTime();
// Version the list of nodes created
Collection versions = this.versionService.createVersion(
diff --git a/source/java/org/alfresco/repo/version/common/VersionHistoryImpl.java b/source/java/org/alfresco/repo/version/common/VersionHistoryImpl.java
index 8158e1bd9c..3a0ccf1e60 100644
--- a/source/java/org/alfresco/repo/version/common/VersionHistoryImpl.java
+++ b/source/java/org/alfresco/repo/version/common/VersionHistoryImpl.java
@@ -24,7 +24,10 @@
*/
package org.alfresco.repo.version.common;
+import java.io.IOException;
+import java.io.ObjectInputStream;
import java.io.Serializable;
+import java.io.ObjectInputStream.GetField;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -45,9 +48,6 @@ import org.alfresco.util.VersionNumber;
*/
public class VersionHistoryImpl implements VersionHistory
{
- /*
- * Serial version UID
- */
private static final long serialVersionUID = 3257001051558326840L;
/*
@@ -56,9 +56,10 @@ public class VersionHistoryImpl implements VersionHistory
private static final String ERR_MSG = "The root version must be specified when creating a version history object.";
/*
- * The root version label
+ * Field is left here to aid in detection of old serialized versions
*/
- private String rootVersionLabel = null;
+ @SuppressWarnings("unused")
+ private transient List versions;
/*
* Version history tree structure map
@@ -74,7 +75,6 @@ public class VersionHistoryImpl implements VersionHistory
* Versions ordered by creation date (descending)
*/
private static Comparator versionComparatorDesc = new VersionComparatorDesc();
- private List versions = new ArrayList();
/**
* Root version
@@ -101,7 +101,6 @@ public class VersionHistoryImpl implements VersionHistory
this.versionsByLabel = new HashMap();
this.rootVersion = rootVersion;
- this.rootVersionLabel = rootVersion.getVersionLabel();
addVersion(rootVersion, null);
}
@@ -125,8 +124,10 @@ public class VersionHistoryImpl implements VersionHistory
*/
public Collection getAllVersions()
{
- Collections.sort(versions, versionComparatorDesc);
- return versions;
+ Collection versions = versionsByLabel.values();
+ List sortedVersions = new ArrayList(versions);
+ Collections.sort(sortedVersions, versionComparatorDesc);
+ return sortedVersions;
}
/**
@@ -211,7 +212,6 @@ public class VersionHistoryImpl implements VersionHistory
// TODO cope with exception case where duplicate version labels have been specified
this.versionsByLabel.put(version.getVersionLabel(), version);
- this.versions.add(version);
if (predecessor != null)
{
@@ -222,7 +222,7 @@ public class VersionHistoryImpl implements VersionHistory
/**
* Version Comparator
*
- * Note: Descending create date order
+ * Note: Descending (last modified) date order
*/
public static class VersionComparatorDesc implements Comparator, Serializable
{
@@ -230,7 +230,7 @@ public class VersionHistoryImpl implements VersionHistory
public int compare(Version v1, Version v2)
{
- int result = v2.getCreatedDate().compareTo(v1.getCreatedDate());
+ int result = v2.getFrozenModifiedDate().compareTo(v1.getFrozenModifiedDate());
if (result == 0)
{
result = new VersionNumber(v2.getVersionLabel()).compareTo(new VersionNumber(v1.getVersionLabel()));
@@ -242,7 +242,7 @@ public class VersionHistoryImpl implements VersionHistory
/**
* Version Comparator
*
- * Note: Ascending create date order
+ * Note: Ascending (last modified) date order
*/
public static class VersionComparatorAsc implements Comparator, Serializable
{
@@ -250,7 +250,7 @@ public class VersionHistoryImpl implements VersionHistory
public int compare(Version v1, Version v2)
{
- int result = v1.getCreatedDate().compareTo(v2.getCreatedDate());
+ int result = v1.getFrozenModifiedDate().compareTo(v2.getFrozenModifiedDate());
if (result == 0)
{
result = new VersionNumber(v1.getVersionLabel()).compareTo(new VersionNumber(v2.getVersionLabel()));
@@ -259,4 +259,29 @@ public class VersionHistoryImpl implements VersionHistory
}
}
+ @SuppressWarnings("unchecked")
+ private void readObject(ObjectInputStream is) throws ClassNotFoundException, IOException
+ {
+ GetField fields = is.readFields();
+ if (fields.defaulted("versionsByLabel"))
+ {
+ // This is a V2.2 class
+ // The old 'rootVersion' maps to the current 'rootVersion'
+ this.rootVersion = (Version) fields.get("rootVersion", null);;
+ // The old 'versions' maps to the current 'versionsByLabel'
+ this.versionsByLabel = (HashMap) fields.get("versions", new HashMap());
+ // The old 'versionHistory' maps to the current 'versionHistory'
+ this.versionHistory = (HashMap) fields.get("versionHistory", new HashMap());
+ }
+ else
+ {
+ // This is a V3.1.0 to ... class
+ // The old 'rootVersion' maps to the current 'rootVersion'
+ this.rootVersion = (Version) fields.get("rootVersion", null);
+ // The old 'versionsByLabel' maps to the current 'versionsByLabel'
+ this.versionsByLabel = (HashMap) fields.get("versionsByLabel", new HashMap());
+ // The old 'versionHistory' maps to the current 'versionHistory'
+ this.versionHistory = (HashMap) fields.get("versionHistory", new HashMap());
+ }
+ }
}
diff --git a/source/java/org/alfresco/repo/version/common/VersionHistoryImplTest.java b/source/java/org/alfresco/repo/version/common/VersionHistoryImplTest.java
index ba5941f294..1f93b9b05d 100644
--- a/source/java/org/alfresco/repo/version/common/VersionHistoryImplTest.java
+++ b/source/java/org/alfresco/repo/version/common/VersionHistoryImplTest.java
@@ -24,6 +24,11 @@
*/
package org.alfresco.repo.version.common;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Collection;
import java.util.Date;
@@ -37,6 +42,9 @@ import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.version.Version;
import org.alfresco.service.cmr.version.VersionDoesNotExistException;
import org.alfresco.service.cmr.version.VersionServiceException;
+import org.alfresco.util.TempFileProvider;
+import org.springframework.core.io.DefaultResourceLoader;
+import org.springframework.core.io.Resource;
/**
* VersionHistoryImpl Unit Test Class
@@ -208,6 +216,7 @@ public class VersionHistoryImplTest extends TestCase
/**
* Test getSuccessors
*/
+ @SuppressWarnings("unchecked")
public void testGetSuccessors()
{
VersionHistoryImpl vh = testAddVersionImpl();
@@ -260,4 +269,75 @@ public class VersionHistoryImplTest extends TestCase
System.out.println("Error message: " + exception.getMessage());
}
}
+
+ /**
+ * Checks that the current version can be serialized and deserialized.
+ */
+ public void testSerialize() throws Exception
+ {
+ File file = TempFileProvider.createTempFile(getName(), ".bin");
+ System.out.println("Test " + getName() + " writing to " + file.getPath());
+ ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream(file));
+
+ VersionHistoryImpl vh = testAddVersionImpl();
+ try
+ {
+ os.writeObject(vh);
+ }
+ finally
+ {
+ try { os.close(); } catch (Throwable e) {}
+ }
+ ObjectInputStream is = new ObjectInputStream(new FileInputStream(file));
+ VersionHistoryImpl vhObj;
+ try
+ {
+ vhObj = (VersionHistoryImpl) is.readObject();
+ }
+ finally
+ {
+ try { is.close(); } catch (Throwable e) {}
+ }
+ assertNotNull(vhObj);
+ assertNotNull("No root version", vhObj.getRootVersion());
+ assertEquals(
+ "Deserialized object does not match original",
+ vh.getRootVersion().getFrozenStateNodeRef(),
+ vhObj.getRootVersion().getFrozenStateNodeRef());
+ }
+
+ public static final String DESERIALIZE_V22SP4 = "classpath:version-history/VersionHistoryImplTest-testSerialize-V2.2.4.bin";
+ public static final String DESERIALIZE_V310_DEV = "classpath:version-history/VersionHistoryImplTest-testSerialize-V3.1.0-dev.bin";
+ public static final String DESERIALIZE_V310 = "classpath:version-history/VersionHistoryImplTest-testSerialize-V3.1.0.bin";
+ /**
+ * @see {@link #DESERIALIZE_V22SP4}
+ * @see {@link #DESERIALIZE_V310_DEV}
+ * @see {@link #DESERIALIZE_V310}
+ */
+ public void testDeserializeV22SP4() throws Exception
+ {
+ String[] resourceLocations = new String[] {
+ DESERIALIZE_V22SP4,
+ DESERIALIZE_V310_DEV,
+ DESERIALIZE_V310
+ };
+ for (String resourceLocation : resourceLocations)
+ {
+ Resource resource = new DefaultResourceLoader().getResource(resourceLocation);
+ assertNotNull("Unable to find " + resourceLocation, resource);
+ assertTrue("Unable to find " + resourceLocation, resource.exists());
+
+ @SuppressWarnings("unused")
+ VersionHistoryImpl vhObj;
+ ObjectInputStream is = new ObjectInputStream(resource.getInputStream());
+ try
+ {
+ vhObj = (VersionHistoryImpl) is.readObject();
+ }
+ finally
+ {
+ try { is.close(); } catch (Throwable e) {}
+ }
+ }
+ }
}
diff --git a/source/java/org/alfresco/repo/version/common/VersionImpl.java b/source/java/org/alfresco/repo/version/common/VersionImpl.java
index f63fd8e59d..981eafbfa9 100644
--- a/source/java/org/alfresco/repo/version/common/VersionImpl.java
+++ b/source/java/org/alfresco/repo/version/common/VersionImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005-2008 Alfresco Software Limited.
+ * Copyright (C) 2005-2009 Alfresco Software Limited.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -96,69 +96,61 @@ public class VersionImpl implements Version
{
return versionProperties.toString();
}
-
-
- /**
- * Helper method to get the created date from the version property data.
- *
- * @return the date the version was created (note: not the date of the original node)
- */
+
+ public Date getFrozenModifiedDate()
+ {
+ Date modifiedDate = (Date)this.versionProperties.get(Version2Model.PROP_FROZEN_MODIFIED);
+ if (modifiedDate == null)
+ {
+ // Assume deprecated V1 version store
+ modifiedDate = (Date)this.versionProperties.get(VersionBaseModel.PROP_CREATED_DATE);
+ }
+ return modifiedDate;
+ }
+
+ public String getFrozenModifier()
+ {
+ String modifier = (String)this.versionProperties.get(Version2Model.PROP_FROZEN_MODIFIER);
+ if (modifier == null)
+ {
+ // Assume deprecated V1 version store
+ modifier = (String)this.versionProperties.get(VersionBaseModel.PROP_CREATOR);
+ }
+ return modifier;
+ }
+
public Date getCreatedDate()
{
- return (Date)this.versionProperties.get(VersionBaseModel.PROP_CREATED_DATE);
+ // note: internal version node created date can be retrieved via standard node service
+ return getFrozenModifiedDate();
}
- /**
- * Helper method to get the creator from the version property data.
- *
- * @return the creator of the version (note: not the creator of the original node)
- */
public String getCreator()
{
- return (String)this.versionProperties.get(VersionBaseModel.PROP_CREATOR);
+ // note: internal version node creator can be retrieved via standard node service
+ return getFrozenModifier();
}
-
- /**
- * Helper method to get the version label from the version property data.
- *
- * @return the version label
- */
+
public String getVersionLabel()
{
return (String)this.versionProperties.get(VersionBaseModel.PROP_VERSION_LABEL);
}
- /**
- * Helper method to get the version type.
- *
- * @return the value of the version type as an enum value
- */
public VersionType getVersionType()
{
return (VersionType)this.versionProperties.get(VersionBaseModel.PROP_VERSION_TYPE);
}
- /**
- * Helper method to get the version description.
- *
- * @return the version description
- */
public String getDescription()
{
return (String)this.versionProperties.get(Version.PROP_DESCRIPTION);
}
- /**
- * @see org.alfresco.service.cmr.version.Version#getVersionProperties()
- */
public Map getVersionProperties()
{
return this.versionProperties;
}
-
- /**
- * @see org.alfresco.service.cmr.version.Version#getVersionProperty(java.lang.String)
- */
+
public Serializable getVersionProperty(String name)
{
Serializable result = null;
@@ -169,9 +161,6 @@ public class VersionImpl implements Version
return result;
}
- /**
- * @see org.alfresco.service.cmr.version.Version#getVersionedNodeRef()
- */
public NodeRef getVersionedNodeRef()
{
NodeRef versionedNodeRef = null;
@@ -193,10 +182,7 @@ public class VersionImpl implements Version
return versionedNodeRef;
}
-
- /**
- * @see org.alfresco.service.cmr.version.Version#getFrozenStateNodeRef()
- */
+
public NodeRef getFrozenStateNodeRef()
{
return this.nodeRef;
diff --git a/source/java/org/alfresco/service/cmr/version/Version.java b/source/java/org/alfresco/service/cmr/version/Version.java
index 2415ec4d72..e8cf4e5395 100644
--- a/source/java/org/alfresco/service/cmr/version/Version.java
+++ b/source/java/org/alfresco/service/cmr/version/Version.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005-2007 Alfresco Software Limited.
+ * Copyright (C) 2005-2009 Alfresco Software Limited.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -38,7 +38,7 @@ import org.alfresco.service.cmr.repository.NodeRef;
* Allows access to version property values and frozen state node references.
* The version history tree can also be navigated.
*
- * @author Roy Wetherall
+ * @author Roy Wetherall, janv
*/
public interface Version extends Serializable
{
@@ -51,6 +51,7 @@ public interface Version extends Serializable
* Helper method to get the created date from the version property data.
*
* @return the date the version was created
+ * @deprecated use getFrozenModifiedDate
*/
public Date getCreatedDate();
@@ -58,8 +59,24 @@ public interface Version extends Serializable
* Helper method to get the creator of the version.
*
* @return the creator of the version
+ * @deprecated use getFrozenModifier
*/
public String getCreator();
+
+ /**
+ * Helper method to get the frozen (original) modified date for this version of the node
+ *
+ * @return the modified date
+ */
+ public Date getFrozenModifiedDate();
+
+
+ /**
+ * Helper method to get the frozen (original) modifier for this version of the node
+ *
+ * @return the modifier
+ */
+ public String getFrozenModifier();
/**
* Helper method to get the version label from the version property data.
diff --git a/source/java/org/alfresco/service/cmr/version/VersionService.java b/source/java/org/alfresco/service/cmr/version/VersionService.java
index 712a74712c..5f366b79bf 100644
--- a/source/java/org/alfresco/service/cmr/version/VersionService.java
+++ b/source/java/org/alfresco/service/cmr/version/VersionService.java
@@ -70,7 +70,7 @@ public interface VersionService
*
* @param nodeRef a node reference
* @param versionProperties the version properties that are stored with the newly created
- * version
+ * version, or null if there are no relevant properties
* @return the created version object
* @throws ReservedVersionNameException
* thrown if a reserved property name is used int he version properties
diff --git a/source/java/org/alfresco/util/schemadump/Main.java b/source/java/org/alfresco/util/schemadump/Main.java
index 2a263c06ea..48cc0d8e0d 100644
--- a/source/java/org/alfresco/util/schemadump/Main.java
+++ b/source/java/org/alfresco/util/schemadump/Main.java
@@ -24,13 +24,12 @@
*/
package org.alfresco.util.schemadump;
-import java.io.IOException;
+import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
-import java.sql.SQLException;
import java.sql.Types;
import java.util.ArrayList;
import java.util.Collections;
@@ -72,32 +71,35 @@ public class Main
private final Map reverseTypeMap = new TreeMap();
/** Should we scale down string field widths (assuming 4 bytes to one character?). */
- private final boolean scaleCharacters;
+ private boolean scaleCharacters;
/** The JDBC connection. */
- private final Connection con;
+ private Connection con;
/**
- * Creates a new instance of this tool..
+ * The main method.
*
- * @param contextPath
- * path to the context xml file
- * @throws SQLException
- * the SQL exception
- * @throws IOException
- * Signals that an I/O exception has occurred.
- * @throws InstantiationException
- * the instantiation exception
- * @throws IllegalAccessException
- * the illegal access exception
- * @throws ClassNotFoundException
- * the class not found exception
- * @throws NoSuchFieldException
- * the no such field exception
+ * @param args
+ * the args: <context.xml> <output.xml>
+ */
+ public static void main(final String[] args) throws Exception
+ {
+ if (args.length != 2)
+ {
+ System.out.println("Usage:");
+ System.out.println("java " + Main.class.getName() + " ");
+ System.exit(1);
+ }
+
+ final File outputFile = new File(args[1]);
+ new Main(args[0]).execute(outputFile);
+ }
+
+ /**
+ * Creates a new instance of this tool by starting up a full context.
*/
@SuppressWarnings("unchecked")
- public Main(final String contextPath) throws SQLException, IOException, InstantiationException, IllegalAccessException,
- ClassNotFoundException, NoSuchFieldException
+ public Main(final String contextPath) throws Exception
{
final ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]
{
@@ -109,6 +111,32 @@ public class Main
// Use Java reflection to bypass accessibility rules and get hold of hibernate's type mapping!
final Properties hibProps = (Properties) context.getBean("hibernateConfigProperties");
final Dialect dialect = (Dialect) Class.forName(hibProps.getProperty("hibernate.dialect")).newInstance();
+
+ // Initialize
+ init(dialect);
+ }
+
+ /**
+ * Create a new instance of the tool within the context of an existing database connection
+ *
+ * @param connection the database connection to use for metadata queries
+ * @param dialect the Hibernate dialect
+ */
+ public Main(final Connection connection, final Dialect dialect) throws Exception
+ {
+ this.con = connection;
+
+ // Initialize
+ init(dialect);
+ }
+
+ /**
+ * Initializes the fields ready to perform the database metadata reading
+ * @param dialect the Hibernate dialect
+ */
+ @SuppressWarnings("unchecked")
+ private void init(final Dialect dialect) throws Exception
+ {
this.scaleCharacters = dialect instanceof Oracle8iDialect;
final Field typeNamesField = Dialect.class.getDeclaredField("typeNames");
typeNamesField.setAccessible(true);
@@ -135,22 +163,13 @@ public class Main
}
/**
- * The main method.
+ * Execute, writing the result to the given file.
*
- * @param args
- * the args
- * @throws Exception
- * the exception
+ * @param outputFile the file to write to
*/
- public static void main(final String[] args) throws Exception
+ public void execute(File outputFile) throws Exception
{
- if (args.length != 2)
- {
- System.out.println("Usage:");
- System.out.println("java " + Main.class.getName() + " ");
- System.exit(1);
- }
- final NamedElementCollection result = new Main(args[0]).execute();
+ final NamedElementCollection result = execute();
// Set up a SAX TransformerHandler for outputting XML
final SAXTransformerFactory stf = (SAXTransformerFactory) TransformerFactory.newInstance();
@@ -165,7 +184,7 @@ public class Main
// It was worth a try
}
t.setOutputProperty(OutputKeys.INDENT, "yes");
- xmlOut.setResult(new StreamResult(args[1]));
+ xmlOut.setResult(new StreamResult(outputFile));
xmlOut.startDocument();
result.output(xmlOut);
@@ -175,28 +194,10 @@ public class Main
/**
* Execute.
*
- * @return the named element collection
- * @throws SQLException
- * the SQL exception
- * @throws IllegalArgumentException
- * the illegal argument exception
- * @throws IllegalAccessException
- * the illegal access exception
- * @throws IOException
- * Signals that an I/O exception has occurred.
- * @throws InstantiationException
- * the instantiation exception
- * @throws ClassNotFoundException
- * the class not found exception
- * @throws SecurityException
- * the security exception
- * @throws NoSuchFieldException
- * the no such field exception
+ * @return Returns the named XML elements
*/
- public NamedElementCollection execute() throws SQLException, IllegalArgumentException, IllegalAccessException,
- IOException, InstantiationException, ClassNotFoundException, SecurityException, NoSuchFieldException
+ public NamedElementCollection execute() throws Exception
{
-
final NamedElementCollection schemaCol = new NamedElementCollection("schema", "table");
final DatabaseMetaData dbmd = this.con.getMetaData();
diff --git a/source/test-resources/version-history/VersionHistoryImplTest-testSerialize-V2.2.4.bin b/source/test-resources/version-history/VersionHistoryImplTest-testSerialize-V2.2.4.bin
new file mode 100644
index 0000000000..ca1baecbfe
Binary files /dev/null and b/source/test-resources/version-history/VersionHistoryImplTest-testSerialize-V2.2.4.bin differ
diff --git a/source/test-resources/version-history/VersionHistoryImplTest-testSerialize-V3.1.0-dev.bin b/source/test-resources/version-history/VersionHistoryImplTest-testSerialize-V3.1.0-dev.bin
new file mode 100644
index 0000000000..b579111c1b
Binary files /dev/null and b/source/test-resources/version-history/VersionHistoryImplTest-testSerialize-V3.1.0-dev.bin differ
diff --git a/source/test-resources/version-history/VersionHistoryImplTest-testSerialize-V3.1.0.bin b/source/test-resources/version-history/VersionHistoryImplTest-testSerialize-V3.1.0.bin
new file mode 100644
index 0000000000..6b2328d4f9
Binary files /dev/null and b/source/test-resources/version-history/VersionHistoryImplTest-testSerialize-V3.1.0.bin differ