diff --git a/config/alfresco/bulk-import-context.xml b/config/alfresco/bulk-import-context.xml index f1ebeaa955..aeb4d9a376 100644 --- a/config/alfresco/bulk-import-context.xml +++ b/config/alfresco/bulk-import-context.xml @@ -47,6 +47,7 @@ + diff --git a/source/java/org/alfresco/repo/batch/BatchProcessor.java b/source/java/org/alfresco/repo/batch/BatchProcessor.java index cc5f5ce66e..738d456c63 100644 --- a/source/java/org/alfresco/repo/batch/BatchProcessor.java +++ b/source/java/org/alfresco/repo/batch/BatchProcessor.java @@ -37,6 +37,7 @@ import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.repo.node.integrity.IntegrityException; import org.alfresco.repo.transaction.AlfrescoTransactionSupport; import org.alfresco.repo.transaction.RetryingTransactionHelper; import org.alfresco.repo.transaction.TransactionListenerAdapter; @@ -773,12 +774,13 @@ public class BatchProcessor implements BatchMonitor if (this.splitTxns) { this.txnLastError = t; - this.txnLastErrorEntryId = this.txnEntryId; + this.txnLastErrorEntryId = (t instanceof IntegrityException) ? "unknown" : this.txnEntryId; this.txnErrors++; if (BatchProcessor.this.logger.isWarnEnabled()) { - BatchProcessor.this.logger.warn(getProcessName() + ": Failed to process entry \"" - + BatchProcessor.this.currentEntryId + "\".", t); + String message = (t instanceof IntegrityException) ? ": Failed on batch commit." : ": Failed to process entry \"" + + this.txnEntryId + "\"."; + BatchProcessor.this.logger.warn(getProcessName() + message, t); } } // Otherwise, we have a retryable exception that we should propagate diff --git a/source/java/org/alfresco/repo/bulkimport/impl/DirectoryAnalyserImpl.java b/source/java/org/alfresco/repo/bulkimport/impl/DirectoryAnalyserImpl.java index e63d723ee4..58538def7d 100644 --- a/source/java/org/alfresco/repo/bulkimport/impl/DirectoryAnalyserImpl.java +++ b/source/java/org/alfresco/repo/bulkimport/impl/DirectoryAnalyserImpl.java @@ -27,13 +27,16 @@ package org.alfresco.repo.bulkimport.impl; import java.io.File; import java.io.FileFilter; +import java.io.Serializable; import java.util.ArrayList; import java.util.Date; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.repo.bulkimport.AnalysedDirectory; import org.alfresco.repo.bulkimport.DirectoryAnalyser; import org.alfresco.repo.bulkimport.ImportFilter; @@ -41,7 +44,12 @@ import org.alfresco.repo.bulkimport.ImportableItem; import org.alfresco.repo.bulkimport.ImportableItem.FileType; import org.alfresco.repo.bulkimport.MetadataLoader; import org.alfresco.repo.dictionary.constraint.NameChecker; +import org.alfresco.service.cmr.dictionary.Constraint; +import org.alfresco.service.cmr.dictionary.ConstraintDefinition; import org.alfresco.service.cmr.dictionary.ConstraintException; +import org.alfresco.service.cmr.dictionary.DictionaryService; +import org.alfresco.service.cmr.dictionary.PropertyDefinition; +import org.alfresco.service.namespace.QName; import org.alfresco.util.ISO8601DateFormat; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -64,6 +72,7 @@ public class DirectoryAnalyserImpl implements DirectoryAnalyser private BulkImportStatusImpl importStatus; private List importFilters; private NameChecker nameChecker; + private DictionaryService dictionaryService; public DirectoryAnalyserImpl(MetadataLoader metadataLoader, BulkImportStatusImpl importStatus, List importFilters, @@ -79,6 +88,11 @@ public class DirectoryAnalyserImpl implements DirectoryAnalyser { } + public void setDictionaryService(DictionaryService dictionaryService) + { + this.dictionaryService = dictionaryService; + } + public void setNameChecker(NameChecker nameChecker) { this.nameChecker = nameChecker; @@ -230,7 +244,7 @@ public class DirectoryAnalyserImpl implements DirectoryAnalyser { ImportableItem importableItem = iter.next(); - if (!importableItem.isValid()) + if (!importableItem.isValid() || !isMetadataValid(importableItem)) { iter.remove(); } @@ -255,6 +269,51 @@ public class DirectoryAnalyserImpl implements DirectoryAnalyser return result; } + private boolean isMetadataValid(ImportableItem importableItem) + { + if (!importableItem.getHeadRevision().metadataFileExists()) + { + return true; + } + + if (metadataLoader != null) + { + MetadataLoader.Metadata result = new MetadataLoader.Metadata(); + metadataLoader.loadMetadata(importableItem.getHeadRevision(), result); + + Map metadataProperties = result.getProperties(); + for (QName propertyName : metadataProperties.keySet()) + { + PropertyDefinition propDef = dictionaryService.getProperty(propertyName); + if (propDef != null) + { + for (ConstraintDefinition constraintDef : propDef.getConstraints()) + { + Constraint constraint = constraintDef.getConstraint(); + if (constraint != null) + { + try + { + constraint.evaluate(metadataProperties.get(propertyName)); + } + catch (ConstraintException e) + { + if (log.isWarnEnabled()) + { + log.warn("Skipping file '" + FileUtils.getFileName(importableItem.getHeadRevision().getContentFile()) + +"' with invalid metadata: '" + FileUtils.getFileName(importableItem.getHeadRevision().getMetadataFile()) + "'.", e); + } + return false; + } + } + } + } + } + } + + return true; + } + private boolean isVersionFile(File file) { Matcher matcher = VERSION_SUFFIX_PATTERN.matcher(file.getName()); diff --git a/source/java/org/alfresco/repo/node/integrity/PropertiesIntegrityEvent.java b/source/java/org/alfresco/repo/node/integrity/PropertiesIntegrityEvent.java index e6ad0cfaf5..fd68fa7077 100644 --- a/source/java/org/alfresco/repo/node/integrity/PropertiesIntegrityEvent.java +++ b/source/java/org/alfresco/repo/node/integrity/PropertiesIntegrityEvent.java @@ -153,9 +153,11 @@ public class PropertiesIntegrityEvent extends AbstractIntegrityEvent // check that enforced, mandatoryproperties are set if (propertyDef.isMandatory() && propertyDef.isMandatoryEnforced() && !nodeProperties.containsKey(propertyQName)) { + String nameProp = (String) nodeService.getProperty(nodeRef, ContentModel.PROP_NAME); IntegrityRecord result = new IntegrityRecord( "Mandatory property not set: \n" + " Node: " + nodeRef + "\n" + + (nameProp != null ? " Name: " + nameProp + "\n" : "") + " Type: " + typeQName + "\n" + " Property: " + propertyQName); eventResults.add(result); @@ -168,9 +170,11 @@ public class PropertiesIntegrityEvent extends AbstractIntegrityEvent { if (propertyValue != null && !(propertyValue instanceof SealedObject)) { + String nameProp = (String) nodeService.getProperty(nodeRef, ContentModel.PROP_NAME); IntegrityRecord result = new IntegrityRecord( "Property must be encrypted: \n" + " Node: " + nodeRef + "\n" + + (nameProp != null ? " Name: " + nameProp + "\n" : "") + " Type: " + typeQName + "\n" + " Property: " + propertyQName); eventResults.add(result); @@ -188,9 +192,11 @@ public class PropertiesIntegrityEvent extends AbstractIntegrityEvent } catch (ConstraintException e) { + String nameProp = (String) nodeService.getProperty(nodeRef, ContentModel.PROP_NAME); IntegrityRecord result = new IntegrityRecord( "Invalid property value: \n" + " Node: " + nodeRef + "\n" + + (nameProp != null ? " Name: " + nameProp + "\n" : "") + " Type: " + typeQName + "\n" + " Property: " + propertyQName + "\n" + " Constraint: " + e.getMessage());