diff --git a/rm-automation/pom.xml b/rm-automation/pom.xml index 70f2b10f0e..61a7768fbc 100644 --- a/rm-automation/pom.xml +++ b/rm-automation/pom.xml @@ -1,9 +1,9 @@ - - + 4.0.0 alfresco-rm-automation Alfresco Records Management Automation + pom org.alfresco @@ -11,43 +11,24 @@ 2.6-SNAPSHOT + + + LGPL 3 + + + + + rm-automation-community-rest-api + rm-automation-enterprise-rest-api + rm-automation-ui + + - 2.45.0 - 4.0.5.RELEASE - 1.8 - testng.xml - true + nightlybuilds - - org.codehaus.mojo - build-helper-maven-plugin - - - add-test-source - - add-test-source - - - - src/unit-test/java - - - - - - - maven-surefire-plugin - - false - - ${project.build.testOutputDirectory}/${suiteXmlFile} - - ${skip.automationtests} - - maven-antrun-plugin @@ -64,15 +45,6 @@ - - org.codehaus.mojo - license-maven-plugin - - alfresco_enterprise - file:${project.parent.basedir}/license - ${project.parent.basedir}/license/description.ftl - - @@ -104,88 +76,6 @@ - - - org.alfresco.test - dataprep - 1.8 - - - org.alfresco.test - alfresco-testng - 1.1 - - - org.alfresco - selenium-grid - 1.8 - - - org.springframework - spring-beans - ${spring.version} - - - org.springframework - spring-core - ${spring.version} - - - org.springframework - spring-context - ${spring.version} - - - org.springframework - spring-tx - ${spring.version} - test - - - org.springframework - spring-test - ${spring.version} - test - - - org.testng - testng - 6.8.8 - - - ru.yandex.qatools.htmlelements - htmlelements-all - 1.15 - - - ru.yandex.qatools.properties - properties-loader - 1.5 - test - - - com.github.tomakehurst - wiremock - 1.56 - - - org.mockito - mockito-all - test - - - org.slf4j - slf4j-log4j12 - test - - - org.slf4j - jul-to-slf4j - 1.7.21 - test - - - install-alfresco @@ -205,7 +95,7 @@ Recreating database... drop database if exists alfresco; create database alfresco Downloading Alfresco installer... - + Installing Alfresco... @@ -241,13 +131,13 @@ org.alfresco - alfresco-rm-enterprise-share + ${alfresco.rm.share} ${project.version} amp org.alfresco - alfresco-rm-enterprise-repo + ${alfresco.rm.repo} ${project.version} amp @@ -271,7 +161,7 @@ process-test-resources true - ${project.build.directory}/amps/alfresco-rm-enterprise-repo-${project.version}.amp + ${project.build.directory}/amps/${alfresco.rm.repo}-${project.version}.amp ${project.build.directory}/alf-installation/tomcat/webapps/alfresco.war @@ -283,7 +173,7 @@ process-test-resources true - ${project.build.directory}/amps/alfresco-rm-enterprise-share-${project.version}.amp + ${project.build.directory}/amps/${alfresco.rm.share}-${project.version}.amp ${project.build.directory}/alf-installation/tomcat/webapps/share.war diff --git a/rm-automation/rm-automation-community-rest-api/.gitignore b/rm-automation/rm-automation-community-rest-api/.gitignore new file mode 100644 index 0000000000..d1a4acb433 --- /dev/null +++ b/rm-automation/rm-automation-community-rest-api/.gitignore @@ -0,0 +1,8 @@ +/target/ +/.settings/ +.classpath +.project +/src/test/resources/local.properties +/.idea/ +*.iml +/test-output/ diff --git a/rm-automation/rm-automation-community-rest-api/README b/rm-automation/rm-automation-community-rest-api/README new file mode 100644 index 0000000000..907f41ab0a --- /dev/null +++ b/rm-automation/rm-automation-community-rest-api/README @@ -0,0 +1,3 @@ +FIXME: Add more info to the README file + +In order to change the value of a property in "config.properties" create a file called "local.properties" under src/test/resources and redefine the property with the new value. \ No newline at end of file diff --git a/rm-automation/rm-automation-community-rest-api/pom.xml b/rm-automation/rm-automation-community-rest-api/pom.xml new file mode 100644 index 0000000000..317d05f586 --- /dev/null +++ b/rm-automation/rm-automation-community-rest-api/pom.xml @@ -0,0 +1,56 @@ + + + + 4.0.0 + alfresco-rm-automation-community-rest-api + Alfresco Records Management Automation Community REST API + + + org.alfresco + alfresco-rm-automation + 2.6-SNAPSHOT + + + + 1.8 + 1.8 + testng.xml + true + alfresco-rm-community-share + alfresco-rm-community-repo + + + + + org.alfresco.tas + restapi-test + 1.0-SNAPSHOT + + + org.alfresco.tas + restapi-test + 1.0-SNAPSHOT + test-jar + + + org.jglue.fluent-json + fluent-json + 2.0.0 + + + + + + + maven-surefire-plugin + + false + + ${project.build.testOutputDirectory}/${suiteXmlFile} + + ${skip.automationtests} + + + + + diff --git a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/model/fileplancomponents/FilePlanComponent.java b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/model/fileplancomponents/FilePlanComponent.java new file mode 100644 index 0000000000..0843a5e840 --- /dev/null +++ b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/model/fileplancomponents/FilePlanComponent.java @@ -0,0 +1,363 @@ +/* + * #%L + * Alfresco Records Management Module + * %% + * Copyright (C) 2005 - 2016 Alfresco Software Limited + * %% + * License rights for this program may be obtained from Alfresco Software, Ltd. + * pursuant to a written agreement and any use of this program without such an + * agreement is prohibited. + * #L% + */ +package org.alfresco.rest.rm.model.fileplancomponents; + +import static org.alfresco.rest.rm.model.fileplancomponents.FilePlanComponentFields.ALLOWABLE_OPERATIONS; +import static org.alfresco.rest.rm.model.fileplancomponents.FilePlanComponentFields.IS_CLOSED; +import static org.alfresco.rest.rm.model.fileplancomponents.FilePlanComponentFields.PROPERTIES; + +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * POJO for file plan component + * + * @author Tuna Aksoy + * @since 2.6 + */ +public class FilePlanComponent +{ + @JsonProperty (required = true) + private String id; + + @JsonProperty (required = true) + private String parentId; + + @JsonProperty (required = true) + private String name; + + @JsonProperty (required = true) + private String nodeType; + + @JsonProperty (required = true) + private boolean isCategory; + + @JsonProperty (required = true) + private boolean isRecordFolder; + + @JsonProperty (required = true) + private boolean isFile; + + @JsonProperty + private boolean hasRetentionSchedule; + + @JsonProperty(value = IS_CLOSED) + private boolean isClosed; + + @JsonProperty + private boolean isCompleted; + + @JsonProperty (required = true) + private List aspectNames; + + @JsonProperty (required = true) + private FilePlanComponentUserInfo createdByUser; + + @JsonProperty(value = PROPERTIES, required = true) + private FilePlanComponentProperties properties; + + @JsonProperty (value = ALLOWABLE_OPERATIONS) + private List allowableOperations; + private FilePlanComponentPath path; + + @JsonProperty (required = true) + private String modifiedAt; + + + @JsonProperty (required = true) + private String createdAt; + + @JsonProperty (required = true) + private FilePlanComponentUserInfo modifiedByUser; + + + /** + * @return the id + */ + public String getId() + { + return this.id; + } + + /** + * @param id the id to set + */ + public void setId(String id) + { + this.id = id; + } + + /** + * @return the parentId + */ + public String getParentId() + { + return this.parentId; + } + + /** + * @param parentId the parentId to set + */ + public void setParentId(String parentId) + { + this.parentId = parentId; + } + + /** + * @return the name + */ + public String getName() + { + return this.name; + } + + /** + * @param name the name to set + */ + public void setName(String name) + { + this.name = name; + } + + /** + * @return the nodeType + */ + public String getNodeType() + { + return this.nodeType; + } + + /** + * @param nodeType the nodeType to set + */ + public void setNodeType(String nodeType) + { + this.nodeType = nodeType; + } + + /** + * @return the isCategory + */ + public boolean isIsCategory() + { + return this.isCategory; + } + + /** + * @param isCategory the isCategory to set + */ + public void setCategory(boolean isCategory) + { + this.isCategory = isCategory; + } + + /** + * @return the isRecordFolder + */ + public boolean isIsRecordFolder() + { + return this.isRecordFolder; + } + + /** + * @param isRecordFolder the isRecordFolder to set + */ + public void setRecordFolder(boolean isRecordFolder) + { + this.isRecordFolder = isRecordFolder; + } + + /** + * @return the isFile + */ + public boolean isIsFile() + { + return this.isFile; + } + + /** + * @param isFile the isFile to set + */ + public void setFile(boolean isFile) + { + this.isFile = isFile; + } + + /** + * @return the hasRetentionSchedule + */ + public boolean isHasRetentionSchedule() + { + return this.hasRetentionSchedule; + } + + /** + * @param hasRetentionSchedule the hasRetentionSchedule to set + */ + public void setHasRetentionSchedule(boolean hasRetentionSchedule) + { + this.hasRetentionSchedule = hasRetentionSchedule; + } + + /** + * @return the properties + */ + public FilePlanComponentProperties getProperties() + { + return properties; + } + + /** + * @param properties the properties to set + */ + public void setProperties(FilePlanComponentProperties properties) + { + this.properties = properties; + } + + /** + * @return the aspectNames + */ + public List getAspectNames() + { + return this.aspectNames; + } + + /** + * @param aspectNames the aspectNames to set + */ + public void setAspectNames(List aspectNames) + { + this.aspectNames = aspectNames; + } + + /** + * @return the createdByUser + */ + public FilePlanComponentUserInfo getCreatedByUser() + { + return this.createdByUser; + } + + /** + * @param createdByUser the createdByUser to set + */ + public void setCreatedByUser(FilePlanComponentUserInfo createdByUser) + { + this.createdByUser = createdByUser; + } + + /** + * @return the allowableOperations + */ + public List getAllowableOperations() + { + return this.allowableOperations; + } + + /** + * @return the path + */ + public FilePlanComponentPath getPath() + { + return this.path; + } + + /** + * @param path the path to set + */ + public void setPath(FilePlanComponentPath path) + { + this.path = path; + } + + /** + * @param modifiedAt the modifiedAt to set + */ + public void setModifiedAt(String modifiedAt) + { + this.modifiedAt = modifiedAt; + } + + /** + * @param createdAt the createdAt to set + */ + public void setCreatedAt(String createdAt) + { + this.createdAt = createdAt; + } + + /** + * @param modifiedByUser the modifiedByUser to set + */ + public void setModifiedByUser(FilePlanComponentUserInfo modifiedByUser) + { + this.modifiedByUser = modifiedByUser; + } + + /** + * @return the modifiedAt + */ + public String getModifiedAt() + { + return this.modifiedAt; + } + + /** + * @return the createdAt + */ + public String getCreatedAt() + { + return this.createdAt; + } + + /** + * @return the modifiedByUser + */ + public FilePlanComponentUserInfo getModifiedByUser() + { + return this.modifiedByUser; + } + + /** + * @return the isClosed + */ + public boolean isClosed() + { + return this.isClosed; + } + + /** + * @param closed the isClosed to set + */ + public void setClosed(boolean closed) + { + this.isClosed = closed; + } + + /** + * @return the isCompleted + */ + public boolean isCompleted() + { + return this.isCompleted; + } + + /** + * @param completed the isCompleted to set + */ + public void setCompleted(boolean completed) + { + this.isCompleted = completed; + } +} diff --git a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/model/fileplancomponents/FilePlanComponentAlias.java b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/model/fileplancomponents/FilePlanComponentAlias.java new file mode 100644 index 0000000000..e5929014f8 --- /dev/null +++ b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/model/fileplancomponents/FilePlanComponentAlias.java @@ -0,0 +1,68 @@ +/* + * #%L + * Alfresco Records Management Module + * %% + * Copyright (C) 2005 - 2016 Alfresco Software Limited + * %% + * License rights for this program may be obtained from Alfresco Software, Ltd. + * pursuant to a written agreement and any use of this program without such an + * agreement is prohibited. + * #L% + */ +package org.alfresco.rest.rm.model.fileplancomponents; + +import static org.alfresco.rest.rm.util.ParameterCheck.mandatoryString; + +/** + * File plan component alias enumeration + * + * @author Tuna Aksoy + * @since 2.6 + */ +public enum FilePlanComponentAlias +{ + FILE_PLAN_ALIAS("-filePlan-"), + TRANSFERS_ALIAS("-transfers-"), + UNFILED_RECORDS_CONTAINER_ALIAS("-unfiled-"), + HOLDS_ALIAS("-holds-"); + + private String alias; + + private FilePlanComponentAlias(String alias) + { + this.alias = alias; + } + + public static final FilePlanComponentAlias getFilePlanComponentAlias(String alias) + { + mandatoryString("alias", alias); + + FilePlanComponentAlias result = null; + FilePlanComponentAlias[] values = values(); + + for (FilePlanComponentAlias filePlanComponentAlias : values) + { + if (filePlanComponentAlias.toString().equals(alias)) + { + result = filePlanComponentAlias; + break; + } + } + + if (result == null) + { + throw new IllegalArgumentException("Invalid file plan component alias enum value: '" + alias + "'."); + } + + return result; + } + + /** + * @see java.lang.Enum#toString() + */ + @Override + public String toString() + { + return this.alias; + } +} diff --git a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/model/fileplancomponents/FilePlanComponentEntry.java b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/model/fileplancomponents/FilePlanComponentEntry.java new file mode 100644 index 0000000000..70bd836090 --- /dev/null +++ b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/model/fileplancomponents/FilePlanComponentEntry.java @@ -0,0 +1,35 @@ +/* + * #%L + * Alfresco Records Management Module + * %% + * Copyright (C) 2005 - 2016 Alfresco Software Limited + * %% + * License rights for this program may be obtained from Alfresco Software, Ltd. + * pursuant to a written agreement and any use of this program without such an + * agreement is prohibited. + * #L% + */ +package org.alfresco.rest.rm.model.fileplancomponents; + +import static org.alfresco.rest.rm.model.fileplancomponents.FilePlanComponentFields.ENTRY; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import org.alfresco.rest.core.RestModels; + +/** + * POJO for file plan component entry + * + * @author Tuna Aksoy + * @since 2.6 + */ +public class FilePlanComponentEntry extends RestModels +{ + @JsonProperty(ENTRY) + FilePlanComponent filePlanComponent; + + public FilePlanComponent getFilePlanComponent() + { + return filePlanComponent; + } +} diff --git a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/model/fileplancomponents/FilePlanComponentFields.java b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/model/fileplancomponents/FilePlanComponentFields.java new file mode 100644 index 0000000000..9d8415d960 --- /dev/null +++ b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/model/fileplancomponents/FilePlanComponentFields.java @@ -0,0 +1,36 @@ +/* + * #%L + * Alfresco Records Management Module + * %% + * Copyright (C) 2005 - 2016 Alfresco Software Limited + * %% + * License rights for this program may be obtained from Alfresco Software, Ltd. + * pursuant to a written agreement and any use of this program without such an + * agreement is prohibited. + * #L% + */ +package org.alfresco.rest.rm.model.fileplancomponents; + +/** + * File plan component field names constants + * + * @author Tuna Aksoy + * @since 2.6 + */ +public class FilePlanComponentFields +{ + public static final String NAME = "name"; + public static final String NODE_TYPE = "nodeType"; + public static final String NODE_PARENT_ID = "parentId"; + public static final String ENTRY = "entry"; + public static final String PROPERTIES = "properties"; + public static final String PROPERTIES_TITLE = "cm:title"; + public static final String PROPERTIES_VITAL_RECORD_INDICATOR = "rma:vitalRecordIndicator"; + public static final String PROPERTIES_HOLD_REASON = "rma:holdReason"; + public static final String PROPERTIES_DESCRIPTION = "cm:description"; + public static final String PROPERTIES_SUPPLEMENTAL_MARKING_LIST = "rmc:supplementalMarkingList"; + public static final String ALLOWABLE_OPERATIONS = "allowableOperations"; + public static final String IS_CLOSED="isclosed"; + public static final String PROPERTIES_REVIEW_PERIOD="rma:reviewPeriod"; + public static final String PROPERTIES_LOCATION="rma:location"; +} diff --git a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/model/fileplancomponents/FilePlanComponentIdNamePair.java b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/model/fileplancomponents/FilePlanComponentIdNamePair.java new file mode 100644 index 0000000000..a7d5f1f9c3 --- /dev/null +++ b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/model/fileplancomponents/FilePlanComponentIdNamePair.java @@ -0,0 +1,56 @@ +/* + * #%L + * Alfresco Records Management Module + * %% + * Copyright (C) 2005 - 2016 Alfresco Software Limited + * %% + * License rights for this program may be obtained from Alfresco Software, Ltd. + * pursuant to a written agreement and any use of this program without such an + * agreement is prohibited. + * #L% + */ +package org.alfresco.rest.rm.model.fileplancomponents; + +/** + * POJO for id/name pair + * + * @author Kristijan Conkas + * @since 2.6 + */ +public class FilePlanComponentIdNamePair +{ + public String id; + public String name; + + /** + * @return the id + */ + public String getId() + { + return this.id; + } + + /** + * @param id the id to set + */ + public void setId(String id) + { + this.id = id; + } + + /** + * @return the name + */ + public String getName() + { + return this.name; + } + + /** + * @param name the name to set + */ + public void setName(String name) + { + this.name = name; + } +} diff --git a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/model/fileplancomponents/FilePlanComponentPath.java b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/model/fileplancomponents/FilePlanComponentPath.java new file mode 100644 index 0000000000..3e75c01396 --- /dev/null +++ b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/model/fileplancomponents/FilePlanComponentPath.java @@ -0,0 +1,78 @@ +/* + * #%L + * Alfresco Records Management Module + * %% + * Copyright (C) 2005 - 2016 Alfresco Software Limited + * %% + * License rights for this program may be obtained from Alfresco Software, Ltd. + * pursuant to a written agreement and any use of this program without such an + * agreement is prohibited. + * #L% + */ +package org.alfresco.rest.rm.model.fileplancomponents; + +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +/** + * POJO for FilePlanComponent path parameter + *
+ * @author Kristijan Conkas + * @since 2.6 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public class FilePlanComponentPath +{ + private String name; + private boolean isComplete; + private List elements; + + /** + * @return the name + */ + public String getName() + { + return this.name; + } + + /** + * @param name the name to set + */ + public void setName(String name) + { + this.name = name; + } + + /** + * @return the isComplete + */ + public boolean isComplete() + { + return this.isComplete; + } + + /** + * @param isComplete the isComplete to set + */ + public void setComplete(boolean isComplete) + { + this.isComplete = isComplete; + } + + /** + * @return the elements + */ + public List getElements() + { + return this.elements; + } + + /** + * @param elements the elements to set + */ + public void setElements(List elements) + { + this.elements = elements; + } +} diff --git a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/model/fileplancomponents/FilePlanComponentProperties.java b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/model/fileplancomponents/FilePlanComponentProperties.java new file mode 100644 index 0000000000..a7179e831a --- /dev/null +++ b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/model/fileplancomponents/FilePlanComponentProperties.java @@ -0,0 +1,171 @@ +/* + * #%L + * Alfresco Records Management Module + * %% + * Copyright (C) 2005 - 2016 Alfresco Software Limited + * %% + * License rights for this program may be obtained from Alfresco Software, Ltd. + * pursuant to a written agreement and any use of this program without such an + * agreement is prohibited. + * #L% + */ +package org.alfresco.rest.rm.model.fileplancomponents; + +import static org.alfresco.rest.rm.model.fileplancomponents.FilePlanComponentFields.PROPERTIES_DESCRIPTION; +import static org.alfresco.rest.rm.model.fileplancomponents.FilePlanComponentFields.PROPERTIES_HOLD_REASON; +import static org.alfresco.rest.rm.model.fileplancomponents.FilePlanComponentFields.PROPERTIES_LOCATION; +import static org.alfresco.rest.rm.model.fileplancomponents.FilePlanComponentFields.PROPERTIES_REVIEW_PERIOD; +import static org.alfresco.rest.rm.model.fileplancomponents.FilePlanComponentFields.PROPERTIES_SUPPLEMENTAL_MARKING_LIST; +import static org.alfresco.rest.rm.model.fileplancomponents.FilePlanComponentFields.PROPERTIES_TITLE; +import static org.alfresco.rest.rm.model.fileplancomponents.FilePlanComponentFields.PROPERTIES_VITAL_RECORD_INDICATOR; + +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * POJO for file plan component properties + * + * @author Kristijan Conkas + * @since 2.6 + */ +//FIXME: Once the fields have been added the JsonIgnoreProperties annotation should be removed +@JsonIgnoreProperties (ignoreUnknown = true) +public class FilePlanComponentProperties +{ + + @JsonProperty(PROPERTIES_VITAL_RECORD_INDICATOR) + private boolean vitalRecord; + + @JsonProperty(PROPERTIES_TITLE) + private String title; + + @JsonProperty(PROPERTIES_HOLD_REASON) + private String holdReason; + + @JsonProperty(PROPERTIES_DESCRIPTION) + private String description; + + @JsonProperty(PROPERTIES_SUPPLEMENTAL_MARKING_LIST) + private List supplementalMarkingList; + + @JsonProperty(PROPERTIES_REVIEW_PERIOD) + private ReviewPeriod reviewPeriod; + + @JsonProperty(PROPERTIES_LOCATION) + private String location; + + + /** + * @return the vitalRecord + */ + public boolean isVitalRecord() + { + return this.vitalRecord; + } + + /** + * @param vitalRecord the vitalRecord to set + */ + public void setVitalRecord(boolean vitalRecord) + { + this.vitalRecord = vitalRecord; + } + + /** + * @return the title + */ + public String getTitle() + { + return this.title; + } + + /** + * @param title the title to set + */ + public void setTitle(String title) + { + this.title = title; + } + + /** + * @return the holdReason + */ + public String getHoldReason() + { + return this.holdReason; + } + + /** + * @param holdReason the holdReason to set + */ + public void setHoldReason(String holdReason) + { + this.holdReason = holdReason; + } + + /** + * @param description the description to set + */ + public void setDescription(String description) + { + this.description = description; + } + + /** + * @return the description + */ + public String getDescription() + { + return this.description; + } + + /** + * @return the supplementalMarkingList + */ + public List getSupplementalMarkingList() + { + return this.supplementalMarkingList; + } + + /** + * @param supplementalMarkingList the supplementalMarkingList to set + */ + public void setSupplementalMarkingList(List supplementalMarkingList) + { + this.supplementalMarkingList = supplementalMarkingList; + } + + /** + * @return the reviewPeriod + */ + public ReviewPeriod getReviewPeriod() + { + return reviewPeriod; + } + + /** + * @param reviewPeriod the reviewPeriod to set + */ + public void setReviewPeriod(ReviewPeriod reviewPeriod) + { + this.reviewPeriod = reviewPeriod; + } + + /** + * @return the location + */ + public String getLocation() + { + return location; + } + + /** + * @param location the location to set + */ + public void setLocation(String location) + { + this.location = location; + } +} diff --git a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/model/fileplancomponents/FilePlanComponentType.java b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/model/fileplancomponents/FilePlanComponentType.java new file mode 100644 index 0000000000..498be5e202 --- /dev/null +++ b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/model/fileplancomponents/FilePlanComponentType.java @@ -0,0 +1,72 @@ +/* + * #%L + * Alfresco Records Management Module + * %% + * Copyright (C) 2005 - 2016 Alfresco Software Limited + * %% + * License rights for this program may be obtained from Alfresco Software, Ltd. + * pursuant to a written agreement and any use of this program without such an + * agreement is prohibited. + * #L% + */ +package org.alfresco.rest.rm.model.fileplancomponents; + +import static org.alfresco.rest.rm.util.ParameterCheck.mandatoryString; + +/** + * File plan component type enumeration + * + * @author Tuna Aksoy + * @since 2.6 + */ +public enum FilePlanComponentType +{ + FILE_PLAN_TYPE("rma:filePlan"), + RECORD_CATEGORY_TYPE("rma:recordCategory"), + RECORD_FOLDER_TYPE("rma:recordFolder"), + HOLD_TYPE("rma:hold"), + UNFILED_RECORD_FOLDER_TYPE("rma:unfiledRecordFolder"), + HOLD_CONTAINER_TYPE("rma:holdContainer"), + TRANSFER_CONTAINER_TYPE("rma:transferContainer"), + UNFILED_CONTAINER_TYPE("rma:unfiledRecordContainer"); + + private String type; + + private FilePlanComponentType(String type) + { + this.type = type; + } + + public static final FilePlanComponentType getFilePlanComponentType(String type) + { + mandatoryString("type", type); + + FilePlanComponentType result = null; + FilePlanComponentType[] values = values(); + + for (FilePlanComponentType filePlanComponentType : values) + { + if (filePlanComponentType.toString().equals(filePlanComponentType)) + { + result = filePlanComponentType; + break; + } + } + + if (result == null) + { + throw new IllegalArgumentException("Invalid file plan component type enum value: '" + type + "'."); + } + + return result; + } + + /** + * @see java.lang.Enum#toString() + */ + @Override + public String toString() + { + return this.type; + } +} diff --git a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/model/fileplancomponents/FilePlanComponentUserInfo.java b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/model/fileplancomponents/FilePlanComponentUserInfo.java new file mode 100644 index 0000000000..7983cd9250 --- /dev/null +++ b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/model/fileplancomponents/FilePlanComponentUserInfo.java @@ -0,0 +1,56 @@ +/* + * #%L + * Alfresco Records Management Module + * %% + * Copyright (C) 2005 - 2016 Alfresco Software Limited + * %% + * License rights for this program may be obtained from Alfresco Software, Ltd. + * pursuant to a written agreement and any use of this program without such an + * agreement is prohibited. + * #L% + */ +package org.alfresco.rest.rm.model.fileplancomponents; + +/** + * POJO for file plan component created by object + * + * @author Kristijan Conkas + * @since 2.6 + */ +public class FilePlanComponentUserInfo +{ + private String id; + private String displayName; + + /** + * @return the id + */ + public String getId() + { + return this.id; + } + + /** + * @param id the id to set + */ + public void setId(String id) + { + this.id = id; + } + + /** + * @return the displayName + */ + public String getDisplayName() + { + return this.displayName; + } + + /** + * @param displayName the displayName to set + */ + public void setDisplayName(String displayName) + { + this.displayName = displayName; + } +} diff --git a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/model/fileplancomponents/FilePlanComponentsCollection.java b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/model/fileplancomponents/FilePlanComponentsCollection.java new file mode 100644 index 0000000000..5cee5e7629 --- /dev/null +++ b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/model/fileplancomponents/FilePlanComponentsCollection.java @@ -0,0 +1,25 @@ +/* + * #%L + * Alfresco Records Management Module + * %% + * Copyright (C) 2005 - 2016 Alfresco Software Limited + * %% + * License rights for this program may be obtained from Alfresco Software, Ltd. + * pursuant to a written agreement and any use of this program without such an + * agreement is prohibited. + * #L% + */ +package org.alfresco.rest.rm.model.fileplancomponents; + +import org.alfresco.rest.core.RestModels; + +/** + * Handle collection of FilePlanComponents + * + * @author Kristijan Conkas + * @since 2.6 + */ +public class FilePlanComponentsCollection extends RestModels +{ + +} diff --git a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/model/fileplancomponents/ReviewPeriod.java b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/model/fileplancomponents/ReviewPeriod.java new file mode 100644 index 0000000000..c96a2bc9f9 --- /dev/null +++ b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/model/fileplancomponents/ReviewPeriod.java @@ -0,0 +1,45 @@ +package org.alfresco.rest.rm.model.fileplancomponents; + +/** + * POJO for the review period + * + * @author Rodica Sutu + * @since 2.6 + */ +public class ReviewPeriod +{ + private String periodType; + private String expression; + + /** + * @return the periodType + */ + public String getPeriodType() + { + return this.periodType; + } + + /** + * @param periodType the periodType to set + */ + public void setPeriodType(String periodType) + { + this.periodType = periodType; + } + + /** + * @return the expression + */ + public String getExpression() + { + return this.expression; + } + + /** + * @param expression the expression to set + */ + public void setExpression(String expression) + { + this.expression = expression; + } +} diff --git a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/model/site/RMSite.java b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/model/site/RMSite.java new file mode 100644 index 0000000000..08846558f9 --- /dev/null +++ b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/model/site/RMSite.java @@ -0,0 +1,48 @@ +/* + * #%L + * Alfresco Records Management Module + * %% + * Copyright (C) 2005 - 2016 Alfresco Software Limited + * %% + * License rights for this program may be obtained from Alfresco Software, Ltd. + * pursuant to a written agreement and any use of this program without such an + * agreement is prohibited. + * #L% + */ +package org.alfresco.rest.rm.model.site; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import org.alfresco.rest.model.RestSiteModel; + +/** + * POJO for RM Site component + * + * @author Rodica Sutu + * @since 2.6 + */ +public class RMSite extends RestSiteModel +{ + @JsonProperty (required = true) + private RMSiteCompliance compliance; + + /** + * Helper method to set RM site compliance + * + * @param compliance {@link RMSiteCompliance} the compliance to set + */ + public void setCompliance(RMSiteCompliance compliance) + { + this.compliance = compliance; + } + + /** + * Helper method to get RM site compliance + * + * @return compliance the RM Site compliance to get + */ + public RMSiteCompliance getCompliance() + { + return compliance; + } +} diff --git a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/model/site/RMSiteCompliance.java b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/model/site/RMSiteCompliance.java new file mode 100644 index 0000000000..96b16a678d --- /dev/null +++ b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/model/site/RMSiteCompliance.java @@ -0,0 +1,24 @@ +/* + * #%L + * Alfresco Records Management Module + * %% + * Copyright (C) 2005 - 2016 Alfresco Software Limited + * %% + * License rights for this program may be obtained from Alfresco Software, Ltd. + * pursuant to a written agreement and any use of this program without such an + * agreement is prohibited. + * #L% + */ +package org.alfresco.rest.rm.model.site; + +/** + * RM Site compliance + * + * @author Tuna Aksoy + * @since 2.6 + */ +public enum RMSiteCompliance +{ + STANDARD, + DOD5015 +} diff --git a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/model/site/RMSiteFields.java b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/model/site/RMSiteFields.java new file mode 100644 index 0000000000..4dd9cf918d --- /dev/null +++ b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/model/site/RMSiteFields.java @@ -0,0 +1,37 @@ +/* + * #%L + * Alfresco Records Management Module + * %% + * Copyright (C) 2005 - 2016 Alfresco Software Limited + * %% + * License rights for this program may be obtained from Alfresco Software, Ltd. + * pursuant to a written agreement and any use of this program without such an + * agreement is prohibited. + * #L% + */ +package org.alfresco.rest.rm.model.site; + +/** + *RM Site properties from the RM Model Schema + *"entry": { + * "id": "string", + * "guid": "string", + * "title": "string", + * "description": "string", + * "visibility": "{@link org.springframework.social.alfresco.api.entities.Site.Visibility}", + * "compliance": "{@link RMSiteCompliance}", + * "role": "{@link org.alfresco.utility.constants.UserRole}" + *} + * @author Tuna Aksoy + * @author Rodica Sutu + * @since 2.6 + */ +public class RMSiteFields +{ + public static final String ID = "id"; + public static final String COMPLIANCE = "compliance"; + public static final String TITLE = "title"; + public static final String DESCRIPTION = "description"; + public static final String VISIBILITY ="visibility"; + public static final String ROLE = "role"; +} diff --git a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/requests/FilePlanComponentAPI.java b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/requests/FilePlanComponentAPI.java new file mode 100644 index 0000000000..a29146e434 --- /dev/null +++ b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/requests/FilePlanComponentAPI.java @@ -0,0 +1,169 @@ +/* + * #%L + * Alfresco Records Management Module + * %% + * Copyright (C) 2005 - 2016 Alfresco Software Limited + * %% + * License rights for this program may be obtained from Alfresco Software, Ltd. + * pursuant to a written agreement and any use of this program without such an + * agreement is prohibited. + * #L% + */ +package org.alfresco.rest.rm.requests; + +import static org.alfresco.rest.core.RestRequest.requestWithBody; +import static org.alfresco.rest.core.RestRequest.simpleRequest; +import static org.alfresco.rest.rm.util.ParameterCheck.mandatoryObject; +import static org.alfresco.rest.rm.util.ParameterCheck.mandatoryString; +import static org.springframework.http.HttpMethod.DELETE; +import static org.springframework.http.HttpMethod.GET; +import static org.springframework.http.HttpMethod.POST; +import static org.springframework.http.HttpMethod.PUT; + +import com.google.gson.JsonObject; + +import org.alfresco.rest.core.RestAPI; +import org.alfresco.rest.rm.model.fileplancomponents.FilePlanComponent; +import org.alfresco.rest.rm.model.fileplancomponents.FilePlanComponentsCollection; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +/** + * File plan component REST API Wrapper + * + * @author Tuna Aksoy + * @author Kristijan Conkas + * @since 2.6 + */ +@Component +@Scope(value = "prototype") +public class FilePlanComponentAPI extends RestAPI +{ + /** + * Get a file plan component + * + * @param filePlanComponentId The id of the file plan component to get + * @return The {@link FilePlanComponent} for the given file plan component id + * @throws Exception for the following cases: + *
    + *
  • {@code fileplanComponentId} is not a valid format
  • + *
  • authentication fails
  • + *
  • {@code fileplanComponentId} does not exist
  • + *
