From c920bfb3095a227f1407e167657750bd17c6bde1 Mon Sep 17 00:00:00 2001 From: Derek Hulley Date: Mon, 3 Mar 2008 13:35:10 +0000 Subject: [PATCH] Merged V2.2 to HEAD 7534: Merged V2.1 to HEAD 7398: XPath metadata extractor selector handles malformed and empty XML files 7401: Fix AR-1879: JBPM Timer never fires 7413: Contribution: Integrity checker ignores exceptions that would normally trigger transaction retries. 7416: AR-1884.Unicode wildcard processing. 7417: Added filtering of pseudo files when a partial wildcard search path is used, such as '*.csv'. AR-1889. 7436: AR-1863: major version's can now be created via the web service API; 7451: Fix for handling of UTF-8 application/x-www-form-urlencoded encoded form arguments as raised in support ticket 242 7458: Fix for AR-1900 7520: Fix to Template API where content was not retrievable from custom d:content properties on a node git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@8413 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../filesys/repo/ContentDiskDriver.java | 29 +++++++++++++++- .../metadata/xml/XmlMetadataExtracter.java | 27 +++++++++++++-- .../xml/XmlMetadataExtracterTest.java | 34 +++++++++++++++++++ .../repo/node/integrity/IntegrityChecker.java | 19 +++++++++++ .../RetryingTransactionHelper.java | 2 +- .../repo/workflow/WorkflowInterpreter.java | 29 ++++++++++------ .../repo/workflow/jbpm/AlfrescoTimer.java | 19 ++++------- .../repo/workflow/jbpm/JBPMEngine.java | 7 +++- .../service/cmr/workflow/WorkflowTimer.java | 3 ++ .../xml-metadata/empty-sample.xml | 0 .../xml-metadata/malformed-sample.xml | 8 +++++ 11 files changed, 149 insertions(+), 28 deletions(-) create mode 100644 source/test-resources/xml-metadata/empty-sample.xml create mode 100644 source/test-resources/xml-metadata/malformed-sample.xml diff --git a/source/java/org/alfresco/filesys/repo/ContentDiskDriver.java b/source/java/org/alfresco/filesys/repo/ContentDiskDriver.java index e30fda5fde..558104bb49 100644 --- a/source/java/org/alfresco/filesys/repo/ContentDiskDriver.java +++ b/source/java/org/alfresco/filesys/repo/ContentDiskDriver.java @@ -844,9 +844,36 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa if ( WildCard.containsWildcards(searchFileSpec)) { - // Check if the folder has any associated pseudo files + // Get the list of pseudo files for the search path pseudoList = searchFolderState.getPseudoFileList(); + + // Check if the wildcard is for all files or a subset + + if ( searchFileSpec.equals( "*") == false && pseudoList != null && pseudoList.numberOfFiles() > 0) + { + // Generate a subset of pseudo files that match the wildcard search pattern + + WildCard wildCard = new WildCard( searchFileSpec, false); + PseudoFileList filterList = null; + + for ( int i = 0; i > pseudoList.numberOfFiles(); i++) + { + PseudoFile pseudoFile = pseudoList.getFileAt( i); + if ( wildCard.matchesPattern( pseudoFile.getFileName())) + { + // Add the pseudo file to the filtered list + + if ( filterList == null) + filterList = new PseudoFileList(); + filterList.addFile( pseudoFile); + } + } + + // Use the filtered pseudo file list, or null if there were no matches + + pseudoList = filterList; + } } else if ( results == null || results.size() == 0) { diff --git a/source/java/org/alfresco/repo/content/metadata/xml/XmlMetadataExtracter.java b/source/java/org/alfresco/repo/content/metadata/xml/XmlMetadataExtracter.java index bfd3667eec..5d04f69b34 100644 --- a/source/java/org/alfresco/repo/content/metadata/xml/XmlMetadataExtracter.java +++ b/source/java/org/alfresco/repo/content/metadata/xml/XmlMetadataExtracter.java @@ -114,6 +114,19 @@ public class XmlMetadataExtracter extends AbstractMappingMetadataExtracter Map destination, Map> mapping) { + // Check the content length + if (reader.getSize() == 0) + { + // There is no content. We don't spoof any properties so there can be nothing extracted. + if (logger.isDebugEnabled()) + { + logger.debug("\n" + + "XML document has zero length, so bypassing extraction: \n" + + " Document: " + reader); + } + return destination; + } + MetadataExtracter extracter = null; // Select a worker for (ContentWorkerSelector selector : selectors) @@ -123,6 +136,10 @@ public class XmlMetadataExtracter extends AbstractMappingMetadataExtracter { extracter = selector.getWorker(spawnedReader); } + catch (Throwable e) + { + // The selector failed, so try another + } finally { if (reader.isChannelOpen()) @@ -149,8 +166,14 @@ public class XmlMetadataExtracter extends AbstractMappingMetadataExtracter // Did we find anything? if (extracter == null) { + if (logger.isDebugEnabled()) + { + logger.debug("\n" + + "No working metadata extractor could be found: \n" + + " Document: " + reader); + } // There will be no properties extracted - modifiedProperties = Collections.emptyMap(); + modifiedProperties = destination; } else { @@ -176,7 +199,7 @@ public class XmlMetadataExtracter extends AbstractMappingMetadataExtracter "XML metadata extractor redirected: \n" + " Reader: " + reader + "\n" + " Extracter: " + extracter + "\n" + - " Extracted: " + modifiedProperties); + " Metadata: " + modifiedProperties); } return modifiedProperties; } diff --git a/source/java/org/alfresco/repo/content/metadata/xml/XmlMetadataExtracterTest.java b/source/java/org/alfresco/repo/content/metadata/xml/XmlMetadataExtracterTest.java index 9e8823d2ea..df15f84d03 100644 --- a/source/java/org/alfresco/repo/content/metadata/xml/XmlMetadataExtracterTest.java +++ b/source/java/org/alfresco/repo/content/metadata/xml/XmlMetadataExtracterTest.java @@ -67,6 +67,8 @@ public class XmlMetadataExtracterTest extends TestCase { private static final String FILE_ALFRESCO_MODEL = "xml-metadata/alfresco-model-sample.xml"; private static final String FILE_ECLIPSE_PROJECT = "xml-metadata/eclipse-project-sample.xml"; + private static final String FILE_EMPTY = "xml-metadata/empty-sample.xml"; + private static final String FILE_MALFORMED = "xml-metadata/malformed-sample.xml"; private static final String CTX_LOCATION = "classpath:xml-metadata/xml-metadata-test-context.xml"; private static final ApplicationContext ctx = new ClassPathXmlApplicationContext(CTX_LOCATION); @@ -157,6 +159,38 @@ public class XmlMetadataExtracterTest extends TestCase assertEquals("JavaCC Nature", checkProperties.get(ContentModel.PROP_DESCRIPTION)); } + public void testEmptyFile() throws Exception + { + // Get an empty file + ContentReader reader = getReader(FILE_EMPTY); + assertTrue(reader.exists()); + + // Pass it to the extracter + PropertyMap checkProperties = new PropertyMap(); + checkProperties.put(ContentModel.PROP_TITLE, getName()); + xmlMetadataExtracter.extract(reader, checkProperties); + + // The map should be unaffected + assertNotNull("Properties changed by empty file extraction", checkProperties.get(ContentModel.PROP_TITLE)); + assertEquals("Properties changed by empty file extraction", getName(), checkProperties.get(ContentModel.PROP_TITLE)); + } + + public void testMalformedFile() throws Exception + { + // Get an empty file + ContentReader reader = getReader(FILE_MALFORMED); + assertTrue(reader.exists()); + + // Pass it to the extracter + PropertyMap checkProperties = new PropertyMap(); + checkProperties.put(ContentModel.PROP_TITLE, getName()); + xmlMetadataExtracter.extract(reader, checkProperties); + + // The map should be unaffected + assertNotNull("Properties changed by malformed file extraction", checkProperties.get(ContentModel.PROP_TITLE)); + assertEquals("Properties changed by malformed file extraction", getName(), checkProperties.get(ContentModel.PROP_TITLE)); + } + public void testRootElementNameSelector() throws Exception { // Load the example files diff --git a/source/java/org/alfresco/repo/node/integrity/IntegrityChecker.java b/source/java/org/alfresco/repo/node/integrity/IntegrityChecker.java index 7a29071bea..52c726d253 100644 --- a/source/java/org/alfresco/repo/node/integrity/IntegrityChecker.java +++ b/source/java/org/alfresco/repo/node/integrity/IntegrityChecker.java @@ -35,6 +35,7 @@ import org.alfresco.repo.node.NodeServicePolicies; import org.alfresco.repo.policy.JavaBehaviour; import org.alfresco.repo.policy.PolicyComponent; import org.alfresco.repo.transaction.AlfrescoTransactionSupport; +import org.alfresco.repo.transaction.RetryingTransactionHelper; import org.alfresco.service.cmr.dictionary.AspectDefinition; import org.alfresco.service.cmr.dictionary.AssociationDefinition; import org.alfresco.service.cmr.dictionary.ClassDefinition; @@ -670,6 +671,24 @@ public class IntegrityChecker } catch (Throwable e) { + // This means that integrity checking itself failed. This is serious. + // There are some exceptions that can be handled by transaction retries, so + // we attempt to handle these and let them get out to trigger the retry. + // Thanks to Carina Lansing. + Throwable retryThrowable = RetryingTransactionHelper.extractRetryCause(e); + if (retryThrowable != null) + { + // The transaction will be retrying on this, so there's no need for the aggressive + // reporting that would normally happen + if (e instanceof RuntimeException) + { + throw (RuntimeException) e; + } + else + { + throw new RuntimeException(e); + } + } e.printStackTrace(); // log it as an error and move to next event IntegrityRecord exceptionRecord = new IntegrityRecord("" + e.getMessage()); diff --git a/source/java/org/alfresco/repo/transaction/RetryingTransactionHelper.java b/source/java/org/alfresco/repo/transaction/RetryingTransactionHelper.java index b72f8186fd..62e0c7c017 100644 --- a/source/java/org/alfresco/repo/transaction/RetryingTransactionHelper.java +++ b/source/java/org/alfresco/repo/transaction/RetryingTransactionHelper.java @@ -353,7 +353,7 @@ public class RetryingTransactionHelper * @param cause the cause to examine * @return Returns the original cause if it is a valid retry cause, otherwise null */ - private Throwable extractRetryCause(Throwable cause) + public static Throwable extractRetryCause(Throwable cause) { Throwable retryCause = ExceptionStackUtil.getCause(cause, RETRY_EXCEPTIONS); if (retryCause == null) diff --git a/source/java/org/alfresco/repo/workflow/WorkflowInterpreter.java b/source/java/org/alfresco/repo/workflow/WorkflowInterpreter.java index b1866f6a1f..c771b62015 100644 --- a/source/java/org/alfresco/repo/workflow/WorkflowInterpreter.java +++ b/source/java/org/alfresco/repo/workflow/WorkflowInterpreter.java @@ -457,6 +457,8 @@ public class WorkflowInterpreter extends BaseInterpreter } } + List timers = new ArrayList(); + if (id.equals("all")) { for (WorkflowDefinition def : workflowService.getAllDefinitions()) @@ -464,11 +466,7 @@ public class WorkflowInterpreter extends BaseInterpreter List workflows = workflowService.getActiveWorkflows(def.id); for (WorkflowInstance workflow : workflows) { - List timers = workflowService.getTimers(workflow.id); - for (WorkflowTimer timer : timers) - { - out.println("id: " + timer.id + " , name: " + timer.name + " , due date: " + timer.dueDate + " , path: " + timer.path.id + " , node: " + timer.path.node.name + " , process: " + timer.path.instance.id + " , task: " + timer.task.name + "(" + timer.task.id + ")"); - } + timers.addAll(workflowService.getTimers(workflow.id)); } } } @@ -477,11 +475,22 @@ public class WorkflowInterpreter extends BaseInterpreter List workflows = workflowService.getActiveWorkflows(id); for (WorkflowInstance workflow : workflows) { - List timers = workflowService.getTimers(workflow.id); - for (WorkflowTimer timer : timers) - { - out.println("id: " + timer.id + " , name: " + timer.name + " , due date: " + timer.dueDate + " , path: " + timer.path.id + " , node: " + timer.path.node.name + " , process: " + timer.path.instance.id + " , task: " + timer.task.name + "(" + timer.task.id + ")"); - } + timers.addAll(workflowService.getTimers(workflow.id)); + } + } + + for (WorkflowTimer timer : timers) + { + out.print("id: " + timer.id + " , name: " + timer.name + " , due date: " + timer.dueDate + " , path: " + timer.path.id + " , node: " + timer.path.node.name + " , process: " + timer.path.instance.id); + if (timer.task != null) + { + out.print(" , task: " + timer.task.name + "(" + timer.task.id + ")"); + } + out.println(); + if (timer.error != null) + { + out.println("error executing timer id " + timer.id); + out.println(timer.error); } } } diff --git a/source/java/org/alfresco/repo/workflow/jbpm/AlfrescoTimer.java b/source/java/org/alfresco/repo/workflow/jbpm/AlfrescoTimer.java index c6b17d7abb..5404e04bbb 100644 --- a/source/java/org/alfresco/repo/workflow/jbpm/AlfrescoTimer.java +++ b/source/java/org/alfresco/repo/workflow/jbpm/AlfrescoTimer.java @@ -84,21 +84,14 @@ public class AlfrescoTimer extends Timer } // execute timer - if (username == null) + executeResult = AuthenticationUtil.runAs(new RunAsWork() { - executeResult = super.execute(jbpmContext); - } - else - { - executeResult = AuthenticationUtil.runAs(new RunAsWork() + @SuppressWarnings("synthetic-access") + public Boolean doWork() throws Exception { - @SuppressWarnings("synthetic-access") - public Boolean doWork() throws Exception - { - return AlfrescoTimer.super.execute(jbpmContext); - } - }, username); - } + return AlfrescoTimer.super.execute(jbpmContext); + } + }, (username == null) ? "system" : username); return executeResult; } diff --git a/source/java/org/alfresco/repo/workflow/jbpm/JBPMEngine.java b/source/java/org/alfresco/repo/workflow/jbpm/JBPMEngine.java index a7fd4d3480..6814b7e3cd 100644 --- a/source/java/org/alfresco/repo/workflow/jbpm/JBPMEngine.java +++ b/source/java/org/alfresco/repo/workflow/jbpm/JBPMEngine.java @@ -2868,9 +2868,14 @@ public class JBPMEngine extends BPMEngine WorkflowTimer workflowTimer = new WorkflowTimer(); workflowTimer.id = createGlobalId(new Long(timer.getId()).toString()); workflowTimer.name = timer.getName(); + workflowTimer.error = timer.getException(); workflowTimer.dueDate = timer.getDueDate(); workflowTimer.path = createWorkflowPath(timer.getToken()); - workflowTimer.task = createWorkflowTask(timer.getTaskInstance()); + TaskInstance taskInstance = timer.getTaskInstance(); + if (taskInstance != null) + { + workflowTimer.task = createWorkflowTask(taskInstance); + } return workflowTimer; } diff --git a/source/java/org/alfresco/service/cmr/workflow/WorkflowTimer.java b/source/java/org/alfresco/service/cmr/workflow/WorkflowTimer.java index 0c518ff5a6..d01dbb6a66 100644 --- a/source/java/org/alfresco/service/cmr/workflow/WorkflowTimer.java +++ b/source/java/org/alfresco/service/cmr/workflow/WorkflowTimer.java @@ -43,6 +43,9 @@ public class WorkflowTimer /** Due Date */ public Date dueDate; + /** Error */ + public String error; + /* * (non-Javadoc) * diff --git a/source/test-resources/xml-metadata/empty-sample.xml b/source/test-resources/xml-metadata/empty-sample.xml new file mode 100644 index 0000000000..e69de29bb2 diff --git a/source/test-resources/xml-metadata/malformed-sample.xml b/source/test-resources/xml-metadata/malformed-sample.xml new file mode 100644 index 0000000000..7e88853698 --- /dev/null +++ b/source/test-resources/xml-metadata/malformed-sample.xml @@ -0,0 +1,8 @@ + + + Repository + JavaCC Nature + + + +