mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-24 17:32:48 +00:00
Moving to root below branch label
git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@2005 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
370
source/java/org/alfresco/repo/version/BaseVersionStoreTest.java
Normal file
370
source/java/org/alfresco/repo/version/BaseVersionStoreTest.java
Normal file
@@ -0,0 +1,370 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
* copy of the License at
|
||||
*
|
||||
* http://www.alfresco.org/legal/license.txt
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the
|
||||
* License.
|
||||
*/
|
||||
package org.alfresco.repo.version;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.dictionary.DictionaryDAO;
|
||||
import org.alfresco.repo.dictionary.M2Model;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationComponent;
|
||||
import org.alfresco.repo.security.authentication.MutableAuthenticationDao;
|
||||
import org.alfresco.repo.version.common.counter.VersionCounterDaoService;
|
||||
import org.alfresco.repo.version.common.versionlabel.SerialVersionLabelPolicy;
|
||||
import org.alfresco.service.cmr.repository.ContentData;
|
||||
import org.alfresco.service.cmr.repository.ContentService;
|
||||
import org.alfresco.service.cmr.repository.ContentWriter;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.cmr.repository.StoreRef;
|
||||
import org.alfresco.service.cmr.security.AuthenticationService;
|
||||
import org.alfresco.service.cmr.version.Version;
|
||||
import org.alfresco.service.cmr.version.VersionService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.service.transaction.TransactionService;
|
||||
import org.alfresco.util.BaseSpringTest;
|
||||
import org.alfresco.util.TestWithUserUtils;
|
||||
|
||||
public abstract class BaseVersionStoreTest extends BaseSpringTest
|
||||
{
|
||||
/*
|
||||
* Services used by the tests
|
||||
*/
|
||||
protected NodeService dbNodeService;
|
||||
protected VersionService versionService;
|
||||
protected VersionCounterDaoService versionCounterDaoService;
|
||||
protected ContentService contentService;
|
||||
protected DictionaryDAO dictionaryDAO;
|
||||
protected AuthenticationService authenticationService;
|
||||
protected TransactionService transactionService;
|
||||
protected MutableAuthenticationDao authenticationDAO;
|
||||
|
||||
/*
|
||||
* Data used by tests
|
||||
*/
|
||||
protected StoreRef testStoreRef;
|
||||
protected NodeRef rootNodeRef;
|
||||
protected Map<String, Serializable> versionProperties;
|
||||
protected HashMap<QName, Serializable> nodeProperties;
|
||||
|
||||
/**
|
||||
* The most recent set of versionable nodes created by createVersionableNode
|
||||
*/
|
||||
protected HashMap<String, NodeRef> versionableNodes;
|
||||
|
||||
/*
|
||||
* Proprety names and values
|
||||
*/
|
||||
protected static final String TEST_NAMESPACE = "http://www.alfresco.org/test/versionstorebasetest/1.0";
|
||||
protected static final QName TEST_TYPE_QNAME = QName.createQName(TEST_NAMESPACE, "testtype");
|
||||
protected static final QName TEST_ASPECT_QNAME = QName.createQName(TEST_NAMESPACE, "testaspect");
|
||||
protected static final QName PROP_1 = QName.createQName(TEST_NAMESPACE, "prop1");
|
||||
protected static final QName PROP_2 = QName.createQName(TEST_NAMESPACE, "prop2");
|
||||
protected static final QName PROP_3 = QName.createQName(TEST_NAMESPACE, "prop3");
|
||||
protected static final QName MULTI_PROP = QName.createQName(TEST_NAMESPACE, "multiProp");
|
||||
protected static final String VERSION_PROP_1 = "versionProp1";
|
||||
protected static final String VERSION_PROP_2 = "versionProp2";
|
||||
protected static final String VERSION_PROP_3 = "versionProp3";
|
||||
protected static final String VALUE_1 = "value1";
|
||||
protected static final String VALUE_2 = "value2";
|
||||
protected static final String VALUE_3 = "value3";
|
||||
protected static final QName TEST_CHILD_ASSOC_1 = QName.createQName(TEST_NAMESPACE, "childassoc1");
|
||||
protected static final QName TEST_CHILD_ASSOC_2 = QName.createQName(TEST_NAMESPACE, "childassoc2");
|
||||
protected static final QName TEST_ASSOC = QName.createQName(TEST_NAMESPACE, "assoc1");
|
||||
|
||||
protected Collection<String> multiValue = null;
|
||||
private AuthenticationComponent authenticationComponent;
|
||||
protected static final String MULTI_VALUE_1 = "multi1";
|
||||
protected static final String MULTI_VALUE_2 = "multi2";
|
||||
|
||||
/**
|
||||
* Test content
|
||||
*/
|
||||
protected static final String TEST_CONTENT = "This is the versioned test content.";
|
||||
|
||||
/**
|
||||
* Test user details
|
||||
*/
|
||||
private static final String PWD = "admin";
|
||||
private static final String USER_NAME = "admin";
|
||||
|
||||
/**
|
||||
* Sets the meta model dao
|
||||
*
|
||||
* @param dictionaryDAO the meta model dao
|
||||
*/
|
||||
public void setDictionaryDAO(DictionaryDAO dictionaryDAO)
|
||||
{
|
||||
this.dictionaryDAO = dictionaryDAO;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called during the transaction setup
|
||||
*/
|
||||
protected void onSetUpInTransaction() throws Exception
|
||||
{
|
||||
// Set the multi value if required
|
||||
if (this.multiValue == null)
|
||||
{
|
||||
this.multiValue = new ArrayList<String>();
|
||||
this.multiValue.add(MULTI_VALUE_1);
|
||||
this.multiValue.add(MULTI_VALUE_2);
|
||||
}
|
||||
|
||||
// Get the services by name from the application context
|
||||
this.dbNodeService = (NodeService)applicationContext.getBean("dbNodeService");
|
||||
this.versionService = (VersionService)applicationContext.getBean("versionService");
|
||||
this.versionCounterDaoService = (VersionCounterDaoService)applicationContext.getBean("versionCounterDaoService");
|
||||
this.contentService = (ContentService)applicationContext.getBean("contentService");
|
||||
this.authenticationService = (AuthenticationService)applicationContext.getBean("authenticationService");
|
||||
this.authenticationComponent = (AuthenticationComponent)applicationContext.getBean("authenticationComponent");
|
||||
this.transactionService = (TransactionService)this.applicationContext.getBean("transactionComponent");
|
||||
this.authenticationDAO = (MutableAuthenticationDao) applicationContext.getBean("alfDaoImpl");
|
||||
|
||||
authenticationService.clearCurrentSecurityContext();
|
||||
|
||||
// Create the test model
|
||||
createTestModel();
|
||||
|
||||
// Create a bag of properties for later use
|
||||
this.versionProperties = new HashMap<String, Serializable>();
|
||||
versionProperties.put(VERSION_PROP_1, VALUE_1);
|
||||
versionProperties.put(VERSION_PROP_2, VALUE_2);
|
||||
versionProperties.put(VERSION_PROP_3, VALUE_3);
|
||||
|
||||
// Create the node properties
|
||||
this.nodeProperties = new HashMap<QName, Serializable>();
|
||||
this.nodeProperties.put(PROP_1, VALUE_1);
|
||||
this.nodeProperties.put(PROP_2, VALUE_2);
|
||||
this.nodeProperties.put(PROP_3, VALUE_3);
|
||||
this.nodeProperties.put(MULTI_PROP, (Serializable)multiValue);
|
||||
this.nodeProperties.put(ContentModel.PROP_CONTENT, new ContentData(null, "text/plain", 0L, "UTF-8"));
|
||||
|
||||
// Create a workspace that contains the 'live' nodes
|
||||
this.testStoreRef = this.dbNodeService.createStore(StoreRef.PROTOCOL_WORKSPACE, "Test_" + System.currentTimeMillis());
|
||||
|
||||
// Get a reference to the root node
|
||||
this.rootNodeRef = this.dbNodeService.getRootNode(this.testStoreRef);
|
||||
|
||||
// Create an authenticate the user
|
||||
|
||||
if(!authenticationDAO.userExists(USER_NAME))
|
||||
{
|
||||
authenticationService.createAuthentication(USER_NAME, PWD.toCharArray());
|
||||
}
|
||||
|
||||
TestWithUserUtils.authenticateUser(USER_NAME, PWD, this.rootNodeRef, this.authenticationService);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the test model used by the tests
|
||||
*/
|
||||
private void createTestModel()
|
||||
{
|
||||
InputStream is = getClass().getClassLoader().getResourceAsStream("org/alfresco/repo/version/VersionStoreBaseTest_model.xml");
|
||||
M2Model model = M2Model.createModel(is);
|
||||
dictionaryDAO.putModel(model);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new versionable node
|
||||
*
|
||||
* @return the node reference
|
||||
*/
|
||||
protected NodeRef createNewVersionableNode()
|
||||
{
|
||||
// Use this map to retrive the versionable nodes in later tests
|
||||
this.versionableNodes = new HashMap<String, NodeRef>();
|
||||
|
||||
// Create node (this node has some content)
|
||||
NodeRef nodeRef = this.dbNodeService.createNode(
|
||||
rootNodeRef,
|
||||
ContentModel.ASSOC_CHILDREN,
|
||||
QName.createQName("{test}MyVersionableNode"),
|
||||
TEST_TYPE_QNAME,
|
||||
this.nodeProperties).getChildRef();
|
||||
this.dbNodeService.addAspect(nodeRef, ContentModel.ASPECT_VERSIONABLE, new HashMap<QName, Serializable>());
|
||||
|
||||
assertNotNull(nodeRef);
|
||||
this.versionableNodes.put(nodeRef.getId(), nodeRef);
|
||||
|
||||
// Add the content to the node
|
||||
ContentWriter contentWriter = this.contentService.getWriter(nodeRef, ContentModel.PROP_CONTENT, true);
|
||||
contentWriter.putContent(TEST_CONTENT);
|
||||
|
||||
// Add some children to the node
|
||||
NodeRef child1 = this.dbNodeService.createNode(
|
||||
nodeRef,
|
||||
TEST_CHILD_ASSOC_1,
|
||||
TEST_CHILD_ASSOC_1,
|
||||
TEST_TYPE_QNAME,
|
||||
this.nodeProperties).getChildRef();
|
||||
this.dbNodeService.addAspect(child1, ContentModel.ASPECT_VERSIONABLE, new HashMap<QName, Serializable>());
|
||||
assertNotNull(child1);
|
||||
this.versionableNodes.put(child1.getId(), child1);
|
||||
NodeRef child2 = this.dbNodeService.createNode(
|
||||
nodeRef,
|
||||
TEST_CHILD_ASSOC_2,
|
||||
TEST_CHILD_ASSOC_2,
|
||||
TEST_TYPE_QNAME,
|
||||
this.nodeProperties).getChildRef();
|
||||
this.dbNodeService.addAspect(child2, ContentModel.ASPECT_VERSIONABLE, new HashMap<QName, Serializable>());
|
||||
assertNotNull(child2);
|
||||
this.versionableNodes.put(child2.getId(), child2);
|
||||
|
||||
// Create a node that can be associated with the root node
|
||||
NodeRef assocNode = this.dbNodeService.createNode(
|
||||
rootNodeRef,
|
||||
ContentModel.ASSOC_CHILDREN,
|
||||
QName.createQName("{test}MyAssocNode"),
|
||||
TEST_TYPE_QNAME,
|
||||
this.nodeProperties).getChildRef();
|
||||
assertNotNull(assocNode);
|
||||
this.dbNodeService.createAssociation(nodeRef, assocNode, TEST_ASSOC);
|
||||
|
||||
return nodeRef;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new version, checking the properties of the version.
|
||||
* <p>
|
||||
* The default test propreties are assigned to the version.
|
||||
*
|
||||
* @param versionableNode the versionable node
|
||||
* @return the created (and checked) new version
|
||||
*/
|
||||
protected Version createVersion(NodeRef versionableNode)
|
||||
{
|
||||
return createVersion(versionableNode, this.versionProperties);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new version, checking the properties of the version.
|
||||
*
|
||||
* @param versionableNode the versionable node
|
||||
* @param versionProperties the version properties
|
||||
* @return the created (and checked) new version
|
||||
*/
|
||||
protected Version createVersion(NodeRef versionableNode, Map<String, Serializable> versionProperties)
|
||||
{
|
||||
// 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 a new version for this node
|
||||
Version newVersion = versionService.createVersion(versionableNode, this.versionProperties);
|
||||
checkNewVersion(beforeVersionTime, nextVersion, nextVersionLabel, newVersion, versionableNode);
|
||||
|
||||
// Return the new version
|
||||
return newVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the next version label
|
||||
*/
|
||||
protected String peekNextVersionLabel(NodeRef nodeRef, int versionNumber, Map<String, Serializable> versionProperties)
|
||||
{
|
||||
Version version = this.versionService.getCurrentVersion(nodeRef);
|
||||
SerialVersionLabelPolicy policy = new SerialVersionLabelPolicy();
|
||||
return policy.calculateVersionLabel(ContentModel.TYPE_CMOBJECT, version, versionNumber, versionProperties);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checkd the validity of a new version
|
||||
*
|
||||
* @param beforeVersionTime the time snap shot before the version was created
|
||||
* @param expectedVersionNumber the expected version number
|
||||
* @param newVersion the new version
|
||||
* @param versionableNode the versioned node
|
||||
*/
|
||||
protected void checkNewVersion(long beforeVersionTime, int expectedVersionNumber, String expectedVersionLabel, Version newVersion, NodeRef versionableNode)
|
||||
{
|
||||
assertNotNull(newVersion);
|
||||
|
||||
// Check the version label and version number
|
||||
assertEquals(
|
||||
"The expected version number was not used.",
|
||||
Integer.toString(expectedVersionNumber),
|
||||
newVersion.getVersionProperty(VersionModel.PROP_VERSION_NUMBER).toString());
|
||||
assertEquals(
|
||||
"The expected version label was not used.",
|
||||
expectedVersionLabel,
|
||||
newVersion.getVersionLabel());
|
||||
|
||||
// Check the created date
|
||||
long afterVersionTime = System.currentTimeMillis();
|
||||
long createdDate = newVersion.getCreatedDate().getTime();
|
||||
if (createdDate < beforeVersionTime || createdDate > afterVersionTime)
|
||||
{
|
||||
fail("The created date of the version is incorrect.");
|
||||
}
|
||||
|
||||
// Check the creator
|
||||
assertEquals(USER_NAME, newVersion.getCreator());
|
||||
|
||||
// Check the properties of the verison
|
||||
Map<String, Serializable> props = newVersion.getVersionProperties();
|
||||
assertNotNull("The version properties collection should not be null.", props);
|
||||
// TODO sort this out - need to check for the reserved properties too
|
||||
//assertEquals(versionProperties.size(), props.size());
|
||||
for (String key : versionProperties.keySet())
|
||||
{
|
||||
assertEquals(
|
||||
versionProperties.get(key),
|
||||
newVersion.getVersionProperty(key));
|
||||
}
|
||||
|
||||
// Check that the node reference is correct
|
||||
NodeRef nodeRef = newVersion.getFrozenStateNodeRef();
|
||||
assertNotNull(nodeRef);
|
||||
assertEquals(
|
||||
VersionModel.STORE_ID,
|
||||
nodeRef.getStoreRef().getIdentifier());
|
||||
assertEquals(
|
||||
VersionModel.STORE_PROTOCOL,
|
||||
nodeRef.getStoreRef().getProtocol());
|
||||
assertNotNull(nodeRef.getId());
|
||||
|
||||
// TODO: How do we check the frozen attributes ??
|
||||
|
||||
// Check the node ref for the current version
|
||||
String currentVersionLabel = (String)this.dbNodeService.getProperty(
|
||||
versionableNode,
|
||||
ContentModel.PROP_VERSION_LABEL);
|
||||
assertEquals(newVersion.getVersionLabel(), currentVersionLabel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next version number without affecting the version counter.
|
||||
*
|
||||
* @return the next version number to be allocated
|
||||
*/
|
||||
protected int peekNextVersionNumber()
|
||||
{
|
||||
StoreRef lwVersionStoreRef = this.versionService.getVersionStoreReference();
|
||||
return this.versionCounterDaoService.currentVersionNumber(lwVersionStoreRef) + 1;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
* copy of the License at
|
||||
*
|
||||
* http://www.alfresco.org/legal/license.txt
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the
|
||||
* License.
|
||||
*/
|
||||
package org.alfresco.repo.version;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.service.cmr.repository.ContentReader;
|
||||
import org.alfresco.service.cmr.repository.ContentService;
|
||||
import org.alfresco.service.cmr.repository.ContentWriter;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.version.Version;
|
||||
|
||||
/**
|
||||
* Tests for retrieving frozen content from a verioned node
|
||||
*
|
||||
* @author Roy Wetherall
|
||||
*/
|
||||
public class ContentServiceImplTest extends BaseVersionStoreTest
|
||||
{
|
||||
/**
|
||||
* Test content data
|
||||
*/
|
||||
private final static String UPDATED_CONTENT = "This content has been updated with a new value.";
|
||||
|
||||
/**
|
||||
* The version content store
|
||||
*/
|
||||
private ContentService contentService;
|
||||
|
||||
/**
|
||||
* Called during the transaction setup
|
||||
*/
|
||||
protected void onSetUpInTransaction() throws Exception
|
||||
{
|
||||
super.onSetUpInTransaction();
|
||||
|
||||
// Get the instance of the required content service
|
||||
this.contentService = (ContentService)this.applicationContext.getBean("contentService");
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getReader
|
||||
*/
|
||||
public void testGetReader()
|
||||
{
|
||||
// Create a new versionable node
|
||||
NodeRef versionableNode = createNewVersionableNode();
|
||||
|
||||
// Create a new version
|
||||
Version version = createVersion(versionableNode, this.versionProperties);
|
||||
NodeRef versionNodeRef = version.getFrozenStateNodeRef();
|
||||
|
||||
// Get the content reader for the frozen node
|
||||
ContentReader contentReader = this.contentService.getReader(versionNodeRef, ContentModel.PROP_CONTENT);
|
||||
assertNotNull(contentReader);
|
||||
assertEquals(TEST_CONTENT, contentReader.getContentString());
|
||||
|
||||
// Now update the content and verison again
|
||||
ContentWriter contentWriter = this.contentService.getWriter(versionableNode, ContentModel.PROP_CONTENT, true);
|
||||
assertNotNull(contentWriter);
|
||||
contentWriter.putContent(UPDATED_CONTENT);
|
||||
Version version2 = createVersion(versionableNode, this.versionProperties);
|
||||
NodeRef version2NodeRef = version2.getFrozenStateNodeRef();
|
||||
|
||||
// Get the content reader for the new verisoned content
|
||||
ContentReader contentReader2 = this.contentService.getReader(version2NodeRef, ContentModel.PROP_CONTENT);
|
||||
assertNotNull(contentReader2);
|
||||
assertEquals(UPDATED_CONTENT, contentReader2.getContentString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getWriter
|
||||
*/
|
||||
public void testGetWriter()
|
||||
{
|
||||
// Create a new versionable node
|
||||
NodeRef versionableNode = createNewVersionableNode();
|
||||
|
||||
// Create a new version
|
||||
Version version = createVersion(versionableNode, this.versionProperties);
|
||||
|
||||
// Get writer is not supported by the version content service
|
||||
try
|
||||
{
|
||||
ContentWriter contentWriter = this.contentService.getWriter(
|
||||
version.getFrozenStateNodeRef(),
|
||||
ContentModel.PROP_CONTENT,
|
||||
true);
|
||||
contentWriter.putContent("bobbins");
|
||||
fail("This operation is not supported.");
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
// An exception should be raised
|
||||
}
|
||||
}
|
||||
}
|
562
source/java/org/alfresco/repo/version/NodeServiceImpl.java
Normal file
562
source/java/org/alfresco/repo/version/NodeServiceImpl.java
Normal file
@@ -0,0 +1,562 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
* copy of the License at
|
||||
*
|
||||
* http://www.alfresco.org/legal/license.txt
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the
|
||||
* License.
|
||||
*/
|
||||
package org.alfresco.repo.version;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.service.cmr.dictionary.DictionaryService;
|
||||
import org.alfresco.service.cmr.dictionary.InvalidAspectException;
|
||||
import org.alfresco.service.cmr.repository.AssociationExistsException;
|
||||
import org.alfresco.service.cmr.repository.AssociationRef;
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
import org.alfresco.service.cmr.repository.InvalidChildAssociationRefException;
|
||||
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.Path;
|
||||
import org.alfresco.service.cmr.repository.StoreRef;
|
||||
import org.alfresco.service.cmr.repository.NodeRef.Status;
|
||||
import org.alfresco.service.cmr.search.QueryParameterDefinition;
|
||||
import org.alfresco.service.cmr.search.SearchService;
|
||||
import org.alfresco.service.namespace.NamespacePrefixResolver;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.service.namespace.QNamePattern;
|
||||
import org.alfresco.service.namespace.RegexQNamePattern;
|
||||
|
||||
|
||||
/**
|
||||
* The light weight version store node service implementation.
|
||||
*
|
||||
* @author Roy Wetherall
|
||||
*/
|
||||
public class NodeServiceImpl implements NodeService, VersionModel
|
||||
{
|
||||
/**
|
||||
* Error messages
|
||||
*/
|
||||
private final static String MSG_UNSUPPORTED =
|
||||
"This operation is not supported by a version store implementation of the node service.";
|
||||
|
||||
/**
|
||||
* The name of the spoofed root association
|
||||
*/
|
||||
private static final QName rootAssocName = QName.createQName(VersionModel.NAMESPACE_URI, "versionedState");
|
||||
|
||||
/**
|
||||
* The db node service, used as the version store implementation
|
||||
*/
|
||||
protected NodeService dbNodeService;
|
||||
|
||||
/**
|
||||
* The repository searcher
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
private SearchService searcher;
|
||||
|
||||
/**
|
||||
* The dictionary service
|
||||
*/
|
||||
protected DictionaryService dicitionaryService;
|
||||
|
||||
|
||||
/**
|
||||
* Sets the db node service, used as the version store implementation
|
||||
*
|
||||
* @param nodeService the node service
|
||||
*/
|
||||
public void setDbNodeService(NodeService nodeService)
|
||||
{
|
||||
this.dbNodeService = nodeService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the searcher
|
||||
*
|
||||
* @param searcher the searcher
|
||||
*/
|
||||
public void setSearcher(SearchService searcher)
|
||||
{
|
||||
this.searcher = searcher;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the dictionary service
|
||||
*
|
||||
* @param dictionaryService the dictionary service
|
||||
*/
|
||||
public void setDictionaryService(DictionaryService dictionaryService)
|
||||
{
|
||||
this.dicitionaryService = dictionaryService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegates to the <code>NodeService</code> used as the version store implementation
|
||||
*/
|
||||
public List<StoreRef> getStores()
|
||||
{
|
||||
return dbNodeService.getStores();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegates to the <code>NodeService</code> used as the version store implementation
|
||||
*/
|
||||
public StoreRef createStore(String protocol, String identifier)
|
||||
{
|
||||
return dbNodeService.createStore(protocol, identifier);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegates to the <code>NodeService</code> used as the version store implementation
|
||||
*/
|
||||
public boolean exists(StoreRef storeRef)
|
||||
{
|
||||
return dbNodeService.exists(storeRef);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegates to the <code>NodeService</code> used as the version store implementation
|
||||
*/
|
||||
public boolean exists(NodeRef nodeRef)
|
||||
{
|
||||
return dbNodeService.exists(convertNodeRef(nodeRef));
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegates to the <code>NodeService</code> used as the version store implementation
|
||||
*/
|
||||
public Status getNodeStatus(NodeRef nodeRef)
|
||||
{
|
||||
return dbNodeService.getNodeStatus(nodeRef);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the incomming node ref (with the version store protocol specified)
|
||||
* to the internal representation with the workspace protocol.
|
||||
*
|
||||
* @param nodeRef the incomming verison protocol node reference
|
||||
* @return the internal version node reference
|
||||
*/
|
||||
private NodeRef convertNodeRef(NodeRef nodeRef)
|
||||
{
|
||||
return new NodeRef(new StoreRef(StoreRef.PROTOCOL_WORKSPACE, STORE_ID), nodeRef.getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegates to the <code>NodeService</code> used as the version store implementation
|
||||
*/
|
||||
public NodeRef getRootNode(StoreRef storeRef)
|
||||
{
|
||||
return dbNodeService.getRootNode(storeRef);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws UnsupportedOperationException always
|
||||
*/
|
||||
public ChildAssociationRef createNode(
|
||||
NodeRef parentRef,
|
||||
QName assocTypeQName,
|
||||
QName assocQName,
|
||||
QName nodeTypeQName) throws InvalidNodeRefException
|
||||
{
|
||||
// This operation is not supported for a verion store
|
||||
throw new UnsupportedOperationException(MSG_UNSUPPORTED);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws UnsupportedOperationException always
|
||||
*/
|
||||
public ChildAssociationRef createNode(
|
||||
NodeRef parentRef,
|
||||
QName assocTypeQName,
|
||||
QName assocQName,
|
||||
QName nodeTypeQName,
|
||||
Map<QName, Serializable> properties) throws InvalidNodeRefException
|
||||
{
|
||||
// This operation is not supported for a verion store
|
||||
throw new UnsupportedOperationException(MSG_UNSUPPORTED);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws UnsupportedOperationException always
|
||||
*/
|
||||
public void deleteNode(NodeRef nodeRef) throws InvalidNodeRefException
|
||||
{
|
||||
// This operation is not supported for a verion store
|
||||
throw new UnsupportedOperationException(MSG_UNSUPPORTED);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws UnsupportedOperationException always
|
||||
*/
|
||||
public ChildAssociationRef addChild(NodeRef parentRef,
|
||||
NodeRef childRef,
|
||||
QName assocTypeQName,
|
||||
QName qname) throws InvalidNodeRefException
|
||||
{
|
||||
// This operation is not supported for a verion store
|
||||
throw new UnsupportedOperationException(MSG_UNSUPPORTED);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws UnsupportedOperationException always
|
||||
*/
|
||||
public void removeChild(NodeRef parentRef, NodeRef childRef) throws InvalidNodeRefException
|
||||
{
|
||||
// This operation is not supported for a verion store
|
||||
throw new UnsupportedOperationException(MSG_UNSUPPORTED);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws UnsupportedOperationException always
|
||||
*/
|
||||
public ChildAssociationRef moveNode(NodeRef nodeToMoveRef, NodeRef newParentRef, QName assocTypeQName, QName assocQName) throws InvalidNodeRefException
|
||||
{
|
||||
throw new UnsupportedOperationException(MSG_UNSUPPORTED);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws UnsupportedOperationException always
|
||||
*/
|
||||
public void setChildAssociationIndex(ChildAssociationRef childAssocRef, int index) throws InvalidChildAssociationRefException
|
||||
{
|
||||
throw new UnsupportedOperationException(MSG_UNSUPPORTED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Type translation for version store
|
||||
*/
|
||||
public QName getType(NodeRef nodeRef) throws InvalidNodeRefException
|
||||
{
|
||||
return (QName)this.dbNodeService.getProperty(convertNodeRef(nodeRef), PROP_QNAME_FROZEN_NODE_TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.service.cmr.repository.NodeService#setType(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.namespace.QName)
|
||||
*/
|
||||
public void setType(NodeRef nodeRef, QName typeQName) throws InvalidNodeRefException
|
||||
{
|
||||
// This operation is not supported for a version store
|
||||
throw new UnsupportedOperationException(MSG_UNSUPPORTED);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws UnsupportedOperationException always
|
||||
*/
|
||||
public void addAspect(NodeRef nodeRef, QName aspectRef, Map<QName, Serializable> aspectProperties) throws InvalidNodeRefException, InvalidAspectException
|
||||
{
|
||||
// This operation is not supported for a verion store
|
||||
throw new UnsupportedOperationException(MSG_UNSUPPORTED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Translation for version store
|
||||
*/
|
||||
public boolean hasAspect(NodeRef nodeRef, QName aspectRef) throws InvalidNodeRefException, InvalidAspectException
|
||||
{
|
||||
return getAspects(nodeRef).contains(aspectRef);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws UnsupportedOperationException always
|
||||
*/
|
||||
public void removeAspect(NodeRef nodeRef, QName aspectRef) throws InvalidNodeRefException, InvalidAspectException
|
||||
{
|
||||
// This operation is not supported for a verion store
|
||||
throw new UnsupportedOperationException(MSG_UNSUPPORTED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Translation for version store
|
||||
*/
|
||||
public Set<QName> getAspects(NodeRef nodeRef) throws InvalidNodeRefException
|
||||
{
|
||||
return new HashSet<QName>(
|
||||
(ArrayList<QName>)this.dbNodeService.getProperty(convertNodeRef(nodeRef), PROP_QNAME_FROZEN_ASPECTS));
|
||||
}
|
||||
|
||||
/**
|
||||
* Property translation for version store
|
||||
*/
|
||||
public Map<QName, Serializable> getProperties(NodeRef nodeRef) throws InvalidNodeRefException
|
||||
{
|
||||
Map<QName, Serializable> result = new HashMap<QName, Serializable>();
|
||||
|
||||
// TODO should be doing this using a path query ..
|
||||
|
||||
Collection<ChildAssociationRef> children = this.dbNodeService.getChildAssocs(convertNodeRef(nodeRef));
|
||||
for (ChildAssociationRef child : children)
|
||||
{
|
||||
if (child.getQName().equals(CHILD_QNAME_VERSIONED_ATTRIBUTES))
|
||||
{
|
||||
NodeRef versionedAttribute = child.getChildRef();
|
||||
|
||||
// Get the QName and the value
|
||||
Serializable value = null;
|
||||
QName qName = (QName)this.dbNodeService.getProperty(versionedAttribute, PROP_QNAME_QNAME);
|
||||
Boolean isMultiValue = (Boolean)this.dbNodeService.getProperty(versionedAttribute, PROP_QNAME_IS_MULTI_VALUE);
|
||||
if (isMultiValue.booleanValue() == false)
|
||||
{
|
||||
value = this.dbNodeService.getProperty(versionedAttribute, PROP_QNAME_VALUE);
|
||||
}
|
||||
else
|
||||
{
|
||||
value = this.dbNodeService.getProperty(versionedAttribute, PROP_QNAME_MULTI_VALUE);
|
||||
}
|
||||
|
||||
result.put(qName, value);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Property translation for version store
|
||||
*/
|
||||
public Serializable getProperty(NodeRef nodeRef, QName qname) throws InvalidNodeRefException
|
||||
{
|
||||
// TODO should be doing this with a search ...
|
||||
|
||||
Map<QName, Serializable> properties = getProperties(convertNodeRef(nodeRef));
|
||||
return properties.get(qname);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws UnsupportedOperationException always
|
||||
*/
|
||||
public void setProperties(NodeRef nodeRef, Map<QName, Serializable> properties) throws InvalidNodeRefException
|
||||
{
|
||||
// This operation is not supported for a verion store
|
||||
throw new UnsupportedOperationException(MSG_UNSUPPORTED);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws UnsupportedOperationException always
|
||||
*/
|
||||
public void setProperty(NodeRef nodeRef, QName qame, Serializable value) throws InvalidNodeRefException
|
||||
{
|
||||
// This operation is not supported for a verion store
|
||||
throw new UnsupportedOperationException(MSG_UNSUPPORTED);
|
||||
}
|
||||
|
||||
/**
|
||||
* The node will appear to be attached to the root of the version store
|
||||
*
|
||||
* @see NodeService#getParentAssocs(NodeRef)
|
||||
*/
|
||||
public List<ChildAssociationRef> getParentAssocs(NodeRef nodeRef)
|
||||
{
|
||||
return getParentAssocs(nodeRef, RegexQNamePattern.MATCH_ALL, RegexQNamePattern.MATCH_ALL);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
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, STORE_ID)),
|
||||
rootAssocName,
|
||||
nodeRef));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see RegexQNamePattern#MATCH_ALL
|
||||
* @see #getChildAssocs(NodeRef, QNamePattern, QNamePattern)
|
||||
*/
|
||||
public List<ChildAssociationRef> getChildAssocs(NodeRef nodeRef) throws InvalidNodeRefException
|
||||
{
|
||||
return getChildAssocs(convertNodeRef(nodeRef), RegexQNamePattern.MATCH_ALL, RegexQNamePattern.MATCH_ALL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs conversion from version store properties to <i>real</i> associations
|
||||
*/
|
||||
public List<ChildAssociationRef> getChildAssocs(NodeRef nodeRef, QNamePattern typeQNamePattern, QNamePattern qnamePattern) throws InvalidNodeRefException
|
||||
{
|
||||
// Get the child assocs from the version store
|
||||
List<ChildAssociationRef> childAssocRefs = this.dbNodeService.getChildAssocs(
|
||||
convertNodeRef(nodeRef),
|
||||
RegexQNamePattern.MATCH_ALL, CHILD_QNAME_VERSIONED_CHILD_ASSOCS);
|
||||
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);
|
||||
|
||||
// get the qualified name of the frozen child association and filter out unwanted names
|
||||
QName qName = (QName)this.dbNodeService.getProperty(childRef, PROP_QNAME_ASSOC_QNAME);
|
||||
|
||||
if (qnamePattern.isMatch(qName) == true)
|
||||
{
|
||||
// Retrieve the isPrimary and nthSibling values of the forzen child association
|
||||
QName assocType = (QName)this.dbNodeService.getProperty(childRef, PROP_QNAME_ASSOC_TYPE_QNAME);
|
||||
boolean isPrimary = ((Boolean)this.dbNodeService.getProperty(childRef, PROP_QNAME_IS_PRIMARY)).booleanValue();
|
||||
int nthSibling = ((Integer)this.dbNodeService.getProperty(childRef, PROP_QNAME_NTH_SIBLING)).intValue();
|
||||
|
||||
// Build a child assoc ref to add to the returned list
|
||||
ChildAssociationRef newChildAssocRef = new ChildAssociationRef(
|
||||
assocType,
|
||||
nodeRef,
|
||||
qName,
|
||||
referencedNode,
|
||||
isPrimary,
|
||||
nthSibling);
|
||||
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 ot the root node of the version store.
|
||||
*/
|
||||
public ChildAssociationRef getPrimaryParent(NodeRef nodeRef) throws InvalidNodeRefException
|
||||
{
|
||||
return new ChildAssociationRef(
|
||||
ContentModel.ASSOC_CHILDREN,
|
||||
dbNodeService.getRootNode(new StoreRef(StoreRef.PROTOCOL_WORKSPACE, STORE_ID)),
|
||||
rootAssocName,
|
||||
nodeRef);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws UnsupportedOperationException always
|
||||
*/
|
||||
public AssociationRef createAssociation(NodeRef sourceRef, NodeRef targetRef, QName assocTypeQName)
|
||||
throws InvalidNodeRefException, AssociationExistsException
|
||||
{
|
||||
// This operation is not supported for a verion store
|
||||
throw new UnsupportedOperationException(MSG_UNSUPPORTED);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws UnsupportedOperationException always
|
||||
*/
|
||||
public void removeAssociation(NodeRef sourceRef, NodeRef targetRef, QName assocTypeQName)
|
||||
{
|
||||
// This operation is not supported for a verion store
|
||||
throw new UnsupportedOperationException(MSG_UNSUPPORTED);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws UnsupportedOperationException always
|
||||
*/
|
||||
public List<AssociationRef> getTargetAssocs(NodeRef sourceRef, QNamePattern qnamePattern)
|
||||
{
|
||||
// Get the child assocs from the version store
|
||||
List<ChildAssociationRef> childAssocRefs = this.dbNodeService.getChildAssocs(
|
||||
convertNodeRef(sourceRef),
|
||||
RegexQNamePattern.MATCH_ALL, CHILD_QNAME_VERSIONED_ASSOCS);
|
||||
List<AssociationRef> result = new ArrayList<AssociationRef>(childAssocRefs.size());
|
||||
for (ChildAssociationRef childAssocRef : childAssocRefs)
|
||||
{
|
||||
// Get the assoc reference
|
||||
NodeRef childRef = childAssocRef.getChildRef();
|
||||
NodeRef referencedNode = (NodeRef)this.dbNodeService.getProperty(childRef, ContentModel.PROP_REFERENCE);
|
||||
|
||||
// get the qualified type name of the frozen child association and filter out unwanted names
|
||||
QName qName = (QName)this.dbNodeService.getProperty(childRef, PROP_QNAME_ASSOC_TYPE_QNAME);
|
||||
|
||||
if (qnamePattern.isMatch(qName) == true)
|
||||
{
|
||||
AssociationRef newAssocRef = new AssociationRef(sourceRef, qName, referencedNode);
|
||||
result.add(newAssocRef);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws UnsupportedOperationException always
|
||||
*/
|
||||
public List<AssociationRef> getSourceAssocs(NodeRef sourceRef, QNamePattern qnamePattern)
|
||||
{
|
||||
// This operation is not supported for a verion store
|
||||
throw new UnsupportedOperationException(MSG_UNSUPPORTED);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws UnsupportedOperationException always
|
||||
*/
|
||||
public Path getPath(NodeRef nodeRef) throws InvalidNodeRefException
|
||||
{
|
||||
ChildAssociationRef childAssocRef = getPrimaryParent(nodeRef);
|
||||
Path path = new Path();
|
||||
path.append(new Path.ChildAssocElement(childAssocRef));
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws UnsupportedOperationException always
|
||||
*/
|
||||
public List<Path> getPaths(NodeRef nodeRef, boolean primaryOnly) throws InvalidNodeRefException
|
||||
{
|
||||
List<Path> paths = new ArrayList<Path>(1);
|
||||
paths.add(getPath(nodeRef));
|
||||
return paths;
|
||||
}
|
||||
|
||||
public List<NodeRef> selectNodes(NodeRef contextNode, String XPath, QueryParameterDefinition[] parameters, NamespacePrefixResolver namespacePrefixResolver, boolean followAllParentLinks)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException(MSG_UNSUPPORTED);
|
||||
}
|
||||
|
||||
public List<Serializable> selectProperties(NodeRef contextNode, String XPath, QueryParameterDefinition[] parameters, NamespacePrefixResolver namespacePrefixResolver, boolean followAllParentLinks)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException(MSG_UNSUPPORTED);
|
||||
}
|
||||
|
||||
public boolean contains(NodeRef nodeRef, QName property, String sqlLikePattern)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public boolean like(NodeRef nodeRef, QName property, String sqlLikePattern, boolean includeFTS)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
|
||||
}
|
568
source/java/org/alfresco/repo/version/NodeServiceImplTest.java
Normal file
568
source/java/org/alfresco/repo/version/NodeServiceImplTest.java
Normal file
@@ -0,0 +1,568 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
* copy of the License at
|
||||
*
|
||||
* http://www.alfresco.org/legal/license.txt
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the
|
||||
* License.
|
||||
*/
|
||||
package org.alfresco.repo.version;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
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.NodeService;
|
||||
import org.alfresco.service.cmr.repository.Path;
|
||||
import org.alfresco.service.cmr.version.Version;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.service.namespace.RegexQNamePattern;
|
||||
import org.alfresco.util.debug.NodeStoreInspector;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* @author Roy Wetherall
|
||||
*/
|
||||
public class NodeServiceImplTest extends BaseVersionStoreTest
|
||||
{
|
||||
private static Log logger = LogFactory.getLog(NodeServiceImplTest.class);
|
||||
|
||||
/**
|
||||
* Light weight version store node service
|
||||
*/
|
||||
protected NodeService lightWeightVersionStoreNodeService = null;
|
||||
|
||||
/**
|
||||
* Error message
|
||||
*/
|
||||
private final static String MSG_ERR =
|
||||
"This operation is not supported by a version store implementation of the node service.";
|
||||
|
||||
/**
|
||||
* Dummy data used in failure tests
|
||||
*/
|
||||
private NodeRef dummyNodeRef = null;
|
||||
private QName dummyQName = null;
|
||||
|
||||
/**
|
||||
* Called during the transaction setup
|
||||
*/
|
||||
protected void onSetUpInTransaction() throws Exception
|
||||
{
|
||||
super.onSetUpInTransaction();
|
||||
|
||||
// Get the node service by name
|
||||
this.lightWeightVersionStoreNodeService = (NodeService)this.applicationContext.getBean("versionNodeService");
|
||||
|
||||
// Create some dummy data used during the tests
|
||||
this.dummyNodeRef = new NodeRef(
|
||||
this.versionService.getVersionStoreReference(),
|
||||
"dummy");
|
||||
this.dummyQName = QName.createQName("{dummy}dummy");
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getType
|
||||
*/
|
||||
public void testGetType()
|
||||
{
|
||||
// Create a new versionable node
|
||||
NodeRef versionableNode = createNewVersionableNode();
|
||||
|
||||
// Create a new version
|
||||
Version version = createVersion(versionableNode, this.versionProperties);
|
||||
|
||||
// Get the type from the versioned state
|
||||
QName versionedType = this.lightWeightVersionStoreNodeService.getType(version.getFrozenStateNodeRef());
|
||||
assertNotNull(versionedType);
|
||||
assertEquals(this.dbNodeService.getType(versionableNode), versionedType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getProperties
|
||||
*/
|
||||
public void testGetProperties()
|
||||
{
|
||||
// Create a new versionable node
|
||||
NodeRef versionableNode = createNewVersionableNode();
|
||||
|
||||
// Get a list of the nodes properties
|
||||
Map<QName, Serializable> origProps = this.dbNodeService.getProperties(versionableNode);
|
||||
|
||||
// Create a new version
|
||||
Version version = createVersion(versionableNode, this.versionProperties);
|
||||
|
||||
// Get the properties of the versioned state
|
||||
Map<QName, Serializable> versionedProperties = this.lightWeightVersionStoreNodeService.getProperties(version.getFrozenStateNodeRef());
|
||||
//assertEquals(origProps.size(), versionedProperties.size());
|
||||
for (QName key : origProps.keySet())
|
||||
{
|
||||
assertTrue(versionedProperties.containsKey(key));
|
||||
assertEquals(origProps.get(key), versionedProperties.get(key));
|
||||
}
|
||||
|
||||
// TODO do futher versioning and check by changing values
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getProperty
|
||||
*/
|
||||
public void testGetProperty()
|
||||
{
|
||||
// Create a new versionable node
|
||||
NodeRef versionableNode = createNewVersionableNode();
|
||||
|
||||
// Create a new version
|
||||
Version version = createVersion(versionableNode, this.versionProperties);
|
||||
|
||||
// Check the property values can be retrieved
|
||||
Serializable value1 = this.lightWeightVersionStoreNodeService.getProperty(
|
||||
version.getFrozenStateNodeRef(),
|
||||
PROP_1);
|
||||
assertEquals(VALUE_1, value1);
|
||||
|
||||
// Check the multi values property specifically
|
||||
Collection<String> multiValue = (Collection<String>)this.lightWeightVersionStoreNodeService.getProperty(version.getFrozenStateNodeRef(), MULTI_PROP);
|
||||
assertNotNull(multiValue);
|
||||
assertEquals(2, multiValue.size());
|
||||
String[] array = multiValue.toArray(new String[multiValue.size()]);
|
||||
assertEquals(MULTI_VALUE_1, array[0]);
|
||||
assertEquals(MULTI_VALUE_2, array[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getChildAssocs
|
||||
*/
|
||||
public void testGetChildAssocs()
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
// Let's have a look at the version store ..
|
||||
System.out.println(NodeStoreInspector.dumpNodeStore(
|
||||
this.dbNodeService,
|
||||
this.versionService.getVersionStoreReference()) + "\n\n");
|
||||
logger.debug("");
|
||||
}
|
||||
|
||||
// Create a new versionable node
|
||||
NodeRef versionableNode = createNewVersionableNode();
|
||||
Collection<ChildAssociationRef> origionalChildren = this.dbNodeService.getChildAssocs(versionableNode);
|
||||
assertNotNull(origionalChildren);
|
||||
|
||||
// Store the origional children in a map for easy navigation later
|
||||
HashMap<String, ChildAssociationRef> origionalChildAssocRefs = new HashMap<String, ChildAssociationRef>();
|
||||
for (ChildAssociationRef ref : origionalChildren)
|
||||
{
|
||||
origionalChildAssocRefs.put(ref.getChildRef().getId(), ref);
|
||||
}
|
||||
|
||||
// Create a new version
|
||||
Version version = createVersion(versionableNode, this.versionProperties);
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
// Let's have a look at the version store ..
|
||||
System.out.println(NodeStoreInspector.dumpNodeStore(
|
||||
this.dbNodeService,
|
||||
this.versionService.getVersionStoreReference()));
|
||||
}
|
||||
|
||||
// Get the children of the versioned node
|
||||
Collection<ChildAssociationRef> versionedChildren = this.lightWeightVersionStoreNodeService.getChildAssocs(version.getFrozenStateNodeRef());
|
||||
assertNotNull(versionedChildren);
|
||||
assertEquals(origionalChildren.size(), versionedChildren.size());
|
||||
|
||||
for (ChildAssociationRef versionedChildRef : versionedChildren)
|
||||
{
|
||||
ChildAssociationRef origChildAssocRef = origionalChildAssocRefs.get(versionedChildRef.getChildRef().getId());
|
||||
assertNotNull(origChildAssocRef);
|
||||
|
||||
assertEquals(
|
||||
origChildAssocRef.getChildRef(),
|
||||
versionedChildRef.getChildRef());
|
||||
assertEquals(
|
||||
origChildAssocRef.isPrimary(),
|
||||
versionedChildRef.isPrimary());
|
||||
assertEquals(
|
||||
origChildAssocRef.getNthSibling(),
|
||||
versionedChildRef.getNthSibling());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getAssociationTargets
|
||||
*/
|
||||
public void testGetAssociationTargets()
|
||||
{
|
||||
// Create a new versionable node
|
||||
NodeRef versionableNode = createNewVersionableNode();
|
||||
|
||||
// Store the current details of the target associations
|
||||
List<AssociationRef> origAssocs = this.dbNodeService.getTargetAssocs(
|
||||
versionableNode,
|
||||
RegexQNamePattern.MATCH_ALL);
|
||||
|
||||
// Create a new version
|
||||
Version version = createVersion(versionableNode, this.versionProperties);
|
||||
|
||||
List<AssociationRef> assocs = this.lightWeightVersionStoreNodeService.getTargetAssocs(
|
||||
version.getFrozenStateNodeRef(),
|
||||
RegexQNamePattern.MATCH_ALL);
|
||||
assertNotNull(assocs);
|
||||
assertEquals(origAssocs.size(), assocs.size());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test hasAspect
|
||||
*/
|
||||
public void testHasAspect()
|
||||
{
|
||||
// Create a new versionable node
|
||||
NodeRef versionableNode = createNewVersionableNode();
|
||||
|
||||
// Create a new version
|
||||
Version version = createVersion(versionableNode, this.versionProperties);
|
||||
|
||||
boolean test1 = this.lightWeightVersionStoreNodeService.hasAspect(
|
||||
version.getFrozenStateNodeRef(),
|
||||
ContentModel.ASPECT_UIFACETS);
|
||||
assertFalse(test1);
|
||||
|
||||
boolean test2 = this.lightWeightVersionStoreNodeService.hasAspect(
|
||||
version.getFrozenStateNodeRef(),
|
||||
ContentModel.ASPECT_VERSIONABLE);
|
||||
assertTrue(test2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getAspects
|
||||
*/
|
||||
public void testGetAspects()
|
||||
{
|
||||
// Create a new versionable node
|
||||
NodeRef versionableNode = createNewVersionableNode();
|
||||
Set<QName> origAspects = this.dbNodeService.getAspects(versionableNode);
|
||||
|
||||
// Create a new version
|
||||
Version version = createVersion(versionableNode, this.versionProperties);
|
||||
|
||||
Set<QName> aspects = this.lightWeightVersionStoreNodeService.getAspects(version.getFrozenStateNodeRef());
|
||||
assertEquals(origAspects.size(), aspects.size());
|
||||
|
||||
// TODO check that the set's contain the same items
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getParentAssocs
|
||||
*/
|
||||
public void testGetParentAssocs()
|
||||
{
|
||||
// Create a new versionable node
|
||||
NodeRef versionableNode = createNewVersionableNode();
|
||||
|
||||
// Create a new version
|
||||
Version version = createVersion(versionableNode, this.versionProperties);
|
||||
NodeRef nodeRef = version.getFrozenStateNodeRef();
|
||||
|
||||
List<ChildAssociationRef> results = this.lightWeightVersionStoreNodeService.getParentAssocs(nodeRef);
|
||||
assertNotNull(results);
|
||||
assertEquals(1, results.size());
|
||||
ChildAssociationRef childAssoc = results.get(0);
|
||||
assertEquals(nodeRef, childAssoc.getChildRef());
|
||||
NodeRef versionStoreRoot = this.dbNodeService.getRootNode(this.versionService.getVersionStoreReference());
|
||||
assertEquals(versionStoreRoot, childAssoc.getParentRef());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getPrimaryParent
|
||||
*/
|
||||
public void testGetPrimaryParent()
|
||||
{
|
||||
// Create a new versionable node
|
||||
NodeRef versionableNode = createNewVersionableNode();
|
||||
|
||||
// Create a new version
|
||||
Version version = createVersion(versionableNode, this.versionProperties);
|
||||
NodeRef nodeRef = version.getFrozenStateNodeRef();
|
||||
|
||||
ChildAssociationRef childAssoc = this.lightWeightVersionStoreNodeService.getPrimaryParent(nodeRef);
|
||||
assertNotNull(childAssoc);
|
||||
assertEquals(nodeRef, childAssoc.getChildRef());
|
||||
NodeRef versionStoreRoot = this.dbNodeService.getRootNode(this.versionService.getVersionStoreReference());
|
||||
assertEquals(versionStoreRoot, childAssoc.getParentRef());
|
||||
}
|
||||
|
||||
/** ================================================
|
||||
* These test ensure that the following operations
|
||||
* are not supported as expected.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Test createNode
|
||||
*/
|
||||
public void testCreateNode()
|
||||
{
|
||||
try
|
||||
{
|
||||
this.lightWeightVersionStoreNodeService.createNode(
|
||||
dummyNodeRef,
|
||||
null,
|
||||
dummyQName,
|
||||
ContentModel.TYPE_CONTENT);
|
||||
fail("This operation is not supported.");
|
||||
}
|
||||
catch (UnsupportedOperationException exception)
|
||||
{
|
||||
if (exception.getMessage() != MSG_ERR)
|
||||
{
|
||||
fail("Unexpected exception raised during method excution: " + exception.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test addAspect
|
||||
*/
|
||||
public void testAddAspect()
|
||||
{
|
||||
try
|
||||
{
|
||||
this.lightWeightVersionStoreNodeService.addAspect(
|
||||
dummyNodeRef,
|
||||
TEST_ASPECT_QNAME,
|
||||
null);
|
||||
fail("This operation is not supported.");
|
||||
}
|
||||
catch (UnsupportedOperationException exception)
|
||||
{
|
||||
if (exception.getMessage() != MSG_ERR)
|
||||
{
|
||||
fail("Unexpected exception raised during method excution: " + exception.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test removeAspect
|
||||
*/
|
||||
public void testRemoveAspect()
|
||||
{
|
||||
try
|
||||
{
|
||||
this.lightWeightVersionStoreNodeService.removeAspect(
|
||||
dummyNodeRef,
|
||||
TEST_ASPECT_QNAME);
|
||||
fail("This operation is not supported.");
|
||||
}
|
||||
catch (UnsupportedOperationException exception)
|
||||
{
|
||||
if (exception.getMessage() != MSG_ERR)
|
||||
{
|
||||
fail("Unexpected exception raised during method excution: " + exception.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test delete node
|
||||
*/
|
||||
public void testDeleteNode()
|
||||
{
|
||||
try
|
||||
{
|
||||
this.lightWeightVersionStoreNodeService.deleteNode(this.dummyNodeRef);
|
||||
fail("This operation is not supported.");
|
||||
}
|
||||
catch (UnsupportedOperationException exception)
|
||||
{
|
||||
if (exception.getMessage() != MSG_ERR)
|
||||
{
|
||||
fail("Unexpected exception raised during method excution: " + exception.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test addChild
|
||||
*/
|
||||
public void testAddChild()
|
||||
{
|
||||
try
|
||||
{
|
||||
this.lightWeightVersionStoreNodeService.addChild(
|
||||
this.dummyNodeRef,
|
||||
this.dummyNodeRef,
|
||||
this.dummyQName,
|
||||
this.dummyQName);
|
||||
fail("This operation is not supported.");
|
||||
}
|
||||
catch (UnsupportedOperationException exception)
|
||||
{
|
||||
if (exception.getMessage() != MSG_ERR)
|
||||
{
|
||||
fail("Unexpected exception raised during method excution: " + exception.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test removeChild
|
||||
*/
|
||||
public void testRemoveChild()
|
||||
{
|
||||
try
|
||||
{
|
||||
this.lightWeightVersionStoreNodeService.removeChild(
|
||||
this.dummyNodeRef,
|
||||
this.dummyNodeRef);
|
||||
fail("This operation is not supported.");
|
||||
}
|
||||
catch (UnsupportedOperationException exception)
|
||||
{
|
||||
if (exception.getMessage() != MSG_ERR)
|
||||
{
|
||||
fail("Unexpected exception raised during method excution: " + exception.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test setProperties
|
||||
*/
|
||||
public void testSetProperties()
|
||||
{
|
||||
try
|
||||
{
|
||||
this.lightWeightVersionStoreNodeService.setProperties(
|
||||
this.dummyNodeRef,
|
||||
new HashMap<QName, Serializable>());
|
||||
fail("This operation is not supported.");
|
||||
}
|
||||
catch (UnsupportedOperationException exception)
|
||||
{
|
||||
if (exception.getMessage() != MSG_ERR)
|
||||
{
|
||||
fail("Unexpected exception raised during method excution: " + exception.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test setProperty
|
||||
*/
|
||||
public void testSetProperty()
|
||||
{
|
||||
try
|
||||
{
|
||||
this.lightWeightVersionStoreNodeService.setProperty(
|
||||
this.dummyNodeRef,
|
||||
this.dummyQName,
|
||||
"dummy");
|
||||
fail("This operation is not supported.");
|
||||
}
|
||||
catch (UnsupportedOperationException exception)
|
||||
{
|
||||
if (exception.getMessage() != MSG_ERR)
|
||||
{
|
||||
fail("Unexpected exception raised during method excution: " + exception.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test createAssociation
|
||||
*/
|
||||
public void testCreateAssociation()
|
||||
{
|
||||
try
|
||||
{
|
||||
this.lightWeightVersionStoreNodeService.createAssociation(
|
||||
this.dummyNodeRef,
|
||||
this.dummyNodeRef,
|
||||
this.dummyQName);
|
||||
fail("This operation is not supported.");
|
||||
}
|
||||
catch (UnsupportedOperationException exception)
|
||||
{
|
||||
if (exception.getMessage() != MSG_ERR)
|
||||
{
|
||||
fail("Unexpected exception raised during method excution: " + exception.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test removeAssociation
|
||||
*/
|
||||
public void testRemoveAssociation()
|
||||
{
|
||||
try
|
||||
{
|
||||
this.lightWeightVersionStoreNodeService.removeAssociation(
|
||||
this.dummyNodeRef,
|
||||
this.dummyNodeRef,
|
||||
this.dummyQName);
|
||||
fail("This operation is not supported.");
|
||||
}
|
||||
catch (UnsupportedOperationException exception)
|
||||
{
|
||||
if (exception.getMessage() != MSG_ERR)
|
||||
{
|
||||
fail("Unexpected exception raised during method excution: " + exception.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getAssociationSources
|
||||
*/
|
||||
public void testGetAssociationSources()
|
||||
{
|
||||
try
|
||||
{
|
||||
this.lightWeightVersionStoreNodeService.getSourceAssocs(
|
||||
this.dummyNodeRef,
|
||||
this.dummyQName);
|
||||
fail("This operation is not supported.");
|
||||
}
|
||||
catch (UnsupportedOperationException exception)
|
||||
{
|
||||
if (exception.getMessage() != MSG_ERR)
|
||||
{
|
||||
fail("Unexpected exception raised during method excution: " + exception.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getPath
|
||||
*/
|
||||
public void testGetPath()
|
||||
{
|
||||
Path path = this.lightWeightVersionStoreNodeService.getPath(this.dummyNodeRef);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getPaths
|
||||
*/
|
||||
public void testGetPaths()
|
||||
{
|
||||
List<Path> paths = this.lightWeightVersionStoreNodeService.getPaths(this.dummyNodeRef, false);
|
||||
}
|
||||
}
|
111
source/java/org/alfresco/repo/version/VersionBootstrap.java
Normal file
111
source/java/org/alfresco/repo/version/VersionBootstrap.java
Normal file
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
* copy of the License at
|
||||
*
|
||||
* http://www.alfresco.org/legal/license.txt
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the
|
||||
* License.
|
||||
*/
|
||||
package org.alfresco.repo.version;
|
||||
|
||||
import javax.transaction.UserTransaction;
|
||||
|
||||
import org.alfresco.error.AlfrescoRuntimeException;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationComponent;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.cmr.repository.StoreRef;
|
||||
import org.alfresco.service.cmr.security.PermissionService;
|
||||
import org.alfresco.service.transaction.TransactionService;
|
||||
|
||||
/**
|
||||
* Bootstrap Version Store
|
||||
*
|
||||
* @author David Caruana
|
||||
*/
|
||||
public class VersionBootstrap
|
||||
{
|
||||
private TransactionService transactionService;
|
||||
private NodeService nodeService;
|
||||
private AuthenticationComponent authenticationComponent;
|
||||
private PermissionService permissionService;
|
||||
|
||||
|
||||
/**
|
||||
* Sets the Transaction Service
|
||||
*
|
||||
* @param userTransaction the user transaction
|
||||
*/
|
||||
public void setTransactionService(TransactionService transactionService)
|
||||
{
|
||||
this.transactionService = transactionService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Node Service
|
||||
*
|
||||
* @param nodeService the node service
|
||||
*/
|
||||
public void setNodeService(NodeService nodeService)
|
||||
{
|
||||
this.nodeService = nodeService;
|
||||
}
|
||||
|
||||
public void setAuthenticationComponent(AuthenticationComponent authenticationComponent)
|
||||
{
|
||||
this.authenticationComponent = authenticationComponent;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void setPermissionService(PermissionService permissionService)
|
||||
{
|
||||
this.permissionService = permissionService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bootstrap the Version Store
|
||||
*/
|
||||
public void bootstrap()
|
||||
{
|
||||
UserTransaction userTransaction = transactionService.getUserTransaction();
|
||||
authenticationComponent.setCurrentUser(authenticationComponent.getSystemUserName());
|
||||
|
||||
try
|
||||
{
|
||||
userTransaction.begin();
|
||||
|
||||
// Ensure that the version store has been created
|
||||
if (this.nodeService.exists(new StoreRef(StoreRef.PROTOCOL_WORKSPACE, VersionModel.STORE_ID)) == true)
|
||||
{
|
||||
userTransaction.rollback();
|
||||
}
|
||||
else
|
||||
{
|
||||
StoreRef vStore = this.nodeService.createStore(StoreRef.PROTOCOL_WORKSPACE, VersionModel.STORE_ID);
|
||||
// TODO: For now there are no permissions on version access
|
||||
permissionService.setPermission(nodeService.getRootNode(vStore), permissionService.getAllAuthorities(), permissionService.getAllPermission(), true);
|
||||
userTransaction.commit();
|
||||
}
|
||||
}
|
||||
catch(Throwable e)
|
||||
{
|
||||
// rollback the transaction
|
||||
try { if (userTransaction != null) {userTransaction.rollback();} } catch (Exception ex) {}
|
||||
try {authenticationComponent.clearCurrentSecurityContext(); } catch (Exception ex) {}
|
||||
throw new AlfrescoRuntimeException("Bootstrap failed", e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
authenticationComponent.clearCurrentSecurityContext();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
161
source/java/org/alfresco/repo/version/VersionModel.java
Normal file
161
source/java/org/alfresco/repo/version/VersionModel.java
Normal file
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
* copy of the License at
|
||||
*
|
||||
* http://www.alfresco.org/legal/license.txt
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the
|
||||
* License.
|
||||
*/
|
||||
package org.alfresco.repo.version;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.service.cmr.version.VersionService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
|
||||
/**
|
||||
* interface conating the constants used by the light weight
|
||||
* version store implementation
|
||||
*
|
||||
* @author Roy Wetherall
|
||||
*/
|
||||
public interface VersionModel
|
||||
{
|
||||
/**
|
||||
* Namespace
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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";
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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 ASSOC_ROOT_VERSION = QName.createQName(NAMESPACE_URI, "rootVersion");
|
||||
|
||||
/**
|
||||
* Verison type
|
||||
*/
|
||||
public static final String TYPE_VERSION = "version";
|
||||
public static final QName TYPE_QNAME_VERSION = QName.createQName(NAMESPACE_URI, TYPE_VERSION);
|
||||
|
||||
/**
|
||||
* Version type properties and associations
|
||||
*/
|
||||
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_FROZEN_NODE_ID = QName.createQName(NAMESPACE_URI, PROP_FROZEN_NODE_ID);
|
||||
public static final QName PROP_QNAME_FROZEN_NODE_TYPE = QName.createQName(NAMESPACE_URI, PROP_FROZEN_NODE_TYPE);
|
||||
public static final QName PROP_QNAME_FROZEN_NODE_STORE_PROTOCOL = QName.createQName(NAMESPACE_URI, PROP_FROZEN_NODE_STORE_PROTOCOL);
|
||||
public static final QName PROP_QNAME_FROZEN_NODE_STORE_ID = QName.createQName(NAMESPACE_URI, PROP_FROZEN_NODE_STORE_ID);
|
||||
public static final QName PROP_QNAME_FROZEN_ASPECTS = QName.createQName(NAMESPACE_URI, PROP_FROZEN_ASPECTS);
|
||||
public static final QName ASSOC_SUCCESSOR = QName.createQName(NAMESPACE_URI, "successor");
|
||||
|
||||
/**
|
||||
* Version Meta Data Value type
|
||||
*/
|
||||
public static final String TYPE_VERSION_META_DATA_VALUE = "versionMetaDataValue";
|
||||
public static final QName TYPE_QNAME_VERSION_META_DATA_VALUE = QName.createQName(NAMESPACE_URI, TYPE_VERSION_META_DATA_VALUE);
|
||||
|
||||
/**
|
||||
* Version Meta Data Value attributes
|
||||
*/
|
||||
public static final String PROP_META_DATA_NAME = "metaDataName";
|
||||
public static final QName PROP_QNAME_META_DATA_NAME = QName.createQName(NAMESPACE_URI, PROP_META_DATA_NAME);
|
||||
public static final String PROP_META_DATA_VALUE = "metaDataValue";
|
||||
public static final QName PROP_QNAME_META_DATA_VALUE = QName.createQName(NAMESPACE_URI, PROP_META_DATA_VALUE);
|
||||
|
||||
/**
|
||||
* Versioned attribute type
|
||||
*/
|
||||
public static final String TYPE_VERSIONED_PROPERTY = "versionedProperty";
|
||||
public static final QName TYPE_QNAME_VERSIONED_PROPERTY = QName.createQName(NAMESPACE_URI, TYPE_VERSIONED_PROPERTY);
|
||||
|
||||
/**
|
||||
* Versioned attribute properties
|
||||
*/
|
||||
public static final String PROP_QNAME = "qname";
|
||||
public static final String PROP_VALUE = "value";
|
||||
public static final String PROP_MULTI_VALUE = "multiValue";
|
||||
public static final String PROP_IS_MULTI_VALUE = "isMultiValue";
|
||||
public static final QName PROP_QNAME_QNAME = QName.createQName(NAMESPACE_URI, PROP_QNAME);
|
||||
public static final QName PROP_QNAME_VALUE = QName.createQName(NAMESPACE_URI, PROP_VALUE);
|
||||
public static final QName PROP_QNAME_MULTI_VALUE = QName.createQName(NAMESPACE_URI, PROP_MULTI_VALUE);
|
||||
public static final QName PROP_QNAME_IS_MULTI_VALUE = QName.createQName(NAMESPACE_URI, PROP_IS_MULTI_VALUE);
|
||||
|
||||
/**
|
||||
* Versioned child assoc type
|
||||
*/
|
||||
public static final String TYPE_VERSIONED_CHILD_ASSOC = "versionedChildAssoc";
|
||||
public static final QName TYPE_QNAME_VERSIONED_CHILD_ASSOC = QName.createQName(NAMESPACE_URI, TYPE_VERSIONED_CHILD_ASSOC);
|
||||
|
||||
/**
|
||||
* Versioned child assoc properties
|
||||
*/
|
||||
public static final String PROP_ASSOC_QNAME = "assocQName";
|
||||
public static final String PROP_ASSOC_TYPE_QNAME = "assocTypeQName";
|
||||
public static final String PROP_IS_PRIMARY = "isPrimary";
|
||||
public static final String PROP_NTH_SIBLING = "nthSibling";
|
||||
public static final QName PROP_QNAME_ASSOC_QNAME = QName.createQName(NAMESPACE_URI, PROP_ASSOC_QNAME);
|
||||
public static final QName PROP_QNAME_ASSOC_TYPE_QNAME = QName.createQName(NAMESPACE_URI, PROP_ASSOC_TYPE_QNAME);
|
||||
public static final QName PROP_QNAME_IS_PRIMARY = QName.createQName(NAMESPACE_URI, PROP_IS_PRIMARY);
|
||||
public static final QName PROP_QNAME_NTH_SIBLING = QName.createQName(NAMESPACE_URI, PROP_NTH_SIBLING);
|
||||
|
||||
/**
|
||||
* Versioned assoc type
|
||||
*/
|
||||
public static final String TYPE_VERSIONED_ASSOC = "versionedAssoc";
|
||||
public static final QName TYPE_QNAME_VERSIONED_ASSOC = QName.createQName(NAMESPACE_URI, TYPE_VERSIONED_ASSOC);
|
||||
|
||||
/**
|
||||
* 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_CHILD_ASSOCS = "versionedChildAssocs";
|
||||
public static final String CHILD_VERSIONED_ASSOCS = "versionedAssocs";
|
||||
public static final String CHILD_VERSION_META_DATA = "versionMetaData";
|
||||
|
||||
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);
|
||||
public static final QName CHILD_QNAME_VERSIONED_ATTRIBUTES = QName.createQName(NAMESPACE_URI, CHILD_VERSIONED_ATTRIBUTES);
|
||||
public static final QName CHILD_QNAME_VERSIONED_CHILD_ASSOCS = QName.createQName(NAMESPACE_URI, CHILD_VERSIONED_CHILD_ASSOCS);
|
||||
public static final QName CHILD_QNAME_VERSIONED_ASSOCS = QName.createQName(NAMESPACE_URI, CHILD_VERSIONED_ASSOCS);
|
||||
public static final QName CHILD_QNAME_VERSION_META_DATA = QName.createQName(NAMESPACE_URI, CHILD_VERSION_META_DATA);
|
||||
}
|
1119
source/java/org/alfresco/repo/version/VersionServiceImpl.java
Normal file
1119
source/java/org/alfresco/repo/version/VersionServiceImpl.java
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,466 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
* copy of the License at
|
||||
*
|
||||
* http://www.alfresco.org/legal/license.txt
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the
|
||||
* License.
|
||||
*/
|
||||
package org.alfresco.repo.version;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.transaction.TransactionUtil;
|
||||
import org.alfresco.service.cmr.repository.ContentReader;
|
||||
import org.alfresco.service.cmr.repository.ContentWriter;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.version.Version;
|
||||
import org.alfresco.service.cmr.version.VersionHistory;
|
||||
import org.alfresco.service.cmr.version.VersionServiceException;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
|
||||
/**
|
||||
* versionService test class.
|
||||
*
|
||||
* @author Roy Wetherall
|
||||
*/
|
||||
public class VersionServiceImplTest extends BaseVersionStoreTest
|
||||
{
|
||||
private static final String UPDATED_VALUE_1 = "updatedValue1";
|
||||
private static final String UPDATED_VALUE_2 = "updatedValue2";
|
||||
private static final String UPDATED_VALUE_3 = "updatedValue3";
|
||||
private static final String UPDATED_CONTENT_1 = "updatedContent1";
|
||||
private static final String UPDATED_CONTENT_2 = "updatedContent2";
|
||||
|
||||
/**
|
||||
* Tests the creation of the initial version of a versionable node
|
||||
*/
|
||||
public void testCreateIntialVersion()
|
||||
{
|
||||
NodeRef versionableNode = createNewVersionableNode();
|
||||
createVersion(versionableNode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test creating a version history with many versions from the same workspace
|
||||
*/
|
||||
public void testCreateManyVersionsSameWorkspace()
|
||||
{
|
||||
NodeRef versionableNode = createNewVersionableNode();
|
||||
createVersion(versionableNode);
|
||||
// TODO mess with some of the properties and stuff as you version
|
||||
createVersion(versionableNode);
|
||||
// TODO mess with some of the properties and stuff as you version
|
||||
createVersion(versionableNode);
|
||||
}
|
||||
|
||||
// TODO test versioning a non versionable node ie: no version apsect
|
||||
|
||||
// TODO test versioning numberious times with branchs implies by different workspaces
|
||||
|
||||
/**
|
||||
* Test versioning the children of a verionable node
|
||||
*/
|
||||
public void testVersioningChildren()
|
||||
{
|
||||
NodeRef versionableNode = createNewVersionableNode();
|
||||
|
||||
// Snap shot data
|
||||
int expectedVersionNumber = peekNextVersionNumber();
|
||||
String expectedVersionLabel = peekNextVersionLabel(versionableNode, expectedVersionNumber, versionProperties);
|
||||
long beforeVersionTime = System.currentTimeMillis();
|
||||
|
||||
// Version the node and its children
|
||||
Collection<Version> versions = this.versionService.createVersion(
|
||||
versionableNode,
|
||||
this.versionProperties,
|
||||
true);
|
||||
|
||||
// Check the returned versions are correct
|
||||
CheckVersionCollection(expectedVersionNumber, expectedVersionLabel, beforeVersionTime, versions);
|
||||
|
||||
// TODO check the version history is correct
|
||||
}
|
||||
|
||||
/**
|
||||
* Test versioning many nodes in one go
|
||||
*/
|
||||
public void testVersioningManyNodes()
|
||||
{
|
||||
NodeRef versionableNode = createNewVersionableNode();
|
||||
|
||||
// Snap shot data
|
||||
int expectedVersionNumber = peekNextVersionNumber();
|
||||
String expectedVersionLabel = peekNextVersionLabel(versionableNode, expectedVersionNumber, versionProperties);
|
||||
long beforeVersionTime = System.currentTimeMillis();
|
||||
|
||||
// Version the list of nodes created
|
||||
Collection<Version> versions = this.versionService.createVersion(
|
||||
this.versionableNodes.values(),
|
||||
this.versionProperties);
|
||||
|
||||
// Check the returned versions are correct
|
||||
CheckVersionCollection(expectedVersionNumber, expectedVersionLabel, beforeVersionTime, versions);
|
||||
|
||||
// TODO check the version histories
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 = (String)version.getVersionProperty(VersionModel.PROP_FROZEN_NODE_ID);
|
||||
assertNotNull("Unable to retrieve the frozen node id from the created version.", frozenNodeId);
|
||||
|
||||
// Get the origional 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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the version history
|
||||
*/
|
||||
public void testNoVersionHistory()
|
||||
{
|
||||
NodeRef nodeRef = createNewVersionableNode();
|
||||
|
||||
VersionHistory vh = this.versionService.getVersionHistory(nodeRef);
|
||||
assertNull(vh);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests getVersionHistory when all the entries in the version history
|
||||
* are from the same workspace.
|
||||
*/
|
||||
public void testGetVersionHistorySameWorkspace()
|
||||
{
|
||||
NodeRef versionableNode = createNewVersionableNode();
|
||||
|
||||
Version version1 = addToVersionHistory(versionableNode, null);
|
||||
Version version2 = addToVersionHistory(versionableNode, version1);
|
||||
Version version3 = addToVersionHistory(versionableNode, version2);
|
||||
Version version4 = addToVersionHistory(versionableNode, version3);
|
||||
addToVersionHistory(versionableNode, version4);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds another version to the version history then checks that getVersionHistory is returning
|
||||
* the correct data.
|
||||
*
|
||||
* @param versionableNode the versionable node reference
|
||||
* @param parentVersion the parent version
|
||||
*/
|
||||
private Version addToVersionHistory(NodeRef versionableNode, Version parentVersion)
|
||||
{
|
||||
Version createdVersion = createVersion(versionableNode);
|
||||
|
||||
VersionHistory vh = this.versionService.getVersionHistory(versionableNode);
|
||||
assertNotNull("The version history should not be null since we know we have versioned this node.", vh);
|
||||
|
||||
if (parentVersion == null)
|
||||
{
|
||||
// Check the root is the newly created version
|
||||
Version root = vh.getRootVersion();
|
||||
assertNotNull(
|
||||
"The root version should never be null, since every version history ust have a root version.",
|
||||
root);
|
||||
assertEquals(createdVersion.getVersionLabel(), root.getVersionLabel());
|
||||
}
|
||||
|
||||
// Get the version from the version history
|
||||
Version version = vh.getVersion(createdVersion.getVersionLabel());
|
||||
assertNotNull(version);
|
||||
assertEquals(createdVersion.getVersionLabel(), version.getVersionLabel());
|
||||
|
||||
// Check that the version is a leaf node of the version history (since it is newly created)
|
||||
Collection<Version> suc = vh.getSuccessors(version);
|
||||
assertNotNull(suc);
|
||||
assertEquals(0, suc.size());
|
||||
|
||||
// Check that the predessor is the passed parent version (if root version should be null)
|
||||
Version pre = vh.getPredecessor(version);
|
||||
if (parentVersion == null)
|
||||
{
|
||||
assertNull(pre);
|
||||
}
|
||||
else
|
||||
{
|
||||
assertNotNull(pre);
|
||||
assertEquals(parentVersion.getVersionLabel(), pre.getVersionLabel());
|
||||
}
|
||||
|
||||
if (parentVersion != null)
|
||||
{
|
||||
// Check that the successors of the parent are the created version
|
||||
Collection<Version> parentSuc = vh.getSuccessors(parentVersion);
|
||||
assertNotNull(parentSuc);
|
||||
assertEquals(1, parentSuc.size());
|
||||
Version tempVersion = (Version)parentSuc.toArray()[0];
|
||||
assertEquals(version.getVersionLabel(), tempVersion.getVersionLabel());
|
||||
}
|
||||
|
||||
return createdVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test revert
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public void testRevert()
|
||||
{
|
||||
// Create a versionable node
|
||||
NodeRef versionableNode = createNewVersionableNode();
|
||||
|
||||
// Store the node details for later
|
||||
Set<QName> origAspects = this.dbNodeService.getAspects(versionableNode);
|
||||
|
||||
// Create the initial version
|
||||
Version version1 = createVersion(versionableNode);
|
||||
|
||||
// Change the property and content values
|
||||
this.dbNodeService.setProperty(versionableNode, PROP_1, UPDATED_VALUE_1);
|
||||
this.dbNodeService.setProperty(versionableNode, PROP_2, null);
|
||||
ContentWriter contentWriter = this.contentService.getWriter(versionableNode, ContentModel.PROP_CONTENT, true);
|
||||
assertNotNull(contentWriter);
|
||||
contentWriter.putContent(UPDATED_CONTENT_1);
|
||||
|
||||
// Change the aspects on the node
|
||||
this.dbNodeService.addAspect(versionableNode, ContentModel.ASPECT_SIMPLE_WORKFLOW, null);
|
||||
|
||||
// Store the node details for later
|
||||
Set<QName> origAspects2 = this.dbNodeService.getAspects(versionableNode);
|
||||
|
||||
// Create a new version
|
||||
Version version2 = createVersion(versionableNode);
|
||||
|
||||
// Change the property and content values
|
||||
this.dbNodeService.setProperty(versionableNode, PROP_1, UPDATED_VALUE_2);
|
||||
this.dbNodeService.setProperty(versionableNode, PROP_2, UPDATED_VALUE_3);
|
||||
this.dbNodeService.setProperty(versionableNode, PROP_3, null);
|
||||
ContentWriter contentWriter2 = this.contentService.getWriter(versionableNode, ContentModel.PROP_CONTENT, true);
|
||||
assertNotNull(contentWriter2);
|
||||
contentWriter2.putContent(UPDATED_CONTENT_2);
|
||||
|
||||
String versionLabel = (String)this.dbNodeService.getProperty(versionableNode, ContentModel.PROP_VERSION_LABEL);
|
||||
|
||||
// Revert to the previous version
|
||||
this.versionService.revert(versionableNode);
|
||||
|
||||
// Check that the version label is unchanged
|
||||
assertEquals(versionLabel, this.dbNodeService.getProperty(versionableNode, ContentModel.PROP_VERSION_LABEL));
|
||||
|
||||
// Check that the properties have been reverted
|
||||
assertEquals(UPDATED_VALUE_1, this.dbNodeService.getProperty(versionableNode, PROP_1));
|
||||
assertNull(this.dbNodeService.getProperty(versionableNode, PROP_2));
|
||||
assertEquals(VALUE_3, this.dbNodeService.getProperty(versionableNode, PROP_3));
|
||||
|
||||
// Check that the content has been reverted
|
||||
ContentReader contentReader1 = this.contentService.getReader(versionableNode, ContentModel.PROP_CONTENT);
|
||||
assertNotNull(contentReader1);
|
||||
assertEquals(UPDATED_CONTENT_1, contentReader1.getContentString());
|
||||
|
||||
// Check that the aspects have been reverted correctly
|
||||
Set<QName> aspects1 = this.dbNodeService.getAspects(versionableNode);
|
||||
assertEquals(aspects1.size(), origAspects2.size());
|
||||
|
||||
// Revert to the first version
|
||||
this.versionService.revert(versionableNode, version1);
|
||||
|
||||
// Check that the version label is correct
|
||||
assertEquals(versionLabel, this.dbNodeService.getProperty(versionableNode, ContentModel.PROP_VERSION_LABEL));
|
||||
|
||||
// Check that the properties are correct
|
||||
assertEquals(VALUE_1, this.dbNodeService.getProperty(versionableNode, PROP_1));
|
||||
assertEquals(VALUE_2, this.dbNodeService.getProperty(versionableNode, PROP_2));
|
||||
assertEquals(VALUE_3, this.dbNodeService.getProperty(versionableNode, PROP_3));
|
||||
|
||||
// Check that the content is correct
|
||||
ContentReader contentReader2 = this.contentService.getReader(versionableNode, ContentModel.PROP_CONTENT);
|
||||
assertNotNull(contentReader2);
|
||||
assertEquals(TEST_CONTENT, contentReader2.getContentString());
|
||||
|
||||
// Check that the aspects have been reverted correctly
|
||||
Set<QName> aspects2 = this.dbNodeService.getAspects(versionableNode);
|
||||
assertEquals(aspects2.size(), origAspects.size());
|
||||
|
||||
// Check that the version label is still the same
|
||||
assertEquals(versionLabel, this.dbNodeService.getProperty(versionableNode, ContentModel.PROP_VERSION_LABEL));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test restore
|
||||
*/
|
||||
public void testRestore()
|
||||
{
|
||||
// Try and restore a node without any version history
|
||||
try
|
||||
{
|
||||
this.versionService.restore(
|
||||
new NodeRef(this.testStoreRef, "123"),
|
||||
rootNodeRef,
|
||||
ContentModel.ASSOC_CHILDREN,
|
||||
QName.createQName("{test}MyVersionableNode"));
|
||||
fail("An exception should have been raised since this node has no version history.");
|
||||
}
|
||||
catch (VersionServiceException exception)
|
||||
{
|
||||
// We where expecting this exception
|
||||
}
|
||||
|
||||
// Create a versionable node
|
||||
NodeRef versionableNode = createNewVersionableNode();
|
||||
|
||||
// Store the node details for later
|
||||
Set<QName> origAspects = this.dbNodeService.getAspects(versionableNode);
|
||||
|
||||
// Try and restore the node (fail since exist!!)
|
||||
try
|
||||
{
|
||||
this.versionService.restore(
|
||||
versionableNode,
|
||||
rootNodeRef,
|
||||
ContentModel.ASSOC_CHILDREN,
|
||||
QName.createQName("{test}MyVersionableNode"));
|
||||
fail("An exception should have been raised since this node exists and you can't restore a node that exists.");
|
||||
}
|
||||
catch (VersionServiceException exception)
|
||||
{
|
||||
// We where expecting this exception
|
||||
}
|
||||
|
||||
// Version it
|
||||
this.versionService.createVersion(versionableNode, null);
|
||||
|
||||
// Delete it
|
||||
this.dbNodeService.deleteNode(versionableNode);
|
||||
assertFalse(this.dbNodeService.exists(versionableNode));
|
||||
|
||||
// Try and resotre it
|
||||
NodeRef restoredNode = this.versionService.restore(
|
||||
versionableNode,
|
||||
this.rootNodeRef,
|
||||
ContentModel.ASSOC_CHILDREN,
|
||||
QName.createQName("{test}MyVersionableNode"));
|
||||
|
||||
assertNotNull(restoredNode);
|
||||
assertTrue(this.dbNodeService.exists(restoredNode));
|
||||
|
||||
// Check that the properties are correct
|
||||
assertEquals(VALUE_1, this.dbNodeService.getProperty(restoredNode, PROP_1));
|
||||
assertEquals(VALUE_2, this.dbNodeService.getProperty(restoredNode, PROP_2));
|
||||
assertEquals(VALUE_3, this.dbNodeService.getProperty(restoredNode, PROP_3));
|
||||
|
||||
// Check that the content is correct
|
||||
ContentReader contentReader2 = this.contentService.getReader(restoredNode, ContentModel.PROP_CONTENT);
|
||||
assertNotNull(contentReader2);
|
||||
assertEquals(TEST_CONTENT, contentReader2.getContentString());
|
||||
|
||||
// Check that the aspects have been reverted correctly
|
||||
Set<QName> aspects2 = this.dbNodeService.getAspects(restoredNode);
|
||||
assertEquals(aspects2.size(), origAspects.size());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test deleteVersionHistory
|
||||
*/
|
||||
public void testDeleteVersionHistory()
|
||||
{
|
||||
// Create a versionable node
|
||||
NodeRef versionableNode = createNewVersionableNode();
|
||||
|
||||
// Check that there is no version history
|
||||
VersionHistory versionHistory1 = this.versionService.getVersionHistory(versionableNode);
|
||||
assertNull(versionHistory1);
|
||||
|
||||
// Create a couple of versions
|
||||
createVersion(versionableNode);
|
||||
Version version1 = createVersion(versionableNode);
|
||||
|
||||
// Check that the version label is correct on the versionable node
|
||||
String versionLabel1 = (String)this.dbNodeService.getProperty(versionableNode, ContentModel.PROP_VERSION_LABEL);
|
||||
assertNotNull(versionLabel1);
|
||||
assertEquals(version1.getVersionLabel(), versionLabel1);
|
||||
|
||||
// Check that the version history has been created correctly
|
||||
VersionHistory versionHistory2 = this.versionService.getVersionHistory(versionableNode);
|
||||
assertNotNull(versionHistory2);
|
||||
assertEquals(2, versionHistory2.getAllVersions().size());
|
||||
|
||||
// Delete the version history
|
||||
this.versionService.deleteVersionHistory(versionableNode);
|
||||
|
||||
// Check that there is no version history available for the node
|
||||
VersionHistory versionHistory3 = this.versionService.getVersionHistory(versionableNode);
|
||||
assertNull(versionHistory3);
|
||||
|
||||
// Check that the current version property on the versionable node is no longer set
|
||||
String versionLabel2 = (String)this.dbNodeService.getProperty(versionableNode, ContentModel.PROP_VERSION_LABEL);
|
||||
assertNull(versionLabel2);
|
||||
|
||||
// Create a couple of versions
|
||||
createVersion(versionableNode);
|
||||
Version version2 = createVersion(versionableNode);
|
||||
|
||||
// Check that the version history is correct
|
||||
VersionHistory versionHistory4 = this.versionService.getVersionHistory(versionableNode);
|
||||
assertNotNull(versionHistory4);
|
||||
assertEquals(2, versionHistory4.getAllVersions().size());
|
||||
|
||||
// Check that the version label is correct on the versionable node
|
||||
String versionLabel3 = (String)this.dbNodeService.getProperty(versionableNode, ContentModel.PROP_VERSION_LABEL);
|
||||
assertNotNull(versionLabel3);
|
||||
assertEquals(version2.getVersionLabel(), versionLabel3);
|
||||
|
||||
}
|
||||
|
||||
public void testAutoVersion()
|
||||
{
|
||||
// Create a versionable node
|
||||
final NodeRef versionableNode = createNewVersionableNode();
|
||||
|
||||
// Add some content
|
||||
ContentWriter contentWriter = this.contentService.getWriter(versionableNode, ContentModel.PROP_CONTENT, true);
|
||||
assertNotNull(contentWriter);
|
||||
contentWriter.putContent(UPDATED_CONTENT_1);
|
||||
|
||||
// Need to commit in order to get the auto version to fire ...
|
||||
setComplete();
|
||||
endTransaction();
|
||||
|
||||
// Now lets have a look and make sure we have the correct number of entries in the version history
|
||||
TransactionUtil.executeInUserTransaction(this.transactionService, new TransactionUtil.TransactionWork<Object>()
|
||||
{
|
||||
public Object doWork() throws Exception
|
||||
{
|
||||
VersionHistory versionHistory = VersionServiceImplTest.this.versionService.getVersionHistory(versionableNode);
|
||||
assertNotNull(versionHistory);
|
||||
assertEquals(1, versionHistory.getAllVersions().size());
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
}
|
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
* copy of the License at
|
||||
*
|
||||
* http://www.alfresco.org/legal/license.txt
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the
|
||||
* License.
|
||||
*/
|
||||
package org.alfresco.repo.version;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.repo.policy.ClassPolicy;
|
||||
import org.alfresco.repo.policy.PolicyScope;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.version.Version;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
|
||||
/**
|
||||
* Version service policy interfaces
|
||||
*
|
||||
* @author Roy Wetherall
|
||||
*/
|
||||
public interface VersionServicePolicies
|
||||
{
|
||||
/**
|
||||
* Before create version policy interface.
|
||||
*/
|
||||
public interface BeforeCreateVersionPolicy extends ClassPolicy
|
||||
{
|
||||
/**
|
||||
* Called before a new version is created for a version
|
||||
*
|
||||
* @param versionableNode reference to the node about to be versioned
|
||||
*/
|
||||
public void beforeCreateVersion(NodeRef versionableNode);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* On create version policy interface
|
||||
*/
|
||||
public interface OnCreateVersionPolicy extends ClassPolicy
|
||||
{
|
||||
public void onCreateVersion(
|
||||
QName classRef,
|
||||
NodeRef versionableNode,
|
||||
Map<String, Serializable> versionProperties,
|
||||
PolicyScope nodeDetails);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate version lable policy interface
|
||||
*/
|
||||
public interface CalculateVersionLabelPolicy extends ClassPolicy
|
||||
{
|
||||
public String calculateVersionLabel(
|
||||
QName classRef,
|
||||
Version preceedingVersion,
|
||||
int versionNumber,
|
||||
Map<String, Serializable>verisonProperties);
|
||||
}
|
||||
}
|
@@ -0,0 +1,112 @@
|
||||
<model name="test:versionstorebasetestmodel" xmlns="http://www.alfresco.org/model/dictionary/1.0">
|
||||
|
||||
<description>VersionStoreBaseTest model</description>
|
||||
<author>Alfresco</author>
|
||||
<published>2005-05-30</published>
|
||||
<version>1.0</version>
|
||||
|
||||
<imports>
|
||||
<import uri="http://www.alfresco.org/model/dictionary/1.0" prefix="d"/>
|
||||
<import uri="http://www.alfresco.org/model/content/1.0" prefix="cm"/>
|
||||
</imports>
|
||||
|
||||
<namespaces>
|
||||
<namespace uri="http://www.alfresco.org/test/versionstorebasetest/1.0" prefix="test"/>
|
||||
</namespaces>
|
||||
|
||||
<types>
|
||||
|
||||
<type name="test:testtype">
|
||||
<title>Test type</title>
|
||||
<description>The test type</description>
|
||||
<parent>cm:content</parent>
|
||||
|
||||
<properties>
|
||||
<property name="test:prop1">
|
||||
<type>d:text</type>
|
||||
<protected>false</protected>
|
||||
<default></default>
|
||||
</property>
|
||||
<property name="test:prop2">
|
||||
<type>d:text</type>
|
||||
<protected>false</protected>
|
||||
<default></default>
|
||||
</property>
|
||||
<property name="test:prop3">
|
||||
<type>d:text</type>
|
||||
<protected>false</protected>
|
||||
<default></default>
|
||||
</property>
|
||||
<property name="test:multiProp">
|
||||
<type>d:text</type>
|
||||
<multiple>true</multiple>
|
||||
</property>
|
||||
</properties>
|
||||
|
||||
<associations>
|
||||
<association name="test:assoc1">
|
||||
<source>
|
||||
<mandatory>false</mandatory>
|
||||
<many>false</many>
|
||||
</source>
|
||||
<target>
|
||||
<class>test:testtype</class>
|
||||
<mandatory>false</mandatory>
|
||||
<many>true</many>
|
||||
</target>
|
||||
</association>
|
||||
<child-association name="test:childassoc1">
|
||||
<source>
|
||||
<mandatory>false</mandatory>
|
||||
<many>true</many>
|
||||
</source>
|
||||
<target>
|
||||
<class>test:testtype</class>
|
||||
<mandatory>false</mandatory>
|
||||
<many>false</many>
|
||||
</target>
|
||||
<child-name>childassoc1</child-name>
|
||||
<duplicate>true</duplicate>
|
||||
</child-association>
|
||||
<child-association name="test:childassoc2">
|
||||
<source>
|
||||
<mandatory>false</mandatory>
|
||||
<many>true</many>
|
||||
</source>
|
||||
<target>
|
||||
<class>test:testtype</class>
|
||||
<mandatory>false</mandatory>
|
||||
<many>false</many>
|
||||
</target>
|
||||
<child-name>childassoc2</child-name>
|
||||
<duplicate>true</duplicate>
|
||||
</child-association>
|
||||
</associations>
|
||||
</type>
|
||||
|
||||
</types>
|
||||
|
||||
<aspects>
|
||||
<aspect name="test:testaspect">
|
||||
<title>Test Aspect</title>
|
||||
<description>The test aspect</description>
|
||||
<parent></parent>
|
||||
|
||||
<properties>
|
||||
|
||||
<property name="test:aspectprop1">
|
||||
<type>d:text</type>
|
||||
<protected>false</protected>
|
||||
<default></default>
|
||||
</property>
|
||||
<property name="test:aspectprop2">
|
||||
<type>d:text</type>
|
||||
<protected>false</protected>
|
||||
<default></default>
|
||||
</property>
|
||||
|
||||
</properties>
|
||||
</aspect>
|
||||
</aspects>
|
||||
|
||||
</model>
|
51
source/java/org/alfresco/repo/version/VersionTestSuite.java
Normal file
51
source/java/org/alfresco/repo/version/VersionTestSuite.java
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
* copy of the License at
|
||||
*
|
||||
* http://www.alfresco.org/legal/license.txt
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the
|
||||
* License.
|
||||
*/
|
||||
package org.alfresco.repo.version;
|
||||
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestSuite;
|
||||
|
||||
import org.alfresco.repo.version.common.VersionHistoryImplTest;
|
||||
import org.alfresco.repo.version.common.VersionImplTest;
|
||||
import org.alfresco.repo.version.common.counter.VersionCounterDaoServiceTest;
|
||||
import org.alfresco.repo.version.common.versionlabel.SerialVersionLabelPolicyTest;
|
||||
|
||||
/**
|
||||
* Version test suite
|
||||
*
|
||||
* @author Roy Wetherall
|
||||
*/
|
||||
public class VersionTestSuite extends TestSuite
|
||||
{
|
||||
/**
|
||||
* Creates the test suite
|
||||
*
|
||||
* @return the test suite
|
||||
*/
|
||||
public static Test suite()
|
||||
{
|
||||
TestSuite suite = new TestSuite();
|
||||
suite.addTestSuite(VersionImplTest.class);
|
||||
suite.addTestSuite(VersionHistoryImplTest.class);
|
||||
suite.addTestSuite(SerialVersionLabelPolicyTest.class);
|
||||
suite.addTestSuite(VersionCounterDaoServiceTest.class);
|
||||
suite.addTestSuite(VersionServiceImplTest.class);
|
||||
suite.addTestSuite(NodeServiceImplTest.class);
|
||||
suite.addTestSuite(ContentServiceImplTest.class);
|
||||
return suite;
|
||||
}
|
||||
}
|
272
source/java/org/alfresco/repo/version/VersionableAspect.java
Normal file
272
source/java/org/alfresco/repo/version/VersionableAspect.java
Normal file
@@ -0,0 +1,272 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
* copy of the License at
|
||||
*
|
||||
* http://www.alfresco.org/legal/license.txt
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the
|
||||
* License.
|
||||
*/
|
||||
package org.alfresco.repo.version;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.action.evaluator.HasVersionHistoryEvaluator;
|
||||
import org.alfresco.repo.action.executer.CreateVersionActionExecuter;
|
||||
import org.alfresco.repo.policy.Behaviour;
|
||||
import org.alfresco.repo.policy.BehaviourDefinition;
|
||||
import org.alfresco.repo.policy.JavaBehaviour;
|
||||
import org.alfresco.repo.policy.PolicyComponent;
|
||||
import org.alfresco.repo.policy.PolicyScope;
|
||||
import org.alfresco.repo.rule.RuntimeRuleService;
|
||||
import org.alfresco.service.cmr.action.Action;
|
||||
import org.alfresco.service.cmr.action.ActionCondition;
|
||||
import org.alfresco.service.cmr.action.ActionService;
|
||||
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.rule.Rule;
|
||||
import org.alfresco.service.cmr.rule.RuleService;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
|
||||
/**
|
||||
* Class containing behaviour for the versionable aspect
|
||||
*
|
||||
* @author Roy Wetherall
|
||||
*/
|
||||
public class VersionableAspect
|
||||
{
|
||||
/**
|
||||
* The policy component
|
||||
*/
|
||||
private PolicyComponent policyComponent;
|
||||
|
||||
/**
|
||||
* The node service
|
||||
*/
|
||||
private NodeService nodeService;
|
||||
|
||||
/**
|
||||
* The rule service
|
||||
*/
|
||||
private RuleService ruleService;
|
||||
|
||||
/**
|
||||
* The action service
|
||||
*/
|
||||
private ActionService actionService;
|
||||
|
||||
/**
|
||||
* The rule used to create versions
|
||||
*/
|
||||
private Rule rule;
|
||||
|
||||
/**
|
||||
* Auto version behaviour
|
||||
*/
|
||||
private Behaviour autoVersionBehaviour;
|
||||
|
||||
/**
|
||||
* Set the policy component
|
||||
*
|
||||
* @param policyComponent the policy component
|
||||
*/
|
||||
public void setPolicyComponent(PolicyComponent policyComponent)
|
||||
{
|
||||
this.policyComponent = policyComponent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the rule service
|
||||
*
|
||||
* @param ruleService the rule service
|
||||
*/
|
||||
public void setRuleService(RuleService ruleService)
|
||||
{
|
||||
this.ruleService = ruleService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the action service
|
||||
*
|
||||
* @param actionService the action service
|
||||
*/
|
||||
public void setActionService(ActionService actionService)
|
||||
{
|
||||
this.actionService = actionService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the node service
|
||||
*
|
||||
* @param nodeService the node service
|
||||
*/
|
||||
public void setNodeService(NodeService nodeService)
|
||||
{
|
||||
this.nodeService = nodeService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise the versionable aspect policies
|
||||
*/
|
||||
public void init()
|
||||
{
|
||||
this.policyComponent.bindClassBehaviour(
|
||||
QName.createQName(NamespaceService.ALFRESCO_URI, "onAddAspect"),
|
||||
ContentModel.ASPECT_VERSIONABLE,
|
||||
new JavaBehaviour(this, "onAddAspect"));
|
||||
autoVersionBehaviour = new JavaBehaviour(this, "onContentUpdate");
|
||||
this.policyComponent.bindClassBehaviour(
|
||||
QName.createQName(NamespaceService.ALFRESCO_URI, "onContentUpdate"),
|
||||
ContentModel.ASPECT_VERSIONABLE,
|
||||
autoVersionBehaviour);
|
||||
|
||||
// Register the copy behaviour
|
||||
this.policyComponent.bindClassBehaviour(
|
||||
QName.createQName(NamespaceService.ALFRESCO_URI, "onCopyNode"),
|
||||
ContentModel.ASPECT_VERSIONABLE,
|
||||
new JavaBehaviour(this, "onCopy"));
|
||||
|
||||
// Register the onCreateVersion behavior for the version aspect
|
||||
//this.policyComponent.bindClassBehaviour(
|
||||
// QName.createQName(NamespaceService.ALFRESCO_URI, "onCreateVersion"),
|
||||
// ContentModel.ASPECT_VERSIONABLE,
|
||||
// new JavaBehaviour(this, "onCreateVersion"));
|
||||
}
|
||||
|
||||
/**
|
||||
* OnCopy behaviour implementation for the version aspect.
|
||||
* <p>
|
||||
* Ensures that the propety values of the version aspect are not copied onto
|
||||
* the destination node.
|
||||
*
|
||||
* @see org.alfresco.repo.copy.CopyServicePolicies.OnCopyNodePolicy#onCopyNode(QName, NodeRef, StoreRef, boolean, PolicyScope)
|
||||
*/
|
||||
public void onCopy(
|
||||
QName sourceClassRef,
|
||||
NodeRef sourceNodeRef,
|
||||
StoreRef destinationStoreRef,
|
||||
boolean copyToNewNode,
|
||||
PolicyScope copyDetails)
|
||||
{
|
||||
// Add the version aspect, but do not copy the version label
|
||||
copyDetails.addAspect(ContentModel.ASPECT_VERSIONABLE);
|
||||
copyDetails.addProperty(
|
||||
ContentModel.ASPECT_VERSIONABLE,
|
||||
ContentModel.PROP_AUTO_VERSION,
|
||||
this.nodeService.getProperty(sourceNodeRef, ContentModel.PROP_AUTO_VERSION));
|
||||
}
|
||||
|
||||
/**
|
||||
* OnCreateVersion behaviour for the version aspect
|
||||
* <p>
|
||||
* Ensures that the version aspect and it proerties are 'frozen' as part of
|
||||
* the versioned state.
|
||||
*
|
||||
* @param classRef the class reference
|
||||
* @param versionableNode the versionable node reference
|
||||
* @param versionProperties the version properties
|
||||
* @param nodeDetails the details of the node to be versioned
|
||||
*/
|
||||
public void onCreateVersion(
|
||||
QName classRef,
|
||||
NodeRef versionableNode,
|
||||
Map<String, Serializable> versionProperties,
|
||||
PolicyScope nodeDetails)
|
||||
{
|
||||
// Do nothing since we do not what to freeze any of the version
|
||||
// properties
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* On add aspect policy behaviour
|
||||
*
|
||||
* @param nodeRef
|
||||
* @param aspectTypeQName
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public void onAddAspect(NodeRef nodeRef, QName aspectTypeQName)
|
||||
{
|
||||
if (aspectTypeQName.equals(ContentModel.ASPECT_VERSIONABLE) == true)
|
||||
{
|
||||
// Queue create version action
|
||||
queueCreateVersionAction(nodeRef);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* On content update policy bahaviour
|
||||
*
|
||||
* @param nodeRef the node reference
|
||||
*/
|
||||
public void onContentUpdate(NodeRef nodeRef)
|
||||
{
|
||||
if (this.nodeService.hasAspect(nodeRef, ContentModel.ASPECT_VERSIONABLE) == true)
|
||||
{
|
||||
// Determine whether the node is auto versionable or not
|
||||
boolean autoVersion = false;
|
||||
Boolean value = (Boolean)this.nodeService.getProperty(nodeRef, ContentModel.PROP_AUTO_VERSION);
|
||||
if (value != null)
|
||||
{
|
||||
// If the value is not null then
|
||||
autoVersion = value.booleanValue();
|
||||
}
|
||||
// else this means that the default value has not been set and the versionable aspect was applied pre-1.1
|
||||
|
||||
if (autoVersion == true)
|
||||
{
|
||||
// Queue create version action
|
||||
queueCreateVersionAction(nodeRef);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable the auto version behaviour
|
||||
*
|
||||
*/
|
||||
public void enableAutoVersion()
|
||||
{
|
||||
this.autoVersionBehaviour.enable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable the auto version behaviour
|
||||
*
|
||||
*/
|
||||
public void disableAutoVersion()
|
||||
{
|
||||
this.autoVersionBehaviour.disable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Queue create version action
|
||||
*
|
||||
* @param nodeRef the node reference
|
||||
*/
|
||||
private void queueCreateVersionAction(NodeRef nodeRef)
|
||||
{
|
||||
if (this.rule == null)
|
||||
{
|
||||
this.rule = this.ruleService.createRule("inbound");
|
||||
Action action = this.actionService.createAction(CreateVersionActionExecuter.NAME);
|
||||
ActionCondition condition = this.actionService.createActionCondition(HasVersionHistoryEvaluator.NAME);
|
||||
condition.setInvertCondition(true);
|
||||
action.addActionCondition(condition);
|
||||
this.rule.addAction(action);
|
||||
}
|
||||
|
||||
((RuntimeRuleService)this.ruleService).addRulePendingExecution(nodeRef, nodeRef, this.rule, true);
|
||||
}
|
||||
}
|
@@ -0,0 +1,281 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
* copy of the License at
|
||||
*
|
||||
* http://www.alfresco.org/legal/license.txt
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the
|
||||
* License.
|
||||
*/
|
||||
package org.alfresco.repo.version.common;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.repo.policy.ClassPolicyDelegate;
|
||||
import org.alfresco.repo.policy.PolicyComponent;
|
||||
import org.alfresco.repo.policy.PolicyScope;
|
||||
import org.alfresco.repo.version.VersionServicePolicies;
|
||||
import org.alfresco.repo.version.VersionServicePolicies.BeforeCreateVersionPolicy;
|
||||
import org.alfresco.repo.version.VersionServicePolicies.CalculateVersionLabelPolicy;
|
||||
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.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.NodeService;
|
||||
import org.alfresco.service.cmr.version.Version;
|
||||
import org.alfresco.service.cmr.version.VersionServiceException;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.service.namespace.RegexQNamePattern;
|
||||
|
||||
/**
|
||||
* Abstract version service implementation.
|
||||
*
|
||||
* @author Roy Wetherall
|
||||
*/
|
||||
public abstract class AbstractVersionServiceImpl
|
||||
{
|
||||
/**
|
||||
* The common node service
|
||||
*/
|
||||
protected NodeService nodeService ;
|
||||
|
||||
/**
|
||||
* Policy component
|
||||
*/
|
||||
protected PolicyComponent policyComponent;
|
||||
|
||||
/**
|
||||
* The dictionary service
|
||||
*/
|
||||
protected DictionaryService dictionaryService;
|
||||
|
||||
/**
|
||||
* Policy delegates
|
||||
*/
|
||||
private ClassPolicyDelegate<BeforeCreateVersionPolicy> beforeCreateVersionDelegate;
|
||||
private ClassPolicyDelegate<OnCreateVersionPolicy> onCreateVersionDelegate;
|
||||
private ClassPolicyDelegate<CalculateVersionLabelPolicy> calculateVersionLabelDelegate;
|
||||
|
||||
/**
|
||||
* Sets the general node service
|
||||
*
|
||||
* @param nodeService the node service
|
||||
*/
|
||||
public void setNodeService(NodeService nodeService)
|
||||
{
|
||||
this.nodeService = nodeService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the policy component
|
||||
*
|
||||
* @param policyComponent the policy component
|
||||
*/
|
||||
public void setPolicyComponent(PolicyComponent policyComponent)
|
||||
{
|
||||
this.policyComponent = policyComponent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the dictionary service
|
||||
*
|
||||
* @param dictionaryService the dictionary service
|
||||
*/
|
||||
public void setDictionaryService(DictionaryService dictionaryService)
|
||||
{
|
||||
this.dictionaryService = dictionaryService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise method
|
||||
*/
|
||||
public void initialise()
|
||||
{
|
||||
// Register the policies
|
||||
this.beforeCreateVersionDelegate = this.policyComponent.registerClassPolicy(VersionServicePolicies.BeforeCreateVersionPolicy.class);
|
||||
this.onCreateVersionDelegate = this.policyComponent.registerClassPolicy(VersionServicePolicies.OnCreateVersionPolicy.class);
|
||||
this.calculateVersionLabelDelegate = this.policyComponent.registerClassPolicy(VersionServicePolicies.CalculateVersionLabelPolicy.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes the before create version policy behaviour
|
||||
*
|
||||
* @param nodeRef the node being versioned
|
||||
*/
|
||||
protected void invokeBeforeCreateVersion(NodeRef nodeRef)
|
||||
{
|
||||
// invoke for node type
|
||||
QName nodeTypeQName = nodeService.getType(nodeRef);
|
||||
this.beforeCreateVersionDelegate.get(nodeTypeQName).beforeCreateVersion(nodeRef);
|
||||
// invoke for node aspects
|
||||
Set<QName> nodeAspectQNames = nodeService.getAspects(nodeRef);
|
||||
this.beforeCreateVersionDelegate.get(nodeAspectQNames).beforeCreateVersion(nodeRef);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke the on create version policy behaviour
|
||||
*
|
||||
*/
|
||||
protected void invokeOnCreateVersion(
|
||||
NodeRef nodeRef,
|
||||
Map<String, Serializable> versionProperties,
|
||||
PolicyScope nodeDetails)
|
||||
{
|
||||
// Sort out the policies for the node type
|
||||
QName classRef = this.nodeService.getType(nodeRef);
|
||||
invokeOnCreateVersion(classRef, nodeRef, versionProperties, nodeDetails);
|
||||
|
||||
// Sort out the policies for the aspects
|
||||
Collection<QName> aspects = this.nodeService.getAspects(nodeRef);
|
||||
for (QName aspect : aspects)
|
||||
{
|
||||
invokeOnCreateVersion(aspect, nodeRef, versionProperties, nodeDetails);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes the on create version policy behaviour for a given type
|
||||
*
|
||||
* @param classRef
|
||||
* @param nodeDetails
|
||||
* @param nodeRef
|
||||
* @param versionProperties
|
||||
*/
|
||||
private void invokeOnCreateVersion(
|
||||
QName classRef,
|
||||
NodeRef nodeRef,
|
||||
Map<String, Serializable> versionProperties,
|
||||
PolicyScope nodeDetails)
|
||||
{
|
||||
Collection<OnCreateVersionPolicy> policies = this.onCreateVersionDelegate.getList(classRef);
|
||||
if (policies.size() == 0)
|
||||
{
|
||||
// Call the default implementation
|
||||
defaultOnCreateVersion(
|
||||
classRef,
|
||||
nodeRef,
|
||||
versionProperties,
|
||||
nodeDetails);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Call the policy definitions
|
||||
for (VersionServicePolicies.OnCreateVersionPolicy policy : policies)
|
||||
{
|
||||
policy.onCreateVersion(
|
||||
classRef,
|
||||
nodeRef,
|
||||
versionProperties,
|
||||
nodeDetails);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Default implementation of the on create version policy. Called if no behaviour is registered for the
|
||||
* policy for the specified type.
|
||||
*
|
||||
* @param nodeRef
|
||||
* @param versionProperties
|
||||
* @param nodeDetails
|
||||
*/
|
||||
protected void defaultOnCreateVersion(
|
||||
QName classRef,
|
||||
NodeRef nodeRef,
|
||||
Map<String, Serializable> versionProperties,
|
||||
PolicyScope nodeDetails)
|
||||
{
|
||||
ClassDefinition classDefinition = this.dictionaryService.getClass(classRef);
|
||||
if (classDefinition != null)
|
||||
{
|
||||
// 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);
|
||||
}
|
||||
|
||||
// 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
|
||||
*
|
||||
* @param classRef
|
||||
* @param preceedingVersion
|
||||
* @param versionNumber
|
||||
* @param versionProperties
|
||||
* @return
|
||||
*/
|
||||
protected String invokeCalculateVersionLabel(
|
||||
QName classRef,
|
||||
Version preceedingVersion,
|
||||
int versionNumber,
|
||||
Map<String, Serializable>versionProperties)
|
||||
{
|
||||
String versionLabel = null;
|
||||
|
||||
Collection<CalculateVersionLabelPolicy> behaviours = this.calculateVersionLabelDelegate.getList(classRef);
|
||||
if (behaviours.size() == 0)
|
||||
{
|
||||
// Default the version label to the version numbder
|
||||
versionLabel = Integer.toString(versionNumber);
|
||||
}
|
||||
else if (behaviours.size() == 1)
|
||||
{
|
||||
// Call the policy behaviour
|
||||
CalculateVersionLabelPolicy[] arr = behaviours.toArray(new CalculateVersionLabelPolicy[]{});
|
||||
versionLabel = arr[0].calculateVersionLabel(classRef, preceedingVersion, versionNumber, versionProperties);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Error since we can only deal with a single caculate version label policy
|
||||
throw new VersionServiceException("More than one CalculateVersionLabelPolicy behaviour has been registered for the type " + classRef.toString());
|
||||
}
|
||||
|
||||
return versionLabel;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
* copy of the License at
|
||||
*
|
||||
* http://www.alfresco.org/legal/license.txt
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the
|
||||
* License.
|
||||
*/
|
||||
package org.alfresco.repo.version.common;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
|
||||
import org.alfresco.service.cmr.version.Version;
|
||||
import org.alfresco.service.cmr.version.VersionDoesNotExistException;
|
||||
import org.alfresco.service.cmr.version.VersionHistory;
|
||||
import org.alfresco.service.cmr.version.VersionServiceException;
|
||||
|
||||
/**
|
||||
* Version History implementation.
|
||||
*
|
||||
* @author Roy Wetherall
|
||||
*/
|
||||
public class VersionHistoryImpl implements VersionHistory
|
||||
{
|
||||
/*
|
||||
* Serial version UID
|
||||
*/
|
||||
private static final long serialVersionUID = 3257001051558326840L;
|
||||
|
||||
/*
|
||||
* Error message(s)
|
||||
*/
|
||||
private static final String ERR_MSG = "The root version must be specified when creating a version history object.";
|
||||
|
||||
/*
|
||||
* The root version label
|
||||
*/
|
||||
private String rootVersionLabel = null;
|
||||
|
||||
/*
|
||||
* Version history tree structure map
|
||||
*/
|
||||
private HashMap<String, String> versionHistory = null;
|
||||
|
||||
/*
|
||||
* Label to version object map
|
||||
*/
|
||||
private HashMap<String, Version> versions = null;
|
||||
|
||||
private Version rootVersion;
|
||||
|
||||
/**
|
||||
* Constructor, ensures the root version is set.
|
||||
*
|
||||
* @param rootVersion the root version, can not be null.
|
||||
*/
|
||||
public VersionHistoryImpl(Version rootVersion)
|
||||
{
|
||||
if (rootVersion == null)
|
||||
{
|
||||
// Exception - a version history can not be created unless
|
||||
// a root version is specified
|
||||
throw new VersionServiceException(VersionHistoryImpl.ERR_MSG);
|
||||
}
|
||||
|
||||
this.versionHistory = new HashMap<String, String>();
|
||||
this.versions = new HashMap<String, Version>();
|
||||
|
||||
this.rootVersion = rootVersion;
|
||||
this.rootVersionLabel = rootVersion.getVersionLabel();
|
||||
addVersion(rootVersion, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the root (or initial) version of the version history.
|
||||
*
|
||||
* @return the root version
|
||||
*/
|
||||
public Version getRootVersion()
|
||||
{
|
||||
return this.rootVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a collection containing all the versions within the
|
||||
* version history.
|
||||
* <p>
|
||||
* The order of the versions is not guarenteed.
|
||||
*
|
||||
* @return collection containing all the versions
|
||||
*/
|
||||
public Collection<Version> getAllVersions()
|
||||
{
|
||||
return this.versions.values();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the predecessor of a specified version
|
||||
*
|
||||
* @param version the version object
|
||||
* @return the predeceeding version, null if root version
|
||||
*/
|
||||
public Version getPredecessor(Version version)
|
||||
{
|
||||
Version result = null;
|
||||
if (version != null)
|
||||
{
|
||||
result = getVersion(this.versionHistory.get(version.getVersionLabel()));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the succeeding versions of a specified version.
|
||||
*
|
||||
* @param version the version object
|
||||
* @return a collection containing the succeeding version, empty is none
|
||||
*/
|
||||
public Collection<Version> getSuccessors(Version version)
|
||||
{
|
||||
ArrayList<Version> result = new ArrayList<Version>();
|
||||
|
||||
if (version != null)
|
||||
{
|
||||
String versionLabel = version.getVersionLabel();
|
||||
|
||||
if (this.versionHistory.containsValue(versionLabel) == true)
|
||||
{
|
||||
for (String key : this.versionHistory.keySet())
|
||||
{
|
||||
if (this.versionHistory.get(key) == versionLabel)
|
||||
{
|
||||
result.add(getVersion(key));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a version with a specified version label. The version label is guarenteed
|
||||
* unique within the version history.
|
||||
*
|
||||
* @param versionLabel the version label
|
||||
* @return the version object
|
||||
* @throws VersionDoesNotExistException indicates requested version does not exisit
|
||||
*/
|
||||
public Version getVersion(String versionLabel)
|
||||
{
|
||||
Version result = null;
|
||||
if (versionLabel != null)
|
||||
{
|
||||
result = this.versions.get(versionLabel);
|
||||
|
||||
if (result == null)
|
||||
{
|
||||
// Throw exception indicating that the version does not exit
|
||||
throw new VersionDoesNotExistException(versionLabel);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a version to the version history.
|
||||
* <p>
|
||||
* Used internally to build the version history tree.
|
||||
*
|
||||
* @param version the version object
|
||||
* @param predecessor the preceeding version
|
||||
*/
|
||||
public void addVersion(Version version, Version predecessor)
|
||||
{
|
||||
// TODO cope with exception case where duplicate version labels have been specified
|
||||
|
||||
this.versions.put(version.getVersionLabel(), version);
|
||||
|
||||
if (predecessor != null)
|
||||
{
|
||||
this.versionHistory.put(version.getVersionLabel(), predecessor.getVersionLabel());
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,255 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
* copy of the License at
|
||||
*
|
||||
* http://www.alfresco.org/legal/license.txt
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the
|
||||
* License.
|
||||
*/
|
||||
package org.alfresco.repo.version.common;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.alfresco.repo.version.VersionModel;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.StoreRef;
|
||||
import org.alfresco.service.cmr.version.Version;
|
||||
import org.alfresco.service.cmr.version.VersionDoesNotExistException;
|
||||
import org.alfresco.service.cmr.version.VersionServiceException;
|
||||
|
||||
/**
|
||||
* VersionHistoryImpl Unit Test Class
|
||||
*
|
||||
* @author Roy Wetherall
|
||||
*/
|
||||
public class VersionHistoryImplTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* Data used in the tests
|
||||
*/
|
||||
private Version rootVersion = null;
|
||||
private Version childVersion1 = null;
|
||||
private Version childVersion2 = null;
|
||||
|
||||
/**
|
||||
* Set up
|
||||
*/
|
||||
protected void setUp() throws Exception
|
||||
{
|
||||
super.setUp();
|
||||
|
||||
// Create dummy node ref
|
||||
NodeRef nodeRef = new NodeRef(new StoreRef(StoreRef.PROTOCOL_WORKSPACE, "test"), "test");
|
||||
|
||||
HashMap<String, Serializable> versionProperties1 = new HashMap<String, Serializable>();
|
||||
versionProperties1.put(VersionModel.PROP_VERSION_LABEL, "1");
|
||||
versionProperties1.put(VersionModel.PROP_CREATED_DATE, new Date());
|
||||
versionProperties1.put("testProperty", "testValue");
|
||||
this.rootVersion = new VersionImpl(versionProperties1, nodeRef);
|
||||
|
||||
HashMap<String, Serializable> versionProperties2 = new HashMap<String, Serializable>();
|
||||
versionProperties2.put(VersionModel.PROP_VERSION_LABEL, "2");
|
||||
versionProperties2.put(VersionModel.PROP_CREATED_DATE, new Date());
|
||||
versionProperties2.put("testProperty", "testValue");
|
||||
this.childVersion1 = new VersionImpl(versionProperties2, nodeRef);
|
||||
|
||||
HashMap<String, Serializable> versionProperties3 = new HashMap<String, Serializable>();
|
||||
versionProperties3.put(VersionModel.PROP_VERSION_LABEL, "3");
|
||||
versionProperties3.put(VersionModel.PROP_CREATED_DATE, new Date());
|
||||
versionProperties3.put("testProperty", "testValue");
|
||||
this.childVersion2 = new VersionImpl(versionProperties3, nodeRef);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test constructor
|
||||
*/
|
||||
public void testConstructor()
|
||||
{
|
||||
testContructorImpl();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test construtor helper
|
||||
*
|
||||
* @return new version history
|
||||
*/
|
||||
private VersionHistoryImpl testContructorImpl()
|
||||
{
|
||||
VersionHistoryImpl vh = new VersionHistoryImpl(this.rootVersion);
|
||||
assertNotNull(vh);
|
||||
|
||||
return vh;
|
||||
}
|
||||
|
||||
/**
|
||||
* Exception case - a root version must be specified when creating a
|
||||
* version history object
|
||||
*/
|
||||
public void testRootVersionSpecified()
|
||||
{
|
||||
try
|
||||
{
|
||||
new VersionHistoryImpl(null);
|
||||
fail();
|
||||
}
|
||||
catch(VersionServiceException exception)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getRootVersion
|
||||
*
|
||||
*@return root version
|
||||
*/
|
||||
public void testGetRootVersion()
|
||||
{
|
||||
VersionHistoryImpl vh = testContructorImpl();
|
||||
|
||||
Version rootVersion = vh.getRootVersion();
|
||||
assertNotNull(rootVersion);
|
||||
assertEquals(rootVersion, this.rootVersion);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getAllVersions
|
||||
*/
|
||||
public void testGetAllVersions()
|
||||
{
|
||||
VersionHistoryImpl vh = testAddVersionImpl();
|
||||
|
||||
Collection<Version> allVersions = vh.getAllVersions();
|
||||
assertNotNull(allVersions);
|
||||
assertEquals(3, allVersions.size());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test addVersion
|
||||
*
|
||||
* @return version history
|
||||
*/
|
||||
public void testAddVersion()
|
||||
{
|
||||
testAddVersionImpl();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test addVersion helper
|
||||
*
|
||||
* @return version history with version tree built
|
||||
*/
|
||||
private VersionHistoryImpl testAddVersionImpl()
|
||||
{
|
||||
VersionHistoryImpl vh = testContructorImpl();
|
||||
Version rootVersion = vh.getRootVersion();
|
||||
|
||||
vh.addVersion(this.childVersion1, rootVersion);
|
||||
vh.addVersion(this.childVersion2, rootVersion);
|
||||
|
||||
return vh;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO Exception case - add version that has already been added
|
||||
*/
|
||||
|
||||
/**
|
||||
* TODO Exception case - add a version with a duplicate version label
|
||||
*/
|
||||
|
||||
/**
|
||||
* Test getPredecessor
|
||||
*/
|
||||
public void testGetPredecessor()
|
||||
{
|
||||
VersionHistoryImpl vh = testAddVersionImpl();
|
||||
|
||||
Version version1 = vh.getPredecessor(this.childVersion1);
|
||||
assertEquals(version1.getVersionLabel(), this.rootVersion.getVersionLabel());
|
||||
|
||||
Version version2 = vh.getPredecessor(this.childVersion2);
|
||||
assertEquals(version2.getVersionLabel(), this.rootVersion.getVersionLabel());
|
||||
|
||||
Version version3 = vh.getPredecessor(this.rootVersion);
|
||||
assertNull(version3);
|
||||
|
||||
try
|
||||
{
|
||||
Version version4 = vh.getPredecessor(null);
|
||||
assertNull(version4);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
fail("Should continue by returning null.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getSuccessors
|
||||
*/
|
||||
public void testGetSuccessors()
|
||||
{
|
||||
VersionHistoryImpl vh = testAddVersionImpl();
|
||||
|
||||
Collection<Version> versions1 = vh.getSuccessors(this.rootVersion);
|
||||
assertNotNull(versions1);
|
||||
assertEquals(versions1.size(), 2);
|
||||
|
||||
for (Version version : versions1)
|
||||
{
|
||||
String versionLabel = version.getVersionLabel();
|
||||
if (!(versionLabel == "2" || versionLabel == "3"))
|
||||
{
|
||||
fail("There is a version in this collection that should not be here.");
|
||||
}
|
||||
}
|
||||
|
||||
Collection versions2 = vh.getSuccessors(this.childVersion1);
|
||||
assertNotNull(versions2);
|
||||
assertTrue(versions2.isEmpty());
|
||||
|
||||
Collection versions3 = vh.getSuccessors(this.childVersion2);
|
||||
assertNotNull(versions3);
|
||||
assertTrue(versions3.isEmpty());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getVersion
|
||||
*/
|
||||
public void testGetVersion()
|
||||
{
|
||||
VersionHistoryImpl vh = testAddVersionImpl();
|
||||
|
||||
Version version1 = vh.getVersion("1");
|
||||
assertEquals(version1.getVersionLabel(), this.rootVersion.getVersionLabel());
|
||||
|
||||
Version version2 = vh.getVersion("2");
|
||||
assertEquals(version2.getVersionLabel(), this.childVersion1.getVersionLabel());
|
||||
|
||||
Version version3 = vh.getVersion("3");
|
||||
assertEquals(version3.getVersionLabel(), this.childVersion2.getVersionLabel());
|
||||
|
||||
try
|
||||
{
|
||||
vh.getVersion("invalidLabel");
|
||||
fail("An exception should have been thrown if the version can not be retrieved.");
|
||||
}
|
||||
catch (VersionDoesNotExistException exception)
|
||||
{
|
||||
System.out.println("Error message: " + exception.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
197
source/java/org/alfresco/repo/version/common/VersionImpl.java
Normal file
197
source/java/org/alfresco/repo/version/common/VersionImpl.java
Normal file
@@ -0,0 +1,197 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
* copy of the License at
|
||||
*
|
||||
* http://www.alfresco.org/legal/license.txt
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the
|
||||
* License.
|
||||
*/
|
||||
package org.alfresco.repo.version.common;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.repo.version.VersionModel;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.StoreRef;
|
||||
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
|
||||
import org.alfresco.service.cmr.repository.datatype.TypeConverter;
|
||||
import org.alfresco.service.cmr.version.Version;
|
||||
import org.alfresco.service.cmr.version.VersionServiceException;
|
||||
import org.alfresco.service.cmr.version.VersionType;
|
||||
|
||||
|
||||
/**
|
||||
* Version class implementation.
|
||||
*
|
||||
* Used to represent the data about a version stored in a version store.
|
||||
*
|
||||
* @author Roy Wetherall
|
||||
*/
|
||||
public class VersionImpl implements Version
|
||||
{
|
||||
/**
|
||||
* Serial version UID
|
||||
*/
|
||||
private static final long serialVersionUID = 3257567304324888881L;
|
||||
|
||||
/**
|
||||
* Error message(s)
|
||||
*/
|
||||
private static final String ERR_NO_NODE_REF = "A valid node reference must be supplied when creating a verison.";
|
||||
|
||||
/**
|
||||
* The properties of the version
|
||||
*/
|
||||
private Map<String, Serializable> versionProperties = null;
|
||||
|
||||
/**
|
||||
* The node reference that represents the frozen state of the versioned object
|
||||
*/
|
||||
private NodeRef nodeRef = null;
|
||||
|
||||
/**
|
||||
* Constructor that initialises the state of the version object.
|
||||
*
|
||||
* @param versionProperties the version properties
|
||||
* @param nodeRef the forzen state node reference
|
||||
*/
|
||||
public VersionImpl(
|
||||
Map<String, Serializable> versionProperties,
|
||||
NodeRef nodeRef)
|
||||
{
|
||||
if (nodeRef == null)
|
||||
{
|
||||
// Exception - a node ref must be specified
|
||||
throw new VersionServiceException(VersionImpl.ERR_NO_NODE_REF);
|
||||
}
|
||||
|
||||
this.versionProperties = versionProperties;
|
||||
this.nodeRef = nodeRef;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Helper method to get the created date from the version property data.
|
||||
*
|
||||
* @return the date the version was created
|
||||
*/
|
||||
public Date getCreatedDate()
|
||||
{
|
||||
return (Date)this.versionProperties.get(VersionModel.PROP_CREATED_DATE);
|
||||
}
|
||||
|
||||
public String getCreator()
|
||||
{
|
||||
return (String)this.versionProperties.get(VersionModel.PROP_CREATOR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to get the version label from the version property data.
|
||||
*
|
||||
* @return the version label
|
||||
*/
|
||||
public String getVersionLabel()
|
||||
{
|
||||
return (String)this.versionProperties.get(VersionModel.PROP_VERSION_LABEL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to get the version type.
|
||||
*
|
||||
* @return the value of the version type as an enum value
|
||||
*/
|
||||
public VersionType getVersionType()
|
||||
{
|
||||
return (VersionType)this.versionProperties.get(VersionModel.PROP_VERSION_TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to get the version description.
|
||||
*
|
||||
* @return the version description
|
||||
*/
|
||||
public String getDescription()
|
||||
{
|
||||
return (String)this.versionProperties.get(PROP_DESCRIPTION);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.service.cmr.version.Version#getVersionProperties()
|
||||
*/
|
||||
public Map<String, Serializable> getVersionProperties()
|
||||
{
|
||||
return this.versionProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.service.cmr.version.Version#getVersionProperty(java.lang.String)
|
||||
*/
|
||||
public Serializable getVersionProperty(String name)
|
||||
{
|
||||
Serializable result = null;
|
||||
if (this.versionProperties != null)
|
||||
{
|
||||
result = this.versionProperties.get(name);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.service.cmr.version.Version#getVersionedNodeRef()
|
||||
*/
|
||||
public NodeRef getVersionedNodeRef()
|
||||
{
|
||||
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 nodeId = (String)this.versionProperties.get(VersionModel.PROP_FROZEN_NODE_ID);
|
||||
return new NodeRef(new StoreRef(storeProtocol, storeId), nodeId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.service.cmr.version.Version#getFrozenStateNodeRef()
|
||||
*/
|
||||
public NodeRef getFrozenStateNodeRef()
|
||||
{
|
||||
return this.nodeRef;
|
||||
}
|
||||
|
||||
/**
|
||||
* Static block to register the version type converters
|
||||
*/
|
||||
static
|
||||
{
|
||||
DefaultTypeConverter.INSTANCE.addConverter(
|
||||
String.class,
|
||||
VersionType.class,
|
||||
new TypeConverter.Converter<String, VersionType>()
|
||||
{
|
||||
public VersionType convert(String source)
|
||||
{
|
||||
return VersionType.valueOf(source);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
DefaultTypeConverter.INSTANCE.addConverter(
|
||||
VersionType.class,
|
||||
String.class,
|
||||
new TypeConverter.Converter<VersionType, String>()
|
||||
{
|
||||
public String convert(VersionType source)
|
||||
{
|
||||
return source.toString();
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
}
|
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
* copy of the License at
|
||||
*
|
||||
* http://www.alfresco.org/legal/license.txt
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the
|
||||
* License.
|
||||
*/
|
||||
package org.alfresco.repo.version.common;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.repo.version.VersionModel;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.StoreRef;
|
||||
import org.alfresco.service.cmr.version.Version;
|
||||
import org.alfresco.service.cmr.version.VersionServiceException;
|
||||
import org.alfresco.service.cmr.version.VersionType;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
/**
|
||||
* VersionImpl Unit Test
|
||||
*
|
||||
* @author Roy Wetherall
|
||||
*/
|
||||
public class VersionImplTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* Property names and values
|
||||
*/
|
||||
private final static String PROP_1 = "prop1";
|
||||
private final static String PROP_2 = "prop2";
|
||||
private final static String PROP_3 = "prop3";
|
||||
private final static String VALUE_1 = "value1";
|
||||
private final static String VALUE_2 = "value2";
|
||||
private final static String VALUE_3 = "value3";
|
||||
private final static String VALUE_DESCRIPTION = "This string describes the version details.";
|
||||
private final static VersionType VERSION_TYPE = VersionType.MINOR;
|
||||
private final static String USER_NAME = "userName";
|
||||
|
||||
/**
|
||||
* Version labels
|
||||
*/
|
||||
private final static String VERSION_1 = "1";
|
||||
|
||||
/**
|
||||
* Data used during tests
|
||||
*/
|
||||
private VersionImpl version = null;
|
||||
private NodeRef nodeRef = null;
|
||||
private Map<String, Serializable> versionProperties = null;
|
||||
private Date createdDate = new Date();
|
||||
|
||||
/**
|
||||
* Test case set up
|
||||
*/
|
||||
protected void setUp() throws Exception
|
||||
{
|
||||
super.setUp();
|
||||
|
||||
// Create the node reference
|
||||
this.nodeRef = new NodeRef(new StoreRef(StoreRef.PROTOCOL_WORKSPACE, "testWS"), "testID");
|
||||
assertNotNull(this.nodeRef);
|
||||
|
||||
// Create the version property map
|
||||
this.versionProperties = new HashMap<String, Serializable>();
|
||||
this.versionProperties.put(VersionModel.PROP_VERSION_LABEL, VERSION_1);
|
||||
this.versionProperties.put(VersionModel.PROP_CREATED_DATE, this.createdDate);
|
||||
this.versionProperties.put(VersionModel.PROP_CREATOR, USER_NAME);
|
||||
this.versionProperties.put(Version.PROP_DESCRIPTION, VALUE_DESCRIPTION);
|
||||
this.versionProperties.put(VersionModel.PROP_VERSION_TYPE, VERSION_TYPE);
|
||||
this.versionProperties.put(PROP_1, VALUE_1);
|
||||
this.versionProperties.put(PROP_2, VALUE_2);
|
||||
this.versionProperties.put(PROP_3, VALUE_3);
|
||||
|
||||
// Create the root version
|
||||
this.version = new VersionImpl(this.versionProperties, this.nodeRef);
|
||||
assertNotNull(this.version);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test getCreatedDate()
|
||||
*/
|
||||
public void testGetCreatedDate()
|
||||
{
|
||||
Date createdDate1 = this.version.getCreatedDate();
|
||||
assertEquals(this.createdDate, createdDate1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getCreator
|
||||
*/
|
||||
public void testGetCreator()
|
||||
{
|
||||
assertEquals(USER_NAME, this.version.getCreator());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getVersionLabel()
|
||||
*/
|
||||
public void testGetVersionLabel()
|
||||
{
|
||||
String versionLabel1 = this.version.getVersionLabel();
|
||||
assertEquals(VersionImplTest.VERSION_1, versionLabel1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getDescription
|
||||
*/
|
||||
public void testGetDescription()
|
||||
{
|
||||
String description = this.version.getDescription();
|
||||
assertEquals(VALUE_DESCRIPTION, description);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getVersionType
|
||||
*/
|
||||
public void testGetVersionType()
|
||||
{
|
||||
VersionType versionType = this.version.getVersionType();
|
||||
assertEquals(VERSION_TYPE, versionType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getVersionProperties
|
||||
*
|
||||
*/
|
||||
public void testGetVersionProperties()
|
||||
{
|
||||
Map<String, Serializable> versionProperties = version.getVersionProperties();
|
||||
assertNotNull(versionProperties);
|
||||
assertEquals(this.versionProperties.size(), versionProperties.size());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getVersionProperty
|
||||
*/
|
||||
public void testGetVersionProperty()
|
||||
{
|
||||
String value1 = (String)version.getVersionProperty(VersionImplTest.PROP_1);
|
||||
assertEquals(value1, VersionImplTest.VALUE_1);
|
||||
|
||||
String value2 = (String)version.getVersionProperty(VersionImplTest.PROP_2);
|
||||
assertEquals(value2, VersionImplTest.VALUE_2);
|
||||
|
||||
String value3 = (String)version.getVersionProperty(VersionImplTest.PROP_3);
|
||||
assertEquals(value3, VersionImplTest.VALUE_3);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getNodeRef()
|
||||
*/
|
||||
public void testGetNodeRef()
|
||||
{
|
||||
NodeRef nodeRef = this.version.getFrozenStateNodeRef();
|
||||
assertNotNull(nodeRef);
|
||||
assertEquals(nodeRef.toString(), this.nodeRef.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Exception case - no node ref supplied when creating a verison
|
||||
*/
|
||||
public void testNoNodeRefOnVersionCreate()
|
||||
{
|
||||
try
|
||||
{
|
||||
new VersionImpl(this.versionProperties, null);
|
||||
fail("It is invalid to create a version object without a node ref specified.");
|
||||
}
|
||||
catch (VersionServiceException exception)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
* copy of the License at
|
||||
*
|
||||
* http://www.alfresco.org/legal/license.txt
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the
|
||||
* License.
|
||||
*/
|
||||
package org.alfresco.repo.version.common;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.alfresco.repo.version.VersionModel;
|
||||
import org.alfresco.service.cmr.version.ReservedVersionNameException;
|
||||
|
||||
/**
|
||||
* Helper class containing helper methods for the versioning services.
|
||||
*
|
||||
* @author Roy Wetherall
|
||||
*/
|
||||
public class VersionUtil
|
||||
{
|
||||
/**
|
||||
* Reserved property names
|
||||
*/
|
||||
public static final String[] RESERVED_PROPERTY_NAMES = new String[]{
|
||||
VersionModel.PROP_CREATED_DATE,
|
||||
VersionModel.PROP_FROZEN_NODE_ID,
|
||||
VersionModel.PROP_FROZEN_NODE_STORE_ID,
|
||||
VersionModel.PROP_FROZEN_NODE_STORE_PROTOCOL,
|
||||
VersionModel.PROP_FROZEN_NODE_TYPE,
|
||||
VersionModel.PROP_FROZEN_ASPECTS,
|
||||
VersionModel.PROP_VERSION_LABEL,
|
||||
VersionModel.PROP_VERSION_NUMBER};
|
||||
|
||||
/**
|
||||
* Checks that the names of the additional version properties are valid and that they do not clash
|
||||
* with the reserved properties.
|
||||
*
|
||||
* @param versionProperties the property names
|
||||
* @return true is the names are considered valid, false otherwise
|
||||
* @throws ReservedVersionNameException
|
||||
*/
|
||||
public static void checkVersionPropertyNames(Collection<String> names)
|
||||
throws ReservedVersionNameException
|
||||
{
|
||||
for (String name : RESERVED_PROPERTY_NAMES)
|
||||
{
|
||||
if (names.contains(name) == true)
|
||||
{
|
||||
throw new ReservedVersionNameException(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
* copy of the License at
|
||||
*
|
||||
* http://www.alfresco.org/legal/license.txt
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the
|
||||
* License.
|
||||
*/
|
||||
package org.alfresco.repo.version.common.counter;
|
||||
|
||||
import org.alfresco.service.cmr.repository.StoreRef;
|
||||
|
||||
/**
|
||||
* Version counter DAO service interface.
|
||||
*
|
||||
* @author Roy Wetherall
|
||||
*/
|
||||
public interface VersionCounterDaoService
|
||||
{
|
||||
/**
|
||||
* Get the next available version number for the specified store.
|
||||
*
|
||||
* @param storeRef the store reference
|
||||
* @return the next version number
|
||||
*/
|
||||
public int nextVersionNumber(StoreRef storeRef);
|
||||
|
||||
/**
|
||||
* Gets the current version number for the specified store.
|
||||
*
|
||||
* @param storeRef the store reference
|
||||
* @return the current versio number
|
||||
*/
|
||||
public int currentVersionNumber(StoreRef storeRef);
|
||||
|
||||
/**
|
||||
* Resets the version number for a the specified store.
|
||||
*
|
||||
* WARNING: calling this method will completely reset the current
|
||||
* version count for the specified store and cannot be undone.
|
||||
*
|
||||
* @param storeRef the store reference
|
||||
*/
|
||||
public void resetVersionNumber(StoreRef storeRef);
|
||||
}
|
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
* copy of the License at
|
||||
*
|
||||
* http://www.alfresco.org/legal/license.txt
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the
|
||||
* License.
|
||||
*/
|
||||
package org.alfresco.repo.version.common.counter;
|
||||
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.cmr.repository.StoreRef;
|
||||
import org.alfresco.util.BaseSpringTest;
|
||||
|
||||
/**
|
||||
* @author Roy Wetherall
|
||||
*/
|
||||
public class VersionCounterDaoServiceTest extends BaseSpringTest
|
||||
{
|
||||
/*
|
||||
* Test store id's
|
||||
*/
|
||||
private final static String STORE_ID_1 = "test1_" + System.currentTimeMillis();
|
||||
private final static String STORE_ID_2 = "test2_" + System.currentTimeMillis();
|
||||
private static final String STORE_NONE = "test3_" + System.currentTimeMillis();;
|
||||
|
||||
private NodeService nodeService;
|
||||
private VersionCounterDaoService counter;
|
||||
|
||||
@Override
|
||||
public void onSetUpInTransaction()
|
||||
{
|
||||
nodeService = (NodeService) applicationContext.getBean("dbNodeService");
|
||||
counter = (VersionCounterDaoService) applicationContext.getBean("versionCounterDaoService");
|
||||
}
|
||||
|
||||
public void testSetUp() throws Exception
|
||||
{
|
||||
assertNotNull(nodeService);
|
||||
assertNotNull(counter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test nextVersionNumber
|
||||
*/
|
||||
public void testNextVersionNumber()
|
||||
{
|
||||
// Create the store references
|
||||
StoreRef store1 = new StoreRef(StoreRef.PROTOCOL_WORKSPACE, VersionCounterDaoServiceTest.STORE_ID_1);
|
||||
StoreRef store2 = new StoreRef(StoreRef.PROTOCOL_WORKSPACE, VersionCounterDaoServiceTest.STORE_ID_2);
|
||||
StoreRef storeNone = new StoreRef(StoreRef.PROTOCOL_WORKSPACE, VersionCounterDaoServiceTest.STORE_NONE);
|
||||
|
||||
int store1Version0 = this.counter.nextVersionNumber(store1);
|
||||
assertEquals(store1Version0, 1);
|
||||
|
||||
int store1Version1 = this.counter.nextVersionNumber(store1);
|
||||
assertEquals(store1Version1, 2);
|
||||
|
||||
int store2Version0 = this.counter.nextVersionNumber(store2);
|
||||
assertEquals(store2Version0, 1);
|
||||
|
||||
int store1Version2 = this.counter.nextVersionNumber(store1);
|
||||
assertEquals(store1Version2, 3);
|
||||
|
||||
int store2Version1 = this.counter.nextVersionNumber(store2);
|
||||
assertEquals(store2Version1, 2);
|
||||
|
||||
int store1Current = this.counter.currentVersionNumber(store1);
|
||||
assertEquals(store1Current, 3);
|
||||
|
||||
int store2Current = this.counter.currentVersionNumber(store2);
|
||||
assertEquals(store2Current, 2);
|
||||
|
||||
int storeNoneCurrent = this.counter.currentVersionNumber(storeNone);
|
||||
assertEquals(storeNoneCurrent, 0);
|
||||
|
||||
// Need to clean-up since the version counter works in its own transaction
|
||||
this.counter.resetVersionNumber(store1);
|
||||
this.counter.resetVersionNumber(store2);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
* copy of the License at
|
||||
*
|
||||
* http://www.alfresco.org/legal/license.txt
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the
|
||||
* License.
|
||||
*/
|
||||
package org.alfresco.repo.version.common.counter.hibernate;
|
||||
|
||||
import java.util.concurrent.locks.Lock;
|
||||
|
||||
import org.alfresco.repo.domain.StoreKey;
|
||||
import org.alfresco.repo.domain.VersionCount;
|
||||
import org.alfresco.repo.domain.hibernate.VersionCountImpl;
|
||||
import org.alfresco.repo.version.common.counter.VersionCounterDaoService;
|
||||
import org.alfresco.service.cmr.repository.StoreRef;
|
||||
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
|
||||
|
||||
/**
|
||||
* Version counter DAO service implemtation using Hibernate.
|
||||
* <p>
|
||||
* The object should execute within its own transaction, and is limited to single-thread
|
||||
* entry. If it becomes a bottleneck, the transaction synchronization should be moved
|
||||
* over to reentrant locks and/or the hibernate mappings should be optimized for better
|
||||
* read-write access.
|
||||
*
|
||||
* @author Derek Hulley
|
||||
*/
|
||||
public class HibernateVersionCounterDaoServiceImpl extends HibernateDaoSupport implements VersionCounterDaoService
|
||||
{
|
||||
private Lock countReadLock;
|
||||
private Lock countWriteLock;
|
||||
|
||||
/**
|
||||
* Retrieves or creates a version counter
|
||||
*
|
||||
* @param storeKey
|
||||
* @return Returns a current or new version counter
|
||||
*/
|
||||
private VersionCount getVersionCounter(StoreRef storeRef)
|
||||
{
|
||||
StoreKey storeKey = new StoreKey(storeRef.getProtocol(), storeRef.getIdentifier());
|
||||
// get the version counter
|
||||
VersionCount versionCounter = (VersionCount) getHibernateTemplate().get(VersionCountImpl.class, storeKey);
|
||||
// check if it exists
|
||||
if (versionCounter == null)
|
||||
{
|
||||
// create a new one
|
||||
versionCounter = new VersionCountImpl();
|
||||
getHibernateTemplate().save(versionCounter, storeKey);
|
||||
}
|
||||
return versionCounter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the next available version number for the specified store.
|
||||
*
|
||||
* @param storeRef the version store id
|
||||
* @return the next version number
|
||||
*/
|
||||
public synchronized int nextVersionNumber(StoreRef storeRef)
|
||||
{
|
||||
// get the version counter
|
||||
VersionCount versionCounter = getVersionCounter(storeRef);
|
||||
// get an incremented count
|
||||
return versionCounter.incrementVersionCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current version number for the specified store.
|
||||
*
|
||||
* @param storeRef the store reference
|
||||
* @return the current version number, zero if no version yet allocated.
|
||||
*/
|
||||
public synchronized int currentVersionNumber(StoreRef storeRef)
|
||||
{
|
||||
// get the version counter
|
||||
VersionCount versionCounter = getVersionCounter(storeRef);
|
||||
// get an incremented count
|
||||
return versionCounter.getVersionCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the version number for a the specified store.
|
||||
*
|
||||
* WARNING: calling this method will completely reset the current
|
||||
* version count for the specified store and cannot be undone.
|
||||
*
|
||||
* @param storeRef the store reference
|
||||
*/
|
||||
public synchronized void resetVersionNumber(StoreRef storeRef)
|
||||
{
|
||||
// get the version counter
|
||||
VersionCount versionCounter = getVersionCounter(storeRef);
|
||||
// get an incremented count
|
||||
versionCounter.resetVersionCount();
|
||||
}
|
||||
}
|
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
* copy of the License at
|
||||
*
|
||||
* http://www.alfresco.org/legal/license.txt
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the
|
||||
* License.
|
||||
*/
|
||||
package org.alfresco.repo.version.common.versionlabel;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.repo.version.VersionModel;
|
||||
import org.alfresco.service.cmr.version.Version;
|
||||
import org.alfresco.service.cmr.version.VersionType;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
|
||||
/**
|
||||
* The serial version label policy.
|
||||
*
|
||||
* @author Roy Wetherall
|
||||
*/
|
||||
public class SerialVersionLabelPolicy
|
||||
{
|
||||
// TODO need to add support for branches into this labeling policy
|
||||
|
||||
/**
|
||||
* Get the version label value base on the data provided.
|
||||
*
|
||||
* @param preceedingVersion the preceeding version, null if none
|
||||
* @param versionNumber the new version number
|
||||
* @param versionProperties the version property values
|
||||
* @return the version label
|
||||
*/
|
||||
public String calculateVersionLabel(
|
||||
QName classRef,
|
||||
Version preceedingVersion,
|
||||
int versionNumber,
|
||||
Map<String, Serializable> versionProperties)
|
||||
{
|
||||
SerialVersionLabel serialVersionNumber = null;
|
||||
|
||||
if (preceedingVersion != null)
|
||||
{
|
||||
serialVersionNumber = new SerialVersionLabel(preceedingVersion.getVersionLabel());
|
||||
|
||||
VersionType versionType = (VersionType)versionProperties.get(VersionModel.PROP_VERSION_TYPE);
|
||||
if (VersionType.MAJOR.equals(versionType) == true)
|
||||
{
|
||||
serialVersionNumber.majorIncrement();
|
||||
}
|
||||
else
|
||||
{
|
||||
serialVersionNumber.minorIncrement();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
serialVersionNumber = new SerialVersionLabel(null);
|
||||
}
|
||||
|
||||
return serialVersionNumber.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Inner class encapsulating the notion of the serial version number.
|
||||
*
|
||||
* @author Roy Wetherall
|
||||
*/
|
||||
private class SerialVersionLabel
|
||||
{
|
||||
/**
|
||||
* The version number delimiter
|
||||
*/
|
||||
private static final String DELIMITER = ".";
|
||||
|
||||
/**
|
||||
* The major revision number
|
||||
*/
|
||||
private int majorRevisionNumber = 1;
|
||||
|
||||
/**
|
||||
* The minor revision number
|
||||
*/
|
||||
private int minorRevisionNumber = 0;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param version the vesion to take the version from
|
||||
*/
|
||||
public SerialVersionLabel(String versionLabel)
|
||||
{
|
||||
if (versionLabel != null && versionLabel.length() != 0)
|
||||
{
|
||||
int iIndex = versionLabel.indexOf(DELIMITER);
|
||||
String majorString = versionLabel.substring(0, iIndex);
|
||||
String minorString = versionLabel.substring(iIndex+1);
|
||||
|
||||
this.majorRevisionNumber = Integer.parseInt(majorString);
|
||||
this.minorRevisionNumber = Integer.parseInt(minorString);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments the major revision numebr and sets the minor to
|
||||
* zero.
|
||||
*/
|
||||
public void majorIncrement()
|
||||
{
|
||||
this.majorRevisionNumber += 1;
|
||||
this.minorRevisionNumber = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments only the minor revision number
|
||||
*/
|
||||
public void minorIncrement()
|
||||
{
|
||||
this.minorRevisionNumber += 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the serial version number into a string
|
||||
*/
|
||||
public String toString()
|
||||
{
|
||||
return this.majorRevisionNumber + DELIMITER + this.minorRevisionNumber;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
* copy of the License at
|
||||
*
|
||||
* http://www.alfresco.org/legal/license.txt
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the
|
||||
* License.
|
||||
*/
|
||||
package org.alfresco.repo.version.common.versionlabel;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.version.VersionModel;
|
||||
import org.alfresco.repo.version.common.VersionImpl;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.StoreRef;
|
||||
import org.alfresco.service.cmr.version.Version;
|
||||
import org.alfresco.service.cmr.version.VersionType;
|
||||
|
||||
/**
|
||||
* Unit test class for SerialVersionLabelPolicy class
|
||||
*
|
||||
* @author Roy Wetherall
|
||||
*/
|
||||
public class SerialVersionLabelPolicyTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* Test getVersionLabelValue
|
||||
*/
|
||||
public void testGetVersionLabelValue()
|
||||
{
|
||||
SerialVersionLabelPolicy policy = new SerialVersionLabelPolicy();
|
||||
|
||||
NodeRef dummyNodeRef = new NodeRef(new StoreRef("", ""), "");
|
||||
|
||||
HashMap<String, Serializable> versionProp1 = new HashMap<String, Serializable>();
|
||||
versionProp1.put(VersionModel.PROP_VERSION_TYPE, VersionType.MINOR);
|
||||
|
||||
String initialVersion = policy.calculateVersionLabel(
|
||||
ContentModel.TYPE_CMOBJECT,
|
||||
null,
|
||||
0,
|
||||
versionProp1);
|
||||
assertEquals("1.0", initialVersion);
|
||||
|
||||
HashMap<String, Serializable> versionProp2 = new HashMap<String, Serializable>();
|
||||
versionProp2.put(VersionModel.PROP_VERSION_LABEL, "1.0");
|
||||
Version version1 = new VersionImpl(versionProp2, dummyNodeRef);
|
||||
|
||||
String verisonLabel1 = policy.calculateVersionLabel(
|
||||
ContentModel.TYPE_CMOBJECT,
|
||||
version1,
|
||||
1,
|
||||
versionProp1);
|
||||
assertEquals("1.1", verisonLabel1);
|
||||
|
||||
HashMap<String, Serializable> versionProp3 = new HashMap<String, Serializable>();
|
||||
versionProp3.put(VersionModel.PROP_VERSION_LABEL, "1.1");
|
||||
Version version2 = new VersionImpl(versionProp3, dummyNodeRef);
|
||||
|
||||
HashMap<String, Serializable> versionProp4 = new HashMap<String, Serializable>();
|
||||
versionProp4.put(VersionModel.PROP_VERSION_TYPE, VersionType.MAJOR);
|
||||
|
||||
String verisonLabel2 = policy.calculateVersionLabel(
|
||||
ContentModel.TYPE_CMOBJECT,
|
||||
version2,
|
||||
1,
|
||||
versionProp4);
|
||||
assertEquals("2.0", verisonLabel2);
|
||||
}
|
||||
|
||||
}
|
156
source/java/org/alfresco/repo/version/version_model.xml
Normal file
156
source/java/org/alfresco/repo/version/version_model.xml
Normal file
@@ -0,0 +1,156 @@
|
||||
<model name="ver:versionmodel" xmlns="http://www.alfresco.org/model/dictionary/1.0">
|
||||
|
||||
<description>Alfresco Version Store Model</description>
|
||||
<author>Alfresco</author>
|
||||
<published>2005-05-30</published>
|
||||
<version>0.1</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/1.0" prefix="ver"/>
|
||||
</namespaces>
|
||||
|
||||
<types>
|
||||
|
||||
<type name="ver:versionMetaDataValue">
|
||||
<parent>sys:base</parent>
|
||||
<properties>
|
||||
<property name="ver:metaDataName">
|
||||
<type>d:text</type>
|
||||
</property>
|
||||
<property name="ver:metaDataValue">
|
||||
<type>d:any</type>
|
||||
</property>
|
||||
</properties>
|
||||
</type>
|
||||
|
||||
<type name="ver:versionedProperty">
|
||||
<parent>sys:base</parent>
|
||||
<properties>
|
||||
<property name="ver:qname">
|
||||
<type>d:qname</type>
|
||||
</property>
|
||||
<property name="ver:value">
|
||||
<type>d:any</type>
|
||||
</property>
|
||||
<property name="ver:multiValue">
|
||||
<type>d:any</type>
|
||||
<multiple>true</multiple>
|
||||
</property>
|
||||
<property name="ver:isMultiValue">
|
||||
<type>d:boolean</type>
|
||||
</property>
|
||||
</properties>
|
||||
</type>
|
||||
|
||||
<type name="ver:versionedAssoc">
|
||||
<parent>sys:reference</parent>
|
||||
<properties>
|
||||
<property name="ver:assocQName">
|
||||
<type>d:qname</type>
|
||||
</property>
|
||||
</properties>
|
||||
</type>
|
||||
|
||||
<type name="ver:versionedChildAssoc">
|
||||
<parent>ver:versionedAssoc</parent>
|
||||
<properties>
|
||||
<property name="ver:isPrimary">
|
||||
<type>d:boolean</type>
|
||||
</property>
|
||||
<property name="ver:nthSibling">
|
||||
<type>d:int</type>
|
||||
</property>
|
||||
</properties>
|
||||
</type>
|
||||
|
||||
<type name="ver:version">
|
||||
<parent>sys:container</parent>
|
||||
<properties>
|
||||
<property name="ver:versionNumber">
|
||||
<type>d:int</type>
|
||||
</property>
|
||||
<property name="ver:versionLabel">
|
||||
<type>d:text</type>
|
||||
</property>
|
||||
<property name="ver:frozenNodeId">
|
||||
<type>d:text</type>
|
||||
</property>
|
||||
<property name="ver:frozenNodeStoreId">
|
||||
<type>d:text</type>
|
||||
</property>
|
||||
<property name="ver:frozenNodeStoreProtocol">
|
||||
<type>d:text</type>
|
||||
</property>
|
||||
<property name="ver:frozenNodeType">
|
||||
<type>d:qname</type>
|
||||
</property>
|
||||
<property name="ver:frozenAspects">
|
||||
<type>d:qname</type>
|
||||
<multiple>true</multiple>
|
||||
</property>
|
||||
</properties>
|
||||
<associations>
|
||||
<child-association name="ver:versionMetaData">
|
||||
<target>
|
||||
<class>ver:versionMetaDataValue</class>
|
||||
</target>
|
||||
</child-association>
|
||||
<child-association name="ver:versionedAttributes">
|
||||
<target>
|
||||
<class>ver:versionedProperty</class>
|
||||
</target>
|
||||
</child-association>
|
||||
<child-association name="ver:versionedChildAssocs">
|
||||
<target>
|
||||
<class>ver:versionedChildAssoc</class>
|
||||
</target>
|
||||
</child-association>
|
||||
<child-association name="ver:versionedAssocs">
|
||||
<target>
|
||||
<class>ver:versionedAssoc</class>
|
||||
</target>
|
||||
</child-association>
|
||||
<association name="ver:successor">
|
||||
<target>
|
||||
<class>ver:version</class>
|
||||
</target>
|
||||
</association>
|
||||
</associations>
|
||||
|
||||
<mandatory-aspects>
|
||||
<aspect>cm:auditable</aspect>
|
||||
</mandatory-aspects>
|
||||
</type>
|
||||
|
||||
<type name="ver:versionHistory">
|
||||
<parent>sys:base</parent>
|
||||
|
||||
<properties>
|
||||
<property name="ver:versionedNodeId">
|
||||
<type>d:text</type>
|
||||
</property>
|
||||
</properties>
|
||||
|
||||
<associations>
|
||||
<child-association name="ver:version">
|
||||
<target>
|
||||
<class>ver:version</class>
|
||||
</target>
|
||||
</child-association>
|
||||
<association name="ver:rootVersion">
|
||||
<target>
|
||||
<class>ver:version</class>
|
||||
</target>
|
||||
</association>
|
||||
</associations>
|
||||
</type>
|
||||
|
||||
</types>
|
||||
|
||||
</model>
|
Reference in New Issue
Block a user