+ */ + public FilePlanComponent getFilePlanComponent(String filePlanComponentId) throws Exception + { + mandatoryString("filePlanComponentId", filePlanComponentId); + + return usingRestWrapper().processModel(FilePlanComponent.class, simpleRequest( + GET, + "fileplan-components/{fileplanComponentId}?{parameters}", + filePlanComponentId, getParameters() + )); + } + + /** + * List child components of a file plan component + * + * @param filePlanComponentId The id of the file plan component of which to get child components + * @return The {@link FilePlanComponent} for the given file plan component id + * @throws Exception for the following cases: + *
    + *
  • {@code fileplanComponentId} is not a valid format
  • + *
  • authentication fails
  • + *
  • {@code fileplanComponentId} does not exist
  • + *
+ */ + public FilePlanComponentsCollection listChildComponents(String filePlanComponentId) throws Exception + { + mandatoryString("filePlanComponentId", filePlanComponentId); + + return usingRestWrapper().processModels(FilePlanComponentsCollection.class, simpleRequest( + GET, + "fileplan-components/{fileplanComponentId}/children", + filePlanComponentId + )); + } + + /** + * Creates a file plan component with the given properties under the parent node with the given id + * + * @param filePlanComponentProperties The properties of the file plan component to be created + * @param parentId The id of the parent where the new file plan component should be created + * @return The {@link FilePlanComponent} with the given properties + * @throws Exception for the following cases: + *
    + *
  • {@code fileplanComponentId} is not a valid format
  • + *
  • authentication fails
  • + *
  • current user does not have permission to add children to {@code fileplanComponentId}
  • + *
  • {@code fileplanComponentId} does not exist
  • + *
  • new name clashes with an existing node in the current parent container
  • + *
  • model integrity exception, including node name with invalid characters
  • + *
+ */ + public FilePlanComponent createFilePlanComponent(JsonObject filePlanComponentProperties, String parentId) throws Exception + { + mandatoryObject("filePlanComponentProperties", filePlanComponentProperties); + mandatoryString("parentId", parentId); + + return usingRestWrapper().processModel(FilePlanComponent.class, requestWithBody( + POST, + filePlanComponentProperties.toString(), + "fileplan-components/{fileplanComponentId}/children", + parentId + )); + } + + /** + * Updates a file plan component + * + * @param filePlanComponentProperties The properties to be updated + * @param filePlanComponentId The id of the file plan component which will be updated + * @param returns The updated {@link FilePlanComponent} + * @throws Exception for the following cases: + *
    + *
  • the update request is invalid or {@code fileplanComponentId} is not a valid format or {@code filePlanComponentProperties} is invalid
  • + *
  • authentication fails
  • + *
  • current user does not have permission to update {@code fileplanComponentId}
  • + *
  • {@code fileplanComponentId} does not exist
  • + *
  • the updated name clashes with an existing node in the current parent folder
  • + *
  • model integrity exception, including node name with invalid characters
  • + *
+ */ + public FilePlanComponent updateFilePlanComponent(JsonObject filePlanComponentProperties, String filePlanComponentId) throws Exception + { + mandatoryObject("filePlanComponentProperties", filePlanComponentProperties); + mandatoryString("filePlanComponentId", filePlanComponentId); + + return usingRestWrapper().processModel(FilePlanComponent.class, requestWithBody( + PUT, + filePlanComponentProperties.toString(), + "fileplan-components/{fileplanComponentId}", + filePlanComponentId + )); + } + + /** + * Delete file plan component + * + * @param filePlanComponentId The id of the file plan component to be deleted + * @throws Exception for the following cases: + *
    + *
  • {@code fileplanComponentId} is not a valid format
  • + *
  • authentication fails
  • + *
  • current user does not have permission to delete {@code fileplanComponentId}
  • + *
  • {@code fileplanComponentId} does not exist
  • + *
  • {@code fileplanComponentId} is locked and cannot be deleted
  • + *
+ */ + public void deleteFilePlanComponent(String filePlanComponentId) throws Exception + { + mandatoryString("filePlanComponentId", filePlanComponentId); + + usingRestWrapper().processEmptyModel(simpleRequest( + DELETE, + "fileplan-components/{fileplanComponentId}", + filePlanComponentId + )); + } +} diff --git a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/requests/RMSiteAPI.java b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/requests/RMSiteAPI.java new file mode 100644 index 0000000000..11e5ca45ba --- /dev/null +++ b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/requests/RMSiteAPI.java @@ -0,0 +1,127 @@ +/* + * #%L + * Alfresco Records Management Module + * %% + * Copyright (C) 2005 - 2016 Alfresco Software Limited + * %% + * License rights for this program may be obtained from Alfresco Software, Ltd. + * pursuant to a written agreement and any use of this program without such an + * agreement is prohibited. + * #L% + */ +package org.alfresco.rest.rm.requests; + +import static org.alfresco.rest.core.RestRequest.requestWithBody; +import static org.alfresco.rest.core.RestRequest.simpleRequest; +import static org.alfresco.rest.rm.util.ParameterCheck.mandatoryObject; +import static org.springframework.http.HttpMethod.DELETE; +import static org.springframework.http.HttpMethod.GET; +import static org.springframework.http.HttpMethod.POST; +import static org.springframework.http.HttpMethod.PUT; + +import com.google.gson.JsonObject; + +import org.alfresco.rest.core.RestAPI; +import org.alfresco.rest.rm.model.site.RMSite; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +/** + * File plan component REST API Wrapper + * + * @author Tuna Aksoy + * @author Rodica Sutu + * @since 2.6 + */ +@Component +@Scope (value = "prototype") +public class RMSiteAPI extends RestAPI +{ + /** + * Get the RM site + * + * @return The {@link RMSite} for the given file plan component id + * @throws Exception for the following cases: + *
    + *
  • Api Response code 400 Invalid parameter: GET request is supported only for the RM site
  • + *
  • Api Response code 401 If authentication failed
  • + *
  • Api Response code 409 If RM Site does not exist
  • + *
  • Api Response code default Unexpected error
  • + *
+ */ + public RMSite getSite() throws Exception + { + return usingRestWrapper().processModel(RMSite.class, simpleRequest( + GET, + "ig-sites/rm" + )); + } + + /** + * Create the RM site + * + * @param rmSiteProperties The properties of the rm site to be created + * @return The {@link RMSite} with the given properties + * @throws Exception for the following cases: + *
    + *
  • Api Response code 400 Invalid parameter: title, or description exceed the maximum length; or siteBodyCreate invalid
  • + *
  • Api Response code 401 If authentication failedApi Response code 409 RM Site already exists
  • + *
  • Api Response code default Unexpected error
  • + *
+ */ + public RMSite createRMSite(JsonObject rmSiteProperties) throws Exception + { + mandatoryObject("rmSiteProperties", rmSiteProperties); + + return usingRestWrapper().processModel(RMSite.class, requestWithBody( + POST, + rmSiteProperties.toString(), + "ig-sites" + )); + } + + /** + * Delete RM site + * @throws Exception for the following cases: + *
    + *
  • Api Response code 400 Invalid parameter: DELETE request is supported only for the RM site
  • + *
  • Api Response code 401 If authentication failedApi Response code 403 Current user does not have permission to delete the site that is visible to them.
  • + *
  • Api Response code 404 RM site does not exist
  • + *
  • Api Response code default Unexpected error
  • + *
+ */ + public void deleteRMSite() throws Exception + { + usingRestWrapper().processEmptyModel(simpleRequest( + DELETE, + "ig-sites/rm" + )); + } + + /** + * Update RM site + * + * @param rmSiteProperties The properties to be updated + * @return The updated {@link RMSite} + * @throws Exception for the following cases: + *
    + *
  • Api Response code 400 the update request is invalid {@code rmSiteProperties} is invalid
  • + *
  • Api Response code 401 If authentication fails
  • + *
  • Api Response code 403 does not have permission to update {@code RMSite}
  • + *
  • Api Response code 404 {@code RMSite} does not exist
  • + *
  • Api Response code default Unexpected error,model integrity exception
  • + *
+ */ + public RMSite updateRMSite(JsonObject rmSiteProperties) throws Exception + { + mandatoryObject("rmSiteProperties", rmSiteProperties); + + return usingRestWrapper().processModel(RMSite.class, requestWithBody( + PUT, + rmSiteProperties.toString(), + "ig-sites/rm" + )); + } +} diff --git a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/util/ParameterCheck.java b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/util/ParameterCheck.java new file mode 100644 index 0000000000..462d832ff4 --- /dev/null +++ b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/util/ParameterCheck.java @@ -0,0 +1,58 @@ +/* + * #%L + * Alfresco Records Management Module + * %% + * Copyright (C) 2005 - 2016 Alfresco Software Limited + * %% + * License rights for this program may be obtained from Alfresco Software, Ltd. + * pursuant to a written agreement and any use of this program without such an + * agreement is prohibited. + * #L% + */ +package org.alfresco.rest.rm.util; + +import static org.apache.commons.lang3.StringUtils.isBlank; + +/** + * Utility class for checking parameters + * + * @author Tuna Aksoy + * @since 2.6 + */ +public class ParameterCheck +{ + private ParameterCheck() + { + // Intentionally blank + } + + /** + * Checks if a given {@link String} is blank or not, i.e. not null, "" or " ". + * + * @param paramName The name of the parameter to check + * @param paramValue The value of the parameter to check + * @throws IllegalArgumentException Throws an exception if the given value is blank + */ + public static void mandatoryString(final String paramName, final String paramValue) throws IllegalArgumentException + { + if (isBlank(paramValue)) + { + throw new IllegalArgumentException("'" + paramName + "' is a mandatory parameter."); + } + } + + /** + * Checks if a given {@link Object} is null or not + * + * @param paramName The name of the parameter to check + * @param object The value of the parameter to check + * @throws IllegalArgumentException Throws an exception if the given value is null + */ + public static void mandatoryObject(final String paramName, final Object object) throws IllegalArgumentException + { + if (object == null) + { + throw new IllegalArgumentException("'" + paramName + "' is a mandatory parameter."); + } + } +} diff --git a/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/base/AllowableOperations.java b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/base/AllowableOperations.java new file mode 100644 index 0000000000..e50a7f07ff --- /dev/null +++ b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/base/AllowableOperations.java @@ -0,0 +1,25 @@ +/* + * #%L + * Alfresco Records Management Module + * %% + * Copyright (C) 2005 - 2016 Alfresco Software Limited + * %% + * License rights for this program may be obtained from Alfresco Software, Ltd. + * pursuant to a written agreement and any use of this program without such an + * agreement is prohibited. + * #L% + */ +package org.alfresco.rest.rm.base; + +/** + * List of allowable operations + * + * @author Tuna Aksoy + * @since 2.6 + */ +public class AllowableOperations +{ + public static final String CREATE = "create"; + public static final String UPDATE = "update"; + public static final String DELETE = "delete"; +} diff --git a/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/base/BaseRestTest.java b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/base/BaseRestTest.java new file mode 100644 index 0000000000..089120d436 --- /dev/null +++ b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/base/BaseRestTest.java @@ -0,0 +1,192 @@ +/* + * #%L + * Alfresco Records Management Module + * %% + * Copyright (C) 2005 - 2016 Alfresco Software Limited + * %% + * License rights for this program may be obtained from Alfresco Software, Ltd. + * pursuant to a written agreement and any use of this program without such an + * agreement is prohibited. + * #L% + */ +package org.alfresco.rest.rm.base; + +import static java.lang.Integer.parseInt; + +import static org.alfresco.rest.rm.base.TestData.CATEGORY_TITLE; +import static org.alfresco.rest.rm.base.TestData.FOLDER_TITLE; +import static org.alfresco.rest.rm.model.fileplancomponents.FilePlanComponentFields.NAME; +import static org.alfresco.rest.rm.model.fileplancomponents.FilePlanComponentFields.NODE_TYPE; +import static org.alfresco.rest.rm.model.fileplancomponents.FilePlanComponentFields.PROPERTIES; +import static org.alfresco.rest.rm.model.fileplancomponents.FilePlanComponentFields.PROPERTIES_TITLE; +import static org.alfresco.rest.rm.model.fileplancomponents.FilePlanComponentType.RECORD_CATEGORY_TYPE; +import static org.alfresco.rest.rm.model.fileplancomponents.FilePlanComponentType.RECORD_FOLDER_TYPE; +import static org.alfresco.rest.rm.model.site.RMSiteCompliance.STANDARD; +import static org.alfresco.rest.rm.model.site.RMSiteFields.COMPLIANCE; +import static org.alfresco.rest.rm.model.site.RMSiteFields.DESCRIPTION; +import static org.alfresco.rest.rm.model.site.RMSiteFields.TITLE; +import static org.jglue.fluentjson.JsonBuilderFactory.buildObject; +import static org.springframework.http.HttpStatus.CREATED; +import static org.springframework.http.HttpStatus.OK; + +import com.google.gson.JsonObject; +import com.jayway.restassured.RestAssured; + +import org.alfresco.rest.RestTest; +import org.alfresco.rest.core.RestWrapper; +import org.alfresco.rest.rm.model.fileplancomponents.FilePlanComponent; +import org.alfresco.rest.rm.model.fileplancomponents.FilePlanComponentType; +import org.alfresco.rest.rm.requests.FilePlanComponentAPI; +import org.alfresco.rest.rm.requests.RMSiteAPI; +import org.alfresco.utility.data.DataUser; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.PropertySource; +import org.testng.annotations.BeforeClass; + +/** + * Base class for all IG REST API Tests + * + * @author Kristijan Conkas + * @author Tuna Aksoy + * @since 2.6 + */ +@Configuration +@PropertySource("classpath:default.properties") +@PropertySource(value = "classpath:local.properties", ignoreResourceNotFound = true) +public class BaseRestTest extends RestTest +{ + @Value ("${alfresco.scheme}") + private String scheme; + + @Value ("${alfresco.server}") + private String server; + + @Value ("${alfresco.port}") + private String port; + + @Value ("${rest.rmPath}") + private String restRmPath; + + @Value ("${rest.basePath}") + private String restCorePath; + + @Autowired + private RMSiteAPI rmSiteAPI; + + @Autowired + private DataUser dataUser; + + @Autowired + public FilePlanComponentAPI filePlanComponentAPI; + + // Constants + public static final String RM_ID = "rm"; + public static final String RM_TITLE = "Records Management"; + public static final String RM_DESCRIPTION = "Records Management Site"; + + /** + * @see org.alfresco.rest.RestTest#checkServerHealth() + */ + @Override + @BeforeClass (alwaysRun = true) + public void checkServerHealth() throws Exception + { + RestAssured.baseURI = scheme + "://" + server; + RestAssured.port = parseInt(port); + RestAssured.basePath = restRmPath; + + // Create RM Site if not exist + createRMSiteIfNotExists(); + } + + /** + * Helper method to create the RM Site via the POST request + * if the site doesn't exist + */ + public void createRMSiteIfNotExists() throws Exception + { + // Check RM site doesn't exist + if (!siteRMExists()) + { + rmSiteAPI.usingRestWrapper().authenticateUser(dataUser.getAdminUser()); + + // Build the RM site properties + JsonObject rmSiteProperties = buildObject() + .add(TITLE, RM_TITLE) + .add(DESCRIPTION, RM_DESCRIPTION) + .add(COMPLIANCE, STANDARD.toString()) + .getJson(); + + // Create the RM site + rmSiteAPI.createRMSite(rmSiteProperties); + + // Verify the status code + rmSiteAPI.usingRestWrapper().assertStatusCodeIs(CREATED); + } + } + + /** + * Check if the RM site exists via the GET request + */ + public boolean siteRMExists() throws Exception + { + RestWrapper restWrapper = rmSiteAPI.usingRestWrapper().authenticateUser(dataUser.getAdminUser()); + rmSiteAPI.getSite(); + return restWrapper.getStatusCode().equals(OK.toString()); + } + + /** + * Helper method to create child category + * + * @param parentCategoryId The id of the parent category + * @param categoryName The name of the category + * @return The created category + * @throws Exception on unsuccessful component creation + */ + public FilePlanComponent createCategory(String parentCategoryId, String categoryName) throws Exception + { + return createComponent(parentCategoryId, categoryName, RECORD_CATEGORY_TYPE, CATEGORY_TITLE); + } + + /** + * Helper method to create child folder + * + * @param parentCategoryId The id of the parent category + * @param folderName The name of the category + * @return The created category + * @throws Exception on unsuccessful component creation + */ + public FilePlanComponent createFolder(String parentCategoryId, String folderName) throws Exception + { + return createComponent(parentCategoryId, folderName, RECORD_FOLDER_TYPE, FOLDER_TITLE); + } + + /** + * Helper method to create generic child component + * + * @param parentComponentId The id of the parent file plan component + * @param componentName The name of the file plan component + * @param componentType The name of the file plan component + * @param componentTitle + * @return The created file plan component + * @throws Exception + */ + private FilePlanComponent createComponent(String parentComponentId, String componentName, FilePlanComponentType componentType, String componentTitle) throws Exception + { + RestWrapper restWrapper = filePlanComponentAPI.usingRestWrapper().authenticateUser(dataUser.getAdminUser()); + + JsonObject componentProperties = buildObject().add(NAME, componentName) + .add(NODE_TYPE, componentType.toString()) + .addObject(PROPERTIES) + .add(PROPERTIES_TITLE, componentTitle) + .end() + .getJson(); + + FilePlanComponent fpc = filePlanComponentAPI.createFilePlanComponent(componentProperties, parentComponentId); + restWrapper.assertStatusCodeIs(CREATED); + return fpc; + } + +} \ No newline at end of file diff --git a/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/base/TestData.java b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/base/TestData.java new file mode 100644 index 0000000000..45acbf1662 --- /dev/null +++ b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/base/TestData.java @@ -0,0 +1,101 @@ +/* + * #%L + * Alfresco Records Management Module + * %% + * Copyright (C) 2005 - 2016 Alfresco Software Limited + * %% + * License rights for this program may be obtained from Alfresco Software, Ltd. + * pursuant to a written agreement and any use of this program without such an + * agreement is prohibited. + * #L% + */ +package org.alfresco.rest.rm.base; + +import static org.alfresco.rest.rm.model.fileplancomponents.FilePlanComponentAlias.FILE_PLAN_ALIAS; +import static org.alfresco.rest.rm.model.fileplancomponents.FilePlanComponentAlias.HOLDS_ALIAS; +import static org.alfresco.rest.rm.model.fileplancomponents.FilePlanComponentAlias.TRANSFERS_ALIAS; +import static org.alfresco.rest.rm.model.fileplancomponents.FilePlanComponentAlias.UNFILED_RECORDS_CONTAINER_ALIAS; +import static org.alfresco.rest.rm.model.fileplancomponents.FilePlanComponentType.FILE_PLAN_TYPE; +import static org.alfresco.rest.rm.model.fileplancomponents.FilePlanComponentType.HOLD_CONTAINER_TYPE; +import static org.alfresco.rest.rm.model.fileplancomponents.FilePlanComponentType.TRANSFER_CONTAINER_TYPE; +import static org.alfresco.rest.rm.model.fileplancomponents.FilePlanComponentType.UNFILED_CONTAINER_TYPE; +import static org.alfresco.utility.data.RandomData.getRandomAlphanumeric; + +import org.testng.annotations.DataProvider; + +/** + * Test data used in tests + * + * @author Rodica Sutu + * @since 2.6 + */ +public interface TestData +{ + /** + * A user with ALFRESCO_ADMINISTRATORS role. + *

"GROUP_ANOTHER_ADMIN_EXISTS" The ANOTHER_ADMIN user has been created. + */ + public static final String ANOTHER_ADMIN = "another_admin"; + + /** + * The default password used when creating test users. + */ + public static final String DEFAULT_PASSWORD = "password"; + + /** + * The default email address used when creating test users. + */ + public static final String DEFAULT_EMAIL = "default@alfresco.com"; + + /** + * Data Provider with the special file plan components alias + * @return file plan component alias + */ + @DataProvider + public static Object[][] getContainers() + { + return new Object[][] { + { FILE_PLAN_ALIAS.toString() }, + { TRANSFERS_ALIAS.toString() }, + { HOLDS_ALIAS.toString() }, + { UNFILED_RECORDS_CONTAINER_ALIAS.toString() }, + }; + } + + /** + * Data Provider with: + * the special file plan components alias + * file plan component node type + * @return file plan component alias + */ + @DataProvider + public static Object[][] getContainersAndTypes() + { + return new Object[][] { + { FILE_PLAN_ALIAS, FILE_PLAN_TYPE }, + { TRANSFERS_ALIAS, TRANSFER_CONTAINER_TYPE }, + { HOLDS_ALIAS, HOLD_CONTAINER_TYPE }, + { UNFILED_RECORDS_CONTAINER_ALIAS, UNFILED_CONTAINER_TYPE }, + }; + } + + /** + * The default CATEGORY name used when creating categories + */ + public static String CATEGORY_NAME = "CATEGORY NAME"+ getRandomAlphanumeric(); + + /** + * The default CATEGORY title used when creating categories + */ + public static String CATEGORY_TITLE = "CATEGORY TITLE" + getRandomAlphanumeric(); + + /** + * The default FOLDER name used when creating categories + */ + public static String FOLDER_NAME = "FOLDER NAME" + getRandomAlphanumeric(); + + /** + * The default FOLDER title used when creating categories + */ + public static String FOLDER_TITLE = "FOLDER TITLE" + getRandomAlphanumeric(); +} diff --git a/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/fileplancomponents/FilePlanTests.java b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/fileplancomponents/FilePlanTests.java new file mode 100644 index 0000000000..3c9bb4b5a2 --- /dev/null +++ b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/fileplancomponents/FilePlanTests.java @@ -0,0 +1,303 @@ +/* + * #%L + * Alfresco Records Management Module + * %% + * Copyright (C) 2005 - 2016 Alfresco Software Limited + * %% + * License rights for this program may be obtained from Alfresco Software, Ltd. + * pursuant to a written agreement and any use of this program without such an + * agreement is prohibited. + * #L% + */ +package org.alfresco.rest.rm.fileplancomponents; + +import static java.util.Arrays.asList; + +import static org.alfresco.rest.rm.base.AllowableOperations.CREATE; +import static org.alfresco.rest.rm.base.AllowableOperations.DELETE; +import static org.alfresco.rest.rm.base.AllowableOperations.UPDATE; +import static org.alfresco.rest.rm.model.fileplancomponents.FilePlanComponentAlias.FILE_PLAN_ALIAS; +import static org.alfresco.rest.rm.model.fileplancomponents.FilePlanComponentFields.NAME; +import static org.alfresco.rest.rm.model.fileplancomponents.FilePlanComponentFields.NODE_TYPE; +import static org.alfresco.rest.rm.model.fileplancomponents.FilePlanComponentFields.PROPERTIES; +import static org.alfresco.rest.rm.model.fileplancomponents.FilePlanComponentFields.PROPERTIES_DESCRIPTION; +import static org.alfresco.rest.rm.model.fileplancomponents.FilePlanComponentFields.PROPERTIES_TITLE; +import static org.alfresco.utility.data.RandomData.getRandomAlphanumeric; +import static org.jglue.fluentjson.JsonBuilderFactory.buildObject; +import static org.springframework.http.HttpStatus.FORBIDDEN; +import static org.springframework.http.HttpStatus.NOT_FOUND; +import static org.springframework.http.HttpStatus.OK; +import static org.springframework.http.HttpStatus.UNPROCESSABLE_ENTITY; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertTrue; + +import com.google.gson.JsonObject; + +import org.alfresco.rest.rm.base.BaseRestTest; +import org.alfresco.rest.rm.base.TestData; +import org.alfresco.rest.rm.model.fileplancomponents.FilePlanComponent; +import org.alfresco.rest.rm.model.fileplancomponents.FilePlanComponentAlias; +import org.alfresco.rest.rm.model.fileplancomponents.FilePlanComponentType; +import org.alfresco.rest.rm.requests.FilePlanComponentAPI; +import org.alfresco.rest.rm.requests.RMSiteAPI; +import org.alfresco.utility.data.DataUser; +import org.alfresco.utility.model.UserModel; +import org.alfresco.utility.report.Bug; +import org.springframework.beans.factory.annotation.Autowired; +import org.testng.annotations.Test; + +/** + * This class contains the tests for + * the File Plan CRUD API + * + * @author Rodica Sutu + * @since 2.6 + */ +public class FilePlanTests extends BaseRestTest +{ + @Autowired + private FilePlanComponentAPI filePlanComponentAPI; + + @Autowired + private RMSiteAPI rmSiteAPI; + + @Autowired + private DataUser dataUser; + + /** + * Given that the RM site doesn't exist + * When I use the API to get the File Plan/Holds/Unfiled Records Container/Transfers + * Then I get the 404 response code + */ + @Test + ( + description = "Check the GET response code when the RM site doesn't exist", + dataProviderClass = TestData.class, + dataProvider = "getContainers" + ) + public void getFilePlanComponentWhenRMIsNotCreated(String filePlanAlias) throws Exception + { + // Check RM Site Exist + if (siteRMExists()) + { + // Delete RM Site + rmSiteAPI.deleteRMSite(); + } + + // Authenticate with admin user + filePlanComponentAPI.usingRestWrapper().authenticateUser(dataUser.getAdminUser()); + + // Get the file plan component + filePlanComponentAPI.getFilePlanComponent(filePlanAlias.toString()); + + //check the response code is NOT_FOUND + filePlanComponentAPI.usingRestWrapper().assertStatusCodeIs(NOT_FOUND); + } + + /** + * Given that a file plan exists + * When I ask the API for the details of the file plan + * Then I am given the details of the file plan + */ + @Test + ( + description = "Check the GET response for special file plan components when the RM site exit", + dataProviderClass = TestData.class, + dataProvider = "getContainersAndTypes" + ) + public void getFilePlanComponentWhenRMIsCreated(FilePlanComponentAlias filePlanAlias, FilePlanComponentType rmType) throws Exception + { + // Create RM Site if doesn't exist + createRMSiteIfNotExists(); + + // Authenticate with admin user + filePlanComponentAPI.usingRestWrapper().authenticateUser(dataUser.getAdminUser()); + + // Get the file plan special container + FilePlanComponent filePlanComponent = filePlanComponentAPI.getFilePlanComponent(filePlanAlias.toString()); + + // Check the response code + filePlanComponentAPI.usingRestWrapper().assertStatusCodeIs(OK); + + // Check the response contains the right node type + assertEquals(filePlanComponent.getNodeType(), rmType.toString()); + } + + /** + * Given that a file plan exists + * When I ask the API for the details of the file plan to include the allowableOperations property + * Then I am given the allowableOperations property with the update and create operations. + */ + @Test + ( + description = "Check the allowableOperations list returned ", + dataProviderClass = TestData.class, + dataProvider = "getContainers" + ) + public void includeAllowableOperations(String specialContainerAlias) throws Exception + { + // Create RM Site if doesn't exist + createRMSiteIfNotExists(); + + // Authenticate with admin user + filePlanComponentAPI.usingRestWrapper().authenticateUser(dataUser.getAdminUser()); + + // Get the file plan special containers with the optional parameter allowableOperations + FilePlanComponent filePlanComponent = filePlanComponentAPI.withParams("include=allowableOperations").getFilePlanComponent(specialContainerAlias); + + // Check the list of allowableOperations returned + assertTrue(filePlanComponent.getAllowableOperations().containsAll(asList(UPDATE, CREATE)), + "Wrong list of the allowable operations is return" + filePlanComponent.getAllowableOperations().toString()); + + // Check the list of allowableOperations doesn't contains DELETE operation + assertFalse(filePlanComponent.getAllowableOperations().contains(DELETE), + "The list of allowable operations contains delete option" + filePlanComponent.getAllowableOperations().toString()); + } + + /** + * Given that a file plan exists + * When I ask the API to modify the details of the file plan + * Then the details of the file are modified + * Note: the details of the file plan are limited to title and description. + */ + @Test + @Bug (id = "RM-4295") + public void updateFilePlan() throws Exception + { + String FILE_PLAN_DESCRIPTION = "Description updated " + getRandomAlphanumeric(); + String FILE_PLAN_TITLE = "Title updated " + getRandomAlphanumeric(); + + // Create RM Site if doesn't exist + createRMSiteIfNotExists(); + + // Authenticate with admin user + filePlanComponentAPI.usingRestWrapper().authenticateUser(dataUser.getAdminUser()); + + // Build the file plan root properties + JsonObject filePlanProperties = buildObject() + .addObject(PROPERTIES) + .add(PROPERTIES_TITLE, FILE_PLAN_TITLE) + .add(PROPERTIES_DESCRIPTION, FILE_PLAN_DESCRIPTION) + .end() + .getJson(); + + // Update the record category + FilePlanComponent renamedFilePlanComponent = filePlanComponentAPI.updateFilePlanComponent(filePlanProperties,FILE_PLAN_ALIAS.toString()); + + // Verify the response status code + filePlanComponentAPI.usingRestWrapper().assertStatusCodeIs(OK); + + // Verify the returned description field for the file plan component + assertEquals(renamedFilePlanComponent.getProperties().getDescription(), FILE_PLAN_DESCRIPTION); + + // Verify the returned title field for the file plan component + assertEquals(renamedFilePlanComponent.getProperties().getTitle(), FILE_PLAN_TITLE); + } + + /** + * Given that a file plan exists + * When I ask the API to delete the file plan + * Then the 403 response code is returned. + */ + @Test + ( + description = "Check the response code when deleting the special file plan components", + dataProviderClass = TestData.class, + dataProvider = "getContainers" + ) + public void deleteFilePlanSpecialComponents(String filePlanAlias) throws Exception + { + // Create RM Site if doesn't exist + createRMSiteIfNotExists(); + + // Authenticate with admin user + filePlanComponentAPI.usingRestWrapper().authenticateUser(dataUser.getAdminUser()); + + // Delete the file plan component + filePlanComponentAPI.deleteFilePlanComponent(filePlanAlias.toString()); + + // Check the DELETE response status code + filePlanComponentAPI.usingRestWrapper().assertStatusCodeIs(FORBIDDEN); + } + + /** + * Given that RM site exists + * When I ask to create the file plan + * Then the 403 response code is returned. + */ + @Test + ( + description = "Check the response code when creating the special file plan components", + dataProviderClass = TestData.class, + dataProvider = "getContainersAndTypes" + ) + @Bug(id="RM-4296") + public void createFilePlanSpecialContainerWhenExists(FilePlanComponentAlias filePlanAlias, FilePlanComponentType rmType) throws Exception + { + // Create RM Site if doesn't exist + createRMSiteIfNotExists(); + + // Authenticate with admin user + rmSiteAPI.usingRestWrapper().authenticateUser(dataUser.getAdminUser()); + // Get the RM site ID + String rmSiteId = rmSiteAPI.getSite().getGuid(); + + String name = filePlanAlias + getRandomAlphanumeric(); + + // Build the file plan root properties + JsonObject componentProperties = buildObject() + .add(NAME, name) + .add(NODE_TYPE, rmType.toString()) + .getJson(); + + // Authenticate with admin user + filePlanComponentAPI.usingRestWrapper().authenticateUser(dataUser.getAdminUser()); + // Create the special containers into RM site - parent folder + filePlanComponentAPI.createFilePlanComponent(componentProperties, rmSiteId); + filePlanComponentAPI.usingRestWrapper().assertStatusCodeIs(UNPROCESSABLE_ENTITY); + + // Create the special containers into RM site - parent folder + filePlanComponentAPI.createFilePlanComponent(componentProperties, FILE_PLAN_ALIAS.toString()); + filePlanComponentAPI.usingRestWrapper().assertStatusCodeIs(UNPROCESSABLE_ENTITY); + + // Create the special containers into the root of special containers containers + filePlanComponentAPI.createFilePlanComponent(componentProperties, filePlanAlias.toString()); + filePlanComponentAPI.usingRestWrapper().assertStatusCodeIs(UNPROCESSABLE_ENTITY); + } + + /** + * Given that RM site exists + * When a non-RM user ask the API for the details of the file plan + * Then the status code 403 (Permission denied) is return + */ + @Test + ( + description = "Check the response code when the RM site containers are get with non rm users", + dataProviderClass = TestData.class, + dataProvider = "getContainers" + ) + public void getSpecialFilePlanComponentsWithNonRMuser(String filePlanAlias) throws Exception + { + // Create RM Site if doesn't exist + createRMSiteIfNotExists(); + + // Disconnect user from REST API session + rmSiteAPI.usingRestWrapper().disconnect(); + + // Authenticate admin user to Alfresco REST API + restClient.authenticateUser(dataUser.getAdminUser()); + + // Create a random user + UserModel nonRMuser = dataUser.createRandomTestUser("testUser"); + + // Authenticate using the random user + filePlanComponentAPI.usingRestWrapper().authenticateUser(nonRMuser); + + // Get the special file plan components + filePlanComponentAPI.getFilePlanComponent(filePlanAlias.toString()); + + // Check the response status code is FORBIDDEN + filePlanComponentAPI.usingRestWrapper().assertStatusCodeIs(FORBIDDEN); + } +} diff --git a/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/fileplancomponents/RecordCategoryTest.java b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/fileplancomponents/RecordCategoryTest.java new file mode 100644 index 0000000000..2a6c30f329 --- /dev/null +++ b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/fileplancomponents/RecordCategoryTest.java @@ -0,0 +1,374 @@ +/* + * #%L + * Alfresco Records Management Module + * %% + * Copyright (C) 2005 - 2016 Alfresco Software Limited + * %% + * License rights for this program may be obtained from Alfresco Software, Ltd. + * pursuant to a written agreement and any use of this program without such an + * agreement is prohibited. + * #L% + */ +package org.alfresco.rest.rm.fileplancomponents; + +import static org.alfresco.rest.rm.model.fileplancomponents.FilePlanComponentAlias.FILE_PLAN_ALIAS; +import static org.alfresco.rest.rm.model.fileplancomponents.FilePlanComponentFields.NAME; +import static org.alfresco.rest.rm.model.fileplancomponents.FilePlanComponentFields.NODE_TYPE; +import static org.alfresco.rest.rm.model.fileplancomponents.FilePlanComponentFields.PROPERTIES; +import static org.alfresco.rest.rm.model.fileplancomponents.FilePlanComponentFields.PROPERTIES_TITLE; +import static org.alfresco.rest.rm.model.fileplancomponents.FilePlanComponentType.RECORD_CATEGORY_TYPE; +import static org.alfresco.rest.rm.model.fileplancomponents.FilePlanComponentType.RECORD_FOLDER_TYPE; +import static org.alfresco.utility.data.RandomData.getRandomAlphanumeric; +import static org.jglue.fluentjson.JsonBuilderFactory.buildObject; +import static org.springframework.http.HttpStatus.CREATED; +import static org.springframework.http.HttpStatus.NOT_FOUND; +import static org.springframework.http.HttpStatus.NO_CONTENT; +import static org.springframework.http.HttpStatus.OK; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.fail; + +import java.util.ArrayList; +import java.util.NoSuchElementException; + +import com.google.gson.JsonObject; + +import org.alfresco.rest.rm.base.BaseRestTest; +import org.alfresco.rest.core.RestWrapper; +import org.alfresco.rest.rm.model.fileplancomponents.FilePlanComponent; +import org.alfresco.rest.rm.model.fileplancomponents.FilePlanComponentProperties; +import org.alfresco.rest.rm.model.fileplancomponents.FilePlanComponentType; +import org.alfresco.rest.rm.model.fileplancomponents.FilePlanComponentsCollection; +import org.alfresco.rest.rm.requests.FilePlanComponentAPI; +import org.alfresco.utility.data.DataUser; +import org.springframework.beans.factory.annotation.Autowired; +import org.testng.annotations.Test; + +/** + * Record category related API tests + * + * @author Kristijan Conkas + * @author Tuna Aksoy + * @since 2.6 + */ +public class RecordCategoryTest extends BaseRestTest +{ + @Autowired + private FilePlanComponentAPI filePlanComponentAPI; + + @Autowired + private DataUser dataUser; + + // Number of children (for children creation test) + private static final int NUMBER_OF_CHILDREN = 10; + + /** + *

+     * Given that a file plan exists
+     * When I ask the API to create a root record category
+     * Then it is created as a root record category
+     */
+    @Test
+    (
+        description = "Create root category"
+    )
+    public void createCategoryTest() throws Exception
+    {
+        // Authenticate with admin user
+        RestWrapper restWrapper = filePlanComponentAPI.usingRestWrapper().authenticateUser(dataUser.getAdminUser());
+
+        String categoryName = "Category name " + getRandomAlphanumeric();
+        String categoryTitle = "Category title " + getRandomAlphanumeric();
+
+        // Build the record category properties
+        JsonObject recordCategoryProperties = buildObject().
+                add(NAME, categoryName).
+                add(NODE_TYPE, RECORD_CATEGORY_TYPE.toString()).
+                addObject(PROPERTIES).
+                    add(PROPERTIES_TITLE, categoryTitle).
+                    end().
+                getJson();
+
+        // Create the record category
+        FilePlanComponent filePlanComponent = filePlanComponentAPI.createFilePlanComponent(recordCategoryProperties, FILE_PLAN_ALIAS.toString());
+
+        // Verify the status code
+        restWrapper.assertStatusCodeIs(CREATED);
+
+        // Verify the returned file plan component
+        assertTrue(filePlanComponent.isIsCategory());
+        assertFalse(filePlanComponent.isIsFile());
+        assertFalse(filePlanComponent.isIsRecordFolder());
+
+        assertEquals(filePlanComponent.getName(), categoryName);
+        assertEquals(filePlanComponent.getNodeType(), RECORD_CATEGORY_TYPE.toString());
+        assertFalse(filePlanComponent.isHasRetentionSchedule());
+
+        assertEquals(filePlanComponent.getCreatedByUser().getId(), dataUser.getAdminUser().getUsername());
+
+        // Verify the returned file plan component properties
+        FilePlanComponentProperties filePlanComponentProperties = filePlanComponent.getProperties();
+        assertEquals(filePlanComponentProperties.getTitle(), categoryTitle);
+
+        logger.info("Aspects: " + filePlanComponent.getAspectNames());
+    }
+
+    /**
+     * 
+     * Given that a record category exists
+     * When I ask the API to update the details of the record category
+     * Then the details of the record category are updated
+     */
+    @Test
+    (
+        description = "Rename root category"
+    )
+    public void renameCategory() throws Exception
+    {
+        // Authenticate with admin user
+        RestWrapper restWrapper = filePlanComponentAPI.usingRestWrapper().authenticateUser(dataUser.getAdminUser());
+
+        // Create record category first
+        String categoryName = "Category name " + getRandomAlphanumeric();
+        String categoryTitle = "Category title " + getRandomAlphanumeric();
+
+        // Build the record category properties
+        JsonObject recordCategoryProperties = buildObject().
+                add(NAME, categoryName).
+                add(NODE_TYPE, RECORD_CATEGORY_TYPE.toString()).
+                addObject(PROPERTIES).
+                    add(PROPERTIES_TITLE, categoryTitle).
+                    end().
+                getJson();
+
+        // Create the record category
+        FilePlanComponent filePlanComponent = filePlanComponentAPI.createFilePlanComponent(recordCategoryProperties, FILE_PLAN_ALIAS.toString());
+
+        String newCategoryName = "Rename " + categoryName;
+
+        // Build the properties which will be updated
+        JsonObject updateRecordCategoryProperties = buildObject().
+                add(NAME, newCategoryName).
+                getJson();
+
+        // Update the record category
+        FilePlanComponent renamedFilePlanComponent = filePlanComponentAPI.updateFilePlanComponent(updateRecordCategoryProperties, filePlanComponent.getId());
+
+        // Verify the status code
+        restWrapper.assertStatusCodeIs(OK);
+
+        // Verify the returned file plan component
+        assertEquals(renamedFilePlanComponent.getName(), newCategoryName);
+
+        // Get actual FILE_PLAN_ALIAS id
+        FilePlanComponent parentComponent = filePlanComponentAPI.getFilePlanComponent(FILE_PLAN_ALIAS.toString());
+
+        // verify renamed component still has this parent
+        assertEquals(renamedFilePlanComponent.getParentId(), parentComponent.getId());
+    }
+
+    /**
+     * 
+     * Given that a record category exists
+     * When I ask the API to delete the record category
+     * Then the record category and all its contents is deleted
+     */
+    @Test
+    (
+        description = "Delete category"
+    )
+    public void deleteCategory() throws Exception
+    {
+        // Authenticate with admin user
+        RestWrapper restWrapper = filePlanComponentAPI.usingRestWrapper().authenticateUser(dataUser.getAdminUser());
+
+        // Create record category first
+        String categoryName = "Category name " + getRandomAlphanumeric();
+        String categoryTitle = "Category title " + getRandomAlphanumeric();
+
+        // Build the record category properties
+        JsonObject recordCategoryProperties = buildObject().
+                add(NAME, categoryName).
+                add(NODE_TYPE, RECORD_CATEGORY_TYPE.toString()).
+                addObject(PROPERTIES).
+                    add(PROPERTIES_TITLE, categoryTitle).
+                    end().
+                getJson();
+
+        // Create the record category
+        FilePlanComponent filePlanComponent = filePlanComponentAPI.createFilePlanComponent(recordCategoryProperties, FILE_PLAN_ALIAS.toString());
+
+        // Delete the record category
+        filePlanComponentAPI.deleteFilePlanComponent(filePlanComponent.getId());
+
+        // Verify the status code
+        restWrapper.assertStatusCodeIs(NO_CONTENT);
+
+        // Deleted component should no longer be retrievable
+        filePlanComponentAPI.getFilePlanComponent(filePlanComponent.getId());
+        restWrapper.assertStatusCodeIs(NOT_FOUND);
+    }
+
+    /**
+     * 
+     * Given that a record category exists
+     * When I ask the API to create a record category
+     * Then it is created within the record category
+     */
+    @Test
+    (
+        description = "Create child category"
+    )
+    public void createSubcategory() throws Exception
+    {
+        // Create root level category
+        FilePlanComponent rootCategory = createCategory(FILE_PLAN_ALIAS.toString(), getRandomAlphanumeric());
+        assertNotNull(rootCategory.getId());
+
+        // Create subcategory as a child of rootCategory
+        FilePlanComponent childCategory = createCategory(rootCategory.getId(), getRandomAlphanumeric());
+
+        // Child category created?
+        assertNotNull(childCategory.getId());
+
+        // Verify child category
+        assertEquals(childCategory.getParentId(), rootCategory.getId());
+        assertTrue(childCategory.isIsCategory());
+        assertFalse(childCategory.isIsFile());
+        assertFalse(childCategory.isIsRecordFolder());
+        assertEquals(childCategory.getNodeType(), RECORD_CATEGORY_TYPE.toString());
+    }
+
+    /**
+     * 
+     * Given that a record category exists
+     * And contains a number of record categories and record folders
+     * When I ask the APi to get me the children of the record category
+     * Then I am returned the contained record categories and record folders
+     * And their details
+     */
+    @Test
+    (
+        description = "List children of a category"
+    )
+    public void listChildren() throws Exception
+    {
+        // Create root level category
+        FilePlanComponent rootCategory = createCategory(FILE_PLAN_ALIAS.toString(), getRandomAlphanumeric());
+        assertNotNull(rootCategory.getId());
+
+        // Add child categories/folders
+        ArrayList children = new ArrayList();
+        for (int i=0; i < NUMBER_OF_CHILDREN; i++)
+        {
+            // Create a child
+            FilePlanComponent child = createComponent(rootCategory.getId(),
+                getRandomAlphanumeric(),
+                // half of the children should be subcategories, the other subfolders
+                (i <= NUMBER_OF_CHILDREN / 2) ? RECORD_CATEGORY_TYPE : RECORD_FOLDER_TYPE);
+            assertNotNull(child.getId());
+            children.add(child);
+        }
+
+        // Authenticate with admin user
+        RestWrapper restWrapper = filePlanComponentAPI.usingRestWrapper().authenticateUser(dataUser.getAdminUser());
+
+        // List children from API
+        FilePlanComponentsCollection apiChildren = filePlanComponentAPI.listChildComponents(rootCategory.getId());
+
+        // Check status code
+        restWrapper.assertStatusCodeIs(OK);
+        logger.info("parent: " + rootCategory.getId());
+
+        // Check listed children against created list
+        apiChildren.getEntries().forEach(c ->
+        {
+            FilePlanComponent filePlanComponent = c.getFilePlanComponent();
+            assertNotNull(filePlanComponent.getId());
+            logger.info("Checking child " + filePlanComponent.getId());
+
+            try
+            {
+                // Find this child in created children list
+                FilePlanComponent createdComponent = children.stream()
+                    .filter(child -> child.getId().equals(filePlanComponent.getId()))
+                    .findFirst()
+                    .get();
+
+                // Created by
+                assertEquals(filePlanComponent.getCreatedByUser().getId(), dataUser.getAdminUser().getUsername());
+
+                // Is parent Id set correctly?
+                assertEquals(filePlanComponent.getParentId(), rootCategory.getId());
+
+                // Only categories or folders have been created
+                assertFalse(filePlanComponent.isIsFile());
+
+                // Boolean properties related to node type
+                // Only RECORD_CATEGORY_TYPE and RECORD_FOLDER_TYPE have been created
+                if (filePlanComponent.getNodeType().equals(RECORD_CATEGORY_TYPE.toString()))
+                {
+                    assertTrue(filePlanComponent.isIsCategory());
+                    assertFalse(filePlanComponent.isIsRecordFolder());
+                }
+                else
+                {
+                    assertTrue(filePlanComponent.isIsRecordFolder());
+                    assertFalse(filePlanComponent.isIsCategory());
+                }
+
+                // Does returned object have the same contents as the created one?
+                assertEquals(createdComponent.getName(), filePlanComponent.getName());
+                assertEquals(createdComponent.getNodeType(), filePlanComponent.getNodeType());
+
+                // Verify properties
+                // FIXME: Verify properties
+            }
+            catch (NoSuchElementException e)
+            {
+                fail("No child element for " + filePlanComponent.getId());
+            }
+        });
+    }
+
+    /**
+     * Helper method to create child category
+     *
+     * @param parentCategoryId The id of the parent category
+     * @param categoryName The name of the category
+     * @return The created category
+     * @throws Exception on unsuccessful component creation
+     */
+    public FilePlanComponent createCategory(String parentCategoryId, String categoryName) throws Exception
+    {
+        return createComponent(parentCategoryId, categoryName, RECORD_CATEGORY_TYPE);
+    }
+
+    /**
+     * Helper method to create generic child component
+     *
+     * @param parentComponentId The id of the parent file plan component
+     * @param componentName The name of the file plan component
+     * @param componentType The name of the file plan component
+     * @return The created file plan component
+     * @throws Exception
+     */
+    private FilePlanComponent createComponent(String parentComponentId, String componentName, FilePlanComponentType componentType) throws Exception
+    {
+        RestWrapper restWrapper = filePlanComponentAPI.usingRestWrapper().authenticateUser(dataUser.getAdminUser());
+
+        JsonObject componentProperties = buildObject().
+            add(NAME, componentName).
+            add(NODE_TYPE, componentType.toString()).
+            addObject(PROPERTIES).
+                add(PROPERTIES_TITLE, "Title for " + componentName).
+                end().
+            getJson();
+
+        FilePlanComponent fpc = filePlanComponentAPI.createFilePlanComponent(componentProperties, parentComponentId);
+        restWrapper.assertStatusCodeIs(CREATED);
+        return fpc;
+    }
+}
diff --git a/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/fileplancomponents/RecordFolderTests.java b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/fileplancomponents/RecordFolderTests.java
new file mode 100644
index 0000000000..9b0fd45e1a
--- /dev/null
+++ b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/fileplancomponents/RecordFolderTests.java
@@ -0,0 +1,368 @@
+/*
+ * #%L
+ * Alfresco Records Management Module
+ * %%
+ * Copyright (C) 2005 - 2016 Alfresco Software Limited
+ * %%
+ * License rights for this program may be obtained from Alfresco Software, Ltd.
+ * pursuant to a written agreement and any use of this program without such an
+ * agreement is prohibited.
+ * #L%
+ */
+package org.alfresco.rest.rm.fileplancomponents;
+
+import static org.alfresco.rest.rm.base.TestData.CATEGORY_NAME;
+import static org.alfresco.rest.rm.base.TestData.FOLDER_NAME;
+import static org.alfresco.rest.rm.base.TestData.FOLDER_TITLE;
+import static org.alfresco.rest.rm.model.fileplancomponents.FilePlanComponentAlias.FILE_PLAN_ALIAS;
+import static org.alfresco.rest.rm.model.fileplancomponents.FilePlanComponentFields.IS_CLOSED;
+import static org.alfresco.rest.rm.model.fileplancomponents.FilePlanComponentFields.NAME;
+import static org.alfresco.rest.rm.model.fileplancomponents.FilePlanComponentFields.NODE_TYPE;
+import static org.alfresco.rest.rm.model.fileplancomponents.FilePlanComponentFields.PROPERTIES;
+import static org.alfresco.rest.rm.model.fileplancomponents.FilePlanComponentFields.PROPERTIES_DESCRIPTION;
+import static org.alfresco.rest.rm.model.fileplancomponents.FilePlanComponentFields.PROPERTIES_LOCATION;
+import static org.alfresco.rest.rm.model.fileplancomponents.FilePlanComponentFields.PROPERTIES_REVIEW_PERIOD;
+import static org.alfresco.rest.rm.model.fileplancomponents.FilePlanComponentFields.PROPERTIES_TITLE;
+import static org.alfresco.rest.rm.model.fileplancomponents.FilePlanComponentFields.PROPERTIES_VITAL_RECORD_INDICATOR;
+import static org.alfresco.rest.rm.model.fileplancomponents.FilePlanComponentType.RECORD_FOLDER_TYPE;
+import static org.alfresco.utility.data.RandomData.getRandomAlphanumeric;
+import static org.jglue.fluentjson.JsonBuilderFactory.buildObject;
+import static org.springframework.http.HttpStatus.CREATED;
+import static org.springframework.http.HttpStatus.NOT_FOUND;
+import static org.springframework.http.HttpStatus.NO_CONTENT;
+import static org.springframework.http.HttpStatus.OK;
+import static org.springframework.http.HttpStatus.UNPROCESSABLE_ENTITY;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.fail;
+import static org.testng.AssertJUnit.assertTrue;
+
+import java.util.ArrayList;
+import java.util.NoSuchElementException;
+
+import com.google.gson.JsonObject;
+
+import org.alfresco.rest.core.RestWrapper;
+import org.alfresco.rest.rm.base.BaseRestTest;
+import org.alfresco.rest.rm.base.TestData;
+import org.alfresco.rest.rm.model.fileplancomponents.FilePlanComponent;
+import org.alfresco.rest.rm.model.fileplancomponents.FilePlanComponentProperties;
+import org.alfresco.rest.rm.model.fileplancomponents.FilePlanComponentsCollection;
+import org.alfresco.rest.rm.requests.FilePlanComponentAPI;
+import org.alfresco.utility.data.DataUser;
+import org.alfresco.utility.report.Bug;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.Test;
+
+/**
+ * This class contains the tests for the
+ * the Record Folder CRUD API
+ *
+ * @author Rodica Sutu
+ * @since 2.6
+ */
+public class RecordFolderTests extends BaseRestTest
+{
+    @Autowired
+    public FilePlanComponentAPI filePlanComponentAPI;
+
+    @Autowired
+    public DataUser dataUser;
+
+    private static final int NUMBER_OF_FOLDERS= 5;
+    /**
+     * Given that a record category exists
+     * When I use the API to create a new record folder
+     * Then it is created within the record category
+     */
+    @Test
+    (
+        description = "Create a folder into a record category"
+    )
+    public void createFolderTest() throws Exception
+    {
+        String CATEGORY = CATEGORY_NAME + getRandomAlphanumeric();
+        // Authenticate with admin user
+        filePlanComponentAPI.usingRestWrapper().authenticateUser(dataUser.getAdminUser());
+        FilePlanComponent filePlanComponent=createCategory(FILE_PLAN_ALIAS.toString(), CATEGORY);
+
+        // Build the record category properties
+        JsonObject recordFolderProperties = buildObject()
+                .add(NAME, FOLDER_NAME)
+                .add(NODE_TYPE, RECORD_FOLDER_TYPE.toString())
+                .addObject(PROPERTIES)
+                .add(PROPERTIES_TITLE, FOLDER_TITLE)
+                .end()
+                .getJson();
+
+        // Create the record folder
+        FilePlanComponent folder = filePlanComponentAPI.createFilePlanComponent(recordFolderProperties, filePlanComponent.getId());
+        filePlanComponentAPI.usingRestWrapper().assertStatusCodeIs(CREATED);
+        // Check folder has been created  within the category created
+        assertEquals(filePlanComponent.getId(),folder.getParentId());
+        // Verify the returned properties for the file plan component - record folder
+        assertFalse(folder.isIsCategory());
+        assertFalse(folder.isIsFile());
+        assertTrue(folder.isIsRecordFolder());
+
+        assertEquals(folder.getName(), FOLDER_NAME);
+        assertEquals(folder.getNodeType(), RECORD_FOLDER_TYPE.toString());
+        assertEquals(folder.getCreatedByUser().getId(), dataUser.getAdminUser().getUsername());
+
+        // Verify the returned file plan component properties
+        FilePlanComponentProperties folderProperties = folder.getProperties();
+        assertEquals(folderProperties.getTitle(), FOLDER_TITLE);
+    }
+
+    /**
+     * Given that RM site is created
+     * When I use the API to create a new record folder into transfers container/holds container/unfiled
+     * Then the operation fails
+     */
+    @Test
+    (
+        description = "Create a folder into hold/transfers/unfiled/file plan  container",
+        dataProviderClass = TestData.class,
+        dataProvider = "getContainers"
+    )
+    @Bug(id="RM-4327")
+    public void createFolderIntoSpecialContainers(String filePlanComponent) throws Exception
+    {
+        // Authenticate with admin user
+        filePlanComponentAPI.usingRestWrapper().authenticateUser(dataUser.getAdminUser());
+
+        String componentID = filePlanComponentAPI.getFilePlanComponent(filePlanComponent).getId();
+
+        // Build the record category properties
+        JsonObject recordFolderProperties = buildObject()
+                .add(NAME, FOLDER_NAME)
+                .add(NODE_TYPE, RECORD_FOLDER_TYPE.toString())
+                .addObject(PROPERTIES)
+                .add(PROPERTIES_TITLE, FOLDER_TITLE)
+                .end()
+                .getJson();
+
+        // Create a record folder
+        filePlanComponentAPI.createFilePlanComponent(recordFolderProperties, componentID);
+
+        // Check the API Response code
+        filePlanComponentAPI.usingRestWrapper().assertStatusCodeIs(UNPROCESSABLE_ENTITY);
+    }
+
+    /**
+     * Given that a record folder exists
+     * When I ask for the details of a record folder
+     * Then I am given the details of a record folder
+     */
+    @Test
+    (
+        description = "Check the details returned for a record folder"
+    )
+    public void checkTheRecordFolderProperties() throws Exception
+    {
+        String CATEGORY=CATEGORY_NAME + getRandomAlphanumeric();
+        // Authenticate with admin user
+        filePlanComponentAPI.usingRestWrapper().authenticateUser(dataUser.getAdminUser());
+        FilePlanComponent category = createCategory(FILE_PLAN_ALIAS.toString(), CATEGORY);
+        FilePlanComponent folder =createFolder(category.getId(),FOLDER_NAME);
+
+        FilePlanComponent folderDetails=filePlanComponentAPI.withParams("include="+IS_CLOSED).getFilePlanComponent(folder.getId());
+
+        // Verify the returned properties for the file plan component - record folder
+        assertEquals(RECORD_FOLDER_TYPE.toString(),folderDetails.getNodeType());
+        assertTrue(folderDetails.isIsRecordFolder());
+        assertFalse(folderDetails.isIsCategory());
+        assertFalse(folderDetails.isIsFile());
+        assertFalse(folderDetails.isClosed());
+
+        assertEquals(FOLDER_NAME,folderDetails.getName());
+        assertEquals(dataUser.getAdminUser().getUsername(),folderDetails.getCreatedByUser().getId());
+        assertEquals(dataUser.getAdminUser().getUsername(), folderDetails.getModifiedByUser().getId());
+        assertEquals(FOLDER_TITLE,folderDetails.getProperties().getTitle());
+
+    }
+
+
+    /**
+     * Given that a record folder exists
+     * When I use the API to update its details
+     * Then the details of the record folder are updated
+     * The above test does treat any  custom metadata
+     * Note: the details of the record folder includes any custom meta-data
+     */
+    @Test
+    (
+        description = "Update the details returned for a record folder"
+    )
+    public void updateTheRecordFolderProperties() throws Exception
+    {
+        String CATEGORY = CATEGORY_NAME + getRandomAlphanumeric();
+        // Authenticate with admin user
+        filePlanComponentAPI.usingRestWrapper().authenticateUser(dataUser.getAdminUser());
+        FilePlanComponent category = createCategory(FILE_PLAN_ALIAS.toString(), CATEGORY);
+        FilePlanComponent folder = createFolder(category.getId(), FOLDER_NAME);
+
+        // Create record category first
+        String folderDescription = "The folder description is updated" + getRandomAlphanumeric();
+        String folderName= "The folder name is updated" + getRandomAlphanumeric();
+        String folderTitle = "Update title " + getRandomAlphanumeric();
+        String location="Location"+getRandomAlphanumeric();
+        String review_period="month|1";
+
+        // Build the file plan root properties
+        JsonObject folderProperties = buildObject()
+                .add(NAME, folderName)
+                .addObject(PROPERTIES)
+                .add(PROPERTIES_TITLE, folderTitle)
+                .add(PROPERTIES_DESCRIPTION, folderDescription)
+                .add(PROPERTIES_VITAL_RECORD_INDICATOR,true)
+                .add(PROPERTIES_REVIEW_PERIOD, review_period)
+                .add(PROPERTIES_LOCATION, location)
+                .end()
+                .getJson();
+
+        // Update the record category
+        FilePlanComponent folderUpdated = filePlanComponentAPI.updateFilePlanComponent(folderProperties, folder.getId());
+
+        // Check the Response Status Code
+        filePlanComponentAPI.usingRestWrapper().assertStatusCodeIs(OK);
+
+        // Verify the returned properties for the file plan component - record folder
+        assertEquals(folderName, folderUpdated.getName());
+        assertEquals(folderDescription, folderUpdated.getProperties().getDescription());
+        assertEquals(folderTitle, folderUpdated.getProperties().getTitle());
+        assertTrue(folderUpdated.getProperties().isVitalRecord());
+        assertEquals(location, folderUpdated.getProperties().getLocation());
+        assertNotNull(folderUpdated.getProperties().getReviewPeriod().getPeriodType());
+        assertNotNull(folderUpdated.getProperties().getReviewPeriod().getExpression());
+
+
+    }
+
+    /**
+     * Given that a record folder exists
+     * When I use the API to delete the record folder
+     * Then it deleted according to the normal rules governing the deletion of record folders
+     */
+    @Test
+    (
+        description = "Delete record folder"
+    )
+    public void deleteRecordFolder() throws Exception
+    {
+        String CATEGORY = CATEGORY_NAME + getRandomAlphanumeric();
+
+        // Authenticate with admin user
+        filePlanComponentAPI.usingRestWrapper().authenticateUser(dataUser.getAdminUser());
+        FilePlanComponent category = createCategory(FILE_PLAN_ALIAS.toString(), CATEGORY);
+        FilePlanComponent folder = createFolder(category.getId(), FOLDER_NAME);
+        // Delete the Record folder
+        filePlanComponentAPI.deleteFilePlanComponent(folder.getId());
+        // Check the Response Status Code
+        filePlanComponentAPI.usingRestWrapper().assertStatusCodeIs(NO_CONTENT);
+        // Check the File Plan Component is not found
+        filePlanComponentAPI.getFilePlanComponent(folder.getId());
+        // Check the Response Status Code
+        filePlanComponentAPI.usingRestWrapper().assertStatusCodeIs(NOT_FOUND);
+    }
+
+    /**
+     * Given that a record category exists
+     * And contains several record folders
+     * When I use the APi to get the file plan component children for the existing category
+     * Then I am provided with a list of the contained record folders
+     * And their details
+    */
+    @Test
+    (
+        description = "List children of a category"
+    )
+    public void listFolders() throws Exception
+    {
+
+        String CATEGORY = CATEGORY_NAME + getRandomAlphanumeric();
+
+        // Authenticate with admin user
+        filePlanComponentAPI.usingRestWrapper().authenticateUser(dataUser.getAdminUser());
+        FilePlanComponent category = createCategory(FILE_PLAN_ALIAS.toString(), CATEGORY);
+
+        // Add child olders
+        ArrayList children = new ArrayList();
+        for (int i = 0; i < NUMBER_OF_FOLDERS; i++)
+        {
+            // Create a child
+            FilePlanComponent child = createFolder(category.getId(),
+                    getRandomAlphanumeric());
+            assertNotNull(child.getId());
+            children.add(child);
+        }
+
+        // Authenticate with admin user
+        RestWrapper restWrapper = filePlanComponentAPI.usingRestWrapper().authenticateUser(dataUser.getAdminUser());
+
+        // List children from API
+        FilePlanComponentsCollection apiChildren = filePlanComponentAPI.listChildComponents(category.getId());
+
+        // Check status code
+        restWrapper.assertStatusCodeIs(OK);
+
+        // Check listed children against created list
+        apiChildren.getEntries().forEach(c ->
+                {
+                    FilePlanComponent filePlanComponent = c.getFilePlanComponent();
+                    assertNotNull(filePlanComponent.getId());
+                    logger.info("Checking child " + filePlanComponent.getId());
+
+                    try
+                    {
+                        // Find this child in created children list
+                        FilePlanComponent createdComponent = children.stream()
+                                                                     .filter(child -> child.getId().equals(filePlanComponent.getId()))
+                                                                     .findFirst()
+                                                                     .get();
+
+                        // Created by
+                        assertEquals(filePlanComponent.getCreatedByUser().getId(), dataUser.getAdminUser().getUsername());
+
+                        // Is parent Id set correctly
+                        assertEquals(filePlanComponent.getParentId(), category.getId());
+                        assertFalse(filePlanComponent.isIsFile());
+
+                        // Boolean properties related to node type
+                        assertTrue(filePlanComponent.isIsRecordFolder());
+                        assertFalse(filePlanComponent.isIsCategory());
+
+                        assertEquals(createdComponent.getName(), filePlanComponent.getName());
+                        assertEquals(createdComponent.getNodeType(), filePlanComponent.getNodeType());
+
+                    }
+                    catch (NoSuchElementException e)
+                    {
+                        fail("No child element for " + filePlanComponent.getId());
+                    }
+                }
+            );
+
+    }
+    @AfterClass (alwaysRun = true)
+    public void tearDown() throws Exception
+    {
+        filePlanComponentAPI.usingRestWrapper().authenticateUser(dataUser.getAdminUser());
+        filePlanComponentAPI.listChildComponents(FILE_PLAN_ALIAS.toString()).getEntries().forEach(filePlanComponentEntry ->
+        {
+            try
+            {
+                filePlanComponentAPI.deleteFilePlanComponent(filePlanComponentEntry.getFilePlanComponent().getId());
+            }
+            catch (Exception e)
+            {
+                e.printStackTrace();
+            }
+        });
+    }
+
+
+
+}
diff --git a/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/site/RMSiteTests.java b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/site/RMSiteTests.java
new file mode 100644
index 0000000000..3919935fac
--- /dev/null
+++ b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/site/RMSiteTests.java
@@ -0,0 +1,346 @@
+/*
+ * #%L
+ * Alfresco Records Management Module
+ * %%
+ * Copyright (C) 2005 - 2016 Alfresco Software Limited
+ * %%
+ * License rights for this program may be obtained from Alfresco Software, Ltd.
+ * pursuant to a written agreement and any use of this program without such an
+ * agreement is prohibited.
+ * #L%
+ */
+package org.alfresco.rest.rm.site;
+
+import static org.alfresco.rest.rm.base.TestData.ANOTHER_ADMIN;
+import static org.alfresco.rest.rm.base.TestData.DEFAULT_EMAIL;
+import static org.alfresco.rest.rm.base.TestData.DEFAULT_PASSWORD;
+import static org.alfresco.rest.rm.model.site.RMSiteCompliance.DOD5015;
+import static org.alfresco.rest.rm.model.site.RMSiteCompliance.STANDARD;
+import static org.alfresco.rest.rm.model.site.RMSiteFields.COMPLIANCE;
+import static org.alfresco.rest.rm.model.site.RMSiteFields.DESCRIPTION;
+import static org.alfresco.rest.rm.model.site.RMSiteFields.TITLE;
+import static org.jglue.fluentjson.JsonBuilderFactory.buildObject;
+import static org.springframework.http.HttpStatus.BAD_REQUEST;
+import static org.springframework.http.HttpStatus.CONFLICT;
+import static org.springframework.http.HttpStatus.CREATED;
+import static org.springframework.http.HttpStatus.FORBIDDEN;
+import static org.springframework.http.HttpStatus.NOT_FOUND;
+import static org.springframework.http.HttpStatus.NO_CONTENT;
+import static org.springframework.http.HttpStatus.OK;
+import static org.springframework.social.alfresco.api.entities.Site.Visibility.PUBLIC;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+
+import com.google.gson.JsonObject;
+
+import org.alfresco.dataprep.UserService;
+import org.alfresco.rest.rm.base.BaseRestTest;
+import org.alfresco.rest.core.RestWrapper;
+import org.alfresco.rest.rm.model.site.RMSite;
+import org.alfresco.rest.rm.requests.RMSiteAPI;
+import org.alfresco.utility.constants.UserRole;
+import org.alfresco.utility.data.DataUser;
+import org.alfresco.utility.data.RandomData;
+import org.alfresco.utility.model.UserModel;
+import org.alfresco.utility.report.Bug;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.testng.annotations.Test;
+
+/**
+ * This class contains the tests for
+ * the RM site CRUD API
+ *
+ * @author Rodica Sutu
+ * @since 2.6
+ */
+public class RMSiteTests extends BaseRestTest
+{
+    @Autowired
+    private UserService userService;
+
+    @Autowired
+    private RMSiteAPI rmSiteAPI;
+
+    @Autowired
+    private DataUser dataUser;
+
+    /**
+     * Given that RM module is installed
+     * When I want to create the RM site with specific title, description and compliance
+     * Then the RM site is created
+     */
+    @Test
+    (
+        description = "Create RM site with Standard Compliance as admin user"
+    )
+    public void createRMSiteAsAdminUser() throws Exception
+    {
+        // Authenticate with admin user
+        rmSiteAPI.usingRestWrapper().authenticateUser(dataUser.getAdminUser());
+
+        // Check if the RM site exists
+        if (siteRMExists())
+        {
+            // Delete the RM site
+            rmSiteAPI.deleteRMSite();
+        }
+
+        // Build the RM site properties
+        JsonObject rmSiteProperties = buildObject()
+                .add(TITLE, RM_TITLE)
+                .add(DESCRIPTION, RM_DESCRIPTION)
+                .add(COMPLIANCE, STANDARD.toString())
+                .getJson();
+
+        // Create the RM site
+        RMSite rmSite = rmSiteAPI.createRMSite(rmSiteProperties);
+
+        // Verify the status code
+        rmSiteAPI.usingRestWrapper().assertStatusCodeIs(CREATED);
+
+        // Verify the returned file plan component
+        assertEquals(rmSite.getId(), RM_ID);
+        assertEquals(rmSite.getTitle(), RM_TITLE);
+        assertEquals(rmSite.getDescription(), RM_DESCRIPTION);
+        assertEquals(rmSite.getCompliance(), STANDARD);
+        assertEquals(rmSite.getVisibility(), PUBLIC);
+        assertEquals(rmSite.getRole(), UserRole.SiteManager.toString());
+    }
+
+    /**
+     * Given that RM site exists
+     * When I want to  create the RM site
+     * Then the response code 409 (Site with the given identifier already exists) is return
+     */
+    @Test
+    (
+        description = "Create RM site when site already exist with admin user"
+    )
+    public void createRMSiteWhenSiteExists() throws Exception
+    {
+        // Create the RM site if it does not exist
+        createRMSiteIfNotExists();
+
+        // Authenticate with admin user
+        RestWrapper restWrapper = rmSiteAPI.usingRestWrapper().authenticateUser(dataUser.getAdminUser());
+
+        // Construct new properties
+        String newTitle = RM_TITLE + "createRMSiteWhenSiteExists";
+        String newDescription = RM_DESCRIPTION + "createRMSiteWhenSiteExists";
+
+        // Build the RM site properties
+        JsonObject rmSiteProperties = buildObject()
+                .add(TITLE, newTitle)
+                .add(DESCRIPTION, newDescription)
+                .add(COMPLIANCE, STANDARD.toString())
+                .getJson();
+
+        // Create the RM site
+        rmSiteAPI.createRMSite(rmSiteProperties);
+
+        // Verify the status code
+        restWrapper.assertStatusCodeIs(CONFLICT);
+    }
+
+    /**
+     * Given that RM site exists
+     * When I want to delete the RM site
+     * Then RM site is successfully deleted
+     */
+    @Test
+    (
+        description = "Delete RM site as admin user"
+    )
+    public void deleteRMSite() throws Exception
+    {
+        // Authenticate with admin user
+        RestWrapper restWrapper = rmSiteAPI.usingRestWrapper().authenticateUser(dataUser.getAdminUser());
+
+        // Delete the RM site
+        rmSiteAPI.deleteRMSite();
+
+        // Verify the status code
+        restWrapper.assertStatusCodeIs(NO_CONTENT);
+    }
+
+    /**
+     * Given that RM site exists
+     * When I GET the retrieve the RM site details
+     * Then RM site details are returned
+     */
+    @Test
+    (
+        description = "GET the RM site as admin user"
+    )
+    public void getRMSite() throws Exception
+    {
+        // Authenticate with admin user
+        RestWrapper restWrapper = rmSiteAPI.usingRestWrapper().authenticateUser(dataUser.getAdminUser());
+
+        // Get the RM site
+        RMSite rmSite = rmSiteAPI.getSite();
+        if (!siteRMExists())
+        {
+            // Verify the status code when RM site  doesn't exist
+            restWrapper.assertStatusCodeIs(NOT_FOUND);
+            createRMSiteIfNotExists();
+        }
+        else
+        {
+            // Verify the status code
+            restWrapper.assertStatusCodeIs(OK);
+            assertEquals(rmSite.getId(), RM_ID);
+            assertEquals(rmSite.getDescription(), RM_DESCRIPTION);
+            assertEquals(rmSite.getCompliance(), STANDARD);
+            assertEquals(rmSite.getVisibility(), PUBLIC);
+        }
+    }
+
+    /**
+     * Given that an user is created and RM site doesn't exist
+     * When the user wants to create a RM site with DOD compliance
+     * Then RM site is created
+     */
+    @Test
+    (
+        description = "Create RM site with DOD compliance as an another admin user"
+    )
+    @Bug (id="RM-4289")
+    public void createRMSiteAsAnotherAdminUser() throws Exception
+    {
+        // Authenticate with admin user
+        rmSiteAPI.usingRestWrapper().authenticateUser(dataUser.getAdminUser());
+
+        // Check if the RM site exists
+        if (siteRMExists())
+        {
+            // Delete the RM site
+            rmSiteAPI.deleteRMSite();
+        }
+
+        // Disconnect the current user from the API session
+        rmSiteAPI.usingRestWrapper().disconnect();
+
+        // Create user
+        userService.create(dataUser.getAdminUser().getUsername(),
+                dataUser.getAdminUser().getPassword(),
+                ANOTHER_ADMIN,
+                DEFAULT_PASSWORD,
+                DEFAULT_EMAIL,
+                ANOTHER_ADMIN,
+                ANOTHER_ADMIN);
+
+        // Build the user model
+        UserModel userModel = new UserModel(ANOTHER_ADMIN,DEFAULT_PASSWORD);
+
+        // Authenticate as that new user
+        rmSiteAPI.usingRestWrapper().authenticateUser(userModel);
+
+        // Build the RM site properties
+        JsonObject rmSiteProperties = buildObject()
+                .add(TITLE, RM_TITLE)
+                .add(DESCRIPTION, RM_DESCRIPTION)
+                .add(COMPLIANCE, DOD5015.toString())
+                .getJson();
+
+        // Create the RM site
+        RMSite rmSite = rmSiteAPI.createRMSite(rmSiteProperties);
+
+        // Verify the status code
+        rmSiteAPI.usingRestWrapper().assertStatusCodeIs(CREATED);
+
+        // Verify the returned file plan component
+        assertEquals(rmSite.getId(), RM_ID);
+        assertEquals(rmSite.getTitle(), RM_TITLE);
+        assertEquals(rmSite.getDescription(), RM_DESCRIPTION);
+        assertEquals(rmSite.getCompliance(), DOD5015);
+        assertEquals(rmSite.getVisibility(), PUBLIC);
+        assertEquals(rmSite.getRole(), UserRole.SiteManager.toString());
+    }
+
+    /**
+     * Given that RM site exist
+     * When a non-RM user wants to update the RM site details (title or description)
+     * Then 403 response status code is return
+     * When the admin user wants to update the RM site details (title or description)
+     * Then RM site details are updated
+     */
+    @Test
+    public void updateRMSiteDetails()throws Exception
+    {
+        String NEW_TITLE = RM_TITLE + RandomData.getRandomAlphanumeric();
+        String NEW_DESCRIPTION=RM_DESCRIPTION+ RandomData.getRandomAlphanumeric();
+
+        // Build the RM site properties
+        JsonObject rmSiteToUpdate = buildObject()
+                .add(TITLE, NEW_TITLE)
+                .add(DESCRIPTION, NEW_DESCRIPTION)
+                .getJson();
+
+        // Authenticate with admin user
+        rmSiteAPI.usingRestWrapper().authenticateUser(dataUser.getAdminUser());
+
+        // Create the site if it does not exist
+        createRMSiteIfNotExists();
+
+        // Disconnect the user from the API session
+        rmSiteAPI.usingRestWrapper().disconnect();
+
+        // Create a random user
+        UserModel nonRMuser = dataUser.createRandomTestUser("testUser");
+
+        // Authenticate as that random user
+        rmSiteAPI.usingRestWrapper().authenticateUser(nonRMuser);
+
+        // Create the RM site
+        RMSite rmSite = rmSiteAPI.updateRMSite(rmSiteToUpdate);
+
+        // Verify the status code
+        rmSiteAPI.usingRestWrapper().assertStatusCodeIs(FORBIDDEN);
+
+        // Disconnect the user from the API session
+        rmSiteAPI.usingRestWrapper().disconnect();
+
+        // Authenticate with admin user
+        rmSiteAPI.usingRestWrapper().authenticateUser(dataUser.getAdminUser());
+
+        // Update the RM Site
+        rmSite = rmSiteAPI.updateRMSite(rmSiteToUpdate);
+
+        // Verify the response status code
+        rmSiteAPI.usingRestWrapper().assertStatusCodeIs(OK);
+
+        // Verify the returned file plan component
+        assertEquals(rmSite.getId(), RM_ID);
+        assertEquals(rmSite.getTitle(), NEW_TITLE);
+        assertEquals(rmSite.getDescription(), NEW_DESCRIPTION);
+        assertNotNull(rmSite.getCompliance());
+        assertEquals(rmSite.getVisibility(), PUBLIC);
+    }
+
+    /**
+     * Given that RM site exist
+     * When the admin user wants to update the RM site compliance
+     * Then RM site compliance is not updated
+     */
+    @Test
+    public void updateRMSiteComplianceAsAdmin() throws Exception
+    {
+        // Authenticate with admin user
+        rmSiteAPI.usingRestWrapper().authenticateUser(dataUser.getAdminUser());
+
+        // Create the RM site if it does not exist
+        createRMSiteIfNotExists();
+
+        // Build the RM site properties
+        JsonObject rmSiteToUpdate = buildObject()
+                .add(COMPLIANCE, DOD5015.toString())
+                .getJson();
+
+        // Update the RM site
+        rmSiteAPI.updateRMSite(rmSiteToUpdate);
+
+        // Verify the response status code
+        rmSiteAPI.usingRestWrapper().assertStatusCodeIs(BAD_REQUEST);
+    }
+}
diff --git a/rm-automation/rm-automation-community-rest-api/src/test/resources/default.properties b/rm-automation/rm-automation-community-rest-api/src/test/resources/default.properties
new file mode 100644
index 0000000000..911f2a44fc
--- /dev/null
+++ b/rm-automation/rm-automation-community-rest-api/src/test/resources/default.properties
@@ -0,0 +1,25 @@
+#########################################################################
+#           Original property values from default.properties            #
+#########################################################################
+
+# Dataprep related
+alfresco.scheme=http
+alfresco.server=localhost
+alfresco.port=8080
+
+# Credentials
+admin.user=admin
+admin.password=admin
+
+# Rest related
+rest.basePath=alfresco/api/-default-/public/alfresco/versions/1
+rest.workflowPath=alfresco/api/-default-/public/workflow/versions/1
+
+# Database Section
+db.url = jdbc:mysql://${alfresco.server}:3306/alfresco
+db.username = alfresco
+db.password = alfresco
+
+#########################################################################
+
+rest.rmPath=alfresco/api/-default-/public/ig/versions/1
\ No newline at end of file
diff --git a/rm-automation/rm-automation-community-rest-api/src/test/resources/testng.xml b/rm-automation/rm-automation-community-rest-api/src/test/resources/testng.xml
new file mode 100644
index 0000000000..ed47d376d7
--- /dev/null
+++ b/rm-automation/rm-automation-community-rest-api/src/test/resources/testng.xml
@@ -0,0 +1,10 @@
+
+
+
+
+   
+      
+         
+      
+   
+
\ No newline at end of file
diff --git a/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/messages/action-service.properties b/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/messages/action-service.properties
index 2c89111f41..fe9a6d959e 100644
--- a/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/messages/action-service.properties
+++ b/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/messages/action-service.properties
@@ -36,7 +36,12 @@ rm.action.records_only_undeclared=You can only complete records.
 rm.action.event-not-undone=You can't undo the event {0} because it's not defined on the retention lifecycle.
 rm.action.node-not-record-category=You can't create a retention schedule for ({0}) because it's not a record category.
 rm.action.parameter-not-supplied=Add a ''{0}'' to continue.
-rm.action.delete-not-hold-type=We couldn't delete the hold because {1} isn't of type {0}. 
+rm.action.delete-not-hold-type=We couldn't delete the hold because {1} isn't of type {0}.
 rm.action.cast-to-rm-type=You can't upload a custom folder type to the records management file plan.
 rm.action.record-folder-create=You can't create a record folder in another record folder.
+rm.action.unique.child.type-error-message=Operation failed. Multiple children of this type are not allowed.
+rm.action.multiple.children.type-error-message=Operation failed. Children of type {0} are not allowed
+rm.action.create.transfer.container.child-error-message=Operation failed. Creation is not allowed in Transfer Container.
+rm.action.create.transfer.child-error-message=Operation failed. Creation is not allowed in Transfer Folders.
+rm.action.create.record.folder.child-error-message=Only records can be created in record folders but it was {0}
 
diff --git a/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/rm-public-rest-context.xml b/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/rm-public-rest-context.xml
index 2f92b31328..2f8e766d91 100644
--- a/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/rm-public-rest-context.xml
+++ b/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/rm-public-rest-context.xml
@@ -27,7 +27,6 @@
         
         
         
-        
     
 
     
diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/BaseBehaviourBean.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/BaseBehaviourBean.java
index 734b7d34e9..306740dae1 100644
--- a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/BaseBehaviourBean.java
+++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/BaseBehaviourBean.java
@@ -27,19 +27,20 @@
 
 package org.alfresco.module.org_alfresco_module_rm.model;
 
-import java.security.InvalidParameterException;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
 import org.alfresco.error.AlfrescoRuntimeException;
 import org.alfresco.module.org_alfresco_module_rm.util.ServiceBaseImpl;
+import org.alfresco.repo.node.integrity.IntegrityException;
 import org.alfresco.repo.policy.BehaviourFilter;
 import org.alfresco.repo.policy.annotation.BehaviourRegistry;
 import org.alfresco.service.cmr.repository.NodeRef;
 import org.alfresco.service.namespace.QName;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
+import org.springframework.extensions.surf.util.I18NUtil;
 
 import com.google.common.collect.Sets;
 
@@ -56,6 +57,10 @@ public abstract class BaseBehaviourBean extends ServiceBaseImpl
     /** Logger */
     protected static final Log LOGGER = LogFactory.getLog(BaseBehaviourBean.class);
 
+    /** I18N */
+    protected static final String UNIQUE_CHILD_TYPE_ERROR = "rm.action.unique.child.type-error-message";
+    protected static final String MULTIPLE_CHILDREN_TYPE_ERROR = "rm.action.multiple.children.type-error-message";
+
     /** behaviour filter */
     protected BehaviourFilter behaviourFilter;
 
@@ -99,9 +104,9 @@ public abstract class BaseBehaviourBean extends ServiceBaseImpl
      * @param childType the child node
      * @param acceptedUniqueChildType a list of node types that are accepted as children of the provided parent only once
      * @param acceptedMultipleChildType a list of node types that are accepted as children of the provided parent multiple times
-     * @throws InvalidParameterException if the child association doesn't comply with the RM rules
+     * @throws IntegrityException if the child association doesn't comply with the RM rules
      */
-    protected void validateNewChildAssociation(NodeRef parent, NodeRef child, List acceptedUniqueChildType, List acceptedMultipleChildType) throws InvalidParameterException
+    protected void validateNewChildAssociation(NodeRef parent, NodeRef child, List acceptedUniqueChildType, List acceptedMultipleChildType) throws IntegrityException
     {
         QName childType = getInternalNodeService().getType(child);
         if(acceptedUniqueChildType.contains(childType))
@@ -109,12 +114,12 @@ public abstract class BaseBehaviourBean extends ServiceBaseImpl
             // check the user is not trying to create multiple children of a type that is only accepted once
             if(nodeService.getChildAssocs(parent, Sets.newHashSet(childType)).size() > 1)
             {
-                throw new InvalidParameterException("Operation failed. Multiple children of this type are not allowed.");
+                throw new IntegrityException(I18NUtil.getMessage(UNIQUE_CHILD_TYPE_ERROR), null);
             }
         }
         else if(!acceptedMultipleChildType.contains(childType))
         {
-            throw new InvalidParameterException("Operation failed. Children of type " + childType + " are not allowed");
+            throw new IntegrityException(I18NUtil.getMessage(MULTIPLE_CHILDREN_TYPE_ERROR, childType), null);
         }
     }
 
@@ -122,9 +127,9 @@ public abstract class BaseBehaviourBean extends ServiceBaseImpl
      * Helper method that checks if the newly created child association is between the sub-types of accepted types.
      * @param childType the child node
      * @param acceptedMultipleChildType a list of node types that are accepted as children of the provided parent multiple times
-     * @throws InvalidParameterException if the child association isn't between the sub-types of accepted types
+     * @throws IntegrityException if the child association isn't between the sub-types of accepted types
      */
-    protected void validateNewChildAssociationSubTypesIncluded(NodeRef child, List acceptedMultipleChildType) throws InvalidParameterException
+    protected void validateNewChildAssociationSubTypesIncluded(NodeRef child, List acceptedMultipleChildType) throws IntegrityException
     {
         QName childType = getInternalNodeService().getType(child);
         for(QName type :  acceptedMultipleChildType)
@@ -135,6 +140,6 @@ public abstract class BaseBehaviourBean extends ServiceBaseImpl
             }
         }
         //no match was found in sub-types of permitted types list
