From 37e86802616caf324c72446fc826178c42840716 Mon Sep 17 00:00:00 2001 From: Dave Ward Date: Wed, 14 Nov 2012 11:56:36 +0000 Subject: [PATCH] Merged V4.1-BUG-FIX to HEAD 43386: ALF-13091: Prevent bean post processor propagation to child application contexts. Remove Jsr250BeanPostPorcessor from the CXF configuration, to prevent strange interaction with component scanning. 43402: Merged DEV to V4.1-BUG-FIX 43330: ALF-16073: Share forms renders is slow when using sets. Optimize performance for fieldsVisibleInAnyMode populating in getFields and FormField obtaining in getVisibleFieldNamesFor. 43412: ALF-16680 ImageMagick exit code 255 is not seen as an error 43420: ALF-16627 SOLR indexing does not provide TransformationOption when converting content to plain text for indexing 43452: Fix for ALF-16296 - On site customization page, when a page containing apostrophe (') is renamed, a backslash (\) is added to the name 43453: Fix for ALF-16105 - Disabled 'Follow' feature does not disable it for existing users 43462: ALF-16715 : Merged V3.4-BUG-FIX (3.4.12) to V4.1-BUG-FIX (4.1.3) 43461: ALF-16713 Cannot disable metadata extractors 43464: ALF-16715 : Merged V3.4-BUG-FIX (3.4.12) to V4.1-BUG-FIX (4.1.3) 43463: ALF-16713 Cannot disable metadata extractors - fix test failures - none set mimetypeService 43471: Fix for ALF-16542 - Web application context for the onlineEditUrl variable is hard-coded to alfresco: Merged BRANCHES/DEV/CLOUD1_SP to BRANCHES/DEV/V4.1-BUG-FIX 40565: CLOUD-23: core changes to allow overriding of "edit online" button's URL generation. 43475: Fix for ALF-15859 - UploadContentServlet servlet /alfresco/upload can update the content, mime type and encoding but not the locale 43476: Merged DEV to V4.1-BUG-FIX 43401 : ALF-16587 GreenMail IMAP server does not clean up session handlers - memory leak 43478: MNT-181: Now WebDAV will ALWAYS preserve the original metadata and versions of ANY node that is temporarily 'moved out' in ANY kind of 'shuffle' operation - To make the source node temporarily invisible to WebDAV the client specific HIDDEN aspect features are used - WebDAVHelper.isRenameShuffle() method introduced, to parallel ALF-3856 CIFS fix and using similar system.webdav.renameShufflePattern global property to detect the start of a shuffle - WebDAVHelper converted to use proper dependency injection - CopyMethod has become a simple subclass of MoveMethod as all the hidden aspect munging is done by it - DeleteMethod now preserves hidden nodes - PropFindMethod now ignores hidden nodes - Listing methods will hide hidden nodes from WebDAV 43483: MNT-181: Corrected typo 43498: Fix for ALF-16648 - Alfresco Enterprise artifacts in artifacts.alfresco.com do not provide POM files / dependencies declarations: Merged HEAD to V4.1-BUG-FIX (4.1.2) 43380: -- added site content for alfresco-platform-distribution POM 43379: -- added site documentation for alfresco-platform-distribution POM 43378: -- added site documentation for alfresco-platform-distribution POM -- deployed site for 4.2.b Community at https://artifacts.alfresco.com/nexus/content/repositories/alfresco-docs/alfresco-platform-distribution/latest/index.html -- created repository for Enterprise docs and added url in the appropriate edition properties 43273: Use property to define POI version 42966: ALF-14353 - Added platform distribution POM to standard maven-deploy procedure 42965: ALF-14353 - added alfresco-platform-distribution to provide a Maven release descriptor (dependencyManagement) per each Community / Enterprise release -- moved maven-ant-tasks not to be in the runtime lib -- added platform distribution pom in the SDK folder -- updated maven.xml to deploy filter and deploy the appropriate platform-distribution POM per each releae -- in maven.xml moved configure-release and configure-snapshot goals to maven-env-prerequisites -- updated sdk readme to explain the presence of alfresco-platform-distribution POM 42912: -- updated README header on the POM specifying it's NOT usable to build Alfresco -- make a clear reference to the POMs that get deployed by pom-experimental.xml being usable for development 42842: ALF-14353: Fix artifactId alfresco-jlan -> alfresco-jlan-embed 41883: ALF-14353 - fixed multiple Maven build issues. Now mvn clean install -f pom-experimental.xml works fine. Also deployed Spring Surf 1.2.0-SNAPSHOT so proper Surf version is retrieved 41882: added pre-requisites to build POMs successfully with mvn clean install -f pom-experimental.xml 43499: Upgrade version in POM files to 4.1.3-SNAPSHOT 43520: ALF-16694 POI becoming responsiveness and causing jvm to freeze for a while with certain XLS (fraction formats) - Patched POI to: - limit the length of fractions to four digits (more than that takes too long to process) e.g. "# #/#####" is too long and will be reduced to "# #/####" which still takes about a second! - handle the -ve fraction format part (i.e. n in p;n;z), so its length is not interpret as part of the fraction format of the +ve fraction part. - handle custom formats a bit better (strip them) rather than interpret the text length as part of the fraction format - handle -ve fractions (just did not work) - limitations: - custom text gets stripped (still better than before) - formats that have p (+ve) and n (-ve) parts must include a fraction format in each part. Otherwise +ve and -ve values are not formatted as a fraction (still better than before) 43523: MNT-181: Corrections - WebDAVLockService.unlock() made 'harmless' to call on already-unlocked nodes - Delete method hides rather than deletes versioned nodes and working copes in case it is called by OSX Finder during a 'replace' operation 43524: MNT-181: Correction - PutMethod now 'unhides' hidden nodes and behaves as though it created them 43541: Merged DEV to V4.1-BUG-FIX 43536: ALF-16200: WQS delete fails to publish to live projects onDeleteNode behavior The condition of "if" operator was modified. Now "if" operator evaluate to true if least one of the nodesToTransfer or nodesToRemoveOnTransfer sets is not empty. beforeDeleteNode() methods were updated for check for the ASPECT_PENDING_DELETE aspect on the node. enqueueRemovedNodes() call was moved from onDeleteNode() into beforeDeleteNode(). These fixes allow to automatically update the sites published to (i.e. live projects) to include the removal of the file and removal of file from any collection (asset list) when a content was deleted from an editorial project. 43542: Fix for ALF-16618 - ScriptableHashMap does not have hasOwnProperty method 43555: Fix for ALF-16494 - site collaborator has rights to modify comments made by another user. 43556: ALF-15859: Prevent NPE on upload without NodeRef 43558: ALF-16694 POI becoming irresponsive and causing jvm to freeze with XLS that includes fraction formats - Original jar did not get removed in previous commit << NO NEED TO MERGE TO CLOUD1-BUG-FIX as there was a tree conflict and the original jar was removed. >> 43570: MNT-181: More corrections researched by Valery - Don't treat all moves to temporary locations as copies - just those from non-temporary locations. Avoids initial upload leaving lots of hidden files around. - Only copy the content, not the whole node including aspects to avoid versioning temporary files! - Don't version on changes to sys:clientVisibilityMask - avoids 'double versioning' - Recognize Mac .TemporaryItems folder and ._ files as temporary 43575: Fix for ALF-9317 - Links: Delete Link button in Selected Items menu is available for Consumer, Contributor and Collaborator 43577: Upgrade POM files after following changes: 43401: ALF-16587 patch greenmail 43520: ALF-16694 Uprade POI and patch it 43584: Merged V4.1 to V4.1-BUG-FIX <> 43582: Merged V4.1-BUG-FIX to V4.1 (4.1.2) 43402: Merged DEV to V4.1-BUG-FIX 43330: ALF-16073: Share forms renders is slow when using sets. Optimize performance for fieldsVisibleInAnyMode populating in getFields and FormField obtaining in getVisibleFieldNamesFor. 43557: Merged V4.1-BUG-FIX to V4.1 43555: Fix for ALF-16494 - site collaborator has rights to modify comments made by another user. 43586: MNT-181: Final correction researched by Valery - Corrected system.webdav.renameShufflePattern so that it matches .TemporaryItems folder and ._ files as a full match 43591: ALF-16772: If the WebDAV path of a document exceeds 255 characters, documents opened in MSOffice cannot be saved back - Interpret null nodeLockToken as not locked. 43594: Merged DEV to V4.1-BUG-FIX 43540: ALF-12425: Can't launch activiti workflow console from Share when external / ntlm / kerberos authentication is used. New webscript that redirects to activiti admin console with URL holding current ticket. The webscript resides below wcs and allows to use alfresco connector in Share. 43562: ALF-12425: Can't launch activiti workflow console from Share when external / ntlm / kerberos authentication is used. Activiti admin console webscript that allows admin console to be invoked behind wcs authentication. 43595: Merged V4.1 to V4.1-BUG-FIX 43376: Merged DEV to V4.1 43339: ALF-16590 : java.lang.IllegalArgumentException while initiating In-Place import FilesystemContentDataFactory#contentIsInStore method was modified. Now files' absolute paths are compared. 43390: ALF-15856: Test org.alfresco.repo.node.NodeServiceTest does not finish on DB2 - Now inner-nested retrying transaction in testConcurrentArchive passes its exception straight through to the outer transaction, which unwraps and retries it if necessary 43397: ALF-16021: RuleServiceImplTest never ends on DB2 - Added endTransaction() call so that testDeleteSpaceWithExecuteScriptRule() doesn't hang indefinitely waiting for the outer transaction to complete 43398: ALF-15856: Test org.alfresco.repo.node.NodeServiceTest does not finish on DB2 - Now inner-nested retrying transaction runs in its own thread and we don't wait forever for it 43404: ALF-16666: IMAP subsystem startup causes Tomcat crash - Stopped IMAP subsystem from depending on itself by using private rather than public IMapService! 43408: Fixed latest DB2 hangs for Samuel (concurrent nested transactions) 43424: Fixed latest DB2 hang for Samuel (concurrent nested transactions) 43426: ALF-16692: Merged HEAD to V4.1 (with corrections) 43425: Fixes issue with YUI SWF files (see: IT-9441) 43450: Possible fix for workflow tests on DB2 - retrying txns where necessary 43484: ALF-16702: Restored missing index in DB2 schema reference 43596: Merged V4.1 to V4.1-BUG-FIX (RECORD ONLY) 43589: Merged V4.1-BUG-FIX to V4.1 43575: Fix for ALF-9317 - Links: Delete Link button in Selected Items menu is available for Consumer, Contributor and Collaborator git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@43601 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- config/alfresco/content-services-context.xml | 3 + config/alfresco/core-services-context.xml | 4 +- config/alfresco/repository.properties | 4 + .../default/imagemagick-transform-context.xml | 4 + pom.xml | 4 +- .../impl/FilesystemContentDataFactory.java | 159 +++++++++--------- .../AbstractMappingMetadataExtracter.java | 49 +++++- .../metadata/AbstractMetadataExtracter.java | 50 +++++- .../metadata/MetadataExtracterRegistry.java | 20 ++- .../repo/imap/AlfrescoImapFolder.java | 14 +- .../alfresco/repo/imap/ImapServiceImpl.java | 12 +- .../repo/jscript/ScriptableHashMap.java | 24 +++ .../repo/jscript/ScriptableQNameMap.java | 27 ++- .../ChildApplicationContextFactory.java | 8 +- .../alfresco/repo/node/NodeServiceTest.java | 89 +++++++++- .../repo/rule/RuleServiceImplTest.java | 1 + .../impl/lucene/ADMLuceneIndexerImpl.java | 10 +- .../authentication/AuthenticationTest.java | 1 + .../transfer/TransferServiceImplTest.java | 30 ++-- ...bstractWorkflowServiceIntegrationTest.java | 59 +++++-- .../test-resources/subsystem-test-context.xml | 2 +- 21 files changed, 426 insertions(+), 148 deletions(-) diff --git a/config/alfresco/content-services-context.xml b/config/alfresco/content-services-context.xml index 5dcf26bf59..94a8fcf7f0 100644 --- a/config/alfresco/content-services-context.xml +++ b/config/alfresco/content-services-context.xml @@ -220,6 +220,9 @@ + + + diff --git a/config/alfresco/core-services-context.xml b/config/alfresco/core-services-context.xml index 09d7e9abaf..0042f20f5f 100644 --- a/config/alfresco/core-services-context.xml +++ b/config/alfresco/core-services-context.xml @@ -641,7 +641,9 @@ fm:commentCount cm:expiryDate - + + sys:clientVisibilityMask + diff --git a/config/alfresco/repository.properties b/config/alfresco/repository.properties index a2d4e59216..c5c30cc5b7 100644 --- a/config/alfresco/repository.properties +++ b/config/alfresco/repository.properties @@ -43,6 +43,10 @@ system.webdav.url.path.prefix= system.webdav.storeName=${protocols.storeName} system.webdav.rootPath=${protocols.rootPath} system.webdav.activities.enabled=true +# File name patterns that trigger rename shuffle detection +# pattern is used by move - tested against full path after it has been lower cased. +system.webdav.renameShufflePattern=(.*/\\..*)|(.*[a-f0-9]{8}+$)|(.*\\.tmp$)|(.*\\.wbk$)|(.*\\.bak$)|(.*\\~$) + # Is the JBPM Deploy Process Servlet enabled? # Default is false. Should not be enabled in production environments as the diff --git a/config/alfresco/subsystems/thirdparty/default/imagemagick-transform-context.xml b/config/alfresco/subsystems/thirdparty/default/imagemagick-transform-context.xml index 6e37fbb827..ba8b02b9a1 100644 --- a/config/alfresco/subsystems/thirdparty/default/imagemagick-transform-context.xml +++ b/config/alfresco/subsystems/thirdparty/default/imagemagick-transform-context.xml @@ -47,6 +47,10 @@ + + + 1,2,255,400,405,410,415,420,425,430,435,440,450,455,460,465,470,475,480,485,490,495,499,700,705,710,715,720,725,730,735,740,750,755,760,765,770,775,780,785,790,795,799 + diff --git a/pom.xml b/pom.xml index bf082d2974..a2999699f9 100644 --- a/pom.xml +++ b/pom.xml @@ -52,7 +52,7 @@ com.icegreen greenmail - 1.3-patched + 1.3-alfresco-patched commons-dbcp @@ -534,7 +534,7 @@ org.apache.poi poi - ${dependency.poi.version} + ${dependency.poi.version}-alfresco-patched org.apache.poi diff --git a/source/java/org/alfresco/repo/bulkimport/impl/FilesystemContentDataFactory.java b/source/java/org/alfresco/repo/bulkimport/impl/FilesystemContentDataFactory.java index 80ad8a4ec5..123982013c 100644 --- a/source/java/org/alfresco/repo/bulkimport/impl/FilesystemContentDataFactory.java +++ b/source/java/org/alfresco/repo/bulkimport/impl/FilesystemContentDataFactory.java @@ -59,96 +59,97 @@ import org.springframework.beans.factory.InitializingBean; */ public class FilesystemContentDataFactory implements ContentDataFactory, InitializingBean { - private static final Log logger = LogFactory.getLog(FilesystemContentDataFactory.class); - - private static final String PROTOCOL_DELIMITER = ContentStore.PROTOCOL_DELIMITER; - private static final String OS_FILE_SEPARATOR = System.getProperty("file.separator"); - - private MimetypeService mimetypeService; - private String defaultEncoding; - private String storeProtocol; - - public void setMimetypeService(MimetypeService mimetypeService) - { - this.mimetypeService = mimetypeService; - } - - public void setDefaultEncoding(String defaultEncoding) - { - this.defaultEncoding = defaultEncoding; - } - - public void setStoreProtocol(String storeProtocol) - { - this.storeProtocol = storeProtocol; - } + private static final Log logger = LogFactory.getLog(FilesystemContentDataFactory.class); + + private static final String PROTOCOL_DELIMITER = ContentStore.PROTOCOL_DELIMITER; + private static final String OS_FILE_SEPARATOR = System.getProperty("file.separator"); + + private MimetypeService mimetypeService; + private String defaultEncoding; + private String storeProtocol; + + public void setMimetypeService(MimetypeService mimetypeService) + { + this.mimetypeService = mimetypeService; + } + + public void setDefaultEncoding(String defaultEncoding) + { + this.defaultEncoding = defaultEncoding; + } + + public void setStoreProtocol(String storeProtocol) + { + this.storeProtocol = storeProtocol; + } - public void afterPropertiesSet() throws Exception - { - PropertyCheck.mandatory(this, "mimetypeService", mimetypeService); + public void afterPropertiesSet() throws Exception + { + PropertyCheck.mandatory(this, "mimetypeService", mimetypeService); PropertyCheck.mandatory(this, "defaultEncoding", defaultEncoding); PropertyCheck.mandatory(this, "storeProtocol", storeProtocol); - } - - /** - * Create a {@link ContentData} by combining the given {@link ContentStore}'s root location and the {@link File}'s path within that store. - * The given file must therefore be accessible within the content store's configured root location. - * The encoding and mimetype will be guessed from the given file. - * - * @param store The {@link ContentStore} in which the file should be - * @param contentFile The {@link File} to check - * @return the constructed {@link ContentData} - */ - public ContentData createContentData(ContentStore store, File contentFile) + } + + /** + * Create a {@link ContentData} by combining the given {@link ContentStore}'s root location and the {@link File}'s path within that store. + * The given file must therefore be accessible within the content store's configured root location. + * The encoding and mimetype will be guessed from the given file. + * + * @param store The {@link ContentStore} in which the file should be + * @param contentFile The {@link File} to check + * @return the constructed {@link ContentData} + */ + public ContentData createContentData(ContentStore store, File contentFile) { - if(!contentIsInStore(contentFile, store)) - { - throw new IllegalArgumentException("Can't create content URL : file '" + contentFile.getAbsolutePath() + - "' is not located within the store's tree ! The store's root is :'" + store.getRootLocation()); - } - - String relativeFilePath = contentFile.getAbsolutePath().replace(store.getRootLocation() + OS_FILE_SEPARATOR, ""); - String mimetype = mimetypeService.guessMimetype(contentFile.getName()); - String encoding = defaultEncoding; - if(!contentFile.isDirectory()) - { - encoding = guessEncoding(contentFile, mimetype); - } - + if(!contentIsInStore(contentFile, store)) + { + throw new IllegalArgumentException("Can't create content URL : file '" + contentFile.getAbsolutePath() + + "' is not located within the store's tree ! The store's root is :'" + store.getRootLocation()); + } + + String relativeFilePath = contentFile.getAbsolutePath().replace(store.getRootLocation() + OS_FILE_SEPARATOR, ""); + String mimetype = mimetypeService.guessMimetype(contentFile.getName()); + String encoding = defaultEncoding; + if(!contentFile.isDirectory()) + { + encoding = guessEncoding(contentFile, mimetype); + } + ContentData contentData = new ContentData(storeProtocol + PROTOCOL_DELIMITER + relativeFilePath, mimetype, contentFile.length(), encoding); Map contentProps = new HashMap(); contentProps.put(ContentModel.PROP_NAME, contentFile.getName()); contentProps.put(ContentModel.PROP_CONTENT, contentData); - return contentData; + return contentData; } - - /** - * Check if file is in the store's tree, by checking if the file path starts - * with the store's configured root location. - * - * @param store The {@link ContentStore} in which the file should be - * @param contentFile The {@link File} to check - * @return boolean : whether or not the file is in the expected file tree - */ - private boolean contentIsInStore(File contentFile,ContentStore store) - { - return contentFile.getAbsolutePath().startsWith(store.getRootLocation()); - } - - /** - * Attempt to guess file encoding. fall back to {@link #defaultEncoding} otherwise. - * - * @param file the {@link java.io.File} to test - * @param mimetype the file mimetype. used to first distinguish between binary and text files - * @return the encoding as a {@link String} - */ - private String guessEncoding(File file,String mimetype) - { + + /** + * Check if file is in the store's tree, by checking if the file path starts + * with the store's configured root location. + * + * @param store The {@link ContentStore} in which the file should be + * @param contentFile The {@link File} to check + * @return boolean : whether or not the file is in the expected file tree + */ + private boolean contentIsInStore(File contentFile,ContentStore store) + { + File contentStoreFile = new File(store.getRootLocation()); + return contentFile.getAbsolutePath().startsWith(contentStoreFile.getAbsolutePath()); + } + + /** + * Attempt to guess file encoding. fall back to {@link #defaultEncoding} otherwise. + * + * @param file the {@link java.io.File} to test + * @param mimetype the file mimetype. used to first distinguish between binary and text files + * @return the encoding as a {@link String} + */ + private String guessEncoding(File file,String mimetype) + { String encoding = defaultEncoding; // fallback default if(file.isDirectory()) - return defaultEncoding; // not necessary to guess folder encoding + return defaultEncoding; // not necessary to guess folder encoding InputStream is = null; ContentCharsetFinder charsetFinder = mimetypeService.getContentCharsetFinder(); @@ -159,7 +160,7 @@ public class FilesystemContentDataFactory implements ContentDataFactory, Initial } catch (Throwable e) { - if(logger.isWarnEnabled()) + if(logger.isWarnEnabled()) logger.warn("Failed to guess character encoding of file: '" + file.getName() + "'. Falling back to configured default encoding (" + defaultEncoding + ")"); } finally @@ -171,6 +172,6 @@ public class FilesystemContentDataFactory implements ContentDataFactory, Initial } return encoding; - } + } } diff --git a/source/java/org/alfresco/repo/content/metadata/AbstractMappingMetadataExtracter.java b/source/java/org/alfresco/repo/content/metadata/AbstractMappingMetadataExtracter.java index e829e19e9f..c4635e1f2c 100644 --- a/source/java/org/alfresco/repo/content/metadata/AbstractMappingMetadataExtracter.java +++ b/source/java/org/alfresco/repo/content/metadata/AbstractMappingMetadataExtracter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2010 Alfresco Software Limited. + * Copyright (C) 2005-2012 Alfresco Software Limited. * * This file is part of Alfresco * @@ -53,6 +53,7 @@ import org.alfresco.service.namespace.QName; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.xmlbeans.impl.xb.xsdschema.All; +import org.springframework.beans.factory.BeanNameAware; import org.springframework.extensions.surf.util.ISO8601DateFormat; /** @@ -95,7 +96,7 @@ import org.springframework.extensions.surf.util.ISO8601DateFormat; * @author Jesper Steen Møller * @author Derek Hulley */ -abstract public class AbstractMappingMetadataExtracter implements MetadataExtracter, MetadataEmbedder +abstract public class AbstractMappingMetadataExtracter implements MetadataExtracter, MetadataEmbedder, BeanNameAware { public static final String NAMESPACE_PROPERTY_PREFIX = "namespace.prefix."; private static final String ERR_TYPE_CONVERSION = "metadata.extraction.err.type_conversion"; @@ -117,6 +118,8 @@ abstract public class AbstractMappingMetadataExtracter implements MetadataExtrac private boolean inheritDefaultMapping; private boolean inheritDefaultEmbedMapping; private boolean enableStringTagging; + private String beanName; + private Properties properties; /** * Default constructor. If this is called, then {@link #isSupported(String)} should @@ -227,7 +230,7 @@ abstract public class AbstractMappingMetadataExtracter implements MetadataExtrac */ public boolean isSupported(String sourceMimetype) { - return supportedMimetypes.contains(sourceMimetype); + return supportedMimetypes.contains(sourceMimetype) && isEnabled(sourceMimetype); } /** @@ -244,6 +247,27 @@ abstract public class AbstractMappingMetadataExtracter implements MetadataExtrac return supportedEmbedMimetypes.contains(sourceMimetype); } + private boolean isEnabled(String mimetype) + { + return properties == null || mimetypeService == null || + (getBooleanProperty(beanName+".enabled", true) && + getBooleanProperty(beanName+'.'+mimetypeService.getExtension(mimetype)+".enabled", true)); + } + + private boolean getBooleanProperty(String name, boolean defaultValue) + { + boolean value = defaultValue; + if (properties != null) + { + String property = properties.getProperty(name); + if (property != null) + { + value = property.trim().equalsIgnoreCase("true"); + } + } + return value; + } + /** * TODO - This doesn't appear to be used, so should be removed / deprecated / replaced * @return Returns 1.0 if the mimetype is supported, otherwise 0.0 @@ -354,6 +378,25 @@ abstract public class AbstractMappingMetadataExtracter implements MetadataExtrac this.inheritDefaultMapping = inheritDefaultMapping; } + @Override + public void setBeanName(String beanName) + { + this.beanName = beanName; + } + + public String getBeanName() + { + return beanName; + } + + /** + * The Alfresco global properties. + */ + public void setProperties(Properties properties) + { + this.properties = properties; + } + /** * Whether or not to enable the pass through of simple strings to cm:taggable tags * diff --git a/source/java/org/alfresco/repo/content/metadata/AbstractMetadataExtracter.java b/source/java/org/alfresco/repo/content/metadata/AbstractMetadataExtracter.java index e55782a18e..8768d9af1b 100644 --- a/source/java/org/alfresco/repo/content/metadata/AbstractMetadataExtracter.java +++ b/source/java/org/alfresco/repo/content/metadata/AbstractMetadataExtracter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005 Jesper Steen Møller + * Copyright (C) 2005-2012 Jesper Steen Møller * * This file is part of Alfresco * @@ -22,6 +22,7 @@ import java.io.Serializable; import java.util.Collections; import java.util.HashMap; import java.util.Map; +import java.util.Properties; import java.util.Set; import org.alfresco.error.AlfrescoRuntimeException; @@ -31,6 +32,7 @@ import org.alfresco.service.cmr.repository.MimetypeService; import org.alfresco.service.namespace.QName; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.springframework.beans.factory.BeanNameAware; /** * Support class for metadata extracters. @@ -40,7 +42,7 @@ import org.apache.commons.logging.LogFactory; * @author Jesper Steen Møller * @author Derek Hulley */ -abstract public class AbstractMetadataExtracter implements MetadataExtracter +abstract public class AbstractMetadataExtracter implements MetadataExtracter, BeanNameAware { protected static Log logger = LogFactory.getLog(AbstractMetadataExtracter.class); @@ -49,6 +51,8 @@ abstract public class AbstractMetadataExtracter implements MetadataExtracter private Set supportedMimetypes; private double reliability; private long extractionTime; + private String beanName; + private Properties properties; protected AbstractMetadataExtracter(String supportedMimetype, double reliability, long extractionTime) { @@ -84,6 +88,25 @@ abstract public class AbstractMetadataExtracter implements MetadataExtracter this.mimetypeService = mimetypeService; } + @Override + public void setBeanName(String beanName) + { + this.beanName = beanName; + } + + public String getBeanName() + { + return beanName; + } + + /** + * The Alfresco global properties. + */ + public void setProperties(Properties properties) + { + this.properties = properties; + } + /** * @return Returns the mimetype helper */ @@ -131,7 +154,28 @@ abstract public class AbstractMetadataExtracter implements MetadataExtracter public boolean isSupported(String mimetype) { double reliability = getReliability(mimetype); - return reliability > 0.0; + return reliability > 0.0 && isEnabled(mimetype); + } + + private boolean isEnabled(String mimetype) + { + return properties == null || mimetypeService == null || + (getBooleanProperty(beanName+".enabled", true) && + getBooleanProperty(beanName+'.'+mimetypeService.getExtension(mimetype)+".enabled", true)); + } + + private boolean getBooleanProperty(String name, boolean defaultValue) + { + boolean value = defaultValue; + if (properties != null) + { + String property = properties.getProperty(name); + if (property != null) + { + value = property.trim().equalsIgnoreCase("true"); + } + } + return value; } public long getExtractionTime() diff --git a/source/java/org/alfresco/repo/content/metadata/MetadataExtracterRegistry.java b/source/java/org/alfresco/repo/content/metadata/MetadataExtracterRegistry.java index 4566c84252..1aabf85e94 100644 --- a/source/java/org/alfresco/repo/content/metadata/MetadataExtracterRegistry.java +++ b/source/java/org/alfresco/repo/content/metadata/MetadataExtracterRegistry.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005 Jesper Steen Møller + * Copyright (C) 2005-2012 Jesper Steen Møller * * This file is part of Alfresco * @@ -119,6 +119,7 @@ public class MetadataExtracterRegistry */ public MetadataExtracter getExtracter(String sourceMimetype) { + logger.debug("Get extractors for " + sourceMimetype); List extractors = null; extracterCacheReadLock.lock(); try @@ -162,12 +163,26 @@ public class MetadataExtracterRegistry // An extractor may dynamically become unavailable if (!extractor.isSupported(sourceMimetype)) { + logger.debug("Get unsupported: "+getName(extractor)); continue; } + logger.debug("Get supported: "+getName(extractor)); liveExtractor = extractor; } + logger.debug("Get returning: "+getName(liveExtractor)); return liveExtractor; } + + private String getName(MetadataExtracter extractor) + { + return extractor == null + ? null + : extractor instanceof AbstractMetadataExtracter + ? ((AbstractMetadataExtracter)extractor).getBeanName() + : extractor instanceof AbstractMappingMetadataExtracter + ? ((AbstractMappingMetadataExtracter)extractor).getBeanName() + : extractor.getClass().getSimpleName(); + } /** * @param sourceMimetype The MIME type under examination @@ -184,10 +199,13 @@ public class MetadataExtracterRegistry if (!extractor.isSupported(sourceMimetype)) { // extraction not achievable + logger.debug("Find unsupported: "+getName(extractor)); continue; } + logger.debug("Find supported: "+getName(extractor)); extractors.add(extractor); } + logger.debug("Find returning: "+extractors); return extractors; } diff --git a/source/java/org/alfresco/repo/imap/AlfrescoImapFolder.java b/source/java/org/alfresco/repo/imap/AlfrescoImapFolder.java index 3ec0e7b6c7..dd1d3bd28a 100644 --- a/source/java/org/alfresco/repo/imap/AlfrescoImapFolder.java +++ b/source/java/org/alfresco/repo/imap/AlfrescoImapFolder.java @@ -30,8 +30,8 @@ import java.util.Map; import java.util.NavigableMap; import javax.mail.Flags; -import javax.mail.MessagingException; import javax.mail.Flags.Flag; +import javax.mail.MessagingException; import javax.mail.internet.MimeMessage; import org.alfresco.model.ContentModel; @@ -127,9 +127,9 @@ public class AlfrescoImapFolder extends AbstractImapFolder implements Serializab /** * Protected constructor for the hierarchy delimiter */ - AlfrescoImapFolder(String userName, ServiceRegistry serviceRegistry) + AlfrescoImapFolder(String userName, ImapService imapService, ServiceRegistry serviceRegistry) { - this(null, userName, "", "", null, serviceRegistry, false, false, 0); + this(null, userName, "", "", null, imapService, serviceRegistry, false, false, 0); } @@ -150,10 +150,11 @@ public class AlfrescoImapFolder extends AbstractImapFolder implements Serializab String folderPath, ImapViewMode viewMode, boolean extractAttachmentsEnabled, + ImapService imapService, ServiceRegistry serviceRegistry, int mountPointId) { - this(folderInfo, userName, folderName, folderPath, viewMode, serviceRegistry, null, extractAttachmentsEnabled, mountPointId); + this(folderInfo, userName, folderName, folderPath, viewMode, imapService, serviceRegistry, null, extractAttachmentsEnabled, mountPointId); } /** @@ -165,7 +166,7 @@ public class AlfrescoImapFolder extends AbstractImapFolder implements Serializab * @param viewMode - defines view mode. Can be one of the following: {@link AlfrescoImapConst#MODE_ARCHIVE} or {@link AlfrescoImapConst#MODE_VIRTUAL}. * @param rootNodeRef - reference to the root node of the store where folder is placed. * @param mountPointName - name of the mount point. - * @param imapService - reference to the {@link ImapHelper} object. + * @param imapService - the IMAP service. * @param selectable - defines whether the folder is selectable or not. */ public AlfrescoImapFolder( @@ -174,6 +175,7 @@ public class AlfrescoImapFolder extends AbstractImapFolder implements Serializab String folderName, String folderPath, ImapViewMode viewMode, + ImapService imapService, ServiceRegistry serviceRegistry, Boolean selectable, boolean extractAttachmentsEnabled, @@ -186,7 +188,7 @@ public class AlfrescoImapFolder extends AbstractImapFolder implements Serializab this.folderPath = folderPath; this.viewMode = viewMode != null ? viewMode : ImapViewMode.ARCHIVE; this.extractAttachmentsEnabled = extractAttachmentsEnabled; - this.imapService = serviceRegistry.getImapService(); + this.imapService = imapService; // MailFolder object can be null if it is used to obtain hierarchy delimiter by LIST command: // Example: diff --git a/source/java/org/alfresco/repo/imap/ImapServiceImpl.java b/source/java/org/alfresco/repo/imap/ImapServiceImpl.java index 4c19cd36df..e19368dd91 100644 --- a/source/java/org/alfresco/repo/imap/ImapServiceImpl.java +++ b/source/java/org/alfresco/repo/imap/ImapServiceImpl.java @@ -568,7 +568,7 @@ public class ImapServiceImpl implements ImapService, OnCreateChildAssociationPol // A request for the hierarchy delimiter if (mailboxName.length() == 0) { - return new AlfrescoImapFolder(user.getLogin(), serviceRegistry); + return new AlfrescoImapFolder(user.getLogin(), this, serviceRegistry); } final NodeRef root; final List pathElements; @@ -633,7 +633,7 @@ public class ImapServiceImpl implements ImapService, OnCreateChildAssociationPol } } return new AlfrescoImapFolder(mailFolder, user.getLogin(), pathElements.get(pathElements.size() - 1), mailboxName, viewMode, - serviceRegistry, true, isExtractionEnabled(mailFolder.getNodeRef()), mountPointId); + this, serviceRegistry, true, isExtractionEnabled(mailFolder.getNodeRef()), mountPointId); } public void deleteMailbox(AlfrescoImapUser user, String mailboxName) @@ -1053,12 +1053,12 @@ public class ImapServiceImpl implements ImapService, OnCreateChildAssociationPol if (!listSubscribed || !unsubscribedFodlers.contains(mountPointFileInfo.getNodeRef())) { result.add(new AlfrescoImapFolder(mountPointFileInfo, userName, mountPointName, mountPointName, viewMode, - isExtractionEnabled(mountPointFileInfo.getNodeRef()), serviceRegistry, mountPointId)); + isExtractionEnabled(mountPointFileInfo.getNodeRef()), this, serviceRegistry, mountPointId)); } else if (rootPath.endsWith("%") && !expandFolder(mountPoint, user, mountPointName, "%", true, viewMode, mountPointId).isEmpty()) // \NoSelect { result.add(new AlfrescoImapFolder(mountPointFileInfo, userName, mountPointName, mountPointName, viewMode, - serviceRegistry, false, isExtractionEnabled(mountPointFileInfo.getNodeRef()), mountPointId)); + this, serviceRegistry, false, isExtractionEnabled(mountPointFileInfo.getNodeRef()), mountPointId)); } if (rootPath.endsWith("*")) { @@ -1169,12 +1169,12 @@ public class ImapServiceImpl implements ImapService, OnCreateChildAssociationPol if (!listSubscribed || !unsubscribedFodlers.contains(fileInfo.getNodeRef())) { fullList.add(new AlfrescoImapFolder(fileInfo, userName, fileInfo.getName(), folderPath, viewMode, - isExtractionEnabled(fileInfo.getNodeRef()), serviceRegistry, mountPointId)); + isExtractionEnabled(fileInfo.getNodeRef()), this, serviceRegistry, mountPointId)); } else if (name.endsWith("%") && !expandFolder(fileInfo.getNodeRef(), user, folderPath, "%", true, viewMode, mountPointId).isEmpty()) // \NoSelect { fullList.add(new AlfrescoImapFolder(fileInfo, userName, fileInfo.getName(), folderPath, viewMode, - serviceRegistry, false, isExtractionEnabled(fileInfo.getNodeRef()), mountPointId)); + this, serviceRegistry, false, isExtractionEnabled(fileInfo.getNodeRef()), mountPointId)); } if (name.endsWith("*")) { diff --git a/source/java/org/alfresco/repo/jscript/ScriptableHashMap.java b/source/java/org/alfresco/repo/jscript/ScriptableHashMap.java index 59f1206169..e5f49a3105 100644 --- a/source/java/org/alfresco/repo/jscript/ScriptableHashMap.java +++ b/source/java/org/alfresco/repo/jscript/ScriptableHashMap.java @@ -21,6 +21,8 @@ package org.alfresco.repo.jscript; import java.util.Iterator; import java.util.LinkedHashMap; +import org.mozilla.javascript.Callable; +import org.mozilla.javascript.Context; import org.mozilla.javascript.Scriptable; /** @@ -51,6 +53,17 @@ public class ScriptableHashMap extends LinkedHashMap implements Scrip { return this.size(); } + else if ("hasOwnProperty".equals(name)) + { + return new Callable() + { + @Override + public Object call(Context cx, Scriptable scope, Scriptable thisObj, Object[] args) + { + return (args.length > 0 ? hasOwnProperty(args[0]) : null); + } + }; + } else { return get(name); @@ -71,6 +84,17 @@ public class ScriptableHashMap extends LinkedHashMap implements Scrip } return value; } + + /** + * ECMAScript 5 hasOwnProperty method support. + * + * @param key Object key to test for + * @return true if found, false otherwise + */ + public boolean hasOwnProperty(Object key) + { + return containsKey(key); + } /** * @see org.mozilla.javascript.Scriptable#has(java.lang.String, org.mozilla.javascript.Scriptable) diff --git a/source/java/org/alfresco/repo/jscript/ScriptableQNameMap.java b/source/java/org/alfresco/repo/jscript/ScriptableQNameMap.java index 891b4b7b05..de855cad3c 100644 --- a/source/java/org/alfresco/repo/jscript/ScriptableQNameMap.java +++ b/source/java/org/alfresco/repo/jscript/ScriptableQNameMap.java @@ -18,9 +18,10 @@ */ package org.alfresco.repo.jscript; -import org.alfresco.service.namespace.NamespacePrefixResolver; import org.alfresco.service.namespace.NamespacePrefixResolverProvider; import org.alfresco.service.namespace.QNameMap; +import org.mozilla.javascript.Callable; +import org.mozilla.javascript.Context; import org.mozilla.javascript.Scriptable; /** @@ -43,7 +44,7 @@ public class ScriptableQNameMap extends QNameMap implements Scriptable { return "ScriptableQNameMap"; } - + /** * @see org.mozilla.javascript.Scriptable#get(java.lang.String, org.mozilla.javascript.Scriptable) */ @@ -54,6 +55,17 @@ public class ScriptableQNameMap extends QNameMap implements Scriptable { return this.size(); } + else if ("hasOwnProperty".equals(name)) + { + return new Callable() + { + @Override + public Object call(Context cx, Scriptable scope, Scriptable thisObj, Object[] args) + { + return (args.length > 0 ? hasOwnProperty(args[0]) : null); + } + }; + } else { return get(name); @@ -68,6 +80,17 @@ public class ScriptableQNameMap extends QNameMap implements Scriptable return null; } + /** + * ECMAScript 5 hasOwnProperty method support. + * + * @param key Object key to test for + * @return true if found, false otherwise + */ + public boolean hasOwnProperty(Object key) + { + return containsKey(key); + } + /** * @see org.mozilla.javascript.Scriptable#has(java.lang.String, org.mozilla.javascript.Scriptable) */ diff --git a/source/java/org/alfresco/repo/management/subsystems/ChildApplicationContextFactory.java b/source/java/org/alfresco/repo/management/subsystems/ChildApplicationContextFactory.java index f7a0403214..2575197c9d 100644 --- a/source/java/org/alfresco/repo/management/subsystems/ChildApplicationContextFactory.java +++ b/source/java/org/alfresco/repo/management/subsystems/ChildApplicationContextFactory.java @@ -449,17 +449,11 @@ public class ChildApplicationContextFactory extends AbstractPropertyBackedBean i // Add a property placeholder configurer, with the subsystem-scoped default properties PropertyPlaceholderConfigurer configurer = new PropertyPlaceholderConfigurer(); - configurer.setProperties(properties); + configurer.setPropertiesArray(new Properties[] {ChildApplicationContextFactory.this.getPropertyDefaults(), properties}); configurer.setIgnoreUnresolvablePlaceholders(true); configurer.setSearchSystemEnvironment(false); addBeanFactoryPostProcessor(configurer); - // Add all the post processors of the parent, e.g. to make sure system placeholders get expanded properly - for (Object postProcessor : getParent().getBeansOfType(BeanFactoryPostProcessor.class, false, false).values()) - { - addBeanFactoryPostProcessor((BeanFactoryPostProcessor) postProcessor); - } - setClassLoader(ChildApplicationContextFactory.this.getParent().getClassLoader()); } diff --git a/source/java/org/alfresco/repo/node/NodeServiceTest.java b/source/java/org/alfresco/repo/node/NodeServiceTest.java index 0a3dd3c21b..672addd80f 100644 --- a/source/java/org/alfresco/repo/node/NodeServiceTest.java +++ b/source/java/org/alfresco/repo/node/NodeServiceTest.java @@ -321,6 +321,22 @@ public class NodeServiceTest extends TestCase assertEquals("", 3, paths.size()); } + static class InnerCallbackException extends RuntimeException + { + private final Throwable hiddenCause; + + public InnerCallbackException(Throwable hiddenCause) + { + super(hiddenCause.getMessage()); + this.hiddenCause = hiddenCause; + } + + public Throwable getHiddenCause() + { + return hiddenCause; + } + } + /** * Tests that two separate node trees can be deleted concurrently at the database level. * This is not a concurrent thread issue; instead we delete a hierarchy and hold the txn @@ -340,10 +356,10 @@ public class NodeServiceTest extends TestCase buildNodeHierarchy(workspaceRootNodeRef, nodesOne); final NodeRef[] nodesTwo = new NodeRef[10]; buildNodeHierarchy(workspaceRootNodeRef, nodesTwo); - + // Prime the root of the archive store (first child adds inherited ACL) nodeService.deleteNode(nodesPrimer[0]); - + RetryingTransactionCallback outerCallback = new RetryingTransactionCallback() { @Override @@ -351,18 +367,73 @@ public class NodeServiceTest extends TestCase { // Delete the first hierarchy nodeService.deleteNode(nodesOne[0]); + // Keep the txn hanging around to maintain DB locks // and start a second transaction to delete another hierarchy - RetryingTransactionCallback innerCallback = new RetryingTransactionCallback() + class InnerThread extends Thread { - @Override - public Void execute() throws Throwable + + private Throwable error; + + public InnerThread() { - nodeService.deleteNode(nodesTwo[0]); - return null; + setDaemon(true); } - }; - txnService.getRetryingTransactionHelper().doInTransaction(innerCallback, false, true); + + public Throwable getError() + { + return error; + } + + /* + * (non-Javadoc) + * @see java.lang.Thread#run() + */ + @Override + public void run() + { + AuthenticationUtil.setRunAsUserSystem(); + RetryingTransactionCallback innerCallback = new RetryingTransactionCallback() + { + @Override + public Void execute() throws Throwable + { + try + { + nodeService.deleteNode(nodesTwo[0]); + return null; + } + catch (Throwable t) + { + // Wrap throwables so they pass straight through the retry mechanism + throw new InnerCallbackException(t); + } + } + }; + try + { + txnService.getRetryingTransactionHelper().doInTransaction(innerCallback, false, true); + } + catch (InnerCallbackException e) + { + error = e.getHiddenCause(); + } + } + } + InnerThread innerThread = new InnerThread(); + innerThread.start(); + innerThread.join(30000); + if (innerThread.isAlive()) + { + innerThread.interrupt(); + fail("Transaction hung for 30 seconds. Test failed."); + } + // Rethrow potentially retryable exception + Throwable t = innerThread.getError(); + if (t != null) + { + throw t; + } return null; } }; diff --git a/source/java/org/alfresco/repo/rule/RuleServiceImplTest.java b/source/java/org/alfresco/repo/rule/RuleServiceImplTest.java index 2cd7aa0abd..569b74ddae 100644 --- a/source/java/org/alfresco/repo/rule/RuleServiceImplTest.java +++ b/source/java/org/alfresco/repo/rule/RuleServiceImplTest.java @@ -953,6 +953,7 @@ public class RuleServiceImplTest extends BaseRuleTest public void testDeleteSpaceWithExecuteScriptRule() throws Exception { + endTransaction(); // So we don't hang indefinitely waiting for the outer transaction transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback() { public Object execute() diff --git a/source/java/org/alfresco/repo/search/impl/lucene/ADMLuceneIndexerImpl.java b/source/java/org/alfresco/repo/search/impl/lucene/ADMLuceneIndexerImpl.java index 4308495b4e..d8beb345b5 100644 --- a/source/java/org/alfresco/repo/search/impl/lucene/ADMLuceneIndexerImpl.java +++ b/source/java/org/alfresco/repo/search/impl/lucene/ADMLuceneIndexerImpl.java @@ -193,7 +193,7 @@ public class ADMLuceneIndexerImpl extends AbstractLuceneIndexerImpl imp } /** - * Helper setter of the transformer debug. + * Setter of the transformer debug. * @param transformerDebug */ public void setTransformerDebug(TransformerDebug transformerDebug) @@ -1435,11 +1435,11 @@ public class ADMLuceneIndexerImpl extends AbstractLuceneIndexerImpl imp try { // get the transformer - TransformationOptions options = new TransformationOptions(); - options.setSourceNodeRef(nodeRef); - transformerDebug.pushAvailable(reader.getContentUrl(), reader.getMimetype(), MimetypeMap.MIMETYPE_TEXT_PLAIN, options); + TransformationOptions options = new TransformationOptions(); + options.setSourceNodeRef(nodeRef); + transformerDebug.pushAvailable(reader.getContentUrl(), reader.getMimetype(), MimetypeMap.MIMETYPE_TEXT_PLAIN, options); long sourceSize = reader.getSize(); - List transformers = contentService.getActiveTransformers(reader.getMimetype(), sourceSize, MimetypeMap.MIMETYPE_TEXT_PLAIN, options); + List transformers = contentService.getActiveTransformers(reader.getMimetype(), sourceSize, MimetypeMap.MIMETYPE_TEXT_PLAIN, options); transformerDebug.availableTransformers(transformers, sourceSize, "ADMLuceneIndexer"); if (transformers.isEmpty()) diff --git a/source/java/org/alfresco/repo/security/authentication/AuthenticationTest.java b/source/java/org/alfresco/repo/security/authentication/AuthenticationTest.java index 7a955d70cf..8f1b470ebd 100644 --- a/source/java/org/alfresco/repo/security/authentication/AuthenticationTest.java +++ b/source/java/org/alfresco/repo/security/authentication/AuthenticationTest.java @@ -559,6 +559,7 @@ public class AuthenticationTest extends TestCase public void testCreateAuthenticationWhileRunningAsSystem() throws Exception { + userTransaction.rollback(); RunAsWork authWorkAsMuppet = new RunAsWork() { public Object doWork() throws Exception diff --git a/source/java/org/alfresco/repo/transfer/TransferServiceImplTest.java b/source/java/org/alfresco/repo/transfer/TransferServiceImplTest.java index 708a4625cf..18552a2621 100644 --- a/source/java/org/alfresco/repo/transfer/TransferServiceImplTest.java +++ b/source/java/org/alfresco/repo/transfer/TransferServiceImplTest.java @@ -1485,6 +1485,7 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest */ public void testPathBasedUpdate() throws Exception { + endTransaction(); final RetryingTransactionHelper tran = transactionService.getRetryingTransactionHelper(); final String CONTENT_TITLE = "ContentTitle"; @@ -1602,22 +1603,29 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest testContext.child = nodeService.createNode(testContext.guestHome, ContentModel.ASSOC_CONTAINS, TEST_QNAME, ContentModel.TYPE_CONTENT); testContext.newContentNodeRef = testContext.child.getChildRef(); nodeService.setProperty(testContext.newContentNodeRef, ContentModel.PROP_TITLE, CONTENT_TITLE_UPDATED); - - /** - * Transfer our node which is a new node (so will not exist on the back end) with a path that already has a node. - */ - { - TransferDefinition definition = new TransferDefinition(); - Setnodes = new HashSet(); - nodes.add(testContext.newContentNodeRef); - definition.setNodes(nodes); - transferService.transfer(testContext.targetName, definition); - } return null; } }; tran.doInTransaction(transfer1CB); + RetryingTransactionCallback transfer1CB2 = new RetryingTransactionCallback() { + + @Override + public Void execute() throws Throwable + { + /** + * Transfer our node which is a new node (so will not exist on the back end) with a path that already has a node. + */ + TransferDefinition definition = new TransferDefinition(); + Setnodes = new HashSet(); + nodes.add(testContext.newContentNodeRef); + definition.setNodes(nodes); + transferService.transfer(testContext.targetName, definition); + return null; + } + }; + tran.doInTransaction(transfer1CB2); + RetryingTransactionCallback validateStep1CB = new RetryingTransactionCallback() { @Override diff --git a/source/java/org/alfresco/repo/workflow/AbstractWorkflowServiceIntegrationTest.java b/source/java/org/alfresco/repo/workflow/AbstractWorkflowServiceIntegrationTest.java index 5d1aafdb9c..b90b842e8c 100644 --- a/source/java/org/alfresco/repo/workflow/AbstractWorkflowServiceIntegrationTest.java +++ b/source/java/org/alfresco/repo/workflow/AbstractWorkflowServiceIntegrationTest.java @@ -35,6 +35,7 @@ import org.alfresco.repo.security.authentication.AuthenticationComponent; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.person.TestGroupManager; import org.alfresco.repo.security.person.TestPersonManager; +import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; import org.alfresco.service.ServiceRegistry; import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.NodeRef; @@ -56,6 +57,7 @@ import org.alfresco.service.cmr.workflow.WorkflowTaskState; import org.alfresco.service.cmr.workflow.WorkflowTimer; import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.QName; +import org.alfresco.service.transaction.TransactionService; import org.alfresco.util.BaseSpringTest; import org.alfresco.util.GUID; import org.alfresco.util.collections.CollectionUtils; @@ -83,6 +85,7 @@ public abstract class AbstractWorkflowServiceIntegrationTest extends BaseSpringT protected NodeService nodeService; private NodeRef companyHome; protected WorkflowTestHelper wfTestHelper; + protected TransactionService transactionService; public void testDeployWorkflowDefinition() { @@ -310,7 +313,7 @@ public abstract class AbstractWorkflowServiceIntegrationTest extends BaseSpringT WorkflowPath path = workflowService.startWorkflow(workflowDef.getId(), params); assertNotNull(path); assertTrue(path.isActive()); - String workflowInstanceId = path.getInstance().getId(); + final String workflowInstanceId = path.getInstance().getId(); // End start task to progress workflow WorkflowTask startTask = workflowService.getStartTask(workflowInstanceId); @@ -356,8 +359,19 @@ public abstract class AbstractWorkflowServiceIntegrationTest extends BaseSpringT assertFalse(workflowService.isTaskEditable(currentTask, USER3)); assertFalse(workflowService.isTaskReassignable(currentTask, USER3)); - // cancel the workflow - workflowService.cancelWorkflow(workflowInstanceId); + setComplete(); + endTransaction(); + transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback() + { + @Override + public Void execute() throws Throwable + { + // cancel the workflow + workflowService.cancelWorkflow(workflowInstanceId); + return null; + } + }); + startNewTransaction(); } public void testPooledTaskCapabilities() @@ -384,7 +398,7 @@ public abstract class AbstractWorkflowServiceIntegrationTest extends BaseSpringT WorkflowPath path = workflowService.startWorkflow(workflowDef.getId(), params); assertNotNull(path); assertTrue(path.isActive()); - String workflowInstanceId = path.getInstance().getId(); + final String workflowInstanceId = path.getInstance().getId(); // End start task to progress workflow WorkflowTask startTask = workflowService.getStartTask(workflowInstanceId); @@ -510,8 +524,19 @@ public abstract class AbstractWorkflowServiceIntegrationTest extends BaseSpringT assertFalse(workflowService.isTaskReassignable(currentTask, USER2)); assertFalse(workflowService.isTaskReassignable(currentTask, USER3)); - // cancel the workflow - workflowService.cancelWorkflow(workflowInstanceId); + setComplete(); + endTransaction(); + transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback() + { + @Override + public Void execute() throws Throwable + { + // cancel the workflow + workflowService.cancelWorkflow(workflowInstanceId); + return null; + } + }); + startNewTransaction(); } public void testGetWorkflowTaskDefinitions() @@ -1190,6 +1215,7 @@ public abstract class AbstractWorkflowServiceIntegrationTest extends BaseSpringT this.nodeService = registry.getNodeService(); Repository repositoryHelper = (Repository) applicationContext.getBean("repositoryHelper"); this.companyHome = repositoryHelper.getCompanyHome(); + this.transactionService = registry.getTransactionService(); MutableAuthenticationService authenticationService = registry.getAuthenticationService(); AuthorityService authorityService = registry.getAuthorityService(); @@ -1223,13 +1249,22 @@ public abstract class AbstractWorkflowServiceIntegrationTest extends BaseSpringT @Override protected void onTearDownInTransaction() throws Exception { - wfTestHelper.tearDown(); - authenticationComponent.setSystemUserAsCurrentUser(); - groupManager.clearGroups(); - personManager.clearPeople(); - authenticationComponent.clearCurrentSecurityContext(); + endTransaction(); + transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback() + { + @Override + public Void execute() throws Throwable + { + wfTestHelper.tearDown(); + authenticationComponent.setSystemUserAsCurrentUser(); + groupManager.clearGroups(); + personManager.clearPeople(); + authenticationComponent.clearCurrentSecurityContext(); - super.onTearDownInTransaction(); + AbstractWorkflowServiceIntegrationTest.super.onTearDownInTransaction(); + return null; + } + }); } protected abstract String getEngine(); diff --git a/source/test-resources/subsystem-test-context.xml b/source/test-resources/subsystem-test-context.xml index 0187ce2a5c..23df0f587c 100644 --- a/source/test-resources/subsystem-test-context.xml +++ b/source/test-resources/subsystem-test-context.xml @@ -5,7 +5,7 @@ xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd"> - +