Work that's part of RM-2431 and RM-2432.

Added to the classified-content-model - various properties as described in RM-2431 along with a constraint on Reclassification Action.
Addition to the ClassificationSchemeService of methods and types associated with Reclassification. (Upgrade, Downgrade, Declassify). See RM-2432.
Behaviour bean that will automatically set lastReclassificationAction and lastReclassifyBy in response to any change to currentClassificationLevel.
Also some util methods in RMCollections.
Fixed some spelling mistakes in classification-related properties.



git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/modules/recordsmanagement/HEAD@108878 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Neil McErlean
2015-07-23 16:13:43 +00:00
parent 9d5fb95ced
commit ebc34f9209
11 changed files with 354 additions and 6 deletions

View File

@@ -28,4 +28,5 @@ import java.io.Serializable;
*/
public interface ClassificationSchemeEntity extends Serializable
{
// Intentionally empty
}

View File

@@ -19,6 +19,7 @@
package org.alfresco.module.org_alfresco_module_rm.classification;
import java.util.List;
import java.util.Set;
import org.alfresco.module.org_alfresco_module_rm.classification.ClassificationException.LevelIdNotFound;
import org.alfresco.module.org_alfresco_module_rm.classification.ClassificationException.ReasonIdNotFound;
@@ -78,4 +79,31 @@ public interface ClassificationSchemeService
* @return The exemption categories in the order that they are defined.
*/
List<ExemptionCategory> getExemptionCategories();
/**
* Identifies the reclassification type for the provided pair of {@link ClassificationLevel levels}.
*
* @param from the first classification level.
* @param to the second classification level.
* @return the reclassification represented by this change, or {@code null} if it is not a change.
*/
Reclassification getReclassification(ClassificationLevel from, ClassificationLevel to);
Set<String> getReclassificationValues();
/** Types of reclassification. */
enum Reclassification
{
UPGRADE, DOWNGRADE, DECLASSIFY;
/** Returns the name of this enum value in a format suitable for storage in the Alfresco repo. */
public String toModelString()
{
final String name = toString();
final StringBuilder result = new StringBuilder(name.length());
result.append(name.charAt(0))
.append(name.substring(1).toLowerCase());
return result.toString();
}
}
}

View File

