From a41f4825574d8ea2fd6b1ead07490ca693daf6b7 Mon Sep 17 00:00:00 2001 From: Britt Park Date: Tue, 24 Apr 2007 21:34:00 +0000 Subject: [PATCH] AVMLockingService is mostly complete. Basic test is in place. Ran across and fixed bug in MapAttributeImpl. git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@5539 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- config/alfresco/avm-services-context.xml | 12 + config/alfresco/public-services-context.xml | 47 +++ .../repo/attributes/MapAttributeImpl.java | 7 +- .../avm/locking/AVMLockingServiceImpl.java | 314 ++++++++++++++++++ .../avm/locking/AVMLockingServiceTest.java | 124 +++++++ .../service/cmr/avm/locking/AVMLock.java | 20 +- .../cmr/avm/locking/AVMLockingService.java | 18 +- 7 files changed, 522 insertions(+), 20 deletions(-) create mode 100644 source/java/org/alfresco/repo/avm/locking/AVMLockingServiceImpl.java create mode 100644 source/java/org/alfresco/repo/avm/locking/AVMLockingServiceTest.java 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); }