VS2 - version store refactor (merged from DEV/VS2 to HEAD)

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@10574 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Jan Vonka
2008-08-29 11:01:41 +00:00
parent 1aa02f5d17
commit 179093d240
38 changed files with 3813 additions and 459 deletions

View File

@@ -191,6 +191,17 @@
</property> </property>
</bean> </bean>
<bean id="version2Bootstrap" parent="version2StoreImporter" singleton="false">
<property name="bootstrapViews">
<list>
<props>
<prop key="path">/</prop>
<prop key="location">alfresco/bootstrap/version2Store.xml</prop>
</props>
</list>
</property>
</bean>
<bean id="spacesArchiveBootstrap" parent="spacesArchiveStoreImporter" singleton="false"> <bean id="spacesArchiveBootstrap" parent="spacesArchiveStoreImporter" singleton="false">
<property name="bootstrapViews"> <property name="bootstrapViews">
<list> <list>

View File

@@ -0,0 +1,15 @@
<view:view xmlns:view="http://www.alfresco.org/view/repository/1.0"
xmlns:ver2="http://www.alfresco.org/model/versionstore/2.0">
<view:reference view:pathref="/">
<!-- Apply All access to Everyone on root node of version2 store -->
<view:acl>
<view:ace view:access="ALLOWED">
<view:authority>GROUP_EVERYONE</view:authority>
<view:permission>All</view:permission>
</view:ace>
</view:acl>
<ver2:versionStoreRoot/>
</view:reference>
</view:view>

View File

@@ -649,7 +649,7 @@
<!-- --> <!-- -->
<bean id="versionService" class="org.alfresco.repo.version.VersionServiceImpl" init-method="initialise"> <bean id="versionService" class="org.alfresco.repo.version.Version2ServiceImpl" init-method="initialise">
<property name="nodeService"> <property name="nodeService">
<ref bean="NodeService" /> <ref bean="NodeService" />
</property> </property>
@@ -671,9 +671,15 @@
<property name="policyBehaviourFilter"> <property name="policyBehaviourFilter">
<ref bean="policyBehaviourFilter" /> <ref bean="policyBehaviourFilter" />
</property> </property>
<property name="permissionService">
<ref bean="permissionService" />
</property>
<property name="onlyUseDeprecatedV1">
<value>${version.store.onlyUseDeprecatedV1}</value>
</property>
</bean> </bean>
<bean id="versionNodeService" class="org.alfresco.repo.version.NodeServiceImpl"> <bean id="versionNodeService" class="org.alfresco.repo.version.Node2ServiceImpl">
<property name="dbNodeService"> <property name="dbNodeService">
<ref bean="dbNodeService" /> <ref bean="dbNodeService" />
</property> </property>
@@ -682,6 +688,27 @@
</property> </property>
</bean> </bean>
<bean id="versionMigrator" class="org.alfresco.repo.version.VersionMigrator" init-method="init">
<property name="dbNodeService">
<ref bean="dbNodeService" />
</property>
<property name="versionNodeService">
<ref bean="versionNodeService" />
</property>
<property name="version2ServiceImpl">
<ref bean="versionService" />
</property>
<property name="policyBehaviourFilter">
<ref bean="policyBehaviourFilter" />
</property>
<property name="dictionaryService">
<ref bean="dictionaryService" />
</property>
<property name="transactionService">
<ref bean="transactionService"/>
</property>
</bean>
<bean id="versionCounterService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> <bean id="versionCounterService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="proxyInterfaces"> <property name="proxyInterfaces">
<value>org.alfresco.repo.version.common.counter.VersionCounterService</value> <value>org.alfresco.repo.version.common.counter.VersionCounterService</value>
@@ -798,7 +825,10 @@
<!-- Implementation models --> <!-- Implementation models -->
<value>org/alfresco/repo/action/actionModel.xml</value> <value>org/alfresco/repo/action/actionModel.xml</value>
<value>org/alfresco/repo/rule/ruleModel.xml</value> <value>org/alfresco/repo/rule/ruleModel.xml</value>
<value>org/alfresco/repo/version/version_model.xml</value>
<!-- Version models -->
<value>org/alfresco/repo/version/version_model.xml</value> <!-- deprecated -->
<value>org/alfresco/repo/version/version2_model.xml</value>
<!-- Email model --> <!-- Email model -->
<value>alfresco/model/emailServerModel.xml</value> <value>alfresco/model/emailServerModel.xml</value>

View File

@@ -165,7 +165,7 @@
<prop key="packageName">spaces_archive</prop> <prop key="packageName">spaces_archive</prop>
</props> </props>
<props> <props>
<prop key="storeRef">workspace://lightWeightVersionStore</prop> <prop key="storeRef">${version.store.version2Store}</prop>
<prop key="packageName">versions</prop> <prop key="packageName">versions</prop>
</props> </props>
</list> </list>
@@ -331,7 +331,13 @@
<bean id="versionStoreImporter" parent="storeImporter" abstract="true"> <bean id="versionStoreImporter" parent="storeImporter" abstract="true">
<property name="storeUrl"> <property name="storeUrl">
<value>workspace://lightWeightVersionStore</value> <value>${version.store.deprecated.lightWeightVersionStore}</value>
</property>
</bean>
<bean id="version2StoreImporter" parent="storeImporter" abstract="true">
<property name="storeUrl">
<value>${version.store.version2Store}</value>
</property> </property>
</bean> </bean>

View File

@@ -223,3 +223,6 @@ patch.createSiteStore.result=Created the AVM site data store.
patch.sitePermissionRefactorPatch.description=Create permission groups for sites. patch.sitePermissionRefactorPatch.description=Create permission groups for sites.
patch.sitePermissionRefactorPatch.result=Groups have been created for all sites and user's allocated accordingly. patch.sitePermissionRefactorPatch.result=Groups have been created for all sites and user's allocated accordingly.
patch.migrateVersionStore.description=Migrate from lightWeightVersionStore to version2Store
patch.migrateVersionStore.result=Migrated version store. Created {0} version histories

View File

@@ -1,4 +1,4 @@
# Rule service externalised display strings # Version service externalised display strings
version_service.err_restore_exists=The node {0} cannot be restored since it already exists. version_service.err_restore_exists=The node {0} cannot be restored since it already exists.
version_service.err_not_found=The current version label of the node does not exist in the version history. version_service.err_not_found=The current version label of the node does not exist in the version history.
@@ -6,3 +6,14 @@ version_service.err_unsupported=The current implementation of the version servic
version_service.err_one_preceeding=The current implementation of the version service only supports one preceeding version. version_service.err_one_preceeding=The current implementation of the version service only supports one preceeding version.
version_service.err_restore_no_version=The node {0} cannot be restore since there is no version information available for this node. version_service.err_restore_no_version=The node {0} cannot be restore since there is no version information available for this node.
version_service.err_revert_mismatch=The version provided to revert to does not come from the nodes version history. version_service.err_revert_mismatch=The version provided to revert to does not come from the nodes version history.
version_service.migration.patch.noop=Nothing to do (no version histories found in old version store)
version_service.migration.patch.complete=Completed migration of {0} version histories (to new version store) in {1} secs
version_service.migration.patch.warn.skip1=Skipped migration of {0} version histories (migrate failed)
version_service.migration.patch.warn.skip2=Skipped migration of {0} version histories (already migrated)
version_service.migration.delete.progress=\t\tBackground deletion of migrated version histories (from old version store) {0}% complete, estimated complete at {1}
version_service.migration.delete.complete=Completed deletion of {0} migrated version histories (from old version store) in {1} secs
version_service.migration.delete.warn.skip1=Skipped deletion of {0} version histories (delete failed)
version_service.migration.delete.warn.skip2=Skipped deletion of {0} version histories (not migrated)

View File

@@ -129,6 +129,11 @@
<property name="maxErrorsPerTransaction" > <property name="maxErrorsPerTransaction" >
<value>5</value> <!-- limit output (exception and log) to the first N violation messages --> <value>5</value> <!-- limit output (exception and log) to the first N violation messages -->
</property> </property>
<property name="storesToIgnore">
<list>
<value>${version.store.version2Store}</value>
</list>
</property>
</bean> </bean>
<!-- tags nodes that are incomplete w.r.t. properties--> <!-- tags nodes that are incomplete w.r.t. properties-->
@@ -142,6 +147,11 @@
<property name="nodeService"> <property name="nodeService">
<ref bean="nodeService" /> <ref bean="nodeService" />
</property> </property>
<property name="storesToIgnore">
<list>
<value>${version.store.version2Store}</value>
</list>
</property>
</bean> </bean>
<!-- NodeService implemented to persist to Database. Resource management enabled. --> <!-- NodeService implemented to persist to Database. Resource management enabled. -->

View File

@@ -1488,4 +1488,16 @@
</property> </property>
</bean> </bean>
<bean id="patch.migrateVersionStore" class="org.alfresco.repo.admin.patch.impl.MigrateVersionStorePatch" parent="basePatch" >
<property name="id"><value>patch.migrateVersionStore</value></property>
<property name="description"><value>patch.migrateVersionStore.description</value></property>
<property name="fixesFromSchema"><value>0</value></property>
<property name="fixesToSchema"><value>129</value></property>
<property name="targetSchema"><value>130</value></property>
<!-- helper beans/properties -->
<property name="versionMigrator">
<ref bean="versionMigrator" />
</property>
</bean>
</beans> </beans>

View File

@@ -185,6 +185,12 @@ spaces.content_forms.childname=app:forms
spaces.user_homes.childname=app:user_homes spaces.user_homes.childname=app:user_homes
spaces.sites.childname=st:sites spaces.sites.childname=st:sites
# ADM VersionStore Configuration
version.store.deprecated.lightWeightVersionStore=workspace://lightWeightVersionStore
version.store.version2Store=workspace://version2Store
# WARNING: For non-production testing only !!! Do not change (to avoid version store issues, including possible mismatch). Should be false since lightWeightVersionStore is deprecated.
version.store.onlyUseDeprecatedV1=false
# Folders for storing people # Folders for storing people
system.system_container.childname=sys:system system.system_container.childname=sys:system
system.people_container.childname=sys:people system.people_container.childname=sys:people

View File

@@ -470,4 +470,36 @@
</property> </property>
</bean> </bean>
<!-- enable scheduler property to activate -->
<bean id="versionStoreMigrationCleanupJob" class="org.alfresco.util.TriggerBean">
<property name="jobDetail">
<bean id="versionStoreMigrationCleanupDetail" class="org.springframework.scheduling.quartz.JobDetailBean">
<property name="jobClass">
<value>org.alfresco.repo.version.MigrationCleanupJob</value>
</property>
<property name="jobDataAsMap">
<map>
<entry key="versionMigrator">
<ref bean="versionMigrator" />
</entry>
</map>
</property>
</bean>
</property>
<!-- enable this to activate bean -->
<property name="scheduler">
<ref bean="schedulerFactory" />
</property>
<!-- start after bootstrap (1 minute) and run once -->
<property name="startDelayMinutes">
<value>1</value>
</property>
<property name="repeatCount">
<value>0</value>
</property>
</bean>
</beans> </beans>

View File

@@ -19,4 +19,4 @@ version.build=@build-number@
# Schema number # Schema number
version.schema=129 version.schema=130

View File

