RM-2319 Bootstrap initial exemption categories into the system.

This change does not include any validation. There is currently no
validation being done for classification reasons either, so it seemed
to make sense to do both in a separate change.

+review RM

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/modules/recordsmanagement/HEAD@106417 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Tom Page
2015-06-17 15:38:10 +00:00
parent d12292297f
commit ece8e174cb
14 changed files with 479 additions and 14 deletions

View File

@@ -52,7 +52,7 @@ rm.dispositionlifecycletrigger.cronexpression=0 0/5 * * * ?
# Records contributors group # Records contributors group
# #
# if false then record contributor check is ignored and all users can contribute records from # if false then record contributor check is ignored and all users can contribute records from
# a collaboration site, if true then a user must be a member of the records contributor group # a collaboration site, if true then a user must be a member of the records contributor group
# in order for them to contribute a record from a collaboration site. Default value 'false'. # in order for them to contribute a record from a collaboration site. Default value 'false'.
rm.record.contributors.group.enabled=false rm.record.contributors.group.enabled=false
# record contributors group, default value 'RECORD_CONTRIBUTORS' # record contributors group, default value 'RECORD_CONTRIBUTORS'
@@ -65,3 +65,5 @@ rm.record.contributors.group.name=RECORD_CONTRIBUTORS
rm.classification.levelsFile=/alfresco/module/org_alfresco_module_rm/classification/rm-classification-levels.json rm.classification.levelsFile=/alfresco/module/org_alfresco_module_rm/classification/rm-classification-levels.json
# The location of the classification reasons configuration file (relative to the classpath). # The location of the classification reasons configuration file (relative to the classpath).
rm.classification.reasonsFile=/alfresco/module/org_alfresco_module_rm/classification/rm-classification-reasons.json rm.classification.reasonsFile=/alfresco/module/org_alfresco_module_rm/classification/rm-classification-reasons.json
# The location of the exemption categories configuration file (relative to the classpath).
rm.classification.exemptionCategoriesFile=/alfresco/module/org_alfresco_module_rm/classification/rm-exemption-categories.json

View File

@@ -0,0 +1,38 @@
[
{
"id" : "1",
"displayLabel" : "rm.exemption-category.1"
},
{
"id" : "2",
"displayLabel" : "rm.exemption-category.2"
},
{
"id" : "3",
"displayLabel" : "rm.exemption-category.3"
},
{
"id" : "4",
"displayLabel" : "rm.exemption-category.4"
},
{
"id" : "5",
"displayLabel" : "rm.exemption-category.5"
},
{
"id" : "6",
"displayLabel" : "rm.exemption-category.6"
},
{
"id" : "7",
"displayLabel" : "rm.exemption-category.7"
},
{
"id" : "8",
"displayLabel" : "rm.exemption-category.8"
},
{
"id" : "9",
"displayLabel" : "rm.exemption-category.9"
}
]

View File

@@ -33,6 +33,7 @@
<bean id="classificationServiceDAO" class="org.alfresco.module.org_alfresco_module_rm.classification.ClassificationServiceDAO"> <bean id="classificationServiceDAO" class="org.alfresco.module.org_alfresco_module_rm.classification.ClassificationServiceDAO">
<property name="levelConfigLocation" value="${rm.classification.levelsFile}" /> <property name="levelConfigLocation" value="${rm.classification.levelsFile}" />
<property name="reasonConfigLocation" value="${rm.classification.reasonsFile}" /> <property name="reasonConfigLocation" value="${rm.classification.reasonsFile}" />
<property name="exemptionCategoryConfigLocation" value="${rm.classification.exemptionCategoriesFile}" />
</bean> </bean>
<!-- Classification Scheme Service --> <!-- Classification Scheme Service -->

View File

