diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/ClassificationLevelManager.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/ClassificationLevelManager.java
new file mode 100644
index 0000000000..cfef0dec6c
--- /dev/null
+++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/ClassificationLevelManager.java
@@ -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 .
+ */
+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 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 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 getClassificationLevels()
+ {
+ return classificationLevels;
+ }
+
+ /**
+ * Get a ClassificationLevel
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);
+ }
+}
diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/ClassificationReasonManager.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/ClassificationReasonManager.java
new file mode 100644
index 0000000000..76b19269e1
--- /dev/null
+++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/ClassificationReasonManager.java
@@ -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 .
+ */
+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 classificationReasons;
+
+ /**
+ * Constructor that stores an immutable copy of the given reasons.
+ *
+ * @param classificationReasons The classification reasons.
+ */
+ public ClassificationReasonManager(Collection classificationReasons)
+ {
+ this.classificationReasons = ImmutableList.copyOf(classificationReasons);
+ }
+
+ /** @return An immutable list of classification reasons. */
+ public ImmutableList getClassificationReasons()
+ {
+ return classificationReasons;
+ }
+
+ /**
+ * Get a ClassificationReason
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);
+ }
+}
diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/ClassificationService.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/ClassificationService.java
index bf5988b802..743bb0d1d7 100644
--- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/ClassificationService.java
+++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/ClassificationService.java
@@ -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 classificationReasons, NodeRef document);
+ void addClassificationToDocument(String classificationLevelId, String classificationAuthority,
+ Set classificationReasonIds, NodeRef document) throws LevelIdNotFound, ReasonIdNotFound;
}
diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/ClassificationServiceException.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/ClassificationServiceException.java
index b849327e77..30f75f8981 100644
--- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/ClassificationServiceException.java
+++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/ClassificationServiceException.java
@@ -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);
+ }
+ }
}
diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/ClassificationServiceImpl.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/ClassificationServiceImpl.java
index 00d97a0ac2..7eaa75cce0 100644
--- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/ClassificationServiceImpl.java
+++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/ClassificationServiceImpl.java
@@ -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 configuredLevels;
+ private ClassificationLevelManager levelManager;
/** The classification reasons currently configured in this server. */
- private List 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 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 getClassificationReasons()
{
- return configuredReasons == null ? Collections.emptyList() :
- Collections.unmodifiableList(configuredReasons);
+ return reasonManager == null ? Collections.emptyList() :
+ Collections.unmodifiableList(reasonManager.getClassificationReasons());
}
@Override
- public void addClassificationToDocument(ClassificationLevel classificationLevel, String classificationAuthority,
- Set classificationReasons, NodeRef document)
+ public void addClassificationToDocument(String classificationLevelId, String classificationAuthority,
+ Set classificationReasonIds, NodeRef document) throws LevelIdNotFound, ReasonIdNotFound
{
- // TODO
+ Map properties = new HashMap();
+
+ ClassificationLevel classificationLevel = levelManager.findLevelById(classificationLevelId);
+ properties.put(PROP_INITIAL_CLASSIFICATION, classificationLevel);
+ properties.put(PROP_CURRENT_CLASSIFICATION, classificationLevel);
+
+ properties.put(PROP_CLASSIFICATION_AUTHORITY, classificationAuthority);
+
+ HashSet 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);
}
}
diff --git a/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/classification/ClassificationLevelManagerUnitTest.java b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/classification/ClassificationLevelManagerUnitTest.java
new file mode 100644
index 0000000000..ed526f4ca6
--- /dev/null
+++ b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/classification/ClassificationLevelManagerUnitTest.java
@@ -0,0 +1,65 @@
+/*
+ * 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 .
+ */
+package org.alfresco.module.org_alfresco_module_rm.classification;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.alfresco.module.org_alfresco_module_rm.classification.ClassificationServiceException.LevelIdNotFound;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Unit tests for the {@link ClassificationLevelManager}.
+ *
+ * @author tpage
+ */
+public class ClassificationLevelManagerUnitTest
+{
+ private static final ClassificationLevel LEVEL_1 = new ClassificationLevel("id1", "displayLabelKey1");
+ private static final ClassificationLevel LEVEL_2 = new ClassificationLevel("id2", "displayLabelKey2");
+ private static final ClassificationLevel LEVEL_3 = new ClassificationLevel("id3", "displayLabelKey3");
+ private static final List LEVELS = Arrays.asList(LEVEL_1, LEVEL_2, LEVEL_3);
+
+ private ClassificationLevelManager classificationLevelManager;
+
+ @Before public void setup()
+ {
+ classificationLevelManager = new ClassificationLevelManager(LEVELS);
+ }
+
+ @Test public void findClassificationById_found()
+ {
+ ClassificationLevel actual = classificationLevelManager.findLevelById("id2");
+ assertEquals(LEVEL_2, actual);
+ }
+
+ @Test(expected=LevelIdNotFound.class) public void findClassificationById_notFound()
+ {
+ classificationLevelManager.findLevelById("id_unknown");
+ }
+
+ @Test public void getMostSecureLevel()
+ {
+ ClassificationLevel actual = classificationLevelManager.getMostSecureLevel();
+ assertEquals(LEVEL_1, actual);
+ }
+}
diff --git a/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/classification/ClassificationReasonManagerUnitTest.java b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/classification/ClassificationReasonManagerUnitTest.java
new file mode 100644
index 0000000000..682e4a8843
--- /dev/null
+++ b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/classification/ClassificationReasonManagerUnitTest.java
@@ -0,0 +1,59 @@
+/*
+ * 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 .
+ */
+package org.alfresco.module.org_alfresco_module_rm.classification;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.alfresco.module.org_alfresco_module_rm.classification.ClassificationServiceException.ReasonIdNotFound;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Unit tests for the {@link ClassificationReasonManager}.
+ *
+ * @author tpage
+ */
+public class ClassificationReasonManagerUnitTest
+{
+ private static final ClassificationReason REASON_1 = new ClassificationReason("id1", "displayLabelKey1");
+ private static final ClassificationReason REASON_2 = new ClassificationReason("id2", "displayLabelKey2");
+ private static final ClassificationReason REASON_3 = new ClassificationReason("id3", "displayLabelKey3");
+ private static final List REASONS = Arrays.asList(REASON_1, REASON_2, REASON_3);
+
+ private ClassificationReasonManager classificationReasonManager;
+
+ @Before public void setup()
+ {
+ classificationReasonManager = new ClassificationReasonManager(REASONS);
+ }
+
+ @Test public void findClassificationById_found()
+ {
+ ClassificationReason actual = classificationReasonManager.findReasonById("id2");
+ assertEquals(REASON_2, actual);
+ }
+
+ @Test(expected = ReasonIdNotFound.class) public void findClassificationById_notFound()
+ {
+ classificationReasonManager.findReasonById("id_unknown");
+ }
+}
diff --git a/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/classification/ClassificationServiceImplUnitTest.java b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/classification/ClassificationServiceImplUnitTest.java
index bb4c09cbcb..82fd21a085 100644
--- a/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/classification/ClassificationServiceImplUnitTest.java
+++ b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/classification/ClassificationServiceImplUnitTest.java
@@ -24,26 +24,36 @@ import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.io.Serializable;
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.List;
+import java.util.Map;
+import java.util.Set;
import java.util.stream.Stream;
+import com.google.common.collect.Sets;
import org.alfresco.module.org_alfresco_module_rm.classification.ClassificationServiceException.MissingConfiguration;
+import org.alfresco.module.org_alfresco_module_rm.classification.model.ClassifiedContentModel;
import org.alfresco.module.org_alfresco_module_rm.test.util.ExceptionUtils;
import org.alfresco.module.org_alfresco_module_rm.test.util.MockAuthenticationUtilHelper;
import org.alfresco.module.org_alfresco_module_rm.util.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.apache.log4j.Appender;
import org.apache.log4j.Level;
import org.apache.log4j.spi.LoggingEvent;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -95,11 +105,16 @@ public class ClassificationServiceImplUnitTest
@InjectMocks private ClassificationServiceImpl classificationServiceImpl;
- @Mock private AttributeService mockedAttributeService;
- @Mock private AuthenticationUtil mockedAuthenticationUtil;
- @Mock private ClassificationServiceDAO mockClassificationServiceDAO;
+ @Mock private AttributeService mockedAttributeService;
+ @Mock private AuthenticationUtil mockedAuthenticationUtil;
+ @Mock private ClassificationServiceDAO mockClassificationServiceDAO;
+ @Mock private NodeService mockNodeService;
/** Using a mock appender in the class logger so that we can verify some of the logging requirements. */
- @Mock private Appender mockAppender;
+ @Mock private Appender mockAppender;
+ @Mock private ClassificationLevelManager mockLevelManager;
+ @Mock private ClassificationReasonManager mockReasonManager;
+ @Captor private ArgumentCaptor loggingEventCaptor;
+ @Captor private ArgumentCaptor