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