@@ -14,4 +14,15 @@ rm.classification-reason.14c=Intelligence activities (including special activiti
rm.classification-reason.14d=Foreign relations or foreign activities for the U.S., including confidential sources. rm.classification-reason.14d=Foreign relations or foreign activities for the U.S., including confidential sources.
rm.classification-reason.14e=Scientific, technological or economic matters relating to the nation security which includes defense against transnational terrorism. rm.classification-reason.14e=Scientific, technological or economic matters relating to the nation security which includes defense against transnational terrorism.
rm.classification-reason.14f=U.S. Government programs for safeguarding nuclear materials of facilities. rm.classification-reason.14f=U.S. Government programs for safeguarding nuclear materials of facilities.
rm.classification-reason.14g=Vulnerabilities or capabilities of systems, installations, infrastructures, projects, plans or protection services relating to the national security, which includes defense against transnational terrorism. rm.classification-reason.14g=Vulnerabilities or capabilities of systems, installations, infrastructures, projects, plans or protection services relating to the national security, which includes defense against transnational terrorism.
## Default exemption categories
rm.exemption-category.1=Information that is currently and properly classified.
rm.exemption-category.2=Information that pertains solely to the internal rules and practices of the agency that, if released, would allow circumvention of an agency rule, policy, or statute, thereby impeding the agency in the conduct of its mission.
rm.exemption-category.3=Information specifically exempted by a statute establishing particular criteria for withholding. The language of the statute must clearly state that the information will not be disclosed.
rm.exemption-category.4=Information such as trade secrets and commercial or financial information obtained from a company on a privileged or confidential basis that, if released, would result in competitive harm to the company, impair the Government's ability to obtain like information in the future, or impair the Government's interest in compliance with program effectiveness.
rm.exemption-category.5=Inter- or intra-agency memorandums or letters containing information considered privileged in civil litigation. The most common privilege is the deliberative process privilege, which concerns documents that are part of the decision-making process and contain subjective evaluations, opinions, and recommendations. Other common privileges are the attorney-client and attorney work product privileges.
rm.exemption-category.6=Information, the release of which would reasonably be expected to constitute a clearly unwarranted invasion of the personal privacy of individuals.
rm.exemption-category.7=Records or information compiled for law enforcement purposes that: (a) Could reasonably be expected to interfere with law enforcement proceedings. (b) Would deprive a person of a right to a fair trial or impartial adjudication. (c) Could reasonably be expected to constitute an unwarranted invasion of the personal privacy of others. (d) Disclose the identity of a confidential source. (e) Disclose investigative techniques and procedures. (f) Could reasonably be expected to endanger the life or physical safety of any individual.
rm.exemption-category.8=Certain records of agencies responsible for supervision of financial institutions.
rm.exemption-category.9=Geological and geophysical information (including maps) concerning wells.

View File

@@ -18,12 +18,12 @@
*/ */
package org.alfresco.module.org_alfresco_module_rm.classification; package org.alfresco.module.org_alfresco_module_rm.classification;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.service.cmr.repository.NodeRef;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.service.cmr.repository.NodeRef;
/** /**
* Generic class for any runtime exception to do with classified records. * Generic class for any runtime exception to do with classified records.
* *
@@ -108,6 +108,18 @@ public class ClassificationException extends AlfrescoRuntimeException
} }
} }
/** The supplied exemption category id was not found in the configured list. */
public static class ExemptionCategoryIdNotFound extends ClassificationException
{
/** serial version uid */
private static final long serialVersionUID = -6754627999115496384L;
public ExemptionCategoryIdNotFound(String id)
{
super("Could not find classification reason with id " + id);
}
}
public static class InvalidNode extends ClassificationException public static class InvalidNode extends ClassificationException
{ {
/** serial version uid */ /** serial version uid */

View File

@@ -21,13 +21,13 @@ package org.alfresco.module.org_alfresco_module_rm.classification;
import static java.util.Arrays.asList; import static java.util.Arrays.asList;
import static org.alfresco.module.org_alfresco_module_rm.util.RMCollectionUtils.getDuplicateElements; import static org.alfresco.module.org_alfresco_module_rm.util.RMCollectionUtils.getDuplicateElements;
import java.util.ArrayList;
import java.util.List;
import org.alfresco.module.org_alfresco_module_rm.classification.ClassificationException.IllegalAbbreviationChars; import org.alfresco.module.org_alfresco_module_rm.classification.ClassificationException.IllegalAbbreviationChars;
import org.alfresco.module.org_alfresco_module_rm.classification.ClassificationException.IllegalConfiguration; import org.alfresco.module.org_alfresco_module_rm.classification.ClassificationException.IllegalConfiguration;
import org.alfresco.module.org_alfresco_module_rm.classification.ClassificationException.MissingConfiguration; import org.alfresco.module.org_alfresco_module_rm.classification.ClassificationException.MissingConfiguration;
import java.util.ArrayList;
import java.util.List;
/** /**
* This class is responsible for validating {@link ClassificationLevel}s. * This class is responsible for validating {@link ClassificationLevel}s.
* *
@@ -36,7 +36,7 @@ import java.util.List;
*/ */
public class ClassificationLevelValidation public class ClassificationLevelValidation
{ {
/** The maximum number of chatacters allowed in a {@link ClassificationLevel#getId() level ID}. */ /** The maximum number of characters allowed in a {@link ClassificationLevel#getId() level ID}. */
private static final int ABBREVIATION_LENGTH_LIMIT = 10; private static final int ABBREVIATION_LENGTH_LIMIT = 10;
/** /**

View File

@@ -46,8 +46,8 @@ public class ClassificationServiceBootstrap extends AbstractLifecycleBean implem
/** Logging utility for the class. */ /** Logging utility for the class. */
private static final Logger LOGGER = LoggerFactory.getLogger(ClassificationServiceBootstrap.class); private static final Logger LOGGER = LoggerFactory.getLogger(ClassificationServiceBootstrap.class);
private final AuthenticationUtil authenticationUtil; private final AuthenticationUtil authenticationUtil;
private final TransactionService transactionService; private final TransactionService transactionService;
private AttributeService attributeService; private AttributeService attributeService;
/** The classification levels currently configured in this server. */ /** The classification levels currently configured in this server. */
private ClassificationLevelManager classificationLevelManager = new ClassificationLevelManager(); private ClassificationLevelManager classificationLevelManager = new ClassificationLevelManager();
@@ -55,6 +55,8 @@ public class ClassificationServiceBootstrap extends AbstractLifecycleBean implem
private ClassificationReasonManager classificationReasonManager = new ClassificationReasonManager(); private ClassificationReasonManager classificationReasonManager = new ClassificationReasonManager();
/** The clearance levels currently configured in this server. */ /** The clearance levels currently configured in this server. */
private ClearanceLevelManager clearanceLevelManager = new ClearanceLevelManager(); private ClearanceLevelManager clearanceLevelManager = new ClearanceLevelManager();
/** The exemption categories currently configured in this server. */
private ExemptionCategoryManager exemptionCategoryManager = new ExemptionCategoryManager();
private ClassificationServiceDAO classificationServiceDAO; private ClassificationServiceDAO classificationServiceDAO;
private final ClassificationLevelValidation levelValidation = new ClassificationLevelValidation(); private final ClassificationLevelValidation levelValidation = new ClassificationLevelValidation();
@@ -73,10 +75,13 @@ public class ClassificationServiceBootstrap extends AbstractLifecycleBean implem
public void setClassificationServiceDAO(ClassificationServiceDAO classificationServiceDAO) { this.classificationServiceDAO = classificationServiceDAO; } public void setClassificationServiceDAO(ClassificationServiceDAO classificationServiceDAO) { this.classificationServiceDAO = classificationServiceDAO; }
public void setAttributeService(AttributeService attributeService) { this.attributeService = attributeService; } public void setAttributeService(AttributeService attributeService) { this.attributeService = attributeService; }
/** Used in unit tests. */ /** Used in unit tests. */
protected void setExemptionCategoryManager(ExemptionCategoryManager exemptionCategoryManager) { this.exemptionCategoryManager = exemptionCategoryManager; }
/** Used in unit tests. */
protected void setClearanceLevelManager(ClearanceLevelManager clearanceLevelManager) { this.clearanceLevelManager = clearanceLevelManager; } protected void setClearanceLevelManager(ClearanceLevelManager clearanceLevelManager) { this.clearanceLevelManager = clearanceLevelManager; }
public ClassificationLevelManager getClassificationLevelManager() { return classificationLevelManager; } public ClassificationLevelManager getClassificationLevelManager() { return classificationLevelManager; }
public ClassificationReasonManager getClassificationReasonManager() { return classificationReasonManager; } public ClassificationReasonManager getClassificationReasonManager() { return classificationReasonManager; }
public ExemptionCategoryManager getExemptionCategoryManager() { return exemptionCategoryManager; }
public ClearanceLevelManager getClearanceLevelManager() { return clearanceLevelManager; } public ClearanceLevelManager getClearanceLevelManager() { return clearanceLevelManager; }
@Override public void onBootstrap(ApplicationEvent event) @Override public void onBootstrap(ApplicationEvent event)
@@ -91,6 +96,7 @@ public class ClassificationServiceBootstrap extends AbstractLifecycleBean implem
{ {
initConfiguredClassificationLevels(); initConfiguredClassificationLevels();
initConfiguredClassificationReasons(); initConfiguredClassificationReasons();
initConfiguredExemptionCategories();
initConfiguredClearanceLevels(classificationLevelManager.getClassificationLevels()); initConfiguredClearanceLevels(classificationLevelManager.getClassificationLevels());
return null; return null;
} }
@@ -173,6 +179,8 @@ public class ClassificationServiceBootstrap extends AbstractLifecycleBean implem
LOGGER.debug("Persisted classification reasons: {}", loggableStatusOf(persistedReasons)); LOGGER.debug("Persisted classification reasons: {}", loggableStatusOf(persistedReasons));
LOGGER.debug("Classpath classification reasons: {}", loggableStatusOf(classpathReasons)); LOGGER.debug("Classpath classification reasons: {}", loggableStatusOf(classpathReasons));
// TODO Add reason validation.
if (isEmpty(persistedReasons)) if (isEmpty(persistedReasons))
{ {
if (isEmpty(classpathReasons)) if (isEmpty(classpathReasons))
@@ -217,6 +225,64 @@ public class ClassificationServiceBootstrap extends AbstractLifecycleBean implem
return classificationServiceDAO.getConfiguredReasons(); return classificationServiceDAO.getConfiguredReasons();
} }
/**
* Initialise the system's exemption categories by loading the values from a configuration file and storing them in
* the attribute service and the {@link ExemptionCategoryManager}.
*/
protected void initConfiguredExemptionCategories()
{
final List<ExemptionCategory> persistedCategories = getPersistedCategories();
final List<ExemptionCategory> classpathCategories = getConfigurationCategories();
LOGGER.debug("Persisted exemption categories: {}", loggableStatusOf(persistedCategories));
LOGGER.debug("Classpath exemption categories: {}", loggableStatusOf(classpathCategories));
// TODO Add exemption category validation.
if (isEmpty(persistedCategories))
{
if (isEmpty(classpathCategories))
{
throw new MissingConfiguration("Exemption category configuration is missing.");
}
attributeService.setAttribute((Serializable) classpathCategories, EXEMPTION_CATEGORIES_KEY);
this.exemptionCategoryManager.setExemptionCategories(classpathCategories);
}
else
{
if (isEmpty(classpathCategories) || !classpathCategories.equals(persistedCategories))
{
LOGGER.warn("Exemption categories configured in classpath do not match those stored in Alfresco. "
+ "Alfresco will use the unchanged values stored in the database.");
// RM-2313 says that we should log a warning and proceed normally.
}
this.exemptionCategoryManager.setExemptionCategories(persistedCategories);
}
}
/**
* Gets the list of exemption categories as persisted in the system.
* @return the list of exemption categories if they have been persisted, else {@code null}.
*/
private List<ExemptionCategory> getPersistedCategories()
{
return authenticationUtil.runAsSystem(new RunAsWork<List<ExemptionCategory>>()
{
@Override
@SuppressWarnings("unchecked")
public List<ExemptionCategory> doWork() throws Exception
{
return (List<ExemptionCategory>) attributeService.getAttribute(EXEMPTION_CATEGORIES_KEY);
}
});
}
/** Gets the list of exemption categories - as defined and ordered in the system configuration. */
private List<ExemptionCategory> getConfigurationCategories()
{
return classificationServiceDAO.getConfiguredExemptionCategories();
}
/** /**
* Initialise and create a {@link ClearanceLevelManager}. * Initialise and create a {@link ClearanceLevelManager}.
* *

View File

@@ -42,6 +42,7 @@ class ClassificationServiceDAO
{ {
private String levelConfigLocation; private String levelConfigLocation;
private String reasonConfigLocation; private String reasonConfigLocation;
private String exemptionCategoryConfigLocation;
/** Set the location of the level configuration file relative to the classpath. */ /** Set the location of the level configuration file relative to the classpath. */
public void setLevelConfigLocation(String levelConfigLocation) { this.levelConfigLocation = levelConfigLocation; } public void setLevelConfigLocation(String levelConfigLocation) { this.levelConfigLocation = levelConfigLocation; }
@@ -49,6 +50,9 @@ class ClassificationServiceDAO
/** Set the location of the reasons configuration file relative to the classpath. */ /** Set the location of the reasons configuration file relative to the classpath. */
public void setReasonConfigLocation(String reasonConfigLocation) { this.reasonConfigLocation = reasonConfigLocation; } public void setReasonConfigLocation(String reasonConfigLocation) { this.reasonConfigLocation = reasonConfigLocation; }
/** Set the location of the exemption categories configuration file relative to the classpath. */
public void setExemptionCategoryConfigLocation(String exemptionCategoryConfigLocation) { this.exemptionCategoryConfigLocation = exemptionCategoryConfigLocation; }
/** /**
* Gets the list (in descending order) of classification levels - as defined in the classpath. * Gets the list (in descending order) of classification levels - as defined in the classpath.
* *
@@ -116,4 +120,38 @@ class ClassificationServiceDAO
} }
return result; return result;
} }
/**
* Gets the list of exemption categories as defined in the classpath.
*
* @return the configured exemption categories in the given order, or an empty list if there are none.
*/
public List<ExemptionCategory> getConfiguredExemptionCategories()
{
List<ExemptionCategory> result;
try (final InputStream in = this.getClass().getResourceAsStream(exemptionCategoryConfigLocation))
{
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 ExemptionCategory(id, displayLabelKey));
}
}
}
catch (IOException | JSONException e)
{
throw new MalformedConfiguration("Could not read exemption category configuration", e);
}
return result;
}
} }

