. JavaScript API enhancements checkpoint:

- checkout() - perform a checkout of a node, returning the working-copy as the result
 - checkin() - perform a checkin of a working-copy node, returning the original as the result
 - cancelCheckout() - cancel the checkout of a work-copy node
. Fix from Roy to VersionableAspect to correctly handle making a node versionable, setting content and checking in/out all within a single transaction

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@3434 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Kevin Roast
2006-07-28 15:27:28 +00:00
parent 8814fac8bc
commit 0c35c285bd
3 changed files with 134 additions and 31 deletions

View File

@@ -31,6 +31,7 @@ import java.util.StringTokenizer;
import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel; import org.alfresco.model.ContentModel;
import org.alfresco.repo.security.permissions.AccessDeniedException; import org.alfresco.repo.security.permissions.AccessDeniedException;
import org.alfresco.repo.version.VersionModel;
import org.alfresco.service.ServiceRegistry; import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.dictionary.InvalidAspectException; import org.alfresco.service.cmr.dictionary.InvalidAspectException;
@@ -49,6 +50,8 @@ import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.TemplateImageResolver; import org.alfresco.service.cmr.repository.TemplateImageResolver;
import org.alfresco.service.cmr.security.AccessStatus; import org.alfresco.service.cmr.security.AccessStatus;
import org.alfresco.service.cmr.security.PermissionService; import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.cmr.version.Version;
import org.alfresco.service.cmr.version.VersionType;
import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern; import org.alfresco.service.namespace.RegexQNamePattern;
@@ -121,6 +124,19 @@ public final class Node implements Serializable, Scopeable
* @param resolver Image resolver to use to retrieve icons * @param resolver Image resolver to use to retrieve icons
*/ */
public Node(NodeRef nodeRef, ServiceRegistry services, TemplateImageResolver resolver) public Node(NodeRef nodeRef, ServiceRegistry services, TemplateImageResolver resolver)
{
this(nodeRef, services, resolver, null);
}
/**
* Constructor
*
* @param nodeRef The NodeRef this Node wrapper represents
* @param services The ServiceRegistry the Node can use to access services
* @param resolver Image resolver to use to retrieve icons
* @param scope Root scope for this Node
*/
public Node(NodeRef nodeRef, ServiceRegistry services, TemplateImageResolver resolver, Scriptable scope)
{ {
if (nodeRef == null) if (nodeRef == null)
{ {
@@ -137,6 +153,7 @@ public final class Node implements Serializable, Scopeable
this.services = services; this.services = services;
this.nodeService = services.getNodeService(); this.nodeService = services.getNodeService();
this.imageResolver = resolver; this.imageResolver = resolver;
this.scope = scope;
} }
/** /**
@@ -258,8 +275,8 @@ public final class Node implements Serializable, Scopeable
for (int i=0; i<childRefs.size(); i++) for (int i=0; i<childRefs.size(); i++)
{ {
// create our Node representation from the NodeRef // create our Node representation from the NodeRef
Node child = new Node(childRefs.get(i).getChildRef(), this.services, this.imageResolver); Node child = new Node(
child.setScope(this.scope); childRefs.get(i).getChildRef(), this.services, this.imageResolver, this.scope);
this.children[i] = child; this.children[i] = child;
} }
} }
@@ -349,8 +366,8 @@ public final class Node implements Serializable, Scopeable
System.arraycopy(nodes, 0, newNodes, 0, nodes.length); System.arraycopy(nodes, 0, newNodes, 0, nodes.length);
nodes = newNodes; nodes = newNodes;
} }
nodes[nodes.length - 1] = new Node(ref.getTargetRef(), this.services, this.imageResolver); nodes[nodes.length - 1] = new Node(
nodes[nodes.length - 1].setScope(this.scope); ref.getTargetRef(), this.services, this.imageResolver, this.scope);
this.assocs.put(ref.getTypeQName().toString(), nodes); this.assocs.put(ref.getTypeQName().toString(), nodes);
} }
@@ -390,8 +407,8 @@ public final class Node implements Serializable, Scopeable
{ {
// NodeRef object properties are converted to new Node objects // NodeRef object properties are converted to new Node objects
// so they can be used as objects within a template // so they can be used as objects within a template
propValue = new Node(((NodeRef)propValue), this.services, this.imageResolver); propValue = new Node(
((Node)propValue).setScope(this.scope); ((NodeRef)propValue), this.services, this.imageResolver, this.scope);
} }
else if (propValue instanceof ContentData) else if (propValue instanceof ContentData)
{ {
@@ -642,8 +659,7 @@ public final class Node implements Serializable, Scopeable
// handle root node (no parent!) // handle root node (no parent!)
if (parentRef != null) if (parentRef != null)
{ {
parent = new Node(parentRef, this.services, this.imageResolver); parent = new Node(parentRef, this.services, this.imageResolver, this.scope);
parent.setScope(this.scope);
} }
} }
@@ -1032,8 +1048,7 @@ public final class Node implements Serializable, Scopeable
{ {
FileInfo fileInfo = this.services.getFileFolderService().create( FileInfo fileInfo = this.services.getFileFolderService().create(
this.nodeRef, name, ContentModel.TYPE_CONTENT); this.nodeRef, name, ContentModel.TYPE_CONTENT);
node = new Node(fileInfo.getNodeRef(), this.services, this.imageResolver); node = new Node(fileInfo.getNodeRef(), this.services, this.imageResolver, this.scope);
node.setScope(this.scope);
} }
} }
catch (FileExistsException fileErr) catch (FileExistsException fileErr)
@@ -1066,8 +1081,7 @@ public final class Node implements Serializable, Scopeable
{ {
FileInfo fileInfo = this.services.getFileFolderService().create( FileInfo fileInfo = this.services.getFileFolderService().create(
this.nodeRef, name, ContentModel.TYPE_FOLDER); this.nodeRef, name, ContentModel.TYPE_FOLDER);
node = new Node(fileInfo.getNodeRef(), this.services, this.imageResolver); node = new Node(fileInfo.getNodeRef(), this.services, this.imageResolver, this.scope);
node.setScope(this.scope);
} }
} }
catch (FileExistsException fileErr) catch (FileExistsException fileErr)
@@ -1108,8 +1122,7 @@ public final class Node implements Serializable, Scopeable
QName.createQName(NamespaceService.ALFRESCO_URI, QName.createValidLocalName(name)), QName.createQName(NamespaceService.ALFRESCO_URI, QName.createValidLocalName(name)),
createQName(type), createQName(type),
props); props);
node = new Node(childAssocRef.getChildRef(), this.services, this.imageResolver); node = new Node(childAssocRef.getChildRef(), this.services, this.imageResolver, this.scope);
node.setScope(this.scope);
} }
} }
catch (AccessDeniedException accessErr) catch (AccessDeniedException accessErr)
@@ -1182,8 +1195,7 @@ public final class Node implements Serializable, Scopeable
ContentModel.ASSOC_CONTAINS, ContentModel.ASSOC_CONTAINS,
getPrimaryParentAssoc().getQName(), getPrimaryParentAssoc().getQName(),
deepCopy); deepCopy);
copy = new Node(copyRef, this.services, this.imageResolver); copy = new Node(copyRef, this.services, this.imageResolver, this.scope);
copy.setScope(this.scope);
} }
} }
catch (AccessDeniedException accessErr) catch (AccessDeniedException accessErr)
@@ -1311,7 +1323,101 @@ public final class Node implements Serializable, Scopeable
// ------------------------------------------------------------------------------ // ------------------------------------------------------------------------------
// Checkout/Checkin Services // Checkout/Checkin Services
/**
* Perform a check-out of this document into the current parent space.
*
* @return the working copy Node for the checked out document
*/
public Node checkout()
{
NodeRef workingCopyRef = this.services.getCheckOutCheckInService().checkout(this.nodeRef);
Node workingCopy = new Node(workingCopyRef, this.services, this.imageResolver, this.scope);
// reset the aspect and properties as checking out a document causes changes
this.properties = null;
this.aspects = null;
return workingCopy;
}
/**
* Perform a check-out of this document into the specified destination space.
*
* @param destination Destination for the checked out document working copy Node.
*
* @return the working copy Node for the checked out document
*/
public Node checkout(Node destination)
{
ChildAssociationRef childAssocRef = this.nodeService.getPrimaryParent(destination.getNodeRef());
NodeRef workingCopyRef = this.services.getCheckOutCheckInService().checkout(this.nodeRef,
destination.getNodeRef(), ContentModel.ASSOC_CONTAINS, childAssocRef.getQName());
Node workingCopy = new Node(workingCopyRef, this.services, this.imageResolver, this.scope);
// reset the aspect and properties as checking out a document causes changes
this.properties = null;
this.aspects = null;
return workingCopy;
}
/**
* Check-in a working copy document. The current state of the working copy is copied to the
* original node, this will include any content updated in the working node. Note that this
* method can only be called on a working copy Node.
*
* @return the original Node that was checked out.
*/
public Node checkin()
{
return checkin("", false);
}
/**
* Check-in a working copy document. The current state of the working copy is copied to the
* original node, this will include any content updated in the working node. Note that this
* method can only be called on a working copy Node.
*
* @param history Version history note
*
* @return the original Node that was checked out.
*/
public Node checkin(String history)
{
return checkin(history, false);
}
/**
* Check-in a working copy document. The current state of the working copy is copied to the
* original node, this will include any content updated in the working node. Note that this
* method can only be called on a working copy Node.
*
* @param history Version history note
* @param majorVersion True to save as a major version increment, false for minor version.
*
* @return the original Node that was checked out.
*/
public Node checkin(String history, boolean majorVersion)
{
Map<String, Serializable> props = new HashMap<String, Serializable>(2, 1.0f);
props.put(Version.PROP_DESCRIPTION, history);
props.put(VersionModel.PROP_VERSION_TYPE, majorVersion ? VersionType.MAJOR : VersionType.MINOR);
NodeRef original = this.services.getCheckOutCheckInService().checkin(this.nodeRef, props);
return new Node(original, this.services, this.imageResolver, this.scope);
}
/**
* Cancel the check-out of a working copy document. The working copy will be deleted and any
* changes made to it are lost. Note that this method can only be called on a working copy Node.
* The reference to this working copy Node should be discarded.
*
* @return the original Node that was checked out.
*/
public Node cancelCheckout()
{
NodeRef original = this.services.getCheckOutCheckInService().cancelCheckout(this.nodeRef);
return new Node(original, this.services, this.imageResolver, this.scope);
}
// ------------------------------------------------------------------------------ // ------------------------------------------------------------------------------
@@ -1403,8 +1509,7 @@ public final class Node implements Serializable, Scopeable
if (nodes.size() != 0) if (nodes.size() != 0)
{ {
result = new Node[1]; result = new Node[1];
result[0] = new Node(nodes.get(0), this.services, this.imageResolver); result[0] = new Node(nodes.get(0), this.services, this.imageResolver, this.scope);
result[0].setScope(this.scope);
} }
} }
// or all the results // or all the results
@@ -1414,8 +1519,7 @@ public final class Node implements Serializable, Scopeable
for (int i=0; i<nodes.size(); i++) for (int i=0; i<nodes.size(); i++)
{ {
NodeRef ref = nodes.get(i); NodeRef ref = nodes.get(i);
result[i] = new Node(ref, this.services, this.imageResolver); result[i] = new Node(ref, this.services, this.imageResolver, this.scope);
result[i].setScope(this.scope);
} }
} }
} }