@@ -18,16 +18,21 @@
*/
package org.alfresco.module.org_alfresco_module_rm.classification;
import static java.util.Collections.unmodifiableSet;
import static org.alfresco.module.org_alfresco_module_rm.util.RMParameterCheck.checkNotBlank;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.alfresco.module.org_alfresco_module_rm.classification.ClassificationException.LevelIdNotFound;
import org.alfresco.module.org_alfresco_module_rm.classification.ClassificationException.ReasonIdNotFound;
import org.alfresco.module.org_alfresco_module_rm.classification.model.ClassifiedContentModel;
import org.alfresco.module.org_alfresco_module_rm.util.ServiceBaseImpl;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.util.ParameterCheck;
/**
* @author Neil Mc Erlean
@@ -122,4 +127,39 @@ public class ClassificationSchemeServiceImpl extends ServiceBaseImpl implements
return (exemptionCategoryManager == null ? Collections.<ExemptionCategory>emptyList() :
Collections.unmodifiableList(exemptionCategoryManager.getExemptionCategories()));
}
@Override
public Reclassification getReclassification(ClassificationLevel from, ClassificationLevel to)
{
ParameterCheck.mandatory("from", from);
ParameterCheck.mandatory("to", to);
final List<ClassificationLevel> levels = getClassificationLevels();
final int fromIndex = levels.indexOf(from);
final int toIndex = levels.indexOf(to);
final int lastIndex = levels.size() - 1;
if (from.equals(to))
{ return null; }
else if (fromIndex < lastIndex && toIndex == lastIndex)
{
return Reclassification.DECLASSIFY;
}
else
{
return fromIndex < toIndex ? Reclassification.DOWNGRADE : Reclassification.UPGRADE;
}
}
@Override
public Set<String> getReclassificationValues()
{
Set<String> result = new HashSet<>();
for (Reclassification r : Reclassification.values())
{
result.add(r.toModelString());
}
return unmodifiableSet(result);
}
}

View File

@@ -44,8 +44,8 @@ import org.alfresco.service.namespace.QName;
*
* @author tpage
*/
public class ContentClassificationServiceImpl extends ServiceBaseImpl implements ContentClassificationService,
ClassifiedContentModel
public class ContentClassificationServiceImpl extends ServiceBaseImpl
implements ContentClassificationService, ClassifiedContentModel
{
private ClassificationLevelManager levelManager;
private ClassificationReasonManager reasonManager;

View File

@@ -0,0 +1,47 @@
/*
* Copyright (C) 2005-2015 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* 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/>.
*/
package org.alfresco.module.org_alfresco_module_rm.classification;
import static java.util.Collections.unmodifiableList;
import org.alfresco.module.org_alfresco_module_rm.classification.model.ClassifiedContentModel;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
/**
* Check that a {@link ClassifiedContentModel#PROP_LAST_RECLASSIFICATION_ACTION reclassifiction action }value is valid.
*
* @author Neil Mc Erlean
* @since 3.0.a
*/
public class ReclassificationValueConstraint extends ClassificationSchemeEntityConstraint
{
@Override
protected List<String> getAllowedValues()
{
final Set<String> resultSet = classificationSchemeService.getReclassificationValues();
List<String> result = new ArrayList<>(resultSet.size());
result.addAll(resultSet);
return unmodifiableList(result);
}
}

View File

@@ -54,6 +54,15 @@ public interface ClassifiedContentModel
QName PROP_DECLASSIFICATION_EVENT = QName.createQName(CLF_URI, "declassificationEvent");
QName PROP_DECLASSIFICATION_EXEMPTIONS = QName.createQName(CLF_URI, "declassificationExemptions");
QName PROP_LAST_RECLASSIFY_BY = QName.createQName(CLF_URI, "lastReclassifyBy");
QName PROP_LAST_RECLASSIFY_AT = QName.createQName(CLF_URI, "lastReclassifyAt");
QName PROP_LAST_RECLASSIFY_REASON = QName.createQName(CLF_URI, "lastReclassifyReason");
QName PROP_LAST_RECLASSIFICATION_ACTION = QName.createQName(CLF_URI, "lastReclassificationAction");
/** Reclassification allowed values. */
String RECLASSIFICATION_UPGRADE = "UPGRADE";
String RECLASSIFICATION_DOWNGRADE = "DOWNGRADE";
String RECLASSIFICATION_DECLASSIFY = "DECLASSIFY";
/** Security Clearance aspect. */
QName ASPECT_SECURITY_CLEARANCE = QName.createQName(CLF_URI, "securityClearance");
QName PROP_CLEARANCE_LEVEL = QName.createQName(CLF_URI, "clearanceLevel");

View File

@@ -0,0 +1,107 @@
/*
* Copyright (C) 2005-2015 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* 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/>.
*/
package org.alfresco.module.org_alfresco_module_rm.model.clf.aspect;
import static org.alfresco.module.org_alfresco_module_rm.classification.ClassificationSchemeService.Reclassification;
import static org.alfresco.module.org_alfresco_module_rm.classification.model.ClassifiedContentModel.ASPECT_CLASSIFIED;
import static org.alfresco.module.org_alfresco_module_rm.classification.model.ClassifiedContentModel.PROP_CURRENT_CLASSIFICATION;
import static org.alfresco.module.org_alfresco_module_rm.classification.model.ClassifiedContentModel.PROP_LAST_RECLASSIFICATION_ACTION;
import static org.alfresco.module.org_alfresco_module_rm.classification.model.ClassifiedContentModel.PROP_LAST_RECLASSIFY_AT;
import static org.alfresco.module.org_alfresco_module_rm.util.RMCollectionUtils.Difference;
import static org.alfresco.module.org_alfresco_module_rm.util.RMCollectionUtils.diffKey;
import org.alfresco.module.org_alfresco_module_rm.classification.ClassificationLevel;
import org.alfresco.module.org_alfresco_module_rm.classification.ClassificationSchemeService;
import org.alfresco.module.org_alfresco_module_rm.classification.model.ClassifiedContentModel;
import org.alfresco.module.org_alfresco_module_rm.model.BaseBehaviourBean;
import org.alfresco.repo.node.NodeServicePolicies;
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.repository.NodeRef;
import org.alfresco.service.namespace.QName;
import java.io.Serializable;
import java.util.Date;
import java.util.Map;
/**
* clf:classification behaviour bean
*
* @since 3.0.a
*/
@BehaviourBean
(
defaultType = "clf:classified"
)
public class ClassifiedAspect extends BaseBehaviourBean
implements NodeServicePolicies.OnUpdatePropertiesPolicy
{
private ClassificationSchemeService classificationSchemeService;
public void setClassificationSchemeService(ClassificationSchemeService service)
{
this.classificationSchemeService = service;
}
/**
* Ensures that on reclassification of content (in other words a change in the value of the
* {@link ClassifiedContentModel#PROP_CURRENT_CLASSIFICATION clf:currentClassification} property)
* that various metadata are correctly updated as a side-effect.
*/
@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<Void>()
{
public Void doWork()
{
final Difference classificationChange = diffKey(before, after, PROP_CURRENT_CLASSIFICATION);
if (classificationChange == Difference.CHANGED && nodeService.hasAspect(nodeRef, ASPECT_CLASSIFIED))
{
final String oldValue = (String)before.get(PROP_CURRENT_CLASSIFICATION);
final String newValue = (String)after.get(PROP_CURRENT_CLASSIFICATION);
final ClassificationLevel oldLevel = classificationSchemeService.getClassificationLevelById(oldValue);
final ClassificationLevel newLevel = classificationSchemeService.getClassificationLevelById(newValue);
Reclassification reclassification = classificationSchemeService.getReclassification(oldLevel, newLevel);
if (reclassification != null)
{
nodeService.setProperty(nodeRef, PROP_LAST_RECLASSIFICATION_ACTION, reclassification.toModelString());
nodeService.setProperty(nodeRef, PROP_LAST_RECLASSIFY_AT, new Date());
}
}
return null;
}
}, AuthenticationUtil.getSystemUserName());
}
}

