diff --git a/config/alfresco/avm-services-context.xml b/config/alfresco/avm-services-context.xml
index abb05145dc..754d221cb9 100644
--- a/config/alfresco/avm-services-context.xml
+++ b/config/alfresco/avm-services-context.xml
@@ -12,10 +12,6 @@
-
-
-
-
@@ -48,12 +44,6 @@
-
-
-
-
-
-
diff --git a/config/alfresco/bootstrap-context.xml b/config/alfresco/bootstrap-context.xml
index cc5379e981..4420dd5e03 100644
--- a/config/alfresco/bootstrap-context.xml
+++ b/config/alfresco/bootstrap-context.xml
@@ -79,6 +79,7 @@
classpath:alfresco/dbscripts/create/${db.script.dialect}/AlfrescoPostCreate-JBPM-Extra.sql
+ classpath:alfresco/dbscripts/create/${db.script.dialect}/node-prop-serializable.sql
@@ -122,6 +123,8 @@
+
+
diff --git a/config/alfresco/core-services-context.xml b/config/alfresco/core-services-context.xml
index 7b96191c37..e2cb2b8610 100644
--- a/config/alfresco/core-services-context.xml
+++ b/config/alfresco/core-services-context.xml
@@ -4,6 +4,16 @@
+
+
+
+
+
+
+
+
+
+
@@ -136,9 +146,22 @@
class="org.springframework.remoting.rmi.RmiRegistryFactoryBean"
lazy-init="true">
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+ patch.db-V3.3-JBPM-Extra
+ patch.schemaUpgradeScript.description
+ 0
+ 4105
+ 4106
+
+ classpath:alfresco/dbscripts/create/${db.script.dialect}/AlfrescoPostCreate-3.3-JBPM-Extra.sql
+
+
+
+
+ patch.db-V3.3-Node-Prop-Serializable
+ patch.schemaUpgradeScript.description
+ 0
+ 4105
+ 4106
+
+ classpath:alfresco/dbscripts/create/${db.script.dialect}/node-prop-serializable.sql
+
+
+
\ No newline at end of file
diff --git a/config/alfresco/remote-services-context.xml b/config/alfresco/remote-services-context.xml
index 35504e9fee..a2f85fc5d7 100644
--- a/config/alfresco/remote-services-context.xml
+++ b/config/alfresco/remote-services-context.xml
@@ -20,9 +20,7 @@
-
-
+
@@ -32,15 +30,9 @@
avm
-
- ${alfresco.rmi.services.port}
- ${avm.rmi.service.port}
-
- ${alfresco.rmi.services.host}
-
@@ -52,8 +44,7 @@
-
+
@@ -63,20 +54,13 @@
avmsync
-
- ${alfresco.rmi.services.port}
-
-
- ${alfresco.rmi.services.host}
- ${avmsync.rmi.service.port}
-
+
@@ -86,12 +70,6 @@
authentication
-
- ${alfresco.rmi.services.port}
-
-
- ${alfresco.rmi.services.host}
- ${authentication.rmi.service.port}
@@ -149,7 +127,7 @@
-
+
@@ -159,12 +137,6 @@
repo
-
- ${alfresco.rmi.services.port}
-
-
- ${alfresco.rmi.services.host}
- ${repo.rmi.service.port}
@@ -181,7 +153,7 @@
-
+
@@ -191,12 +163,6 @@
action
-
- ${alfresco.rmi.services.port}
-
-
- ${alfresco.rmi.services.host}
- ${action.rmi.service.port}
diff --git a/config/alfresco/rendition-services-context.xml b/config/alfresco/rendition-services-context.xml
index 52f663ffc5..d10a1062bc 100644
--- a/config/alfresco/rendition-services-context.xml
+++ b/config/alfresco/rendition-services-context.xml
@@ -83,6 +83,9 @@
+
+ false
+ ${ldap.authentication.java.naming.provider.url}
-
+
${ldap.authentication.java.naming.security.authentication}
+
+
+
+
diff --git a/config/alfresco/subsystems/Authentication/ldap-ad/ldap-ad-authentication.properties b/config/alfresco/subsystems/Authentication/ldap-ad/ldap-ad-authentication.properties
index a6d3718b63..05df62c1aa 100644
--- a/config/alfresco/subsystems/Authentication/ldap-ad/ldap-ad-authentication.properties
+++ b/config/alfresco/subsystems/Authentication/ldap-ad/ldap-ad-authentication.properties
@@ -19,7 +19,7 @@ ldap.authentication.java.naming.factory.initial=com.sun.jndi.ldap.LdapCtxFactory
# The URL to connect to the LDAP server
ldap.authentication.java.naming.provider.url=ldap://domaincontroller.company.com:389
-# The authentication mechanism to use
+# The authentication mechanism to use for password validation
ldap.authentication.java.naming.security.authentication=simple
# Escape commas entered by the user at bind time
@@ -40,6 +40,9 @@ ldap.authentication.defaultAdministratorUserNames=Administrator
# authentication, in which case this flag should be set to false.
ldap.synchronization.active=true
+# The authentication mechanism to use for synchronization
+ldap.synchronization.java.naming.security.authentication=simple
+
# The default principal to bind with (only used for LDAP sync). This should be a UPN or DN
ldap.synchronization.java.naming.security.principal=alfresco@domain
diff --git a/config/alfresco/subsystems/Authentication/ldap/ldap-authentication.properties b/config/alfresco/subsystems/Authentication/ldap/ldap-authentication.properties
index 2b0796aed9..2caf6a30cf 100644
--- a/config/alfresco/subsystems/Authentication/ldap/ldap-authentication.properties
+++ b/config/alfresco/subsystems/Authentication/ldap/ldap-authentication.properties
@@ -25,7 +25,7 @@ ldap.authentication.java.naming.factory.initial=com.sun.jndi.ldap.LdapCtxFactory
# The URL to connect to the LDAP server
ldap.authentication.java.naming.provider.url=ldap://openldap.domain.com:389
-# The authentication mechanism to use
+# The authentication mechanism to use for password validation
ldap.authentication.java.naming.security.authentication=simple
# Escape commas entered by the user at bind time
@@ -46,6 +46,9 @@ ldap.authentication.defaultAdministratorUserNames=
# authentication, in which case this flag should be set to false.
ldap.synchronization.active=true
+# The authentication mechanism to use for synchronization
+ldap.synchronization.java.naming.security.authentication=simple
+
# The default principal to use (only used for LDAP sync)
ldap.synchronization.java.naming.security.principal=cn\=Manager,dc\=company,dc\=com
diff --git a/config/alfresco/subsystems/email/InboundSMTP/inboundSMTP-context.xml b/config/alfresco/subsystems/email/InboundSMTP/inboundSMTP-context.xml
index 82bd92110c..1a66145512 100755
--- a/config/alfresco/subsystems/email/InboundSMTP/inboundSMTP-context.xml
+++ b/config/alfresco/subsystems/email/InboundSMTP/inboundSMTP-context.xml
@@ -36,7 +36,7 @@
-
+
@@ -46,9 +46,6 @@
EmailService
-
- ${alfresco.rmi.services.port}
-
diff --git a/config/alfresco/subsystems/wcm_deployment_receiver/default/deployment-receiver-context.xml b/config/alfresco/subsystems/wcm_deployment_receiver/default/deployment-receiver-context.xml
index bece4d12b2..26bbf4a150 100644
--- a/config/alfresco/subsystems/wcm_deployment_receiver/default/deployment-receiver-context.xml
+++ b/config/alfresco/subsystems/wcm_deployment_receiver/default/deployment-receiver-context.xml
@@ -50,7 +50,7 @@
-
+
@@ -60,15 +60,9 @@
deployment
-
- ${alfresco.rmi.services.port}
- ${wcm-deployment-receiver.rmi.service.port}
-
- ${alfresco.rmi.services.host}
-
diff --git a/config/alfresco/transfer-service-context.xml b/config/alfresco/transfer-service-context.xml
index 0e40f5b7b3..6d4bb89cc9 100644
--- a/config/alfresco/transfer-service-context.xml
+++ b/config/alfresco/transfer-service-context.xml
@@ -58,6 +58,7 @@
+ /${spaces.company_home.childname}/${spaces.dictionary.childname}/${spaces.transfers.childname}
diff --git a/config/alfresco/version.properties b/config/alfresco/version.properties
index 920dd97f51..40f60eaeab 100644
--- a/config/alfresco/version.properties
+++ b/config/alfresco/version.properties
@@ -19,4 +19,4 @@ version.build=@build-number@
# Schema number
-version.schema=4105
+version.schema=4106
diff --git a/source/java/org/alfresco/filesys/auth/cifs/PassthruCifsAuthenticator.java b/source/java/org/alfresco/filesys/auth/cifs/PassthruCifsAuthenticator.java
index 90de086fa5..d03d201505 100644
--- a/source/java/org/alfresco/filesys/auth/cifs/PassthruCifsAuthenticator.java
+++ b/source/java/org/alfresco/filesys/auth/cifs/PassthruCifsAuthenticator.java
@@ -269,14 +269,17 @@ public class PassthruCifsAuthenticator extends CifsAuthenticatorBase implements
else
{
// Map the passthru username to an Alfresco person
-
+
String username = client.getUserName();
- String personName = getPersonService().getUserIdentifier( username);
-
+ String personName = getPersonService().getUserIdentifier(username);
+ if (null == personName)
+ {
+ personName = username;
+ }
if ( personName != null)
{
// Use the person name as the current user
-
+
getAuthenticationComponent().setCurrentUser(personName);
alfClient.setAuthenticationTicket(getAuthenticationService().getCurrentTicket());
diff --git a/source/java/org/alfresco/filesys/auth/ftp/PassthruFtpAuthenticator.java b/source/java/org/alfresco/filesys/auth/ftp/PassthruFtpAuthenticator.java
index 747be9f0d6..d1ba324b2b 100644
--- a/source/java/org/alfresco/filesys/auth/ftp/PassthruFtpAuthenticator.java
+++ b/source/java/org/alfresco/filesys/auth/ftp/PassthruFtpAuthenticator.java
@@ -415,7 +415,7 @@ public class PassthruFtpAuthenticator extends FTPAuthenticatorBase {
}
catch (Exception ex)
{
- logger.error("Passthru error", ex);
+ logger.debug("Passthru error", ex);
}
finally {
diff --git a/source/java/org/alfresco/repo/action/executer/ContentMetadataExtracter.java b/source/java/org/alfresco/repo/action/executer/ContentMetadataExtracter.java
index e3406ec508..f600d02d86 100644
--- a/source/java/org/alfresco/repo/action/executer/ContentMetadataExtracter.java
+++ b/source/java/org/alfresco/repo/action/executer/ContentMetadataExtracter.java
@@ -186,6 +186,11 @@ public class ContentMetadataExtracter extends ActionExecuterAbstractBase
Set requiredAspectQNames = new HashSet(3);
Set aspectPropertyQNames = new HashSet(17);
+ /**
+ * The modified properties contain null values as well. As we are only interested
+ * in the keys, this will force aspect aspect properties to be removed even if there
+ * are no settable properties pertaining to the aspect.
+ */
for (QName propertyQName : modifiedProperties.keySet())
{
PropertyDefinition propertyDef = dictionaryService.getProperty(propertyQName);
@@ -212,6 +217,12 @@ public class ContentMetadataExtracter extends ActionExecuterAbstractBase
{
if (!modifiedProperties.containsKey(aspectPropertyQName))
{
+ // Simple case: This property was not extracted
+ nodeProperties.remove(aspectPropertyQName);
+ }
+ else if (modifiedProperties.get(aspectPropertyQName) == null)
+ {
+ // Trickier (ALF-1823): The property was extracted as 'null'
nodeProperties.remove(aspectPropertyQName);
}
}
diff --git a/source/java/org/alfresco/repo/action/executer/ContentMetadataExtracterTest.java b/source/java/org/alfresco/repo/action/executer/ContentMetadataExtracterTest.java
index c51c92dd1f..659eeee77c 100644
--- a/source/java/org/alfresco/repo/action/executer/ContentMetadataExtracterTest.java
+++ b/source/java/org/alfresco/repo/action/executer/ContentMetadataExtracterTest.java
@@ -123,9 +123,9 @@ public class ContentMetadataExtracterTest extends BaseSpringTest
private static final QName PROP_UNKNOWN_1 = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "unkown1");
private static final QName PROP_UNKNOWN_2 = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "unkown2");
- private static class UnknownMetadataExtracter extends AbstractMappingMetadataExtracter
+ private static class TestUnknownMetadataExtracter extends AbstractMappingMetadataExtracter
{
- public UnknownMetadataExtracter()
+ public TestUnknownMetadataExtracter()
{
Properties mappingProperties = new Properties();
mappingProperties.put("unknown1", PROP_UNKNOWN_1.toString());
@@ -156,7 +156,7 @@ public class ContentMetadataExtracterTest extends BaseSpringTest
public void testUnknownProperties()
{
MetadataExtracterRegistry registry = (MetadataExtracterRegistry) applicationContext.getBean("metadataExtracterRegistry");
- UnknownMetadataExtracter extracterUnknown = new UnknownMetadataExtracter();
+ TestUnknownMetadataExtracter extracterUnknown = new TestUnknownMetadataExtracter();
extracterUnknown.setRegistry(registry);
extracterUnknown.register();
// Now add some content with a binary mimetype
@@ -174,6 +174,85 @@ public class ContentMetadataExtracterTest extends BaseSpringTest
assertNotNull("Unknown property is null", prop1);
assertNotNull("Unknown property is null", prop2);
}
+
+ private static class TestNullPropMetadataExtracter extends AbstractMappingMetadataExtracter
+ {
+ public TestNullPropMetadataExtracter()
+ {
+ Properties mappingProperties = new Properties();
+ mappingProperties.put("title", ContentModel.PROP_TITLE.toString());
+ mappingProperties.put("description", ContentModel.PROP_DESCRIPTION.toString());
+ setMappingProperties(mappingProperties);
+ }
+ @Override
+ protected Map> getDefaultMapping()
+ {
+ // No need to give anything back as we have explicitly set the mapping already
+ return new HashMap>(0);
+ }
+ @Override
+ public boolean isSupported(String sourceMimetype)
+ {
+ return sourceMimetype.equals(MimetypeMap.MIMETYPE_BINARY);
+ }
+
+ public Map extractRaw(ContentReader reader) throws Throwable
+ {
+ Map rawMap = newRawMap();
+ putRawValue("title", null, rawMap);
+ putRawValue("description", "", rawMap);
+ return rawMap;
+ }
+ }
+
+ /**
+ * Ensure that missing raw values result in node properties being removed
+ * when running with {@link ContentMetadataExtracter#setCarryAspectProperties(boolean)}
+ * set to false.
+ */
+ public void testNullExtractedValues_ALF1823()
+ {
+ MetadataExtracterRegistry registry = (MetadataExtracterRegistry) applicationContext.getBean("metadataExtracterRegistry");
+ TestNullPropMetadataExtracter extractor = new TestNullPropMetadataExtracter();
+ extractor.setRegistry(registry);
+ extractor.register();
+ // Now set the title and description
+ nodeService.setProperty(nodeRef, ContentModel.PROP_TITLE, "TITLE");
+ nodeService.setProperty(nodeRef, ContentModel.PROP_DESCRIPTION, "DESCRIPTION");
+ // Now add some content with a binary mimetype
+ ContentWriter cw = this.contentService.getWriter(nodeRef, ContentModel.PROP_CONTENT, true);
+ cw.setMimetype(MimetypeMap.MIMETYPE_BINARY);
+ cw.putContent("Content for " + getName());
+
+ ActionImpl action = new ActionImpl(null, ID, SetPropertyValueActionExecuter.NAME, null);
+ executer.execute(action, this.nodeRef);
+
+ // cm:titled properties should be present
+ Serializable title = nodeService.getProperty(nodeRef, ContentModel.PROP_TITLE);
+ Serializable descr = nodeService.getProperty(nodeRef, ContentModel.PROP_DESCRIPTION);
+
+ assertNotNull("cm:title property is null", title);
+ assertNotNull("cm:description property is null", descr);
+
+ try
+ {
+ // Now change the setting to remove unset aspect properties
+ executer.setCarryAspectProperties(false);
+ // Extract again
+ executer.execute(action, this.nodeRef);
+
+ // cm:titled properties should *NOT* be present
+ title = nodeService.getProperty(nodeRef, ContentModel.PROP_TITLE);
+ descr = nodeService.getProperty(nodeRef, ContentModel.PROP_DESCRIPTION);
+
+ assertNull("cm:title property is not null", title);
+ assertNull("cm:description property is not null", descr);
+ }
+ finally
+ {
+ executer.setCarryAspectProperties(true);
+ }
+ }
/**
* Test execution of the pragmatic approach
diff --git a/source/java/org/alfresco/repo/avm/AVMDAOs.java b/source/java/org/alfresco/repo/avm/AVMDAOs.java
index 4b95cddb96..d81c7ea6a9 100644
--- a/source/java/org/alfresco/repo/avm/AVMDAOs.java
+++ b/source/java/org/alfresco/repo/avm/AVMDAOs.java
@@ -74,16 +74,6 @@ public class AVMDAOs
*/
public ChildEntryDAO fChildEntryDAO;
- /**
- * The HistoryLinkDAO.
- */
- public HistoryLinkDAO fHistoryLinkDAO;
-
- /**
- * The MergeLinkDAO.
- */
- public MergeLinkDAO fMergeLinkDAO;
-
/**
* The AVMStorePropertyDAO
*/
@@ -123,23 +113,7 @@ public class AVMDAOs
{
fChildEntryDAO = childEntryDAO;
}
-
- /**
- * @param historyLinkDAO the fHistoryLinkDAO to set
- */
- public void setHistoryLinkDAO(HistoryLinkDAO historyLinkDAO)
- {
- fHistoryLinkDAO = historyLinkDAO;
- }
-
- /**
- * @param mergeLinkDAO the fMergeLinkDAO to set
- */
- public void setMergeLinkDAO(MergeLinkDAO mergeLinkDAO)
- {
- fMergeLinkDAO = mergeLinkDAO;
- }
-
+
/**
* @param aVMStoreDAO The fAVMStoreDAO to set
*/
diff --git a/source/java/org/alfresco/repo/avm/AVMNodeImpl.java b/source/java/org/alfresco/repo/avm/AVMNodeImpl.java
index 386e258862..97e69aae0a 100644
--- a/source/java/org/alfresco/repo/avm/AVMNodeImpl.java
+++ b/source/java/org/alfresco/repo/avm/AVMNodeImpl.java
@@ -26,6 +26,7 @@ import java.util.Set;
import org.alfresco.repo.avm.util.RawServices;
import org.alfresco.repo.domain.DbAccessControlList;
import org.alfresco.repo.domain.PropertyValue;
+import org.alfresco.repo.domain.avm.AVMHistoryLinkEntity;
import org.alfresco.repo.security.permissions.ACLCopyMode;
import org.alfresco.service.cmr.avm.AVMReadOnlyException;
import org.alfresco.service.namespace.QName;
@@ -135,22 +136,19 @@ public abstract class AVMNodeImpl implements AVMNode
{
return;
}
- HistoryLinkImpl link = new HistoryLinkImpl();
- link.setAncestor(ancestor);
- link.setDescendent(this);
- AVMDAOs.Instance().fHistoryLinkDAO.save(link);
+ AVMDAOs.Instance().newAVMNodeLinksDAO.createHistoryLink(ancestor.getId(), this.getId());
}
-
+
/**
* Change the ancestor of this node.
* @param ancestor The new ancestor to give it.
*/
public void changeAncestor(AVMNode ancestor)
{
- HistoryLink old = AVMDAOs.Instance().fHistoryLinkDAO.getByDescendent(this);
- if (old != null)
+ AVMHistoryLinkEntity hlEntity = AVMDAOs.Instance().newAVMNodeLinksDAO.getHistoryLinkByDescendent(this.getId());
+ if (hlEntity != null)
{
- AVMDAOs.Instance().fHistoryLinkDAO.delete(old);
+ AVMDAOs.Instance().newAVMNodeLinksDAO.deleteHistoryLink(hlEntity.getAncestorNodeId(), hlEntity.getDescendentNodeId());
}
setAncestor(ancestor);
}
@@ -174,10 +172,7 @@ public abstract class AVMNodeImpl implements AVMNode
{
return;
}
- MergeLinkImpl link = new MergeLinkImpl();
- link.setMfrom(mergedFrom);
- link.setMto(this);
- AVMDAOs.Instance().fMergeLinkDAO.save(link);
+ AVMDAOs.Instance().newAVMNodeLinksDAO.createMergeLink(mergedFrom.getId(), this.getId());
}
/**
diff --git a/source/java/org/alfresco/repo/avm/AVMRepository.java b/source/java/org/alfresco/repo/avm/AVMRepository.java
index ac3f4a6f64..8db578d186 100644
--- a/source/java/org/alfresco/repo/avm/AVMRepository.java
+++ b/source/java/org/alfresco/repo/avm/AVMRepository.java
@@ -58,9 +58,9 @@ import org.alfresco.service.cmr.security.PermissionContext;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.FileNameValidator;
+import org.alfresco.util.Pair;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-import org.alfresco.util.Pair;
/**
* This or AVMStore are the implementors of the operations specified by AVMService.
@@ -1016,12 +1016,15 @@ public class AVMRepository
throw new AccessDeniedException("Not allowed to purge: " + name);
}
+ root.setIsRoot(false);
fAVMNodeDAO.update(root);
List vRoots = fVersionRootDAO.getAllInAVMStore(store);
for (VersionRoot vr : vRoots)
{
AVMNode node = fAVMNodeDAO.getByID(vr.getRoot().getId());
+
+ root.setIsRoot(false);
fAVMNodeDAO.update(node);
fVersionLayeredNodeEntryDAO.delete(vr);
@@ -1038,6 +1041,11 @@ public class AVMRepository
fAVMStoreDAO.delete(store);
fAVMStoreDAO.invalidateCache();
fPurgeStoreTxnListener.storePurged(name);
+
+ if (fgLogger.isDebugEnabled())
+ {
+ fgLogger.debug("Purged store: "+name);
+ }
}
/**
@@ -1059,6 +1067,11 @@ public class AVMRepository
fLookupCache.onDelete(name);
store.purgeVersion(version);
fPurgeVersionTxnListener.versionPurged(name, version);
+
+ if (fgLogger.isDebugEnabled())
+ {
+ fgLogger.debug("Purged version: "+name+" "+version);
+ }
}
/**
diff --git a/source/java/org/alfresco/repo/avm/AVMStoreImpl.java b/source/java/org/alfresco/repo/avm/AVMStoreImpl.java
index 90e6b06ab1..2c56fccbdd 100644
--- a/source/java/org/alfresco/repo/avm/AVMStoreImpl.java
+++ b/source/java/org/alfresco/repo/avm/AVMStoreImpl.java
@@ -844,8 +844,11 @@ public class AVMStoreImpl implements AVMStore
throw new AVMNotFoundException("Not allowed to delete in store : " + getName() +" at " + path);
}
- dir.removeChild(lPath, name);
- //dir.updateModTime();
+ if (dir != null)
+ {
+ dir.removeChild(lPath, name);
+ //dir.updateModTime();
+ }
}
/**
diff --git a/source/java/org/alfresco/repo/avm/AVMTester.java b/source/java/org/alfresco/repo/avm/AVMTester.java
index a88c2cd19f..b2edfced29 100644
--- a/source/java/org/alfresco/repo/avm/AVMTester.java
+++ b/source/java/org/alfresco/repo/avm/AVMTester.java
@@ -315,6 +315,10 @@ class AVMTester implements Runnable
{
String name = fNames[fgRandom.nextInt(26 * 26)];
String path = randomPath();
+ if (path == null)
+ {
+ return;
+ }
AVMNodeDescriptor desc = fService.lookup(-1, path);
if (desc == null)
{
@@ -398,6 +402,10 @@ class AVMTester implements Runnable
private void removeNode()
{
String target = randomPath();
+ if (target == null)
+ {
+ return;
+ }
int lastSlash = target.lastIndexOf('/');
String path = target.substring(0, lastSlash);
if (path.equals("main:"))
diff --git a/source/java/org/alfresco/repo/avm/HistoryLink.java b/source/java/org/alfresco/repo/avm/HistoryLink.java
deleted file mode 100644
index 8ddef44c1c..0000000000
--- a/source/java/org/alfresco/repo/avm/HistoryLink.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2005-2010 Alfresco Software Limited.
- *
- * This file is part of Alfresco
- *
- * Alfresco is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Alfresco is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with Alfresco. If not, see . */
-
-package org.alfresco.repo.avm;
-
-/**
- * Interface for the ancestor-descendent relationship.
- * @author britt
- */
-public interface HistoryLink
-{
- /**
- * Set the ancestor part of this.
- * @param ancestor
- */
- public void setAncestor(AVMNode ancestor);
-
- /**
- * Get the ancestor part of this.
- * @return The ancestor.
- */
- public AVMNode getAncestor();
-
- /**
- * Set the descendent part of this.
- * @param descendent
- */
- public void setDescendent(AVMNode descendent);
-
- /**
- * Get the descendent part of this.
- * @return The descendent of this link.
- */
- public AVMNode getDescendent();
-}
diff --git a/source/java/org/alfresco/repo/avm/HistoryLinkDAO.java b/source/java/org/alfresco/repo/avm/HistoryLinkDAO.java
deleted file mode 100644
index b55cff0e38..0000000000
--- a/source/java/org/alfresco/repo/avm/HistoryLinkDAO.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2005-2010 Alfresco Software Limited.
- *
- * This file is part of Alfresco
- *
- * Alfresco is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Alfresco is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with Alfresco. If not, see . */
-
-package org.alfresco.repo.avm;
-
-import java.util.List;
-
-/**
- * DAO for history links.
- * @author britt
- */
-public interface HistoryLinkDAO
-{
- /**
- * Save and unsaved HistoryLink.
- * @param link
- */
- public void save(HistoryLink link);
-
- /**
- * Get the history link with the given descendent.
- * @param descendent The descendent.
- * @return The HistoryLink or null if not found.
- */
- public HistoryLink getByDescendent(AVMNode descendent);
-
- /**
- * Get all the descendents of a node.
- * @param ancestor The ancestor node.
- * @return A List of AVMNode descendents.
- */
- public List getByAncestor(AVMNode ancestor);
-
- /**
- * Delete a HistoryLink
- * @param link The link to delete.
- */
- public void delete(HistoryLink link);
-}
diff --git a/source/java/org/alfresco/repo/avm/HistoryLinkImpl.java b/source/java/org/alfresco/repo/avm/HistoryLinkImpl.java
deleted file mode 100644
index 723c0c7f7c..0000000000
--- a/source/java/org/alfresco/repo/avm/HistoryLinkImpl.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright (C) 2005-2010 Alfresco Software Limited.
- *
- * This file is part of Alfresco
- *
- * Alfresco is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Alfresco is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with Alfresco. If not, see . */
-
-package org.alfresco.repo.avm;
-
-import java.io.Serializable;
-
-/**
- * Holds a ancestor-descendent relationship.
- * @author britt
- */
-public class HistoryLinkImpl implements HistoryLink, Serializable
-{
- private static final long serialVersionUID = -430859344980137718L;
-
- /**
- * The ancestor.
- */
- private AVMNode fAncestor;
-
- /**
- * The descendent.
- */
- private AVMNode fDescendent;
-
- /**
- * Set the ancestor part of this.
- * @param ancestor
- */
- public void setAncestor(AVMNode ancestor)
- {
- fAncestor = ancestor;
- }
-
- /**
- * Get the ancestor part of this.
- * @return The ancestor.
- */
- public AVMNode getAncestor()
- {
- return fAncestor;
- }
-
- /**
- * Set the descendent part of this.
- * @param descendent
- */
- public void setDescendent(AVMNode descendent)
- {
- fDescendent = descendent;
- }
-
- /**
- * Get the descendent part of this.
- * @return The descendent.
- */
- public AVMNode getDescendent()
- {
- return fDescendent;
- }
-
- /**
- * Equals override.
- * @param obj
- * @return Equality.
- */
- @Override
- public boolean equals(Object obj)
- {
- if (this == obj)
- {
- return true;
- }
- if (!(obj instanceof HistoryLink))
- {
- return false;
- }
- HistoryLink o = (HistoryLink)obj;
- return fAncestor.equals(o.getAncestor()) && fDescendent.equals(o.getDescendent());
- }
-
- /**
- * Get the hashcode.
- * @return The hashcode.
- */
- @Override
- public int hashCode()
- {
- return fAncestor.hashCode() + fDescendent.hashCode();
- }
-}
diff --git a/source/java/org/alfresco/repo/avm/MergeLink.java b/source/java/org/alfresco/repo/avm/MergeLink.java
deleted file mode 100644
index aecc343ff4..0000000000
--- a/source/java/org/alfresco/repo/avm/MergeLink.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2005-2010 Alfresco Software Limited.
- *
- * This file is part of Alfresco
- *
- * Alfresco is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Alfresco is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with Alfresco. If not, see . */
-
-package org.alfresco.repo.avm;
-
-/**
- * This is the interface for the merged from - to relationship.
- * @author britt
- */
-public interface MergeLink
-{
- /**
- * Set the from part.
- * @param from
- */
- public void setMfrom(AVMNode from);
-
- /**
- * Get the from part.
- * @return The from part.
- */
- public AVMNode getMfrom();
-
- /**
- * Set the to part.
- * @param to
- */
- public void setMto(AVMNode to);
-
- /**
- * Get the to part.
- * @return The to part.
- */
- public AVMNode getMto();
-}
diff --git a/source/java/org/alfresco/repo/avm/MergeLinkDAO.java b/source/java/org/alfresco/repo/avm/MergeLinkDAO.java
deleted file mode 100644
index 9fffeca84a..0000000000
--- a/source/java/org/alfresco/repo/avm/MergeLinkDAO.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2005-2010 Alfresco Software Limited.
- *
- * This file is part of Alfresco
- *
- * Alfresco is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Alfresco is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with Alfresco. If not, see . */
-
-package org.alfresco.repo.avm;
-
-import java.util.List;
-
-/**
- * DAO for MergeLinks.
- * @author britt
- */
-public interface MergeLinkDAO
-{
- /**
- * Save an unsaved MergeLink.
- * @param link The link to save.
- */
- public void save(MergeLink link);
-
- /**
- * Get a link from the merged to node.
- * @param to The node merged to.
- * @return An AVMNode or null if not found.
- */
- public MergeLink getByTo(AVMNode to);
-
- /**
- * Get all the link that the given node was merged to.
- * @param from The node that was merged from
- * @return A List of MergeLinks.
- */
- public List getByFrom(AVMNode from);
-
- /**
- * Delete a link.
- * @param link The link to delete.
- */
- public void delete(MergeLink link);
-}
diff --git a/source/java/org/alfresco/repo/avm/MergeLinkImpl.java b/source/java/org/alfresco/repo/avm/MergeLinkImpl.java
deleted file mode 100644
index e68f880f42..0000000000
--- a/source/java/org/alfresco/repo/avm/MergeLinkImpl.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright (C) 2005-2010 Alfresco Software Limited.
- *
- * This file is part of Alfresco
- *
- * Alfresco is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Alfresco is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with Alfresco. If not, see . */
-
-package org.alfresco.repo.avm;
-
-import java.io.Serializable;
-
-/**
- * This contains a single merged from-to relationship.
- * @author britt
- */
-public class MergeLinkImpl implements MergeLink, Serializable
-{
- private static final long serialVersionUID = 6672271083042424944L;
-
- /**
- * The node that was merged from.
- */
- private AVMNode fFrom;
-
- /**
- * The node that was merged to.
- */
- private AVMNode fTo;
-
- /**
- * Set the from part.
- * @param from
- */
- public void setMfrom(AVMNode from)
- {
- fFrom = from;
- }
-
- /**
- * Get the from part.
- * @return The from part.
- */
- public AVMNode getMfrom()
- {
- return fFrom;
- }
-
- /**
- * Set the to part.
- * @param to
- */
- public void setMto(AVMNode to)
- {
- fTo = to;
- }
-
- /**
- * Get the to part.
- * @return The to part.
- */
- public AVMNode getMto()
- {
- return fTo;
- }
-
- /**
- * Override of equals.
- * @param obj
- * @return Equality.
- */
- @Override
- public boolean equals(Object obj)
- {
- if (this == obj)
- {
- return true;
- }
- if (!(obj instanceof MergeLink))
- {
- return false;
- }
- MergeLink o = (MergeLink)obj;
- return fFrom.equals(o.getMfrom()) && fTo.equals(o.getMto());
- }
-
- /**
- * Get the hash code.
- * @return The hash code.
- */
- @Override
- public int hashCode()
- {
- return fFrom.hashCode() + fTo.hashCode();
- }
-}
diff --git a/source/java/org/alfresco/repo/avm/OrphanReaper.java b/source/java/org/alfresco/repo/avm/OrphanReaper.java
index ca38bcbdc0..a624dfcdb3 100644
--- a/source/java/org/alfresco/repo/avm/OrphanReaper.java
+++ b/source/java/org/alfresco/repo/avm/OrphanReaper.java
@@ -22,12 +22,13 @@ import java.util.LinkedList;
import java.util.List;
import org.alfresco.repo.domain.DbAccessControlList;
+import org.alfresco.repo.domain.avm.AVMHistoryLinkEntity;
+import org.alfresco.repo.domain.avm.AVMMergeLinkEntity;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.transaction.TransactionService;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-import org.hibernate.SessionFactory;
/**
* This is the background thread for reaping no longer referenced nodes in the AVM repository. These orphans arise from
@@ -43,9 +44,20 @@ public class OrphanReaper
{
if (fRunning)
{
+ if (fgLogger.isDebugEnabled())
+ {
+ fgLogger.debug("OrphanReaper is already running - just return");
+ }
+
return;
}
+
fRunning = true;
+
+ if (fgLogger.isTraceEnabled())
+ {
+ fgLogger.trace("Start running OrphanReaper ...");
+ }
}
try
{
@@ -54,14 +66,23 @@ public class OrphanReaper
doBatch();
if (fDone)
{
+ if (fgLogger.isTraceEnabled())
+ {
+ fgLogger.trace("OrphanReaper is done - just return");
+ }
return;
}
try
{
+ if (fgLogger.isTraceEnabled())
+ {
+ fgLogger.trace("OrphanReaper is not done - sleep for "+fActiveBaseSleep+" ms");
+ }
Thread.sleep(fActiveBaseSleep);
}
catch (InterruptedException e)
{
+ fgLogger.warn("OrphanReaper was interrupted - do nothing: "+e);
// Do nothing.
}
}
@@ -72,6 +93,11 @@ public class OrphanReaper
synchronized (this)
{
fRunning = false;
+
+ if (fgLogger.isTraceEnabled())
+ {
+ fgLogger.trace("... finish running OrphanReaper");
+ }
}
}
}
@@ -239,6 +265,11 @@ public class OrphanReaper
List nodes = AVMDAOs.Instance().fAVMNodeDAO.getOrphans(fQueueLength);
if (nodes.size() == 0)
{
+ if (fgLogger.isTraceEnabled())
+ {
+ fgLogger.trace("Nothing to purge (set fActive = false)");
+ }
+
fActive = false;
return null;
}
@@ -248,55 +279,80 @@ public class OrphanReaper
fPurgeQueue.add(node.getId());
}
}
+
+ if (fgLogger.isDebugEnabled())
+ {
+ fgLogger.debug("Found orphan nodes (fpurgeQueue size = "+fPurgeQueue.size()+")");
+ }
+
fActive = true;
for (int i = 0; i < fBatchSize; i++)
{
if (fPurgeQueue.size() == 0)
{
+ if (fgLogger.isDebugEnabled())
+ {
+ fgLogger.debug("Purge queue is empty (fpurgeQueue size = "+fPurgeQueue.size()+")");
+ }
+
fPurgeQueue = null;
return null;
}
- AVMNode node = AVMDAOs.Instance().fAVMNodeDAO.getByID(fPurgeQueue.removeFirst());
+
+ Long nodeId = fPurgeQueue.removeFirst();
+ AVMNode node = AVMDAOs.Instance().fAVMNodeDAO.getByID(nodeId);
if (node == null)
{
// eg. cluster, multiple reapers
+
+ fgLogger.warn("Node ["+nodeId+"] not found - assume multiple reapers ...");
+
continue;
}
// Save away the ancestor and merged from fields from this node.
- HistoryLink hlink = AVMDAOs.Instance().fHistoryLinkDAO.getByDescendent(node);
+
AVMNode ancestor = null;
- if (hlink != null)
+ AVMHistoryLinkEntity hlEntity = AVMDAOs.Instance().newAVMNodeLinksDAO.getHistoryLinkByDescendent(node.getId());
+ if (hlEntity != null)
{
- ancestor = hlink.getAncestor();
- AVMDAOs.Instance().fHistoryLinkDAO.delete(hlink);
+ ancestor = AVMDAOs.Instance().fAVMNodeDAO.getByID(hlEntity.getAncestorNodeId());
+ AVMDAOs.Instance().newAVMNodeLinksDAO.deleteHistoryLink(hlEntity.getAncestorNodeId(), hlEntity.getDescendentNodeId());
}
- MergeLink mlink = AVMDAOs.Instance().fMergeLinkDAO.getByTo(node);
+
AVMNode mergedFrom = null;
- if (mlink != null)
+ AVMMergeLinkEntity mlEntity = AVMDAOs.Instance().newAVMNodeLinksDAO.getMergeLinkByTo(node.getId());
+ if (mlEntity != null)
{
- mergedFrom = mlink.getMfrom();
- AVMDAOs.Instance().fMergeLinkDAO.delete(mlink);
+ mergedFrom = AVMDAOs.Instance().fAVMNodeDAO.getByID(mlEntity.getMergeFromNodeId());
+ AVMDAOs.Instance().newAVMNodeLinksDAO.deleteMergeLink(mlEntity.getMergeFromNodeId(), mlEntity.getMergeToNodeId());
}
// Get all the nodes that have this node as ancestor.
- List links = AVMDAOs.Instance().fHistoryLinkDAO.getByAncestor(node);
- for (HistoryLink link : links)
+ List hlEntities = AVMDAOs.Instance().newAVMNodeLinksDAO.getHistoryLinksByAncestor(node.getId());
+ for (AVMHistoryLinkEntity link : hlEntities)
{
- AVMNode desc = link.getDescendent();
- desc.setAncestor(ancestor);
- if (desc.getMergedFrom() == null)
+ AVMNode desc = AVMDAOs.Instance().fAVMNodeDAO.getByID(link.getDescendentNodeId());
+ if (desc != null)
{
- desc.setMergedFrom(mergedFrom);
+ desc.setAncestor(ancestor);
+ if (desc.getMergedFrom() == null)
+ {
+ desc.setMergedFrom(mergedFrom);
+ }
}
- AVMDAOs.Instance().fHistoryLinkDAO.delete(link);
+ AVMDAOs.Instance().newAVMNodeLinksDAO.deleteHistoryLink(link.getAncestorNodeId(), link.getDescendentNodeId());
}
// Get all the nodes that have this node as mergedFrom
- List mlinks = AVMDAOs.Instance().fMergeLinkDAO.getByFrom(node);
- for (MergeLink link : mlinks)
+ List mlEntities = AVMDAOs.Instance().newAVMNodeLinksDAO.getMergeLinksByFrom(node.getId());
+ for (AVMMergeLinkEntity link : mlEntities)
{
- link.getMto().setMergedFrom(ancestor);
- AVMDAOs.Instance().fMergeLinkDAO.delete(link);
+ AVMNode mto = AVMDAOs.Instance().fAVMNodeDAO.getByID(link.getMergeToNodeId());
+ if (mto != null)
+ {
+ mto.setMergedFrom(ancestor);
+ }
+ AVMDAOs.Instance().newAVMNodeLinksDAO.deleteMergeLink(link.getMergeFromNodeId(), link.getMergeToNodeId());
}
// Get rid of all properties belonging to this node.
@@ -334,6 +390,11 @@ public class OrphanReaper
}
// Finally, delete it
AVMDAOs.Instance().fAVMNodeDAO.delete(node);
+
+ if (fgLogger.isTraceEnabled())
+ {
+ fgLogger.trace("Deleted Node ["+node.getId()+"]");
+ }
}
return null;
}
diff --git a/source/java/org/alfresco/repo/avm/PurgeTestP.java b/source/java/org/alfresco/repo/avm/PurgeTestP.java
index 15317440e4..473bab94c2 100644
--- a/source/java/org/alfresco/repo/avm/PurgeTestP.java
+++ b/source/java/org/alfresco/repo/avm/PurgeTestP.java
@@ -20,6 +20,8 @@ package org.alfresco.repo.avm;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.repo.avm.util.BulkLoader;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
/**
* Test the purge thread.
@@ -27,6 +29,46 @@ import org.alfresco.repo.avm.util.BulkLoader;
*/
public class PurgeTestP extends AVMServiceTestBase
{
+ private static Log logger = LogFactory.getLog(PurgeTestP.class);
+
+ public void testSetup()
+ {
+ runOrphanReaper();
+ }
+
+ public void testRemoveNodes() throws Throwable
+ {
+ try
+ {
+ logger.info("testRemoveNodes");
+
+ runOrphanReaper();
+
+ int fileCount = 10;
+
+ logger.info("Create "+fileCount+" files ...");
+
+ for (int i = 1; i <= fileCount; i++)
+ {
+ fService.createFile("main:/", "file"+i);
+ }
+
+ logger.info("Remove "+fileCount+" files ...");
+
+ for (int i = 1; i <= fileCount; i++)
+ {
+ fService.removeNode("main:/", "file"+i);
+ }
+
+ runOrphanReaper();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace(System.err);
+ throw e;
+ }
+ }
+
/**
* Test purging a version.
*/
@@ -34,6 +76,10 @@ public class PurgeTestP extends AVMServiceTestBase
{
try
{
+ logger.info("testPurgeVersion");
+
+ runOrphanReaper();
+
setupBasicTree();
BulkLoader loader = new BulkLoader();
loader.setAvmService(fService);
@@ -44,9 +90,9 @@ public class PurgeTestP extends AVMServiceTestBase
loader.recursiveLoad("source/java/org/alfresco/repo/avm", "main:/");
- System.err.println("Load time: " + (System.currentTimeMillis() - start) + "ms");
+ logger.info("Load time: " + (System.currentTimeMillis() - start) + "ms");
fService.createSnapshot("main", null, null);
- System.err.println("Load time + snapshot: " + (System.currentTimeMillis() - start) + "ms");
+ logger.info("Load time + snapshot: " + (System.currentTimeMillis() - start) + "ms");
fService.purgeVersion(2, "main");
runOrphanReaper();
@@ -65,6 +111,10 @@ public class PurgeTestP extends AVMServiceTestBase
{
try
{
+ logger.info("testPurgeOlderVersion");
+
+ runOrphanReaper();
+
setupBasicTree();
BulkLoader loader = new BulkLoader();
loader.setAvmService(fService);
@@ -75,9 +125,9 @@ public class PurgeTestP extends AVMServiceTestBase
loader.recursiveLoad("source/java/org/alfresco/repo/avm", "main:/");
- System.err.println("Load time: " + (System.currentTimeMillis() - start) + "ms");
+ logger.info("Load time: " + (System.currentTimeMillis() - start) + "ms");
fService.createSnapshot("main", null, null);
- System.err.println("Load time + snapshot: " + (System.currentTimeMillis() - start) + "ms");
+ logger.info("Load time + snapshot: " + (System.currentTimeMillis() - start) + "ms");
//fService.removeNode("main:/source/java/org/alfresco", "repo");
@@ -103,7 +153,12 @@ public class PurgeTestP extends AVMServiceTestBase
{
try
{
+ logger.info("testPurgeStore");
+
+ runOrphanReaper();
+
setupBasicTree();
+
BulkLoader loader = new BulkLoader();
loader.setAvmService(fService);
long start = System.currentTimeMillis();
@@ -113,9 +168,9 @@ public class PurgeTestP extends AVMServiceTestBase
loader.recursiveLoad("source/java/org/alfresco/repo/avm", "main:/");
- System.err.println("Load time: " + (System.currentTimeMillis() - start) + "ms");
+ logger.info("Load time: " + (System.currentTimeMillis() - start) + "ms");
fService.createSnapshot("main", null, null);
- System.err.println("Load time + snapshot: " + (System.currentTimeMillis() - start) + "ms");
+ logger.info("Load time + snapshot: " + (System.currentTimeMillis() - start) + "ms");
//fService.createLayeredDirectory("main:/source", "main:/", "layer");
@@ -125,8 +180,8 @@ public class PurgeTestP extends AVMServiceTestBase
fService.removeNode("main:/layer", "actions");
fService.createFile("main:/layer", "goofy").close();
-
fService.createSnapshot("main", null, null);
+
fService.purgeStore("main");
runOrphanReaper();
@@ -140,7 +195,10 @@ public class PurgeTestP extends AVMServiceTestBase
private void runOrphanReaper()
{
+ logger.info("Reaper started");
+
fReaper.activate();
+ fReaper.execute();
final int maxCycles = 100;
@@ -149,12 +207,13 @@ public class PurgeTestP extends AVMServiceTestBase
{
try
{
- System.out.print(".");
+ //System.out.print(".");
Thread.sleep(2000);
}
catch (InterruptedException e)
{
// Do nothing.
+ logger.warn("OrphanReaper was interrupted - do nothing: "+e);
}
cycles++;
@@ -165,6 +224,6 @@ public class PurgeTestP extends AVMServiceTestBase
throw new AlfrescoRuntimeException("Orphan reaper still active - failed to clean orphans in "+cycles+" cycles (max "+maxCycles+")");
}
- System.out.println("\nReaper finished (in "+cycles+" cycles)");
+ logger.info("Reaper finished (in "+cycles+" cycles)");
}
}
diff --git a/source/java/org/alfresco/repo/avm/ibatis/AVMNodeDAOIbatis.java b/source/java/org/alfresco/repo/avm/ibatis/AVMNodeDAOIbatis.java
index 4d4ffe57c6..c715ddb02a 100644
--- a/source/java/org/alfresco/repo/avm/ibatis/AVMNodeDAOIbatis.java
+++ b/source/java/org/alfresco/repo/avm/ibatis/AVMNodeDAOIbatis.java
@@ -34,19 +34,19 @@ import org.alfresco.repo.avm.BasicAttributesImpl;
import org.alfresco.repo.avm.DeletedNode;
import org.alfresco.repo.avm.DeletedNodeImpl;
import org.alfresco.repo.avm.DirectoryNode;
-import org.alfresco.repo.avm.HistoryLink;
import org.alfresco.repo.avm.Layered;
import org.alfresco.repo.avm.LayeredDirectoryNode;
import org.alfresco.repo.avm.LayeredDirectoryNodeImpl;
import org.alfresco.repo.avm.LayeredFileNode;
import org.alfresco.repo.avm.LayeredFileNodeImpl;
-import org.alfresco.repo.avm.MergeLink;
import org.alfresco.repo.avm.PlainDirectoryNode;
import org.alfresco.repo.avm.PlainDirectoryNodeImpl;
import org.alfresco.repo.avm.PlainFileNode;
import org.alfresco.repo.avm.PlainFileNodeImpl;
import org.alfresco.repo.domain.DbAccessControlList;
import org.alfresco.repo.domain.PropertyValue;
+import org.alfresco.repo.domain.avm.AVMHistoryLinkEntity;
+import org.alfresco.repo.domain.avm.AVMMergeLinkEntity;
import org.alfresco.repo.domain.avm.AVMNodeEntity;
import org.alfresco.repo.domain.avm.AVMVersionRootEntity;
import org.alfresco.service.namespace.QName;
@@ -208,12 +208,12 @@ class AVMNodeDAOIbatis implements AVMNodeDAO
*/
public AVMNode getAncestor(AVMNode descendent)
{
- HistoryLink hl = AVMDAOs.Instance().fHistoryLinkDAO.getByDescendent(descendent);
- if (hl == null)
+ AVMHistoryLinkEntity hlEntity = AVMDAOs.Instance().newAVMNodeLinksDAO.getHistoryLinkByDescendent(descendent.getId());
+ if (hlEntity == null)
{
return null;
}
- return hl.getAncestor();
+ return AVMDAOs.Instance().fAVMNodeDAO.getByID(hlEntity.getAncestorNodeId());
}
/* (non-Javadoc)
@@ -221,12 +221,12 @@ class AVMNodeDAOIbatis implements AVMNodeDAO
*/
public AVMNode getMergedFrom(AVMNode mTo)
{
- MergeLink ml = AVMDAOs.Instance().fMergeLinkDAO.getByTo(mTo);
- if (ml == null)
+ AVMMergeLinkEntity mlEntity = AVMDAOs.Instance().newAVMNodeLinksDAO.getMergeLinkByTo(mTo.getId());
+ if (mlEntity == null)
{
return null;
}
- return ml.getMfrom();
+ return AVMDAOs.Instance().fAVMNodeDAO.getByID(mlEntity.getMergeFromNodeId());
}
/* (non-Javadoc)
diff --git a/source/java/org/alfresco/repo/avm/ibatis/HistoryLinkDAOIbatis.java b/source/java/org/alfresco/repo/avm/ibatis/HistoryLinkDAOIbatis.java
deleted file mode 100644
index 91181eb66b..0000000000
--- a/source/java/org/alfresco/repo/avm/ibatis/HistoryLinkDAOIbatis.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (C) 2005-2010 Alfresco Software Limited.
- *
- * This file is part of Alfresco
- *
- * Alfresco is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Alfresco is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with Alfresco. If not, see . */
-
-package org.alfresco.repo.avm.ibatis;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.alfresco.repo.avm.AVMDAOs;
-import org.alfresco.repo.avm.AVMNode;
-import org.alfresco.repo.avm.HistoryLink;
-import org.alfresco.repo.avm.HistoryLinkDAO;
-import org.alfresco.repo.avm.HistoryLinkImpl;
-import org.alfresco.repo.domain.avm.AVMHistoryLinkEntity;
-
-/**
- * iBATIS DAO wrapper for HistoryLink
- *
- * @author janv
- */
-class HistoryLinkDAOIbatis implements HistoryLinkDAO
-{
- /* (non-Javadoc)
- * @see org.alfresco.repo.avm.HistoryLinkDAO#save(org.alfresco.repo.avm.HistoryLink)
- */
- public void save(HistoryLink link)
- {
- AVMDAOs.Instance().newAVMNodeLinksDAO.createHistoryLink(link.getAncestor().getId(), link.getDescendent().getId());
- }
-
- /* (non-Javadoc)
- * @see org.alfresco.repo.avm.HistoryLinkDAO#getByDescendent(org.alfresco.repo.avm.AVMNode)
- */
- public HistoryLink getByDescendent(AVMNode descendent)
- {
- AVMHistoryLinkEntity hlEntity = AVMDAOs.Instance().newAVMNodeLinksDAO.getHistoryLinkByDescendent(descendent.getId());
-
- if (hlEntity == null)
- {
- return null;
- }
-
- AVMNode ancestor = AVMDAOs.Instance().fAVMNodeDAO.getByID(hlEntity.getAncestorNodeId());
-
- HistoryLink hl = new HistoryLinkImpl();
- hl.setAncestor(ancestor);
- hl.setDescendent(descendent);
- return hl;
- }
-
- /* (non-Javadoc)
- * @see org.alfresco.repo.avm.HistoryLinkDAO#getByAncestor(org.alfresco.repo.avm.AVMNode)
- */
- public List getByAncestor(AVMNode ancestor)
- {
- List hlEntities = AVMDAOs.Instance().newAVMNodeLinksDAO.getHistoryLinksByAncestor(ancestor.getId());
-
- List hls = new ArrayList(hlEntities.size());
- for (AVMHistoryLinkEntity hlEntity : hlEntities)
- {
- AVMNode descendent = AVMDAOs.Instance().fAVMNodeDAO.getByID(hlEntity.getDescendentNodeId());
-
- HistoryLink hl = new HistoryLinkImpl();
- hl.setAncestor(ancestor);
- hl.setDescendent(descendent);
-
- hls.add(hl);
- }
-
- return hls;
- }
-
- /* (non-Javadoc)
- * @see org.alfresco.repo.avm.HistoryLinkDAO#delete(org.alfresco.repo.avm.HistoryLink)
- */
- public void delete(HistoryLink link)
- {
- AVMDAOs.Instance().newAVMNodeLinksDAO.deleteHistoryLink(link.getAncestor().getId(), link.getDescendent().getId());
- }
-}
diff --git a/source/java/org/alfresco/repo/avm/ibatis/MergeLinkDAOIbatis.java b/source/java/org/alfresco/repo/avm/ibatis/MergeLinkDAOIbatis.java
deleted file mode 100644
index 3a3d7293f7..0000000000
--- a/source/java/org/alfresco/repo/avm/ibatis/MergeLinkDAOIbatis.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (C) 2005-2010 Alfresco Software Limited.
- *
- * This file is part of Alfresco
- *
- * Alfresco is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Alfresco is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with Alfresco. If not, see . */
-
-package org.alfresco.repo.avm.ibatis;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.alfresco.repo.avm.AVMDAOs;
-import org.alfresco.repo.avm.AVMNode;
-import org.alfresco.repo.avm.MergeLink;
-import org.alfresco.repo.avm.MergeLinkDAO;
-import org.alfresco.repo.avm.MergeLinkImpl;
-import org.alfresco.repo.domain.avm.AVMMergeLinkEntity;
-
-/**
- * iBATIS DAO wrapper for MergeLink
- *
- * @author janv
- */
-class MergeLinkDAOIbatis implements MergeLinkDAO
-{
- /* (non-Javadoc)
- * @see org.alfresco.repo.avm.MergeLinkDAO#save(org.alfresco.repo.avm.MergeLink)
- */
- public void save(MergeLink link)
- {
- AVMDAOs.Instance().newAVMNodeLinksDAO.createMergeLink(link.getMfrom().getId(), link.getMto().getId());
- }
-
- /* (non-Javadoc)
- * @see org.alfresco.repo.avm.MergeLinkDAO#getByTo(org.alfresco.repo.avm.AVMNode)
- */
- public MergeLink getByTo(AVMNode to)
- {
- AVMMergeLinkEntity mlEntity = AVMDAOs.Instance().newAVMNodeLinksDAO.getMergeLinkByTo(to.getId());
-
- if (mlEntity == null)
- {
- return null;
- }
-
- AVMNode from = AVMDAOs.Instance().fAVMNodeDAO.getByID(mlEntity.getMergeFromNodeId());
-
- MergeLink ml = new MergeLinkImpl();
- ml.setMfrom(from);
- ml.setMto(to);
- return ml;
- }
-
- /* (non-Javadoc)
- * @see org.alfresco.repo.avm.MergeLinkDAO#getByFrom(org.alfresco.repo.avm.AVMNode)
- */
- public List getByFrom(AVMNode from)
- {
- List mlEntities = AVMDAOs.Instance().newAVMNodeLinksDAO.getMergeLinksByFrom(from.getId());
-
- List mls = new ArrayList(mlEntities.size());
- for (AVMMergeLinkEntity mlEntity : mlEntities)
- {
- AVMNode to = AVMDAOs.Instance().fAVMNodeDAO.getByID(mlEntity.getMergeToNodeId());
-
- MergeLink ml = new MergeLinkImpl();
- ml.setMfrom(from);
- ml.setMto(to);
-
- mls.add(ml);
- }
-
- return mls;
- }
-
- /* (non-Javadoc)
- * @see org.alfresco.repo.avm.MergeLinkDAO#delete(org.alfresco.repo.avm.MergeLink)
- */
- public void delete(MergeLink link)
- {
- AVMDAOs.Instance().newAVMNodeLinksDAO.deleteMergeLink(link.getMfrom().getId(), link.getMto().getId());
- }
-}
diff --git a/source/java/org/alfresco/repo/content/metadata/AbstractMappingMetadataExtracter.java b/source/java/org/alfresco/repo/content/metadata/AbstractMappingMetadataExtracter.java
index 118c94132f..9e8c7a71b9 100644
--- a/source/java/org/alfresco/repo/content/metadata/AbstractMappingMetadataExtracter.java
+++ b/source/java/org/alfresco/repo/content/metadata/AbstractMappingMetadataExtracter.java
@@ -856,6 +856,11 @@ abstract public class AbstractMappingMetadataExtracter implements MetadataExtrac
*/
protected Date makeDate(String dateStr)
{
+ if (dateStr == null || dateStr.length() == 0)
+ {
+ return null;
+ }
+
Date date = null;
try
{
@@ -885,9 +890,8 @@ abstract public class AbstractMappingMetadataExtracter implements MetadataExtrac
}
/**
- * Adds a value to the map if it is non-trivial. A value is trivial if
+ * Adds a value to the map, conserving null values. Values are converted to null if:
*
- *
it is null
*
it is an empty string value after trimming
*
it is an empty collection
*
it is an empty array
@@ -907,14 +911,14 @@ abstract public class AbstractMappingMetadataExtracter implements MetadataExtrac
{
if (value == null)
{
- return false;
+ // Just keep this
}
- if (value instanceof String)
+ else if (value instanceof String)
{
String valueStr = ((String) value).trim();
if (valueStr.length() == 0)
{
- return false;
+ value = null;
}
else
{
@@ -927,14 +931,14 @@ abstract public class AbstractMappingMetadataExtracter implements MetadataExtrac
Collection valueCollection = (Collection) value;
if (valueCollection.isEmpty())
{
- return false;
+ value = null;
}
}
else if (value.getClass().isArray())
{
if (Array.getLength(value) == 0)
{
- return false;
+ value = null;
}
}
// It passed all the tests
diff --git a/source/java/org/alfresco/repo/content/metadata/MetadataExtracter.java b/source/java/org/alfresco/repo/content/metadata/MetadataExtracter.java
index d72a2fefff..6c288d1e0d 100644
--- a/source/java/org/alfresco/repo/content/metadata/MetadataExtracter.java
+++ b/source/java/org/alfresco/repo/content/metadata/MetadataExtracter.java
@@ -52,6 +52,7 @@ public interface MetadataExtracter extends ContentWorker
*
*
the extracted property is not null
*
+ * null extracted values are return in the 'modified' map.
*/
EAGER
{
@@ -64,11 +65,10 @@ public interface MetadataExtracter extends ContentWorker
QName propertyQName = entry.getKey();
Serializable extractedValue = entry.getValue();
// Ignore null extracted value
- if (extractedValue == null)
+ if (extractedValue != null)
{
- continue;
+ targetProperties.put(propertyQName, extractedValue);
}
- targetProperties.put(propertyQName, extractedValue);
modifiedProperties.put(propertyQName, extractedValue);
}
return modifiedProperties;
@@ -82,6 +82,7 @@ public interface MetadataExtracter extends ContentWorker
*
the target value is null
*
the string representation of the target value is an empty string
*
+ * null extracted values are return in the 'modified' map.
*/
PRAGMATIC
{
@@ -99,6 +100,7 @@ public interface MetadataExtracter extends ContentWorker
// Ignore null extracted value
if (extractedValue == null)
{
+ modifiedProperties.put(propertyQName, extractedValue);
continue;
}
// Handle the shortcut cases where the target value is missing or null
@@ -148,6 +150,7 @@ public interface MetadataExtracter extends ContentWorker
*
the extracted property is not null
*
there is no target key for the property
*
+ * null extracted values are return in the 'modified' map.
*/
CAUTIOUS
{
@@ -162,6 +165,7 @@ public interface MetadataExtracter extends ContentWorker
// Ignore null extracted value
if (extractedValue == null)
{
+ modifiedProperties.put(propertyQName, extractedValue);
continue;
}
// Is the key present in the target values
@@ -181,8 +185,8 @@ public interface MetadataExtracter extends ContentWorker
* Apply the overwrite policy for the extracted properties.
*
* @return
- * Returns a map of all properties that were applied to the target map. If the result is
- * an empty map, then the target map remains unchanged.
+ * Returns a map of all properties that were applied to the target map
+ * as well as any null values that weren't applied but were present.
*/
public Map applyProperties(Map extractedProperties, Map targetProperties)
{
diff --git a/source/java/org/alfresco/repo/policy/BehaviourFilter.java b/source/java/org/alfresco/repo/policy/BehaviourFilter.java
index 2982884af4..bac0cc49ef 100644
--- a/source/java/org/alfresco/repo/policy/BehaviourFilter.java
+++ b/source/java/org/alfresco/repo/policy/BehaviourFilter.java
@@ -24,14 +24,16 @@ import org.alfresco.service.namespace.QName;
/**
* Contract disabling and enabling policy behaviours.
*
+ * @See org.alfresco.repo.policy.PolicyComponent
+ *
* @author David Caruana
*/
public interface BehaviourFilter
{
/**
- * Disable behaviour for all nodes.
+ * Disable behaviour for a type or aspect for all nodes.
*
- * The change applies ONLY to the current trasaction.
+ * The change applies ONLY to the current transaction.
*
* @param className the type/aspect behaviour to disable
* @return true => already disabled
@@ -41,7 +43,7 @@ public interface BehaviourFilter
/**
* Disable behaviour for specific node
*
- * The change applies ONLY to the current trasaction.
+ * The change applies ONLY to the current transaction.
*
* @param nodeRef the node to disable for
* @param className the type/aspect behaviour to disable
@@ -52,7 +54,7 @@ public interface BehaviourFilter
/**
* Enable behaviour for all nodes
*
- * The change applies ONLY to the current trasaction.
+ * The change applies ONLY to the current transaction.
*
* @param className the type/aspect behaviour to enable
*/
@@ -61,7 +63,7 @@ public interface BehaviourFilter
/**
* Enable behaviour for specific node
*
- * The change applies ONLY to the current trasaction.
+ * The change applies ONLY to the current transaction.
*
* @param nodeRef the node to enable for
* @param className the type/aspect behaviour to enable
@@ -71,24 +73,37 @@ public interface BehaviourFilter
/**
* Enable all behaviours for specific node
*
- * The change applies ONLY to the current trasaction.
+ * The change applies ONLY to the current transaction.
*
* @param nodeRef the node to enable for
*/
public void enableBehaviours(NodeRef nodeRef);
/**
- * Enable all behaviours i.e. undo all disable calls - both at the
+ * Disable all behaviours. Once this method is called the node and class level filters, enableBehaviours and disableBehaviours
+ * methods have no effect, every behaviour is disabled.
+ * EnableAllBehaviours reverses the result of calling this method.
+ *
+ * Calling this method may result in nodes existing in your repository that do not conform to your policies.
+ *
+ *
+ * The change applies ONLY to the current transaction.
+ * @see #enableAllBehaviours
+ */
+ public void disableAllBehaviours();
+
+ /**
+ * Enable all behaviours i.e. undo all disable calls - at the global,
* node and class level.
*
- * The change applies ONLY to the current trasaction.
+ * The change applies ONLY to the current transaction.
*/
public void enableAllBehaviours();
/**
* Determine if behaviour is enabled across all nodes.
*
- * The change applies ONLY to the current trasaction.
+ * The change applies ONLY to the current transaction.
*
* @param className the behaviour to test for
* @return true => behaviour is enabled
@@ -102,7 +117,7 @@ public interface BehaviourFilter
* a) the behaviour is not disabled across all nodes
* b) the behaviour is not disabled specifically for the provided node
*
- * The change applies ONLY to the current trasaction.
+ * The change applies ONLY to the current transaction.
*
* @param nodeRef the node to test for
* @param className the behaviour to test for
@@ -113,7 +128,7 @@ public interface BehaviourFilter
/**
* Determine if any behaviours have been disabled?
*
- * The change applies ONLY to the current trasaction.
+ * The change applies ONLY to the current transaction.
*
* @return true => behaviours have been filtered
*/
diff --git a/source/java/org/alfresco/repo/policy/BehaviourFilterImpl.java b/source/java/org/alfresco/repo/policy/BehaviourFilterImpl.java
index deaa220e1e..aad6c64612 100644
--- a/source/java/org/alfresco/repo/policy/BehaviourFilterImpl.java
+++ b/source/java/org/alfresco/repo/policy/BehaviourFilterImpl.java
@@ -37,6 +37,7 @@ import org.alfresco.service.namespace.QName;
*/
public class BehaviourFilterImpl implements BehaviourFilter
{
+ private static final String KEY_GLOBAL_FILTER = "BehaviourFilterImpl.gloalFilter";
private static final String KEY_CLASS_FILTER = "BehaviourFilterImpl.classFilter";
private static final String KEY_NODEREF_FILTER = "BehaviourFilterImpl.nodeRefFilter";
@@ -122,14 +123,26 @@ public class BehaviourFilterImpl implements BehaviourFilter
nodeRefFilters.remove(nodeRef);
}
+ public void disableAllBehaviours()
+ {
+ TransactionalResourceHelper.setBoolean(KEY_GLOBAL_FILTER);
+ }
+
public void enableAllBehaviours()
{
+ TransactionalResourceHelper.resetBoolean(KEY_GLOBAL_FILTER);
+
Map> filters = TransactionalResourceHelper.getMap(KEY_NODEREF_FILTER);
filters.clear();
}
public boolean isEnabled(NodeRef nodeRef, QName className)
{
+ if(TransactionalResourceHelper.testBoolean(KEY_GLOBAL_FILTER))
+ {
+ return false;
+ }
+
// check global filters
if (!isEnabled(className))
{
@@ -163,6 +176,11 @@ public class BehaviourFilterImpl implements BehaviourFilter
public boolean isEnabled(QName className)
{
+ if(TransactionalResourceHelper.testBoolean(KEY_GLOBAL_FILTER))
+ {
+ return false;
+ }
+
// check global class filters
List classFilters = TransactionalResourceHelper.getList(KEY_CLASS_FILTER);
boolean filtered = classFilters.contains(className);
@@ -186,6 +204,8 @@ public class BehaviourFilterImpl implements BehaviourFilter
{
List classFilters = TransactionalResourceHelper.getList(KEY_CLASS_FILTER);
Map> nodeRefFilters = TransactionalResourceHelper.getMap(KEY_NODEREF_FILTER);
- return (!classFilters.isEmpty()) || (!nodeRefFilters.isEmpty());
+ boolean globalFlag = TransactionalResourceHelper.testBoolean(KEY_GLOBAL_FILTER);
+ return ((!classFilters.isEmpty()) || (!nodeRefFilters.isEmpty()) || globalFlag);
}
+
}
diff --git a/source/java/org/alfresco/repo/policy/PolicyComponent.java b/source/java/org/alfresco/repo/policy/PolicyComponent.java
index fe04cc1029..7acd37cb75 100644
--- a/source/java/org/alfresco/repo/policy/PolicyComponent.java
+++ b/source/java/org/alfresco/repo/policy/PolicyComponent.java
@@ -38,6 +38,9 @@ import org.alfresco.service.namespace.QName;
* this case, the behaviour is not validated (i.e. checked to determine if it
* supports the policy interface) until the Policy is registered. Otherwise,
* the behaviour is validated at bind-time.
+ *
+ * @see org.alfresco.repo.policy.BehaviourFilter
+ *
*
* @author David Caruana
*
diff --git a/source/java/org/alfresco/repo/rule/RulesAspect.java b/source/java/org/alfresco/repo/rule/RulesAspect.java
index c2822ebb33..88cc458b76 100644
--- a/source/java/org/alfresco/repo/rule/RulesAspect.java
+++ b/source/java/org/alfresco/repo/rule/RulesAspect.java
@@ -35,6 +35,8 @@ import org.alfresco.service.cmr.rule.RuleService;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.PropertyCheck;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
/**
* Class containing behaviour for the rules aspect
@@ -50,6 +52,8 @@ public class RulesAspect implements
private RuleService ruleService;
private NodeService nodeService;
+ private static Log logger = LogFactory.getLog(RulesAspect.class);
+
public void setPolicyComponent(PolicyComponent policyComponent)
{
this.policyComponent = policyComponent;
@@ -85,7 +89,6 @@ public class RulesAspect implements
QName.createQName(NamespaceService.ALFRESCO_URI, "onCopyComplete"),
RuleModel.ASPECT_RULES,
new JavaBehaviour(this, "onCopyComplete"));
-
this.policyComponent.bindClassBehaviour(
QName.createQName(NamespaceService.ALFRESCO_URI, "onAddAspect"),
RuleModel.ASPECT_RULES,
@@ -103,6 +106,10 @@ public class RulesAspect implements
int count = this.nodeService.getChildAssocs(nodeRef, RuleModel.ASSOC_RULE_FOLDER, RuleModel.ASSOC_RULE_FOLDER).size();
if (count == 0)
{
+ if(logger.isDebugEnabled())
+ {
+ logger.debug("rules folder does not exist: create new rules folder for: " + nodeRef);
+ }
this.nodeService.createNode(
nodeRef,
RuleModel.ASSOC_RULE_FOLDER,
diff --git a/source/java/org/alfresco/repo/security/authentication/ldap/LDAPInitialDirContextFactoryImpl.java b/source/java/org/alfresco/repo/security/authentication/ldap/LDAPInitialDirContextFactoryImpl.java
index 969b1bedd1..d1d586d9fa 100644
--- a/source/java/org/alfresco/repo/security/authentication/ldap/LDAPInitialDirContextFactoryImpl.java
+++ b/source/java/org/alfresco/repo/security/authentication/ldap/LDAPInitialDirContextFactoryImpl.java
@@ -49,7 +49,8 @@ public class LDAPInitialDirContextFactoryImpl implements LDAPInitialDirContextFa
{
private static final Log logger = LogFactory.getLog(LDAPInitialDirContextFactoryImpl.class);
- private Map initialDirContextEnvironment = Collections. emptyMap();
+ private Map defaultEnvironment = Collections. emptyMap();
+ private Map authenticatedEnvironment = Collections. emptyMap();
static
{
@@ -63,13 +64,18 @@ public class LDAPInitialDirContextFactoryImpl implements LDAPInitialDirContextFa
public void setInitialDirContextEnvironment(Map initialDirContextEnvironment)
{
- this.initialDirContextEnvironment = initialDirContextEnvironment;
+ this.authenticatedEnvironment = initialDirContextEnvironment;
}
public Map getInitialDirContextEnvironment()
{
- return initialDirContextEnvironment;
+ return authenticatedEnvironment;
}
+
+ public void setDefaultIntialDirContextEnvironment(Map defaultEnvironment)
+ {
+ this.defaultEnvironment = defaultEnvironment;
+ }
public InitialDirContext getDefaultIntialDirContext() throws AuthenticationException
{
@@ -78,10 +84,8 @@ public class LDAPInitialDirContextFactoryImpl implements LDAPInitialDirContextFa
public InitialDirContext getDefaultIntialDirContext(int pageSize) throws AuthenticationException
{
- Hashtable env = new Hashtable(initialDirContextEnvironment.size());
- env.putAll(initialDirContextEnvironment);
- env.put("javax.security.auth.useSubjectCredsOnly", "false");
- env.put("com.sun.jndi.ldap.connect.pool", "true"); // Pool the default connection
+ Hashtable env = new Hashtable(defaultEnvironment.size());
+ env.putAll(defaultEnvironment);
return buildInitialDirContext(env, pageSize);
}
@@ -185,8 +189,8 @@ public class LDAPInitialDirContextFactoryImpl implements LDAPInitialDirContextFa
throw new AuthenticationException("Empty credentials provided.");
}
- Hashtable env = new Hashtable(initialDirContextEnvironment.size());
- env.putAll(initialDirContextEnvironment);
+ Hashtable env = new Hashtable(authenticatedEnvironment.size());
+ env.putAll(authenticatedEnvironment);
env.put(Context.SECURITY_PRINCIPAL, principal);
env.put(Context.SECURITY_CREDENTIALS, credentials);
@@ -284,8 +288,8 @@ public class LDAPInitialDirContextFactoryImpl implements LDAPInitialDirContextFa
{
// Check Anonymous bind
- Hashtable env = new Hashtable(initialDirContextEnvironment.size());
- env.putAll(initialDirContextEnvironment);
+ Hashtable env = new Hashtable(authenticatedEnvironment.size());
+ env.putAll(authenticatedEnvironment);
env.remove(Context.SECURITY_PRINCIPAL);
env.remove(Context.SECURITY_CREDENTIALS);
try
@@ -310,8 +314,8 @@ public class LDAPInitialDirContextFactoryImpl implements LDAPInitialDirContextFa
// Simple DN and password
- env = new Hashtable(initialDirContextEnvironment.size());
- env.putAll(initialDirContextEnvironment);
+ env = new Hashtable(authenticatedEnvironment.size());
+ env.putAll(authenticatedEnvironment);
env.put(Context.SECURITY_PRINCIPAL, "daftAsABrush");
env.put(Context.SECURITY_CREDENTIALS, "daftAsABrush");
try
@@ -339,8 +343,8 @@ public class LDAPInitialDirContextFactoryImpl implements LDAPInitialDirContextFa
// DN and password
- env = new Hashtable(initialDirContextEnvironment.size());
- env.putAll(initialDirContextEnvironment);
+ env = new Hashtable(authenticatedEnvironment.size());
+ env.putAll(authenticatedEnvironment);
env.put(Context.SECURITY_PRINCIPAL, "cn=daftAsABrush,dc=woof");
env.put(Context.SECURITY_CREDENTIALS, "daftAsABrush");
try
@@ -368,14 +372,14 @@ public class LDAPInitialDirContextFactoryImpl implements LDAPInitialDirContextFa
// Check more if we have a real principal we expect to work
- env = new Hashtable(initialDirContextEnvironment.size());
- env.putAll(initialDirContextEnvironment);
+ env = new Hashtable(defaultEnvironment.size());
+ env.putAll(defaultEnvironment);
if (env.get(Context.SECURITY_PRINCIPAL) != null)
{
// Correct principal invalid password
- env = new Hashtable(initialDirContextEnvironment.size());
- env.putAll(initialDirContextEnvironment);
+ env = new Hashtable(defaultEnvironment.size());
+ env.putAll(defaultEnvironment);
env.put(Context.SECURITY_CREDENTIALS, "sdasdasdasdasd123123123");
try
{
diff --git a/source/java/org/alfresco/repo/security/sync/ChainingUserRegistrySynchronizer.java b/source/java/org/alfresco/repo/security/sync/ChainingUserRegistrySynchronizer.java
index 5bf58bb9b4..21e566bf48 100644
--- a/source/java/org/alfresco/repo/security/sync/ChainingUserRegistrySynchronizer.java
+++ b/source/java/org/alfresco/repo/security/sync/ChainingUserRegistrySynchronizer.java
@@ -34,6 +34,9 @@ import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.batch.BatchProcessor;
@@ -58,6 +61,7 @@ import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.transaction.TransactionService;
import org.alfresco.util.PropertyMap;
+import org.alfresco.util.TraceableThreadFactory;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
@@ -103,8 +107,8 @@ public class ChainingUserRegistrySynchronizer extends AbstractLifecycleBean impl
private static final QName LOCK_QNAME = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI,
"ChainingUserRegistrySynchronizer");
- /** The maximum time this lock will be held for (1 day). */
- private static final long LOCK_TTL = 1000 * 60 * 60 * 24;
+ /** The time this lock will persist for in the database (now only 2 minutes but refreshed at regular intervals). */
+ private static final long LOCK_TTL = 1000 * 60 * 2;
/** The path in the attribute service below which we persist attributes. */
private static final String ROOT_ATTRIBUTE_PATH = ".ChainingUserRegistrySynchronizer";
@@ -315,7 +319,7 @@ public class ChainingUserRegistrySynchronizer extends AbstractLifecycleBean impl
* (non-Javadoc)
* @see org.alfresco.repo.security.sync.UserRegistrySynchronizer#synchronize(boolean, boolean, boolean)
*/
- public void synchronize(boolean forceUpdate, boolean allowDeletions, boolean splitTxns)
+ public void synchronize(boolean forceUpdate, boolean allowDeletions, final boolean splitTxns)
{
// Don't proceed with the sync if the repository is read only
if (this.transactionService.isReadOnly())
@@ -325,8 +329,15 @@ public class ChainingUserRegistrySynchronizer extends AbstractLifecycleBean impl
return;
}
+ // Create a background executor that will refresh our lock. This means we can request a lock with a relatively
+ // small persistence time and not worry about it lasting after server restarts. Note we use an independent
+ // executor because this is a compound operation that spans accross multiple batch processors.
String lockToken = null;
-
+ TraceableThreadFactory threadFactory = new TraceableThreadFactory();
+ threadFactory.setNamePrefix("ChainingUserRegistrySynchronizer lock refresh");
+ threadFactory.setThreadDaemon(true);
+ ScheduledExecutorService lockRefresher = new ScheduledThreadPoolExecutor(1, threadFactory);
+
// Let's ensure all exceptions get logged
try
{
@@ -351,7 +362,7 @@ public class ChainingUserRegistrySynchronizer extends AbstractLifecycleBean impl
else
{
// If this is a login-triggered sync, give it a few retries before giving up
- this.jobLockService.getTransactionalLock(ChainingUserRegistrySynchronizer.LOCK_QNAME,
+ lockToken = this.jobLockService.getLock(ChainingUserRegistrySynchronizer.LOCK_QNAME,
ChainingUserRegistrySynchronizer.LOCK_TTL, 3000, 10);
}
}
@@ -363,6 +374,27 @@ public class ChainingUserRegistrySynchronizer extends AbstractLifecycleBean impl
return;
}
+ // Schedule the lock refresh to run at regular intervals
+ final String token = lockToken;
+ lockRefresher.scheduleAtFixedRate(new Runnable()
+ {
+ public void run()
+ {
+ ChainingUserRegistrySynchronizer.this.transactionService.getRetryingTransactionHelper()
+ .doInTransaction(new RetryingTransactionCallback