-        throw new InvalidParameterException("Operation failed. Children of type " + childType + " are not allowed");
+        throw new IntegrityException(I18NUtil.getMessage(MULTIPLE_CHILDREN_TYPE_ERROR, childType), null);
     }
 }
diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/behaviour/RecordsManagementSearchBehaviour.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/behaviour/RecordsManagementSearchBehaviour.java
index aacda376c7..6917cc8899 100644
--- a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/behaviour/RecordsManagementSearchBehaviour.java
+++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/behaviour/RecordsManagementSearchBehaviour.java
@@ -519,48 +519,45 @@ public class RecordsManagementSearchBehaviour implements RecordsManagementModel
      */
     private void updateDispositionActionProperties(NodeRef record, NodeRef dispositionAction)
     {
-        if (!methodCached("updateDispositionActionProperties", record))
+        Map props = nodeService.getProperties(record);
+
+        DispositionAction da = new DispositionActionImpl(recordsManagementServiceRegistry, dispositionAction);
+
+        props.put(PROP_RS_DISPOSITION_ACTION_NAME, da.getName());
+        props.put(PROP_RS_DISPOSITION_ACTION_AS_OF, da.getAsOfDate());
+        props.put(PROP_RS_DISPOSITION_EVENTS_ELIGIBLE, nodeService.getProperty(dispositionAction, PROP_DISPOSITION_EVENTS_ELIGIBLE));
+
+        DispositionActionDefinition daDefinition = da.getDispositionActionDefinition();
+        if (daDefinition != null)
         {
-            Map props = nodeService.getProperties(record);
-    
-            DispositionAction da = new DispositionActionImpl(recordsManagementServiceRegistry, dispositionAction);
-    
-            props.put(PROP_RS_DISPOSITION_ACTION_NAME, da.getName());
-            props.put(PROP_RS_DISPOSITION_ACTION_AS_OF, da.getAsOfDate());
-            props.put(PROP_RS_DISPOSITION_EVENTS_ELIGIBLE, nodeService.getProperty(dispositionAction, PROP_DISPOSITION_EVENTS_ELIGIBLE));
-    
-            DispositionActionDefinition daDefinition = da.getDispositionActionDefinition();
-            if (daDefinition != null)
+            Period period = daDefinition.getPeriod();
+            if (period != null)
             {
-                Period period = daDefinition.getPeriod();
-                if (period != null)
-                {
-                    props.put(PROP_RS_DISPOSITION_PERIOD, period.getPeriodType());
-                    props.put(PROP_RS_DISPOSITION_PERIOD_EXPRESSION, period.getExpression());
-                }
-                else
-                {
-                    props.put(PROP_RS_DISPOSITION_PERIOD, null);
-                    props.put(PROP_RS_DISPOSITION_PERIOD_EXPRESSION, null);
-                }
+                props.put(PROP_RS_DISPOSITION_PERIOD, period.getPeriodType());
+                props.put(PROP_RS_DISPOSITION_PERIOD_EXPRESSION, period.getExpression());
             }
-    
-            nodeService.setProperties(record, props);
-    
-            if (logger.isDebugEnabled())
+            else
             {
-                logger.debug("Set rma:recordSearchDispositionActionName for node " + record + " to: " +
-                            props.get(PROP_RS_DISPOSITION_ACTION_NAME));
-                logger.debug("Set rma:recordSearchDispositionActionAsOf for node " + record + " to: " +
-                            props.get(PROP_RS_DISPOSITION_ACTION_AS_OF));
-                logger.debug("Set rma:recordSearchDispositionEventsEligible for node " + record + " to: " +
-                            props.get(PROP_RS_DISPOSITION_EVENTS_ELIGIBLE));
-                logger.debug("Set rma:recordSearchDispositionPeriod for node " + record + " to: " +
-                            props.get(PROP_RS_DISPOSITION_PERIOD));
-                logger.debug("Set rma:recordSearchDispositionPeriodExpression for node " + record + " to: " +
-                            props.get(PROP_RS_DISPOSITION_PERIOD_EXPRESSION));
+                props.put(PROP_RS_DISPOSITION_PERIOD, null);
+                props.put(PROP_RS_DISPOSITION_PERIOD_EXPRESSION, null);
             }
         }
+
+        nodeService.setProperties(record, props);
+
+        if (logger.isDebugEnabled())
+        {
+            logger.debug("Set rma:recordSearchDispositionActionName for node " + record + " to: " +
+                        props.get(PROP_RS_DISPOSITION_ACTION_NAME));
+            logger.debug("Set rma:recordSearchDispositionActionAsOf for node " + record + " to: " +
+                        props.get(PROP_RS_DISPOSITION_ACTION_AS_OF));
+            logger.debug("Set rma:recordSearchDispositionEventsEligible for node " + record + " to: " +
+                        props.get(PROP_RS_DISPOSITION_EVENTS_ELIGIBLE));
+            logger.debug("Set rma:recordSearchDispositionPeriod for node " + record + " to: " +
+                        props.get(PROP_RS_DISPOSITION_PERIOD));
+            logger.debug("Set rma:recordSearchDispositionPeriodExpression for node " + record + " to: " +
+                        props.get(PROP_RS_DISPOSITION_PERIOD_EXPRESSION));
+        }
     }
 
     /**
diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/RecordCategoryType.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/RecordCategoryType.java
index 8a16406151..a060a18a21 100644
--- a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/RecordCategoryType.java
+++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/RecordCategoryType.java
@@ -27,8 +27,10 @@
 
 package org.alfresco.module.org_alfresco_module_rm.model.rma.type;
 
-import org.alfresco.error.AlfrescoRuntimeException;
-import org.alfresco.model.ContentModel;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
 import org.alfresco.module.org_alfresco_module_rm.model.BaseBehaviourBean;
 import org.alfresco.module.org_alfresco_module_rm.recordfolder.RecordFolderService;
 import org.alfresco.module.org_alfresco_module_rm.security.FilePlanPermissionService;
@@ -61,6 +63,9 @@ public class RecordCategoryType extends    BaseBehaviourBean
                                 implements NodeServicePolicies.OnCreateChildAssociationPolicy,
                                            NodeServicePolicies.OnCreateNodePolicy
 {
+    private final static List ACCEPTED_UNIQUE_CHILD_TYPES = new ArrayList();
+    private final static List ACCEPTED_NON_UNIQUE_CHILD_TYPES = Arrays.asList(TYPE_RECORD_CATEGORY, TYPE_RECORD_FOLDER);
+
     /** vital record service */
     protected VitalRecordService vitalRecordService;
 