@@ -0,0 +1,85 @@
/*
* Copyright (C) 2005-2008 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
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing
*/
package org.alfresco.repo.admin.patch.impl;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.i18n.I18NUtil;
import org.alfresco.repo.admin.patch.AbstractPatch;
import org.alfresco.repo.version.VersionMigrator;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Migrate version store from workspace://lightWeightVersionStore to workspace://version2Store
*/
public class MigrateVersionStorePatch extends AbstractPatch
{
private static Log logger = LogFactory.getLog(MigrateVersionStorePatch.class);
private static final String MSG_SUCCESS = "patch.migrateVersionStore.result";
private VersionMigrator versionMigrator;
private int batchSize = 1;
private boolean deleteImmediately = false;
public void setVersionMigrator(VersionMigrator versionMigrator)
{
this.versionMigrator = versionMigrator;
}
public void setBatchSize(int batchSize)
{
this.batchSize = batchSize;
}
public void setDeleteImmediately(boolean deleteImmediately)
{
this.deleteImmediately = deleteImmediately;
}
public void init()
{
if (batchSize < 1)
{
String errorMessage = "batchSize ("+batchSize+") cannot be less than 1";
logger.error(errorMessage);
throw new AlfrescoRuntimeException(errorMessage);
}
super.init();
}
@Override
protected String applyInternal() throws Exception
{
int vhCount = versionMigrator.migrateVersions(batchSize, deleteImmediately);
// build the result message
String msg = I18NUtil.getMessage(MSG_SUCCESS, vhCount);
// done
return msg;
}
}

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2005-2007 Alfresco Software Limited. * Copyright (C) 2005-2008 Alfresco Software Limited.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@@ -31,9 +31,11 @@ import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel; import org.alfresco.model.ContentModel;
import org.alfresco.repo.node.archive.NodeArchiveService; import org.alfresco.repo.node.archive.NodeArchiveService;
import org.alfresco.repo.policy.BehaviourFilter; import org.alfresco.repo.policy.BehaviourFilter;
import org.alfresco.repo.version.Version2Model;
import org.alfresco.repo.version.VersionModel; import org.alfresco.repo.version.VersionModel;
import org.alfresco.repo.version.common.VersionUtil; import org.alfresco.repo.version.common.VersionUtil;
import org.alfresco.service.cmr.ml.EditionService; import org.alfresco.service.cmr.ml.EditionService;
@@ -257,9 +259,29 @@ public class EditionServiceImpl implements EditionService
Map<QName, Serializable> properties = versionNodeService.getProperties(mlContainerEdition.getFrozenStateNodeRef()); Map<QName, Serializable> properties = versionNodeService.getProperties(mlContainerEdition.getFrozenStateNodeRef());
List<VersionHistory> versionHistories = null;
// Switch VersionStore depending on configured impl
if (versionService.getVersionStoreReference().getIdentifier().equals(Version2Model.STORE_ID))
{
// V2 version store (eg. workspace://version2Store)
// get the serialisation of the version histories in the version properties // get the serialisation of the version histories in the version properties
List<VersionHistory> versionHistories = (List<VersionHistory>) versionHistories = (List<VersionHistory>)
properties.get(VersionModel.PROP_QNAME_TRANSLATION_VERIONS); properties.get(Version2Model.PROP_QNAME_TRANSLATION_VERSIONS);
}
else if (versionService.getVersionStoreReference().getIdentifier().equals(VersionModel.STORE_ID))
{
// Deprecated V1 version store (eg. workspace://lightWeightVersionStore)
// get the serialisation of the version histories in the version properties
versionHistories = (List<VersionHistory>)
properties.get(VersionModel.PROP_QNAME_TRANSLATION_VERSIONS);
}
else
{
throw new AlfrescoRuntimeException("Unexpected versionstore: " + versionService.getVersionStoreReference().getIdentifier());
}
if (versionHistories == null) if (versionHistories == null)
{ {
@@ -296,8 +318,21 @@ public class EditionServiceImpl implements EditionService
// properties in which the version histories will be stored // properties in which the version histories will be stored
Map<QName, Serializable> properties = new HashMap<QName, Serializable>(); Map<QName, Serializable> properties = new HashMap<QName, Serializable>();
// Switch VersionStore depending on configured impl
if (versionService.getVersionStoreReference().getIdentifier().equals(Version2Model.STORE_ID))
{
// V2 version store (eg. workspace://version2Store)
// add the version history of the translation as property of the Edition // add the version history of the translation as property of the Edition
properties.put(VersionModel.PROP_QNAME_QNAME, VersionModel.PROP_QNAME_TRANSLATION_VERIONS); NodeRef versionNodeRef = VersionUtil.convertNodeRef(edition.getFrozenStateNodeRef());
this.nodeService.setProperty(versionNodeRef, Version2Model.PROP_QNAME_TRANSLATION_VERSIONS, (Serializable) translationVersionHistories);
}
else if (versionService.getVersionStoreReference().getIdentifier().equals(VersionModel.STORE_ID))
{
// Deprecated V1 version store (eg. workspace://lightWeightVersionStore)
// add the version history of the translation as property of the Edition
properties.put(VersionModel.PROP_QNAME_QNAME, VersionModel.PROP_QNAME_TRANSLATION_VERSIONS);
properties.put(VersionModel.PROP_QNAME_IS_MULTI_VALUE, true); properties.put(VersionModel.PROP_QNAME_IS_MULTI_VALUE, true);
properties.put(VersionModel.PROP_QNAME_MULTI_VALUE, (Serializable) translationVersionHistories); properties.put(VersionModel.PROP_QNAME_MULTI_VALUE, (Serializable) translationVersionHistories);
@@ -309,6 +344,12 @@ public class EditionServiceImpl implements EditionService
VersionModel.TYPE_QNAME_VERSIONED_PROPERTY, VersionModel.TYPE_QNAME_VERSIONED_PROPERTY,
properties); properties);
} }
else
{
throw new AlfrescoRuntimeException("Unexpected versionstore: " + versionService.getVersionStoreReference().getIdentifier());
}
}
/** /**
* Util method to add the usefull properties to the existing properties of the given, mlContainer * Util method to add the usefull properties to the existing properties of the given, mlContainer

View File

@@ -25,6 +25,7 @@
package org.alfresco.repo.node.integrity; package org.alfresco.repo.node.integrity;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
@@ -79,6 +80,7 @@ public class IncompleteNodeTagger
private PolicyComponent policyComponent; private PolicyComponent policyComponent;
private DictionaryService dictionaryService; private DictionaryService dictionaryService;
private NodeService nodeService; private NodeService nodeService;
private List<String> storesToIgnore = new ArrayList<String>(0);
public IncompleteNodeTagger() public IncompleteNodeTagger()
{ {
@@ -108,6 +110,15 @@ public class IncompleteNodeTagger
this.nodeService = nodeService; this.nodeService = nodeService;
} }
/**
* @param storesToIgnore stores (eg. workspace://version2Store) which will be
* ignored by IncompleteNodeTagger. Note: assumes associations are within a store.
*/
public void setStoresToIgnore(List<String> storesToIgnore)
{
this.storesToIgnore = storesToIgnore;
}
/** /**
* Registers the system-level policy behaviours * Registers the system-level policy behaviours
*/ */
@@ -235,11 +246,14 @@ public class IncompleteNodeTagger
* {@inheritDoc} * {@inheritDoc}
*/ */
public void onCreateNode(ChildAssociationRef childAssocRef) public void onCreateNode(ChildAssociationRef childAssocRef)
{
if (! storesToIgnore.contains(childAssocRef.getChildRef().getStoreRef().toString()))
{ {
NodeRef nodeRef = childAssocRef.getChildRef(); NodeRef nodeRef = childAssocRef.getChildRef();
save(nodeRef); save(nodeRef);
saveAssoc(nodeRef, null); saveAssoc(nodeRef, null);
} }
}
/** /**
* {@inheritDoc} * {@inheritDoc}
@@ -248,9 +262,12 @@ public class IncompleteNodeTagger
NodeRef nodeRef, NodeRef nodeRef,
Map<QName, Serializable> before, Map<QName, Serializable> before,
Map<QName, Serializable> after) Map<QName, Serializable> after)
{
if (! storesToIgnore.contains(nodeRef.getStoreRef().toString()))
{ {
save(nodeRef); save(nodeRef);
} }
}
/** /**
* {@inheritDoc} * {@inheritDoc}
@@ -260,6 +277,8 @@ public class IncompleteNodeTagger
* not processed. * not processed.
*/ */
public void onAddAspect(NodeRef nodeRef, QName aspectTypeQName) public void onAddAspect(NodeRef nodeRef, QName aspectTypeQName)
{
if (! storesToIgnore.contains(nodeRef.getStoreRef().toString()))
{ {
if (aspectTypeQName.equals(ContentModel.ASPECT_INCOMPLETE)) if (aspectTypeQName.equals(ContentModel.ASPECT_INCOMPLETE))
{ {
@@ -270,11 +289,14 @@ public class IncompleteNodeTagger
} }
save(nodeRef); save(nodeRef);
} }
}
/** /**
* Recheck the node as an aspect was removed. * Recheck the node as an aspect was removed.
*/ */
public void onRemoveAspect(NodeRef nodeRef, QName aspectTypeQName) public void onRemoveAspect(NodeRef nodeRef, QName aspectTypeQName)
{
if (! storesToIgnore.contains(nodeRef.getStoreRef().toString()))
{ {
if (aspectTypeQName.equals(ContentModel.ASPECT_INCOMPLETE)) if (aspectTypeQName.equals(ContentModel.ASPECT_INCOMPLETE))
{ {
@@ -285,6 +307,7 @@ public class IncompleteNodeTagger
} }
save(nodeRef); save(nodeRef);
} }
}
/** /**
* {@inheritDoc} * {@inheritDoc}
@@ -293,36 +316,48 @@ public class IncompleteNodeTagger
* node will handle it. * node will handle it.
*/ */
public void onCreateChildAssociation(ChildAssociationRef childAssocRef, boolean isNew) public void onCreateChildAssociation(ChildAssociationRef childAssocRef, boolean isNew)
{
if (! storesToIgnore.contains(childAssocRef.getChildRef().getStoreRef().toString()))
{ {
if (!isNew) if (!isNew)
{ {
saveAssoc(childAssocRef.getParentRef(), childAssocRef.getTypeQName()); saveAssoc(childAssocRef.getParentRef(), childAssocRef.getTypeQName());
} }
} }
}
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
public void onDeleteChildAssociation(ChildAssociationRef childAssocRef) public void onDeleteChildAssociation(ChildAssociationRef childAssocRef)
{
if (! storesToIgnore.contains(childAssocRef.getChildRef().getStoreRef().toString()))
{ {
saveAssoc(childAssocRef.getParentRef(), childAssocRef.getTypeQName()); saveAssoc(childAssocRef.getParentRef(), childAssocRef.getTypeQName());
} }
}
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
public void onCreateAssociation(AssociationRef nodeAssocRef) public void onCreateAssociation(AssociationRef nodeAssocRef)
{
if (! storesToIgnore.contains(nodeAssocRef.getSourceRef().getStoreRef().toString()))
{ {
saveAssoc(nodeAssocRef.getSourceRef(), nodeAssocRef.getTypeQName()); saveAssoc(nodeAssocRef.getSourceRef(), nodeAssocRef.getTypeQName());
} }
}
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
public void onDeleteAssociation(AssociationRef nodeAssocRef) public void onDeleteAssociation(AssociationRef nodeAssocRef)
{
if (! storesToIgnore.contains(nodeAssocRef.getSourceRef().getStoreRef().toString()))
{ {
saveAssoc(nodeAssocRef.getSourceRef(), nodeAssocRef.getTypeQName()); saveAssoc(nodeAssocRef.getSourceRef(), nodeAssocRef.getTypeQName());
} }
}
/** /**
* Process all the nodes that require checking within the transaction. * Process all the nodes that require checking within the transaction.

View File

@@ -107,6 +107,7 @@ public class IntegrityChecker
private boolean failOnViolation; private boolean failOnViolation;
private int maxErrorsPerTransaction; private int maxErrorsPerTransaction;
private boolean traceOn; private boolean traceOn;
private List<String> storesToIgnore = new ArrayList<String>(0);
/** /**
* Downgrade violations to warnings within the current transaction. This is temporary and * Downgrade violations to warnings within the current transaction. This is temporary and
@@ -207,6 +208,15 @@ public class IntegrityChecker
this.maxErrorsPerTransaction = maxLogNumberPerTransaction; this.maxErrorsPerTransaction = maxLogNumberPerTransaction;
} }
/**
* @param storesToIgnore stores (eg. workspace://version2Store) which will be
* ignored by integrity checker. Note: assumes associations are within a store.
*/
public void setStoresToIgnore(List<String> storesToIgnore)
{
this.storesToIgnore = storesToIgnore;
}
/** /**
* Registers the system-level policy behaviours * Registers the system-level policy behaviours
*/ */
@@ -320,6 +330,8 @@ public class IntegrityChecker
public void onCreateNode(ChildAssociationRef childAssocRef) public void onCreateNode(ChildAssociationRef childAssocRef)
{ {
NodeRef childRef = childAssocRef.getChildRef(); NodeRef childRef = childAssocRef.getChildRef();
if (! storesToIgnore.contains(childRef.getStoreRef().toString()))
{
IntegrityEvent event = null; IntegrityEvent event = null;
// check properties on child node // check properties on child node
event = new PropertiesIntegrityEvent( event = new PropertiesIntegrityEvent(
@@ -358,6 +370,7 @@ public class IntegrityChecker
save(event); save(event);
} }
} }
}
/** /**
* @see PropertiesIntegrityEvent * @see PropertiesIntegrityEvent
@@ -366,12 +379,15 @@ public class IntegrityChecker
NodeRef nodeRef, NodeRef nodeRef,
Map<QName, Serializable> before, Map<QName, Serializable> before,
Map<QName, Serializable> after) Map<QName, Serializable> after)
{
if (! storesToIgnore.contains(nodeRef.getStoreRef().toString()))
{ {
IntegrityEvent event = null; IntegrityEvent event = null;
// check properties on node // check properties on node
event = new PropertiesIntegrityEvent(nodeService, dictionaryService, nodeRef); event = new PropertiesIntegrityEvent(nodeService, dictionaryService, nodeRef);
save(event); save(event);
} }
}
/** /**
* No checking performed: The association changes will be handled * No checking performed: The association changes will be handled
@@ -385,6 +401,8 @@ public class IntegrityChecker
* @see AssocTargetMultiplicityIntegrityEvent * @see AssocTargetMultiplicityIntegrityEvent
*/ */
public void onAddAspect(NodeRef nodeRef, QName aspectTypeQName) public void onAddAspect(NodeRef nodeRef, QName aspectTypeQName)
{
if (! storesToIgnore.contains(nodeRef.getStoreRef().toString()))
{ {
IntegrityEvent event = null; IntegrityEvent event = null;
// check properties on node // check properties on node
@@ -413,17 +431,20 @@ public class IntegrityChecker
save(event); save(event);
} }
} }
}
/** /**
* @see AspectsIntegrityEvent * @see AspectsIntegrityEvent
*/ */
public void onRemoveAspect(NodeRef nodeRef, QName aspectTypeQName) public void onRemoveAspect(NodeRef nodeRef, QName aspectTypeQName)
{
if (! storesToIgnore.contains(nodeRef.getStoreRef().toString()))
{ {
IntegrityEvent event = null; IntegrityEvent event = null;
// check mandatory aspects // check mandatory aspects
event = new AspectsIntegrityEvent(nodeService, dictionaryService, nodeRef); event = new AspectsIntegrityEvent(nodeService, dictionaryService, nodeRef);
save(event); save(event);
}
} }
/** /**
@@ -442,6 +463,8 @@ public class IntegrityChecker
return; return;
} }
if (! storesToIgnore.contains(childAssocRef.getChildRef().getStoreRef().toString()))
{
IntegrityEvent event = null; IntegrityEvent event = null;
// check source type // check source type
event = new AssocSourceTypeIntegrityEvent( event = new AssocSourceTypeIntegrityEvent(
@@ -482,12 +505,15 @@ public class IntegrityChecker
childAssocRef.getQName()); childAssocRef.getQName());
save(event); save(event);
} }
}
/** /**
* @see AssocSourceMultiplicityIntegrityEvent * @see AssocSourceMultiplicityIntegrityEvent
* @see AssocTargetMultiplicityIntegrityEvent * @see AssocTargetMultiplicityIntegrityEvent
*/ */
public void onDeleteChildAssociation(ChildAssociationRef childAssocRef) public void onDeleteChildAssociation(ChildAssociationRef childAssocRef)
{
if (! storesToIgnore.contains(childAssocRef.getChildRef().getStoreRef().toString()))
{ {
IntegrityEvent event = null; IntegrityEvent event = null;
// check source multiplicity // check source multiplicity
@@ -507,6 +533,7 @@ public class IntegrityChecker
true); true);
save(event); save(event);
} }
}
/** /**
* @see AssocSourceTypeIntegrityEvent * @see AssocSourceTypeIntegrityEvent
@@ -515,6 +542,8 @@ public class IntegrityChecker
* @see AssocTargetMultiplicityIntegrityEvent * @see AssocTargetMultiplicityIntegrityEvent
*/ */
public void onCreateAssociation(AssociationRef nodeAssocRef) public void onCreateAssociation(AssociationRef nodeAssocRef)
{
if (! storesToIgnore.contains(nodeAssocRef.getSourceRef().getStoreRef().toString()))
{ {
IntegrityEvent event = null; IntegrityEvent event = null;
// check source type // check source type
@@ -548,12 +577,15 @@ public class IntegrityChecker
false); false);
save(event); save(event);
} }
}
/** /**
* @see AssocSourceMultiplicityIntegrityEvent * @see AssocSourceMultiplicityIntegrityEvent
* @see AssocTargetMultiplicityIntegrityEvent * @see AssocTargetMultiplicityIntegrityEvent
*/ */
public void onDeleteAssociation(AssociationRef nodeAssocRef) public void onDeleteAssociation(AssociationRef nodeAssocRef)
{
if (! storesToIgnore.contains(nodeAssocRef.getSourceRef().getStoreRef().toString()))
{ {
IntegrityEvent event = null; IntegrityEvent event = null;
// check source multiplicity // check source multiplicity
@@ -573,6 +605,7 @@ public class IntegrityChecker
true); true);
save(event); save(event);
} }
}
/** /**
* Runs several types of checks, querying specifically for events that * Runs several types of checks, querying specifically for events that

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2005-2007 Alfresco Software Limited. * Copyright (C) 2005-2008 Alfresco Software Limited.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@@ -133,6 +133,11 @@ public abstract class BaseVersionStoreTest extends BaseSpringTest
this.dictionaryDAO = dictionaryDAO; this.dictionaryDAO = dictionaryDAO;
} }
public void setVersionService(VersionService versionService)
{
this.versionService = versionService;
}
/** /**
* Called during the transaction setup * Called during the transaction setup
*/ */
@@ -148,7 +153,6 @@ public abstract class BaseVersionStoreTest extends BaseSpringTest
// Get the services by name from the application context // Get the services by name from the application context
this.dbNodeService = (NodeService)applicationContext.getBean("dbNodeService"); this.dbNodeService = (NodeService)applicationContext.getBean("dbNodeService");
this.versionService = (VersionService)applicationContext.getBean("versionService");
this.versionCounterDaoService = (VersionCounterService)applicationContext.getBean("versionCounterService"); this.versionCounterDaoService = (VersionCounterService)applicationContext.getBean("versionCounterService");
this.contentService = (ContentService)applicationContext.getBean("contentService"); this.contentService = (ContentService)applicationContext.getBean("contentService");
this.authenticationService = (AuthenticationService)applicationContext.getBean("authenticationService"); this.authenticationService = (AuthenticationService)applicationContext.getBean("authenticationService");
@@ -158,6 +162,8 @@ public abstract class BaseVersionStoreTest extends BaseSpringTest
this.nodeArchiveService = (NodeArchiveService) applicationContext.getBean("nodeArchiveService"); this.nodeArchiveService = (NodeArchiveService) applicationContext.getBean("nodeArchiveService");
this.nodeService = (NodeService)applicationContext.getBean("nodeService"); this.nodeService = (NodeService)applicationContext.getBean("nodeService");
setVersionService((VersionService)applicationContext.getBean("versionService"));
authenticationService.clearCurrentSecurityContext(); authenticationService.clearCurrentSecurityContext();
// Create the test model // Create the test model
@@ -214,6 +220,16 @@ public abstract class BaseVersionStoreTest extends BaseSpringTest
* @return the node reference * @return the node reference
*/ */
protected NodeRef createNewVersionableNode() protected NodeRef createNewVersionableNode()
{
return createNode(true);
}
protected NodeRef createNewNode()
{
return createNode(false);
}
protected NodeRef createNode(boolean versionable)
{ {
// Use this map to retrive the versionable nodes in later tests // Use this map to retrive the versionable nodes in later tests
this.versionableNodes = new HashMap<String, NodeRef>(); this.versionableNodes = new HashMap<String, NodeRef>();
@@ -225,7 +241,10 @@ public abstract class BaseVersionStoreTest extends BaseSpringTest
QName.createQName("{test}MyVersionableNode"), QName.createQName("{test}MyVersionableNode"),
TEST_TYPE_QNAME, TEST_TYPE_QNAME,
this.nodeProperties).getChildRef(); this.nodeProperties).getChildRef();
if (versionable)
{
this.dbNodeService.addAspect(nodeRef, ContentModel.ASPECT_VERSIONABLE, new HashMap<QName, Serializable>()); this.dbNodeService.addAspect(nodeRef, ContentModel.ASPECT_VERSIONABLE, new HashMap<QName, Serializable>());
}
assertNotNull(nodeRef); assertNotNull(nodeRef);
this.versionableNodes.put(nodeRef.getId(), nodeRef); this.versionableNodes.put(nodeRef.getId(), nodeRef);
@@ -241,7 +260,12 @@ public abstract class BaseVersionStoreTest extends BaseSpringTest
TEST_CHILD_ASSOC_1, TEST_CHILD_ASSOC_1,
TEST_TYPE_QNAME, TEST_TYPE_QNAME,
this.nodeProperties).getChildRef(); this.nodeProperties).getChildRef();
if (versionable)
{
this.dbNodeService.addAspect(child1, ContentModel.ASPECT_VERSIONABLE, new HashMap<QName, Serializable>()); this.dbNodeService.addAspect(child1, ContentModel.ASPECT_VERSIONABLE, new HashMap<QName, Serializable>());
}
assertNotNull(child1); assertNotNull(child1);
this.versionableNodes.put(child1.getId(), child1); this.versionableNodes.put(child1.getId(), child1);
NodeRef child2 = this.dbNodeService.createNode( NodeRef child2 = this.dbNodeService.createNode(
@@ -250,7 +274,12 @@ public abstract class BaseVersionStoreTest extends BaseSpringTest
TEST_CHILD_ASSOC_2, TEST_CHILD_ASSOC_2,
TEST_TYPE_QNAME, TEST_TYPE_QNAME,
this.nodeProperties).getChildRef(); this.nodeProperties).getChildRef();
if (versionable)
{
this.dbNodeService.addAspect(child2, ContentModel.ASPECT_VERSIONABLE, new HashMap<QName, Serializable>()); this.dbNodeService.addAspect(child2, ContentModel.ASPECT_VERSIONABLE, new HashMap<QName, Serializable>());
}
assertNotNull(child2); assertNotNull(child2);
this.versionableNodes.put(child2.getId(), child2); this.versionableNodes.put(child2.getId(), child2);
@@ -304,6 +333,25 @@ public abstract class BaseVersionStoreTest extends BaseSpringTest
return newVersion; return newVersion;
} }
protected Collection<Version> createVersion(NodeRef versionableNode, Map<String, Serializable> versionProperties, boolean versionChildren)
{
// Get the next version number
int nextVersion = peekNextVersionNumber();
String nextVersionLabel = peekNextVersionLabel(versionableNode, nextVersion, versionProperties);
// Snap-shot the date-time
long beforeVersionTime = System.currentTimeMillis();
// Now lets create new version for this node (optionally with children)
Collection<Version> versions = versionService.createVersion(versionableNode, this.versionProperties, versionChildren);
// Check the returned versions are correct
checkVersionCollection(nextVersion, nextVersionLabel, beforeVersionTime, versions);
// Return the new versions
return versions;
}
/** /**
* Gets the next version label * Gets the next version label
*/ */
@@ -322,15 +370,17 @@ public abstract class BaseVersionStoreTest extends BaseSpringTest
* @param newVersion the new version * @param newVersion the new version
* @param versionableNode the versioned node * @param versionableNode the versioned node
*/ */
protected void checkNewVersion(long beforeVersionTime, int expectedVersionNumber, String expectedVersionLabel, Version newVersion, NodeRef versionableNode) protected void checkVersion(long beforeVersionTime, int expectedVersionNumber, String expectedVersionLabel, Version newVersion, NodeRef versionableNode)
{ {
assertNotNull(newVersion); assertNotNull(newVersion);
// Check the version label and version number // Check the version label and version number
assertEquals( assertEquals(
"The expected version number was not used.", "The expected version number was not used.",
Integer.toString(expectedVersionNumber), Integer.toString(expectedVersionNumber),
newVersion.getVersionProperty(VersionModel.PROP_VERSION_NUMBER).toString()); newVersion.getVersionProperty(VersionBaseModel.PROP_VERSION_NUMBER).toString());
assertEquals( assertEquals(
"The expected version label was not used.", "The expected version label was not used.",
expectedVersionLabel, expectedVersionLabel,
@@ -347,9 +397,11 @@ public abstract class BaseVersionStoreTest extends BaseSpringTest
// Check the creator // Check the creator
assertEquals(USER_NAME, newVersion.getCreator()); assertEquals(USER_NAME, newVersion.getCreator());
// Check the properties of the verison // Check the metadata properties of the version
Map<String, Serializable> props = newVersion.getVersionProperties(); Map<String, Serializable> props = newVersion.getVersionProperties();
assertNotNull("The version properties collection should not be null.", props); assertNotNull("The version properties collection should not be null.", props);
if (versionProperties != null)
{
// TODO sort this out - need to check for the reserved properties too // TODO sort this out - need to check for the reserved properties too
//assertEquals(versionProperties.size(), props.size()); //assertEquals(versionProperties.size(), props.size());
for (String key : versionProperties.keySet()) for (String key : versionProperties.keySet())
@@ -358,10 +410,27 @@ public abstract class BaseVersionStoreTest extends BaseSpringTest
versionProperties.get(key), versionProperties.get(key),
newVersion.getVersionProperty(key)); newVersion.getVersionProperty(key));
} }
}
// Check that the node reference is correct // Check that the node reference is correct
NodeRef nodeRef = newVersion.getFrozenStateNodeRef(); NodeRef nodeRef = newVersion.getFrozenStateNodeRef();
assertNotNull(nodeRef); assertNotNull(nodeRef);
// Switch VersionStore depending on configured impl
if (versionService.getVersionStoreReference().getIdentifier().equals(Version2Model.STORE_ID))
{
// V2 version store (eg. workspace://version2Store)
assertEquals(
Version2Model.STORE_ID,
nodeRef.getStoreRef().getIdentifier());
assertEquals(
Version2Model.STORE_PROTOCOL,
nodeRef.getStoreRef().getProtocol());
assertNotNull(nodeRef.getId());
}
else if (versionService.getVersionStoreReference().getIdentifier().equals(VersionModel.STORE_ID))
{
// Deprecated V1 version store (eg. workspace://lightWeightVersionStore)
assertEquals( assertEquals(
VersionModel.STORE_ID, VersionModel.STORE_ID,
nodeRef.getStoreRef().getIdentifier()); nodeRef.getStoreRef().getIdentifier());
@@ -369,6 +438,12 @@ public abstract class BaseVersionStoreTest extends BaseSpringTest
VersionModel.STORE_PROTOCOL, VersionModel.STORE_PROTOCOL,
nodeRef.getStoreRef().getProtocol()); nodeRef.getStoreRef().getProtocol());
assertNotNull(nodeRef.getId()); assertNotNull(nodeRef.getId());
}
}
protected void checkNewVersion(long beforeVersionTime, int expectedVersionNumber, String expectedVersionLabel, Version newVersion, NodeRef versionableNode)
{
checkVersion(beforeVersionTime, expectedVersionNumber, expectedVersionLabel, newVersion, versionableNode);
// TODO: How do we check the frozen attributes ?? // TODO: How do we check the frozen attributes ??
@@ -379,6 +454,43 @@ public abstract class BaseVersionStoreTest extends BaseSpringTest
assertEquals(newVersion.getVersionLabel(), currentVersionLabel); assertEquals(newVersion.getVersionLabel(), currentVersionLabel);
} }
/**
* Helper method to check the validity of the list of newly created versions.
*
* @param expectedVersionNumber the expected version number that all the versions should have
* @param beforeVersionTime the time before the versions where created
* @param versions the collection of version objects
*/
private void checkVersionCollection(int expectedVersionNumber, String expectedVersionLabel, long beforeVersionTime, Collection<Version> versions)
{
for (Version version : versions)
{
// Get the frozen id from the version
String frozenNodeId = null;
// Switch VersionStore depending on configured impl
if (versionService.getVersionStoreReference().getIdentifier().equals(Version2Model.STORE_ID))
{
// V2 version store (eg. workspace://version2Store)
frozenNodeId = ((NodeRef)version.getVersionProperty(Version2Model.PROP_FROZEN_NODE_REF)).getId();
}
else if (versionService.getVersionStoreReference().getIdentifier().equals(VersionModel.STORE_ID))
{
// Deprecated V1 version store (eg. workspace://lightWeightVersionStore)
frozenNodeId = (String)version.getVersionProperty(VersionModel.PROP_FROZEN_NODE_ID);
}
assertNotNull("Unable to retrieve the frozen node id from the created version.", frozenNodeId);
// Get the original node ref (based on the forzen node)
NodeRef origionaNodeRef = this.versionableNodes.get(frozenNodeId);
assertNotNull("The versionable node ref that relates to the frozen node id can not be found.", origionaNodeRef);
// Check the new version
checkNewVersion(beforeVersionTime, expectedVersionNumber, expectedVersionLabel, version, origionaNodeRef);
}
}
/** /**
* Returns the next version number without affecting the version counter. * Returns the next version number without affecting the version counter.
* *

View File

@@ -0,0 +1,79 @@
/*
* Copyright (C) 2005-2008 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
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.repo.version;
import org.alfresco.error.AlfrescoRuntimeException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
/**
* Cleanup of Version Store Migration - to delete old/migrated version histories from old version store. Typically this is configured to run once on startup.
*/
public class MigrationCleanupJob implements Job
{
private static Log logger = LogFactory.getLog(MigrationCleanupJob.class);
private static final String KEY_COMPONENT = "versionMigrator";
private static final String KEY_BATCHSIZE = "batchSize";
private int batchSize = 1;
public void execute(JobExecutionContext context) throws JobExecutionException
{
JobDataMap jobData = context.getJobDetail().getJobDataMap();
VersionMigrator migrationCleanup = (VersionMigrator)jobData.get(KEY_COMPONENT);
if (migrationCleanup == null)
{
throw new JobExecutionException("Missing job data: " + KEY_COMPONENT);
}
String batchSizeStr = (String)jobData.get(KEY_BATCHSIZE);
if (batchSizeStr == null)
{
try
{
batchSize = new Integer(batchSizeStr);
}
catch (Exception e)
{
logger.warn("Invalid batchsize, using default: " + batchSize, e);
}
}
if (batchSize < 1)
{
String errorMessage = "batchSize ("+batchSize+") cannot be less than 1";
logger.error(errorMessage);
throw new AlfrescoRuntimeException(errorMessage);
}
// perform the cleanup of the old version store
migrationCleanup.executeCleanup(batchSize);
}
}

