mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-06-02 17:35:18 +00:00
svn merge svn://svn.alfresco.com:3691/alfresco/BRANCHES/V1.4@4252 svn://svn.alfresco.com:3691/alfresco/BRANCHES/V1.4@4294 . svn revert root\common\common.xml svn resolved root\projects\repository\config\alfresco\script-services-context.xml git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@4634 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
491 lines
18 KiB
Java
491 lines
18 KiB
Java
/*
|
|
* 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.coci;
|
|
|
|
import java.io.Serializable;
|
|
import java.util.HashMap;
|
|
import java.util.Map;
|
|
|
|
import org.alfresco.error.AlfrescoRuntimeException;
|
|
import org.alfresco.i18n.I18NUtil;
|
|
import org.alfresco.model.ContentModel;
|
|
import org.alfresco.repo.version.VersionableAspect;
|
|
import org.alfresco.service.cmr.coci.CheckOutCheckInService;
|
|
import org.alfresco.service.cmr.coci.CheckOutCheckInServiceException;
|
|
import org.alfresco.service.cmr.lock.LockService;
|
|
import org.alfresco.service.cmr.lock.LockType;
|
|
import org.alfresco.service.cmr.lock.UnableToReleaseLockException;
|
|
import org.alfresco.service.cmr.repository.AspectMissingException;
|
|
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
|
import org.alfresco.service.cmr.repository.ContentData;
|
|
import org.alfresco.service.cmr.repository.CopyService;
|
|
import org.alfresco.service.cmr.repository.NodeRef;
|
|
import org.alfresco.service.cmr.repository.NodeService;
|
|
import org.alfresco.service.cmr.search.ResultSet;
|
|
import org.alfresco.service.cmr.search.SearchService;
|
|
import org.alfresco.service.cmr.security.AuthenticationService;
|
|
import org.alfresco.service.cmr.version.VersionService;
|
|
import org.alfresco.service.namespace.QName;
|
|
|
|
/**
|
|
* Version opertaions service implementation
|
|
*
|
|
* @author Roy Wetherall
|
|
*/
|
|
public class CheckOutCheckInServiceImpl implements CheckOutCheckInService
|
|
{
|
|
/**
|
|
* I18N labels
|
|
*/
|
|
private static final String MSG_ERR_BAD_COPY = "coci_service.err_bad_copy";
|
|
private static final String MSG_WORKING_COPY_LABEL = "coci_service.working_copy_label";
|
|
private static final String MSG_ERR_NOT_OWNER = "coci_service.err_not_owner";
|
|
private static final String MSG_ERR_ALREADY_WORKING_COPY = "coci_service.err_workingcopy_checkout";
|
|
private static final String MSG_ERR_NOT_AUTHENTICATED = "coci_service.err_not_authenticated";
|
|
private static final String MSG_ERR_WORKINGCOPY_HAS_NO_MIMETYPE = "coci_service.err_workingcopy_has_no_mimetype";
|
|
private static final String MSG_ALREADY_CHECKEDOUT = "coci_service.err_already_checkedout";
|
|
|
|
/**
|
|
* Extension character, used to recalculate the working copy names
|
|
*/
|
|
private static final String EXTENSION_CHARACTER = ".";
|
|
|
|
/**
|
|
* The node service
|
|
*/
|
|
private NodeService nodeService;
|
|
|
|
/**
|
|
* The version service
|
|
*/
|
|
private VersionService versionService;
|
|
|
|
/**
|
|
* The lock service
|
|
*/
|
|
private LockService lockService;
|
|
|
|
/**
|
|
* The copy service
|
|
*/
|
|
private CopyService copyService;
|
|
|
|
/**
|
|
* The search service
|
|
*/
|
|
private SearchService searchService;
|
|
|
|
/**
|
|
* The authentication service
|
|
*/
|
|
private AuthenticationService authenticationService;
|
|
|
|
/**
|
|
* The versionable aspect behaviour implementation
|
|
*/
|
|
private VersionableAspect versionableAspect;
|
|
|
|
/**
|
|
* Set the node service
|
|
*
|
|
* @param nodeService the node service
|
|
*/
|
|
public void setNodeService(NodeService nodeService)
|
|
{
|
|
this.nodeService = nodeService;
|
|
}
|
|
|
|
/**
|
|
* Set the version service
|
|
*
|
|
* @param versionService the version service
|
|
*/
|
|
public void setVersionService(VersionService versionService)
|
|
{
|
|
this.versionService = versionService;
|
|
}
|
|
|
|
/**
|
|
* Sets the lock service
|
|
*
|
|
* @param lockService the lock service
|
|
*/
|
|
public void setLockService(LockService lockService)
|
|
{
|
|
this.lockService = lockService;
|
|
}
|
|
|
|
/**
|
|
* Sets the copy service
|
|
*
|
|
* @param copyService the copy service
|
|
*/
|
|
public void setCopyService(
|
|
CopyService copyService)
|
|
{
|
|
this.copyService = copyService;
|
|
}
|
|
|
|
/**
|
|
* Sets the authentication service
|
|
*
|
|
* @param authenticationService the authentication service
|
|
*/
|
|
public void setAuthenticationService(
|
|
AuthenticationService authenticationService)
|
|
{
|
|
this.authenticationService = authenticationService;
|
|
}
|
|
|
|
/**
|
|
* Set the search service
|
|
*
|
|
* @param searchService the search service
|
|
*/
|
|
public void setSearchService(SearchService searchService)
|
|
{
|
|
this.searchService = searchService;
|
|
}
|
|
|
|
/**
|
|
* Sets the versionable aspect behaviour implementation
|
|
*
|
|
* @param versionableAspect the versionable aspect behaviour implementation
|
|
*/
|
|
public void setVersionableAspect(VersionableAspect versionableAspect)
|
|
{
|
|
this.versionableAspect = versionableAspect;
|
|
}
|
|
|
|
/**
|
|
* Get the working copy label.
|
|
*
|
|
* @return the working copy label
|
|
*/
|
|
public String getWorkingCopyLabel()
|
|
{
|
|
return I18NUtil.getMessage(MSG_WORKING_COPY_LABEL);
|
|
}
|
|
|
|
/**
|
|
* @see org.alfresco.service.cmr.coci.CheckOutCheckInService#checkout(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.namespace.QName, org.alfresco.service.namespace.QName)
|
|
*/
|
|
public NodeRef checkout(
|
|
NodeRef nodeRef,
|
|
NodeRef destinationParentNodeRef,
|
|
QName destinationAssocTypeQName,
|
|
QName destinationAssocQName)
|
|
{
|
|
LockType lockType = this.lockService.getLockType(nodeRef);
|
|
if (LockType.READ_ONLY_LOCK.equals(lockType) == true)
|
|
{
|
|
throw new CheckOutCheckInServiceException(MSG_ALREADY_CHECKEDOUT);
|
|
}
|
|
|
|
// Make sure we are no checking out a working copy node
|
|
if (this.nodeService.hasAspect(nodeRef, ContentModel.ASPECT_WORKING_COPY) == true)
|
|
{
|
|
throw new CheckOutCheckInServiceException(MSG_ERR_ALREADY_WORKING_COPY);
|
|
}
|
|
|
|
// Apply the lock aspect if required
|
|
if (this.nodeService.hasAspect(nodeRef, ContentModel.ASPECT_LOCKABLE) == false)
|
|
{
|
|
this.nodeService.addAspect(nodeRef, ContentModel.ASPECT_LOCKABLE, null);
|
|
}
|
|
|
|
// Rename the working copy
|
|
String copyName = (String)this.nodeService.getProperty(nodeRef, ContentModel.PROP_NAME);
|
|
if (this.getWorkingCopyLabel() != null && this.getWorkingCopyLabel().length() != 0)
|
|
{
|
|
if (copyName != null && copyName.length() != 0)
|
|
{
|
|
int index = copyName.lastIndexOf(EXTENSION_CHARACTER);
|
|
if (index > 0)
|
|
{
|
|
// Insert the working copy label before the file extension
|
|
copyName = copyName.substring(0, index) + " " + getWorkingCopyLabel() + copyName.substring(index);
|
|
}
|
|
else
|
|
{
|
|
// Simply append the working copy label onto the end of the existing name
|
|
copyName = copyName + " " + getWorkingCopyLabel();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
copyName = getWorkingCopyLabel();
|
|
}
|
|
}
|
|
|
|
// Make the working copy
|
|
destinationAssocQName = QName.createQName(destinationAssocQName.getNamespaceURI(), QName.createValidLocalName(copyName));
|
|
NodeRef workingCopy = this.copyService.copy(
|
|
nodeRef,
|
|
destinationParentNodeRef,
|
|
destinationAssocTypeQName,
|
|
destinationAssocQName);
|
|
|
|
// Update the working copy name
|
|
this.nodeService.setProperty(workingCopy, ContentModel.PROP_NAME, copyName);
|
|
|
|
// Get the user
|
|
String userName = getUserName();
|
|
|
|
// Apply the working copy aspect to the working copy
|
|
Map<QName, Serializable> workingCopyProperties = new HashMap<QName, Serializable>(1);
|
|
workingCopyProperties.put(ContentModel.PROP_WORKING_COPY_OWNER, userName);
|
|
this.nodeService.addAspect(workingCopy, ContentModel.ASPECT_WORKING_COPY, workingCopyProperties);
|
|
|
|
// Apply the sys:temporary aspect to tag the working copy as a temporary node
|
|
// so it doesn't get archived when checked in
|
|
this.nodeService.addAspect(workingCopy, ContentModel.ASPECT_TEMPORARY, null);
|
|
|
|
// Lock the origional node
|
|
this.lockService.lock(nodeRef, LockType.READ_ONLY_LOCK);
|
|
|
|
// Return the working copy
|
|
return workingCopy;
|
|
}
|
|
|
|
/**
|
|
* Gets the authenticated users node reference
|
|
*
|
|
* @return the users node reference
|
|
*/
|
|
private String getUserName()
|
|
{
|
|
String un = this.authenticationService.getCurrentUserName();
|
|
if (un != null)
|
|
{
|
|
return un;
|
|
}
|
|
else
|
|
{
|
|
throw new CheckOutCheckInServiceException(MSG_ERR_NOT_AUTHENTICATED);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @see org.alfresco.service.cmr.coci.CheckOutCheckInService#checkout(org.alfresco.service.cmr.repository.NodeRef)
|
|
*/
|
|
public NodeRef checkout(NodeRef nodeRef)
|
|
{
|
|
// Find the primary parent in order to determine where to put the copy
|
|
ChildAssociationRef childAssocRef = this.nodeService.getPrimaryParent(nodeRef);
|
|
|
|
// Checkout the working copy to the same destination
|
|
return checkout(nodeRef, childAssocRef.getParentRef(), childAssocRef.getTypeQName(), childAssocRef.getQName());
|
|
}
|
|
|
|
/**
|
|
* @see org.alfresco.repo.version.operations.VersionOperationsService#checkin(org.alfresco.repo.ref.NodeRef, Map<String,Serializable>, java.lang.String, boolean)
|
|
*/
|
|
public NodeRef checkin(
|
|
NodeRef workingCopyNodeRef,
|
|
Map<String,Serializable> versionProperties,
|
|
String contentUrl,
|
|
boolean keepCheckedOut)
|
|
{
|
|
NodeRef nodeRef = null;
|
|
|
|
// Check that we have been handed a working copy
|
|
if (this.nodeService.hasAspect(workingCopyNodeRef, ContentModel.ASPECT_WORKING_COPY) == false)
|
|
{
|
|
// Error since we have not been passed a working copy
|
|
throw new AspectMissingException(ContentModel.ASPECT_WORKING_COPY, workingCopyNodeRef);
|
|
}
|
|
|
|
// Check that the working node still has the copy aspect applied
|
|
if (this.nodeService.hasAspect(workingCopyNodeRef, ContentModel.ASPECT_COPIEDFROM) == true)
|
|
{
|
|
// Disable versionable behaviours since we don't want the auto version policy behaviour to execute when we check-in
|
|
//this.versionableAspect.disableAutoVersion();
|
|
//try
|
|
//{
|
|
Map<QName, Serializable> workingCopyProperties = nodeService.getProperties(workingCopyNodeRef);
|
|
// Try and get the original node reference
|
|
nodeRef = (NodeRef) workingCopyProperties.get(ContentModel.PROP_COPY_REFERENCE);
|
|
if(nodeRef == null)
|
|
{
|
|
// Error since the original node can not be found
|
|
throw new CheckOutCheckInServiceException(MSG_ERR_BAD_COPY);
|
|
}
|
|
|
|
try
|
|
{
|
|
// Release the lock
|
|
this.lockService.unlock(nodeRef);
|
|
}
|
|
catch (UnableToReleaseLockException exception)
|
|
{
|
|
throw new CheckOutCheckInServiceException(MSG_ERR_NOT_OWNER, exception);
|
|
}
|
|
|
|
if (contentUrl != null)
|
|
{
|
|
ContentData contentData = (ContentData) workingCopyProperties.get(ContentModel.PROP_CONTENT);
|
|
if (contentData == null)
|
|
{
|
|
throw new AlfrescoRuntimeException(MSG_ERR_WORKINGCOPY_HAS_NO_MIMETYPE, new Object[]{workingCopyNodeRef});
|
|
}
|
|
else
|
|
{
|
|
contentData = new ContentData(
|
|
contentUrl,
|
|
contentData.getMimetype(),
|
|
contentData.getSize(),
|
|
contentData.getEncoding());
|
|
}
|
|
// Set the content url value onto the working copy
|
|
this.nodeService.setProperty(
|
|
workingCopyNodeRef,
|
|
ContentModel.PROP_CONTENT,
|
|
contentData);
|
|
}
|
|
|
|
// Copy the contents of the working copy onto the original
|
|
this.copyService.copy(workingCopyNodeRef, nodeRef);
|
|
|
|
if (versionProperties != null && this.nodeService.hasAspect(nodeRef, ContentModel.ASPECT_VERSIONABLE) == true)
|
|
{
|
|
// Create the new version
|
|
this.versionService.createVersion(nodeRef, versionProperties);
|
|
}
|
|
|
|
if (keepCheckedOut == false)
|
|
{
|
|
// Delete the working copy
|
|
this.nodeService.removeAspect(workingCopyNodeRef, ContentModel.ASPECT_WORKING_COPY);
|
|
this.nodeService.deleteNode(workingCopyNodeRef);
|
|
}
|
|
else
|
|
{
|
|
// Re-lock the original node
|
|
this.lockService.lock(nodeRef, LockType.READ_ONLY_LOCK);
|
|
}
|
|
//}
|
|
//finally
|
|
//{
|
|
// this.versionableAspect.enableAutoVersion();
|
|
//}
|
|
|
|
}
|
|
else
|
|
{
|
|
// Error since the copy aspect is missing
|
|
throw new AspectMissingException(ContentModel.ASPECT_COPIEDFROM, workingCopyNodeRef);
|
|
}
|
|
|
|
return nodeRef;
|
|
}
|
|
|
|
/**
|
|
* @see org.alfresco.service.cmr.coci.CheckOutCheckInService#checkin(org.alfresco.service.cmr.repository.NodeRef, Map, java.lang.String)
|
|
*/
|
|
public NodeRef checkin(
|
|
NodeRef workingCopyNodeRef,
|
|
Map<String, Serializable> versionProperties,
|
|
String contentUrl)
|
|
{
|
|
return checkin(workingCopyNodeRef, versionProperties, contentUrl, false);
|
|
}
|
|
|
|
/**
|
|
* @see org.alfresco.service.cmr.coci.CheckOutCheckInService#checkin(org.alfresco.service.cmr.repository.NodeRef, Map)
|
|
*/
|
|
public NodeRef checkin(
|
|
NodeRef workingCopyNodeRef,
|
|
Map<String, Serializable> versionProperties)
|
|
{
|
|
return checkin(workingCopyNodeRef, versionProperties, null, false);
|
|
}
|
|
|
|
/**
|
|
* @see org.alfresco.service.cmr.coci.CheckOutCheckInService#cancelCheckout(org.alfresco.service.cmr.repository.NodeRef)
|
|
*/
|
|
public NodeRef cancelCheckout(NodeRef workingCopyNodeRef)
|
|
{
|
|
NodeRef nodeRef = null;
|
|
|
|
// Check that we have been handed a working copy
|
|
if (this.nodeService.hasAspect(workingCopyNodeRef, ContentModel.ASPECT_WORKING_COPY) == false)
|
|
{
|
|
// Error since we have not been passed a working copy
|
|
throw new AspectMissingException(ContentModel.ASPECT_WORKING_COPY, workingCopyNodeRef);
|
|
}
|
|
|
|
// Ensure that the node has the copy aspect
|
|
if (this.nodeService.hasAspect(workingCopyNodeRef, ContentModel.ASPECT_COPIEDFROM) == true)
|
|
{
|
|
// Get the original node
|
|
nodeRef = (NodeRef)this.nodeService.getProperty(workingCopyNodeRef, ContentModel.PROP_COPY_REFERENCE);
|
|
if (nodeRef == null)
|
|
{
|
|
// Error since the original node can not be found
|
|
throw new CheckOutCheckInServiceException(MSG_ERR_BAD_COPY);
|
|
}
|
|
|
|
// Release the lock on the original node
|
|
this.lockService.unlock(nodeRef);
|
|
|
|
// Delete the working copy
|
|
this.nodeService.removeAspect(workingCopyNodeRef, ContentModel.ASPECT_WORKING_COPY);
|
|
this.nodeService.deleteNode(workingCopyNodeRef);
|
|
}
|
|
else
|
|
{
|
|
// Error since the copy aspect is missing
|
|
throw new AspectMissingException(ContentModel.ASPECT_COPIEDFROM, workingCopyNodeRef);
|
|
}
|
|
|
|
return nodeRef;
|
|
}
|
|
|
|
/**
|
|
* @see org.alfresco.service.cmr.coci.CheckOutCheckInService#getWorkingCopy(org.alfresco.service.cmr.repository.NodeRef)
|
|
*/
|
|
public NodeRef getWorkingCopy(NodeRef nodeRef)
|
|
{
|
|
NodeRef workingCopy = null;
|
|
|
|
// Do a search to find the working copy document
|
|
ResultSet resultSet = null;
|
|
|
|
try
|
|
{
|
|
resultSet = this.searchService.query(
|
|
nodeRef.getStoreRef(),
|
|
SearchService.LANGUAGE_LUCENE,
|
|
"ASPECT:\"" + ContentModel.ASPECT_WORKING_COPY.toString() + "\" +@\\{http\\://www.alfresco.org/model/content/1.0\\}" + ContentModel.PROP_COPY_REFERENCE.getLocalName() + ":\"" + nodeRef.toString() + "\"");
|
|
if (resultSet.getNodeRefs().size() != 0)
|
|
{
|
|
workingCopy = resultSet.getNodeRef(0);
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
if (resultSet != null)
|
|
{
|
|
resultSet.close();
|
|
}
|
|
}
|
|
|
|
return workingCopy;
|
|
}
|
|
}
|