/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* -
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
* -
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* -
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
* -
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.module.org_alfresco_module_rm.model.rma.aspect;
import java.io.Serializable;
import java.util.Map;
import org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService;
import org.alfresco.module.org_alfresco_module_rm.identifier.IdentifierService;
import org.alfresco.module.org_alfresco_module_rm.model.BaseBehaviourBean;
import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel;
import org.alfresco.repo.copy.CopyBehaviourCallback;
import org.alfresco.repo.copy.CopyDetails;
import org.alfresco.repo.copy.CopyServicePolicies;
import org.alfresco.repo.copy.DoNothingCopyBehaviourCallback;
import org.alfresco.repo.node.NodeServicePolicies;
import org.alfresco.repo.node.integrity.IntegrityException;
import org.alfresco.repo.policy.Behaviour.NotificationFrequency;
import org.alfresco.repo.policy.annotation.Behaviour;
import org.alfresco.repo.policy.annotation.BehaviourBean;
import org.alfresco.repo.policy.annotation.BehaviourKind;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
import org.alfresco.service.cmr.attributes.AttributeService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.QName;
import org.springframework.extensions.surf.util.I18NUtil;
/**
* rma:recordComponentIdentifier behaviour bean
*
* @author Roy Wetherall
* @since 2.2
*/
@BehaviourBean
(
defaultType = "rma:recordComponentIdentifier"
)
public class RecordComponentIdentifierAspect extends BaseBehaviourBean
implements NodeServicePolicies.OnUpdatePropertiesPolicy,
NodeServicePolicies.BeforeDeleteNodePolicy,
CopyServicePolicies.OnCopyCompletePolicy
{
/** I18N */
private static final String MSG_SET_ID = "rm.service.set-id";
/** attribute context value */
private static final String CONTEXT_VALUE = "rma:identifier";
/** file plan service */
private FilePlanService filePlanService;
/** attribute service */
private AttributeService attributeService;
/** identifier service */
private IdentifierService identifierService;
/**
* @param filePlanService file plan service
*/
public void setFilePlanService(FilePlanService filePlanService)
{
this.filePlanService = filePlanService;
}
/**
* @param attributeService attribute service
*/
public void setAttributeService(AttributeService attributeService)
{
this.attributeService = attributeService;
}
/**
* @param identifierService identifier service
*/
public void setIdentifierService(IdentifierService identifierService)
{
this.identifierService = identifierService;
}
/**
* Ensures that the {@link RecordsManagementModel#PROP_IDENTIFIER rma:identifier} property remains
* unique within the context of the parent node.
*
* @see org.alfresco.repo.node.NodeServicePolicies.OnUpdatePropertiesPolicy#onUpdateProperties(org.alfresco.service.cmr.repository.NodeRef, java.util.Map, java.util.Map)
*/
@Override
@Behaviour
(
kind = BehaviourKind.CLASS,
notificationFrequency = NotificationFrequency.EVERY_EVENT
)
public void onUpdateProperties(final NodeRef nodeRef, final Map<QName, Serializable> before, final Map<QName, Serializable> after)
{
AuthenticationUtil.runAs(new RunAsWork<Object>()
{
public Object doWork()
{
String newIdValue = (String)after.get(PROP_IDENTIFIER);
if (newIdValue != null)
{
String oldIdValue = (String)before.get(PROP_IDENTIFIER);
if (oldIdValue != null && !oldIdValue.equals(newIdValue))
{
throw new IntegrityException(I18NUtil.getMessage(MSG_SET_ID, nodeRef.toString()), null);
}
// update uniqueness
updateUniqueness(nodeRef, oldIdValue, newIdValue);
}
return null;
}
}, AuthenticationUtil.getSystemUserName());
}
/**
* Cleans up the {@link RecordsManagementModel#PROP_IDENTIFIER rma:identifier} property unique triplet.
*
* @see org.alfresco.repo.node.NodeServicePolicies.BeforeDeleteNodePolicy#beforeDeleteNode(org.alfresco.service.cmr.repository.NodeRef)
*/
@Override
@Behaviour
(
kind = BehaviourKind.CLASS,
notificationFrequency = NotificationFrequency.EVERY_EVENT
)
public void beforeDeleteNode(final NodeRef nodeRef)
{
AuthenticationUtil.runAs(new RunAsWork<Object>()
{
public Object doWork()
{
String beforeId = (String) nodeService.getProperty(nodeRef, PROP_IDENTIFIER);
updateUniqueness(nodeRef, beforeId, null);
return null;
}
}, AuthenticationUtil.getSystemUserName());
}
/**
* Record component identifier aspect copy callback
*/
@Behaviour
(
kind = BehaviourKind.CLASS,
policy = "alf:getCopyCallback"
)
public CopyBehaviourCallback getCopyCallback(QName classRef, CopyDetails copyDetails)
{
return new DoNothingCopyBehaviourCallback();
}
@SuppressWarnings("rawtypes")
@Override
@Behaviour
(
kind = BehaviourKind.CLASS,
notificationFrequency = NotificationFrequency.TRANSACTION_COMMIT
)
public void onCopyComplete(QName classRef, NodeRef sourceNodeRef, NodeRef targetNodeRef, boolean copyToNewNode, Map copyMap)
{
//Generate the id for the copy
String id = identifierService.generateIdentifier(
nodeService.getType(nodeService.getPrimaryParent(targetNodeRef).getParentRef()),
nodeService.getPrimaryParent(targetNodeRef).getParentRef());
//We need to allow the id to be overwritten disable the policy protecting changes to the id
behaviourFilter.disableBehaviour();
try
{
nodeService.setProperty(targetNodeRef, PROP_IDENTIFIER, id);
}
finally
{
behaviourFilter.enableBehaviour();
}
}
/**
* Updates the uniqueness check using the values provided. If the after value is <tt>null</tt>
* then this is considered to be a removal.
*
* @param nodeRef node reference
* @param beforeId id before
* @param afterId id after
*/
private void updateUniqueness(NodeRef nodeRef, String beforeId, String afterId)
{
NodeRef contextNodeRef = filePlanService.getFilePlan(nodeRef);
if (beforeId == null)
{
if (afterId != null)
{
// Just create it
attributeService.createAttribute(null, CONTEXT_VALUE, contextNodeRef, afterId);
}
}
else if (afterId == null)
{
// The before value was not null, so remove it
attributeService.removeAttribute(CONTEXT_VALUE, contextNodeRef, beforeId);
// Do a blanket removal in case this is a contextual nodes
attributeService.removeAttributes(CONTEXT_VALUE, nodeRef);
}
else
{
// This is a full update
attributeService.updateOrCreateAttribute(
CONTEXT_VALUE, contextNodeRef, beforeId,
CONTEXT_VALUE, contextNodeRef, afterId);
}
}
}