View File

@@ -17,9 +17,6 @@
package org.alfresco.repo.jscript; package org.alfresco.repo.jscript;
import java.io.StringReader; import java.io.StringReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel; import org.alfresco.model.ContentModel;
@@ -28,7 +25,6 @@ import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.repository.TemplateImageResolver; import org.alfresco.service.cmr.repository.TemplateImageResolver;
import org.alfresco.service.cmr.repository.TemplateNode;
import org.alfresco.service.cmr.search.ResultSet; import org.alfresco.service.cmr.search.ResultSet;
import org.alfresco.service.cmr.search.ResultSetRow; import org.alfresco.service.cmr.search.ResultSetRow;
import org.alfresco.service.cmr.search.SearchService; import org.alfresco.service.cmr.search.SearchService;
@@ -183,8 +179,7 @@ public final class Search implements Scopeable
for (ResultSetRow row: results) for (ResultSetRow row: results)
{ {
NodeRef nodeRef = row.getNodeRef(); NodeRef nodeRef = row.getNodeRef();
nodes[count] = new Node(nodeRef, services, this.imageResolver); nodes[count] = new Node(nodeRef, services, this.imageResolver, this.scope);
nodes[count].setScope(this.scope);
count++; count++;
} }
} }

View File

@@ -178,7 +178,7 @@ public class VersionableAspect implements ContentServicePolicies.OnContentUpdate
*/ */
public void onAddAspect(NodeRef nodeRef, QName aspectTypeQName) public void onAddAspect(NodeRef nodeRef, QName aspectTypeQName)
{ {
if (aspectTypeQName.equals(ContentModel.ASPECT_VERSIONABLE) == true) if (this.nodeService.exists(nodeRef) == true && aspectTypeQName.equals(ContentModel.ASPECT_VERSIONABLE) == true)
{ {
boolean initialVersion = true; boolean initialVersion = true;
Boolean value = (Boolean)this.nodeService.getProperty(nodeRef, ContentModel.PROP_INITIAL_VERSION); Boolean value = (Boolean)this.nodeService.getProperty(nodeRef, ContentModel.PROP_INITIAL_VERSION);
@@ -190,10 +190,14 @@ public class VersionableAspect implements ContentServicePolicies.OnContentUpdate
if (initialVersion == true) if (initialVersion == true)
{ {
// Queue create version action Map<NodeRef, NodeRef> versionedNodeRefs = (Map)AlfrescoTransactionSupport.getResource(KEY_VERSIONED_NODEREFS);
Map<String, Serializable> versionDetails = new HashMap<String, Serializable>(1); if (versionedNodeRefs == null || versionedNodeRefs.containsKey(nodeRef) == false)
versionDetails.put(Version.PROP_DESCRIPTION, I18NUtil.getMessage(MSG_INITIAL_VERSION)); {
this.versionService.createVersion(nodeRef, versionDetails); // Queue create version action
Map<String, Serializable> versionDetails = new HashMap<String, Serializable>(1);
versionDetails.put(Version.PROP_DESCRIPTION, I18NUtil.getMessage(MSG_INITIAL_VERSION));
this.versionService.createVersion(nodeRef, versionDetails);
}
} }
} }
} }