View File

@@ -18,13 +18,17 @@
*/
package org.alfresco.module.org_alfresco_module_rm.util;
import static org.springframework.util.ObjectUtils.nullSafeEquals;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Various common helper methods for Collections.
* Various common helper methods for Collections. This class is probably only appropriate for use with relatively
* small collections as it has not been optimised for dealing with large collections.
*
* @author Neil Mc Erlean
* @since 3.0
@@ -58,4 +62,45 @@ public final class RMCollectionUtils
}
return duplicateElems;
}
/**
* This enum represents a change in an entry between 2 collections.
*/
public enum Difference
{
ADDED, REMOVED, CHANGED, UNCHANGED
}
/**
* Determines the change in a Map entry between two Maps.
* Note that both maps must have the same types of key-value pair.
*
* @param from the first collection.
* @param to the second collection.
* @param key the key identifying the entry.
* @param <K> the type of the key.
* @param <V> the type of the value.
* @return the {@link Difference}.
*
* @throws IllegalArgumentException if {@code key} is {@code null}.
*/
public static <K, V> Difference diffKey(Map<K, V> from, Map<K, V> to, K key)
{
if (key == null) { throw new IllegalArgumentException("Key cannot be null."); }
if (from.containsKey(key))
{
if (to.containsKey(key))
{
if (nullSafeEquals(from.get(key), to.get(key))) { return Difference.UNCHANGED; }
else { return Difference.CHANGED; }
}
else { return Difference.REMOVED; }
}
else
{
if (to.containsKey(key)) { return Difference.ADDED; }
else { return Difference.UNCHANGED; }
}
}
}