diff --git a/config/alfresco/avm-services-context.xml b/config/alfresco/avm-services-context.xml
index 35410e747f..5c28dedd9a 100644
--- a/config/alfresco/avm-services-context.xml
+++ b/config/alfresco/avm-services-context.xml
@@ -252,6 +252,18 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/config/alfresco/public-services-context.xml b/config/alfresco/public-services-context.xml
index 6173a0285d..241d4c67f6 100644
--- a/config/alfresco/public-services-context.xml
+++ b/config/alfresco/public-services-context.xml
@@ -971,6 +971,53 @@
+
+
+
+
+
+
+
+
+
+
+ getLock
+ getUserLocks
+ getWebProjectLocks
+
+
+
+
+
+
+
+
+
+
+ addWebProject
+ lockPath
+ removeLock
+ removeWebProject
+
+
+
+
+
+
+
+ org.alfresco.service.cmr.avm.locking.AVMLockingService
+
+
+
+ avmLockingService
+
+
+
+ avmLockingServiceWriteTxnAdvisor
+ avmLockingServiceReadTxnAdvisor
+
+
+
diff --git a/source/java/org/alfresco/repo/attributes/MapAttributeImpl.java b/source/java/org/alfresco/repo/attributes/MapAttributeImpl.java
index 63542ad5bb..02e52c0699 100644
--- a/source/java/org/alfresco/repo/attributes/MapAttributeImpl.java
+++ b/source/java/org/alfresco/repo/attributes/MapAttributeImpl.java
@@ -158,7 +158,12 @@ public class MapAttributeImpl extends AttributeImpl implements MapAttribute
@Override
public Attribute get(String key)
{
- return AVMDAOs.Instance().fMapEntryDAO.get(this, key).getAttribute();
+ MapEntry entry = AVMDAOs.Instance().fMapEntryDAO.get(this, key);
+ if (entry == null)
+ {
+ return null;
+ }
+ return entry.getAttribute();
}
/* (non-Javadoc)
diff --git a/source/java/org/alfresco/repo/avm/locking/AVMLockingServiceImpl.java b/source/java/org/alfresco/repo/avm/locking/AVMLockingServiceImpl.java
new file mode 100644
index 0000000000..d0d11edddb
--- /dev/null
+++ b/source/java/org/alfresco/repo/avm/locking/AVMLockingServiceImpl.java
@@ -0,0 +1,314 @@
+/*
+ * Copyright (C) 2005-2007 Alfresco Software Limited.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program 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 General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ * As a special exception to the terms and conditions of version 2.0 of
+ * the GPL, you may redistribute this Program in connection with Free/Libre
+ * and Open Source Software ("FLOSS") applications as described in Alfresco's
+ * FLOSS exception. You should have recieved a copy of the text describing
+ * the FLOSS exception, and it is also available here:
+ * http://www.alfresco.com/legal/licensing
+ */
+
+package org.alfresco.repo.avm.locking;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.alfresco.repo.attributes.Attribute;
+import org.alfresco.repo.attributes.MapAttributeValue;
+import org.alfresco.repo.attributes.StringAttributeValue;
+import org.alfresco.repo.transaction.RetryingTransactionHelper;
+import org.alfresco.repo.transaction.RetryingTransactionHelper.Callback;
+import org.alfresco.service.cmr.attributes.AttrQueryEquals;
+import org.alfresco.service.cmr.attributes.AttributeService;
+import org.alfresco.service.cmr.avm.AVMExistsException;
+import org.alfresco.service.cmr.avm.AVMNotFoundException;
+import org.alfresco.service.cmr.avm.locking.AVMLock;
+import org.alfresco.service.cmr.avm.locking.AVMLockingService;
+import org.alfresco.util.GUID;
+import org.alfresco.util.Pair;
+
+/**
+ * Implementation of the lock service.
+ * @author britt
+ */
+public class AVMLockingServiceImpl implements AVMLockingService
+{
+ public static final String LOCK_TABLE = ".avm_lock_table";
+ public static final String WEB_PROJECTS = "web_projects";
+ public static final String USERS = "users";
+
+ /**
+ * AttributeService reference.
+ */
+ private AttributeService fAttributeService;
+
+ /**
+ * Transaction Helper reference.
+ */
+ private RetryingTransactionHelper fRetryingTransactionHelper;
+
+ public AVMLockingServiceImpl()
+ {
+ }
+
+ /**
+ * Setter for AttributeService reference.
+ * @param service
+ */
+ public void setAttributeService(AttributeService service)
+ {
+ fAttributeService = service;
+ }
+
+ /**
+ * Setter for RetryingTransactionHelper reference.
+ * @param helper
+ */
+ public void setRetryingTransactionHelper(RetryingTransactionHelper helper)
+ {
+ fRetryingTransactionHelper = helper;
+ }
+
+ public void init()
+ {
+ Callback callback = new Callback()
+ {
+ public Object execute()
+ {
+ Attribute table = fAttributeService.getAttribute(LOCK_TABLE);
+ if (table != null)
+ {
+ return null;
+ }
+ fAttributeService.setAttribute("", LOCK_TABLE, new MapAttributeValue());
+ fAttributeService.setAttribute(LOCK_TABLE, WEB_PROJECTS, new MapAttributeValue());
+ fAttributeService.setAttribute(LOCK_TABLE, USERS, new MapAttributeValue());
+ return null;
+ }
+ };
+ fRetryingTransactionHelper.doInTransaction(callback, false);
+ }
+
+ /* (non-Javadoc)
+ * @see org.alfresco.service.cmr.avm.locking.AVMLockingService#getLock(java.lang.String, java.lang.String)
+ */
+ public AVMLock getLock(String webProject, String path)
+ {
+ path = normalizePath(path);
+ List keys = new ArrayList();
+ keys.add(LOCK_TABLE);
+ keys.add(WEB_PROJECTS);
+ keys.add(webProject);
+ List> attrs =
+ fAttributeService.query(keys, new AttrQueryEquals(path));
+ if (attrs.size() == 0)
+ {
+ return null;
+ }
+ return new AVMLock(attrs.get(0).getSecond());
+ }
+
+ /**
+ * Utility to get relative paths into canonical form.
+ * @param path The incoming path.
+ * @return The normalized path.
+ */
+ private String normalizePath(String path)
+ {
+ while (path.startsWith("/"))
+ {
+ path = path.substring(1);
+ }
+ while (path.endsWith("/"))
+ {
+ path = path.substring(0, path.length() - 1);
+ }
+ return path.replaceAll("/+", "/");
+ }
+
+ /* (non-Javadoc)
+ * @see org.alfresco.service.cmr.avm.locking.AVMLockingService#getUsersLocks(java.lang.String)
+ */
+ public List getUsersLocks(String user)
+ {
+ List keys = new ArrayList();
+ keys.add(LOCK_TABLE);
+ keys.add(USERS);
+ keys.add(user);
+ Attribute userLocks = fAttributeService.getAttribute(keys);
+ List locks = new ArrayList();
+ if (userLocks == null)
+ {
+ return locks;
+ }
+ for (Attribute entry : userLocks.values())
+ {
+ String webProject = entry.get("web_project").getStringValue();
+ String path = entry.get("path").getStringValue();
+ locks.add(getLock(webProject, path));
+ }
+ return locks;
+ }
+
+ /* (non-Javadoc)
+ * @see org.alfresco.service.cmr.avm.locking.AVMLockingService#lockPath(org.alfresco.service.cmr.avm.locking.AVMLock)
+ */
+ public void lockPath(AVMLock lock)
+ {
+ List keys = new ArrayList();
+ Attribute lockData = lock.getAttribute();
+ keys.add(LOCK_TABLE);
+ keys.add(WEB_PROJECTS);
+ keys.add(lock.getWebProject());
+ if (fAttributeService.getAttribute(keys) == null)
+ {
+ throw new AVMExistsException("Lock Exists: " + keys);
+ }
+ fAttributeService.setAttribute(keys, lock.getPath(), lockData);
+ keys.clear();
+ keys.add(LOCK_TABLE);
+ keys.add(USERS);
+ for (String user : lock.getOwners())
+ {
+ keys.add(user);
+ Attribute userEntry = fAttributeService.getAttribute(keys);
+ keys.remove(2);
+ if (userEntry == null)
+ {
+ fAttributeService.setAttribute(keys, user, new MapAttributeValue());
+ }
+ keys.add(user);
+ Attribute entry = new MapAttributeValue();
+ entry.put("web_project", new StringAttributeValue(lock.getWebProject()));
+ entry.put("path", new StringAttributeValue(lock.getPath()));
+ fAttributeService.setAttribute(keys, GUID.generate(), entry);
+ keys.remove(2);
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.alfresco.service.cmr.avm.locking.AVMLockingService#removeLock(java.lang.String, java.lang.String)
+ */
+ public void removeLock(String webProject, String path)
+ {
+ path = normalizePath(path);
+ List keys = new ArrayList();
+ keys.add(LOCK_TABLE);
+ keys.add(WEB_PROJECTS);
+ keys.add(webProject);
+ keys.add(path);
+ Attribute lockData = fAttributeService.getAttribute(keys);
+ if (lockData == null)
+ {
+ throw new AVMNotFoundException("Lock does not exist: " + webProject + " " + path);
+ }
+ keys.remove(3);
+ fAttributeService.removeAttribute(keys, path);
+ AVMLock lock = new AVMLock(lockData);
+ List userKeys = new ArrayList();
+ userKeys.add(LOCK_TABLE);
+ userKeys.add(USERS);
+ for (String user : lock.getOwners())
+ {
+ userKeys.add(user);
+ Attribute userLocks = fAttributeService.getAttribute(userKeys);
+ for (Map.Entry entry : userLocks.entrySet())
+ {
+ Attribute lockInfo = entry.getValue();
+ if (lockInfo.get("web_project").getStringValue().equals(lock.getWebProject())
+ && lockInfo.get("path").getStringValue().equals(lock.getPath()))
+ {
+ fAttributeService.removeAttribute(userKeys, entry.getKey());
+ break;
+ }
+ }
+ userKeys.remove(2);
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.alfresco.service.cmr.avm.locking.AVMLockingService#addWebProject(java.lang.String)
+ */
+ public void addWebProject(String webProject)
+ {
+ List keys = new ArrayList();
+ keys.add(LOCK_TABLE);
+ keys.add(WEB_PROJECTS);
+ keys.add(webProject);
+ if (fAttributeService.getAttribute(keys) != null)
+ {
+ throw new AVMExistsException("Web Project Exists: " + webProject);
+ }
+ keys.remove(2);
+ fAttributeService.setAttribute(keys, webProject, new MapAttributeValue());
+ }
+
+ /* (non-Javadoc)
+ * @see org.alfresco.service.cmr.avm.locking.AVMLockingService#getWebProjectLocks(java.lang.String)
+ */
+ public List getWebProjectLocks(String webProject)
+ {
+ List keys = new ArrayList();
+ keys.add(LOCK_TABLE);
+ keys.add(WEB_PROJECTS);
+ keys.add(webProject);
+ Attribute locksMap = fAttributeService.getAttribute(keys);
+ List result = new ArrayList();
+ if (locksMap != null)
+ {
+ for (Attribute lockData : locksMap.values())
+ {
+ result.add(new AVMLock(lockData));
+ }
+ }
+ return result;
+ }
+
+ /* (non-Javadoc)
+ * @see org.alfresco.service.cmr.avm.locking.AVMLockingService#removeWebProject(java.lang.String)
+ */
+ public void removeWebProject(String webProject)
+ {
+ List locks = getWebProjectLocks(webProject);
+ List userKeys = new ArrayList();
+ userKeys.add(LOCK_TABLE);
+ userKeys.add(USERS);
+ for (AVMLock lock : locks)
+ {
+ for (String user : lock.getOwners())
+ {
+ userKeys.add(user);
+ Attribute userLocks = fAttributeService.getAttribute(userKeys);
+ for (Map.Entry entry : userLocks.entrySet())
+ {
+ if (entry.getValue().get("web_project").getStringValue().equals(lock.getWebProject()) &&
+ entry.getValue().get("path").getStringValue().equals(lock.getPath()))
+ {
+ fAttributeService.removeAttribute(userKeys, entry.getKey());
+ }
+ }
+ userKeys.remove(2);
+ }
+ }
+ List keys = new ArrayList();
+ keys.add(LOCK_TABLE);
+ keys.add(WEB_PROJECTS);
+ fAttributeService.removeAttribute(keys, webProject);
+ }
+}
diff --git a/source/java/org/alfresco/repo/avm/locking/AVMLockingServiceTest.java b/source/java/org/alfresco/repo/avm/locking/AVMLockingServiceTest.java
new file mode 100644
index 0000000000..05f07c4568
--- /dev/null
+++ b/source/java/org/alfresco/repo/avm/locking/AVMLockingServiceTest.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2005-2007 Alfresco Software Limited.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program 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 General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ * As a special exception to the terms and conditions of version 2.0 of
+ * the GPL, you may redistribute this Program in connection with Free/Libre
+ * and Open Source Software ("FLOSS") applications as described in Alfresco's
+ * FLOSS exception. You should have recieved a copy of the text describing
+ * the FLOSS exception, and it is also available here:
+ * http://www.alfresco.com/legal/licensing
+ */
+
+package org.alfresco.repo.avm.locking;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.alfresco.service.cmr.attributes.AttributeService;
+import org.alfresco.service.cmr.avm.locking.AVMLock;
+import org.alfresco.service.cmr.avm.locking.AVMLockingService;
+import org.springframework.context.support.FileSystemXmlApplicationContext;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests for AVM locking service.
+ * @author britt
+ */
+public class AVMLockingServiceTest extends TestCase
+{
+ private static FileSystemXmlApplicationContext fContext = null;
+
+ private static AVMLockingService fService;
+
+ private static AttributeService fAttributeService;
+
+ /* (non-Javadoc)
+ * @see junit.framework.TestCase#setUp()
+ */
+ @Override
+ protected void setUp() throws Exception
+ {
+ if (fContext == null)
+ {
+ fContext = new FileSystemXmlApplicationContext("config/alfresco/application-context.xml");
+ fService = (AVMLockingService)fContext.getBean("AVMLockingService");
+ fAttributeService = (AttributeService)fContext.getBean("AttributeService");
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see junit.framework.TestCase#tearDown()
+ */
+ @Override
+ protected void tearDown() throws Exception
+ {
+ List keys = fAttributeService.getKeys("");
+ for (String key : keys)
+ {
+ fAttributeService.removeAttribute("", key);
+ }
+ }
+
+ public void testAll()
+ {
+ try
+ {
+ fService.addWebProject("alfresco");
+ System.out.println(fAttributeService.getAttribute(".avm_lock_table"));
+ List owners = new ArrayList();
+ owners.add("Buffy");
+ owners.add("Spike");
+ AVMLock lock = new AVMLock("alfresco",
+ "Sunnydale",
+ "Revello Drive/1630",
+ AVMLockingService.Type.DISCRETIONARY,
+ owners);
+ fService.lockPath(lock);
+ System.out.println(fAttributeService.getAttribute(".avm_lock_table"));
+ assertNotNull(fService.getLock("alfresco", "Revello Drive/1630"));
+ assertEquals(1, fService.getUsersLocks("Buffy").size());
+ assertEquals(1, fService.getWebProjectLocks("alfresco").size());
+ List owners2 = new ArrayList();
+ owners2.add("Buffy");
+ owners2.add("Willow");
+ AVMLock lock2 = new AVMLock("alfresco",
+ "Sunnydale",
+ "UC Sunnydale/Stevenson Hall",
+ AVMLockingService.Type.DISCRETIONARY,
+ owners2);
+ fService.lockPath(lock2);
+ System.out.println(fAttributeService.getAttribute(".avm_lock_table"));
+ assertEquals(2, fService.getUsersLocks("Buffy").size());
+ assertEquals(2, fService.getWebProjectLocks("alfresco").size());
+ fService.removeLock("alfresco", "Revello Drive/1630");
+ System.out.println(fAttributeService.getAttribute(".avm_lock_table"));
+ assertEquals(1, fService.getUsersLocks("Buffy").size());
+ assertEquals(1, fService.getWebProjectLocks("alfresco").size());
+ fService.removeWebProject("alfresco");
+ assertEquals(0, fService.getUsersLocks("Spike").size());
+ assertEquals(0, fService.getUsersLocks("Buffy").size());
+ assertEquals(0, fService.getUsersLocks("Willow").size());
+ assertEquals(0, fService.getUsersLocks("Tara").size());
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ fail();
+ }
+ }
+}
diff --git a/source/java/org/alfresco/service/cmr/avm/locking/AVMLock.java b/source/java/org/alfresco/service/cmr/avm/locking/AVMLock.java
index a977e3252c..e21d7f840d 100644
--- a/source/java/org/alfresco/service/cmr/avm/locking/AVMLock.java
+++ b/source/java/org/alfresco/service/cmr/avm/locking/AVMLock.java
@@ -30,10 +30,10 @@ import java.util.ArrayList;
import java.util.List;
import org.alfresco.repo.attributes.Attribute;
-import org.alfresco.repo.attributes.BooleanAttributeImpl;
+import org.alfresco.repo.attributes.BooleanAttributeValue;
import org.alfresco.repo.attributes.MapAttribute;
-import org.alfresco.repo.attributes.MapAttributeImpl;
-import org.alfresco.repo.attributes.StringAttributeImpl;
+import org.alfresco.repo.attributes.MapAttributeValue;
+import org.alfresco.repo.attributes.StringAttributeValue;
/**
* Struct representing an AVM lock.
@@ -99,16 +99,16 @@ public class AVMLock implements Serializable
public Attribute getAttribute()
{
- MapAttribute lockData = new MapAttributeImpl();
- lockData.put(PATH, new StringAttributeImpl(fPath));
- lockData.put(STORE, new StringAttributeImpl(fStore));
- lockData.put(TYPE, new StringAttributeImpl(fType.name()));
- lockData.put(WEBPROJECT, new StringAttributeImpl(fWebProject));
- MapAttribute owners = new MapAttributeImpl();
+ MapAttribute lockData = new MapAttributeValue();
+ lockData.put(PATH, new StringAttributeValue(fPath));
+ lockData.put(STORE, new StringAttributeValue(fStore));
+ lockData.put(TYPE, new StringAttributeValue(fType.name()));
+ lockData.put(WEBPROJECT, new StringAttributeValue(fWebProject));
+ MapAttribute owners = new MapAttributeValue();
for (String owner : fOwners)
{
// The value is a dummy.
- owners.put(owner, new BooleanAttributeImpl(true));
+ owners.put(owner, new BooleanAttributeValue(true));
}
lockData.put(OWNERS, owners);
return lockData;
diff --git a/source/java/org/alfresco/service/cmr/avm/locking/AVMLockingService.java b/source/java/org/alfresco/service/cmr/avm/locking/AVMLockingService.java
index 706069f4d7..28830003e1 100644
--- a/source/java/org/alfresco/service/cmr/avm/locking/AVMLockingService.java
+++ b/source/java/org/alfresco/service/cmr/avm/locking/AVMLockingService.java
@@ -70,21 +70,21 @@ public interface AVMLockingService
public List getUsersLocks(String user);
/**
- * Get all locks in a webProject.
- * @param webProject
- * @return A List (possibly empty) of all locks in a web project.
- */
- public List getLocks(String webProject);
-
- /**
- * Add a web project.
+ * Add a web project to the locking tables.
* @param webProject The web project name.
*/
public void addWebProject(String webProject);
/**
- * Remove a web project from the locking tables.
+ * Remove a web project and all associated data from the locking tables.
* @param webProject The web project name.
*/
public void removeWebProject(String webProject);
+
+ /**
+ * Get all locks in a give web project.
+ * @param webProject The web project name.
+ * @return All the locks found.
+ */
+ public List getWebProjectLocks(String webProject);
}