diff --git a/build.gradle b/build.gradle index d37ed7e726..3be5fe81a3 100644 --- a/build.gradle +++ b/build.gradle @@ -227,7 +227,7 @@ subprojects { copy { from "${configModuleDir}" include "${moduleProperties}" - include "${fileMapping}" + include "${fileMapping}" into assembleDir } @@ -239,7 +239,8 @@ subprojects { copy { from configDir exclude "**/${moduleProperties}" - exclude "**/${fileMapping}" + exclude "**/${fileMapping}" + exclude "**/dev-context.xml" into "${assembleDir}/config" } diff --git a/rm-server/config/alfresco/module/org_alfresco_module_rm/log4j.properties b/rm-server/config/alfresco/module/org_alfresco_module_rm/log4j.properties index 57c59d75ba..ec18e783e1 100644 --- a/rm-server/config/alfresco/module/org_alfresco_module_rm/log4j.properties +++ b/rm-server/config/alfresco/module/org_alfresco_module_rm/log4j.properties @@ -1,2 +1,3 @@ log4j.logger.org.alfresco.module.org_alfresco_module_rm.caveat=warn log4j.logger.org.alfresco.module.org_alfresco_module_rm.security.RMMethodSecurityPostProcessor=warn +log4j.logger.org.alfresco.module.org_alfresco_module_rm.patch=debug diff --git a/rm-server/config/alfresco/module/org_alfresco_module_rm/model/recordsModel.xml b/rm-server/config/alfresco/module/org_alfresco_module_rm/model/recordsModel.xml index 3f93a56a23..9dea1037dd 100644 --- a/rm-server/config/alfresco/module/org_alfresco_module_rm/model/recordsModel.xml +++ b/rm-server/config/alfresco/module/org_alfresco_module_rm/model/recordsModel.xml @@ -581,7 +581,6 @@ - File Plan Component false diff --git a/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-patch-context.xml b/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-patch-context.xml index 469a4ec2fe..4822dc0072 100644 --- a/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-patch-context.xml +++ b/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-patch-context.xml @@ -49,6 +49,22 @@ + + + + + + + + + + + + + + { - "data": - { - "customProperties": - { - <#list customProps as prop> - "${prop.name.toPrefixString()}": - { - "dataType": "<#if prop.dataType??>${prop.dataType.name.toPrefixString()}", - "label": "${prop.title!""}", - "description": "${prop.description!""}", - "mandatory": ${prop.mandatory?string}, - "multiValued": ${prop.multiValued?string}, - "defaultValue": "${prop.defaultValue!""}", - "protected": ${prop.protected?string}, - "propId": "${prop.name.localName}", - "constraintRefs": - [ - <#list prop.constraints as con> - { - "name": "${con.constraint.shortName!""}", - "title": "${con.title!""}", - "type": "${con.constraint.type!""}", - "parameters": - { - <#-- Basic implementation. Only providing 2 hardcoded parameters. --> - <#assign lov = con.constraint.parameters["allowedValues"]> - "caseSensitive": ${con.constraint.parameters["caseSensitive"]?string}, - "listOfValues" : - [ - <#list lov as val>"${val}"<#if val_has_next>, - ] - } - }<#if con_has_next>, - - ] - }<#if prop_has_next>, - - } - } + "data": + { + "customProperties": + { + <#list customProps as prop> + "${prop.name.toPrefixString()}": + { + "dataType": "<#if prop.dataType??>${prop.dataType.name.toPrefixString()}", + "label": "${prop.title!""}", + "description": "${prop.description!""}", + "mandatory": ${prop.mandatory?string}, + "multiValued": ${prop.multiValued?string}, + "defaultValue": "${prop.defaultValue!""}", + "protected": ${prop.protected?string}, + "propId": "${prop.name.localName}", + "constraintRefs": + [ + <#list prop.constraints as con> + { + "name": "${con.constraint.shortName!""}", + "title": "${con.constraint.title!""}", + "type": "${con.constraint.type!""}", + "parameters": + { + <#-- Basic implementation. Only providing 2 hardcoded parameters. --> + <#assign lov = con.constraint.parameters["allowedValues"]> + "caseSensitive": ${con.constraint.parameters["caseSensitive"]?string}, + "listOfValues" : + [ + <#list lov as val>"${val}"<#if val_has_next>, + ] + } + }<#if con_has_next>, + + ] + }<#if prop_has_next>, + + } + } } \ No newline at end of file diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/RecordsManagementAdminServiceImpl.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/RecordsManagementAdminServiceImpl.java index fe9c67439f..8540efc651 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/RecordsManagementAdminServiceImpl.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/RecordsManagementAdminServiceImpl.java @@ -1246,7 +1246,8 @@ public class RecordsManagementAdminServiceImpl implements RecordsManagementAdmin String compoundID = this.getCompoundIdFor(source, target); if (existsLabel(compoundID)) { - throw new IllegalArgumentException(I18NUtil.getMessage(MSG_REF_LABEL_IN_USE, compoundID)); + return null; + //throw new IllegalArgumentException(I18NUtil.getMessage(MSG_REF_LABEL_IN_USE, compoundID)); } NodeRef modelRef = getCustomModelRef(""); // defaults to RM_CUSTOM_URI diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/action/RMActionExecuterAbstractBase.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/action/RMActionExecuterAbstractBase.java index a0ae7e4b48..1373d5eea1 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/action/RMActionExecuterAbstractBase.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/action/RMActionExecuterAbstractBase.java @@ -528,7 +528,8 @@ public abstract class RMActionExecuterAbstractBase extends PropertySubActionExe // Get the period properties value QName periodProperty = nextDispositionActionDefinition.getPeriodProperty(); - if (periodProperty != null) + if (periodProperty != null && + RecordsManagementModel.PROP_DISPOSITION_AS_OF.equals(periodProperty) == false) { // doesn't matter if the period property isn't set ... the asOfDate will get updated later // when the value of the period property is set diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/audit/RecordsManagementAuditServiceImpl.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/audit/RecordsManagementAuditServiceImpl.java index 1d4b8a4619..c7a48c1cf1 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/audit/RecordsManagementAuditServiceImpl.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/audit/RecordsManagementAuditServiceImpl.java @@ -322,6 +322,10 @@ public class RecordsManagementAuditServiceImpl new AuditEvent("unfreeze", MSG_UNFREEZE)); this.auditEvents.put("reject", new AuditEvent("reject", MSG_REJECT_RECORD)); + + // Added for DOD compliance + this.auditEvents.put("createPerson", + new AuditEvent("createPerson", "User Created")); } @Override @@ -341,7 +345,11 @@ public class RecordsManagementAuditServiceImpl policyComponent.bindClassBehaviour( BeforeDeleteNodePolicy.QNAME, RecordsManagementModel.ASPECT_RECORD_COMPONENT_ID, - new JavaBehaviour(this, "beforeDeleteNode")); + new JavaBehaviour(this, "beforeDeleteNode")); + policyComponent.bindClassBehaviour( + OnCreateNodePolicy.QNAME, + ContentModel.TYPE_PERSON, + new JavaBehaviour(this, "onCreatePersonNode")); } @Override @@ -473,7 +481,12 @@ public class RecordsManagementAuditServiceImpl { auditRMEvent(childAssocRef.getChildRef(), RM_AUDIT_EVENT_CREATE_RM_OBJECT, null, null); } - + + public void onCreatePersonNode(ChildAssociationRef childAssocRef) + { + auditRMEvent(childAssocRef.getChildRef(), "createPerson", null, null); + } + /** * {@inheritDoc} * @since 3.2 @@ -505,19 +518,9 @@ public class RecordsManagementAuditServiceImpl { // Deleted nodes will not be available at the end of the transaction. The data needs to // be extracted now and the audit entry needs to be created now. - Map auditMap = new HashMap(13); - auditMap.put( - AuditApplication.buildPath( - RecordsManagementAuditService.RM_AUDIT_SNIPPET_EVENT, - RecordsManagementAuditService.RM_AUDIT_SNIPPET_NAME), - eventName); - // Action node - auditMap.put( - AuditApplication.buildPath( - RecordsManagementAuditService.RM_AUDIT_SNIPPET_EVENT, - RecordsManagementAuditService.RM_AUDIT_SNIPPET_NODE), - nodeRef); + Map auditMap = buildAuditMap(nodeRef, eventName); auditMap = auditComponent.recordAuditValues(RecordsManagementAuditService.RM_AUDIT_PATH_ROOT, auditMap); + if (logger.isDebugEnabled()) { logger.debug("RM Audit: Audited node deletion: \n" + auditMap); @@ -555,6 +558,31 @@ public class RecordsManagementAuditServiceImpl // That is it. The values are queued for the end of the transaction. } } + + /** + * Helper method to build audit map + * + * @param nodeRef + * @param eventName + * @return + * @since 2.0.3 + */ + private Map buildAuditMap(NodeRef nodeRef, String eventName) + { + Map auditMap = new HashMap(13); + auditMap.put( + AuditApplication.buildPath( + RecordsManagementAuditService.RM_AUDIT_SNIPPET_EVENT, + RecordsManagementAuditService.RM_AUDIT_SNIPPET_NAME), + eventName); + // Action node + auditMap.put( + AuditApplication.buildPath( + RecordsManagementAuditService.RM_AUDIT_SNIPPET_EVENT, + RecordsManagementAuditService.RM_AUDIT_SNIPPET_NODE), + nodeRef); + return auditMap; + } /** * A stateless transaction listener for RM auditing. This component picks up the data of @@ -615,20 +643,13 @@ public class RecordsManagementAuditServiceImpl RMAuditNode auditedNode = entry.getValue(); - Map auditMap = new HashMap(13); // Action description String eventName = auditedNode.getEventName(); - auditMap.put( - AuditApplication.buildPath( - RecordsManagementAuditService.RM_AUDIT_SNIPPET_EVENT, - RecordsManagementAuditService.RM_AUDIT_SNIPPET_NAME), - eventName); - // Action node - auditMap.put( - AuditApplication.buildPath( - RecordsManagementAuditService.RM_AUDIT_SNIPPET_EVENT, - RecordsManagementAuditService.RM_AUDIT_SNIPPET_NODE), - nodeRef); + + Map auditMap = buildAuditMap(nodeRef, eventName); + + // TODO do we care if the before and after are null?? + // Property changes Map propertiesBefore = auditedNode.getNodePropertiesBefore(); Map propertiesAfter = auditedNode.getNodePropertiesAfter(); @@ -648,6 +669,7 @@ public class RecordsManagementAuditServiceImpl RecordsManagementAuditService.RM_AUDIT_SNIPPET_CHANGES, RecordsManagementAuditService.RM_AUDIT_SNIPPET_AFTER), (Serializable) deltaPair.getSecond()); + // Audit it if (logger.isDebugEnabled()) { @@ -742,7 +764,7 @@ public class RecordsManagementAuditServiceImpl * @param reportFormat Format to write the audit trail in, ignored if writer is null */ private void getAuditTrailImpl( - RecordsManagementAuditQueryParameters params, + final RecordsManagementAuditQueryParameters params, final List results, final Writer writer, final ReportFormat reportFormat) @@ -785,6 +807,7 @@ public class RecordsManagementAuditServiceImpl return false; } + Date timestamp = new Date(time); String eventName = null; String fullName = null; @@ -846,6 +869,22 @@ public class RecordsManagementAuditServiceImpl return true; } + // filter out events if set + if (params.getEvent() != null && + params.getEvent().endsWith(eventName) == false) + { + // skip it + return true; + } + + + if (params.getProperty() != null && + getChangedProperties(beforeProperties, afterProperties).contains(params.getProperty()) == false) + { + // skip it + return false; + } + // TODO: Refactor this to use the builder pattern RecordsManagementAuditEntry entry = new RecordsManagementAuditEntry( timestamp, @@ -878,6 +917,32 @@ public class RecordsManagementAuditServiceImpl return true; } + private List getChangedProperties(Map beforeProperties, Map afterProperties) + { + List changedProperties = new ArrayList(21); + + if (beforeProperties != null && afterProperties != null) + { + // add all the properties present before the audited action + for (QName valuePropName : beforeProperties.keySet()) + { + changedProperties.add(valuePropName); + } + + // add all the properties present after the audited action that + // have not already been added + for (QName valuePropName : afterProperties.keySet()) + { + if (!beforeProperties.containsKey(valuePropName)) + { + changedProperties.add(valuePropName); + } + } + } + + return changedProperties; + } + private void writeEntryToFile(RecordsManagementAuditEntry entry) { if (writer == null) @@ -1215,7 +1280,18 @@ public class RecordsManagementAuditServiceImpl json.put("userRole", entry.getUserRole() == null ? "": entry.getUserRole()); json.put("fullName", entry.getFullName() == null ? "": entry.getFullName()); json.put("nodeRef", entry.getNodeRef() == null ? "": entry.getNodeRef()); - json.put("nodeName", entry.getNodeName() == null ? "": entry.getNodeName()); + + if (entry.getEvent().equals("createPerson") == true && entry.getNodeRef() != null) + { + NodeRef nodeRef = entry.getNodeRef(); + String userName = (String)nodeService.getProperty(nodeRef, ContentModel.PROP_USERNAME); + json.put("nodeName", userName == null ? "": userName); + } + else + { + json.put("nodeName", entry.getNodeName() == null ? "": entry.getNodeName()); + } + json.put("nodeType", entry.getNodeType() == null ? "": entry.getNodeType()); json.put("event", entry.getEvent() == null ? "": getAuditEventLabel(entry.getEvent())); json.put("identifier", entry.getIdentifier() == null ? "": entry.getIdentifier()); diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/caveat/ScriptConstraint.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/caveat/ScriptConstraint.java index 2c3598d20d..4e9dec35d1 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/caveat/ScriptConstraint.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/caveat/ScriptConstraint.java @@ -28,29 +28,30 @@ import java.util.List; import java.util.Set; import org.alfresco.service.cmr.security.AuthorityService; +import org.apache.commons.lang.StringUtils; import org.json.JSONArray; import org.json.JSONObject; public class ScriptConstraint implements Serializable { /** - * + * */ private static final long serialVersionUID = 1L; private RMConstraintInfo info; - + private RMCaveatConfigService rmCaveatconfigService; - + private AuthorityService authorityService; - + ScriptConstraint(RMConstraintInfo info, RMCaveatConfigService rmCaveatconfigService, AuthorityService authorityService) { this.info = info; - this.rmCaveatconfigService = rmCaveatconfigService; + this.rmCaveatconfigService = rmCaveatconfigService; this.authorityService = authorityService; } - + public void setTitle(String title) { info.setTitle(title); @@ -63,49 +64,49 @@ public class ScriptConstraint implements Serializable { info.setName(name); } - + public String getName() { String xxx = info.getName().replace(":", "_"); return xxx; } - + public boolean isCaseSensitive() { return info.isCaseSensitive(); } - + public String[] getAllowedValues() { return info.getAllowedValues(); } - + public ScriptConstraintAuthority[] getAuthorities() { Map> values = rmCaveatconfigService.getListDetails(info.getName()); - + if (values == null) { return new ScriptConstraintAuthority[0]; } - + // Here with some data to return Set authorities = values.keySet(); - + ArrayList constraints = new ArrayList(values.size()); for(String authority : authorities) { ScriptConstraintAuthority constraint = new ScriptConstraintAuthority(); constraint.setAuthorityName(authority); constraint.setValues(values.get(authority)); - constraints.add(constraint); + constraints.add(constraint); } - + ScriptConstraintAuthority[] retVal = constraints.toArray(new ScriptConstraintAuthority[constraints.size()]); - - return retVal; + + return retVal; } - + /** * updateTitle */ @@ -114,7 +115,7 @@ public class ScriptConstraint implements Serializable info.setTitle(newTitle); rmCaveatconfigService.updateRMConstraintTitle(info.getName(), newTitle) ; } - + /** * updateAllowedValues */ @@ -123,7 +124,7 @@ public class ScriptConstraint implements Serializable info.setAllowedValues(allowedValues); rmCaveatconfigService.updateRMConstraintAllowedValues(info.getName(), allowedValues); } - + /** * Update a value * @param values @@ -133,7 +134,7 @@ public class ScriptConstraint implements Serializable { for(int i = 0; i < bodge.length(); i++) { - + JSONObject obj = bodge.getJSONObject(i); String value = obj.getString("value"); JSONArray authorities = obj.getJSONArray("authorities"); @@ -142,10 +143,10 @@ public class ScriptConstraint implements Serializable { aList.add(authorities.getString(j)); } - rmCaveatconfigService.updateRMConstraintListValue(info.getName(), value, aList); - } + rmCaveatconfigService.updateRMConstraintListValue(info.getName(), value, aList); + } } - + /** * Update a value * @param values @@ -154,27 +155,27 @@ public class ScriptConstraint implements Serializable public void updateValues(String value, String[] authorities) { List list = Arrays.asList(authorities); - rmCaveatconfigService.updateRMConstraintListValue(info.getName(), value, list); + rmCaveatconfigService.updateRMConstraintListValue(info.getName(), value, list); } - + /** * Cascade delete an authority * @param authority */ public void deleteAuthority(String authority) { - + } - + /** * Cascade delete a value * @param value */ public void deleteValue(String value) { - + } - + /** * Get a single value @@ -184,7 +185,7 @@ public class ScriptConstraint implements Serializable public ScriptConstraintValue getValue(String value) { ScriptConstraintValue[] values = getValues(); - + for(ScriptConstraintValue val : values) { if(val.getValueName().equalsIgnoreCase(value)) @@ -194,39 +195,39 @@ public class ScriptConstraint implements Serializable } return null; } - + public ScriptConstraintValue[] getValues() { // authority, values Map> details = rmCaveatconfigService.getListDetails(info.getName()); - + if (details == null) { details = new HashMap>(); } - + // values, authorities Map> pivot = PivotUtil.getPivot(details); - + // Here with some data to return Set values = pivot.keySet(); - + ArrayList constraints = new ArrayList(pivot.size()); for(String value : values) { ScriptConstraintValue constraint = new ScriptConstraintValue(); constraint.setValueName(value); constraint.setValueTitle(value); - + Listauthorities = pivot.get(value); List sauth = new ArrayList(); for(String authority : authorities) { ScriptAuthority a = new ScriptAuthority(); a.setAuthorityName(authority); - + String displayName = authorityService.getAuthorityDisplayName(authority); - if(displayName != null) + if(StringUtils.isNotBlank(displayName)) { a.setAuthorityTitle(displayName); } @@ -236,10 +237,10 @@ public class ScriptConstraint implements Serializable } sauth.add(a); } - constraint.setAuthorities(sauth); - constraints.add(constraint); + constraint.setAuthorities(sauth); + constraints.add(constraint); } - + /** * Now go through and add any "empty" values */ @@ -251,14 +252,14 @@ public class ScriptConstraint implements Serializable constraint.setValueName(value); constraint.setValueTitle(value); List sauth = new ArrayList(); - constraint.setAuthorities(sauth); + constraint.setAuthorities(sauth); constraints.add(constraint); } } - - + + ScriptConstraintValue[] retVal = constraints.toArray(new ScriptConstraintValue[constraints.size()]); return retVal; } - + } diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/forms/RecordsManagementTypeFormFilter.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/forms/RecordsManagementTypeFormFilter.java index b61b26355e..915cca99cc 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/forms/RecordsManagementTypeFormFilter.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/forms/RecordsManagementTypeFormFilter.java @@ -26,6 +26,7 @@ import java.util.Set; import org.alfresco.module.org_alfresco_module_rm.identifier.IdentifierService; import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel; import org.alfresco.repo.forms.Field; +import org.alfresco.repo.forms.FieldDefinition; import org.alfresco.repo.forms.FieldGroup; import org.alfresco.repo.forms.Form; import org.alfresco.repo.forms.FormData; @@ -84,8 +85,12 @@ public class RecordsManagementTypeFormFilter extends RecordsManagementFormFilter * java.util.List, java.util.List, org.alfresco.repo.forms.Form, * java.util.Map) */ - public void afterGenerate(TypeDefinition type, List fields, List forcedFields, Form form, - Map context) + public void afterGenerate( + TypeDefinition type, + List fields, + List forcedFields, + Form form, + Map context) { QName typeName = type.getName(); if (rmAdminService.isCustomisable(typeName) == true) @@ -102,6 +107,18 @@ public class RecordsManagementTypeFormFilter extends RecordsManagementFormFilter addCustomRMProperties(aspect, form); } } + + // set the id + List fieldDefs = form.getFieldDefinitions(); + for (FieldDefinition fieldDef : fieldDefs) + { + String prefixName = fieldDef.getName(); + if (prefixName.equals("rma:identifier")) + { + String defaultId = identifierService.generateIdentifier(typeName, null); + fieldDef.setDefaultValue(defaultId); + } + } } /** @@ -140,5 +157,4 @@ public class RecordsManagementTypeFormFilter extends RecordsManagementFormFilter public void afterPersist(TypeDefinition item, FormData data, final NodeRef nodeRef) { } - } diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/patch/RMv2FilePlanNodeRefPatch.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/patch/RMv2FilePlanNodeRefPatch.java new file mode 100644 index 0000000000..526b4756cb --- /dev/null +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/patch/RMv2FilePlanNodeRefPatch.java @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2005-2011 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ +package org.alfresco.module.org_alfresco_module_rm.patch; + +import java.util.List; + +import org.alfresco.module.org_alfresco_module_rm.RecordsManagementService; +import org.alfresco.module.org_alfresco_module_rm.dod5015.DOD5015Model; +import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel; +import org.alfresco.repo.domain.node.NodeDAO; +import org.alfresco.repo.domain.patch.PatchDAO; +import org.alfresco.repo.domain.qname.QNameDAO; +import org.alfresco.repo.module.AbstractModuleComponent; +import org.alfresco.repo.policy.BehaviourFilter; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.namespace.QName; +import org.alfresco.util.Pair; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.beans.factory.BeanNameAware; + +/** + * RM v2.0 File Plan Node Ref Patch + * + * @author Roy Wetherall + */ +public class RMv2FilePlanNodeRefPatch extends AbstractModuleComponent + implements BeanNameAware, RecordsManagementModel, DOD5015Model +{ + /** Logger */ + private static Log logger = LogFactory.getLog(RMv2FilePlanNodeRefPatch.class); + + private NodeService nodeService; + private RecordsManagementService recordsManagementService; + private BehaviourFilter behaviourFilter; + private PatchDAO patchDAO; + private NodeDAO nodeDAO; + private QNameDAO qnameDAO; + + public void setNodeService(NodeService nodeService) + { + this.nodeService = nodeService; + } + + public void setRecordsManagementService(RecordsManagementService recordsManagementService) + { + this.recordsManagementService = recordsManagementService; + } + + public void setBehaviourFilter(BehaviourFilter behaviourFilter) + { + this.behaviourFilter = behaviourFilter; + } + + public void setPatchDAO(PatchDAO patchDAO) + { + this.patchDAO = patchDAO; + } + + public void setNodeDAO(NodeDAO nodeDAO) + { + this.nodeDAO = nodeDAO; + } + + public void setQnameDAO(QNameDAO qnameDAO) + { + this.qnameDAO = qnameDAO; + } + + /** + * @see org.alfresco.repo.module.AbstractModuleComponent#executeInternal() + */ + @Override + protected void executeInternal() throws Throwable + { + if (logger.isDebugEnabled() == true) + { + logger.debug("RM Module RMv2FilePlanNodeRef Patch ..."); + } + + Pair aspectPair = qnameDAO.getQName(ASPECT_FILE_PLAN_COMPONENT); + if (aspectPair != null) + { + List records = patchDAO.getNodesByAspectQNameId(aspectPair.getFirst(), 0L, patchDAO.getMaxAdmNodeID()); + + if (logger.isDebugEnabled() == true) + { + logger.debug(" ... updating " + records.size() + " items" ); + } + + behaviourFilter.disableBehaviour(); + try + { + for (Long record : records) + { + Pair recordPair = nodeDAO.getNodePair(record); + NodeRef recordNodeRef = recordPair.getSecond(); + + if (nodeService.getProperty(recordNodeRef, PROP_ROOT_NODEREF) == null) + { + nodeService.setProperty(recordNodeRef, PROP_ROOT_NODEREF, recordsManagementService.getFilePlan(recordNodeRef)); + } + } + } + finally + { + behaviourFilter.enableBehaviour(); + } + } + + if (logger.isDebugEnabled() == true) + { + logger.debug(" ... complete RM Module RMv2FilePlanNodeRef Patch"); + } + + } +} diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/patch/RMv2ModelPatch.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/patch/RMv2ModelPatch.java index 1db2d4fd45..b4b1e5368b 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/patch/RMv2ModelPatch.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/patch/RMv2ModelPatch.java @@ -80,7 +80,7 @@ public class RMv2ModelPatch extends AbstractModuleComponent { if (logger.isDebugEnabled() == true) { - logger.debug("RM Module NotificationTemplatePatch ..."); + logger.debug("RM Module RMv2ModelPatch ..."); } updateQName(QName.createQName(DOD_URI, "filePlan"), TYPE_FILE_PLAN, "TYPE"); diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/script/CustomPropertyDefinitionPut.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/script/CustomPropertyDefinitionPut.java index 71f11e7c68..9567e4b5b0 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/script/CustomPropertyDefinitionPut.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/script/CustomPropertyDefinitionPut.java @@ -22,24 +22,27 @@ import java.io.IOException; import java.io.Serializable; import java.util.HashMap; import java.util.Iterator; +import java.util.List; import java.util.Map; import org.alfresco.module.org_alfresco_module_rm.CustomMetadataException; +import org.alfresco.module.org_alfresco_module_rm.PropertyAlreadyExistsMetadataException; import org.alfresco.module.org_alfresco_module_rm.RecordsManagementAdminService; +import org.alfresco.service.cmr.dictionary.ConstraintDefinition; import org.alfresco.service.namespace.QName; +import org.json.JSONException; +import org.json.JSONObject; +import org.json.JSONTokener; import org.springframework.extensions.surf.util.ParameterCheck; import org.springframework.extensions.webscripts.Cache; import org.springframework.extensions.webscripts.Status; import org.springframework.extensions.webscripts.WebScriptException; import org.springframework.extensions.webscripts.WebScriptRequest; -import org.json.JSONException; -import org.json.JSONObject; -import org.json.JSONTokener; /** * Implementation for Java backed webscript to update RM custom property definitions * in the custom model. - * + * * @author Neil McErlean */ public class CustomPropertyDefinitionPut extends BaseCustomPropertyWebScript @@ -86,30 +89,30 @@ public class CustomPropertyDefinitionPut extends BaseCustomPropertyWebScript throw new WebScriptException(Status.STATUS_BAD_REQUEST, "Could not parse JSON from req.", je); } - + return ftlModel; } /** * Applies custom properties. - * @throws CustomMetadataException + * @throws CustomMetadataException */ protected Map handlePropertyDefinitionUpdate(WebScriptRequest req, JSONObject json) throws JSONException, CustomMetadataException { Map result = new HashMap(); - + Map params = getParamsFromUrlAndJson(req, json); - + QName propertyQName; propertyQName = updatePropertyDefinition(params); String localName = propertyQName.getLocalName(); - + result.put(PROP_ID, localName); - + String urlResult = req.getServicePath(); result.put(URL, urlResult); - + return result; } @@ -117,15 +120,16 @@ public class CustomPropertyDefinitionPut extends BaseCustomPropertyWebScript * If label has a non-null value, it is set on the property def. * If constraintRef has a non-null value, it is set on this propDef. * If constraintRef has a null value, all constraints for that propDef are removed. - * + * * @param params * @return - * @throws CustomMetadataException + * @throws CustomMetadataException */ protected QName updatePropertyDefinition(Map params) throws CustomMetadataException { QName result = null; - + boolean updated = false; + String propId = (String)params.get(PROP_ID); ParameterCheck.mandatoryString("propId", propId); @@ -135,45 +139,71 @@ public class CustomPropertyDefinitionPut extends BaseCustomPropertyWebScript throw new WebScriptException(Status.STATUS_NOT_FOUND, "Could not find property definition for: " + propId); } - + if (params.containsKey(PARAM_CONSTRAINT_REF)) { - String constraintRef = (String)params.get(PARAM_CONSTRAINT_REF); - - if (constraintRef == null) - { - result = rmAdminService.removeCustomPropertyDefinitionConstraints(propQName); - } - else - { - QName constraintRefQName = QName.createQName(constraintRef, namespaceService); - result = rmAdminService.setCustomPropertyDefinitionConstraint(propQName, constraintRefQName); - } + String constraintRef = (String)params.get(PARAM_CONSTRAINT_REF); + List constraints = rmAdminService.getCustomPropertyDefinitions().get(propQName).getConstraints(); + + if (constraintRef == null) + { + result = rmAdminService.removeCustomPropertyDefinitionConstraints(propQName); + updated = constraints.isEmpty() ? false : true; + } + else + { + boolean exists = false; + for (ConstraintDefinition constraintDefinition : constraints) + { + if (constraintDefinition.getConstraint().getShortName().equalsIgnoreCase(constraintRef)) + { + exists = true; + break; + } + } + if (exists == false) + { + QName constraintRefQName = QName.createQName(constraintRef, namespaceService); + result = rmAdminService.setCustomPropertyDefinitionConstraint(propQName, constraintRefQName); + updated = true; + } + } } if (params.containsKey(PARAM_LABEL)) { String label = (String)params.get(PARAM_LABEL); - result = rmAdminService.updateCustomPropertyDefinitionName(propQName, label); + try + { + result = rmAdminService.updateCustomPropertyDefinitionName(propQName, label); + } + catch (PropertyAlreadyExistsMetadataException ex) + { + if (updated == false) + { + String propIdAsString = rmAdminService.getQNameForClientId(label).toPrefixString(namespaceService); + throw new PropertyAlreadyExistsMetadataException(propIdAsString); + } + } } return result; } - @SuppressWarnings("unchecked") + @SuppressWarnings("rawtypes") protected Map getParamsFromUrlAndJson(WebScriptRequest req, JSONObject json) throws JSONException { Map params; params = new HashMap(); - + Map templateVars = req.getServiceMatch().getTemplateVars(); String propId = templateVars.get(PROP_ID); if (propId != null) { params.put(PROP_ID, (Serializable)propId); } - + for (Iterator iter = json.keys(); iter.hasNext(); ) { String nextKeyString = (String)iter.next(); @@ -182,10 +212,10 @@ public class CustomPropertyDefinitionPut extends BaseCustomPropertyWebScript { nextValueString = json.getString(nextKeyString); } - + params.put(nextKeyString, nextValueString); } - + return params; } } \ No newline at end of file diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/script/TransferReportPost.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/script/TransferReportPost.java index b28761370e..76c25d05e4 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/script/TransferReportPost.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/script/TransferReportPost.java @@ -59,79 +59,79 @@ import org.springframework.extensions.webscripts.WebScriptResponse; /** * Files a transfer report as a record. - * + * * @author Gavin Cornwell */ public class TransferReportPost extends BaseTransferWebScript { /** Logger */ private static Log logger = LogFactory.getLog(TransferReportPost.class); - + protected static final String REPORT_FILE_PREFIX = "report_"; protected static final String REPORT_FILE_SUFFIX = ".html"; protected static final String PARAM_DESTINATION = "destination"; protected static final String RESPONSE_SUCCESS = "success"; protected static final String RESPONSE_RECORD = "record"; protected static final String RESPONSE_RECORD_NAME = "recordName"; - + protected DictionaryService ddService; protected RecordsManagementActionService rmActionService; protected RecordsManagementService rmService; protected DispositionService dispositionService; - + /** * Sets the DictionaryService instance - * + * * @param ddService The DictionaryService instance */ public void setDictionaryService(DictionaryService ddService) { this.ddService = ddService; } - + /** * Sets the RecordsManagementService instance - * + * * @param rmService RecordsManagementService instance */ public void setRecordsManagementService(RecordsManagementService rmService) { this.rmService = rmService; } - + /** * Sets the disposition service - * + * * @param dispositionService disposition service */ public void setDispositionService(DispositionService dispositionService) { this.dispositionService = dispositionService; } - + /** * Sets the RecordsManagementActionService instance - * + * * @param rmActionService RecordsManagementActionService instance */ public void setRecordsManagementActionService(RecordsManagementActionService rmActionService) { this.rmActionService = rmActionService; } - + @Override protected File executeTransfer(NodeRef transferNode, - WebScriptRequest req, WebScriptResponse res, + WebScriptRequest req, WebScriptResponse res, Status status, Cache cache) throws IOException { File report = null; - + // retrieve requested format String format = req.getFormat(); Map model = new HashMap(); model.put("status", status); model.put("cache", cache); - + try { // extract the destination parameter, ensure it's present and it is @@ -139,63 +139,63 @@ public class TransferReportPost extends BaseTransferWebScript JSONObject json = new JSONObject(new JSONTokener(req.getContent().getContent())); if (!json.has(PARAM_DESTINATION)) { - status.setCode(HttpServletResponse.SC_BAD_REQUEST, + status.setCode(HttpServletResponse.SC_BAD_REQUEST, "Mandatory '" + PARAM_DESTINATION + "' parameter has not been supplied"); Map templateModel = createTemplateParameters(req, res, model); sendStatus(req, res, status, cache, format, templateModel); return null; } - + String destinationParam = json.getString(PARAM_DESTINATION); NodeRef destination = new NodeRef(destinationParam); - + if (!this.nodeService.exists(destination)) { - status.setCode(HttpServletResponse.SC_NOT_FOUND, + status.setCode(HttpServletResponse.SC_NOT_FOUND, "Node " + destination.toString() + " does not exist"); Map templateModel = createTemplateParameters(req, res, model); sendStatus(req, res, status, cache, format, templateModel); return null; } - + // ensure the node is a filePlan object if (!RecordsManagementModel.TYPE_RECORD_FOLDER.equals(this.nodeService.getType(destination))) { - status.setCode(HttpServletResponse.SC_BAD_REQUEST, + status.setCode(HttpServletResponse.SC_BAD_REQUEST, "Node " + destination.toString() + " is not a record folder"); Map templateModel = createTemplateParameters(req, res, model); sendStatus(req, res, status, cache, format, templateModel); return null; } - + if (logger.isDebugEnabled()) logger.debug("Filing transfer report as record in record folder: " + destination); - + // generate the report (will be in JSON format) report = generateHTMLTransferReport(transferNode); - + // file the report as a record NodeRef record = fileTransferReport(report, destination); - + if (logger.isDebugEnabled()) logger.debug("Filed transfer report as new record: " + record); - + // return success flag and record noderef as JSON JSONObject responseJSON = new JSONObject(); responseJSON.put(RESPONSE_SUCCESS, (record != null)); if (record != null) { responseJSON.put(RESPONSE_RECORD, record.toString()); - responseJSON.put(RESPONSE_RECORD_NAME, + responseJSON.put(RESPONSE_RECORD_NAME, (String)nodeService.getProperty(record, ContentModel.PROP_NAME)); } - + // setup response String jsonString = responseJSON.toString(); res.setContentType(MimetypeMap.MIMETYPE_JSON); res.setContentEncoding("UTF-8"); res.setHeader("Content-Length", Long.toString(jsonString.length())); - + // write the JSON response res.getWriter().write(jsonString); } @@ -203,14 +203,14 @@ public class TransferReportPost extends BaseTransferWebScript { throw createStatusException(je, req, res); } - + // return the file for deletion return report; } - + /** * Generates a File containing the JSON representation of a transfer report. - * + * * @param transferNode The transfer node * @return File containing JSON representation of a transfer report * @throws IOException @@ -223,16 +223,16 @@ public class TransferReportPost extends BaseTransferWebScript { // get all 'transferred' nodes NodeRef[] itemsToTransfer = getTransferNodes(transferNode); - + if (logger.isDebugEnabled()) { - logger.debug("Generating HTML transfer report for " + itemsToTransfer.length + + logger.debug("Generating HTML transfer report for " + itemsToTransfer.length + " items into file: " + report.getAbsolutePath()); } - + // create the writer writer = new FileWriter(report); - + // use RMService to get disposition authority String dispositionAuthority = null; if (itemsToTransfer.length > 0) @@ -244,11 +244,19 @@ public class TransferReportPost extends BaseTransferWebScript dispositionAuthority = ds.getDispositionAuthority(); } } - + // write the HTML header writer.write("\n"); writer.write("\n\n"); - writer.write("Transfer Report\n"); + Boolean isAccession = (Boolean)this.nodeService.getProperty(transferNode, PROP_TRANSFER_ACCESSION_INDICATOR); + if (isAccession == true) + { + writer.write("Accession Report\n"); + } + else + { + writer.write("Transfer Report\n"); + } writer.write("\n"); - writer.write("\n

Transfer Report

\n"); - + if (isAccession == true) + { + writer.write("\n

Accession Report

\n"); + } + else + { + writer.write("\n

Transfer Report

\n"); + } + writer.write(""); writer.write(""); writer.write(""); writer.write(""); writer.write("
Transfer Date:"); Date transferDate = (Date)this.nodeService.getProperty(transferNode, ContentModel.PROP_CREATED); writer.write(StringEscapeUtils.escapeHtml(transferDate.toString())); writer.write("
Transfer Location:"); - writer.write(StringEscapeUtils.escapeHtml((String)this.nodeService.getProperty(transferNode, + if (isAccession == true) + { + writer.write("NARA"); + } + else + { + writer.write(StringEscapeUtils.escapeHtml((String)this.nodeService.getProperty(transferNode, RecordsManagementModel.PROP_TRANSFER_LOCATION))); + } writer.write("
Performed By:"); - writer.write(StringEscapeUtils.escapeHtml((String)this.nodeService.getProperty(transferNode, + writer.write(StringEscapeUtils.escapeHtml((String)this.nodeService.getProperty(transferNode, ContentModel.PROP_CREATOR))); writer.write("
Disposition Authority:"); writer.write(dispositionAuthority != null ? StringEscapeUtils.escapeHtml(dispositionAuthority) : ""); writer.write("
\n"); - + writer.write("

Transferred Items

\n"); - + // write out HTML representation of items to transfer generateTransferItemsHTML(writer, itemsToTransfer); - + // write the HTML footer writer.write(""); } @@ -291,13 +313,13 @@ public class TransferReportPost extends BaseTransferWebScript try { writer.close(); } catch (IOException ioe) {} } } - + return report; } - + /** * Generates the JSON to represent the given NodeRefs - * + * * @param writer Writer to write to * @param itemsToTransfer NodeRefs being transferred * @throws IOException @@ -319,10 +341,10 @@ public class TransferReportPost extends BaseTransferWebScript writer.write("\n"); } } - + /** * Generates the JSON to represent the given folder. - * + * * @param writer Writer to write to * @param folderNode Folder being transferred * @throws IOException @@ -331,19 +353,19 @@ public class TransferReportPost extends BaseTransferWebScript throws IOException { writer.write(""); - writer.write(StringEscapeUtils.escapeHtml((String)this.nodeService.getProperty(folderNode, + writer.write(StringEscapeUtils.escapeHtml((String)this.nodeService.getProperty(folderNode, ContentModel.PROP_NAME))); writer.write(" (Unique Folder Identifier: "); - writer.write(StringEscapeUtils.escapeHtml((String)this.nodeService.getProperty(folderNode, + writer.write(StringEscapeUtils.escapeHtml((String)this.nodeService.getProperty(folderNode, RecordsManagementModel.PROP_IDENTIFIER))); writer.write(")\n"); - + writer.write("
\n"); - + // NOTE: we don't expect any nested folder structures so just render // the records contained in the folder. - - List assocs = this.nodeService.getChildAssocs(folderNode, + + List assocs = this.nodeService.getChildAssocs(folderNode, ContentModel.ASSOC_CONTAINS, RegexQNamePattern.MATCH_ALL); for (ChildAssociationRef child : assocs) { @@ -353,13 +375,13 @@ public class TransferReportPost extends BaseTransferWebScript generateTransferRecordHTML(writer, childRef); } } - + writer.write("\n
\n"); } - + /** * Generates the JSON to represent the given record. - * + * * @param writer Writer to write to * @param recordNode Record being transferred * @throws IOException @@ -369,29 +391,29 @@ public class TransferReportPost extends BaseTransferWebScript { writer.write("
\n"); writer.write(" "); - writer.write(StringEscapeUtils.escapeHtml((String)this.nodeService.getProperty(recordNode, + writer.write(StringEscapeUtils.escapeHtml((String)this.nodeService.getProperty(recordNode, ContentModel.PROP_NAME))); writer.write(" (Unique Record Identifier: "); - writer.write(StringEscapeUtils.escapeHtml((String)this.nodeService.getProperty(recordNode, + writer.write(StringEscapeUtils.escapeHtml((String)this.nodeService.getProperty(recordNode, RecordsManagementModel.PROP_IDENTIFIER))); writer.write(")"); - + if (this.nodeService.hasAspect(recordNode, RecordsManagementModel.ASPECT_DECLARED_RECORD)) { Date declaredOn = (Date)this.nodeService.getProperty(recordNode, RecordsManagementModel.PROP_DECLARED_AT); writer.write(" declared by "); - writer.write(StringEscapeUtils.escapeHtml((String)this.nodeService.getProperty(recordNode, + writer.write(StringEscapeUtils.escapeHtml((String)this.nodeService.getProperty(recordNode, RecordsManagementModel.PROP_DECLARED_BY))); writer.write(" on "); writer.write(StringEscapeUtils.escapeHtml(declaredOn.toString())); } - + writer.write("\n
\n"); } - + /** * Files the given transfer report as a record in the given record folder. - * + * * @param report Report to file * @param destination The destination record folder * @return NodeRef of the created record @@ -400,17 +422,17 @@ public class TransferReportPost extends BaseTransferWebScript { ParameterCheck.mandatory("report", report); ParameterCheck.mandatory("destination", destination); - + NodeRef record = null; - + Map properties = new HashMap(1); properties.put(ContentModel.PROP_NAME, report.getName()); - + // file the transfer report as an undeclared record - record = this.nodeService.createNode(destination, - ContentModel.ASSOC_CONTAINS, - QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, - QName.createValidLocalName(report.getName())), + record = this.nodeService.createNode(destination, + ContentModel.ASSOC_CONTAINS, + QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, + QName.createValidLocalName(report.getName())), ContentModel.TYPE_CONTENT, properties).getChildRef(); // Set the content @@ -418,7 +440,7 @@ public class TransferReportPost extends BaseTransferWebScript writer.setMimetype(MimetypeMap.MIMETYPE_HTML); writer.setEncoding("UTF-8"); writer.putContent(report); - + return record; } } \ No newline at end of file diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/script/slingshot/RMSearchGet.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/script/slingshot/RMSearchGet.java index df8c40bc25..fa9724d74a 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/script/slingshot/RMSearchGet.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/script/slingshot/RMSearchGet.java @@ -21,6 +21,7 @@ package org.alfresco.module.org_alfresco_module_rm.script.slingshot; import java.io.Serializable; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; +import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; @@ -53,7 +54,7 @@ import org.springframework.extensions.webscripts.WebScriptRequest; /** * RM search GET web script - * + * * @author Roy Wetherall */ public class RMSearchGet extends DeclarativeWebScript @@ -63,34 +64,34 @@ public class RMSearchGet extends DeclarativeWebScript private static final String PARAM_SORTBY = "sortby"; private static final String PARAM_FILTERS = "filters"; private static final String PARAM_MAX_ITEMS = "maxitems"; - + /** Records management search service */ protected RecordsManagementSearchService recordsManagementSearchService; - + /** Site service */ protected SiteService siteService; - + /** Namespace service */ protected NamespaceService namespaceService; - + /** Node serivce */ protected NodeService nodeService; - + /** Dictionary service */ protected DictionaryService dictionaryService; - + /** Permission service */ protected PermissionService permissionService; - + /** Person service */ protected PersonService personService; - + /** Content service */ protected ContentService contentService; - + /** Person data cache */ private Map personDataCache = null; - + /** * @param recordsManagementSearchService records management search service */ @@ -98,7 +99,7 @@ public class RMSearchGet extends DeclarativeWebScript { this.recordsManagementSearchService = recordsManagementSearchService; } - + /** * @param siteService site service */ @@ -106,7 +107,7 @@ public class RMSearchGet extends DeclarativeWebScript { this.siteService = siteService; } - + /** * @param namespaceService namespace service */ @@ -114,7 +115,7 @@ public class RMSearchGet extends DeclarativeWebScript { this.namespaceService = namespaceService; } - + /** * @param nodeService node service */ @@ -122,7 +123,7 @@ public class RMSearchGet extends DeclarativeWebScript { this.nodeService = nodeService; } - + /** * @param dictionaryService dictionary service */ @@ -130,7 +131,7 @@ public class RMSearchGet extends DeclarativeWebScript { this.dictionaryService = dictionaryService; } - + /** * @param permissionService permission service */ @@ -138,7 +139,7 @@ public class RMSearchGet extends DeclarativeWebScript { this.permissionService = permissionService; } - + /** * @param personService person service */ @@ -146,7 +147,7 @@ public class RMSearchGet extends DeclarativeWebScript { this.personService = personService; } - + /** * @param contentService content service */ @@ -154,7 +155,7 @@ public class RMSearchGet extends DeclarativeWebScript { this.contentService = contentService; } - + /* * @see org.alfresco.web.scripts.DeclarativeWebScript#executeImpl(org.alfresco.web.scripts.WebScriptRequest, org.alfresco.web.scripts.Status, org.alfresco.web.scripts.Cache) */ @@ -162,7 +163,7 @@ public class RMSearchGet extends DeclarativeWebScript protected Map executeImpl(WebScriptRequest req, Status status, Cache cache) { // Get the site id and confirm it is valid - Map templateVars = req.getServiceMatch().getTemplateVars(); + Map templateVars = req.getServiceMatch().getTemplateVars(); String siteId = templateVars.get("site"); if (siteId == null || siteId.length() == 0) { @@ -172,50 +173,55 @@ public class RMSearchGet extends DeclarativeWebScript { throw new WebScriptException(Status.STATUS_NOT_FOUND, "Site not found."); } - + // Get the query parameter String query = req.getParameter(PARAM_QUERY); // TODO check that this is there - + String sortby = req.getParameter(PARAM_SORTBY); // TODO this is optional - + String filters = req.getParameter(PARAM_FILTERS); // TODO this is optional - + // Convert into a rm search parameter object - RecordsManagementSearchParameters searchParameters = + RecordsManagementSearchParameters searchParameters = SavedSearchDetailsCompatibility.createSearchParameters(filters, new String[]{",", "/"}, sortby, namespaceService); - + // Set the max results String maxItems = req.getParameter(PARAM_MAX_ITEMS); if (maxItems != null && maxItems.length() != 0) { searchParameters.setMaxItems(Integer.parseInt(maxItems)); } - - // Execute search + + // Execute search List results = recordsManagementSearchService.search(siteId, query, searchParameters); - + // Reset person data cache personDataCache = new HashMap(57); - - // Process the result items - Item[] items = new Item[results.size()]; - int index = 0; + + // Process the result items + List items = new ArrayList(results.size()); for (NodeRef nodeRef : results) { - items[index] = new Item(nodeRef); - index++; + // FIXME: This is a workaround for DOD Recert + // TC 3-3 Create User Groups + try + { + Item item = new Item(nodeRef); + items.add(item); + } + catch(Exception e) {} } - + // Return model Map model = new HashMap(1); - model.put("items", items); + model.put("items", items); return model; } - + /** * Item class to contain information about items being placed in model. */ @@ -231,38 +237,38 @@ public class RMSearchGet extends DeclarativeWebScript private String createdBy; private Map nodeProperties; private Map properties; - + public Item(NodeRef nodeRef) { // Set node ref this.nodeRef = nodeRef; - + // Get type QName nodeRefType = nodeService.getType(nodeRef); this.type = nodeRefType.toPrefixString(namespaceService); - + // Get properties this.nodeProperties = nodeService.getProperties(nodeRef); - + // Determine if container or not isContainer = true; if (dictionaryService.isSubClass(nodeRefType, ContentModel.TYPE_CONTENT) == true) { isContainer = false; } - + // Get parent node reference NodeRef parent = null; ChildAssociationRef assoc = nodeService.getPrimaryParent(nodeRef); if (assoc != null) - { + { parent = assoc.getParentRef(); } - + if (isContainer == true) { this.size = -1; - + String displayPath = nodeService.getPath(nodeRef).toDisplayPath(nodeService, permissionService); String[] pathElements = displayPath.split("/"); if (pathElements.length >= 5) @@ -271,7 +277,7 @@ public class RMSearchGet extends DeclarativeWebScript { this.parentFolder = (String)nodeService.getProperty(parent, ContentModel.PROP_NAME); } - + pathElements = (String[])ArrayUtils.subarray(pathElements, 5, pathElements.length); String newPath = StringUtils.join(pathElements, "/"); StringBuilder relPath = new StringBuilder("/").append(newPath); @@ -287,7 +293,7 @@ public class RMSearchGet extends DeclarativeWebScript catch (UnsupportedEncodingException e) { throw new AlfrescoRuntimeException("Could not process search results.", e); - } + } } } else @@ -299,27 +305,27 @@ public class RMSearchGet extends DeclarativeWebScript { this.size = (int)contentData.getSize(); } - + // Set the document parent name if (parent != null) { this.parentFolder = (String)nodeService.getProperty(parent, ContentModel.PROP_NAME); } - + // Set the document browse URL this.browseUrl = "document-details?nodeRef=" + nodeRef.toString(); - } - + } + this.modifiedBy = getDisplayName(getModifiedByUser()); this.createdBy = getDisplayName(getCreatedByUser()); - + // Process the custom properties properties = new HashMap(nodeProperties.size()); for (Map.Entry entry : nodeProperties.entrySet()) { QName qName = entry.getKey().getPrefixedQName(namespaceService); if (NamespaceService.SYSTEM_MODEL_1_0_URI.equals(qName.getNamespaceURI()) == false) - { + { String prefixName = qName.getPrefixString().replace(":", "_"); Serializable value = entry.getValue(); if (value instanceof NodeRef) @@ -335,7 +341,7 @@ public class RMSearchGet extends DeclarativeWebScript } } } - + private String getDisplayName(String userName) { String result = personDataCache.get(userName); @@ -356,85 +362,85 @@ public class RMSearchGet extends DeclarativeWebScript } personDataCache.put(userName, result); } - + return result; } - + public NodeRef getNodeRef() { return nodeRef; } - + public String getType() { return type; } - + public String getName() { return (String)nodeProperties.get(ContentModel.PROP_NAME); } - + public String getTitle() { return (String)nodeProperties.get(ContentModel.PROP_TITLE); } - + public String getDescription() { return (String)nodeProperties.get(ContentModel.PROP_DESCRIPTION); } - + public Date getModifiedOn() { return (Date)nodeProperties.get(ContentModel.PROP_MODIFIED); } - + public String getModifiedByUser() { return (String)nodeProperties.get(ContentModel.PROP_MODIFIER); } - + public String getModifiedBy() { return modifiedBy; } - + public Date getCreatedOn() { return (Date)nodeProperties.get(ContentModel.PROP_CREATED); } - + public String getCreatedByUser() { return (String)nodeProperties.get(ContentModel.PROP_CREATOR); } - + public String getCreatedBy() { return createdBy; } - + public String getAuthor() { return (String)nodeProperties.get(ContentModel.PROP_AUTHOR); - } - + } + public String getParentFolder() { return parentFolder; } - + public int getSize() { return size; - } - + } + public String getBrowseUrl() { return browseUrl; } - + public Map getProperties() { return properties; diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/search/RecordsManagementSearchParameters.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/search/RecordsManagementSearchParameters.java index 4529833148..009679f6b3 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/search/RecordsManagementSearchParameters.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/search/RecordsManagementSearchParameters.java @@ -37,15 +37,15 @@ import org.json.JSONObject; */ @SuppressWarnings("serial") public class RecordsManagementSearchParameters -{ +{ /** Default sort order */ - private static final Map DEFAULT_SORT_ORDER = new HashMap() + private static final List DEFAULT_SORT_ORDER = new ArrayList() { { - put(ContentModel.PROP_NAME, Boolean.TRUE); + add(new SortItem(ContentModel.PROP_NAME, Boolean.TRUE)); } }; - + /** Default templates */ private static final Map DEFAULT_TEMPLATES = new HashMap() { @@ -72,24 +72,24 @@ public class RecordsManagementSearchParameters put("vitalRecordReviewPeriod", "%(rma:recordSearchVitalRecordReviewPeriod)"); } }; - + /** Default included container types */ private static final List DEFAULT_INCLUDED_CONTAINER_TYPES = Collections.emptyList(); - + /** Max items */ private int maxItems = 500; - + private boolean includeRecords = true; private boolean includeUndeclaredRecords = false; private boolean includeVitalRecords = false; private boolean includeRecordFolders = true; private boolean includeFrozen = false; private boolean includeCutoff = false; - + private List includedContainerTypes = DEFAULT_INCLUDED_CONTAINER_TYPES; - private Map sortOrder = DEFAULT_SORT_ORDER; + private List sortOrder = DEFAULT_SORT_ORDER; private Map templates = DEFAULT_TEMPLATES; - + private static final String JSON_MAXITEMS = "maxitems"; private static final String JSON_RECORDS = "records"; private static final String JSON_UNDECLAREDRECORDS = "undeclaredrecords"; @@ -101,9 +101,9 @@ public class RecordsManagementSearchParameters private static final String JSON_SORT = "sort"; private static final String JSON_FIELD = "field"; private static final String JSON_ASCENDING = "ascending"; - + /** - * { + * { * "maxItems" : 500, * "records" : true, * "undeclaredrecords" : false, @@ -111,19 +111,19 @@ public class RecordsManagementSearchParameters * "recordfolders" : false, * "frozen" : false, * "cutoff" : false, - * "containertypes" : + * "containertypes" : * [ * "rma:recordSeries", * "rma:recordCategory" * ] - * "sort" : + * "sort" : * [ * { * "field" : "cm:name", * "ascending" : true * } - * ] - * } + * ] + * } */ public static RecordsManagementSearchParameters createFromJSON(String json, NamespaceService namespaceService) { @@ -137,9 +137,9 @@ public class RecordsManagementSearchParameters throw new AlfrescoRuntimeException("Unable to create records management search parameters from json string. " + json, e); } } - + /** - * + * * @param jsonObject * @return */ @@ -148,7 +148,7 @@ public class RecordsManagementSearchParameters try { RecordsManagementSearchParameters searchParameters = new RecordsManagementSearchParameters(); - + // Get the search parameter properties if (jsonObject.has(JSON_MAXITEMS) == true) { @@ -178,7 +178,7 @@ public class RecordsManagementSearchParameters { searchParameters.setIncludeCutoff(jsonObject.getBoolean(JSON_CUTOFF)); } - + // Get container types if (jsonObject.has(JSON_CONTAINERTYPES) == true) { @@ -191,43 +191,43 @@ public class RecordsManagementSearchParameters } searchParameters.setIncludedContainerTypes(containerTypes); } - + // Get sort details if (jsonObject.has(JSON_SORT) == true) { JSONArray jsonArray = jsonObject.getJSONArray(JSON_SORT); - Map sortOrder = new HashMap(jsonArray.length()); + List sortOrder = new ArrayList(jsonArray.length()); for (int i = 0; i < jsonArray.length(); i++) { JSONObject sortJSONObject = jsonArray.getJSONObject(i); if (sortJSONObject.has(JSON_FIELD) == true && sortJSONObject.has(JSON_ASCENDING) == true) { - sortOrder.put( - QName.createQName(sortJSONObject.getString(JSON_FIELD), namespaceService), - Boolean.valueOf(sortJSONObject.getBoolean(JSON_ASCENDING))); + sortOrder.add(new SortItem( + QName.createQName(sortJSONObject.getString(JSON_FIELD), namespaceService), + sortJSONObject.getBoolean(JSON_ASCENDING))); } - } + } searchParameters.setSortOrder(sortOrder); } - + return searchParameters; } catch (JSONException e) { throw new AlfrescoRuntimeException("Unable to create records management search parameters from json string. " + jsonObject.toString(), e); - } + } } - + /** - * + * * @return */ public String toJSONString(NamespaceService namespaceService) { return toJSONObject(namespaceService).toString(); } - + public JSONObject toJSONObject(NamespaceService namespaceService) { try @@ -240,7 +240,7 @@ public class RecordsManagementSearchParameters jsonObject.put(JSON_RECORDFOLDERES, includeRecordFolders); jsonObject.put(JSON_FROZEN, includeFrozen); jsonObject.put(JSON_CUTOFF, includeCutoff); - + // Included containers JSONArray jsonArray = new JSONArray(); for (QName containerType : includedContainerTypes) @@ -248,18 +248,18 @@ public class RecordsManagementSearchParameters jsonArray.put(containerType.toPrefixString(namespaceService)); } jsonObject.put(JSON_CONTAINERTYPES, jsonArray); - + // Sort JSONArray jsonSortArray = new JSONArray(); - for (Map.Entry entry : sortOrder.entrySet()) + for (SortItem entry : sortOrder) { JSONObject jsonEntry = new JSONObject(); - jsonEntry.put(JSON_FIELD, entry.getKey().toPrefixString(namespaceService)); - jsonEntry.put(JSON_ASCENDING, entry.getValue().booleanValue()); + jsonEntry.put(JSON_FIELD, entry.property.toPrefixString(namespaceService)); + jsonEntry.put(JSON_ASCENDING, entry.assc); jsonSortArray.put(jsonEntry); } jsonObject.put(JSON_SORT, jsonSortArray); - + return jsonObject; } catch (JSONException e) @@ -267,102 +267,102 @@ public class RecordsManagementSearchParameters throw new AlfrescoRuntimeException("Unable to generate json string for records management search parameters.", e); } } - + public void setMaxItems(int maxItems) { this.maxItems = maxItems; } - + public int getMaxItems() { return maxItems; } - - public void setSortOrder(Map sortOrder) + + public void setSortOrder(List sortOrder) { this.sortOrder = sortOrder; } - - public Map getSortOrder() + + public List getSortOrder() { return sortOrder; } - + public void setTemplates(Map templates) { this.templates = templates; } - + public Map getTemplates() { return templates; } - + public void setIncludeRecords(boolean includeRecords) { this.includeRecords = includeRecords; } - + public boolean isIncludeRecords() { return includeRecords; } - + public void setIncludeUndeclaredRecords(boolean includeUndeclaredRecords) { this.includeUndeclaredRecords = includeUndeclaredRecords; } - + public boolean isIncludeUndeclaredRecords() { return includeUndeclaredRecords; } - + public void setIncludeVitalRecords(boolean includeVitalRecords) { this.includeVitalRecords = includeVitalRecords; } - + public boolean isIncludeVitalRecords() { return includeVitalRecords; } - + public void setIncludeRecordFolders(boolean includeRecordFolders) { this.includeRecordFolders = includeRecordFolders; } - + public boolean isIncludeRecordFolders() { return includeRecordFolders; } - + public void setIncludeFrozen(boolean includeFrozen) { this.includeFrozen = includeFrozen; } - + public boolean isIncludeFrozen() { return includeFrozen; } - + public void setIncludeCutoff(boolean includeCutoff) { this.includeCutoff = includeCutoff; } - + public boolean isIncludeCutoff() { return includeCutoff; } - + public void setIncludedContainerTypes(List includedContainerTypes) { this.includedContainerTypes = includedContainerTypes; } - + public List getIncludedContainerTypes() { return includedContainerTypes; diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/search/RecordsManagementSearchServiceImpl.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/search/RecordsManagementSearchServiceImpl.java index 73254dd6e4..7923f7aa99 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/search/RecordsManagementSearchServiceImpl.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/search/RecordsManagementSearchServiceImpl.java @@ -182,9 +182,9 @@ public class RecordsManagementSearchServiceImpl implements RecordsManagementSear searchParameters.setNamespace(RecordsManagementModel.RM_URI); // set sort - for(Entry entry : rmSearchParameters.getSortOrder().entrySet()) + for(SortItem entry : rmSearchParameters.getSortOrder()) { - searchParameters.addSort(entry.getKey().toPrefixString(namespaceService), entry.getValue().booleanValue()); + searchParameters.addSort(entry.property.toPrefixString(namespaceService), entry.assc); } // set templates diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/search/SavedSearchDetails.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/search/SavedSearchDetails.java index 4c0dc935a1..53d6923a03 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/search/SavedSearchDetails.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/search/SavedSearchDetails.java @@ -89,6 +89,8 @@ public class SavedSearchDetails extends ReportDetails public static final String SORT = "sort"; public static final String PARAMS = "params"; + private static final String DEFAULT_SITE_ID = "rm"; + /** Site id */ private String siteId; @@ -117,11 +119,11 @@ public class SavedSearchDetails extends ReportDetails JSONObject search = new JSONObject(jsonString); // Get the site id - if (search.has(SITE_ID) == false) + String siteId = DEFAULT_SITE_ID; + if (search.has(SITE_ID) == true) { - throw new AlfrescoRuntimeException("Can not create saved search details from json, because required siteid is not present. " + jsonString); - } - String siteId = search.getString(SITE_ID); + siteId = search.getString(SITE_ID); + } // Get the name if (search.has(NAME) == false) diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/search/SavedSearchDetailsCompatibility.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/search/SavedSearchDetailsCompatibility.java index c4882ec968..0acc5dcb89 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/search/SavedSearchDetailsCompatibility.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/search/SavedSearchDetailsCompatibility.java @@ -21,9 +21,7 @@ package org.alfresco.module.org_alfresco_module_rm.search; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map; import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel; import org.alfresco.service.namespace.NamespaceService; @@ -128,10 +126,6 @@ public class SavedSearchDetailsCompatibility implements RecordsManagementModel { includedContainerTypes.add(TYPE_RECORD_CATEGORY); } -// else if ("series".equals(paramName) == true && Boolean.parseBoolean(paramValue) == true) -// { -// includedContainerTypes.add(DOD5015Model.TYPE_RECORD_SERIES); -// } } result.setIncludedContainerTypes(includedContainerTypes); @@ -139,7 +133,7 @@ public class SavedSearchDetailsCompatibility implements RecordsManagementModel { // Map the sort string into the search details String[] sortPairs = sort.split(","); - Map sortOrder = new HashMap(sortPairs.length); + List sortOrder = new ArrayList(sortPairs.length); for (String sortPairString : sortPairs) { String[] sortPair = sortPairString.split("/"); @@ -149,7 +143,7 @@ public class SavedSearchDetailsCompatibility implements RecordsManagementModel { isAcsending = Boolean.TRUE; } - sortOrder.put(field, isAcsending); + sortOrder.add(new SortItem(field, isAcsending)); } result.setSortOrder(sortOrder); } @@ -178,7 +172,7 @@ public class SavedSearchDetailsCompatibility implements RecordsManagementModel { StringBuilder builder = new StringBuilder(64); - for (Map.Entry entry : this.savedSearchDetails.getSearchParameters().getSortOrder().entrySet()) + for (SortItem entry : this.savedSearchDetails.getSearchParameters().getSortOrder()) { if (builder.length() !=0) { @@ -186,11 +180,11 @@ public class SavedSearchDetailsCompatibility implements RecordsManagementModel } String order = "desc"; - if (Boolean.TRUE.equals(entry.getValue()) == true) + if (entry.assc == true) { order = "asc"; } - builder.append(entry.getKey().toPrefixString(this.namespaceService)) + builder.append(entry.property.toPrefixString(this.namespaceService)) .append("/") .append(order); } diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/search/SortItem.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/search/SortItem.java new file mode 100644 index 0000000000..925b1d3193 --- /dev/null +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/search/SortItem.java @@ -0,0 +1,15 @@ +package org.alfresco.module.org_alfresco_module_rm.search; + +import org.alfresco.service.namespace.QName; + +/*package*/ class SortItem +{ + public QName property = null; + public boolean assc = true; + public SortItem(QName property, boolean assc) + { + this.property = property; + this.assc = assc; + } + +}