@@ -106,13 +111,9 @@ public class RecordCategoryType extends    BaseBehaviourBean
     )
     public void onCreateChildAssociation(ChildAssociationRef childAssocRef, boolean bNew)
     {
-        // ensure content is not placed directly into a record category
         NodeRef nodeRef = childAssocRef.getChildRef();
-        if (instanceOf(nodeRef, ContentModel.TYPE_CONTENT))
-        {
-            throw new AlfrescoRuntimeException("Operation failed, because you can't place content directly into a record category.");
-        }
-
+        NodeRef parentRef = childAssocRef.getParentRef();
+        validateNewChildAssociation(parentRef, nodeRef, ACCEPTED_UNIQUE_CHILD_TYPES, ACCEPTED_NON_UNIQUE_CHILD_TYPES);
         if (bNew)
         {
             // setup the record folder
diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/RecordFolderType.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/RecordFolderType.java
index d9b8ffe6b4..bf43fc7210 100644
--- a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/RecordFolderType.java
+++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/RecordFolderType.java
@@ -32,6 +32,7 @@ import java.util.Map;
 
 import org.alfresco.error.AlfrescoRuntimeException;
 import org.alfresco.model.ContentModel;
+import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel;
 import org.alfresco.module.org_alfresco_module_rm.model.behaviour.AbstractDisposableItem;
 import org.alfresco.module.org_alfresco_module_rm.record.RecordService;
 import org.alfresco.module.org_alfresco_module_rm.recordfolder.RecordFolderService;
@@ -40,6 +41,7 @@ import org.alfresco.repo.copy.CopyBehaviourCallback;
 import org.alfresco.repo.copy.CopyDetails;
 import org.alfresco.repo.copy.DefaultCopyBehaviourCallback;
 import org.alfresco.repo.node.NodeServicePolicies;
+import org.alfresco.repo.node.integrity.IntegrityException;
 import org.alfresco.repo.policy.Behaviour.NotificationFrequency;
 import org.alfresco.repo.policy.annotation.Behaviour;
 import org.alfresco.repo.policy.annotation.BehaviourBean;
@@ -76,7 +78,7 @@ public class RecordFolderType extends    AbstractDisposableItem
     protected VitalRecordService vitalRecordService;
 
     /** I18N */
-    private static final String MSG_CANNOT_CREATE_RECORD_FOLDER = "rm.action.record-folder-create";
+    private static final String MSG_CANNOT_CREATE_RECORD_FOLDER_CHILD = "rm.action.create.record.folder.child-error-message";
 
     /**
      * @param recordService record service
@@ -219,6 +221,15 @@ public class RecordFolderType extends    AbstractDisposableItem
 
         if (nodeService.exists(nodeRef))
         {
+            boolean notFolderOrRmFolderSubType = !instanceOf(nodeRef, ContentModel.TYPE_FOLDER) ||
+                                              instanceOf(nodeRef, RecordsManagementModel.TYPE_RECORDS_MANAGEMENT_CONTAINER) ||
+                                              instanceOf(nodeRef, RecordsManagementModel.TYPE_RECORD_FOLDER) ||
+                                              instanceOf(nodeRef, RecordsManagementModel.TYPE_TRANSFER);
+
+            if (!instanceOf(nodeRef, ContentModel.TYPE_CONTENT) && notFolderOrRmFolderSubType)
+            {
+                throw new IntegrityException(I18NUtil.getMessage(MSG_CANNOT_CREATE_RECORD_FOLDER_CHILD, nodeService.getType(nodeRef)), null);
+            }
             // ensure nothing is being added to a closed record folder
             NodeRef recordFolder = childAssocRef.getParentRef();
             Boolean isClosed = (Boolean) nodeService.getProperty(recordFolder, PROP_IS_CLOSED);
@@ -245,9 +256,9 @@ public class RecordFolderType extends    AbstractDisposableItem
         final NodeRef recordFolder = childAssocRef.getChildRef();
 
         // only records can be added in a record folder or hidden folders(is the case of e-mail attachments)
-        if (!instanceOf(recordFolder, ContentModel.TYPE_CONTENT) && !nodeService.hasAspect(recordFolder, ContentModel.ASPECT_HIDDEN))
+        if (instanceOf(recordFolder, ContentModel.TYPE_FOLDER) && !nodeService.hasAspect(recordFolder, ContentModel.ASPECT_HIDDEN))
         {
-            throw new AlfrescoRuntimeException(I18NUtil.getMessage(MSG_CANNOT_CREATE_RECORD_FOLDER));
+            throw new IntegrityException(I18NUtil.getMessage(MSG_CANNOT_CREATE_RECORD_FOLDER_CHILD, nodeService.getType(recordFolder)), null);
         }
 
         behaviourFilter.disableBehaviour();
diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/RmSiteType.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/RmSiteType.java
index 9068216fb3..82eb0b57ac 100644
--- a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/RmSiteType.java
+++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/RmSiteType.java
@@ -28,7 +28,6 @@
 package org.alfresco.module.org_alfresco_module_rm.model.rma.type;
 
 import java.io.Serializable;
-import java.security.InvalidParameterException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
@@ -41,6 +40,7 @@ import org.alfresco.module.org_alfresco_module_rm.capability.CapabilityService;
 import org.alfresco.module.org_alfresco_module_rm.model.BaseBehaviourBean;
 import org.alfresco.module.org_alfresco_module_rm.search.RecordsManagementSearchService;
 import org.alfresco.repo.node.NodeServicePolicies;
+import org.alfresco.repo.node.integrity.IntegrityException;
 import org.alfresco.repo.policy.Behaviour.NotificationFrequency;
 import org.alfresco.repo.policy.annotation.Behaviour;
 import org.alfresco.repo.policy.annotation.BehaviourBean;
@@ -59,6 +59,7 @@ import org.alfresco.service.cmr.site.SiteVisibility;
 import org.alfresco.service.namespace.QName;
 import org.alfresco.util.ParameterCheck;
 import org.alfresco.util.PropertyMap;
+import org.springframework.extensions.surf.util.I18NUtil;
 
 import com.google.common.collect.Sets;
 
@@ -343,14 +344,14 @@ public class RmSiteType extends    BaseBehaviourBean
      */
     @Override
     protected void validateNewChildAssociation(NodeRef parent, NodeRef child, List acceptedUniqueChildType,
-                List acceptedMultipleChildType) throws InvalidParameterException
+                List acceptedMultipleChildType) throws IntegrityException
     {
         super.validateNewChildAssociation(parent, child, acceptedUniqueChildType, acceptedMultipleChildType);
 
         // check the user is not trying to create more than 2 folders that are created by default.
         if(nodeService.getChildAssocs(parent, Sets.newHashSet(ContentModel.TYPE_FOLDER)).size() > 2)
         {
-            throw new InvalidParameterException("Operation failed. Children of type " + ContentModel.TYPE_FOLDER + " are not allowed");
+            throw new IntegrityException(I18NUtil.getMessage(MULTIPLE_CHILDREN_TYPE_ERROR, ContentModel.TYPE_FOLDER), null);
         }
     }
 }
diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/TransferContainerType.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/TransferContainerType.java
index b46fd8c711..d0fba4ff99 100644
--- a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/TransferContainerType.java
+++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/TransferContainerType.java
@@ -26,12 +26,11 @@
  */
 package org.alfresco.module.org_alfresco_module_rm.model.rma.type;
 
-import java.security.InvalidParameterException;
-
 import org.alfresco.error.AlfrescoRuntimeException;
 import org.alfresco.model.ContentModel;
 import org.alfresco.module.org_alfresco_module_rm.model.BaseBehaviourBean;
 import org.alfresco.repo.node.NodeServicePolicies;
+import org.alfresco.repo.node.integrity.IntegrityException;
 import org.alfresco.repo.policy.annotation.Behaviour;
 import org.alfresco.repo.policy.annotation.BehaviourBean;
 import org.alfresco.repo.policy.annotation.BehaviourKind;
@@ -50,6 +49,7 @@ public class TransferContainerType extends BaseBehaviourBean
             implements NodeServicePolicies.OnCreateChildAssociationPolicy, NodeServicePolicies.OnCreateNodePolicy
 {
     private final static String MSG_ERROR_ADD_CONTENT_CONTAINER = "rm.service.error-add-content-container";
+    private final static String MSG_ERROR_ADD_CHILD_TO_TRANSFER_CONTAINER = "rm.action.create.transfer.container.child-error-message";
     private static final String BEHAVIOUR_NAME = "onCreateChildAssocsForTransferContainer";
 
     /**
@@ -84,7 +84,7 @@ public class TransferContainerType extends BaseBehaviourBean
     )
     public void onCreateChildAssociation(ChildAssociationRef childAssocRef, boolean bNew)
     {
-        throw new InvalidParameterException("Operation failed. Creation is not allowed in Transfer Container");
+        throw new IntegrityException(I18NUtil.getMessage(MSG_ERROR_ADD_CHILD_TO_TRANSFER_CONTAINER), null);
     }
 
     @Override
diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/TransferType.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/TransferType.java
index 268caa0165..aa8be553e4 100644
--- a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/TransferType.java
+++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/TransferType.java
@@ -27,14 +27,14 @@
 
 package org.alfresco.module.org_alfresco_module_rm.model.rma.type;
 
-import java.security.InvalidParameterException;
-
 import org.alfresco.module.org_alfresco_module_rm.model.BaseBehaviourBean;
 import org.alfresco.repo.node.NodeServicePolicies;
+import org.alfresco.repo.node.integrity.IntegrityException;
 import org.alfresco.repo.policy.annotation.Behaviour;
 import org.alfresco.repo.policy.annotation.BehaviourBean;
 import org.alfresco.repo.policy.annotation.BehaviourKind;
 import org.alfresco.service.cmr.repository.ChildAssociationRef;
+import org.springframework.extensions.surf.util.I18NUtil;
 
 /**
  * rma:transfer behaviour bean
@@ -45,6 +45,7 @@ import org.alfresco.service.cmr.repository.ChildAssociationRef;
 @BehaviourBean(defaultType = "rma:transfer")
 public class TransferType extends BaseBehaviourBean implements NodeServicePolicies.OnCreateChildAssociationPolicy
 {
+    private final static String MSG_ERROR_ADD_CHILD_TO_TRANSFER = "rm.action.create.transfer.child-error-message";
     private static final String BEHAVIOUR_NAME = "onCreateChildAssocsForTransferType";
 
     /**
@@ -76,6 +77,6 @@ public class TransferType extends BaseBehaviourBean implements NodeServicePolici
     )
     public void onCreateChildAssociation(ChildAssociationRef childAssocRef, boolean isNewNode)
     {
-        throw new InvalidParameterException("Operation failed. Creation is not allowed in Transfer Folders");
+        throw new IntegrityException(I18NUtil.getMessage(MSG_ERROR_ADD_CHILD_TO_TRANSFER), null);
     }
 }
diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/impl/RMNodesImpl.java b/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/impl/RMNodesImpl.java
index b5bd4267f3..b127e2fbe1 100644
--- a/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/impl/RMNodesImpl.java
+++ b/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/impl/RMNodesImpl.java
@@ -37,7 +37,6 @@ import java.util.concurrent.ConcurrentHashMap;
 
 import org.alfresco.model.ContentModel;
 import org.alfresco.module.org_alfresco_module_rm.RecordsManagementServiceRegistry;
-import org.alfresco.module.org_alfresco_module_rm.capability.CapabilityService;
 import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionSchedule;
 import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService;
 import org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService;
@@ -65,8 +64,6 @@ import org.alfresco.service.namespace.QName;
 import org.alfresco.util.Pair;
 import org.alfresco.util.ParameterCheck;
 
-import net.sf.acegisecurity.vote.AccessDecisionVoter;
-
 /**
  * Centralizes access to the repository.
  *
@@ -87,7 +84,6 @@ public class RMNodesImpl extends NodesImpl implements RMNodes
     private Repository repositoryHelper;
     private DictionaryService dictionaryService;
     private DispositionService dispositionService;
-    private CapabilityService capabilityService;
 
     /**
      * TODO to remove this after isSpecialNode is made protected in core implementation(REPO-1459)
@@ -117,11 +113,6 @@ public class RMNodesImpl extends NodesImpl implements RMNodes
         this.filePlanService = filePlanService;
     }
 
-    public void setCapabilityService(CapabilityService capabilityService)
-    {
-        this.capabilityService = capabilityService;
-    }
-
     @Override
     public Node getFolderOrDocument(final NodeRef nodeRef, NodeRef parentNodeRef, QName nodeTypeQName, List includeParam, Map mapUserInfo)
     {
@@ -132,6 +123,26 @@ public class RMNodesImpl extends NodesImpl implements RMNodes
             nodeTypeQName = nodeService.getType(nodeRef);
         }
 
+        //TODO to remove this part of code after isSpecialNode will be made protected on core, will not need this anymore since the right allowed operations will be returned from core(REPO-1459).
+        if (includeParam.contains(PARAM_INCLUDE_ALLOWABLEOPERATIONS) && originalNode.getAllowableOperations() != null)
+        {
+            List allowableOperations = originalNode.getAllowableOperations();
+            List modifiedAllowableOperations = new ArrayList<>();
+            modifiedAllowableOperations.addAll(allowableOperations);
+
+            for (String op : allowableOperations)
+            {
+                if (op.equals(OP_DELETE) && (isSpecialNode(nodeRef, nodeTypeQName)))
+                {
+                    // special case: do not return "delete" (as an allowable op) for specific system nodes
+                    modifiedAllowableOperations.remove(op);
+                }
+            }
+
+            originalNode.setAllowableOperations((modifiedAllowableOperations.size() > 0 )? modifiedAllowableOperations : null);
+        }
+
+
         RMNodeType type = getType(nodeTypeQName, nodeRef);
         FileplanComponentNode node = null;
         if (mapUserInfo == null)
@@ -182,55 +193,9 @@ public class RMNodesImpl extends NodesImpl implements RMNodes
             }
         }
 
-        if (includeParam.contains(PARAM_INCLUDE_ALLOWABLEOPERATIONS))
-        {
-            node.setAllowableOperations(getAllowableOperations(nodeRef, type));
-        }
-
         return node;
     }
 
-    /**
-     * Helper method that generates allowable operation for the provided node
-     * @param nodeRef the node to get the allowable operations for
-     * @param type the type of the provided nodeRef
-     * @return a sublist of [{@link Nodes.OP_DELETE}, {@link Nodes.OP_CREATE}, {@link Nodes.OP_UPDATE}] representing the allowable operations for the provided node
-     */
-    private List getAllowableOperations(NodeRef nodeRef, RMNodeType type)
-    {
-        List allowableOperations = new ArrayList<>();
-
-        NodeRef filePlan = filePlanService.getFilePlanBySiteId(FilePlanService.DEFAULT_RM_SITE_ID);
-        boolean isFilePlan = nodeRef.equals(filePlan);
-        boolean isTransferContainer = nodeRef.equals(filePlanService.getTransferContainer(filePlan));
-        boolean isUnfiledContainer = nodeRef.equals(filePlanService.getUnfiledContainer(filePlan));
-        boolean isHoldsContainer = nodeRef.equals(filePlanService.getHoldContainer(filePlan)) ;
-        boolean isSpecialContainer = isFilePlan || isTransferContainer || isUnfiledContainer || isHoldsContainer;
-
-        // DELETE
-        if(!isSpecialContainer && 
-                capabilityService.getCapability("Delete").evaluate(nodeRef) == AccessDecisionVoter.ACCESS_GRANTED)
-        {
-            allowableOperations.add(OP_DELETE);
-        }
-
-        // CREATE
-        if(type != RMNodeType.FILE &&  
-                !isTransferContainer &&
-                capabilityService.getCapability("FillingPermissionOnly").evaluate(nodeRef) == AccessDecisionVoter.ACCESS_GRANTED)
-        {
-            allowableOperations.add(OP_CREATE);
-        }
-
-        // UPDATE
-        if (capabilityService.getCapability("Update").evaluate(nodeRef) == AccessDecisionVoter.ACCESS_GRANTED)
-        {
-            allowableOperations.add(OP_UPDATE);
-        }
-
-        return allowableOperations;
-    }
-
     @Override
     public NodeRef validateNode(String nodeId)
     {
diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/sites/RMSiteEntityResource.java b/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/sites/RMSiteEntityResource.java
index eb11498de8..903d19e41c 100644
--- a/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/sites/RMSiteEntityResource.java
+++ b/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/sites/RMSiteEntityResource.java
@@ -46,7 +46,7 @@ import org.alfresco.rm.rest.api.model.SiteUpdate;
  * @since 2.6
  *
  */
-@EntityResource(name = "sites", title = "IG Sites")
+@EntityResource(name = "ig-sites", title = "IG Sites")
 public class RMSiteEntityResource implements EntityResourceAction.Delete, EntityResourceAction.Create,
             EntityResourceAction.Update, EntityResourceAction.ReadById
 {
diff --git a/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/disposition/MultipleSchedulesTest.java b/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/disposition/MultipleSchedulesTest.java
index f2b55655b2..f18a3d2b5d 100644
--- a/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/disposition/MultipleSchedulesTest.java
+++ b/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/disposition/MultipleSchedulesTest.java
@@ -66,6 +66,10 @@ public class MultipleSchedulesTest extends BaseRMTestCase
     protected static final String CATEGORY_B_NAME = TEST_PREFIX + "CategoryB";
     /** The name to use for the folder within the second category. */
     protected static final String FOLDER_B_NAME = TEST_PREFIX + "FolderB";
+    /** The name to use for the third category. */
+    protected static final String CATEGORY_C_NAME = TEST_PREFIX + "CategoryC";
+    /** The name to use for the folder within the third category. */
+    protected static final String FOLDER_C_NAME = TEST_PREFIX + "FolderC";
     /** The name to use for the record. */
     protected static final String RECORD_NAME = TEST_PREFIX + "Record";
 
@@ -80,6 +84,10 @@ public class MultipleSchedulesTest extends BaseRMTestCase
     private NodeRef categoryB;
     /** The folder node within the second category. */
     private NodeRef folderB;
+    /** The third category node. */
+    private NodeRef categoryC;
+    /** The folder node within the third category. */
+    private NodeRef folderC;
     /** The record node. */
     private NodeRef record;
 
@@ -114,6 +122,7 @@ public class MultipleSchedulesTest extends BaseRMTestCase
         // Create two categories.
         categoryA = filePlanService.createRecordCategory(filePlan, CATEGORY_A_NAME);
         categoryB = filePlanService.createRecordCategory(filePlan, CATEGORY_B_NAME);
+        categoryC = filePlanService.createRecordCategory(filePlan, CATEGORY_C_NAME);
         // Create a disposition schedule for category A (Cut off immediately, then Destroy immediately).
         DispositionSchedule dispSchedA = utils.createBasicDispositionSchedule(categoryA, "instructions", "authority", true, false);
         Map cutOffParamsA = ImmutableMap.of(PROP_DISPOSITION_ACTION_NAME, CutOffAction.NAME,
@@ -135,9 +144,21 @@ public class MultipleSchedulesTest extends BaseRMTestCase
                         PROP_DISPOSITION_PERIOD, CommonRMTestUtils.PERIOD_ONE_WEEK,
                         PROP_DISPOSITION_PERIOD_PROPERTY, PROP_CUT_OFF_DATE);
         dispositionService.addDispositionActionDefinition(dispSchedB, destroyParamsB);
+        // Create a disposition schedule for category C (Cut off immediately, then Destroy one year after cutoff).
+        DispositionSchedule dispSchedC = utils.createBasicDispositionSchedule(categoryC, "instructions", "authority", true, false);
+        Map cutOffParamsC = ImmutableMap.of(PROP_DISPOSITION_ACTION_NAME, CutOffAction.NAME,
+                        PROP_DISPOSITION_DESCRIPTION, "description",
+                        PROP_DISPOSITION_PERIOD, CommonRMTestUtils.PERIOD_IMMEDIATELY);
+        dispositionService.addDispositionActionDefinition(dispSchedC, cutOffParamsC);
+        Map destroyParamsC = ImmutableMap.of(PROP_DISPOSITION_ACTION_NAME, DestroyAction.NAME,
+                        PROP_DISPOSITION_DESCRIPTION, "description",
+                        PROP_DISPOSITION_PERIOD, CommonRMTestUtils.PERIOD_ONE_YEAR,
+                        PROP_DISPOSITION_PERIOD_PROPERTY, PROP_CUT_OFF_DATE);
+        dispositionService.addDispositionActionDefinition(dispSchedC, destroyParamsC);
         // Create a folder within each category.
         folderA = recordFolderService.createRecordFolder(categoryA, FOLDER_A_NAME);
         folderB = recordFolderService.createRecordFolder(categoryB, FOLDER_B_NAME);
+        folderC = recordFolderService.createRecordFolder(categoryC, FOLDER_C_NAME);
     }
 
     /**
@@ -155,6 +176,7 @@ public class MultipleSchedulesTest extends BaseRMTestCase
         test()
             .given(() -> {
                 setUpFilePlan();
+                
                 // Create a record filed under category A and linked to category B.
                 record = fileFolderService.create(folderA, RECORD_NAME, ContentModel.TYPE_CONTENT).getNodeRef();
                 recordService.link(record, folderB);
@@ -219,19 +241,22 @@ public class MultipleSchedulesTest extends BaseRMTestCase
         test()
             .given(() -> {
                 setUpFilePlan();
-                // Create a record filed under category A and linked to category B.
+                // Create a record filed under category A and linked to category B and C.
                 record = fileFolderService.create(folderA, RECORD_NAME, ContentModel.TYPE_CONTENT).getNodeRef();
                 recordService.link(record, folderB);
-            })
-            .when(() -> {
+                recordService.link(record, folderC);
                 // Cut off the record.
                 dispositionService.cutoffDisposableItem(record);
+                // Ensure the update has been applied to the record.
+                internalDispositionService.updateNextDispositionAction(record);
+            })
+            .when(() -> {
                 // Unlink the record from folder B.
                 recordService.unlink(record, folderB);
             })
             .then()
-                .expect(true)
+                .expect(false)
                         .from(() -> dispositionService.isNextDispositionActionEligible(record))
-                    .because("Destroy action should be available, as the record should follow its origin disposition schedule.");
+                    .because("Destroy action shouldn't be available, as the record should follow disposition schedule from category C.");
     }
 }
diff --git a/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/issue/RM3341Test.java b/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/issue/RM3341Test.java
index e729e9ac7a..623399f628 100644
--- a/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/issue/RM3341Test.java
+++ b/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/issue/RM3341Test.java
@@ -27,11 +27,10 @@
  */
 package org.alfresco.module.org_alfresco_module_rm.test.integration.issue;
 
-import java.security.InvalidParameterException;
-
 import org.alfresco.model.ContentModel;
 import org.alfresco.module.org_alfresco_module_rm.capability.RMPermissionModel;
 import org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase;
+import org.alfresco.repo.node.integrity.IntegrityException;
 import org.alfresco.service.cmr.repository.NodeRef;
 import org.alfresco.service.cmr.security.AccessStatus;
 
@@ -78,7 +77,7 @@ public class RM3341Test extends BaseRMTestCase
                     fileFolderService.create(holdContainer, "test file", ContentModel.TYPE_CONTENT);
                     fail("This should have thrown an exception");
                 }
-                catch (InvalidParameterException e)
+                catch (IntegrityException e)
                 {
                     // ("Content can't be added to a hold container. Use record folders to file content.")
                 }
@@ -104,7 +103,7 @@ public class RM3341Test extends BaseRMTestCase
                     fail("This should have thrown an exception");
 
                 }
