diff --git a/config/alfresco/avm-services-context.xml b/config/alfresco/avm-services-context.xml
index 7770ef2da2..abb05145dc 100644
--- a/config/alfresco/avm-services-context.xml
+++ b/config/alfresco/avm-services-context.xml
@@ -228,13 +228,13 @@
-
-
-
-
-
-
-
+
+
+
+
+
+
+
@@ -250,6 +250,9 @@
workspace://SpacesStore
+
+
+
diff --git a/config/alfresco/dao/dao-context.xml b/config/alfresco/dao/dao-context.xml
index 5b0484b864..eb413b708b 100644
--- a/config/alfresco/dao/dao-context.xml
+++ b/config/alfresco/dao/dao-context.xml
@@ -158,6 +158,11 @@
+
+
+
+
+
diff --git a/config/alfresco/ibatis/org.hibernate.dialect.Dialect/avm-common-SqlMap.xml b/config/alfresco/ibatis/org.hibernate.dialect.Dialect/avm-common-SqlMap.xml
index 0118a39050..ccc8d0382b 100644
--- a/config/alfresco/ibatis/org.hibernate.dialect.Dialect/avm-common-SqlMap.xml
+++ b/config/alfresco/ibatis/org.hibernate.dialect.Dialect/avm-common-SqlMap.xml
@@ -218,6 +218,14 @@
+
+
+
+
+
+
+
+
@@ -1226,4 +1234,60 @@
class_type = 'layeredfile'
+
+
+ delete from
+ alf_prop_unique_ctx
+ where exists
+ (
+ select
+ *
+ from
+ alf_prop_value pv3
+ join alf_prop_string_value psv3 on (psv3.id = pv3.long_value),
+ alf_prop_link pl
+ left join alf_prop_value pkey on (pkey.id = pl.key_prop_id and pkey.persisted_type = 3)
+ left join alf_prop_string_value psvk on (psvk.id = pkey.long_value)
+ left join alf_prop_value pval on (pval.id = pl.value_prop_id and pval.persisted_type = 3)
+ left join alf_prop_string_value psvv on (psvv.id = pval.long_value)
+ where
+ value1_prop_id = ? and
+ value2_prop_id = ? and
+ value3_prop_id = pv3.id and
+ pv3.persisted_type = 3 and
+ psv3.string_value like ? and
+ prop1_id = pl.root_prop_id and
+ psvk.string_value = ? and
+ psvv.string_value = ?
+ )
+
+
+
+ delete from
+ alf_prop_unique_ctx
+ where exists
+ (
+ select
+ *
+ from
+ alf_prop_value pv3
+ join alf_prop_string_value psv3 on (psv3.id = pv3.long_value)
+ where
+ value1_prop_id = ? and
+ value2_prop_id = ? and
+ value3_prop_id = pv3.id and
+ pv3.persisted_type = 3 and
+ psv3.string_value like ?
+ )
+
+
\ No newline at end of file
diff --git a/source/java/org/alfresco/repo/avm/locking/AVMLockingServiceImpl.java b/source/java/org/alfresco/repo/avm/locking/AVMLockingServiceImpl.java
index aedbe52c93..837cc7aa77 100644
--- a/source/java/org/alfresco/repo/avm/locking/AVMLockingServiceImpl.java
+++ b/source/java/org/alfresco/repo/avm/locking/AVMLockingServiceImpl.java
@@ -19,19 +19,16 @@
package org.alfresco.repo.avm.locking;
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.alfresco.model.WCMAppModel;
+import org.alfresco.repo.domain.avm.AVMLockDAO;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.service.cmr.attributes.AttributeService;
import org.alfresco.service.cmr.attributes.DuplicateAttributeException;
-import org.alfresco.service.cmr.attributes.AttributeService.AttributeQueryCallback;
import org.alfresco.service.cmr.avm.AVMBadArgumentException;
import org.alfresco.service.cmr.avm.locking.AVMLockingException;
import org.alfresco.service.cmr.avm.locking.AVMLockingService;
@@ -44,7 +41,6 @@ import org.alfresco.service.cmr.security.AuthorityService;
import org.alfresco.service.cmr.security.AuthorityType;
import org.alfresco.service.cmr.security.PersonService;
import org.alfresco.service.namespace.NamespaceService;
-import org.alfresco.util.EqualsHelper;
import org.alfresco.util.ParameterCheck;
import org.alfresco.wcm.util.WCMUtil;
import org.apache.commons.logging.Log;
@@ -70,6 +66,8 @@ public class AVMLockingServiceImpl implements AVMLockingService
private AuthorityService authorityService;
private PersonService personService;
private NodeService nodeService;
+
+ private AVMLockDAO avmLockDAO;
/**
* @param webProjectStore The webProjectStore to set
@@ -102,17 +100,22 @@ public class AVMLockingServiceImpl implements AVMLockingService
{
this.personService = personService;
}
-
+
public void setSearchService(SearchService searchService)
{
this.searchService = searchService;
}
-
+
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
+ public void setAvmLockDAO(AVMLockDAO avmLockDAO)
+ {
+ this.avmLockDAO = avmLockDAO;
+ }
+
/**
* Appends the lock owner to the lock data.
*/
@@ -317,54 +320,8 @@ public class AVMLockingServiceImpl implements AVMLockingService
dirPathStart = dirPath;
}
- final List pathKeys = new ArrayList(10);
-
- AttributeQueryCallback callback = new AttributeQueryCallback()
- {
- @SuppressWarnings("unchecked")
- public boolean handleAttribute(Long id, Serializable value, Serializable[] keys)
- {
- if (keys.length != 3 || !EqualsHelper.nullSafeEquals(keys[0], KEY_AVM_LOCKS) || keys[1] == null || keys[2] == null || value == null)
- {
- logger.warn("Unexpected AVM lock attribute: \n" +
- " id: " + id + "\n" +
- " keys: " + Arrays.toString(keys) + "\n" +
- " value: " + value);
- return true;
- }
-
- Map lockData = (Map) value;
-
- for (Map.Entry entry : lockDataToMatch.entrySet())
- {
- String lockDataValue = lockData.get(entry.getKey());
- if (lockDataValue != null)
- {
- if (! lockDataValue.equals(entry.getValue()))
- {
- return true;
- }
- }
- }
-
- String pathKey = (String)keys[2];
-
- if (dirPathStart == null || pathKey.startsWith(dirPathStart))
- {
- pathKeys.add(pathKey);
- }
-
- // Continue
- return true;
- }
- };
-
- attributeService.getAttributes(callback, KEY_AVM_LOCKS, avmStore);
-
- for (String pathKey : pathKeys)
- {
- attributeService.removeAttribute(KEY_AVM_LOCKS, avmStore, pathKey);
- }
+ // optimised to delete with single DB query
+ avmLockDAO.removeLocks(avmStore, dirPathStart, lockDataToMatch);
}
/**
diff --git a/source/java/org/alfresco/repo/domain/avm/AVMLockDAO.java b/source/java/org/alfresco/repo/domain/avm/AVMLockDAO.java
new file mode 100644
index 0000000000..0a49346f46
--- /dev/null
+++ b/source/java/org/alfresco/repo/domain/avm/AVMLockDAO.java
@@ -0,0 +1,46 @@
+/*
+ * 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.domain.avm;
+
+import java.util.Map;
+
+/**
+ * DAO service to remove AVM locks.
+ *
+ * Added here for now, since this is currently an WCM-specific use-case to optimise lock removal
+ * based on matching path (bypassing the Attribute Service -> PropVal DAO). See also AbstractPropertyValueDAOImpl.
+ * Affected table is currently:
+ *
+ * alf_prop_unique_ctx
+ *
+ * @author janv
+ * @since 3.4
+ */
+public interface AVMLockDAO
+{
+ /**
+ * Remove all locks for a specific AVM store that start with a given directory path
+ * that also optionally match a map of lock data entries.
+ *
+ * @param avmStore the name of the AVM store
+ * @param dirPath optional - start with given directory path or null to match all
+ * @param lockDataToMatch optional - lock data to match (note: all entries must match) or null/empty to match all
+ */
+ public void removeLocks(String avmStore, String dirPath, final Map lockDataToMatch);
+}
diff --git a/source/java/org/alfresco/repo/domain/avm/AbstractAVMLockDAOImpl.java b/source/java/org/alfresco/repo/domain/avm/AbstractAVMLockDAOImpl.java
new file mode 100644
index 0000000000..a71797aab7
--- /dev/null
+++ b/source/java/org/alfresco/repo/domain/avm/AbstractAVMLockDAOImpl.java
@@ -0,0 +1,108 @@
+/*
+ * 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.domain.avm;
+
+import java.io.Serializable;
+import java.util.Map;
+
+import org.alfresco.error.AlfrescoRuntimeException;
+import org.alfresco.repo.avm.locking.AVMLockingServiceImpl;
+import org.alfresco.repo.domain.propval.PropertyValueDAO;
+import org.alfresco.util.Pair;
+import org.alfresco.wcm.util.WCMUtil;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+
+/**
+ * Abstract implementation for AVMLock DAO.
+ *
+ * @author janv
+ * @since 3.4
+ */
+public abstract class AbstractAVMLockDAOImpl implements AVMLockDAO
+{
+ protected final Log logger = LogFactory.getLog(this.getClass());
+
+ private PropertyValueDAO propertyValueDAO;
+
+ public void setPropertyValueDAO(PropertyValueDAO propertyValueDAO)
+ {
+ this.propertyValueDAO = propertyValueDAO;
+ }
+
+ /**
+ * Default constructor.
+ */
+ public AbstractAVMLockDAOImpl()
+ {
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void removeLocks(String avmStore, String dirPathToMatch, final Map lockDataToMatch)
+ {
+ Long avmLocksValueId = null;
+ Pair valuePair = propertyValueDAO.getPropertyValue(AVMLockingServiceImpl.KEY_AVM_LOCKS);
+ if (valuePair == null)
+ {
+ // No such value, so no need to delete
+ return;
+ }
+ avmLocksValueId = valuePair.getFirst();
+
+ Long avmStoreNameId = null;
+ valuePair = propertyValueDAO.getPropertyValue(avmStore);
+ if (valuePair == null)
+ {
+ // No such value, so no need to delete
+ return;
+ }
+ avmStoreNameId = valuePair.getFirst();
+
+ String lockDataStoreKey = null;
+ String lockDataStoreValue = null;
+
+ if ((lockDataToMatch != null) && (lockDataToMatch.size() > 0))
+ {
+ lockDataStoreKey = WCMUtil.LOCK_KEY_STORE_NAME;
+
+ if ((lockDataToMatch.size() != 1) || (! lockDataToMatch.containsKey(lockDataStoreKey)))
+ {
+ throw new AlfrescoRuntimeException("Expected lockData to contain either no entries or only one entry with key: "+lockDataStoreKey);
+ }
+
+ lockDataStoreValue = lockDataToMatch.get(lockDataStoreKey);
+ }
+
+ int deleted = deletePropertyUniqueContexts(avmLocksValueId, avmStoreNameId, dirPathToMatch, lockDataStoreKey, lockDataStoreValue);
+
+ // Done
+ if (logger.isDebugEnabled())
+ {
+ logger.debug(
+ "Deleted " + deleted + " unique property contexts: \n" +
+ " dirPathToMatch: " + dirPathToMatch + "\n" +
+ " lockDataToMatch: " + lockDataToMatch);
+ }
+ }
+
+ protected abstract int deletePropertyUniqueContexts(Long avmLocksValueId, Long avmStoreNameId, String dirPathToMatch, String lockDataStoreKey, String lockDataStoreValue);
+}
diff --git a/source/java/org/alfresco/repo/domain/avm/ibatis/AVMLockDAOImpl.java b/source/java/org/alfresco/repo/domain/avm/ibatis/AVMLockDAOImpl.java
new file mode 100644
index 0000000000..f539b1f904
--- /dev/null
+++ b/source/java/org/alfresco/repo/domain/avm/ibatis/AVMLockDAOImpl.java
@@ -0,0 +1,78 @@
+/*
+ * 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.domain.avm.ibatis;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.alfresco.repo.domain.avm.AbstractAVMLockDAOImpl;
+import org.springframework.orm.ibatis.SqlMapClientTemplate;
+
+/**
+ * iBatis-specific implementation of the AVMLock DAO.
+ *
+ * @author janv
+ * @since 3.4
+ */
+public class AVMLockDAOImpl extends AbstractAVMLockDAOImpl
+{
+ private static final String DELETE_MATCHING_AVM_LOCKS_1_KV ="alfresco.avm.delete_PropertyUniqueContextByValuesWithOneKV";
+ private static final String DELETE_MATCHING_AVM_LOCKS_0_KV ="alfresco.avm.delete_PropertyUniqueContextByValuesWithNoKV";
+
+ private SqlMapClientTemplate template;
+
+ public void setSqlMapClientTemplate(SqlMapClientTemplate sqlMapClientTemplate)
+ {
+ this.template = sqlMapClientTemplate;
+ }
+
+ @Override
+ protected int deletePropertyUniqueContexts(Long avmLocksValueId, Long avmStoreNameId, String dirPathToMatch, String lockDataStoreKey, String lockDataStoreValue)
+ {
+ if (dirPathToMatch == null)
+ {
+ dirPathToMatch = "%";
+ }
+ else if (! dirPathToMatch.endsWith("%"))
+ {
+ dirPathToMatch = dirPathToMatch + "%";
+ }
+
+ if (lockDataStoreKey != null)
+ {
+ Map params = new HashMap(5);
+ params.put("value1PropId", avmLocksValueId);
+ params.put("value2PropId", avmStoreNameId);
+ params.put("value3LikeStr", dirPathToMatch);
+ params.put("lockDataStoreKey", lockDataStoreKey);
+ params.put("lockDataStoreValue", lockDataStoreValue);
+
+ return template.delete(DELETE_MATCHING_AVM_LOCKS_1_KV, params);
+ }
+ else
+ {
+ Map params = new HashMap(3);
+ params.put("value1PropId", avmLocksValueId);
+ params.put("value2PropId", avmStoreNameId);
+ params.put("value3LikeStr", dirPathToMatch);
+
+ return template.delete(DELETE_MATCHING_AVM_LOCKS_0_KV, params);
+ }
+ }
+}