View File

@@ -0,0 +1,210 @@
/*
* Copyright (C) 2005-2008 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
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.repo.version;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.version.common.VersionUtil;
import org.alfresco.service.cmr.repository.AssociationRef;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
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.namespace.QName;
import org.alfresco.service.namespace.QNamePattern;
/**
* The version2 store node service implementation
*/
public class Node2ServiceImpl extends NodeServiceImpl implements NodeService, Version2Model
{
/**
* The name of the spoofed root association
*/
private static final QName rootAssocName = QName.createQName(Version2Model.NAMESPACE_URI, "versionedState");
/**
* Type translation for version store
*/
public QName getType(NodeRef nodeRef) throws InvalidNodeRefException
{
if (nodeRef.getStoreRef().getIdentifier().equals(VersionModel.STORE_ID))
{
return super.getType(nodeRef);
}
// frozen node type -> replaced by actual node type of the version node
return (QName)this.dbNodeService.getType(VersionUtil.convertNodeRef(nodeRef));
}
/**
* Translation for version store
*/
public Set<QName> getAspects(NodeRef nodeRef) throws InvalidNodeRefException
{
if (nodeRef.getStoreRef().getIdentifier().equals(VersionModel.STORE_ID))
{
return super.getAspects(nodeRef);
}
Set<QName> aspects = this.dbNodeService.getAspects(VersionUtil.convertNodeRef(nodeRef));
aspects.remove(Version2Model.ASPECT_VERSION);
return aspects;
}
/**
* Property translation for version store
*/
public Map<QName, Serializable> getProperties(NodeRef nodeRef) throws InvalidNodeRefException
{
if (nodeRef.getStoreRef().getIdentifier().equals(VersionModel.STORE_ID))
{
return super.getProperties(nodeRef);
}
Map<QName, Serializable> props = dbNodeService.getProperties(VersionUtil.convertNodeRef(nodeRef));
VersionUtil.convertFrozenToOriginalProps(props);
return props;
}
/**
* Property translation for version store
*/
public Serializable getProperty(NodeRef nodeRef, QName qname) throws InvalidNodeRefException
{
if (nodeRef.getStoreRef().getIdentifier().equals(VersionModel.STORE_ID))
{
return super.getProperty(nodeRef, qname);
}
// TODO optimise - get property directly and convert if needed
Map<QName, Serializable> properties = getProperties(VersionUtil.convertNodeRef(nodeRef));
return properties.get(qname);
}
/**
* The node will apprear to be attached to the root of the version store
*
* @see NodeService#getParentAssocs(NodeRef, QNamePattern, QNamePattern)
*/
public List<ChildAssociationRef> getParentAssocs(NodeRef nodeRef, QNamePattern typeQNamePattern, QNamePattern qnamePattern)
{
if (nodeRef.getStoreRef().getIdentifier().equals(VersionModel.STORE_ID))
{
return super.getParentAssocs(nodeRef, typeQNamePattern, qnamePattern);
}
List<ChildAssociationRef> result = new ArrayList<ChildAssociationRef>();
if (qnamePattern.isMatch(rootAssocName) == true)
{
result.add(new ChildAssociationRef(
ContentModel.ASSOC_CHILDREN,
dbNodeService.getRootNode(new StoreRef(StoreRef.PROTOCOL_WORKSPACE, Version2Model.STORE_ID)),
rootAssocName,
nodeRef));
}
return result;
}
/**
* Performs conversion from version store properties to <i>real</i> associations
*/
public List<ChildAssociationRef> getChildAssocs(NodeRef nodeRef, QNamePattern typeQNamePattern, QNamePattern qnamePattern) throws InvalidNodeRefException
{
if (nodeRef.getStoreRef().getIdentifier().equals(VersionModel.STORE_ID))
{
return super.getChildAssocs(nodeRef, typeQNamePattern, qnamePattern);
}
// Get the child assocs from the version store
List<ChildAssociationRef> childAssocRefs = this.dbNodeService.getChildAssocs(
VersionUtil.convertNodeRef(nodeRef),
typeQNamePattern, qnamePattern);
List<ChildAssociationRef> result = new ArrayList<ChildAssociationRef>(childAssocRefs.size());
for (ChildAssociationRef childAssocRef : childAssocRefs)
{
// Get the child reference
NodeRef childRef = childAssocRef.getChildRef();
NodeRef referencedNode = (NodeRef)this.dbNodeService.getProperty(childRef, ContentModel.PROP_REFERENCE);
// Build a child assoc ref to add to the returned list
ChildAssociationRef newChildAssocRef = new ChildAssociationRef(
childAssocRef.getTypeQName(),
childAssocRef.getParentRef(),
childAssocRef.getQName(),
referencedNode,
childAssocRef.isPrimary(),
childAssocRef.getNthSibling());
result.add(newChildAssocRef);
}
// sort the results so that the order appears to be exactly as it was originally
Collections.sort(result);
return result;
}
/**
* Simulates the node begin attached to the root node of the version store.
*/
public ChildAssociationRef getPrimaryParent(NodeRef nodeRef) throws InvalidNodeRefException
{
if (nodeRef.getStoreRef().getIdentifier().equals(VersionModel.STORE_ID))
{
return super.getPrimaryParent(nodeRef);
}
return new ChildAssociationRef(
ContentModel.ASSOC_CHILDREN,
dbNodeService.getRootNode(new StoreRef(StoreRef.PROTOCOL_WORKSPACE, Version2Model.STORE_ID)),
rootAssocName,
nodeRef);
}
/**
* @throws UnsupportedOperationException always
*/
@Override
public List<AssociationRef> getTargetAssocs(NodeRef sourceRef, QNamePattern qnamePattern)
{
if (sourceRef.getStoreRef().getIdentifier().equals(VersionModel.STORE_ID))
{
return super.getTargetAssocs(sourceRef, qnamePattern);
}
// This operation is not supported for a version2 store
throw new UnsupportedOperationException(MSG_UNSUPPORTED);
}
}

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2005-2007 Alfresco Software Limited. * Copyright (C) 2005-2008 Alfresco Software Limited.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@@ -36,6 +36,7 @@ import java.util.Set;
import org.alfresco.model.ContentModel; import org.alfresco.model.ContentModel;
import org.alfresco.repo.version.common.VersionUtil; import org.alfresco.repo.version.common.VersionUtil;
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.dictionary.InvalidAspectException; import org.alfresco.service.cmr.dictionary.InvalidAspectException;
import org.alfresco.service.cmr.dictionary.PropertyDefinition; import org.alfresco.service.cmr.dictionary.PropertyDefinition;
@@ -54,6 +55,8 @@ import org.alfresco.service.cmr.search.SearchService;
import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.QNamePattern; import org.alfresco.service.namespace.QNamePattern;
import org.alfresco.service.namespace.RegexQNamePattern; import org.alfresco.service.namespace.RegexQNamePattern;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/** /**
@@ -63,10 +66,12 @@ import org.alfresco.service.namespace.RegexQNamePattern;
*/ */
public class NodeServiceImpl implements NodeService, VersionModel public class NodeServiceImpl implements NodeService, VersionModel
{ {
private static Log logger = LogFactory.getLog(NodeServiceImpl.class);
/** /**
* Error messages * Error messages
*/ */
private final static String MSG_UNSUPPORTED = protected final static String MSG_UNSUPPORTED =
"This operation is not supported by a version store implementation of the node service."; "This operation is not supported by a version store implementation of the node service.";
/** /**
@@ -331,7 +336,23 @@ public class NodeServiceImpl implements NodeService, VersionModel
if (isMultiValue.booleanValue() == false) if (isMultiValue.booleanValue() == false)
{ {
value = this.dbNodeService.getProperty(versionedAttribute, PROP_QNAME_VALUE); value = this.dbNodeService.getProperty(versionedAttribute, PROP_QNAME_VALUE);
value = (Serializable)DefaultTypeConverter.INSTANCE.convert(propDef.getDataType(), value);
if (propDef != null)
{
DataTypeDefinition dataTypeDef = propDef.getDataType();
if (dataTypeDef != null)
{
value = (Serializable)DefaultTypeConverter.INSTANCE.convert(dataTypeDef, value);
}
else
{
logger.warn("Null dataTypeDefinition for: " + propDef);
}
}
else
{
logger.warn("Null propertyDefinition for: " + qName);
}
} }
else else
{ {

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2005-2007 Alfresco Software Limited. * Copyright (C) 2005-2008 Alfresco Software Limited.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@@ -119,13 +119,25 @@ public class NodeServiceImplTest extends BaseVersionStoreTest
// Get the properties of the versioned state // Get the properties of the versioned state
Map<QName, Serializable> versionedProperties = this.lightWeightVersionStoreNodeService.getProperties(version.getFrozenStateNodeRef()); Map<QName, Serializable> versionedProperties = this.lightWeightVersionStoreNodeService.getProperties(version.getFrozenStateNodeRef());
//assertEquals(origProps.size(), versionedProperties.size());
if (logger.isDebugEnabled())
{
logger.debug("original ("+origProps.size()+"): " + origProps.keySet());
logger.debug("versioned ("+versionedProperties.size()+"): " + versionedProperties.keySet());
}
for (QName key : origProps.keySet()) for (QName key : origProps.keySet())
{ {
assertTrue(versionedProperties.containsKey(key)); assertTrue(versionedProperties.containsKey(key));
assertEquals(origProps.get(key), versionedProperties.get(key)); assertEquals(""+key, origProps.get(key), versionedProperties.get(key));
} }
// NOTE: cm:versionLabel is an expected additional property
//assertEquals(origProps.size(), versionedProperties.size());
// check version label
assertEquals("1.0", versionedProperties.get(ContentModel.PROP_VERSION_LABEL));
// TODO do futher versioning and check by changing values // TODO do futher versioning and check by changing values
} }
@@ -163,46 +175,47 @@ public class NodeServiceImplTest extends BaseVersionStoreTest
*/ */
public void testGetChildAssocs() public void testGetChildAssocs()
{ {
if (logger.isDebugEnabled()) if (logger.isTraceEnabled())
{ {
// Let's have a look at the version store .. // Let's have a look at the version store ..
System.out.println(NodeStoreInspector.dumpNodeStore( logger.trace(NodeStoreInspector.dumpNodeStore(
this.dbNodeService, this.dbNodeService,
this.versionService.getVersionStoreReference()) + "\n\n"); this.versionService.getVersionStoreReference()) + "\n\n");
logger.debug(""); logger.trace("");
} }
// Create a new versionable node // Create a new versionable node
NodeRef versionableNode = createNewVersionableNode(); NodeRef versionableNode = createNewVersionableNode();
Collection<ChildAssociationRef> origionalChildren = this.dbNodeService.getChildAssocs(versionableNode); Collection<ChildAssociationRef> originalChildren = this.dbNodeService.getChildAssocs(versionableNode);
assertNotNull(origionalChildren); assertNotNull(originalChildren);
// Store the origional children in a map for easy navigation later // Store the original children in a map for easy navigation later
HashMap<String, ChildAssociationRef> origionalChildAssocRefs = new HashMap<String, ChildAssociationRef>(); HashMap<String, ChildAssociationRef> originalChildAssocRefs = new HashMap<String, ChildAssociationRef>();
for (ChildAssociationRef ref : origionalChildren) for (ChildAssociationRef ref : originalChildren)
{ {
origionalChildAssocRefs.put(ref.getChildRef().getId(), ref); originalChildAssocRefs.put(ref.getChildRef().getId(), ref);
} }
// Create a new version // Create a new version
Version version = createVersion(versionableNode, this.versionProperties); Version version = createVersion(versionableNode, this.versionProperties);
if (logger.isDebugEnabled()) if (logger.isTraceEnabled())
{ {
// Let's have a look at the version store .. // Let's have a look at the version store ..
System.out.println(NodeStoreInspector.dumpNodeStore( logger.trace(NodeStoreInspector.dumpNodeStore(
this.dbNodeService, this.dbNodeService,
this.versionService.getVersionStoreReference())); this.versionService.getVersionStoreReference()));
logger.trace("");
} }
// Get the children of the versioned node // Get the children of the versioned node
Collection<ChildAssociationRef> versionedChildren = this.lightWeightVersionStoreNodeService.getChildAssocs(version.getFrozenStateNodeRef()); Collection<ChildAssociationRef> versionedChildren = this.lightWeightVersionStoreNodeService.getChildAssocs(version.getFrozenStateNodeRef());
assertNotNull(versionedChildren); assertNotNull(versionedChildren);
assertEquals(origionalChildren.size(), versionedChildren.size()); assertEquals(originalChildren.size(), versionedChildren.size());
for (ChildAssociationRef versionedChildRef : versionedChildren) for (ChildAssociationRef versionedChildRef : versionedChildren)
{ {
ChildAssociationRef origChildAssocRef = origionalChildAssocRefs.get(versionedChildRef.getChildRef().getId()); ChildAssociationRef origChildAssocRef = originalChildAssocRefs.get(versionedChildRef.getChildRef().getId());
assertNotNull(origChildAssocRef); assertNotNull(origChildAssocRef);
assertEquals( assertEquals(
@@ -219,9 +232,34 @@ public class NodeServiceImplTest extends BaseVersionStoreTest
/** /**
* Test getAssociationTargets * Test getAssociationTargets
*
* @deprecated
*/ */
public void testGetAssociationTargets() public void testGetAssociationTargets()
{ {
// Switch VersionStore depending on configured impl
if (versionService.getVersionStoreReference().getIdentifier().equals(Version2Model.STORE_ID))
{
// V2 version store (eg. workspace://version2Store)
try
{
this.lightWeightVersionStoreNodeService.getTargetAssocs(
dummyNodeRef,
RegexQNamePattern.MATCH_ALL);
fail("This operation is not supported.");
}
catch (UnsupportedOperationException exception)
{
if (exception.getMessage() != MSG_ERR)
{
fail("Unexpected exception raised during method excution: " + exception.getMessage());
}
}
}
else if (versionService.getVersionStoreReference().getIdentifier().equals(VersionModel.STORE_ID))
{
// Deprecated V1 version store (eg. workspace://lightWeightVersionStore)
// Create a new versionable node // Create a new versionable node
NodeRef versionableNode = createNewVersionableNode(); NodeRef versionableNode = createNewVersionableNode();
@@ -239,6 +277,7 @@ public class NodeServiceImplTest extends BaseVersionStoreTest
assertNotNull(assocs); assertNotNull(assocs);
assertEquals(origAssocs.size(), assocs.size()); assertEquals(origAssocs.size(), assocs.size());
} }
}
/** /**
* Test hasAspect * Test hasAspect
@@ -277,7 +316,10 @@ public class NodeServiceImplTest extends BaseVersionStoreTest
Set<QName> aspects = this.lightWeightVersionStoreNodeService.getAspects(version.getFrozenStateNodeRef()); Set<QName> aspects = this.lightWeightVersionStoreNodeService.getAspects(version.getFrozenStateNodeRef());
assertEquals(origAspects.size(), aspects.size()); assertEquals(origAspects.size(), aspects.size());
// TODO check that the set's contain the same items for (QName origAspect : origAspects)
{
assertTrue(origAspect+"",aspects.contains(origAspect));
}
} }
/** /**

View File

@@ -0,0 +1,118 @@
/*
* Copyright (C) 2005-2008 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
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.repo.version;
import org.alfresco.service.namespace.QName;
/**
* Version2 Model Constants used by version2Store implementation
*/
public interface Version2Model extends VersionBaseModel
{
/**
* Namespace
*/
public static final String NAMESPACE_URI = "http://www.alfresco.org/model/versionstore/2.0";
/**
* The store id
*/
public static final String STORE_ID = "version2Store";
/** The version store root aspect */
public static final QName ASPECT_VERSION_STORE_ROOT = QName.createQName(NAMESPACE_URI, ASPECT_LOCALNAME_VERSION_STORE_ROOT);
/**
* Version history type
*/
public static final QName TYPE_QNAME_VERSION_HISTORY = QName.createQName(NAMESPACE_URI, TYPE_VERSION_HISTORY);
/**
* Version history properties and associations
*/
public static final QName PROP_QNAME_VERSIONED_NODE_ID = QName.createQName(NAMESPACE_URI, PROP_VERSIONED_NODE_ID);
public static final QName ASSOC_ROOT_VERSION = QName.createQName(NAMESPACE_URI, ASSOC_LOCALNAME_ROOT_VERSION);
/**
* Version aspect + aspect properties
*/
public static final String ASPECT_LOCALNAME_VERSION = "version";
public static final QName ASPECT_VERSION = QName.createQName(NAMESPACE_URI, ASPECT_LOCALNAME_VERSION);
public static final String PROP_VERSION_DESCRIPTION = "versionDescription"; // maps from description
public static final QName PROP_QNAME_VERSION_LABEL = QName.createQName(NAMESPACE_URI, PROP_VERSION_LABEL);
public static final QName PROP_QNAME_VERSION_NUMBER = QName.createQName(NAMESPACE_URI, PROP_VERSION_NUMBER);
public static final QName PROP_QNAME_VERSION_DESCRIPTION = QName.createQName(NAMESPACE_URI, PROP_VERSION_DESCRIPTION);
// frozen sys:referenceable properties (x4)
public static final String PROP_FROZEN_NODE_REF = "frozenNodeRef";
public static final QName PROP_QNAME_FROZEN_NODE_REF = QName.createQName(NAMESPACE_URI, PROP_FROZEN_NODE_REF);
public static final String PROP_FROZEN_NODE_DBID = "frozenNodeDbId";
public static final QName PROP_QNAME_FROZEN_NODE_DBID = QName.createQName(NAMESPACE_URI, PROP_FROZEN_NODE_DBID);
// frozen cm:auditable properties (x5)
public static final String PROP_FROZEN_CREATOR = "frozenCreator";
public static final QName PROP_QNAME_FROZEN_CREATOR = QName.createQName(NAMESPACE_URI, PROP_FROZEN_CREATOR);
public static final String PROP_FROZEN_CREATED = "frozenCreated";
public static final QName PROP_QNAME_FROZEN_CREATED = QName.createQName(NAMESPACE_URI, PROP_FROZEN_CREATED);
public static final String PROP_FROZEN_MODIFIER = "frozenModifer";
public static final QName PROP_QNAME_FROZEN_MODIFIER = QName.createQName(NAMESPACE_URI, PROP_FROZEN_MODIFIER);
public static final String PROP_FROZEN_MODIFIED = "frozenModified";
public static final QName PROP_QNAME_FROZEN_MODIFIED = QName.createQName(NAMESPACE_URI, PROP_FROZEN_MODIFIED);
public static final String PROP_FROZEN_ACCESSED = "frozenAccessed";
public static final QName PROP_QNAME_FROZEN_ACCESSED = QName.createQName(NAMESPACE_URI, PROP_FROZEN_ACCESSED);
public static final QName ASSOC_SUCCESSOR = QName.createQName(NAMESPACE_URI, "successor");
public static final String PROP_METADATA_PREFIX = "metadata-";
public static final String PROP_VERSION_TYPE = "versionType";
/**
* Child relationship names
*/
public static final QName CHILD_QNAME_VERSION_HISTORIES = QName.createQName(NAMESPACE_URI, CHILD_VERSION_HISTORIES);
public static final QName CHILD_QNAME_VERSIONS = QName.createQName(NAMESPACE_URI, CHILD_VERSIONS);
// Used by ML service
/**
* Created version associated to the deleted translations of an mlContainer
*/
public static final QName PROP_QNAME_TRANSLATION_VERSIONS = QName.createQName(VersionModel.NAMESPACE_URI, PROP_TRANSLATION_VERSIONS);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,78 @@
/*
* Copyright (C) 2005-2008 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
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.repo.version;
import org.alfresco.model.ContentModel;
import org.alfresco.service.cmr.version.VersionService;
/**
* Base Version Model interface containing the common local names (and other constants)
* used by the lightWeightVersionStore and version2Store implementations
*/
public interface VersionBaseModel
{
/**
* The store protocol
*/
public static final String STORE_PROTOCOL = VersionService.VERSION_STORE_PROTOCOL;
public static final String PROP_DESCRIPTION = "description";
public static final String PROP_VERSION_DESCRIPTION = "versionDescription";
public static final String PROP_VERSION_LABEL = "versionLabel";
public static final String PROP_CREATED_DATE = ContentModel.PROP_CREATED.getLocalName();
public static final String PROP_CREATOR = ContentModel.PROP_CREATOR.getLocalName();
public static final String PROP_VERSION_TYPE = "versionType";
public static final String PROP_VERSION_NUMBER = "versionNumber";
/** The version store root aspect localname*/
public static final String ASPECT_LOCALNAME_VERSION_STORE_ROOT = "versionStoreRoot";
/**
* Version history type
*/
public static final String TYPE_VERSION_HISTORY = "versionHistory";
/**
* Version history properties and associations
*/
public static final String PROP_VERSIONED_NODE_ID = "versionedNodeId";
public static final String ASSOC_LOCALNAME_ROOT_VERSION = "rootVersion";
/**
* Child relationship names
*/
public static final String CHILD_VERSION_HISTORIES = "versionHistory";
public static final String CHILD_VERSIONS = "version";
// Used by ML service
/**
* Created version associated to the deleted translations of an mlContainer
*/
public static final String PROP_TRANSLATION_VERSIONS = "translationVersions";
}

View File

@@ -0,0 +1,659 @@
/*
* Copyright (C) 2005-2008 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
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.repo.version;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.alfresco.i18n.I18NUtil;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.domain.hibernate.SessionSizeResourceManager;
import org.alfresco.repo.node.MLPropertyInterceptor;
import org.alfresco.repo.policy.BehaviourFilter;
import org.alfresco.repo.policy.PolicyScope;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.repo.version.common.VersionUtil;
import org.alfresco.service.cmr.dictionary.ClassDefinition;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
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.namespace.QName;
import org.alfresco.service.transaction.TransactionService;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Version2 Migrator
*/
public class VersionMigrator
{
protected static Log logger = LogFactory.getLog(VersionMigrator.class);
public static final StoreRef VERSION_STORE_REF_OLD = new StoreRef(StoreRef.PROTOCOL_WORKSPACE, VersionModel.STORE_ID);
public static final StoreRef VERSION_STORE_REF_NEW = new StoreRef(StoreRef.PROTOCOL_WORKSPACE, Version2Model.STORE_ID);
/** track completion * */
int percentComplete;
/** start time * */
long startTime;
private static final String MSG_PATCH_NOOP = "version_service.migration.patch.noop";
private static final String MSG_PATCH_COMPLETE = "version_service.migration.patch.complete";
private static final String MSG_PATCH_SKIP1 = "version_service.migration.patch.warn.skip1";
private static final String MSG_PATCH_SKIP2 = "version_service.migration.patch.warn.skip2";
private static final String MSG_DELETE_PROGRESS = "version_service.migration.delete.progress";
private static final String MSG_DELETE_COMPLETE = "version_service.migration.delete.complete";
private static final String MSG_DELETE_SKIP1 = "version_service.migration.delete.warn.skip1";
private static final String MSG_DELETE_SKIP2 = "version_service.migration.delete.warn.skip2";
private static final String MSG_PATCH_PROGRESS = "patch.progress";
private static final long RANGE_10 = 1000 * 60 * 90;
private static final long RANGE_5 = 1000 * 60 * 60 * 4;
private static final long RANGE_2 = 1000 * 60 * 90 * 10;
private static boolean busy = false;
public final static String PREFIX_MIGRATED = "migrated-";
private VersionServiceImpl version1Service = new VersionServiceImpl();
private Version2ServiceImpl version2Service;
private NodeService dbNodeService;
private BehaviourFilter policyBehaviourFilter;
private DictionaryService dictionaryService;
private TransactionService transactionService;
private NodeService versionNodeService; // NodeService impl which redirects to appropriate VersionService
public void setVersion2ServiceImpl(Version2ServiceImpl versionService)
{
this.version2Service = versionService;
}
public void setDbNodeService(NodeService nodeService)
{
this.dbNodeService = nodeService;
}
public void setPolicyBehaviourFilter(BehaviourFilter policyBehaviourFilter)
{
this.policyBehaviourFilter = policyBehaviourFilter;
}
public void setDictionaryService(DictionaryService dictionaryService)
{
this.dictionaryService = dictionaryService;
}
public void setTransactionService(TransactionService transactionService)
{
this.transactionService = transactionService;
}
public void setVersionNodeService(NodeService versionNodeService)
{
this.versionNodeService = versionNodeService;
}
public void init()
{
version1Service.setNodeService(dbNodeService);
version1Service.setDbNodeService(dbNodeService);
version2Service.setDbNodeService(dbNodeService);
}
public NodeRef migrateVersionHistory(NodeRef oldVHNodeRef, NodeRef versionedNodeRef)
{
if (logger.isTraceEnabled())
{
logger.trace("migrateVersionHistory: oldVersionHistoryRef = " + oldVHNodeRef);
}
VersionHistory vh = v1BuildVersionHistory(oldVHNodeRef, versionedNodeRef);
// create new version history node
NodeRef newVHNodeRef = v2CreateVersionHistory(versionedNodeRef);
Version[] oldVersions = (Version[])vh.getAllVersions().toArray(new Version[]{});
// Disable auditable behaviour - so that migrated versions maintain their original auditable properties (eg. created, creator)
this.policyBehaviourFilter.disableBehaviour(ContentModel.ASPECT_AUDITABLE);
try
{
for (int i = (oldVersions.length-1); i >= 0; i--)
{
// migrate versions
v2CreateNewVersion(newVHNodeRef, oldVersions[i]);
}
}
finally
{
// Enable auditable behaviour
this.policyBehaviourFilter.enableBehaviour(ContentModel.ASPECT_AUDITABLE);
}
return newVHNodeRef;
}
private NodeRef v2CreateVersionHistory(NodeRef nodeRef)
{
return version2Service.createVersionHistory(nodeRef);
}
private NodeRef v2CreateNewVersion(NodeRef newVersionHistoryRef, Version oldVersion)
{
NodeRef versionedNodeRef = oldVersion.getVersionedNodeRef(); // nodeRef to versioned node in live store
NodeRef frozenStateNodeRef = oldVersion.getFrozenStateNodeRef(); // nodeRef to version node in version store
if (logger.isTraceEnabled())
{
logger.trace("v2CreateNewVersion: oldVersionRef = " + frozenStateNodeRef + " " + oldVersion);
}
String versionLabel = oldVersion.getVersionLabel();
String versionDescription = oldVersion.getDescription();
QName sourceType = versionNodeService.getType(frozenStateNodeRef);
Set<QName> nodeAspects = versionNodeService.getAspects(frozenStateNodeRef);
Map<QName, Serializable> nodeProperties = versionNodeService.getProperties(frozenStateNodeRef);
long nodeDbId = (Long)nodeProperties.get(ContentModel.PROP_NODE_DBID);
nodeProperties.remove(ContentModel.PROP_NODE_UUID); // else will try to persist with this node uuid (see AbstractNodeServiceImpl.generateGuid)
int versionNumber = (Integer)dbNodeService.getProperty(VersionUtil.convertNodeRef(frozenStateNodeRef), VersionModel.PROP_QNAME_VERSION_NUMBER);
// get oldVersion auditable properties (of the version node itself, rather than the live versioned node)
Date versionCreated = (Date)dbNodeService.getProperty(VersionUtil.convertNodeRef(frozenStateNodeRef), ContentModel.PROP_CREATED);
String versionCreator = (String)dbNodeService.getProperty(VersionUtil.convertNodeRef(frozenStateNodeRef), ContentModel.PROP_CREATOR);
Date versionModified = (Date)dbNodeService.getProperty(VersionUtil.convertNodeRef(frozenStateNodeRef), ContentModel.PROP_MODIFIED);
String versionModifier = (String)dbNodeService.getProperty(VersionUtil.convertNodeRef(frozenStateNodeRef), ContentModel.PROP_MODIFIER);
Date versionAccessed = (Date)dbNodeService.getProperty(VersionUtil.convertNodeRef(frozenStateNodeRef), ContentModel.PROP_ACCESSED);
Map<String, Serializable> versionMetaDataProperties = version1Service.getVersionMetaData(VersionUtil.convertNodeRef(frozenStateNodeRef));
// Create the node details
PolicyScope nodeDetails = new PolicyScope(sourceType);
// add properties
for (Map.Entry<QName, Serializable> entry : nodeProperties.entrySet())
{
nodeDetails.addProperty(sourceType, entry.getKey(), entry.getValue());
}
// add aspects
for (QName aspect : nodeAspects)
{
// add aspect
nodeDetails.addAspect(aspect);
// copy the aspect properties
ClassDefinition classDefinition = dictionaryService.getClass(aspect);
if (classDefinition != null)
{
Map<QName,PropertyDefinition> propertyDefinitions = classDefinition.getProperties();
for (QName propertyName : propertyDefinitions.keySet())
{
Serializable propValue = nodeProperties.get(propertyName);
nodeDetails.addProperty(aspect, propertyName, propValue);
}
}
}
NodeRef newVersionRef = version2Service.createNewVersion(
sourceType,
newVersionHistoryRef,
version2Service.getStandardVersionProperties(versionedNodeRef, nodeDbId, nodeAspects, versionNumber, versionLabel, versionDescription),
versionMetaDataProperties,
versionNumber,
nodeDetails);
// set newVersion auditable properties (of the version node itself, rather than the live versioned node)
Map<QName, Serializable> props = dbNodeService.getProperties(newVersionRef);
props.put(ContentModel.PROP_CREATED, versionCreated);
props.put(ContentModel.PROP_CREATOR, versionCreator);
props.put(ContentModel.PROP_MODIFIED, versionModified);
props.put(ContentModel.PROP_MODIFIER, versionModifier);
props.put(ContentModel.PROP_ACCESSED, versionAccessed);
dbNodeService.setProperties(newVersionRef, props);
return newVersionRef;
}
protected NodeRef v1GetVersionedNodeRef(NodeRef oldVersionHistoryRef)
{
NodeRef versionedNodeRef = null;
// Get versioned nodeRef from one of the versions - note: assumes all versions refer to the same versioned nodeRef
Collection<ChildAssociationRef> versions = dbNodeService.getChildAssocs(oldVersionHistoryRef);
if (versions.size() > 0)
{
Iterator<ChildAssociationRef> itr = versions.iterator();
ChildAssociationRef childAssocRef = itr.next();
NodeRef versionRef = childAssocRef.getChildRef();
Version version = version1Service.getVersion(versionRef);
versionedNodeRef = version.getVersionedNodeRef();
}
return versionedNodeRef;
}
private VersionHistory v1BuildVersionHistory(NodeRef oldVersionHistoryRef, NodeRef versionedNodeRef)
{
return version1Service.buildVersionHistory(oldVersionHistoryRef, versionedNodeRef);
}
protected void v1DeleteVersionHistory(NodeRef oldVersionHistoryRef)
{
dbNodeService.deleteNode(oldVersionHistoryRef);
}
private void v1MarkVersionHistory(NodeRef oldVersionHistoryRef)
{
String migratedName = PREFIX_MIGRATED+oldVersionHistoryRef.getId();
dbNodeService.setProperty(oldVersionHistoryRef, ContentModel.PROP_NAME, migratedName);
}
public List<ChildAssociationRef> getVersionHistories(final NodeRef rootNodeRef)
{
return dbNodeService.getChildAssocs(rootNodeRef);
}
public int migrateVersions(final int batchSize, final boolean deleteImmediately)
{
final NodeRef oldRootNodeRef = dbNodeService.getRootNode(VersionMigrator.VERSION_STORE_REF_OLD);
final List<ChildAssociationRef> childAssocRefs = getVersionHistories(oldRootNodeRef);
int toDo = childAssocRefs.size();
if (toDo == 0)
{
logger.info(I18NUtil.getMessage(MSG_PATCH_NOOP));
return 0;
}
if (logger.isDebugEnabled())
{
logger.debug("Found "+toDo+" version histories in old version store");
}
// note: assumes patch runs before cleanup starts
startTime = System.currentTimeMillis();
percentComplete = 0;
int vhCount = 0;
int alreadyMigratedCount = 0;
int failCount = 0;
RetryingTransactionHelper txHelper = transactionService.getRetryingTransactionHelper();
boolean wasMLAware = MLPropertyInterceptor.setMLAware(true);
SessionSizeResourceManager.setDisableInTransaction();
try
{
int batchCount = 0;
int totalCount = 0;
final List<NodeRef> tmpBatch = new ArrayList<NodeRef>(batchSize);
for (final ChildAssociationRef childAssocRef : childAssocRefs)
{
reportProgress(MSG_PATCH_PROGRESS, toDo, totalCount);
totalCount++;
if (((String)dbNodeService.getProperty(childAssocRef.getChildRef(), ContentModel.PROP_NAME)).startsWith(VersionMigrator.PREFIX_MIGRATED))
{
// skip - already migrated
alreadyMigratedCount++;
continue;
}
if (batchCount < batchSize)
{
tmpBatch.add(childAssocRef.getChildRef());
batchCount++;
}
if ((batchCount == batchSize) || (totalCount == childAssocRefs.size()))
{
while (tmpBatch.size() != 0)
{
txHelper.setMaxRetries(1);
NodeRef failed = txHelper.doInTransaction(new RetryingTransactionCallback<NodeRef>()
{
public NodeRef execute() throws Throwable
{
if (logger.isTraceEnabled())
{
logger.trace("Attempt to migrate batch of "+tmpBatch.size()+" version histories");
}
long startTime = System.currentTimeMillis();
for (NodeRef oldVHNodeRef : tmpBatch)
{
try
{
NodeRef versionedNodeRef = v1GetVersionedNodeRef(oldVHNodeRef);
migrateVersionHistory(oldVHNodeRef, versionedNodeRef);
if (deleteImmediately)
{
// delete old version history node
v1DeleteVersionHistory(oldVHNodeRef);
}
else
{
// mark old version history node for later cleanup
v1MarkVersionHistory(oldVHNodeRef);
}
}
catch (Throwable t)
{
logger.error("Skipping migration of: " + oldVHNodeRef, t);
return oldVHNodeRef;
}
}
if (logger.isDebugEnabled())
{
logger.debug("Migrated batch of "+tmpBatch.size()+" version histories in "+(System.currentTimeMillis()-startTime)+ " ms");
}
return null;
}
}, false, true);
if (failed != null)
{
tmpBatch.remove(failed); // retry batch without the failed node
failCount++;
}
else
{
vhCount = vhCount + tmpBatch.size();
tmpBatch.clear();
batchCount = 0;
}
}
}
}
}
finally
{
MLPropertyInterceptor.setMLAware(wasMLAware);
SessionSizeResourceManager.setEnableInTransaction();
}
if (failCount > 0)
{
logger.warn(I18NUtil.getMessage(MSG_PATCH_SKIP1, failCount));
}
else if (alreadyMigratedCount > 0)
{
logger.warn(I18NUtil.getMessage(MSG_PATCH_SKIP2, alreadyMigratedCount));
}
logger.info(I18NUtil.getMessage(MSG_PATCH_COMPLETE, vhCount, ((System.currentTimeMillis()-startTime)/1000)));
return vhCount;
}
public void executeCleanup(final int batchSize)
{
if (! busy)
{
try
{
busy = true;
final RetryingTransactionHelper txHelper = transactionService.getRetryingTransactionHelper();
txHelper.setMaxRetries(1);
txHelper.doInTransaction(new RetryingTransactionCallback<Object>()
{
public Object execute() throws Throwable
{
NodeRef oldRootNodeRef = dbNodeService.getRootNode(VersionMigrator.VERSION_STORE_REF_OLD);
List<ChildAssociationRef> childAssocRefs = getVersionHistories(oldRootNodeRef);
int toDo = childAssocRefs.size();
if (toDo > 0)
{
if (logger.isDebugEnabled())
{
logger.debug("Found "+toDo+" version histories in old version store");
}
// note: assumes cleanup runs after patch has completed
startTime = System.currentTimeMillis();
percentComplete = 0;
int deletedCount = 0;
int failCount = 0;
int notMigratedCount = 0;
boolean wasMLAware = MLPropertyInterceptor.setMLAware(true);
SessionSizeResourceManager.setDisableInTransaction();
try
{
int batchCount = 0;
int totalCount = 0;
final List<NodeRef> tmpBatch = new ArrayList<NodeRef>(batchSize);
for (final ChildAssociationRef childAssocRef : childAssocRefs)
{
reportProgress(MSG_DELETE_PROGRESS, toDo, totalCount);
totalCount++;
if (((String)dbNodeService.getProperty(childAssocRef.getChildRef(), ContentModel.PROP_NAME)).startsWith(VersionMigrator.PREFIX_MIGRATED))
{
if (batchCount < batchSize)
{
tmpBatch.add(childAssocRef.getChildRef());
batchCount++;
}
if ((batchCount == batchSize) || (totalCount == childAssocRefs.size()))
{
while (tmpBatch.size() != 0)
{
txHelper.setMaxRetries(1);
NodeRef failed = txHelper.doInTransaction(new RetryingTransactionCallback<NodeRef>()
{
public NodeRef execute() throws Throwable
{
if (logger.isTraceEnabled())
{
logger.trace("Attempt to delete batch of "+tmpBatch.size()+" migrated version histories");
}
long startTime = System.currentTimeMillis();
for (NodeRef oldVHNodeRef : tmpBatch)
{
try
{
// delete old version history node
v1DeleteVersionHistory(oldVHNodeRef);
}
catch (Throwable t)
{
logger.error("Skipping deletion of: " + oldVHNodeRef, t);
return oldVHNodeRef;
}
}
if (logger.isDebugEnabled())
{
logger.debug("Deleted batch of "+tmpBatch.size()+" migrated version histories in "+(System.currentTimeMillis()-startTime)+ " ms");
}
return null;
}
}, false, true);
if (failed != null)
{
tmpBatch.remove(failed); // retry batch without the failed node
failCount++;
}
else
{
deletedCount = deletedCount + tmpBatch.size();
tmpBatch.clear();
batchCount = 0;
}
}
}
}
else
{
notMigratedCount++;
}
}
}
finally
{
MLPropertyInterceptor.setMLAware(wasMLAware);
SessionSizeResourceManager.setEnableInTransaction();
}
if (failCount > 0)
{
logger.warn(I18NUtil.getMessage(MSG_DELETE_SKIP1, failCount));
}
if (notMigratedCount > 0)
{
logger.warn(I18NUtil.getMessage(MSG_DELETE_SKIP2, notMigratedCount));
}
logger.info(I18NUtil.getMessage(MSG_DELETE_COMPLETE, deletedCount, ((System.currentTimeMillis()-startTime)/1000)));
}
return null;
}
}, true, true);
}
finally
{
busy = false;
}
}
}
/**
* Support to report % completion and estimated completion time.
*
* @param estimatedTotal
* @param currentInteration
*/
protected void reportProgress(String msgKey, long estimatedTotal, long currentInteration)
{
if (currentInteration == 0)
{
percentComplete = 0;
}
else if (currentInteration * 100l / estimatedTotal > percentComplete)
{
int previous = percentComplete;
percentComplete = (int) (currentInteration * 100l / estimatedTotal);
if (percentComplete < 100)
{
// conditional report
long currentTime = System.currentTimeMillis();
long timeSoFar = currentTime - startTime;
long timeRemaining = timeSoFar * (100 - percentComplete) / percentComplete;
int report = -1;
if (timeRemaining > 60000)
{
int reportInterval = getreportingInterval(timeSoFar, timeRemaining);
for (int i = previous + 1; i <= percentComplete; i++)
{
if (i % reportInterval == 0)
{
report = i;
}
}
if (report > 0)
{
Date end = new Date(currentTime + timeRemaining);
logger.info(I18NUtil.getMessage(msgKey, report, end));
}
}
}
}
}
private int getreportingInterval(long soFar, long toGo)
{
long total = soFar + toGo;
if (total < RANGE_10)
{
return 10;
}
else if (total < RANGE_5)
{
return 5;
}
else if (total < RANGE_2)
{
return 2;
}
else
{
return 1;
}
}
}

View File

@@ -0,0 +1,232 @@
/*
* Copyright (C) 2005-2007 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
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.repo.version;
import java.io.Serializable;
import java.util.Date;
import java.util.Map;
import java.util.Set;
import org.alfresco.repo.policy.PolicyComponent;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.version.Version;
import org.alfresco.service.cmr.version.VersionHistory;
import org.alfresco.service.namespace.QName;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Test simple version store migration
*/
public class VersionMigratorTest extends BaseVersionStoreTest
{
private static Log logger = LogFactory.getLog(VersionMigratorTest.class);
protected VersionServiceImpl version1Service = new VersionServiceImpl();
protected Version2ServiceImpl version2Service;
protected NodeService versionNodeService;
protected VersionMigrator versionMigrator;
protected PolicyComponent policyComponent;
protected DictionaryService dictionaryService;
public VersionMigratorTest()
{
//super.setDefaultRollback(false); // default is true
}
protected void onSetUpInTransaction() throws Exception
{
super.onSetUpInTransaction();
this.versionMigrator = (VersionMigrator)applicationContext.getBean("versionMigrator");
this.policyComponent = (PolicyComponent)applicationContext.getBean("policyComponent");
this.dictionaryService = (DictionaryService)applicationContext.getBean("dictionaryService");
this.version2Service = (Version2ServiceImpl)applicationContext.getBean("versionService");
this.versionNodeService = (NodeService)applicationContext.getBean("versionNodeService"); // note: auto-switches between V1 and V2
// Version1Service is used to create the version nodes in Version1Store (workspace://lightWeightVersionStore)
version1Service.setDbNodeService(dbNodeService);
version1Service.setNodeService(dbNodeService);
version1Service.setVersionCounterService(versionCounterDaoService);
version1Service.setPolicyComponent(policyComponent);
version1Service.setDictionaryService(dictionaryService);
version1Service.initialiseWithoutBind(); // TODO - temp - if use intialise, get: "More than one CalculateVersionLabelPolicy behaviour has been registered for the type {http://www.alfresco.org/model/content/1.0}content"
super.setVersionService(version1Service);
}
/**
* Test migration of a simple versioned node (one version, no children)
*/
public void testMigrateOneVersion() throws Exception
{
if (version2Service.useDeprecatedV1 == true)
{
logger.info("testMigrateOneVersion: skip");
return;
}
NodeRef versionableNode = createNewVersionableNode();
logger.info("testMigrateOneVersion: versionedNodeRef = " + versionableNode);
// Get the next version number
int nextVersion = peekNextVersionNumber();
String nextVersionLabel = peekNextVersionLabel(versionableNode, nextVersion, versionProperties);
// Snap-shot the date-time
Date beforeVersionDate = new Date();
long beforeVersionTime = beforeVersionDate.getTime();
logger.info("beforeVersion Date/Time: " + beforeVersionDate + " [" + beforeVersionTime + "]");
Version oldVersion = createVersion(versionableNode);
// get and store old version details for later comparison - versionNodeService will retrieve these from the old version store
QName oldVersionType = versionNodeService.getType(oldVersion.getFrozenStateNodeRef());
Set<QName> oldVersionAspects = versionNodeService.getAspects(oldVersion.getFrozenStateNodeRef());
Map<QName, Serializable> oldVersionProps = versionNodeService.getProperties(oldVersion.getFrozenStateNodeRef());
logger.info("oldVersion props: " + oldVersion);
logger.info("oldVersion created: " + oldVersion.getCreatedDate() + " [" + oldVersion.getCreatedDate().getTime()+"]");
logger.info("oldVersion props via versionNodeService: " + oldVersionProps);
VersionHistory vh = version1Service.getVersionHistory(versionableNode);
assertEquals(1, vh.getAllVersions().size());
NodeRef oldVHNodeRef = version1Service.getVersionHistoryNodeRef(versionableNode);
// Migrate and delete old version history !
NodeRef versionedNodeRef = versionMigrator.v1GetVersionedNodeRef(oldVHNodeRef);
NodeRef newVHNodeRef = versionMigrator.migrateVersionHistory(oldVHNodeRef, versionedNodeRef);
versionMigrator.v1DeleteVersionHistory(oldVHNodeRef);
VersionHistory vh2 = version2Service.getVersionHistory(versionableNode);
assertEquals(1, vh2.getAllVersions().size());
Version newVersion = vh2.getRootVersion();
logger.info("newVersion props: " + newVersion);
logger.info("newVersion created: " + newVersion.getCreatedDate() + " [" + newVersion.getCreatedDate().getTime()+"]");
// check new version - switch to new version service to do the check
super.setVersionService(version2Service);
checkNewVersion(beforeVersionTime, nextVersion, nextVersionLabel, newVersion, versionableNode);
// get and compare new version details - - versionNodeService will retrieve these from the new version store
QName newVersionType = versionNodeService.getType(newVersion.getFrozenStateNodeRef());
Set<QName> newVersionAspects = versionNodeService.getAspects(newVersion.getFrozenStateNodeRef());
Map<QName, Serializable> newVersionProps = versionNodeService.getProperties(newVersion.getFrozenStateNodeRef());
logger.info("newVersion props via versionNodeService: " + newVersionProps);
assertEquals(oldVersionType, newVersionType);
assertEquals(oldVersionAspects.size(), newVersionAspects.size());
for (QName key : oldVersionAspects)
{
assertTrue(""+key, newVersionAspects.contains(key));
}
assertEquals(oldVersionProps.size(), newVersionProps.size());
for (QName key : oldVersionProps.keySet())
{
assertEquals(""+key, oldVersionProps.get(key), newVersionProps.get(key));
}
logger.info("testMigrateOneVersion: Migrated from oldVHNodeRef = " + oldVHNodeRef + " to newVHNodeRef = " + newVHNodeRef);
}
/**
* Test migration of a multiple versioned nodes
*/
public void testMigrateMultipleVersions() throws Exception
{
if (version2Service.useDeprecatedV1 == true)
{
logger.info("testMigrateOneVersion: skip");
return;
}
NodeRef versionableNode = createNewVersionableNode();
// 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();
Version version1 = createVersion(versionableNode);
logger.info(version1);
// 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();
Version version2 = createVersion(versionableNode);
logger.info(version2);
// 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();
Version version3 = createVersion(versionableNode);
logger.info(version3);
VersionHistory vh1 = version1Service.getVersionHistory(versionableNode);
assertEquals(3, vh1.getAllVersions().size());
logger.info("testMigrateMultipleVersions: versionedNodeRef = " + versionableNode);
NodeRef oldVHNodeRef = version1Service.getVersionHistoryNodeRef(versionableNode);
// Migrate and delete old version history !
NodeRef versionedNodeRef = versionMigrator.v1GetVersionedNodeRef(oldVHNodeRef);
NodeRef newVHNodeRef = versionMigrator.migrateVersionHistory(oldVHNodeRef, versionedNodeRef);
versionMigrator.v1DeleteVersionHistory(oldVHNodeRef);
VersionHistory vh2 = version2Service.getVersionHistory(versionableNode);
assertEquals(3, vh2.getAllVersions().size());
// TODO move check version history into BaseVersionStoreTest
// check new versions - switch to new version service to do the check
super.setVersionService(version2Service);
Version[] newVersions = vh2.getAllVersions().toArray(new Version[]{});
checkVersion(beforeVersionTime1, nextVersion1, nextVersionLabel1, newVersions[2], versionableNode);
checkVersion(beforeVersionTime2, nextVersion2, nextVersionLabel2, newVersions[1], versionableNode);
checkNewVersion(beforeVersionTime3, nextVersion3, nextVersionLabel3, newVersions[0], versionableNode);
logger.info("testMigrateMultipleVersions: Migrated from oldVHNodeRef = " + oldVHNodeRef + " to newVHNodeRef = " + newVHNodeRef);
}
}

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2005-2007 Alfresco Software Limited. * Copyright (C) 2005-2008 Alfresco Software Limited.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@@ -24,60 +24,38 @@
*/ */
package org.alfresco.repo.version; package org.alfresco.repo.version;
import org.alfresco.model.ContentModel;
import org.alfresco.service.cmr.version.VersionService;
import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.QName;
/** /**
* interface conating the constants used by the light weight * Version1 Model Constants used by lightWeightVersionStore implementation
* version store implementation
* *
* @author Roy Wetherall * @author Roy Wetherall
*/ */
public interface VersionModel public interface VersionModel extends VersionBaseModel
{ {
/** /**
* Namespace * Namespace
*/ */
public static final String NAMESPACE_URI = "http://www.alfresco.org/model/versionstore/1.0"; public static final String NAMESPACE_URI = "http://www.alfresco.org/model/versionstore/1.0";
/**
* The store protocol
*/
public static final String STORE_PROTOCOL = VersionService.VERSION_STORE_PROTOCOL;
/** /**
* The store id * The store id
*/ */
public static final String STORE_ID = "lightWeightVersionStore"; public static final String STORE_ID = "lightWeightVersionStore";
public static final String PROP_VERSION_LABEL = "versionLabel";
public static final String PROP_CREATED_DATE = ContentModel.PROP_CREATED.getLocalName();
public static final String PROP_CREATOR = ContentModel.PROP_CREATOR.getLocalName();
public static final String PROP_VERSION_TYPE = "versionType";
public static final String PROP_VERSION_NUMBER = "versionNumber";
public static final String PROP_FROZEN_NODE_ID = "frozenNodeId";
public static final String PROP_FROZEN_NODE_TYPE = "frozenNodeType";
public static final String PROP_FROZEN_NODE_STORE_PROTOCOL = "frozenNodeStoreProtocol";
public static final String PROP_FROZEN_NODE_STORE_ID = "frozenNodeStoreId";
public static final String PROP_FROZEN_ASPECTS = "frozenAspects";
/** The version store root aspect */ /** The version store root aspect */
public static final QName ASPECT_VERSION_STORE_ROOT = QName.createQName(NAMESPACE_URI, "versionStoreRoot"); public static final QName ASPECT_VERSION_STORE_ROOT = QName.createQName(NAMESPACE_URI, ASPECT_LOCALNAME_VERSION_STORE_ROOT);
/** /**
* Version history type * Version history type
*/ */
public static final String TYPE_VERSION_HISTORY = "versionHistory";
public static final QName TYPE_QNAME_VERSION_HISTORY = QName.createQName(NAMESPACE_URI, TYPE_VERSION_HISTORY); public static final QName TYPE_QNAME_VERSION_HISTORY = QName.createQName(NAMESPACE_URI, TYPE_VERSION_HISTORY);
/** /**
* Version history properties and associations * Version history properties and associations
*/ */
public static final String PROP_VERSIONED_NODE_ID = "versionedNodeId";
public static final QName PROP_QNAME_VERSIONED_NODE_ID = QName.createQName(NAMESPACE_URI, PROP_VERSIONED_NODE_ID); public static final QName PROP_QNAME_VERSIONED_NODE_ID = QName.createQName(NAMESPACE_URI, PROP_VERSIONED_NODE_ID);
public static final QName ASSOC_ROOT_VERSION = QName.createQName(NAMESPACE_URI, "rootVersion"); public static final QName ASSOC_ROOT_VERSION = QName.createQName(NAMESPACE_URI, ASSOC_LOCALNAME_ROOT_VERSION);
/** /**
* Verison type * Verison type
@@ -88,6 +66,12 @@ public interface VersionModel
/** /**
* Version type properties and associations * Version type properties and associations
*/ */
public static final String PROP_FROZEN_NODE_ID = "frozenNodeId";
public static final String PROP_FROZEN_NODE_STORE_PROTOCOL = "frozenNodeStoreProtocol";
public static final String PROP_FROZEN_NODE_STORE_ID = "frozenNodeStoreId";
public static final String PROP_FROZEN_NODE_TYPE = "frozenNodeType";
public static final String PROP_FROZEN_ASPECTS = "frozenAspects";
public static final QName PROP_QNAME_VERSION_LABEL = QName.createQName(NAMESPACE_URI, PROP_VERSION_LABEL); public static final QName PROP_QNAME_VERSION_LABEL = QName.createQName(NAMESPACE_URI, PROP_VERSION_LABEL);
public static final QName PROP_QNAME_VERSION_NUMBER = QName.createQName(NAMESPACE_URI, PROP_VERSION_NUMBER); public static final QName PROP_QNAME_VERSION_NUMBER = QName.createQName(NAMESPACE_URI, PROP_VERSION_NUMBER);
public static final QName PROP_QNAME_FROZEN_NODE_ID = QName.createQName(NAMESPACE_URI, PROP_FROZEN_NODE_ID); public static final QName PROP_QNAME_FROZEN_NODE_ID = QName.createQName(NAMESPACE_URI, PROP_FROZEN_NODE_ID);
@@ -156,8 +140,6 @@ public interface VersionModel
/** /**
* Child relationship names * Child relationship names
*/ */
public static final String CHILD_VERSION_HISTORIES = "versionHistory";
public static final String CHILD_VERSIONS = "version";
public static final String CHILD_VERSIONED_ATTRIBUTES = "versionedAttributes"; public static final String CHILD_VERSIONED_ATTRIBUTES = "versionedAttributes";
public static final String CHILD_VERSIONED_CHILD_ASSOCS = "versionedChildAssocs"; public static final String CHILD_VERSIONED_CHILD_ASSOCS = "versionedChildAssocs";
public static final String CHILD_VERSIONED_ASSOCS = "versionedAssocs"; public static final String CHILD_VERSIONED_ASSOCS = "versionedAssocs";
@@ -173,7 +155,5 @@ public interface VersionModel
/** /**
* Created version associated to the deleted translations of an mlContainer * Created version associated to the deleted translations of an mlContainer
*/ */
public static final String PROP_TRANSLATION_VERIONS = "translationVersions"; public static final QName PROP_QNAME_TRANSLATION_VERSIONS = QName.createQName(VersionModel.NAMESPACE_URI, PROP_TRANSLATION_VERSIONS);
public static final QName PROP_QNAME_TRANSLATION_VERIONS = QName.createQName(VersionModel.NAMESPACE_URI, PROP_TRANSLATION_VERIONS);
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2005-2007 Alfresco Software Limited. * Copyright (C) 2005-2008 Alfresco Software Limited.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@@ -34,6 +34,7 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import org.alfresco.model.ContentModel; import org.alfresco.model.ContentModel;
import org.alfresco.repo.node.MLPropertyInterceptor;
import org.alfresco.repo.policy.BehaviourFilter; import org.alfresco.repo.policy.BehaviourFilter;
import org.alfresco.repo.policy.JavaBehaviour; import org.alfresco.repo.policy.JavaBehaviour;
import org.alfresco.repo.policy.PolicyScope; import org.alfresco.repo.policy.PolicyScope;
@@ -43,6 +44,9 @@ import org.alfresco.repo.version.common.VersionImpl;
import org.alfresco.repo.version.common.VersionUtil; import org.alfresco.repo.version.common.VersionUtil;
import org.alfresco.repo.version.common.counter.VersionCounterService; import org.alfresco.repo.version.common.counter.VersionCounterService;
import org.alfresco.repo.version.common.versionlabel.SerialVersionLabelPolicy; import org.alfresco.repo.version.common.versionlabel.SerialVersionLabelPolicy;
import org.alfresco.service.cmr.dictionary.AssociationDefinition;
import org.alfresco.service.cmr.dictionary.ClassDefinition;
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
import org.alfresco.service.cmr.repository.AspectMissingException; import org.alfresco.service.cmr.repository.AspectMissingException;
import org.alfresco.service.cmr.repository.AssociationRef; import org.alfresco.service.cmr.repository.AssociationRef;
import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.ChildAssociationRef;
@@ -59,29 +63,32 @@ import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern; import org.alfresco.service.namespace.RegexQNamePattern;
import org.alfresco.util.ParameterCheck; import org.alfresco.util.ParameterCheck;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/** /**
* The version service implementation. * Version1 Service - implements lightWeightVersionStore
* *
* @author Roy Wetheral * @author Roy Wetheral
*/ */
public class VersionServiceImpl extends AbstractVersionServiceImpl public class VersionServiceImpl extends AbstractVersionServiceImpl implements VersionService, VersionModel
implements VersionService, VersionModel
{ {
private static Log logger = LogFactory.getLog(VersionServiceImpl.class);
/** /**
* Error message I18N id's * Error message I18N id's
*/ */
private static final String MSGID_ERR_NOT_FOUND = "version_service.err_not_found"; protected static final String MSGID_ERR_NOT_FOUND = "version_service.err_not_found";
private static final String MSGID_ERR_NO_BRANCHES = "version_service.err_unsupported"; protected static final String MSGID_ERR_NO_BRANCHES = "version_service.err_unsupported";
private static final String MSGID_ERR_RESTORE_EXISTS = "version_service.err_restore_exists"; protected static final String MSGID_ERR_RESTORE_EXISTS = "version_service.err_restore_exists";
private static final String MSGID_ERR_ONE_PRECEEDING = "version_service.err_one_preceeding"; protected static final String MSGID_ERR_ONE_PRECEEDING = "version_service.err_one_preceeding";
private static final String MSGID_ERR_RESTORE_NO_VERSION = "version_service.err_restore_no_version"; protected static final String MSGID_ERR_RESTORE_NO_VERSION = "version_service.err_restore_no_version";
private static final String MSGID_ERR_REVERT_MISMATCH = "version_service.err_revert_mismatch"; protected static final String MSGID_ERR_REVERT_MISMATCH = "version_service.err_revert_mismatch";
/** /**
* The version counter service * The version counter service
*/ */
private VersionCounterService versionCounterService; protected VersionCounterService versionCounterService;
/** /**
* The db node service, used as the version store implementation * The db node service, used as the version store implementation
@@ -91,13 +98,12 @@ public class VersionServiceImpl extends AbstractVersionServiceImpl
/** /**
* Policy behaviour filter * Policy behaviour filter
*/ */
private BehaviourFilter policyBehaviourFilter; protected BehaviourFilter policyBehaviourFilter;
/** /**
* The repository searcher * The repository searcher
*/ */
@SuppressWarnings("unused") protected SearchService searcher; // unused
private SearchService searcher;
/** /**
* Sets the db node service, used as the version store implementation * Sets the db node service, used as the version store implementation
@@ -156,11 +162,18 @@ public class VersionServiceImpl extends AbstractVersionServiceImpl
new JavaBehaviour(new SerialVersionLabelPolicy(), "calculateVersionLabel")); new JavaBehaviour(new SerialVersionLabelPolicy(), "calculateVersionLabel"));
} }
// TODO - temp
protected void initialiseWithoutBind()
{
super.initialise();
}
/** /**
* Gets the reference to the version store * Gets the reference to the version store
* *
* @return reference to the version store * @return reference to the version store
*/ */
@Override
public StoreRef getVersionStoreReference() public StoreRef getVersionStoreReference()
{ {
return new StoreRef( return new StoreRef(
@@ -176,11 +189,20 @@ public class VersionServiceImpl extends AbstractVersionServiceImpl
Map<String, Serializable> versionProperties) Map<String, Serializable> versionProperties)
throws ReservedVersionNameException, AspectMissingException throws ReservedVersionNameException, AspectMissingException
{ {
long startTime = System.currentTimeMillis();
// Get the next version number // Get the next version number
int versionNumber = this.versionCounterService.nextVersionNumber(getVersionStoreReference()); int versionNumber = this.versionCounterService.nextVersionNumber(getVersionStoreReference());
// Create the version // Create the version
return createVersion(nodeRef, versionProperties, versionNumber); Version version = createVersion(nodeRef, versionProperties, versionNumber);
if (logger.isDebugEnabled())
{
logger.debug("created version (" + versionNumber + " - " + VersionUtil.convertNodeRef(version.getFrozenStateNodeRef()) + ") in " + (System.currentTimeMillis()-startTime) + " ms");
}
return version;
} }
/** /**
@@ -194,11 +216,22 @@ public class VersionServiceImpl extends AbstractVersionServiceImpl
boolean versionChildren) boolean versionChildren)
throws ReservedVersionNameException, AspectMissingException throws ReservedVersionNameException, AspectMissingException
{ {
long startTime = System.currentTimeMillis();
// Get the next version number // Get the next version number
int versionNumber = this.versionCounterService.nextVersionNumber(getVersionStoreReference()); int versionNumber = this.versionCounterService.nextVersionNumber(getVersionStoreReference());
// Create the versions // Create the versions
return createVersion(nodeRef, versionProperties, versionChildren, versionNumber); Collection<Version> versions = createVersion(nodeRef, versionProperties, versionChildren, versionNumber);
if (logger.isDebugEnabled())
{
Version[] versionsArray = versions.toArray(new Version[0]);
Version version = versionsArray[versionsArray.length -1]; // last item is the new parent version
logger.debug("created version (" + versionNumber + " - " + VersionUtil.convertNodeRef(version.getFrozenStateNodeRef()) + ") in "+ (System.currentTimeMillis()-startTime) +" ms "+(versionChildren ? "(with " + (versions.size() - 1) + " children)" : ""));
}
return versions;
} }
/** /**
@@ -257,6 +290,8 @@ public class VersionServiceImpl extends AbstractVersionServiceImpl
Map<String, Serializable> versionProperties) Map<String, Serializable> versionProperties)
throws ReservedVersionNameException, AspectMissingException throws ReservedVersionNameException, AspectMissingException
{ {
long startTime = System.currentTimeMillis();
Collection<Version> result = new ArrayList<Version>(nodeRefs.size()); Collection<Version> result = new ArrayList<Version>(nodeRefs.size());
// Get the next version number // Get the next version number
@@ -268,6 +303,11 @@ public class VersionServiceImpl extends AbstractVersionServiceImpl
result.add(createVersion(nodeRef, versionProperties, versionNumber)); result.add(createVersion(nodeRef, versionProperties, versionNumber));
} }
if (logger.isDebugEnabled())
{
logger.debug("created version list (" + versionNumber + " - " + getVersionStoreReference() + ") in "+ (System.currentTimeMillis()-startTime) +" ms (with " + nodeRefs.size() + " nodes)");
}
return result; return result;
} }
@@ -282,12 +322,13 @@ public class VersionServiceImpl extends AbstractVersionServiceImpl
* @throws ReservedVersionNameException * @throws ReservedVersionNameException
* thrown if there is a name clash in the version properties * thrown if there is a name clash in the version properties
*/ */
private Version createVersion( protected Version createVersion(
NodeRef nodeRef, NodeRef nodeRef,
Map<String, Serializable> origVersionProperties, Map<String, Serializable> origVersionProperties,
int versionNumber) int versionNumber)
throws ReservedVersionNameException throws ReservedVersionNameException
{ {
long startTime = System.currentTimeMillis();
// Copy the version properties (to prevent unexpected side effects to the caller) // Copy the version properties (to prevent unexpected side effects to the caller)
Map<String, Serializable> versionProperties = new HashMap<String, Serializable>(); Map<String, Serializable> versionProperties = new HashMap<String, Serializable>();
@@ -370,7 +411,7 @@ public class VersionServiceImpl extends AbstractVersionServiceImpl
} }
// Create the version data object // Create the version data object
Version version = getVersion(newVersionRef); Version version = this.getVersion(newVersionRef);
// Set the new version label on the versioned node // Set the new version label on the versioned node
this.nodeService.setProperty( this.nodeService.setProperty(
@@ -386,6 +427,11 @@ public class VersionServiceImpl extends AbstractVersionServiceImpl
// Invoke the policy behaviour // Invoke the policy behaviour
invokeAfterCreateVersion(nodeRef, version); invokeAfterCreateVersion(nodeRef, version);
if (logger.isTraceEnabled())
{
logger.trace("created Version (" + versionNumber + " - " + getVersionStoreReference() + ") " + nodeRef + " in " + (System.currentTimeMillis()-startTime) +" ms");
}
// Return the data object representing the newly created version // Return the data object representing the newly created version
return version; return version;
} }
@@ -465,30 +511,30 @@ public class VersionServiceImpl extends AbstractVersionServiceImpl
Map<QName, Serializable> result = new HashMap<QName, Serializable>(10); Map<QName, Serializable> result = new HashMap<QName, Serializable>(10);
// Set the version number for the new version // Set the version number for the new version
result.put(QName.createQName(NAMESPACE_URI, VersionModel.PROP_VERSION_NUMBER), Integer.toString(versionNumber)); result.put(VersionModel.PROP_QNAME_VERSION_NUMBER, Integer.toString(versionNumber));
// Set the versionable node id // Set the versionable node id
result.put(QName.createQName(NAMESPACE_URI, VersionModel.PROP_FROZEN_NODE_ID), nodeRef.getId()); result.put(VersionModel.PROP_QNAME_FROZEN_NODE_ID, nodeRef.getId());
// Set the versionable node store protocol // Set the versionable node store protocol
result.put(QName.createQName(NAMESPACE_URI, VersionModel.PROP_FROZEN_NODE_STORE_PROTOCOL), nodeRef.getStoreRef().getProtocol()); result.put(VersionModel.PROP_QNAME_FROZEN_NODE_STORE_PROTOCOL, nodeRef.getStoreRef().getProtocol());
// Set the versionable node store id // Set the versionable node store id
result.put(QName.createQName(NAMESPACE_URI, VersionModel.PROP_FROZEN_NODE_STORE_ID), nodeRef.getStoreRef().getIdentifier()); result.put(VersionModel.PROP_QNAME_FROZEN_NODE_STORE_ID, nodeRef.getStoreRef().getIdentifier());
// Store the current node type // Store the current node type
QName nodeType = this.nodeService.getType(nodeRef); QName nodeType = this.nodeService.getType(nodeRef);
result.put(QName.createQName(NAMESPACE_URI, VersionModel.PROP_FROZEN_NODE_TYPE), nodeType); result.put(VersionModel.PROP_QNAME_FROZEN_NODE_TYPE, nodeType);
// Store the current aspects // Store the current aspects
Set<QName> aspects = this.nodeService.getAspects(nodeRef); Set<QName> aspects = this.nodeService.getAspects(nodeRef);
result.put(QName.createQName(NAMESPACE_URI, VersionModel.PROP_FROZEN_ASPECTS), (Serializable)aspects); result.put(VersionModel.PROP_QNAME_FROZEN_ASPECTS, (Serializable)aspects);
// Calculate the version label // Calculate the version label
QName classRef = this.nodeService.getType(nodeRef); QName classRef = this.nodeService.getType(nodeRef);
Version preceedingVersion = getVersion(preceedingNodeRef); Version preceedingVersion = getVersion(preceedingNodeRef);
String versionLabel = invokeCalculateVersionLabel(classRef, preceedingVersion, versionNumber, versionProperties); String versionLabel = invokeCalculateVersionLabel(classRef, preceedingVersion, versionNumber, versionProperties);
result.put(QName.createQName(NAMESPACE_URI, VersionModel.PROP_VERSION_LABEL), versionLabel); result.put(VersionModel.PROP_QNAME_VERSION_LABEL, versionLabel);
return result; return result;
} }
@@ -557,6 +603,27 @@ public class VersionServiceImpl extends AbstractVersionServiceImpl
} }
} }
protected Map<String, Serializable> getVersionMetaData(NodeRef versionNodeRef)
{
// Get the meta data
List<ChildAssociationRef> metaData = this.dbNodeService.getChildAssocs(
versionNodeRef,
RegexQNamePattern.MATCH_ALL,
CHILD_QNAME_VERSION_META_DATA);
Map<String, Serializable> versionProperties = new HashMap<String, Serializable>(metaData.size());
for (ChildAssociationRef ref : metaData)
{
NodeRef metaDataValue = (NodeRef)ref.getChildRef();
String name = (String)this.dbNodeService.getProperty(metaDataValue, PROP_QNAME_META_DATA_NAME);
Serializable value = this.dbNodeService.getProperty(metaDataValue, PROP_QNAME_META_DATA_VALUE);
versionProperties.put(name, value);
}
return versionProperties;
}
/** /**
* Freeze the aspects * Freeze the aspects
* *
@@ -675,7 +742,7 @@ public class VersionServiceImpl extends AbstractVersionServiceImpl
* *
* @return the node ref to the root node of the version store * @return the node ref to the root node of the version store
*/ */
private NodeRef getRootNode() protected NodeRef getRootNode()
{ {
// Get the version store root node reference // Get the version store root node reference
return this.dbNodeService.getRootNode(getVersionStoreReference()); return this.dbNodeService.getRootNode(getVersionStoreReference());
@@ -691,12 +758,21 @@ public class VersionServiceImpl extends AbstractVersionServiceImpl
* @param nodeRef the node reference * @param nodeRef the node reference
* @return a constructed version history object * @return a constructed version history object
*/ */
private VersionHistory buildVersionHistory(NodeRef versionHistoryRef, NodeRef nodeRef) protected VersionHistory buildVersionHistory(NodeRef versionHistoryRef, NodeRef nodeRef)
{ {
VersionHistory versionHistory = null; VersionHistory versionHistory = null;
ArrayList<NodeRef> versionHistoryNodeRefs = new ArrayList<NodeRef>(); ArrayList<NodeRef> versionHistoryNodeRefs = new ArrayList<NodeRef>();
NodeRef currentVersion = getCurrentVersionNodeRef(versionHistoryRef, nodeRef);
NodeRef currentVersion;
if (this.nodeService.exists(nodeRef))
{
currentVersion = getCurrentVersionNodeRef(versionHistoryRef, nodeRef);
}
else
{
currentVersion = VersionUtil.convertNodeRef(getLatestVersion(nodeRef).getFrozenStateNodeRef());
}
while (currentVersion != null) while (currentVersion != null)
{ {
@@ -751,7 +827,7 @@ public class VersionServiceImpl extends AbstractVersionServiceImpl
* @param versionRef the version reference * @param versionRef the version reference
* @return object containing verison data * @return object containing verison data
*/ */
private Version getVersion(NodeRef versionRef) protected Version getVersion(NodeRef versionRef)
{ {
if (versionRef == null) if (versionRef == null)
{ {
@@ -768,17 +844,8 @@ public class VersionServiceImpl extends AbstractVersionServiceImpl
} }
// Get the meta data // Get the meta data
List<ChildAssociationRef> metaData = this.dbNodeService.getChildAssocs( Map<String, Serializable> versionMetaDataProperties = getVersionMetaData(versionRef);
versionRef, versionProperties.putAll(versionMetaDataProperties);
RegexQNamePattern.MATCH_ALL,
CHILD_QNAME_VERSION_META_DATA);
for (ChildAssociationRef ref : metaData)
{
NodeRef metaDataValue = (NodeRef)ref.getChildRef();
String name = (String)this.dbNodeService.getProperty(metaDataValue, PROP_QNAME_META_DATA_NAME);
Serializable value = this.dbNodeService.getProperty(metaDataValue, PROP_QNAME_META_DATA_VALUE);
versionProperties.put(name, value);
}
// Create and return the version object // Create and return the version object
NodeRef newNodeRef = new NodeRef(new StoreRef(STORE_PROTOCOL, STORE_ID), versionRef.getId()); NodeRef newNodeRef = new NodeRef(new StoreRef(STORE_PROTOCOL, STORE_ID), versionRef.getId());
@@ -793,7 +860,7 @@ public class VersionServiceImpl extends AbstractVersionServiceImpl
* @param nodeRef a node reference * @param nodeRef a node reference
* @return a reference to the version history node, null of none * @return a reference to the version history node, null of none
*/ */
private NodeRef getVersionHistoryNodeRef(NodeRef nodeRef) protected NodeRef getVersionHistoryNodeRef(NodeRef nodeRef)
{ {
return this.dbNodeService.getChildByName(getRootNode(), CHILD_QNAME_VERSION_HISTORIES, nodeRef.getId()); return this.dbNodeService.getChildByName(getRootNode(), CHILD_QNAME_VERSION_HISTORIES, nodeRef.getId());
} }
@@ -1086,6 +1153,39 @@ public class VersionServiceImpl extends AbstractVersionServiceImpl
return version; return version;
} }
private Version getLatestVersion(NodeRef nodeRef)
{
Version version = null;
StoreRef storeRef = nodeRef.getStoreRef();
NodeRef versionHistoryNodeRef = getVersionHistoryNodeRef(nodeRef);
if (versionHistoryNodeRef != null)
{
List<ChildAssociationRef> versionsAssoc = this.dbNodeService.getChildAssocs(versionHistoryNodeRef, RegexQNamePattern.MATCH_ALL, VersionModel.CHILD_QNAME_VERSIONS);
for (ChildAssociationRef versionAssoc : versionsAssoc)
{
NodeRef versionNodeRef = versionAssoc.getChildRef();
List<AssociationRef> predecessors = this.dbNodeService.getSourceAssocs(versionNodeRef, VersionModel.ASSOC_SUCCESSOR);
if (predecessors.size() == 0)
{
String storeProtocol = (String)this.dbNodeService.getProperty(
versionNodeRef,
QName.createQName(NAMESPACE_URI, VersionModel.PROP_FROZEN_NODE_STORE_PROTOCOL));
String storeId = (String)this.dbNodeService.getProperty(
versionNodeRef,
QName.createQName(NAMESPACE_URI, VersionModel.PROP_FROZEN_NODE_STORE_ID));
StoreRef versionStoreRef = new StoreRef(storeProtocol, storeId);
if (storeRef.equals(versionStoreRef) == true)
{
version = getVersion(versionNodeRef);
}
}
}
}
return version;
}
/** /**
* @see org.alfresco.cms.version.VersionService#deleteVersionHistory(NodeRef) * @see org.alfresco.cms.version.VersionService#deleteVersionHistory(NodeRef)
*/ */
@@ -1107,4 +1207,58 @@ public class VersionServiceImpl extends AbstractVersionServiceImpl
} }
} }
} }
@Override
protected void defaultOnCreateVersion(
QName classRef,
NodeRef nodeRef,
Map<String, Serializable> versionProperties,
PolicyScope nodeDetails)
{
ClassDefinition classDefinition = this.dictionaryService.getClass(classRef);
if (classDefinition != null)
{
boolean wasMLAware = MLPropertyInterceptor.setMLAware(true);
try
{
// Copy the properties
Map<QName,PropertyDefinition> propertyDefinitions = classDefinition.getProperties();
for (QName propertyName : propertyDefinitions.keySet())
{
Serializable propValue = this.nodeService.getProperty(nodeRef, propertyName);
nodeDetails.addProperty(classRef, propertyName, propValue);
}
}
finally
{
MLPropertyInterceptor.setMLAware(wasMLAware);
}
// Version the associations (child and target)
Map<QName, AssociationDefinition> assocDefs = classDefinition.getAssociations();
// TODO: Need way of getting child assocs of a given type
if (classDefinition.isContainer())
{
List<ChildAssociationRef> childAssocRefs = this.nodeService.getChildAssocs(nodeRef);
for (ChildAssociationRef childAssocRef : childAssocRefs)
{
if (assocDefs.containsKey(childAssocRef.getTypeQName()))
{
nodeDetails.addChildAssociation(classDefinition.getName(), childAssocRef);
}
}
}
// TODO: Need way of getting assocs of a given type
List<AssociationRef> nodeAssocRefs = this.nodeService.getTargetAssocs(nodeRef, RegexQNamePattern.MATCH_ALL);
for (AssociationRef nodeAssocRef : nodeAssocRefs)
{
if (assocDefs.containsKey(nodeAssocRef.getTypeQName()))
{
nodeDetails.addAssociation(classDefinition.getName(), nodeAssocRef);
}
}
}
}
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2005-2007 Alfresco Software Limited. * Copyright (C) 2005-2008 Alfresco Software Limited.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@@ -70,6 +70,11 @@ public class VersionServiceImplTest extends BaseVersionStoreTest
private static final String UPDATED_CONTENT_1 = "updatedContent1"; private static final String UPDATED_CONTENT_1 = "updatedContent1";
private static final String UPDATED_CONTENT_2 = "updatedContent2"; private static final String UPDATED_CONTENT_2 = "updatedContent2";
public void testSetup()
{
// NOOP
}
/** /**
* Tests the creation of the initial version of a versionable node * Tests the creation of the initial version of a versionable node
*/ */
@@ -90,9 +95,39 @@ public class VersionServiceImplTest extends BaseVersionStoreTest
createVersion(versionableNode); createVersion(versionableNode);
// TODO mess with some of the properties and stuff as you version // TODO mess with some of the properties and stuff as you version
createVersion(versionableNode); createVersion(versionableNode);
VersionHistory vh = this.versionService.getVersionHistory(versionableNode);
assertNotNull(vh);
assertEquals(3, vh.getAllVersions().size());
// TODO check list of versions ... !
} }
// TODO test versioning a non versionable node ie: no version apsect /**
* Tests the creation of multiple versions of a versionable node with null version properties
*/
public void testCreateManyVersionsWithNullVersionProperties()
{
this.versionProperties = null;
NodeRef versionableNode = createNewVersionableNode();
createVersion(versionableNode);
createVersion(versionableNode);
createVersion(versionableNode);
VersionHistory vh = this.versionService.getVersionHistory(versionableNode);
assertNotNull(vh);
assertEquals(3, vh.getAllVersions().size());
}
/**
* Test versioning a non versionable node ie: no version apsect
*/
public void testCreateInitialVersionWhenNotVersionable()
{
NodeRef node = createNewNode(); // not marked as versionable
createVersion(node);
}
// TODO test versioning numberious times with branchs implies by different workspaces // TODO test versioning numberious times with branchs implies by different workspaces
@@ -155,15 +190,28 @@ public class VersionServiceImplTest extends BaseVersionStoreTest
for (Version version : versions) for (Version version : versions)
{ {
// Get the frozen id from the version // Get the frozen id from the version
String frozenNodeId = (String)version.getVersionProperty(VersionModel.PROP_FROZEN_NODE_ID); String frozenNodeId = null;
// Switch VersionStore depending on configured impl
if (versionService.getVersionStoreReference().getIdentifier().equals(Version2Model.STORE_ID))
{
// V2 version store (eg. workspace://version2Store)
frozenNodeId = ((NodeRef)version.getVersionProperty(Version2Model.PROP_FROZEN_NODE_REF)).getId();
}
else if (versionService.getVersionStoreReference().getIdentifier().equals(VersionModel.STORE_ID))
{
// Deprecated V1 version store (eg. workspace://lightWeightVersionStore)
frozenNodeId = (String)version.getVersionProperty(VersionModel.PROP_FROZEN_NODE_ID);
}
assertNotNull("Unable to retrieve the frozen node id from the created version.", frozenNodeId); assertNotNull("Unable to retrieve the frozen node id from the created version.", frozenNodeId);
// Get the origional node ref (based on the forzen node) // Get the origional node ref (based on the forzen node)
NodeRef origionaNodeRef = this.versionableNodes.get(frozenNodeId); NodeRef originalNodeRef = this.versionableNodes.get(frozenNodeId);
assertNotNull("The versionable node ref that relates to the frozen node id can not be found.", origionaNodeRef); assertNotNull("The versionable node ref that relates to the frozen node id can not be found.", originalNodeRef);
// Check the new version // Check the new version
checkNewVersion(beforeVersionTime, expectedVersionNumber, expectedVersionLabel, version, origionaNodeRef); checkNewVersion(beforeVersionTime, expectedVersionNumber, expectedVersionLabel, version, originalNodeRef);
} }
} }
@@ -476,12 +524,12 @@ public class VersionServiceImplTest extends BaseVersionStoreTest
public Object execute() throws Exception public Object execute() throws Exception
{ {
// Check that the initial version has not been created // Check that the initial version has not been created
VersionHistory versionHistory = VersionServiceImplTest.this.versionService.getVersionHistory(versionableNode); VersionHistory versionHistory = versionService.getVersionHistory(versionableNode);
assertNotNull(versionHistory); assertNotNull(versionHistory);
assertEquals(1, versionHistory.getAllVersions().size()); assertEquals(1, versionHistory.getAllVersions().size());
// Add some content // Add some content
ContentWriter contentWriter = VersionServiceImplTest.this.contentService.getWriter(versionableNode, ContentModel.PROP_CONTENT, true); ContentWriter contentWriter = contentService.getWriter(versionableNode, ContentModel.PROP_CONTENT, true);
assertNotNull(contentWriter); assertNotNull(contentWriter);
contentWriter.putContent(UPDATED_CONTENT_1); contentWriter.putContent(UPDATED_CONTENT_1);
@@ -494,7 +542,7 @@ public class VersionServiceImplTest extends BaseVersionStoreTest
{ {
public Object execute() throws Exception public Object execute() throws Exception
{ {
VersionHistory versionHistory = VersionServiceImplTest.this.versionService.getVersionHistory(versionableNode); VersionHistory versionHistory = versionService.getVersionHistory(versionableNode);
assertNotNull(versionHistory); assertNotNull(versionHistory);
assertEquals(2, versionHistory.getAllVersions().size()); assertEquals(2, versionHistory.getAllVersions().size());
@@ -520,7 +568,7 @@ public class VersionServiceImplTest extends BaseVersionStoreTest
public Object execute() throws Exception public Object execute() throws Exception
{ {
// Add some content // Add some content
ContentWriter contentWriter = VersionServiceImplTest.this.contentService.getWriter(versionableNode, ContentModel.PROP_CONTENT, true); ContentWriter contentWriter = contentService.getWriter(versionableNode, ContentModel.PROP_CONTENT, true);
assertNotNull(contentWriter); assertNotNull(contentWriter);
contentWriter.putContent(UPDATED_CONTENT_1); contentWriter.putContent(UPDATED_CONTENT_1);
@@ -533,7 +581,7 @@ public class VersionServiceImplTest extends BaseVersionStoreTest
{ {
public Object execute() throws Exception public Object execute() throws Exception
{ {
VersionHistory versionHistory = VersionServiceImplTest.this.versionService.getVersionHistory(versionableNode); VersionHistory versionHistory = versionService.getVersionHistory(versionableNode);
assertNotNull(versionHistory); assertNotNull(versionHistory);
assertEquals(1, versionHistory.getAllVersions().size()); assertEquals(1, versionHistory.getAllVersions().size());
@@ -567,7 +615,7 @@ public class VersionServiceImplTest extends BaseVersionStoreTest
{ {
public Object execute() throws Exception public Object execute() throws Exception
{ {
VersionHistory versionHistory = VersionServiceImplTest.this.versionService.getVersionHistory(nodeRef); VersionHistory versionHistory = versionService.getVersionHistory(nodeRef);
assertNull(versionHistory); assertNull(versionHistory);
return null; return null;
@@ -596,12 +644,12 @@ public class VersionServiceImplTest extends BaseVersionStoreTest
public Object execute() throws Exception public Object execute() throws Exception
{ {
// Check that the version history has been created // Check that the version history has been created
VersionHistory versionHistory = VersionServiceImplTest.this.versionService.getVersionHistory(nodeRef); VersionHistory versionHistory = versionService.getVersionHistory(nodeRef);
assertNotNull(versionHistory); assertNotNull(versionHistory);
assertEquals(1, versionHistory.getAllVersions().size()); assertEquals(1, versionHistory.getAllVersions().size());
// Remove the versionable aspect // Remove the versionable aspect
VersionServiceImplTest.this.dbNodeService.removeAspect(nodeRef, ContentModel.ASPECT_VERSIONABLE); dbNodeService.removeAspect(nodeRef, ContentModel.ASPECT_VERSIONABLE);
return null; return null;
} }
@@ -612,11 +660,11 @@ public class VersionServiceImplTest extends BaseVersionStoreTest
public Object execute() throws Exception public Object execute() throws Exception
{ {
// Check that the version history has been removed // Check that the version history has been removed
VersionHistory versionHistory = VersionServiceImplTest.this.versionService.getVersionHistory(nodeRef); VersionHistory versionHistory = versionService.getVersionHistory(nodeRef);
assertNull(versionHistory); assertNull(versionHistory);
// Re-add the versionable aspect // Re-add the versionable aspect
VersionServiceImplTest.this.dbNodeService.addAspect(nodeRef, ContentModel.ASPECT_VERSIONABLE, null); dbNodeService.addAspect(nodeRef, ContentModel.ASPECT_VERSIONABLE, null);
return null; return null;
} }
@@ -627,7 +675,7 @@ public class VersionServiceImplTest extends BaseVersionStoreTest
public Object execute() throws Exception public Object execute() throws Exception
{ {
// Check that the version history has been created // Check that the version history has been created
VersionHistory versionHistory = VersionServiceImplTest.this.versionService.getVersionHistory(nodeRef); VersionHistory versionHistory = versionService.getVersionHistory(nodeRef);
assertNotNull(versionHistory); assertNotNull(versionHistory);
assertEquals(1, versionHistory.getAllVersions().size()); assertEquals(1, versionHistory.getAllVersions().size());
@@ -658,12 +706,12 @@ public class VersionServiceImplTest extends BaseVersionStoreTest
{ {
public Object execute() throws Exception public Object execute() throws Exception
{ {
VersionHistory versionHistory = VersionServiceImplTest.this.versionService.getVersionHistory(nodeRef); VersionHistory versionHistory = versionService.getVersionHistory(nodeRef);
assertNotNull(versionHistory); assertNotNull(versionHistory);
assertEquals(1, versionHistory.getAllVersions().size()); assertEquals(1, versionHistory.getAllVersions().size());
// Delete the node // Delete the node
VersionServiceImplTest.this.dbNodeService.deleteNode(nodeRef); dbNodeService.deleteNode(nodeRef);
return null; return null;
} }
@@ -674,15 +722,15 @@ public class VersionServiceImplTest extends BaseVersionStoreTest
public Object execute() throws Exception public Object execute() throws Exception
{ {
// Get the archived noderef // Get the archived noderef
NodeRef archivedNodeRef = VersionServiceImplTest.this.nodeArchiveService.getArchivedNode(nodeRef); NodeRef archivedNodeRef = nodeArchiveService.getArchivedNode(nodeRef);
// The archived noderef should still have a link to the version history // The archived noderef should still have a link to the version history
VersionHistory versionHistory = VersionServiceImplTest.this.versionService.getVersionHistory(archivedNodeRef); VersionHistory versionHistory = versionService.getVersionHistory(archivedNodeRef);
assertNotNull(versionHistory); assertNotNull(versionHistory);
assertEquals(1, versionHistory.getAllVersions().size()); assertEquals(1, versionHistory.getAllVersions().size());
// Delete the node for good // Delete the node for good
VersionServiceImplTest.this.dbNodeService.deleteNode(archivedNodeRef); dbNodeService.deleteNode(archivedNodeRef);
return null; return null;
} }
@@ -693,12 +741,12 @@ public class VersionServiceImplTest extends BaseVersionStoreTest
public Object execute() throws Exception public Object execute() throws Exception
{ {
// Get the archived noderef // Get the archived noderef
NodeRef archivedNodeRef = VersionServiceImplTest.this.nodeArchiveService.getArchivedNode(nodeRef); NodeRef archivedNodeRef = nodeArchiveService.getArchivedNode(nodeRef);
// Check that the version histories have been deleted // Check that the version histories have been deleted
VersionHistory versionHistory12 = VersionServiceImplTest.this.versionService.getVersionHistory(nodeRef); VersionHistory versionHistory12 = versionService.getVersionHistory(nodeRef);
assertNull(versionHistory12); assertNull(versionHistory12);
VersionHistory versionHistory23 = VersionServiceImplTest.this.versionService.getVersionHistory(archivedNodeRef); VersionHistory versionHistory23 = versionService.getVersionHistory(archivedNodeRef);
assertNull(versionHistory23); assertNull(versionHistory23);
return null; return null;
@@ -761,8 +809,15 @@ public class VersionServiceImplTest extends BaseVersionStoreTest
final AuthenticationComponent authenticationComponent = (AuthenticationComponent) ctx.getBean("authenticationComponent"); final AuthenticationComponent authenticationComponent = (AuthenticationComponent) ctx.getBean("authenticationComponent");
authenticationComponent.setSystemUserAsCurrentUser(); authenticationComponent.setSystemUserAsCurrentUser();
// TEMP - for migration testing - force V1 store (override repository property)
final Version2ServiceImpl version2ServiceImpl = (Version2ServiceImpl)ctx.getBean("versionService");
version2ServiceImpl.setOnlyUseDeprecatedV1(true);
System.out.println("Using: " + versionService.getVersionStoreReference());
// Create a new store // Create a new store
StoreRef storeRef = new StoreRef("test", "VersionServiceImplTest.main"); StoreRef storeRef = new StoreRef("test", "VersionServiceImplTest-main-"+System.currentTimeMillis());
if (!nodeService.exists(storeRef)) if (!nodeService.exists(storeRef))
{ {
nodeService.createStore(storeRef.getProtocol(), storeRef.getIdentifier()); nodeService.createStore(storeRef.getProtocol(), storeRef.getIdentifier());
@@ -819,5 +874,7 @@ public class VersionServiceImplTest extends BaseVersionStoreTest
lastReport = now; lastReport = now;
} }
} }
System.out.println("Finished: " + fileCount);
} }
} }

View File

@@ -54,6 +54,7 @@ public class VersionTestSuite extends TestSuite
suite.addTestSuite(VersionServiceImplTest.class); suite.addTestSuite(VersionServiceImplTest.class);
suite.addTestSuite(NodeServiceImplTest.class); suite.addTestSuite(NodeServiceImplTest.class);
suite.addTestSuite(ContentServiceImplTest.class); suite.addTestSuite(ContentServiceImplTest.class);
suite.addTestSuite(VersionMigratorTest.class);
return suite; return suite;
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2005-2007 Alfresco Software Limited. * Copyright (C) 2005-2008 Alfresco Software Limited.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@@ -205,6 +205,7 @@ public class VersionableAspect implements ContentServicePolicies.OnContentUpdate
// Queue create version action // Queue create version action
Map<String, Serializable> versionDetails = new HashMap<String, Serializable>(1); Map<String, Serializable> versionDetails = new HashMap<String, Serializable>(1);
versionDetails.put(Version.PROP_DESCRIPTION, I18NUtil.getMessage(MSG_INITIAL_VERSION)); versionDetails.put(Version.PROP_DESCRIPTION, I18NUtil.getMessage(MSG_INITIAL_VERSION));
this.versionService.createVersion(nodeRef, versionDetails); this.versionService.createVersion(nodeRef, versionDetails);
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2005-2007 Alfresco Software Limited. * Copyright (C) 2005-2008 Alfresco Software Limited.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@@ -26,11 +26,9 @@ package org.alfresco.repo.version.common;
import java.io.Serializable; import java.io.Serializable;
import java.util.Collection; import java.util.Collection;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import org.alfresco.repo.node.MLPropertyInterceptor;
import org.alfresco.repo.policy.ClassPolicyDelegate; import org.alfresco.repo.policy.ClassPolicyDelegate;
import org.alfresco.repo.policy.PolicyComponent; import org.alfresco.repo.policy.PolicyComponent;
import org.alfresco.repo.policy.PolicyScope; import org.alfresco.repo.policy.PolicyScope;
@@ -39,18 +37,13 @@ import org.alfresco.repo.version.VersionServicePolicies.AfterCreateVersionPolicy
import org.alfresco.repo.version.VersionServicePolicies.BeforeCreateVersionPolicy; import org.alfresco.repo.version.VersionServicePolicies.BeforeCreateVersionPolicy;
import org.alfresco.repo.version.VersionServicePolicies.CalculateVersionLabelPolicy; import org.alfresco.repo.version.VersionServicePolicies.CalculateVersionLabelPolicy;
import org.alfresco.repo.version.VersionServicePolicies.OnCreateVersionPolicy; import org.alfresco.repo.version.VersionServicePolicies.OnCreateVersionPolicy;
import org.alfresco.service.cmr.dictionary.AssociationDefinition;
import org.alfresco.service.cmr.dictionary.ClassDefinition;
import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
import org.alfresco.service.cmr.repository.AssociationRef;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService; 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.Version;
import org.alfresco.service.cmr.version.VersionServiceException; import org.alfresco.service.cmr.version.VersionServiceException;
import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern;
/** /**
* Abstract version service implementation. * Abstract version service implementation.
@@ -223,58 +216,11 @@ public abstract class AbstractVersionServiceImpl
* @param versionProperties * @param versionProperties
* @param nodeDetails * @param nodeDetails
*/ */
protected void defaultOnCreateVersion( abstract protected void defaultOnCreateVersion(
QName classRef, QName classRef,
NodeRef nodeRef, NodeRef nodeRef,
Map<String, Serializable> versionProperties, Map<String, Serializable> versionProperties,
PolicyScope nodeDetails) PolicyScope nodeDetails);
{
ClassDefinition classDefinition = this.dictionaryService.getClass(classRef);
if (classDefinition != null)
{
boolean wasMLAware = MLPropertyInterceptor.setMLAware(true);
try
{
// Copy the properties
Map<QName,PropertyDefinition> propertyDefinitions = classDefinition.getProperties();
for (QName propertyName : propertyDefinitions.keySet())
{
Serializable propValue = this.nodeService.getProperty(nodeRef, propertyName);
nodeDetails.addProperty(classRef, propertyName, propValue);
}
}
finally
{
MLPropertyInterceptor.setMLAware(wasMLAware);
}
// Version the associations (child and target)
Map<QName, AssociationDefinition> assocDefs = classDefinition.getAssociations();
// TODO: Need way of getting child assocs of a given type
if (classDefinition.isContainer())
{
List<ChildAssociationRef> childAssocRefs = this.nodeService.getChildAssocs(nodeRef);
for (ChildAssociationRef childAssocRef : childAssocRefs)
{
if (assocDefs.containsKey(childAssocRef.getTypeQName()))
{
nodeDetails.addChildAssociation(classDefinition.getName(), childAssocRef);
}
}
}
// TODO: Need way of getting assocs of a given type
List<AssociationRef> nodeAssocRefs = this.nodeService.getTargetAssocs(nodeRef, RegexQNamePattern.MATCH_ALL);
for (AssociationRef nodeAssocRef : nodeAssocRefs)
{
if (assocDefs.containsKey(nodeAssocRef.getTypeQName()))
{
nodeDetails.addAssociation(classDefinition.getName(), nodeAssocRef);
}
}
}
}
/** /**
* Invoke the calculate version label policy behaviour * Invoke the calculate version label policy behaviour
@@ -314,4 +260,5 @@ public abstract class AbstractVersionServiceImpl
return versionLabel; return versionLabel;
} }
abstract public StoreRef getVersionStoreReference();
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2005-2007 Alfresco Software Limited. * Copyright (C) 2005-2008 Alfresco Software Limited.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@@ -225,11 +225,11 @@ public class VersionHistoryImplTest extends TestCase
} }
} }
Collection versions2 = vh.getSuccessors(this.childVersion1); Collection<Version> versions2 = vh.getSuccessors(this.childVersion1);
assertNotNull(versions2); assertNotNull(versions2);
assertTrue(versions2.isEmpty()); assertTrue(versions2.isEmpty());
Collection versions3 = vh.getSuccessors(this.childVersion2); Collection<Version> versions3 = vh.getSuccessors(this.childVersion2);
assertNotNull(versions3); assertNotNull(versions3);
assertTrue(versions3.isEmpty()); assertTrue(versions3.isEmpty());
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2005-2007 Alfresco Software Limited. * Copyright (C) 2005-2008 Alfresco Software Limited.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@@ -28,6 +28,8 @@ import java.io.Serializable;
import java.util.Date; import java.util.Date;
import java.util.Map; import java.util.Map;
import org.alfresco.repo.version.Version2Model;
import org.alfresco.repo.version.VersionBaseModel;
import org.alfresco.repo.version.VersionModel; import org.alfresco.repo.version.VersionModel;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.service.cmr.repository.StoreRef;
@@ -45,6 +47,7 @@ import org.alfresco.service.cmr.version.VersionType;
* *
* @author Roy Wetherall * @author Roy Wetherall
*/ */
public class VersionImpl implements Version public class VersionImpl implements Version
{ {
/** /**
@@ -98,16 +101,21 @@ public class VersionImpl implements Version
/** /**
* Helper method to get the created date from the version property data. * Helper method to get the created date from the version property data.
* *
* @return the date the version was created * @return the date the version was created (note: not the date of the original node)
*/ */
public Date getCreatedDate() public Date getCreatedDate()
{ {
return (Date)this.versionProperties.get(VersionModel.PROP_CREATED_DATE); return (Date)this.versionProperties.get(VersionBaseModel.PROP_CREATED_DATE);
} }
/**
* 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() public String getCreator()
{ {
return (String)this.versionProperties.get(VersionModel.PROP_CREATOR); return (String)this.versionProperties.get(VersionBaseModel.PROP_CREATOR);
} }
/** /**
@@ -117,7 +125,7 @@ public class VersionImpl implements Version
*/ */
public String getVersionLabel() public String getVersionLabel()
{ {
return (String)this.versionProperties.get(VersionModel.PROP_VERSION_LABEL); return (String)this.versionProperties.get(VersionBaseModel.PROP_VERSION_LABEL);
} }
/** /**
@@ -127,7 +135,7 @@ public class VersionImpl implements Version
*/ */
public VersionType getVersionType() public VersionType getVersionType()
{ {
return (VersionType)this.versionProperties.get(VersionModel.PROP_VERSION_TYPE); return (VersionType)this.versionProperties.get(VersionBaseModel.PROP_VERSION_TYPE);
} }
/** /**
@@ -137,7 +145,7 @@ public class VersionImpl implements Version
*/ */
public String getDescription() public String getDescription()
{ {
return (String)this.versionProperties.get(PROP_DESCRIPTION); return (String)this.versionProperties.get(Version.PROP_DESCRIPTION);
} }
/** /**
@@ -166,10 +174,24 @@ public class VersionImpl implements Version
*/ */
public NodeRef getVersionedNodeRef() public NodeRef getVersionedNodeRef()
{ {
NodeRef versionedNodeRef = null;
// Switch VersionStore depending on configured impl
if (nodeRef.getStoreRef().getIdentifier().equals(Version2Model.STORE_ID))
{
// V2 version store (eg. workspace://version2Store)
versionedNodeRef = (NodeRef)this.versionProperties.get(Version2Model.PROP_FROZEN_NODE_REF);
}
else if (nodeRef.getStoreRef().getIdentifier().equals(VersionModel.STORE_ID))
{
// Deprecated V1 version store (eg. workspace://lightWeightVersionStore)
String storeProtocol = (String)this.versionProperties.get(VersionModel.PROP_FROZEN_NODE_STORE_PROTOCOL); String storeProtocol = (String)this.versionProperties.get(VersionModel.PROP_FROZEN_NODE_STORE_PROTOCOL);
String storeId = (String)this.versionProperties.get(VersionModel.PROP_FROZEN_NODE_STORE_ID); String storeId = (String)this.versionProperties.get(VersionModel.PROP_FROZEN_NODE_STORE_ID);
String nodeId = (String)this.versionProperties.get(VersionModel.PROP_FROZEN_NODE_ID); String nodeId = (String)this.versionProperties.get(VersionModel.PROP_FROZEN_NODE_ID);
return new NodeRef(new StoreRef(storeProtocol, storeId), nodeId); versionedNodeRef = new NodeRef(new StoreRef(storeProtocol, storeId), nodeId);
}
return versionedNodeRef;
} }
/** /**

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2005-2007 Alfresco Software Limited. * Copyright (C) 2005-2008 Alfresco Software Limited.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@@ -24,12 +24,22 @@
*/ */
package org.alfresco.repo.version.common; package org.alfresco.repo.version.common;
import java.io.Serializable;
import java.util.Collection; import java.util.Collection;
import java.util.Date;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.version.Version2Model;
import org.alfresco.repo.version.VersionBaseModel;
import org.alfresco.repo.version.VersionModel; import org.alfresco.repo.version.VersionModel;
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.version.ReservedVersionNameException; import org.alfresco.service.cmr.version.ReservedVersionNameException;
import org.alfresco.service.namespace.QName;
/** /**
* Helper class containing helper methods for the versioning services. * Helper class containing helper methods for the versioning services.
@@ -42,14 +52,21 @@ public class VersionUtil
* Reserved property names * Reserved property names
*/ */
public static final String[] RESERVED_PROPERTY_NAMES = new String[]{ public static final String[] RESERVED_PROPERTY_NAMES = new String[]{
VersionModel.PROP_CREATED_DATE, VersionModel.PROP_FROZEN_NODE_ID, // deprecated
VersionModel.PROP_FROZEN_NODE_ID, VersionModel.PROP_FROZEN_NODE_STORE_ID, // deprecated
VersionModel.PROP_FROZEN_NODE_STORE_ID, VersionModel.PROP_FROZEN_NODE_STORE_PROTOCOL, // deprecated
VersionModel.PROP_FROZEN_NODE_STORE_PROTOCOL, VersionModel.PROP_FROZEN_NODE_TYPE, // deprecated
VersionModel.PROP_FROZEN_NODE_TYPE, VersionModel.PROP_FROZEN_ASPECTS, // deprecated
VersionModel.PROP_FROZEN_ASPECTS, VersionBaseModel.PROP_CREATED_DATE,
VersionModel.PROP_VERSION_LABEL, VersionBaseModel.PROP_VERSION_LABEL,
VersionModel.PROP_VERSION_NUMBER}; VersionBaseModel.PROP_VERSION_NUMBER,
VersionBaseModel.PROP_VERSION_DESCRIPTION,
Version2Model.PROP_FROZEN_NODE_DBID,
Version2Model.PROP_FROZEN_CREATED,
Version2Model.PROP_FROZEN_CREATOR,
Version2Model.PROP_FROZEN_MODIFIED,
Version2Model.PROP_FROZEN_MODIFIER,
Version2Model.PROP_FROZEN_ACCESSED};
/** /**
* Checks that the names of the additional version properties are valid and that they do not clash * Checks that the names of the additional version properties are valid and that they do not clash
@@ -93,4 +110,81 @@ public class VersionUtil
{ {
return new NodeRef(convertStoreRef(nodeRef.getStoreRef()), nodeRef.getId()); return new NodeRef(convertStoreRef(nodeRef.getStoreRef()), nodeRef.getId());
} }
public static void convertFrozenToOriginalProps(Map<QName, Serializable> props) throws InvalidNodeRefException
{
if (props != null)
{
props.remove(Version2Model.PROP_QNAME_VERSION_DESCRIPTION);
props.remove(Version2Model.PROP_QNAME_VERSION_NUMBER);
Set<QName> keys = new HashSet<QName>(props.keySet());
for (QName key : keys)
{
String keyName = key.getLocalName();
int idx = keyName.indexOf(Version2Model.PROP_METADATA_PREFIX);
if (idx == 0)
{
props.remove(key);
}
}
String versionLabel = (String)props.get(Version2Model.PROP_QNAME_VERSION_LABEL);
props.put(ContentModel.PROP_VERSION_LABEL, versionLabel);
props.remove(Version2Model.PROP_QNAME_VERSION_LABEL);
// Convert frozen sys:referenceable properties
NodeRef nodeRef = (NodeRef)props.get(Version2Model.PROP_QNAME_FROZEN_NODE_REF);
if (nodeRef != null)
{
props.put(ContentModel.PROP_STORE_PROTOCOL, nodeRef.getStoreRef().getProtocol());
props.put(ContentModel.PROP_STORE_IDENTIFIER, nodeRef.getStoreRef().getIdentifier());
props.put(ContentModel.PROP_NODE_UUID, nodeRef.getId());
}
props.remove(Version2Model.PROP_QNAME_FROZEN_NODE_REF);
Long dbid = (Long)props.get(Version2Model.PROP_QNAME_FROZEN_NODE_DBID);
props.put(ContentModel.PROP_NODE_DBID, dbid);
props.remove(Version2Model.PROP_QNAME_FROZEN_NODE_DBID);
// Convert frozen cm:auditable properties
String creator = (String)props.get(Version2Model.PROP_QNAME_FROZEN_CREATOR);
if (creator != null)
{
props.put(ContentModel.PROP_CREATOR, creator);
}
props.remove(Version2Model.PROP_QNAME_FROZEN_CREATOR);
Date created = (Date)props.get(Version2Model.PROP_QNAME_FROZEN_CREATED);
if (created != null)
{
props.put(ContentModel.PROP_CREATED, created);
}
props.remove(Version2Model.PROP_QNAME_FROZEN_CREATED);
// TODO - check use-cases for get version, revert, restore ....
String modifier = (String)props.get(Version2Model.PROP_QNAME_FROZEN_MODIFIER);
if (modifier != null)
{
props.put(ContentModel.PROP_MODIFIER, modifier);
}
props.remove(Version2Model.PROP_QNAME_FROZEN_MODIFIER);
Date modified = (Date)props.get(Version2Model.PROP_QNAME_FROZEN_MODIFIED);
if (modified != null)
{
props.put(ContentModel.PROP_MODIFIED, modified);
}
props.remove(Version2Model.PROP_QNAME_FROZEN_MODIFIED);
Date accessed = (Date)props.get(Version2Model.PROP_QNAME_FROZEN_ACCESSED);
if (accessed != null)
{
props.put(ContentModel.PROP_ACCESSED, accessed);
}
props.remove(Version2Model.PROP_QNAME_FROZEN_ACCESSED);
}
}
} }

View File

@@ -62,7 +62,12 @@ public class SerialVersionLabelPolicy
{ {
serialVersionNumber = new SerialVersionLabel(preceedingVersion.getVersionLabel()); serialVersionNumber = new SerialVersionLabel(preceedingVersion.getVersionLabel());
VersionType versionType = (VersionType)versionProperties.get(VersionModel.PROP_VERSION_TYPE); VersionType versionType = null;
if (versionProperties != null)
{
versionType = (VersionType)versionProperties.get(VersionModel.PROP_VERSION_TYPE);
}
if (VersionType.MAJOR.equals(versionType) == true) if (VersionType.MAJOR.equals(versionType) == true)
{ {
serialVersionNumber.majorIncrement(); serialVersionNumber.majorIncrement();

View File

@@ -0,0 +1,140 @@
<model name="ver2:versionmodel" xmlns="http://www.alfresco.org/model/dictionary/1.0">
<description>Alfresco Version2 Store Model</description>
<author>Alfresco</author>
<published>2008-07-18</published>
<version>2.0</version>
<imports>
<import uri="http://www.alfresco.org/model/dictionary/1.0" prefix="d"/>
<import uri="http://www.alfresco.org/model/system/1.0" prefix="sys"/>
<import uri="http://www.alfresco.org/model/content/1.0" prefix="cm"/>
</imports>
<namespaces>
<namespace uri="http://www.alfresco.org/model/versionstore/2.0" prefix="ver2"/>
</namespaces>
<types>
<type name="ver2:versionHistory">
<parent>cm:cmobject</parent>
<properties>
<property name="ver2:versionedNodeId">
<type>d:text</type>
</property>
</properties>
<associations>
<child-association name="ver2:version">
<target>
<class>sys:base</class>
</target>
</child-association>
<association name="ver2:rootVersion">
<target>
<class>sys:base</class>
</target>
</association>
</associations>
</type>
</types>
<aspects>
<aspect name="ver2:versionStoreRoot">
<title>Version Store Root</title>
<associations>
<child-association name="ver2:versionHistory">
<source>
<mandatory>false</mandatory>
<many>true</many>
</source>
<target>
<class>ver2:versionHistory</class>
<mandatory>false</mandatory>
<many>true</many>
</target>
<duplicate>false</duplicate>
</child-association>
</associations>
</aspect>
<aspect name="ver2:version">
<title>Version</title>
<properties>
<property name="ver2:versionNumber">
<type>d:int</type>
</property>
<property name="ver2:versionLabel">
<type>d:text</type>
</property>
<property name="ver2:description">
<type>d:text</type>
</property>
<property name="ver2:frozenNodeType">
<type>d:qname</type>
</property>
<property name="ver2:frozenAspects">
<type>d:qname</type>
<multiple>true</multiple>
</property>
<!-- frozen sys:referenceable properties (x4) -->
<property name="ver2:frozenNodeStoreProtocol">
<type>d:text</type>
<mandatory enforced="true">true</mandatory>
</property>
<property name="ver2:frozenNodeStoreId">
<type>d:text</type>
<mandatory enforced="true">true</mandatory>
</property>
<property name="ver2:frozenNodeId">
<type>d:text</type>
<mandatory enforced="true">true</mandatory>
</property>
<property name="ver2:frozenNodeDbId">
<type>d:long</type>
<mandatory enforced="true">true</mandatory>
</property>
<!-- frozen cm:auditable properties (x5) -->
<property name="ver2:frozenCreated">
<title>Created</title>
<type>d:datetime</type>
<protected>true</protected>
</property>
<property name="ver2:frozenCreator">
<title>Creator</title>
<type>d:text</type>
<protected>true</protected>
</property>
<property name="ver2:frozenModified">
<title>Modified</title>
<type>d:datetime</type>
<protected>true</protected>
</property>
<property name="ver2:frozenModifier">
<title>Modifier</title>
<type>d:text</type>
<protected>true</protected>
</property>
<property name="ver2:frozenAccessed">
<title>Accessed</title>
<type>d:datetime</type>
<protected>true</protected>
</property>
</properties>
</aspect>
</aspects>
</model>

View File

@@ -1,5 +1,7 @@
<model name="ver:versionmodel" xmlns="http://www.alfresco.org/model/dictionary/1.0"> <model name="ver:versionmodel" xmlns="http://www.alfresco.org/model/dictionary/1.0">
<!-- deprecated -->
<description>Alfresco Version Store Model</description> <description>Alfresco Version Store Model</description>
<author>Alfresco</author> <author>Alfresco</author>
<published>2005-05-30</published> <published>2005-05-30</published>

View File

@@ -28,6 +28,7 @@ import java.io.Serializable;
import java.util.Date; import java.util.Date;
import java.util.Map; import java.util.Map;
import org.alfresco.repo.version.VersionBaseModel;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
@@ -44,7 +45,7 @@ public interface Version extends Serializable
/** /**
* Names of the system version properties * Names of the system version properties
*/ */
public static final String PROP_DESCRIPTION = "description"; public static final String PROP_DESCRIPTION = VersionBaseModel.PROP_DESCRIPTION;
/** /**
* Helper method to get the created date from the version property data. * Helper method to get the created date from the version property data.
@@ -103,7 +104,7 @@ public interface Version extends Serializable
* Note that this reference will be to the current state of the versioned * Note that this reference will be to the current state of the versioned
* node which may now correspond to a later version. * node which may now correspond to a later version.
* *
* @return a node reference * @return a node reference (to the versioned node in the 'live' store)
*/ */
public NodeRef getVersionedNodeRef(); public NodeRef getVersionedNodeRef();
@@ -111,7 +112,7 @@ public interface Version extends Serializable
* Gets the reference to the node that contains the frozen state of the * Gets the reference to the node that contains the frozen state of the
* version. * version.
* *
* @return a node reference * @return a node reference (to the version node in the 'version' store)
*/ */
public NodeRef getFrozenStateNodeRef(); public NodeRef getFrozenStateNodeRef();
} }