-                catch (InvalidParameterException e)
+                catch (IntegrityException e)
                 {
                     // ("Content can't be added to a transfer container. Use record folders to file content.")
                 }
diff --git a/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/issue/RM3450Test.java b/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/issue/RM3450Test.java
index 02ff9dd758..e2d031f057 100644
--- a/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/issue/RM3450Test.java
+++ b/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/issue/RM3450Test.java
@@ -26,10 +26,9 @@
  */
 package org.alfresco.module.org_alfresco_module_rm.test.integration.issue;
 
-import java.security.InvalidParameterException;
-
 import org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase;
 import org.alfresco.module.org_alfresco_module_rm.test.util.TestModel;
+import org.alfresco.repo.node.integrity.IntegrityException;
 import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
 import org.alfresco.util.GUID;
 import org.springframework.extensions.surf.util.I18NUtil;
@@ -50,7 +49,7 @@ public class RM3450Test extends BaseRMTestCase
         doTestInTransaction(new FailureTest
                 (
                         I18NUtil.getMessage(MSG_CANNOT_CAST_TO_RM_TYPE),
-                        InvalidParameterException.class
+                        IntegrityException.class
                 )
         {
             @Override
diff --git a/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/FilePlanTypeUnitTest.java b/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/FilePlanTypeUnitTest.java
index bdad80df6e..ef08b695da 100644
--- a/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/FilePlanTypeUnitTest.java
+++ b/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/FilePlanTypeUnitTest.java
@@ -29,11 +29,11 @@ package org.alfresco.module.org_alfresco_module_rm.model.rma.type;
 
 import static org.mockito.Mockito.when;
 
-import java.security.InvalidParameterException;
 import java.util.Arrays;
 
 import org.alfresco.model.ContentModel;
 import org.alfresco.module.org_alfresco_module_rm.test.util.BaseUnitTest;
+import org.alfresco.repo.node.integrity.IntegrityException;
 import org.alfresco.service.cmr.repository.ChildAssociationRef;
 import org.alfresco.service.cmr.repository.NodeRef;
 import org.alfresco.service.namespace.QName;
@@ -69,7 +69,7 @@ public class FilePlanTypeUnitTest extends BaseUnitTest
      * When adding a child of type TYPE_FILE_PLAN
      * Then an error should be thrown
      */
-    @Test (expected = InvalidParameterException.class)
+    @Test (expected = IntegrityException.class)
     public void testAddFileplanToFileplan()
     {
         ChildAssociationRef childAssoc = createFileplanContainerChild(TYPE_FILE_PLAN);
@@ -112,7 +112,7 @@ public class FilePlanTypeUnitTest extends BaseUnitTest
      * When adding another child of type TYPE_HOLD_CONTAINER
      * Then an error should be thrown
      */
-    @Test (expected = InvalidParameterException.class)
+    @Test (expected = IntegrityException.class)
     public void testCreateMultipleHoldContainers()
     {
         ChildAssociationRef existingHoldAssoc = createFileplanContainerChild(TYPE_HOLD_CONTAINER);
@@ -141,7 +141,7 @@ public class FilePlanTypeUnitTest extends BaseUnitTest
      * When adding another child of type TYPE_TRANSFER_CONTAINER
      * Then an error should be thrown
      */
-    @Test (expected = InvalidParameterException.class)
+    @Test (expected = IntegrityException.class)
     public void testCreateMultipleTransferContainers()
     {
         ChildAssociationRef existingHoldAssoc = createFileplanContainerChild(TYPE_TRANSFER_CONTAINER);
@@ -170,7 +170,7 @@ public class FilePlanTypeUnitTest extends BaseUnitTest
      * When adding another child of type TYPE_UNFILED_RECORD_CONTAINER
      * Then an error should be thrown
      */
-    @Test (expected = InvalidParameterException.class)
+    @Test (expected = IntegrityException.class)
     public void testCreateMultipleUnfiledRecordsContainers()
     {
         ChildAssociationRef existingHoldAssoc = createFileplanContainerChild(TYPE_UNFILED_RECORD_CONTAINER);
diff --git a/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/HoldContainerTypeUnitTest.java b/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/HoldContainerTypeUnitTest.java
index 1a614fc075..9e414974ca 100644
--- a/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/HoldContainerTypeUnitTest.java
+++ b/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/HoldContainerTypeUnitTest.java
@@ -29,10 +29,9 @@ package org.alfresco.module.org_alfresco_module_rm.model.rma.type;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
-import java.security.InvalidParameterException;
-
 import org.alfresco.module.org_alfresco_module_rm.test.util.AlfMock;
 import org.alfresco.module.org_alfresco_module_rm.test.util.BaseUnitTest;
+import org.alfresco.repo.node.integrity.IntegrityException;
 import org.alfresco.service.cmr.repository.ChildAssociationRef;
 import org.alfresco.service.cmr.repository.NodeRef;
 import org.alfresco.service.namespace.QName;
@@ -52,9 +51,9 @@ public class HoldContainerTypeUnitTest extends BaseUnitTest
 
     /**
      * Given that we try to add a non "rma:hold" type to hold container,
-     * Then InvalidParameterException is thrown.
+     * Then IntegrityException is thrown.
      */
-    @Test (expected = InvalidParameterException.class)
+    @Test (expected = IntegrityException.class)
     public void testAddNonHoldTypeToHoldContainer()
     {
         QName type = AlfMock.generateQName();
diff --git a/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/RecordCategoryTypeUnitTest.java b/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/RecordCategoryTypeUnitTest.java
new file mode 100644
index 0000000000..4b264f3c70
--- /dev/null
+++ b/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/RecordCategoryTypeUnitTest.java
@@ -0,0 +1,111 @@
+/*
+ * #%L
+ * Alfresco Records Management Module
+ * %%
+ * Copyright (C) 2005 - 2016 Alfresco Software Limited
+ * %%
+ * This file is part of the Alfresco software.
+ * -
+ * If the software was purchased under a paid Alfresco license, the terms of
+ * the paid license agreement will prevail.  Otherwise, the software is
+ * provided under the following open source license terms:
+ * -
+ * 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 .
+ * #L%
+ */
+
+package org.alfresco.module.org_alfresco_module_rm.model.rma.type;
+
+import static org.mockito.Mockito.when;
+
+import org.alfresco.module.org_alfresco_module_rm.test.util.AlfMock;
+import org.alfresco.module.org_alfresco_module_rm.test.util.BaseUnitTest;
+import org.alfresco.module.org_alfresco_module_rm.test.util.MockAuthenticationUtilHelper;
+import org.alfresco.module.org_alfresco_module_rm.util.AuthenticationUtil;
+import org.alfresco.module.org_alfresco_module_rm.vital.VitalRecordService;
+import org.alfresco.repo.node.integrity.IntegrityException;
+import org.alfresco.service.cmr.repository.ChildAssociationRef;
+import org.alfresco.service.cmr.repository.NodeRef;
+import org.alfresco.service.namespace.QName;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Unit test class for RecordCategoryType
+ *
+ * @author Silviu Dinuta
+ * @since 2.6
+ *
+ */
+public class RecordCategoryTypeUnitTest extends BaseUnitTest
+{
+    @Mock
+    private AuthenticationUtil mockAuthenticationUtil;
+
+    @Mock
+    private VitalRecordService mockedVitalRecordService;
+
+    private @InjectMocks RecordCategoryType recordCategoryType;
+
+    @Before
+    public void setup()
+    {
+        MockitoAnnotations.initMocks(this);
+        MockAuthenticationUtilHelper.setup(mockAuthenticationUtil);
+        when(mockedApplicationContext.getBean("dbNodeService")).thenReturn(mockedNodeService);
+    }
+
+    /**
+     * Given that we try to add types different than "rma:recordCategory" and "rma:recordFolder" to a record category,
+     * Then IntegrityException is thrown.
+     */
+    @Test(expected = IntegrityException.class)
+    public void testCreateNonAceptedTypes() throws Exception
+    {
+        NodeRef recordCategoryNodeRef = AlfMock.generateNodeRef(mockedNodeService, TYPE_RECORD_CATEGORY);
+        QName type = AlfMock.generateQName();
+        NodeRef nodeRef = AlfMock.generateNodeRef(mockedNodeService, type, true);
+        ChildAssociationRef childAssocRef = generateChildAssociationRef(recordCategoryNodeRef, nodeRef);
+        recordCategoryType.onCreateChildAssociation(childAssocRef, true);
+    }
+
+    /**
+     * Given that we try to add "rma:recordCategory" type to a record category,
+     * Then operation is successful.
+     */
+    @Test
+    public void testCreateRecordCategory() throws Exception
+    {
+        NodeRef recordCategoryNodeRef = AlfMock.generateNodeRef(mockedNodeService, TYPE_RECORD_CATEGORY);
+        NodeRef nodeRef = AlfMock.generateNodeRef(mockedNodeService, TYPE_RECORD_CATEGORY, true);
+        ChildAssociationRef childAssocRef = generateChildAssociationRef(recordCategoryNodeRef, nodeRef);
+        recordCategoryType.onCreateChildAssociation(childAssocRef, true);
+    }
+
+    /**
+     * Given that we try to add "rma:recordFolder" type to a record category,
+     * Then operation is successful.
+     */
+    @Test
+    public void testCreateRecordFolder() throws Exception
+    {
+        NodeRef recordCategoryNodeRef = AlfMock.generateNodeRef(mockedNodeService, TYPE_RECORD_CATEGORY);
+        NodeRef nodeRef = AlfMock.generateNodeRef(mockedNodeService, TYPE_RECORD_FOLDER, true);
+        ChildAssociationRef childAssocRef = generateChildAssociationRef(recordCategoryNodeRef, nodeRef);
+        recordCategoryType.onCreateChildAssociation(childAssocRef, true);
+    }
+}
diff --git a/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/RecordFolderTypeUnitTest.java b/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/RecordFolderTypeUnitTest.java
new file mode 100644
index 0000000000..c058675604
--- /dev/null
+++ b/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/RecordFolderTypeUnitTest.java
@@ -0,0 +1,226 @@
+/*
+ * #%L
+ * Alfresco Records Management Module
+ * %%
+ * Copyright (C) 2005 - 2016 Alfresco Software Limited
+ * %%
+ * This file is part of the Alfresco software.
+ * -
+ * If the software was purchased under a paid Alfresco license, the terms of
+ * the paid license agreement will prevail.  Otherwise, the software is
+ * provided under the following open source license terms:
+ * -
+ * 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 .
+ * #L%
+ */
+
+package org.alfresco.module.org_alfresco_module_rm.model.rma.type;
+
+import static org.mockito.Mockito.when;
+
+import org.alfresco.module.org_alfresco_module_rm.test.util.AlfMock;
+import org.alfresco.module.org_alfresco_module_rm.test.util.BaseUnitTest;
+import org.alfresco.module.org_alfresco_module_rm.test.util.MockAuthenticationUtilHelper;
+import org.alfresco.module.org_alfresco_module_rm.util.AuthenticationUtil;
+import org.alfresco.module.org_alfresco_module_rm.vital.VitalRecordService;
+import org.alfresco.repo.node.integrity.IntegrityException;
+import org.alfresco.service.cmr.repository.ChildAssociationRef;
+import org.alfresco.service.cmr.repository.NodeRef;
+import org.alfresco.service.namespace.QName;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Unit test class for RecordFolderType
+ *
+ * @author Silviu Dinuta
+ * @since 2.6
+ *
+ */
+public class RecordFolderTypeUnitTest extends BaseUnitTest
+{
+    @Mock
+    private AuthenticationUtil mockAuthenticationUtil;
+
+    @Mock
+    private VitalRecordService mockedVitalRecordService;
+
+    private @InjectMocks RecordFolderType recordFolderType;
+
+    @Before
+    public void setup()
+    {
+        MockitoAnnotations.initMocks(this);
+        MockAuthenticationUtilHelper.setup(mockAuthenticationUtil);
+        when(mockedApplicationContext.getBean("dbNodeService")).thenReturn(mockedNodeService);
+    }
+
+    /**
+     * Given that we try to add one rma:transfer to a record folder,
+     * Then IntegrityException is thrown.
+     */
+    @Test(expected = IntegrityException.class)
+    public void testCreateTransferFolder() throws Exception
+    {
+        NodeRef recordFolderNodeRef = AlfMock.generateNodeRef(mockedNodeService, TYPE_RECORD_FOLDER);
+        QName type = AlfMock.generateQName();
+        when(mockedDictionaryService.isSubClass(type, TYPE_TRANSFER)).thenReturn(true);
+        NodeRef nodeRef = AlfMock.generateNodeRef(mockedNodeService, type, true);
+        ChildAssociationRef childAssocRef = generateChildAssociationRef(recordFolderNodeRef, nodeRef);
+        recordFolderType.onCreateChildAssociation(childAssocRef, true);
+    }
+
+    /**
+     * Given that we try to add one record folder to a record folder,
+     * Then IntegrityException is thrown.
+     */
+    @Test(expected = IntegrityException.class)
+    public void testCreateRecordFolder() throws Exception
+    {
+        NodeRef recordFolderNodeRef = AlfMock.generateNodeRef(mockedNodeService, TYPE_RECORD_FOLDER);
+        QName type = AlfMock.generateQName();
+        when(mockedDictionaryService.isSubClass(type, TYPE_RECORD_FOLDER)).thenReturn(true);
+        NodeRef nodeRef = AlfMock.generateNodeRef(mockedNodeService, type, true);
+        ChildAssociationRef childAssocRef = generateChildAssociationRef(recordFolderNodeRef, nodeRef);
+        recordFolderType.onCreateChildAssociation(childAssocRef, true);
+    }
+
+    /**
+     * Given that we try to add sub-type of rma:recordsManagementContainer to a record folder,
+     * Then IntegrityException is thrown.
+     */
+    @Test(expected = IntegrityException.class)
+    public void testCreateSubTypesOfRecordManagementContainer() throws Exception
+    {
+        NodeRef recordFolderNodeRef = AlfMock.generateNodeRef(mockedNodeService, TYPE_RECORD_FOLDER);
+        QName type = AlfMock.generateQName();
+        when(mockedDictionaryService.isSubClass(type, TYPE_RECORDS_MANAGEMENT_CONTAINER)).thenReturn(true);
+        NodeRef nodeRef = AlfMock.generateNodeRef(mockedNodeService, type, true);
+        ChildAssociationRef childAssocRef = generateChildAssociationRef(recordFolderNodeRef, nodeRef);
+        recordFolderType.onCreateChildAssociation(childAssocRef, true);
+    }
+
+    /**
+     * Given that we try to add cm:folder sub-type to a record folder,
+     * Then the operation is successful.
+     */
+    @Test
+    public void testCreateFolderSubType() throws Exception
+    {
+        NodeRef recordFolderNodeRef = AlfMock.generateNodeRef(mockedNodeService, TYPE_RECORD_FOLDER);
+        QName type = AlfMock.generateQName();
+        when(mockedDictionaryService.isSubClass(type, TYPE_FOLDER)).thenReturn(true);
+        NodeRef nodeRef = AlfMock.generateNodeRef(mockedNodeService, type, true);
+        ChildAssociationRef childAssocRef = generateChildAssociationRef(recordFolderNodeRef, nodeRef);
+        recordFolderType.onCreateChildAssociation(childAssocRef, true);
+    }
+
+    /**
+     * Given that we try to add non cm:folder sub-type to a record folder,
+     * Then IntegrityException is thrown.
+     */
+    @Test(expected = IntegrityException.class)
+    public void testCreateNonFolderSubType() throws Exception
+    {
+        NodeRef recordFolderNodeRef = AlfMock.generateNodeRef(mockedNodeService, TYPE_RECORD_FOLDER);
+        QName type = AlfMock.generateQName();
+        when(mockedDictionaryService.isSubClass(type, TYPE_FOLDER)).thenReturn(false);
+        NodeRef nodeRef = AlfMock.generateNodeRef(mockedNodeService, type, true);
+        ChildAssociationRef childAssocRef = generateChildAssociationRef(recordFolderNodeRef, nodeRef);
+        recordFolderType.onCreateChildAssociation(childAssocRef, true);
+    }
+
+    /**
+     * Given that we try to add cm:content sub-type to a record folder,
+     * Then the operation is successful.
+     */
+    public void testCreateContent() throws Exception
+    {
+        NodeRef recordFolderNodeRef = AlfMock.generateNodeRef(mockedNodeService, TYPE_RECORD_FOLDER);
+        QName type = AlfMock.generateQName();
+        when(mockedDictionaryService.isSubClass(type, TYPE_CONTENT)).thenReturn(true);
+        NodeRef nodeRef = AlfMock.generateNodeRef(mockedNodeService, type, true);
+        ChildAssociationRef childAssocRef = generateChildAssociationRef(recordFolderNodeRef, nodeRef);
+        recordFolderType.onCreateChildAssociation(childAssocRef, true);
+    }
+
+    /**
+     * Given that we try to add non cm:content or non cm:folder sub-type to a record folder,
+     * Then IntegrityException is thrown.
+     */
+    @Test(expected = IntegrityException.class)
+    public void testCreateNonContent() throws Exception
+    {
+        NodeRef recordFolderNodeRef = AlfMock.generateNodeRef(mockedNodeService, TYPE_RECORD_FOLDER);
+        QName type = AlfMock.generateQName();
+        when(mockedDictionaryService.isSubClass(type, TYPE_CONTENT)).thenReturn(false);
+        when(mockedDictionaryService.isSubClass(type, TYPE_FOLDER)).thenReturn(false);
+        NodeRef nodeRef = AlfMock.generateNodeRef(mockedNodeService, type, true);
+        ChildAssociationRef childAssocRef = generateChildAssociationRef(recordFolderNodeRef, nodeRef);
+        recordFolderType.onCreateChildAssociation(childAssocRef, true);
+    }
+
+    /**
+     * Given that we try to add not hidden cm:folder sub-type to a record folder,
+     * Then IntegrityException is thrown on commit.
+     */
+    @Test(expected = IntegrityException.class)
+    public void testCreateNotHiddenFolderSubTypeOnCommit() throws Exception
+    {
+        NodeRef recordFolderNodeRef = AlfMock.generateNodeRef(mockedNodeService, TYPE_RECORD_FOLDER);
+        QName type = AlfMock.generateQName();
+        when(mockedDictionaryService.isSubClass(type, TYPE_FOLDER)).thenReturn(true);
+        NodeRef nodeRef = AlfMock.generateNodeRef(mockedNodeService, type, true);
+        ChildAssociationRef childAssocRef = generateChildAssociationRef(recordFolderNodeRef, nodeRef);
+        recordFolderType.onCreateChildAssociationOnCommit(childAssocRef, true);
+    }
+
+    /**
+     * Given that we try to add hidden cm:folder sub-type to a record folder,
+     * Then the operation is successful.
+     */
+    @Test
+    public void testCreateHiddenFolderSubTypeOnCommit() throws Exception
+    {
+        NodeRef recordFolderNodeRef = AlfMock.generateNodeRef(mockedNodeService, TYPE_RECORD_FOLDER);
+        QName type = AlfMock.generateQName();
+        NodeRef nodeRef = AlfMock.generateNodeRef(mockedNodeService, type, true);
+
+        when(mockedDictionaryService.isSubClass(type, TYPE_FOLDER)).thenReturn(true);
+        when(mockedNodeService.hasAspect(nodeRef, ASPECT_HIDDEN)).thenReturn(true);
+
+        ChildAssociationRef childAssocRef = generateChildAssociationRef(recordFolderNodeRef, nodeRef);
+        recordFolderType.onCreateChildAssociationOnCommit(childAssocRef, true);
+    }
+
+    /**
+     * Given that we try to add non cm:folder sub-type to a record folder,
+     * Then the operation is successful.
+     */
+    @Test
+    public void testCreateNonFolderSubTypeOnCommit() throws Exception
+    {
+        NodeRef recordFolderNodeRef = AlfMock.generateNodeRef(mockedNodeService, TYPE_RECORD_FOLDER);
+        QName type = AlfMock.generateQName();
+        NodeRef nodeRef = AlfMock.generateNodeRef(mockedNodeService, type, true);
+
+        when(mockedDictionaryService.isSubClass(type, TYPE_FOLDER)).thenReturn(false);
+
+        ChildAssociationRef childAssocRef = generateChildAssociationRef(recordFolderNodeRef, nodeRef);
+        recordFolderType.onCreateChildAssociationOnCommit(childAssocRef, true);
+    }
+}
diff --git a/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/RmSiteTypeUnitTest.java b/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/RmSiteTypeUnitTest.java
index a9483509ad..5e876ffaed 100644
--- a/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/RmSiteTypeUnitTest.java
+++ b/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/RmSiteTypeUnitTest.java
@@ -30,7 +30,6 @@ package org.alfresco.module.org_alfresco_module_rm.model.rma.type;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
-import java.security.InvalidParameterException;
 import java.util.ArrayList;
 
 import org.alfresco.module.org_alfresco_module_rm.dod5015.DOD5015Model;
@@ -38,6 +37,7 @@ import org.alfresco.module.org_alfresco_module_rm.test.util.AlfMock;
 import org.alfresco.module.org_alfresco_module_rm.test.util.BaseUnitTest;
 import org.alfresco.module.org_alfresco_module_rm.test.util.MockAuthenticationUtilHelper;
 import org.alfresco.module.org_alfresco_module_rm.util.AuthenticationUtil;
+import org.alfresco.repo.node.integrity.IntegrityException;
 import org.alfresco.service.cmr.repository.ChildAssociationRef;
 import org.alfresco.service.cmr.repository.NodeRef;
 import org.alfresco.service.cmr.site.SiteInfo;
@@ -77,9 +77,9 @@ public class RmSiteTypeUnitTest extends BaseUnitTest implements DOD5015Model
 
     /**
      * Given that we try to add non allowed type to rm site,
-     * Then InvalidParameterException is thrown.
+     * Then IntegrityException is thrown.
      */
-    @Test(expected = InvalidParameterException.class)
+    @Test(expected = IntegrityException.class)
     public void testAddNonAcceptedTypeToRmSite()
     {
         NodeRef rmSiteNodeRef = generateNodeRef(TYPE_RM_SITE, true);
@@ -149,9 +149,9 @@ public class RmSiteTypeUnitTest extends BaseUnitTest implements DOD5015Model
 
     /**
      * Given that we try to add more than two cm:folder to rm site,
-     * Then InvalidParameterException is thrown.
+     * Then IntegrityException is thrown.
      */
-    @Test(expected = InvalidParameterException.class)
+    @Test(expected = IntegrityException.class)
     public void testAddMoreThanTwhoFolderTypeToRmSite()
     {
         NodeRef rmSiteNodeRef = generateNodeRef(TYPE_RM_SITE, true);
@@ -208,9 +208,9 @@ public class RmSiteTypeUnitTest extends BaseUnitTest implements DOD5015Model
 
     /**
      * Given that we try to add one dod:filePlan to standard rm site,
-     * Then InvalidParameterException is thrown.
+     * Then IntegrityException is thrown.
      */
-    @Test(expected = InvalidParameterException.class)
+    @Test(expected = IntegrityException.class)
     public void testAddDODFilePlanTypeToStandardRmSite()
     {
         NodeRef rmSiteNodeRef = generateNodeRef(TYPE_RM_SITE, true);
@@ -225,9 +225,9 @@ public class RmSiteTypeUnitTest extends BaseUnitTest implements DOD5015Model
 
     /**
      * Given that we try to add more than one rma:filePlan to rm site,
-     * Then InvalidParameterException is thrown.
+     * Then IntegrityException is thrown.
      */
-    @Test(expected = InvalidParameterException.class)
+    @Test(expected = IntegrityException.class)
     public void testAddMoreThanOneFilePlanTypeToRmSite()
     {
         NodeRef rmSiteNodeRef = generateNodeRef(TYPE_RM_SITE, true);
@@ -281,9 +281,9 @@ public class RmSiteTypeUnitTest extends BaseUnitTest implements DOD5015Model
 
     /**
      * Given that we try to add more than one dod:filePlan to rm site,
-     * Then InvalidParameterException is thrown.
+     * Then IntegrityException is thrown.
      */
-    @Test(expected = InvalidParameterException.class)
+    @Test(expected = IntegrityException.class)
     public void testAddMoreThanOneDODFilePlanTypeToRmSite()
     {
         NodeRef rmSiteNodeRef = generateNodeRef(TYPE_DOD_5015_SITE, true);
@@ -315,9 +315,9 @@ public class RmSiteTypeUnitTest extends BaseUnitTest implements DOD5015Model
 
     /**
      * Given that we try to add one rma:filePlan to DOD rm site,
-     * Then InvalidParameterException is thrown.
+     * Then IntegrityException is thrown.
      */
-    @Test(expected = InvalidParameterException.class)
+    @Test(expected = IntegrityException.class)
     public void testAddStandardFilePlanTypeToDODRmSite()
     {
         NodeRef rmSiteNodeRef = generateNodeRef(TYPE_DOD_5015_SITE, true);
diff --git a/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/TransferContainerTypeUnitTest.java b/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/TransferContainerTypeUnitTest.java
index 1623164f25..2126da6b8b 100644
--- a/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/TransferContainerTypeUnitTest.java
+++ b/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/TransferContainerTypeUnitTest.java
@@ -29,10 +29,9 @@ package org.alfresco.module.org_alfresco_module_rm.model.rma.type;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
-import java.security.InvalidParameterException;
-
 import org.alfresco.module.org_alfresco_module_rm.test.util.AlfMock;
 import org.alfresco.module.org_alfresco_module_rm.test.util.BaseUnitTest;
+import org.alfresco.repo.node.integrity.IntegrityException;
 import org.alfresco.service.cmr.repository.ChildAssociationRef;
 import org.alfresco.service.cmr.repository.NodeRef;
 import org.alfresco.service.namespace.QName;
@@ -52,9 +51,9 @@ public class TransferContainerTypeUnitTest extends BaseUnitTest
 
     /**
      * Given that we try to add to transfer container,
-     * Then InvalidParameterException is thrown.
+     * Then IntegrityException is thrown.
      */
-    @Test(expected = InvalidParameterException.class)
+    @Test(expected = IntegrityException.class)
     public void testAddToTransferContainerTest()
     {
         NodeRef transferContainer = generateNodeRef(TYPE_TRANSFER_CONTAINER, true);
diff --git a/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/TransferTypeUnitTest.java b/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/TransferTypeUnitTest.java
index d16b49759a..fe5cf4a69a 100644
--- a/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/TransferTypeUnitTest.java
+++ b/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/TransferTypeUnitTest.java
@@ -30,10 +30,9 @@ package org.alfresco.module.org_alfresco_module_rm.model.rma.type;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
-import java.security.InvalidParameterException;
-
 import org.alfresco.module.org_alfresco_module_rm.test.util.AlfMock;
 import org.alfresco.module.org_alfresco_module_rm.test.util.BaseUnitTest;
+import org.alfresco.repo.node.integrity.IntegrityException;
 import org.alfresco.service.cmr.repository.ChildAssociationRef;
 import org.alfresco.service.cmr.repository.NodeRef;
 import org.alfresco.service.namespace.QName;
@@ -53,9 +52,9 @@ public class TransferTypeUnitTest extends BaseUnitTest
 
     /**
      * Given that we try to add to transfer type folder,
-     * Then InvalidParameterException is thrown.
+     * Then IntegrityException is thrown.
      */
-    @Test(expected = InvalidParameterException.class)
+    @Test(expected = IntegrityException.class)
     public void testAddToTransferFolderTest()
     {
         NodeRef transferFolder = generateNodeRef(TYPE_TRANSFER, true);
diff --git a/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/UnfiledRecordContainerTypeUnitTest.java b/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/UnfiledRecordContainerTypeUnitTest.java
index 5ed5fc662e..6edd9c2eda 100644
--- a/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/UnfiledRecordContainerTypeUnitTest.java
+++ b/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/UnfiledRecordContainerTypeUnitTest.java
@@ -30,11 +30,10 @@ package org.alfresco.module.org_alfresco_module_rm.model.rma.type;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
-import java.security.InvalidParameterException;
-
 import org.alfresco.model.ContentModel;
 import org.alfresco.module.org_alfresco_module_rm.test.util.AlfMock;
 import org.alfresco.module.org_alfresco_module_rm.test.util.BaseUnitTest;
+import org.alfresco.repo.node.integrity.IntegrityException;
 import org.alfresco.service.cmr.repository.ChildAssociationRef;
 import org.alfresco.service.cmr.repository.NodeRef;
 import org.alfresco.service.namespace.QName;
@@ -54,9 +53,9 @@ public class UnfiledRecordContainerTypeUnitTest extends BaseUnitTest
 
     /**
      * Given that we try to add a type that is not one of "rma:unfiledRecordFolder", "cm:content" or "rma:nonElectronicDocument" types to unfiled record container,
-     * Then InvalidParameterException is thrown.
+     * Then IntegrityException is thrown.
      */
-    @Test(expected = InvalidParameterException.class)
+    @Test(expected = IntegrityException.class)
     public void testAddNonAcceptedTypeToUnfiledRecordContainer()
     {
         QName type = AlfMock.generateQName();
diff --git a/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/UnfiledRecordFolderTypeUnitTest.java b/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/UnfiledRecordFolderTypeUnitTest.java
index 18efc7ecde..34f5411031 100644
--- a/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/UnfiledRecordFolderTypeUnitTest.java
+++ b/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/UnfiledRecordFolderTypeUnitTest.java
@@ -30,11 +30,10 @@ package org.alfresco.module.org_alfresco_module_rm.model.rma.type;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
-import java.security.InvalidParameterException;
-
 import org.alfresco.model.ContentModel;
 import org.alfresco.module.org_alfresco_module_rm.test.util.AlfMock;
 import org.alfresco.module.org_alfresco_module_rm.test.util.BaseUnitTest;
+import org.alfresco.repo.node.integrity.IntegrityException;
 import org.alfresco.service.cmr.repository.ChildAssociationRef;
 import org.alfresco.service.cmr.repository.NodeRef;
 import org.alfresco.service.namespace.QName;
@@ -54,9 +53,9 @@ public class UnfiledRecordFolderTypeUnitTest extends BaseUnitTest
 
     /**
      * Given that we try to add a type that is not one of "rma:unfiledRecordFolder", "cm:content" or "rma:nonElectronicDocument" types to unfiled record folder,
-     * Then InvalidParameterException is thrown.
+     * Then IntegrityException is thrown.
      */
-    @Test(expected = InvalidParameterException.class)
+    @Test(expected = IntegrityException.class)
     public void testAddNonAcceptedTypeToUnfiledRecordFolder()
     {
         QName type = AlfMock.generateQName();
diff --git a/rm-community/rm-community-repo/unit-test/java/org/alfresco/rm/rest/api/impl/RMNodesImplUnitTest.java b/rm-community/rm-community-repo/unit-test/java/org/alfresco/rm/rest/api/impl/RMNodesImplUnitTest.java
index abbb8e9aa7..3ae63a99c2 100644
--- a/rm-community/rm-community-repo/unit-test/java/org/alfresco/rm/rest/api/impl/RMNodesImplUnitTest.java
+++ b/rm-community/rm-community-repo/unit-test/java/org/alfresco/rm/rest/api/impl/RMNodesImplUnitTest.java
@@ -30,6 +30,7 @@ package org.alfresco.rm.rest.api.impl;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 import static org.mockito.Matchers.any;
@@ -44,8 +45,6 @@ import java.util.ArrayList;
 import java.util.List;
 
 import org.alfresco.model.ContentModel;
-import org.alfresco.module.org_alfresco_module_rm.capability.Capability;
-import org.alfresco.module.org_alfresco_module_rm.capability.CapabilityService;
 import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionSchedule;
 import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel;
 import org.alfresco.module.org_alfresco_module_rm.test.util.AlfMock;
@@ -75,8 +74,6 @@ import org.mockito.InjectMocks;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
-import net.sf.acegisecurity.vote.AccessDecisionVoter;
-
 /**
  * Unit Test class for RMNodesImpl.
  *
@@ -106,17 +103,10 @@ public class RMNodesImplUnitTest extends BaseUnitTest
 
     @Mock
     private ServiceRegistry mockedServiceRegistry;
-    
-    @Mock
-    private CapabilityService mockedCapabilityService;
 
     @InjectMocks
     private RMNodesImpl rmNodesImpl;
 
-    private Capability deleteCapability;
-    private Capability createCapability;
-    private Capability updateCapability;
-
     @Before
     public void before()
     {
@@ -127,12 +117,6 @@ public class RMNodesImplUnitTest extends BaseUnitTest
         when(mockedNamespaceService.getPrefixes(any(String.class))).thenReturn(prefixes);
         when(mockedNamespaceService.getNamespaceURI(any(String.class))).thenReturn(RM_URI);
 
-        deleteCapability = mock(Capability.class);
-        when(mockedCapabilityService.getCapability("Delete")).thenReturn(deleteCapability);
-        createCapability = mock(Capability.class);
-        when(mockedCapabilityService.getCapability("FillingPermissionOnly")).thenReturn(createCapability);
-        updateCapability = mock(Capability.class);
-        when(mockedCapabilityService.getCapability("Update")).thenReturn(updateCapability);
     }
 
     @Test
@@ -176,13 +160,19 @@ public class RMNodesImplUnitTest extends BaseUnitTest
 
         setPermissions(nodeRef, AccessStatus.ALLOWED);
 
-        when(deleteCapability.evaluate(nodeRef)).thenReturn(AccessDecisionVoter.ACCESS_GRANTED);
-        when(createCapability.evaluate(nodeRef)).thenReturn(AccessDecisionVoter.ACCESS_GRANTED);
-        when(updateCapability.evaluate(nodeRef)).thenReturn(AccessDecisionVoter.ACCESS_GRANTED);
-
         when(mockedFilePlanService.getFilePlanBySiteId(RM_SITE_ID)).thenReturn(nodeRef);
         Node folderOrDocument = rmNodesImpl.getFolderOrDocument(nodeRef, null, null, includeParamList, null);
-        checksAllowedOperations(folderOrDocument, false, true, false);
+        assertNotNull(folderOrDocument);
+        assertTrue(FileplanComponentNode.class.isInstance(folderOrDocument));
+
+        FileplanComponentNode resultNode = (FileplanComponentNode) folderOrDocument;
+        assertEquals(false, resultNode.getIsRecordFolder());
+        assertEquals(false, resultNode.getIsFile());
+        assertEquals(false, resultNode.getIsCategory());
+        List allowableOperations = resultNode.getAllowableOperations();
+        assertTrue("Create operation should be available for FilePlan.", allowableOperations.contains(RMNodes.OP_CREATE));
+        assertTrue("Update operation should be available for FilePlan.", allowableOperations.contains(RMNodes.OP_UPDATE));
+        assertFalse("Delete operation should note be available for FilePlan.", allowableOperations.contains(RMNodes.OP_DELETE));
     }
 
     @Test
@@ -213,15 +203,15 @@ public class RMNodesImplUnitTest extends BaseUnitTest
         assertEquals(false, resultNode.getIsFile());
         assertEquals(false, resultNode.getIsCategory());
         List allowableOperations = resultNode.getAllowableOperations();
-        assertEquals(0, allowableOperations.size());
+        assertNull(allowableOperations);
     }
 
     @Test
     public void testGetTransferContainerAllowableOperations() throws Exception
     {
         NodeRef nodeRef = AlfMock.generateNodeRef(mockedNodeService);
-        when(mockedNodeService.getType(nodeRef)).thenReturn(RecordsManagementModel.TYPE_TRANSFER_CONTAINER);
-        when(mockedDictionaryService.isSubClass(RecordsManagementModel.TYPE_TRANSFER_CONTAINER, ContentModel.TYPE_FOLDER)).thenReturn(true);
+        when(mockedNodeService.getType(nodeRef)).thenReturn(RecordsManagementModel.TYPE_RECORD_CATEGORY);
+        when(mockedDictionaryService.isSubClass(RecordsManagementModel.TYPE_RECORD_CATEGORY, ContentModel.TYPE_FOLDER)).thenReturn(true);
 
         setupCompanyHomeAndPrimaryParent(nodeRef);
 
@@ -234,22 +224,16 @@ public class RMNodesImplUnitTest extends BaseUnitTest
         when(mockedFilePlanService.getFilePlanBySiteId(RM_SITE_ID)).thenReturn(filePlanNodeRef);
         when(mockedFilePlanService.getTransferContainer(filePlanNodeRef)).thenReturn(nodeRef);
 
-        when(deleteCapability.evaluate(nodeRef)).thenReturn(AccessDecisionVoter.ACCESS_GRANTED);
-        when(createCapability.evaluate(nodeRef)).thenReturn(AccessDecisionVoter.ACCESS_GRANTED);
-        when(updateCapability.evaluate(nodeRef)).thenReturn(AccessDecisionVoter.ACCESS_GRANTED);
-
-        when(mockedFilePlanService.isFilePlanComponent(nodeRef)).thenReturn(true);
-
         Node folderOrDocument = rmNodesImpl.getFolderOrDocument(nodeRef, null, null, includeParamList, null);
-        checksAllowedOperations(folderOrDocument, false, true, false);
+        checkSpecialContainersAllowedOperations(folderOrDocument);
     }
 
     @Test
     public void testGetHoldContainerAllowableOperations() throws Exception
     {
         NodeRef nodeRef = AlfMock.generateNodeRef(mockedNodeService);
-        when(mockedNodeService.getType(nodeRef)).thenReturn(RecordsManagementModel.TYPE_HOLD_CONTAINER);
-        when(mockedDictionaryService.isSubClass(RecordsManagementModel.TYPE_HOLD_CONTAINER, ContentModel.TYPE_FOLDER)).thenReturn(true);
+        when(mockedNodeService.getType(nodeRef)).thenReturn(RecordsManagementModel.TYPE_RECORD_CATEGORY);
+        when(mockedDictionaryService.isSubClass(RecordsManagementModel.TYPE_RECORD_CATEGORY, ContentModel.TYPE_FOLDER)).thenReturn(true);
 
         setupCompanyHomeAndPrimaryParent(nodeRef);
 
@@ -266,22 +250,16 @@ public class RMNodesImplUnitTest extends BaseUnitTest
 
         when(mockedFilePlanService.getHoldContainer(filePlanNodeRef)).thenReturn(nodeRef);
 
-        when(deleteCapability.evaluate(nodeRef)).thenReturn(AccessDecisionVoter.ACCESS_GRANTED);
-        when(createCapability.evaluate(nodeRef)).thenReturn(AccessDecisionVoter.ACCESS_GRANTED);
-        when(updateCapability.evaluate(nodeRef)).thenReturn(AccessDecisionVoter.ACCESS_GRANTED);
-
-        when(mockedFilePlanService.isFilePlanComponent(nodeRef)).thenReturn(true);
-
         Node folderOrDocument = rmNodesImpl.getFolderOrDocument(nodeRef, null, null, includeParamList, null);
-        checksAllowedOperations(folderOrDocument, true, true, false);
+        checkSpecialContainersAllowedOperations(folderOrDocument);
     }
 
     @Test
     public void testGetUnfiledContainerAllowableOperations() throws Exception
     {
         NodeRef nodeRef = AlfMock.generateNodeRef(mockedNodeService);
-        when(mockedNodeService.getType(nodeRef)).thenReturn(RecordsManagementModel.TYPE_UNFILED_RECORD_CONTAINER);
-        when(mockedDictionaryService.isSubClass(RecordsManagementModel.TYPE_UNFILED_RECORD_CONTAINER, ContentModel.TYPE_FOLDER)).thenReturn(true);
+        when(mockedNodeService.getType(nodeRef)).thenReturn(RecordsManagementModel.TYPE_RECORD_CATEGORY);
+        when(mockedDictionaryService.isSubClass(RecordsManagementModel.TYPE_RECORD_CATEGORY, ContentModel.TYPE_FOLDER)).thenReturn(true);
 
         setupCompanyHomeAndPrimaryParent(nodeRef);
 
@@ -301,14 +279,8 @@ public class RMNodesImplUnitTest extends BaseUnitTest
 
         when(mockedFilePlanService.getUnfiledContainer(filePlanNodeRef)).thenReturn(nodeRef);
 
-        when(deleteCapability.evaluate(nodeRef)).thenReturn(AccessDecisionVoter.ACCESS_GRANTED);
-        when(createCapability.evaluate(nodeRef)).thenReturn(AccessDecisionVoter.ACCESS_GRANTED);
-        when(updateCapability.evaluate(nodeRef)).thenReturn(AccessDecisionVoter.ACCESS_GRANTED);
-
-        when(mockedFilePlanService.isFilePlanComponent(nodeRef)).thenReturn(true);
-
         Node folderOrDocument = rmNodesImpl.getFolderOrDocument(nodeRef, null, null, includeParamList, null);
-        checksAllowedOperations(folderOrDocument, true, true, false);
+        checkSpecialContainersAllowedOperations(folderOrDocument);
     }
 
     @Test
@@ -769,23 +741,18 @@ public class RMNodesImplUnitTest extends BaseUnitTest
         when(mockedPermissionService.hasPermission(nodeRef, PermissionService.ADD_CHILDREN)).thenReturn(permissionToSet);
     }
 
-    private void checksAllowedOperations(Node containerNode, boolean allowCreate, boolean allowUpdate, boolean allowDelete)
+    private void checkSpecialContainersAllowedOperations(Node containerNode)
     {
         assertNotNull(containerNode);
-        assertTrue(FileplanComponentNode.class.isInstance(containerNode));
-        FileplanComponentNode resultNode = (FileplanComponentNode) containerNode;
+        assertTrue(RecordCategoryNode.class.isInstance(containerNode));
+
+        RecordCategoryNode resultNode = (RecordCategoryNode) containerNode;
+        assertEquals(false, resultNode.getIsRecordFolder());
+        assertEquals(false, resultNode.getIsFile());
+        assertEquals(true, resultNode.getIsCategory());
         List allowableOperations = resultNode.getAllowableOperations();
-
-        assertEquals("Create operation should " + (allowCreate?"":"not ") + "be available for provided container.", 
-                allowCreate, 
-                allowableOperations.contains(RMNodes.OP_CREATE));
-  
-        assertEquals("Update operation should " + (allowCreate?"":"not ") + "be available for provided container.", 
-                allowUpdate, 
-                allowableOperations.contains(RMNodes.OP_UPDATE));
-
-        assertEquals("Delete operation should " + (allowCreate?"":"not ") + "be available for provided container.", 
-                allowDelete, 
-                allowableOperations.contains(RMNodes.OP_DELETE));
+        assertTrue("Create operation should be available for provided container.", allowableOperations.contains(RMNodes.OP_CREATE));
+        assertTrue("Update operation should be available for provided container.", allowableOperations.contains(RMNodes.OP_UPDATE));
+        assertFalse("Delete operation should note be available for provided container.", allowableOperations.contains(RMNodes.OP_DELETE));
     }
 }