diff --git a/rm-server/config/alfresco/module/org_alfresco_module_rm/classification/rm-classification-reasons.json b/rm-server/config/alfresco/module/org_alfresco_module_rm/classification/rm-classification-reasons.json
new file mode 100644
index 0000000000..9535c91e4c
--- /dev/null
+++ b/rm-server/config/alfresco/module/org_alfresco_module_rm/classification/rm-classification-reasons.json
@@ -0,0 +1,14 @@
+[
+ {
+ "id" : "1.4(a)",
+ "displayLabel" : "rm.classification-reason.militaryPlans"
+ },
+ {
+ "id" : "1.4(b)",
+ "displayLabel" : "rm.classification-reason.foreignGovernment"
+ },
+ {
+ "id" : "1.4(c)",
+ "displayLabel" : "rm.classification.intelligenceActivities"
+ }
+]
diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/ClassificationReason.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/ClassificationReason.java
new file mode 100644
index 0000000000..b95b7cf683
--- /dev/null
+++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/ClassificationReason.java
@@ -0,0 +1,93 @@
+/*
+ * 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 org.springframework.extensions.surf.util.I18NUtil;
+
+import java.io.Serializable;
+
+/**
+ * This class is a POJO data type for a classification reason.
+ *
+ * @author Tom Page
+ * @since 3.0
+ */
+public final class ClassificationReason implements Serializable {
+ private static final long serialVersionUID = 4876939094239038838L;
+ private final String id;
+ private final String displayLabelKey;
+
+ /**
+ * Constructor to create a classification reason.
+ *
+ * @param id
+ * The unique identifier that represents this classification
+ * reason.
+ * @param displayLabelKey
+ * The I18N key for the display label for the reason.
+ */
+ public ClassificationReason(final String id, final String displayLabelKey) {
+ if (id == null || id.trim().equals("")) {
+ throw new IllegalArgumentException("Illegal id: '" + id + "'");
+ }
+ this.id = id;
+ this.displayLabelKey = displayLabelKey;
+ }
+
+ /**
+ * Returns the unique identifier that represents this classification reason.
+ */
+ public String getId() {
+ return this.id;
+ }
+
+ /**
+ * Returns the localised (current locale) display label for this
+ * classification reason.
+ */
+ public String getDisplayLabel() {
+ return I18NUtil.getMessage(displayLabelKey);
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder msg = new StringBuilder();
+ msg.append(ClassificationReason.class.getSimpleName()).append(":")
+ .append(id);
+
+ return msg.toString();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o)
+ return true;
+ if (o == null || getClass() != o.getClass())
+ return false;
+
+ ClassificationReason that = (ClassificationReason) o;
+
+ return this.id.equals(that.id);
+ }
+
+ @Override
+ public int hashCode() {
+ return id.hashCode();
+ }
+}
diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/ClassificationServiceBootstrap.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/ClassificationServiceBootstrap.java
index 8a5c712471..313c0a0ccb 100644
--- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/ClassificationServiceBootstrap.java
+++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/ClassificationServiceBootstrap.java
@@ -33,7 +33,7 @@ import org.springframework.extensions.surf.util.AbstractLifecycleBean;
public class ClassificationServiceBootstrap extends AbstractLifecycleBean
{
private final AuthenticationUtil authenticationUtil;
- private final ClassificationServiceImpl classificationService;
+ private final ClassificationServiceImpl classificationServiceImpl;
private final TransactionService transactionService;
public ClassificationServiceBootstrap(AuthenticationUtil authUtil,
@@ -41,7 +41,7 @@ public class ClassificationServiceBootstrap extends AbstractLifecycleBean
TransactionService txService)
{
this.authenticationUtil = authUtil;
- this.classificationService = cService;
+ this.classificationServiceImpl = cService;
this.transactionService = txService;
}
@@ -55,7 +55,8 @@ public class ClassificationServiceBootstrap extends AbstractLifecycleBean
{
public Void execute()
{
- classificationService.initConfiguredClassificationLevels();
+ classificationServiceImpl.initConfiguredClassificationLevels();
+ classificationServiceImpl.initConfiguredClassificationReasons();
return null;
}
};
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 bef1fc9b4f..e2d40f913f 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
@@ -24,6 +24,8 @@ import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.service.cmr.attributes.AttributeService;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import java.io.Serializable;
import java.util.Collections;
@@ -36,21 +38,30 @@ import java.util.List;
public class ClassificationServiceImpl extends ServiceBaseImpl
implements ClassificationService
{
- private static Log logger = LogFactory.getLog(ClassificationServiceImpl.class);
+ private static final Logger LOGGER = LoggerFactory.getLogger(ClassificationServiceImpl.class);
private static final String[] LEVELS_KEY = new String[] { "org.alfresco",
"module.org_alfresco_module_rm",
"classification.levels" };
+ private static final String[] REASONS_KEY = new String[] { "org.alfresco",
+ "module.org_alfresco_module_rm",
+ "classification.reasons" };
- public static final String DEFAULT_CONFIG_LOCATION =
- "/alfresco/module/org_alfresco_module_rm/classification/rm-classification-levels.json";
+
+ static final String DEFAULT_CONFIG_DIRECTORY = "/alfresco/module/org_alfresco_module_rm/classification/";
+ static final String DEFAULT_LEVELS_FILE = DEFAULT_CONFIG_DIRECTORY
+ + "rm-classification-levels.json";
+ static final String DEFAULT_REASONS_FILE = DEFAULT_CONFIG_DIRECTORY
+ + "rm-classification-reasons.json";
private AttributeService attributeService; // TODO What about other code (e.g. REST API) accessing the AttrService?
/** The classification levels currently configured in this server. */
private List configuredLevels;
+ /** The classification reasons currently configured in this server. */
+ private List configuredReasons;
- private Configuration config = new Configuration(DEFAULT_CONFIG_LOCATION);
+ private Configuration config = new Configuration(DEFAULT_LEVELS_FILE, DEFAULT_REASONS_FILE);
public void setAttributeService(AttributeService service) { this.attributeService = service; }
@@ -59,12 +70,9 @@ public class ClassificationServiceImpl extends ServiceBaseImpl
final List allPersistedLevels = getPersistedLevels();
final List configurationLevels = getConfigurationLevels();
- if (logger.isDebugEnabled())
- {
- // Note! We cannot log the level names or even the size of these lists for security reasons.
- logger.debug("Persisted classification levels: " + loggableStatusOf(allPersistedLevels));
- logger.debug("Classpath classification levels: " + loggableStatusOf(configurationLevels));
- }
+ // Note! We cannot log the level names or even the size of these lists for security reasons.
+ LOGGER.debug("Persisted classification levels: {}", loggableStatusOf(allPersistedLevels));
+ LOGGER.debug("Classpath classification levels: {}", loggableStatusOf(configurationLevels));
if (configurationLevels == null || configurationLevels.isEmpty())
{
@@ -80,6 +88,29 @@ public class ClassificationServiceImpl extends ServiceBaseImpl
this.configuredLevels = allPersistedLevels;
}
}
+
+ void initConfiguredClassificationReasons() {
+ final List allPersistedReasons = getPersistedReasons();
+ final List configurationReasons = getConfigurationReasons();
+
+ // Note! We cannot log the reasons or even the size of these lists for security reasons.
+ LOGGER.debug("Persisted classification reasons: {}", loggableStatusOf(allPersistedReasons));
+ LOGGER.debug("Classpath classification reasons: {}", loggableStatusOf(configurationReasons));
+
+ if (configurationReasons == null || configurationReasons.isEmpty())
+ {
+ throw new MissingConfiguration("Classification reason configuration is missing.");
+ }
+ else if ( !configurationReasons.equals(allPersistedReasons))
+ {
+ attributeService.setAttribute((Serializable) configurationReasons, REASONS_KEY);
+ this.configuredReasons = configurationReasons;
+ }
+ else
+ {
+ this.configuredReasons = allPersistedReasons;
+ }
+ }
/** Helper method for debug-logging of sensitive lists. */
private String loggableStatusOf(List> l)
@@ -110,6 +141,28 @@ public class ClassificationServiceImpl extends ServiceBaseImpl
{
return config.getConfiguredLevels();
}
+
+ /**
+ * Gets the list of classification reasons as persisted in the system.
+ * @return the list of classification reasons if they have been persisted, else {@code null}.
+ */
+ List getPersistedReasons() {
+ return authenticationUtil.runAsSystem(new AuthenticationUtil.RunAsWork>()
+ {
+ @Override
+ @SuppressWarnings("unchecked")
+ public List doWork() throws Exception
+ {
+ return (List) attributeService.getAttribute(REASONS_KEY);
+ }
+ });
+ }
+
+ /** Gets the list of classification reasons - as defined and ordered in the system configuration. */
+ List getConfigurationReasons()
+ {
+ return config.getConfiguredReasons();
+ }
@Override
public List getClassificationLevels()
diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/Configuration.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/Configuration.java
index f048805e8c..456cec2816 100644
--- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/Configuration.java
+++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/Configuration.java
@@ -18,6 +18,12 @@
*/
package org.alfresco.module.org_alfresco_module_rm.classification;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
import org.alfresco.module.org_alfresco_module_rm.classification.ClassificationServiceException.MalformedConfiguration;
import org.apache.commons.io.IOUtils;
import org.json.JSONArray;
@@ -25,12 +31,6 @@ import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONTokener;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
/**
* This class is responsible for providing the configured classification levels, dealing with
* JSON schema as part of that.
@@ -40,11 +40,13 @@ import java.util.List;
*/
class Configuration
{
- public final String configLocation;
+ public final String levelConfigLocation;
+ public final String reasonConfigLocation;
- public Configuration(String classpathLocation)
+ public Configuration(String levelConfigLocation, String reasonConfigLocation)
{
- this.configLocation = classpathLocation;
+ this.levelConfigLocation = levelConfigLocation;
+ this.reasonConfigLocation = reasonConfigLocation;
}
/**
@@ -55,7 +57,7 @@ class Configuration
public List getConfiguredLevels()
{
List result;
- try (final InputStream in = this.getClass().getResourceAsStream(configLocation))
+ try (final InputStream in = this.getClass().getResourceAsStream(levelConfigLocation))
{
if (in == null) { result = Collections.emptyList(); }
else
@@ -80,4 +82,37 @@ class Configuration
}
return result;
}
+
+ /**
+ * Gets the list of classification reasons as defined in the system configuration.
+ *
+ * @return the configured classification reasons in descending order, or an empty list if there are none.
+ */
+ public List getConfiguredReasons() {
+ List result;
+ try (final InputStream in = this.getClass().getResourceAsStream(reasonConfigLocation))
+ {
+ if (in == null) { result = Collections.emptyList(); }
+ else
+ {
+ final String jsonString = IOUtils.toString(in);
+ final JSONArray jsonArray = new JSONArray(new JSONTokener(jsonString));
+
+ result = new ArrayList<>(jsonArray.length());
+
+ for (int i = 0; i < jsonArray.length(); i++)
+ {
+ final JSONObject nextObj = jsonArray.getJSONObject(i);
+ final String id = nextObj.getString("id");
+ final String displayLabelKey = nextObj.getString("displayLabel");
+ result.add(new ClassificationReason(id, displayLabelKey));
+ }
+ }
+ }
+ catch (IOException | JSONException e)
+ {
+ throw new MalformedConfiguration("Could not read classification reason configuration", e);
+ }
+ return result;
+ }
}
diff --git a/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/classification/ConfigurationUnitTest.java b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/classification/ConfigurationUnitTest.java
index da358fca68..4fb055b08a 100644
--- a/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/classification/ConfigurationUnitTest.java
+++ b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/classification/ConfigurationUnitTest.java
@@ -18,14 +18,15 @@
*/
package org.alfresco.module.org_alfresco_module_rm.classification;
-import org.alfresco.module.org_alfresco_module_rm.classification.ClassificationServiceException.MalformedConfiguration;
-import org.junit.Test;
+import static org.alfresco.module.org_alfresco_module_rm.classification.ClassificationServiceImplUnitTest.asLevelList;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import java.util.List;
-import static org.alfresco.module.org_alfresco_module_rm.classification.ClassificationServiceImplUnitTest.asLevelList;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
+import org.alfresco.module.org_alfresco_module_rm.classification.ClassificationServiceException.MalformedConfiguration;
+import org.junit.Test;
/**
* Unit tests for {@link Configuration}.
@@ -40,23 +41,48 @@ public class ConfigurationUnitTest
"Confidential", "C",
"NoClearance", "NC");
- @Test public void readingDefaultConfigurationShouldWork()
+ @Test public void getConfiguredLevels_readingDefaultConfigurationShouldWork()
{
- Configuration c = new Configuration(ClassificationServiceImpl.DEFAULT_CONFIG_LOCATION);
+ Configuration c = new Configuration(ClassificationServiceImpl.DEFAULT_LEVELS_FILE, ClassificationServiceImpl.DEFAULT_REASONS_FILE);
List config = c.getConfiguredLevels();
assertEquals(DEFAULT_CLASSIFICATION_LEVELS, config);
}
- @Test public void readingMissingConfigurationShouldProduceEmptyConfig() throws Exception
+ @Test public void getConfiguredLevels_readingMissingConfigurationShouldProduceEmptyConfig() throws Exception
{
- Configuration c = new Configuration("/no/such/resource");
+ Configuration c = new Configuration("/no/such/resource", "/no/such/resource");
assertTrue(c.getConfiguredLevels().isEmpty());
}
@Test (expected = MalformedConfiguration.class)
- public void readingMalformedConfigurationShouldFail() throws Exception
+ public void getConfiguredLevels_readingMalformedConfigurationShouldFail()
{
- Configuration c = new Configuration("/alfresco/classification/rm-classification-levels-malformed.json");
- c.getConfiguredLevels();
+ Configuration c = new Configuration(
+ "/alfresco/classification/rm-classification-levels-malformed.json",
+ "/alfresco/classification/rm-classification-levels-malformed.json");
+ c.getConfiguredLevels();
+ }
+
+ @Test public void getConfiguredReasons_readingDefaultConfigurationShouldWork()
+ {
+ Configuration c = new Configuration(ClassificationServiceImpl.DEFAULT_LEVELS_FILE,
+ ClassificationServiceImpl.DEFAULT_REASONS_FILE);
+ List config = c.getConfiguredReasons();
+ assertFalse(config.isEmpty());
+ }
+
+ @Test public void getConfiguredReasons_readingMissingConfigurationShouldProduceEmptyConfig() throws Exception
+ {
+ Configuration c = new Configuration("/no/such/resource", "/no/such/resource");
+ assertTrue(c.getConfiguredReasons().isEmpty());
+ }
+
+ @Test (expected = MalformedConfiguration.class)
+ public void getConfiguredReasons_readingMalformedConfigurationShouldFail()
+ {
+ Configuration c = new Configuration(
+ "/alfresco/classification/rm-classification-levels-malformed.json",
+ "/alfresco/classification/rm-classification-levels-malformed.json");
+ c.getConfiguredReasons();
}
}