RM-2045 Create Java API to classify a document.

Create dedicated objects to handle queries against the list of configured
classification levels and reasons.

+review RM-25

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/modules/recordsmanagement/HEAD@101986 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Tom Page
2015-04-16 10:07:07 +00:00
parent f67f5e66e7
commit 19596e3484
9 changed files with 400 additions and 27 deletions

View File

@@ -0,0 +1,76 @@
/*
* 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 java.util.List;
import com.google.common.collect.ImmutableList;
import org.alfresco.module.org_alfresco_module_rm.classification.ClassificationServiceException.LevelIdNotFound;
/**
* Container for the configured {@link ClassificationLevel} objects.
*
* @author tpage
*/
public class ClassificationLevelManager
{
/** An immutable list of classification levels ordered from most to least secure. */
private ImmutableList<ClassificationLevel> classificationLevels;
/**
* Constructor that stores an immutable copy of the given levels.
*
* @param classificationLevels A list of classification levels ordered from most to least secure.
*/
public ClassificationLevelManager(List<ClassificationLevel> classificationLevels)
{
this.classificationLevels = ImmutableList.copyOf(classificationLevels);
}
/** @return the highest security classification level. */
public ClassificationLevel getMostSecureLevel()
{
return classificationLevels.get(0);
}
/** @return An immutable list of classification levels ordered from most to least secure. */
public ImmutableList<ClassificationLevel> getClassificationLevels()
{
return classificationLevels;
}
/**
* Get a <code>ClassificationLevel</code> using its id.
*
* @param id The id of a classification level.
* @return The classification level.
* @throws LevelIdNotFound If the classification level cannot be found.
*/
public ClassificationLevel findLevelById(String id) throws LevelIdNotFound
{
for (ClassificationLevel classificationLevel : classificationLevels)
{
if (classificationLevel.getId().equals(id))
{
return classificationLevel;
}
}
throw new LevelIdNotFound(id);
}
}

View File

@@ -0,0 +1,70 @@
/*
* 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 java.util.Collection;
import com.google.common.collect.ImmutableList;
import org.alfresco.module.org_alfresco_module_rm.classification.ClassificationServiceException.ReasonIdNotFound;
/**
* Container for the configured {@link ClassificationReason} objects.
*
* @author tpage
*/
public class ClassificationReasonManager
{
/** An immutable list of classification reasons. */
private ImmutableList<ClassificationReason> classificationReasons;
/**
* Constructor that stores an immutable copy of the given reasons.
*
* @param classificationReasons The classification reasons.
*/
public ClassificationReasonManager(Collection<ClassificationReason> classificationReasons)
{
this.classificationReasons = ImmutableList.copyOf(classificationReasons);
}
/** @return An immutable list of classification reasons. */
public ImmutableList<ClassificationReason> getClassificationReasons()
{
return classificationReasons;
}
/**
* Get a <code>ClassificationReason</code> using its id.
*
* @param id The id of a classification reason.
* @return The classification reason.
* @throws ReasonIdNotFound If the classification reason cannot be found.
*/
public ClassificationReason findReasonById(String id) throws ReasonIdNotFound
{
for (ClassificationReason classificationReason : classificationReasons)
{
if (classificationReason.getId().equals(id))
{
return classificationReason;
}
}
throw new ReasonIdNotFound(id);
}
}

View File

@@ -21,6 +21,8 @@ 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.ClassificationServiceException.LevelIdNotFound;
import org.alfresco.module.org_alfresco_module_rm.classification.ClassificationServiceException.ReasonIdNotFound;
import org.alfresco.service.cmr.repository.NodeRef;
/**
@@ -50,11 +52,13 @@ public interface ClassificationService
/**
* Classify a document.
*
* @param classificationLevel The security clearance needed to access the document.
* @param classificationLevelId The security clearance needed to access the document.
* @param classificationAuthority The name of the authority responsible for the classification of this document.
* @param classificationReasons A non-empty set of reasons for classifying the document in this way.
* @param classificationReasonIds A non-empty set of ids of reasons for classifying the document in this way.
* @param document The node to classify.
* @throws LevelIdNotFound If the supplied level id is not found.
* @throws ReasonIdNotFound If any of the supplied reason ids are not found.
*/
void addClassificationToDocument(ClassificationLevel classificationLevel, String classificationAuthority,
Set<ClassificationReason> classificationReasons, NodeRef document);
void addClassificationToDocument(String classificationLevelId, String classificationAuthority,
Set<String> classificationReasonIds, NodeRef document) throws LevelIdNotFound, ReasonIdNotFound;
}

View File

@@ -59,8 +59,32 @@ public class ClassificationServiceException extends AlfrescoRuntimeException
{
/** serial version uid */
private static final long serialVersionUID = 8191162359241035026L;
public MalformedConfiguration(String msgId) { super(msgId); }
public MalformedConfiguration(String msgId, Throwable cause) { super(msgId, cause); }
}
/** The supplied classification level id was not found in the configured list. */
public static class LevelIdNotFound extends ClassificationServiceException
{
/** serial version uid */
private static final long serialVersionUID = -8507186704795004383L;
public LevelIdNotFound(String levelId)
{
super("Could not find classification level with id " + levelId);
}
}
/** The supplied classification reason id was not found in the configured list. */
public static class ReasonIdNotFound extends ClassificationServiceException
{
/** serial version uid */
private static final long serialVersionUID = -643842413653375433L;
public ReasonIdNotFound(String reasonId)
{
super("Could not find classification reason with id " + reasonId);
}
}
}