View File

@@ -0,0 +1,87 @@
/*
* 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 org.apache.commons.lang.StringUtils.isNotBlank;
import java.io.Serializable;
import org.alfresco.module.org_alfresco_module_rm.util.RMParameterCheck;
import org.springframework.extensions.surf.util.I18NUtil;
/**
* This class is a POJO data type for an exemption category. It gives a reason why a piece of content should not be
* declassified.
*
* @author tpage
* @since 3.0
*/
public final class ExemptionCategory implements Serializable
{
/** serial version uid */
private static final long serialVersionUID = -8990809567320071986L;
private final String id;
private final String displayLabelKey;
public ExemptionCategory(final String id, final String displayLabelKey)
{
RMParameterCheck.checkNotBlank("id", id);
RMParameterCheck.checkNotBlank("displayLabelKey", displayLabelKey);
this.id = id;
this.displayLabelKey = displayLabelKey;
}
/** Returns the unique identifier for this exemption category. */
public String getId() { return this.id; }
/** Returns the key for the display label. */
public String getDisplayLabelKey() { return displayLabelKey; }
/**
* Returns the localised (current locale) display label for this exemption category. If no translation is found then
* return the key instead.
*/
public String getDisplayLabel()
{
String message = I18NUtil.getMessage(displayLabelKey);
return (isNotBlank(message) ? message : displayLabelKey);
}
@Override public String toString()
{
StringBuilder msg = new StringBuilder();
msg.append(ExemptionCategory.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;
ExemptionCategory that = (ExemptionCategory) o;
return this.id.equals(that.id);
}
@Override public int hashCode() { return id.hashCode(); }
}

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.ClassificationException.ExemptionCategoryIdNotFound;
/**
* Container for the configured {@link ExemptionCategory} objects.
*
* @author tpage
*/
public class ExemptionCategoryManager
{
/** An immutable list of exemption categories. */
private ImmutableList<ExemptionCategory> exemptionCategories;
/**
* Store an immutable copy of the given categories.
*
* @param exemptionCategories The exemption categories.
*/
public void setExemptionCategories(Collection<ExemptionCategory> exemptionCategories)
{
this.exemptionCategories = ImmutableList.copyOf(exemptionCategories);
}
/** @return An immutable list of exemption categories. */
public ImmutableList<ExemptionCategory> getExemptionCategories()
{
return exemptionCategories;
}
/**
* Get a <code>ExemptionCategory</code> using its id.
*
* @param id The id of an exemption category.
* @return The exemption category.
* @throws ExemptionCategoryIdNotFound If the exemption category cannot be found.
*/
public ExemptionCategory findCategoryById(String id) throws ExemptionCategoryIdNotFound
{
for (ExemptionCategory exemptionCategory : exemptionCategories)
{
if (exemptionCategory.getId().equals(id))
{
return exemptionCategory;
}
}
throw new ExemptionCategoryIdNotFound(id);
}
}

View File

@@ -38,6 +38,7 @@ public interface ClassifiedContentModel
Serializable[] LEVELS_KEY = new String[] { "org.alfresco", "module.org_alfresco_module_rm", "classification.levels" }; Serializable[] LEVELS_KEY = new String[] { "org.alfresco", "module.org_alfresco_module_rm", "classification.levels" };
Serializable[] REASONS_KEY = new String[] { "org.alfresco", "module.org_alfresco_module_rm", "classification.reasons" }; Serializable[] REASONS_KEY = new String[] { "org.alfresco", "module.org_alfresco_module_rm", "classification.reasons" };
Serializable[] EXEMPTION_CATEGORIES_KEY = new String[] { "org.alfresco", "module.org_alfresco_module_rm", "classification.exemptionCategories" };
/** Classified aspect */ /** Classified aspect */
QName ASPECT_CLASSIFIED = QName.createQName(CLF_URI, "classified"); QName ASPECT_CLASSIFIED = QName.createQName(CLF_URI, "classified");

View File

@@ -22,7 +22,7 @@ package org.alfresco.module.org_alfresco_module_rm.test.integration.classificati
import java.util.List; import java.util.List;
import org.alfresco.module.org_alfresco_module_rm.classification.ClassificationReason; import org.alfresco.module.org_alfresco_module_rm.classification.ClassificationReason;
import org.alfresco.module.org_alfresco_module_rm.classification.ClassificationSchemeServiceImpl; import org.alfresco.module.org_alfresco_module_rm.classification.ClassificationServiceBootstrap;
import org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase; import org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase;
/** /**
@@ -39,7 +39,7 @@ public class ClassificationReasonsTest extends BaseRMTestCase
* <p> * <p>
* Note that this test requires a clean db, as otherwise the classification scheme service will use the persisted * Note that this test requires a clean db, as otherwise the classification scheme service will use the persisted
* classification reasons in preference to those given on the classpath (see the logic in * classification reasons in preference to those given on the classpath (see the logic in
* {@link ClassificationSchemeServiceImpl#initConfiguredClassificationReasons()}). * {@link ClassificationServiceBootstrap#initConfiguredClassificationReasons()}).
*/ */
public void testLoadBootstrappedClassificationReasons() throws Exception public void testLoadBootstrappedClassificationReasons() throws Exception
{ {

View File

@@ -73,6 +73,9 @@ public class ClassificationServiceBootstrapUnitTest
new ClassificationReason("id2", "label2")); new ClassificationReason("id2", "label2"));
private static final List<ClassificationReason> ALTERNATIVE_CLASSIFICATION_REASONS = asList(new ClassificationReason("id8", "label8"), private static final List<ClassificationReason> ALTERNATIVE_CLASSIFICATION_REASONS = asList(new ClassificationReason("id8", "label8"),
new ClassificationReason("id9", "label9")); new ClassificationReason("id9", "label9"));
private static final List<ExemptionCategory> EXEMPTION_CATEGORIES = asList(new ExemptionCategory("id1", "label1"),
new ExemptionCategory("id2", "label2"));
private static final List<ExemptionCategory> CHANGED_EXEMPTION_CATEGORIES = asList(new ExemptionCategory("id3", "label3"));
/** /**
* A convenience method for turning lists of level id Strings into lists * A convenience method for turning lists of level id Strings into lists
@@ -103,6 +106,7 @@ public class ClassificationServiceBootstrapUnitTest
@Mock ClassificationServiceDAO mockClassificationServiceDAO; @Mock ClassificationServiceDAO mockClassificationServiceDAO;
@Mock AttributeService mockAttributeService; @Mock AttributeService mockAttributeService;
@Mock AuthenticationUtil mockAuthenticationUtil; @Mock AuthenticationUtil mockAuthenticationUtil;
@Mock ExemptionCategoryManager mockExemptionCategoryManager;
@Mock ClearanceLevelManager mockClearanceLevelManager; @Mock ClearanceLevelManager mockClearanceLevelManager;
/** Using a mock appender in the class logger so that we can verify some of the logging requirements. */ /** Using a mock appender in the class logger so that we can verify some of the logging requirements. */
@Mock Appender mockAppender; @Mock Appender mockAppender;
@@ -113,7 +117,8 @@ public class ClassificationServiceBootstrapUnitTest
{ {
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
MockAuthenticationUtilHelper.setup(mockAuthenticationUtil); MockAuthenticationUtilHelper.setup(mockAuthenticationUtil);
// This seems to be necessary because the ClearanceLevelManager isn't a constructor argument. // This seems to be necessary because the POJO managers aren't constructor arguments.
classificationServiceBootstrap.setExemptionCategoryManager(mockExemptionCategoryManager);
classificationServiceBootstrap.setClearanceLevelManager(mockClearanceLevelManager); classificationServiceBootstrap.setClearanceLevelManager(mockClearanceLevelManager);
} }
@@ -224,6 +229,80 @@ public class ClassificationServiceBootstrapUnitTest
classificationServiceBootstrap.initConfiguredClassificationReasons(); classificationServiceBootstrap.initConfiguredClassificationReasons();
} }
@Test
public void testInitConfiguredExemptionCategories_firstLoad()
{
when(mockAttributeService.getAttribute(anyString(), anyString(), anyString()))
.thenReturn((Serializable) null);
when(mockClassificationServiceDAO.getConfiguredExemptionCategories()).thenReturn(EXEMPTION_CATEGORIES);
classificationServiceBootstrap.initConfiguredExemptionCategories();
verify(mockExemptionCategoryManager).setExemptionCategories(EXEMPTION_CATEGORIES);
}
@Test
public void testInitConfiguredExemptionCategories_secondLoad()
{
when(mockAttributeService.getAttribute(anyString(), anyString(), anyString()))
.thenReturn((Serializable) EXEMPTION_CATEGORIES);
when(mockClassificationServiceDAO.getConfiguredExemptionCategories()).thenReturn(EXEMPTION_CATEGORIES);
classificationServiceBootstrap.initConfiguredExemptionCategories();
verify(mockExemptionCategoryManager).setExemptionCategories(EXEMPTION_CATEGORIES);
}
/**
* Check that if the exemption categories supplied on the classpath differ from those already persisted then a
* warning is logged and no change is made to the persisted categories.
* <p>
* This test uses the underlying log4j implementation to insert a mock Appender, and tests this for the warning
* message. If the underlying logging framework is changed then this unit test will fail, and it may not be possible
* to/worth fixing.
*/
@Test
public void testInitConfiguredExemptionCategories_changedCategories()
{
when(mockAttributeService.getAttribute(anyString(), anyString(), anyString()))
.thenReturn((Serializable) EXEMPTION_CATEGORIES);
when(mockClassificationServiceDAO.getConfiguredExemptionCategories()).thenReturn(CHANGED_EXEMPTION_CATEGORIES);
// Put the mock Appender into the log4j logger and allow warning messages to be received.
org.apache.log4j.Logger log4jLogger = org.apache.log4j.Logger.getLogger(ClassificationServiceBootstrap.class);
log4jLogger.addAppender(mockAppender);
Level normalLevel = log4jLogger.getLevel();
log4jLogger.setLevel(Level.WARN);
// Call the method under test.
classificationServiceBootstrap.initConfiguredExemptionCategories();
// Reset the logging level for other tests.
log4jLogger.setLevel(normalLevel);
// Check the persisted values weren't changed.
verify(mockAttributeService, never()).setAttribute(any(Serializable.class),
anyString(), anyString(), anyString());
// Check that the warning message was logged.
verify(mockAppender).doAppend(loggingEventCaptor.capture());
List<LoggingEvent> loggingEvents = loggingEventCaptor.getAllValues();
Stream<String> messages = loggingEvents.stream()
.map(LoggingEvent::getRenderedMessage);
String expectedMessage = "Exemption categories configured in classpath do not match those stored in Alfresco. Alfresco will use the unchanged values stored in the database.";
assertTrue("Warning message not found in log.", messages.anyMatch(message -> expectedMessage.equals(message)));
}
@Test(expected = MissingConfiguration.class)
public void testInitConfiguredExemptionCategories_noCategoriesFound()
{
when(mockAttributeService.getAttribute(anyString(), anyString(), anyString()))
.thenReturn((Serializable) null);
when(mockClassificationServiceDAO.getConfiguredReasons()).thenReturn(null);
classificationServiceBootstrap.initConfiguredExemptionCategories();
}
/** /**
* Check that the initialise method creates a clearance level corresponding to each classification level and that * Check that the initialise method creates a clearance level corresponding to each classification level and that
* the display label for the lowest clearance level is "No Clearance" (rather than "Unclassified"). * the display label for the lowest clearance level is "No Clearance" (rather than "Unclassified").

View File

@@ -0,0 +1,60 @@
/*
* 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 org.junit.Assert.assertEquals;
import java.util.Arrays;
import java.util.List;
import org.alfresco.module.org_alfresco_module_rm.classification.ClassificationException.ExemptionCategoryIdNotFound;
import org.junit.Before;
import org.junit.Test;
/**
* Unit tests for the {@link ExemptionCategoryManager}.
*
* @author tpage
*/
public class ExemptionCategoryManagerUnitTest
{
private static final ExemptionCategory CATEGORY_1 = new ExemptionCategory("id1", "displayLabelKey1");
private static final ExemptionCategory CATEGORY_2 = new ExemptionCategory("id2", "displayLabelKey2");
private static final ExemptionCategory CATEGORY_3 = new ExemptionCategory("id3", "displayLabelKey3");
private static final List<ExemptionCategory> CATEGORIES = Arrays.asList(CATEGORY_1, CATEGORY_2, CATEGORY_3);
private ExemptionCategoryManager exemptionCategoryManager;
@Before public void setup()
{
exemptionCategoryManager = new ExemptionCategoryManager();
exemptionCategoryManager.setExemptionCategories(CATEGORIES);
}
@Test public void findClassificationById_found()
{
ExemptionCategory actual = exemptionCategoryManager.findCategoryById("id2");
assertEquals(CATEGORY_2, actual);
}
@Test(expected = ExemptionCategoryIdNotFound.class) public void findClassificationById_notFound()
{
exemptionCategoryManager.findCategoryById("id_unknown");
}
}