View File

@@ -20,14 +20,22 @@ package org.alfresco.module.org_alfresco_module_rm.classification;
import java.io.Serializable;
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.module.org_alfresco_module_rm.classification.ClassificationServiceException.LevelIdNotFound;
import org.alfresco.module.org_alfresco_module_rm.classification.ClassificationServiceException.MissingConfiguration;
import org.alfresco.module.org_alfresco_module_rm.classification.ClassificationServiceException.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.repo.security.authentication.AuthenticationUtil;
import org.alfresco.service.cmr.attributes.AttributeService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.namespace.QName;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -36,7 +44,7 @@ import org.slf4j.LoggerFactory;
* @since 3.0
*/
public class ClassificationServiceImpl extends ServiceBaseImpl
implements ClassificationService
implements ClassificationService, ClassifiedContentModel
{
private static final Serializable[] LEVELS_KEY = new String[] { "org.alfresco",
"module.org_alfresco_module_rm",
@@ -47,14 +55,16 @@ public class ClassificationServiceImpl extends ServiceBaseImpl
private static final Logger LOGGER = LoggerFactory.getLogger(ClassificationServiceImpl.class);
private AttributeService attributeService; // TODO What about other code (e.g. REST API) accessing the AttrService?
private NodeService nodeService;
private ClassificationServiceDAO classificationServiceDao;
/** The classification levels currently configured in this server. */
private List<ClassificationLevel> configuredLevels;
private ClassificationLevelManager levelManager;
/** The classification reasons currently configured in this server. */
private List<ClassificationReason> configuredReasons;
private ClassificationReasonManager reasonManager;
public void setAttributeService(AttributeService service) { this.attributeService = service; }
public void setNodeService(NodeService service) { this.nodeService = service; }
/** Set the object from which configuration options will be read. */
public void setClassificationServiceDAO(ClassificationServiceDAO classificationServiceDao) { this.classificationServiceDao = classificationServiceDao; }
@@ -75,11 +85,11 @@ public class ClassificationServiceImpl extends ServiceBaseImpl
else if (!configurationLevels.equals(allPersistedLevels))
{
attributeService.setAttribute((Serializable) configurationLevels, LEVELS_KEY);
this.configuredLevels = configurationLevels;
this.levelManager = new ClassificationLevelManager(configurationLevels);
}
else
{
this.configuredLevels = allPersistedLevels;
this.levelManager = new ClassificationLevelManager(allPersistedLevels);
}
}
@@ -99,7 +109,7 @@ public class ClassificationServiceImpl extends ServiceBaseImpl
throw new MissingConfiguration("Classification reason configuration is missing.");
}
attributeService.setAttribute((Serializable) classpathReasons, REASONS_KEY);
this.configuredReasons = classpathReasons;
this.reasonManager = new ClassificationReasonManager(classpathReasons);
}
else
{
@@ -109,7 +119,7 @@ public class ClassificationServiceImpl extends ServiceBaseImpl
+ "Alfresco will use the unchanged values stored in the database.");
// RM-2073 says that we should log a warning and proceed normally.
}
this.configuredReasons = persistedReasons;
this.reasonManager = new ClassificationReasonManager(persistedReasons);
}
}
@@ -188,25 +198,41 @@ public class ClassificationServiceImpl extends ServiceBaseImpl
@Override
public List<ClassificationLevel> getClassificationLevels()
{
if (configuredLevels == null)
if (levelManager == null)
{
return Collections.emptyList();
}
// FIXME Currently assume user has highest security clearance, this should be fixed as part of RM-2112.
ClassificationLevel usersLevel = configuredLevels.get(0);
return restrictList(configuredLevels, usersLevel);
ClassificationLevel usersLevel = levelManager.getMostSecureLevel();
return restrictList(levelManager.getClassificationLevels(), usersLevel);
}
@Override public List<ClassificationReason> getClassificationReasons()
{
return configuredReasons == null ? Collections.<ClassificationReason>emptyList() :
Collections.unmodifiableList(configuredReasons);
return reasonManager == null ? Collections.<ClassificationReason>emptyList() :
Collections.unmodifiableList(reasonManager.getClassificationReasons());
}
@Override
public void addClassificationToDocument(ClassificationLevel classificationLevel, String classificationAuthority,
Set<ClassificationReason> classificationReasons, NodeRef document)
public void addClassificationToDocument(String classificationLevelId, String classificationAuthority,
Set<String> classificationReasonIds, NodeRef document) throws LevelIdNotFound, ReasonIdNotFound
{
// TODO
Map<QName, Serializable> properties = new HashMap<QName, Serializable>();
ClassificationLevel classificationLevel = levelManager.findLevelById(classificationLevelId);
properties.put(PROP_INITIAL_CLASSIFICATION, classificationLevel);
properties.put(PROP_CURRENT_CLASSIFICATION, classificationLevel);
properties.put(PROP_CLASSIFICATION_AUTHORITY, classificationAuthority);
HashSet<ClassificationReason> classificationReasons = new HashSet<>();
for (String classificationReasonId : classificationReasonIds)
{
ClassificationReason classificationReason = reasonManager.findReasonById(classificationReasonId);
classificationReasons.add(classificationReason);
}
properties.put(PROP_CLASSIFICATION_REASONS, classificationReasons);
nodeService.addAspect(document, ASPECT_CLASSIFIED, properties);
}
}