From e438c81d27c1c238df465109435219115815e95b Mon Sep 17 00:00:00 2001 From: Jan Vonka Date: Mon, 23 Jun 2008 15:06:50 +0000 Subject: [PATCH] Merged DEV/WCM-PERMISSIONS2 to HEAD AVM folder diff (r9383-r9503) git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@9545 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- config/alfresco/bootstrap-context.xml | 3 + .../org/alfresco/repo/avm/AVMCrawlTestP.java | 128 +- .../org/alfresco/repo/avm/AVMScaleTestP.java | 55 +- .../repo/avm/AVMServiceIndexTest.java | 2 + .../repo/avm/AVMServiceLocalTest.java | 296 ++++- .../repo/avm/AVMServicePermissionsTest.java | 1102 ++++++++++++++++- .../org/alfresco/repo/avm/AVMServiceTest.java | 88 +- .../alfresco/repo/avm/AVMServiceTestBase.java | 20 +- .../alfresco/repo/avm/AVMSyncServiceImpl.java | 438 +++++-- .../org/alfresco/repo/avm/AvmBootstrap.java | 11 +- .../AbstractPermissionsDaoComponentImpl.java | 4 +- 11 files changed, 1956 insertions(+), 191 deletions(-) diff --git a/config/alfresco/bootstrap-context.xml b/config/alfresco/bootstrap-context.xml index 2e2caea19c..480ee2a3ab 100644 --- a/config/alfresco/bootstrap-context.xml +++ b/config/alfresco/bootstrap-context.xml @@ -100,6 +100,9 @@ + + + diff --git a/source/java/org/alfresco/repo/avm/AVMCrawlTestP.java b/source/java/org/alfresco/repo/avm/AVMCrawlTestP.java index 7d421918b1..7802d59f2d 100644 --- a/source/java/org/alfresco/repo/avm/AVMCrawlTestP.java +++ b/source/java/org/alfresco/repo/avm/AVMCrawlTestP.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2007 Alfresco Software Limited. + * Copyright (C) 2005-2008 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 @@ -43,85 +43,95 @@ public class AVMCrawlTestP extends AVMServiceTestBase { int n = 8; // Number of Threads. int m = 2; // How many multiples of content to start with. - long runTime = 28800000; // 8 Hours. . - fService.purgeStore("main"); - BulkLoader loader = new BulkLoader(); - loader.setAvmService(fService); - for (int i = 0; i < m; i++) + try { - fService.createStore("d" + i); - loader.recursiveLoad("source", "d" + i + ":/"); - fService.createSnapshot("d" + i, null, null); - } - long startTime = System.currentTimeMillis(); - List crawlers = new ArrayList(); - List threads = new ArrayList(); - for (int i = 0; i < n; i++) - { - crawlers.add(new AVMCrawler(fService)); - threads.add(new Thread(crawlers.get(i))); - threads.get(i).start(); - } - while (true) - { - try + long runTime = 28800000; // 8 Hours. . + fService.purgeStore("main"); + BulkLoader loader = new BulkLoader(); + loader.setAvmService(fService); + for (int i = 0; i < m; i++) { - Thread.sleep(5000); - // Check that none of the crawlers has errored out. - for (AVMCrawler crawler : crawlers) + fService.createStore("d" + i); + loader.recursiveLoad("source", "d" + i + ":/"); + fService.createSnapshot("d" + i, null, null); + } + long startTime = System.currentTimeMillis(); + List crawlers = new ArrayList(); + List threads = new ArrayList(); + for (int i = 0; i < n; i++) + { + crawlers.add(new AVMCrawler(fService)); + threads.add(new Thread(crawlers.get(i))); + threads.get(i).start(); + } + while (true) + { + try { - if (crawler.getError()) + Thread.sleep(5000); + // Check that none of the crawlers has errored out. + for (AVMCrawler crawler : crawlers) { - for (AVMCrawler craw : crawlers) + if (crawler.getError()) { - craw.setDone(); - } - for (Thread thread : threads) - { - try + for (AVMCrawler craw : crawlers) { - thread.join(); + craw.setDone(); } - catch (InterruptedException ie) + for (Thread thread : threads) { - // Do nothing. + try + { + thread.join(); + } + catch (InterruptedException ie) + { + // Do nothing. + } } + fail(); } - fail(); } } + catch (InterruptedException ie) + { + // Do nothing. + } + long now = System.currentTimeMillis(); + if (now - startTime > runTime) + { + break; + } } - catch (InterruptedException ie) + for (AVMCrawler crawler : crawlers) { - // Do nothing. + crawler.setDone(); } - long now = System.currentTimeMillis(); - if (now - startTime > runTime) + for (Thread thread : threads) { - break; + try + { + thread.join(); + } + catch (InterruptedException ie) + { + // Do nothing. + } } + long ops = 0L; + for (AVMCrawler crawler : crawlers) + { + ops += crawler.getOpCount(); + } + long time = System.currentTimeMillis() - startTime; + System.out.println("Ops/Sec: " + (ops * 1000L / time)); } - for (AVMCrawler crawler : crawlers) + finally { - crawler.setDone(); - } - for (Thread thread : threads) - { - try + for (int i = 0; i < m; i++) { - thread.join(); - } - catch (InterruptedException ie) - { - // Do nothing. + if (fService.getStore("d" + i) != null) { fService.purgeStore("d" + i); } } } - long ops = 0L; - for (AVMCrawler crawler : crawlers) - { - ops += crawler.getOpCount(); - } - long time = System.currentTimeMillis() - startTime; - System.out.println("Ops/Sec: " + (ops * 1000L / time)); } } diff --git a/source/java/org/alfresco/repo/avm/AVMScaleTestP.java b/source/java/org/alfresco/repo/avm/AVMScaleTestP.java index ea0cf9ec6b..6306df627f 100644 --- a/source/java/org/alfresco/repo/avm/AVMScaleTestP.java +++ b/source/java/org/alfresco/repo/avm/AVMScaleTestP.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2007 Alfresco Software Limited. + * Copyright (C) 2005-2008 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 @@ -37,28 +37,39 @@ public class AVMScaleTestP extends AVMServiceTestBase public void testScaling() { int n = 250; // The number of BulkLoads to do. - int futzCount = 10; // The number of post snapshot modifications to make after each load. - String load = "/Users/britt/hibernate-3.1"; // The tree of stuff to load. - BulkLoader loader = new BulkLoader(); - loader.setAvmService(fService); - loader.setPropertyCount(50); - BulkReader reader = new BulkReader(); - reader.setAvmService(fService); - long lastTime = System.currentTimeMillis(); - for (int i = 0; i < n; i++) + + try { - System.out.println("Round " + (i + 1)); - fService.createStore("store" + i); - loader.recursiveLoad(load, "store" + i + ":/"); - fService.createSnapshot("store" + i, null, null); - long now = System.currentTimeMillis(); - System.out.println("Load Time: " + (now - lastTime) + "ms"); - lastTime = now; - reader.recursiveFutz("store" + i, "store" + i + ":/", futzCount); - now = System.currentTimeMillis(); - System.out.println("Read Time: " + (now - lastTime) + "ms"); - System.out.flush(); - lastTime = now; + int futzCount = 10; // The number of post snapshot modifications to make after each load. + String load = "config/alfresco"; // The tree of stuff to load. + BulkLoader loader = new BulkLoader(); + loader.setAvmService(fService); + loader.setPropertyCount(50); + BulkReader reader = new BulkReader(); + reader.setAvmService(fService); + long lastTime = System.currentTimeMillis(); + for (int i = 0; i < n; i++) + { + System.out.println("Round " + (i + 1)); + fService.createStore("store" + i); + loader.recursiveLoad(load, "store" + i + ":/"); + fService.createSnapshot("store" + i, null, null); + long now = System.currentTimeMillis(); + System.out.println("Load Time: " + (now - lastTime) + "ms"); + lastTime = now; + reader.recursiveFutz("store" + i, "store" + i + ":/", futzCount); + now = System.currentTimeMillis(); + System.out.println("Read Time: " + (now - lastTime) + "ms"); + System.out.flush(); + lastTime = now; + } + } + finally + { + for (int i = 0; i < n; i++) + { + if (fService.getStore("store" + i) != null) { fService.purgeStore("store" + i); } + } } } } diff --git a/source/java/org/alfresco/repo/avm/AVMServiceIndexTest.java b/source/java/org/alfresco/repo/avm/AVMServiceIndexTest.java index f83c5ffdd8..47ea618112 100644 --- a/source/java/org/alfresco/repo/avm/AVMServiceIndexTest.java +++ b/source/java/org/alfresco/repo/avm/AVMServiceIndexTest.java @@ -166,5 +166,7 @@ public class AVMServiceIndexTest extends AVMServiceTestBase results = searchService.query(storeRef, "lucene", "PATH:\"//.\""); assertEquals(4, results.length()); results.close(); + + fService.purgeStore("avmAsynchronousTest"); } } diff --git a/source/java/org/alfresco/repo/avm/AVMServiceLocalTest.java b/source/java/org/alfresco/repo/avm/AVMServiceLocalTest.java index 9fb87c22f6..bfbc0750ba 100644 --- a/source/java/org/alfresco/repo/avm/AVMServiceLocalTest.java +++ b/source/java/org/alfresco/repo/avm/AVMServiceLocalTest.java @@ -27,19 +27,24 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; import junit.framework.TestCase; +import org.alfresco.model.ContentModel; import org.alfresco.repo.avm.util.RemoteBulkLoader; +import org.alfresco.repo.domain.PropertyValue; import org.alfresco.service.cmr.avm.AVMNodeDescriptor; import org.alfresco.service.cmr.avm.AVMStoreDescriptor; import org.alfresco.service.cmr.avmsync.AVMDifference; import org.alfresco.service.cmr.avmsync.AVMSyncException; import org.alfresco.service.cmr.avmsync.AVMSyncService; +import org.alfresco.service.cmr.dictionary.DataTypeDefinition; import org.alfresco.service.cmr.remote.AVMRemote; import org.alfresco.service.cmr.security.AuthenticationService; +import org.alfresco.service.namespace.QName; import org.alfresco.util.NameMatcher; import org.alfresco.util.Pair; import org.apache.commons.logging.Log; @@ -291,50 +296,186 @@ public class AVMServiceLocalTest extends TestCase } } - /** - * Test update to layered directory - */ - public void testSimpleUpdateLD() throws Exception + // + // Test updates to layered directories + // + + public void testSimpleUpdateLD1() throws Throwable + { + try + { + List diffs = fSyncService.compare(-1, "main:/", -1, "main:/", null); + assertEquals(0, diffs.size()); + + diffs = fSyncService.compare(-1, "layer:/", -1, "main:/", null); + assertEquals(0, diffs.size()); + + // create file f-a in main root dir + fService.createFile("main:/", "f-a").close(); + + diffs = fSyncService.compare(-1, "layer:/", -1, "main:/", null); + assertEquals("[layer:/f-a[-1] < main:/f-a[-1]]", diffs.toString()); + assertEquals(1, diffs.size()); + + fService.createLayeredDirectory("main:/", "layer:/", "layer"); + + diffs = fSyncService.compare(-1, "layer:/layer", -1, "main:/", null); + assertEquals(0, diffs.size()); + + // create file f-b in main root dir + fService.createFile("main:/", "f-b").close(); + + diffs = fSyncService.compare(-1, "layer:/layer", -1, "main:/", null); + assertEquals(0, diffs.size()); + + // edit file f-b in layer + fService.getFileOutputStream("layer:/layer/f-b").close(); + + diffs = fSyncService.compare(-1, "layer:/layer", -1, "main:/", null); + assertEquals("[layer:/layer/f-b[-1] > main:/f-b[-1]]", diffs.toString()); + assertEquals(1, diffs.size()); + + // update main from layer + fSyncService.update(diffs, null, false, false, false, false, null, null); + + diffs = fSyncService.compare(-1, "layer:/layer", -1, "main:/", null); + assertEquals(0, diffs.size()); + } + catch (Throwable t) + { + t.printStackTrace(); + throw t; + } + } + + public void testSimpleUpdateLD2() throws Throwable + { + try + { + // create directories base/d-a and file f-aa in main + fService.createDirectory("main:/", "base"); + fService.createDirectory("main:/base", "d-a"); + fService.createFile("main:/base/d-a", "f-aa").close(); + + List diffs = fSyncService.compare(-1, "layer" + ":/", -1, "main:/", null); + assertEquals("[layer:/base[-1] < main:/base[-1]]", diffs.toString()); + assertEquals(1, diffs.size()); + + fService.createLayeredDirectory("main:/base", "layer:/", "layer-to-base"); + + diffs = fSyncService.compare(-1, "layer:/layer-to-base", -1, "main:/base", null); + assertEquals(0, diffs.size()); + + // edit file f-aa in main + fService.getFileOutputStream("main:/base/d-a/f-aa").close(); + + diffs = fSyncService.compare(-1, "layer:/layer-to-base", -1, "main:/base", null); + assertEquals(0, diffs.size()); + + // edit file f-aa in layer + fService.getFileOutputStream("layer:/layer-to-base/d-a/f-aa").close(); + + diffs = fSyncService.compare(-1, "layer:/layer-to-base", -1, "main:/base", null); + assertEquals("[layer:/layer-to-base/d-a/f-aa[-1] > main:/base/d-a/f-aa[-1]]", diffs.toString()); + assertEquals(1, diffs.size()); + + // update main from layer + fSyncService.update(diffs, null, false, false, false, false, null, null); + + diffs = fSyncService.compare(-1, "layer:/layer-to-base", -1, "main:/base", null); + assertEquals(0, diffs.size()); + } + catch (Throwable t) + { + t.printStackTrace(); + throw t; + } + } + + public void testSimpleUpdateLD3() throws Throwable + { + try + { + fService.createDirectory("main:/", "base"); + + fService.createLayeredDirectory("main:/base", "layer:/", "layer-to-base"); + + List diffs = fSyncService.compare(-1, "layer:/layer-to-base", -1, "main:/base", null); + assertEquals(0, diffs.size()); + + // create directory d-a and file f-aa in layer + fService.createDirectory("layer:/layer-to-base", "d-a"); + fService.createFile("layer:/layer-to-base/d-a", "f-aa").close(); + + diffs = fSyncService.compare(-1, "layer:/layer-to-base", -1, "main:/base", null); + assertEquals("[layer:/layer-to-base/d-a[-1] > "+"main:/base/d-a[-1]]", diffs.toString()); + assertEquals(1, diffs.size()); + + // update main from layer + fSyncService.update(diffs, null, false, false, false, false, null, null); + + diffs = fSyncService.compare(-1, "layer:/layer-to-base", -1, "main:/base", null); + assertEquals(0, diffs.size()); + } + catch (Throwable t) + { + t.printStackTrace(); + throw t; + } + } + + public void testSimpleUpdateLD4() throws Exception { try { fService.createLayeredDirectory("main:/", "layer:/", "layer"); - // Create a directory. + // create directory b and file foo in layer fService.createDirectory("layer:/layer", "b"); - // Create a file. fService.createFile("layer:/layer/b", "foo").close(); List diffs = fSyncService.compare(-1, "layer:/layer", -1, "main:/", null); assertEquals(1, diffs.size()); assertEquals("[layer:/layer/b[-1] > main:/b[-1]]", diffs.toString()); + fService.createSnapshot("layer", null, null); + fSyncService.update(diffs, null, false, false, false, false, null, null); + fService.createSnapshot("main", null, null); + diffs = fSyncService.compare(-1, "layer:/layer", -1, "main:/", null); assertEquals(0, diffs.size()); + fSyncService.flatten("layer:/layer", "main:/"); + recursiveList("layer"); recursiveList("main"); + fService.createStore("layer2"); fService.createLayeredDirectory("layer:/layer", "layer2:/", "layer"); - // Create a directory. + // create directory c and file foo in layer2 fService.createDirectory("layer2:/layer/", "c"); - // Create a file. fService.createFile("layer2:/layer/c", "foo").close(); fService.createSnapshot("layer2", null, null); + diffs = fSyncService.compare(-1, "layer2:/layer", -1, "layer:/layer", null); assertEquals(1, diffs.size()); assertEquals("[layer2:/layer/c[-1] > layer:/layer/c[-1]]", diffs.toString()); + fSyncService.update(diffs, null, false, false, false, false, null, null); + diffs = fSyncService.compare(-1, "layer2:/layer", -1, "layer:/layer", null); assertEquals(0, diffs.size()); + fSyncService.flatten("layer2:/layer", "layer:/layer"); + diffs = fSyncService.compare(-1, "layer:/layer", -1, "main:/", null); assertEquals(1, diffs.size()); assertEquals("[layer:/layer/c[-1] > main:/c[-1]]", diffs.toString()); + recursiveList("layer2"); recursiveList("layer"); recursiveList("main"); @@ -723,6 +864,145 @@ public class AVMServiceLocalTest extends TestCase throw e; } } + + /** + * Test file properties update ... + */ + public void testUpdateFileTitleAndDescription() throws Exception + { + try + { + fService.createLayeredDirectory("main:/", "layer:/", "layer"); + fService.createDirectory("layer:/layer", "b"); + fService.createFile("layer:/layer/b", "foo").close(); + + List diffs = fSyncService.compare(-1, "layer:/layer", -1, "main:/", null); + assertEquals("[layer:/layer/b[-1] > main:/b[-1]]", diffs.toString()); + + fService.createSnapshot("layer", null, null); + fSyncService.update(diffs, null, false, false, false, false, null, null); + fService.createSnapshot("main", null, null); + + diffs = fSyncService.compare(-1, "layer:/layer", -1, "main:/", null); + assertEquals(0, diffs.size()); + + fSyncService.flatten("layer:/layer", "main:/"); + + assertEquals(0, fService.getNodeProperties(-1, "main:/b/foo").size()); + assertEquals(0, fService.getNodeProperties(-1, "layer:/layer/b/foo").size()); + + Map properties = new HashMap(); + properties.put(ContentModel.PROP_TITLE, new PropertyValue(DataTypeDefinition.TEXT, "foo title")); + properties.put(ContentModel.PROP_DESCRIPTION, new PropertyValue(DataTypeDefinition.TEXT, "foo descrip")); + fService.setNodeProperties("layer:/layer/b/foo", properties); + + diffs = fSyncService.compare(-1, "layer:/layer", -1, "main:/", null); + assertEquals("[layer:/layer/b/foo[-1] > main:/b/foo[-1]]", diffs.toString()); + + fService.createSnapshot("layer", null, null); + fSyncService.update(diffs, null, false, false, false, false, null, null); + fService.createSnapshot("main", null, null); + + diffs = fSyncService.compare(-1, "layer:/layer", -1, "main:/", null); + assertEquals(0, diffs.size()); + + fSyncService.flatten("layer:/layer", "main:/"); + + assertEquals(2, fService.getNodeProperties(-1, "main:/b/foo").size()); + + assertEquals("foo title", fService.getNodeProperty(-1, "main:/b/foo", ContentModel.PROP_TITLE).getStringValue()); + assertEquals("foo descrip", fService.getNodeProperty(-1, "main:/b/foo", ContentModel.PROP_DESCRIPTION).getStringValue()); + } + catch (Exception e) + { + e.printStackTrace(System.err); + throw e; + } + } + + /** + * Test directory properties update ... + */ + public void testUpdateDirectoryTitleAndDescription() throws Exception + { + try + { + fService.createLayeredDirectory("main:/", "layer:/", "layer"); + fService.createDirectory("layer:/layer", "b"); + fService.createFile("layer:/layer/b", "foo").close(); + + List diffs = fSyncService.compare(-1, "layer:/layer", -1, "main:/", null); + assertEquals("[layer:/layer/b[-1] > main:/b[-1]]", diffs.toString()); + + fService.createSnapshot("layer", null, null); + fSyncService.update(diffs, null, false, false, false, false, null, null); + fService.createSnapshot("main", null, null); + + diffs = fSyncService.compare(-1, "layer:/layer", -1, "main:/", null); + assertEquals(0, diffs.size()); + + fSyncService.flatten("layer:/layer", "main:/"); + + assertEquals(0, fService.getNodeProperties(-1, "main:/b").size()); + assertEquals(0, fService.getNodeProperties(-1, "layer:/layer/b").size()); + + Map properties = new HashMap(); + properties.put(ContentModel.PROP_TITLE, new PropertyValue(DataTypeDefinition.TEXT, "b title")); + properties.put(ContentModel.PROP_DESCRIPTION, new PropertyValue(DataTypeDefinition.TEXT, "b descrip")); + fService.setNodeProperties("layer:/layer/b", properties); + + assertEquals(0, fService.getNodeProperties(-1, "main:/b").size()); + assertEquals(2, fService.getNodeProperties(-1, "layer:/layer/b").size()); + + diffs = fSyncService.compare(-1, "layer:/layer", -1, "main:/", null); + assertEquals("[layer:/layer/b[-1] > main:/b[-1]]", diffs.toString()); + + fService.createSnapshot("layer", null, null); + fSyncService.update(diffs, null, false, false, false, false, null, null); + fService.createSnapshot("main", null, null); + + assertEquals(2, fService.getNodeProperties(-1, "main:/b").size()); + assertEquals(2, fService.getNodeProperties(-1, "layer:/layer/b").size()); + + diffs = fSyncService.compare(-1, "layer:/layer", -1, "main:/", null); + assertEquals(0, diffs.size()); + + fSyncService.flatten("layer:/layer", "main:/"); + + assertEquals(2, fService.getNodeProperties(-1, "main:/b").size()); + assertEquals(2, fService.getNodeProperties(-1, "layer:/layer/b").size()); + + assertEquals("b title", fService.getNodeProperty(-1, "main:/b", ContentModel.PROP_TITLE).getStringValue()); + assertEquals("b descrip", fService.getNodeProperty(-1, "main:/b", ContentModel.PROP_DESCRIPTION).getStringValue()); + + + fService.setNodeProperty("layer:/layer/b", ContentModel.PROP_TITLE, new PropertyValue(DataTypeDefinition.TEXT, "b title2")); + fService.setNodeProperty("layer:/layer/b", ContentModel.PROP_DESCRIPTION, new PropertyValue(DataTypeDefinition.TEXT, "b descrip2")); + + diffs = fSyncService.compare(-1, "layer:/layer", -1, "main:/", null); + assertEquals("[layer:/layer/b[-1] > main:/b[-1]]", diffs.toString()); + + fService.createSnapshot("layer", null, null); + fSyncService.update(diffs, null, false, false, false, false, null, null); + fService.createSnapshot("main", null, null); + + diffs = fSyncService.compare(-1, "layer:/layer", -1, "main:/", null); + assertEquals(0, diffs.size()); + + fSyncService.flatten("layer:/layer", "main:/"); + + assertEquals(2, fService.getNodeProperties(-1, "main:/b").size()); + assertEquals(2, fService.getNodeProperties(-1, "layer:/layer/b").size()); + + assertEquals("b title2", fService.getNodeProperty(-1, "main:/b", ContentModel.PROP_TITLE).getStringValue()); + assertEquals("b descrip2", fService.getNodeProperty(-1, "main:/b", ContentModel.PROP_DESCRIPTION).getStringValue()); + } + catch (Exception e) + { + e.printStackTrace(System.err); + throw e; + } + } protected void recursiveContents(String path) { diff --git a/source/java/org/alfresco/repo/avm/AVMServicePermissionsTest.java b/source/java/org/alfresco/repo/avm/AVMServicePermissionsTest.java index c2c34b20c1..ae0471da66 100644 --- a/source/java/org/alfresco/repo/avm/AVMServicePermissionsTest.java +++ b/source/java/org/alfresco/repo/avm/AVMServicePermissionsTest.java @@ -117,8 +117,6 @@ public class AVMServicePermissionsTest extends TestCase private AVMNodeDAO avmNodeDAO; - private Object fContext; - private AVMSyncService avmSyncService; public AVMServicePermissionsTest() @@ -1094,6 +1092,1046 @@ public class AVMServicePermissionsTest extends TestCase } } + + /* + * create directories & file in main + * set file permission in layer + * update back to main + * flatten + */ + public void testSimpleFilePermissionDiff() throws Throwable + { + runAs("admin"); + + String baseStore = "main"; + String layeredStore = "layer"; + + try + { + System.out.println("create store: " + baseStore); + avmService.createStore(baseStore); + + // create directories and file in main + System.out.println("create D: " + baseStore + ":/base"); + avmService.createDirectory(baseStore + ":/", "base"); + System.out.println("create D: " + baseStore + ":/base/d-a"); + avmService.createDirectory(baseStore + ":/base", "d-a"); + System.out.println("create F: " + baseStore + ":/base/d-a/f-aa"); + avmService.createFile(baseStore + ":/base/d-a", "f-aa").close(); + + AVMNodeDescriptor baseNodeDesc = avmService.lookup(-1, baseStore + ":/base/d-a/f-aa"); + checkHeadPermissionNotSet(baseNodeDesc, "andy", PermissionService.DELETE, true); + + System.out.println("create store: " + layeredStore); + avmService.createStore(layeredStore); + + System.out.println("create LD: " + layeredStore + ":/layer-to-base -> " + baseStore + ":/base"); + avmService.createLayeredDirectory(baseStore + ":/base", layeredStore + ":/", "layer-to-base"); + + recursiveList(baseStore); + recursiveList(layeredStore); + + List diffs = avmSyncService.compare(-1, layeredStore + ":/layer-to-base", -1, baseStore + ":/base", null); + assertEquals(0, diffs.size()); + + AVMNodeDescriptor layeredNodeDesc = avmService.lookup(-1, layeredStore + ":/layer-to-base/d-a/f-aa"); + NodeRef layeredNodeRef = AVMNodeConverter.ToNodeRef(-1, layeredNodeDesc.getPath()); + + // set DELETE permission on file in layer + System.out.println("set P (DELETE): " + layeredStore + ":/layer-to-base/d-a/f-aa"); + checkHeadPermissionNotSet(layeredNodeDesc, "andy", PermissionService.DELETE, true); + permissionService.setPermission(layeredNodeRef, "andy", PermissionService.DELETE, true); + checkHeadPermission(layeredNodeDesc, "andy", PermissionService.DELETE, true); + + recursiveList(baseStore); + recursiveList(layeredStore); + + diffs = avmSyncService.compare(-1, layeredStore + ":/layer-to-base", -1, baseStore + ":/base", null); + assertEquals("["+layeredStore+":/layer-to-base/d-a/f-aa[-1] > "+baseStore+":/base/d-a/f-aa[-1]]", diffs.toString()); + assertEquals(1, diffs.size()); + + baseNodeDesc = avmService.lookup(-1, baseStore + ":/base/d-a/f-aa"); + checkHeadPermissionNotSet(baseNodeDesc, "andy", PermissionService.DELETE, true); + + // update main from layer + System.out.println("update: main from layer"); + avmSyncService.update(diffs, null, false, false, false, false, null, null); + + baseNodeDesc = avmService.lookup(-1, baseStore + ":/base/d-a/f-aa"); + checkHeadPermission(baseNodeDesc, "andy", PermissionService.DELETE, true); + + recursiveList(baseStore); + recursiveList(layeredStore); + + diffs = avmSyncService.compare(-1, layeredStore + ":/layer-to-base", -1, baseStore + ":/base", null); + assertEquals(0, diffs.size()); + + // flatten + System.out.println("flatten: layer to main"); + avmSyncService.flatten(layeredStore + ":/layer-to-base", baseStore + ":/base"); + + recursiveList(baseStore); + recursiveList(layeredStore); + + diffs = avmSyncService.compare(-1, layeredStore + ":/layer-to-base", -1, baseStore + ":/base", null); + assertEquals(0, diffs.size()); + + // check that the DELETE permission is still set in main & layer + baseNodeDesc = avmService.lookup(-1, baseStore + ":/base/d-a/f-aa"); + checkHeadPermission(baseNodeDesc, "andy", PermissionService.DELETE, true); + + layeredNodeDesc = avmService.lookup(-1, layeredStore + ":/layer-to-base/d-a/f-aa"); + checkHeadPermission(layeredNodeDesc, "andy", PermissionService.DELETE, true); + + // check that file in layer is the same as the one from main + assertEquals(baseNodeDesc, layeredNodeDesc); + } + catch (Throwable t) + { + t.printStackTrace(); + throw t; + } + finally + { + avmService.purgeStore(baseStore); + avmService.purgeStore(layeredStore); + } + } + + /* + * create directory in main + * set directory permission in main + */ + public void testSimpleDirectoryPermissionDiff0() throws Throwable + { + runAs("admin"); + + String baseStore = "main"; + String layeredStore = "layer"; + + try + { + System.out.println("create store: " + baseStore); + avmService.createStore(baseStore); + + // create directory in main + System.out.println("create D: " + baseStore + ":/d-a"); + avmService.createDirectory(baseStore + ":/", "d-a"); + + AVMNodeDescriptor baseNodeDesc = avmService.lookup(-1, baseStore + ":/d-a"); + checkHeadPermissionNotSet(baseNodeDesc, "andy", PermissionService.DELETE, true); + + System.out.println("create store: " + layeredStore); + avmService.createStore(layeredStore); + + System.out.println("create LD: " + layeredStore + ":/layer -> " + baseStore + ":/"); + avmService.createLayeredDirectory(baseStore + ":/", layeredStore + ":/", "layer"); + + recursiveList(baseStore); + recursiveList(layeredStore); + + List diffs = avmSyncService.compare(-1, layeredStore + ":/layer", -1, baseStore + ":/", null); + assertEquals(0, diffs.size()); + + baseNodeDesc = avmService.lookup(-1, baseStore + ":/d-a"); + NodeRef baseNodeRef = AVMNodeConverter.ToNodeRef(-1, baseNodeDesc.getPath()); + + // set DELETE permission on directory in main + System.out.println("set P (DELETE): " + baseStore + ":/d-a"); + checkHeadPermissionNotSet(baseNodeDesc, "andy", PermissionService.DELETE, true); + permissionService.setPermission(baseNodeRef, "andy", PermissionService.DELETE, true); + checkHeadPermission(baseNodeDesc, "andy", PermissionService.DELETE, true); + + recursiveList(baseStore); + recursiveList(layeredStore); + + diffs = avmSyncService.compare(-1, layeredStore + ":/layer", -1, baseStore + ":/", null); + assertEquals(0, diffs.size()); + + // update main from layer - NOOP + System.out.println("update: main from layer"); + avmSyncService.update(diffs, null, false, false, false, false, null, null); + + recursiveList(baseStore); + recursiveList(layeredStore); + + diffs = avmSyncService.compare(-1, layeredStore + ":/layer", -1, baseStore + ":/", null); + assertEquals(0, diffs.size()); + + // flatten - NOOP + System.out.println("flatten: layer to main"); + avmSyncService.flatten(layeredStore + ":/layer", baseStore + ":/"); + + recursiveList(baseStore); + recursiveList(layeredStore); + + diffs = avmSyncService.compare(-1, layeredStore + ":/layer", -1, baseStore + ":/", null); + assertEquals(0, diffs.size()); + + // check that the DELETE permission is still set in main (and appears in layer) + baseNodeDesc = avmService.lookup(-1, baseStore + ":/d-a"); + checkHeadPermission(baseNodeDesc, "andy", PermissionService.DELETE, true); + + AVMNodeDescriptor layeredNodeDesc = avmService.lookup(-1, layeredStore + ":/layer/d-a"); + checkHeadPermission(layeredNodeDesc, "andy", PermissionService.DELETE, true); + + // check that directory in layer is the same as the one from main + assertEquals(baseNodeDesc, layeredNodeDesc); + } + catch (Throwable t) + { + t.printStackTrace(); + throw t; + } + finally + { + avmService.purgeStore(baseStore); + avmService.purgeStore(layeredStore); + } + } + + /* + * create directory in main + * set directory permission in layer + * update back to main + * flatten + */ + public void testSimpleDirectoryPermissionDiff1() throws Throwable + { + runAs("admin"); + + String baseStore = "main"; + String layeredStore = "layer"; + + try + { + System.out.println("create store: " + baseStore); + avmService.createStore(baseStore); + + // create directory in main + System.out.println("create D: " + baseStore + ":/d-a"); + avmService.createDirectory(baseStore + ":/", "d-a"); + + AVMNodeDescriptor baseNodeDesc = avmService.lookup(-1, baseStore + ":/d-a"); + checkHeadPermissionNotSet(baseNodeDesc, "andy", PermissionService.DELETE, true); + + System.out.println("create store: " + layeredStore); + avmService.createStore(layeredStore); + + System.out.println("create LD: " + layeredStore + ":/layer -> " + baseStore + ":/"); + avmService.createLayeredDirectory(baseStore + ":/", layeredStore + ":/", "layer"); + + recursiveList(baseStore); + recursiveList(layeredStore); + + List diffs = avmSyncService.compare(-1, layeredStore + ":/layer", -1, baseStore + ":/", null); + assertEquals(0, diffs.size()); + + AVMNodeDescriptor layeredNodeDesc = avmService.lookup(-1, layeredStore + ":/layer/d-a"); + NodeRef layeredNodeRef = AVMNodeConverter.ToNodeRef(-1, layeredNodeDesc.getPath()); + + // set DELETE permission on directory in layer + System.out.println("set P (DELETE): " + layeredStore + ":/layer/d-a"); + checkHeadPermissionNotSet(layeredNodeDesc, "andy", PermissionService.DELETE, true); + permissionService.setPermission(layeredNodeRef, "andy", PermissionService.DELETE, true); + checkHeadPermission(layeredNodeDesc, "andy", PermissionService.DELETE, true); + + recursiveList(baseStore); + recursiveList(layeredStore); + + diffs = avmSyncService.compare(-1, layeredStore + ":/layer", -1, baseStore + ":/", null); + assertEquals("["+layeredStore+":/layer/d-a[-1] > "+baseStore+":/d-a[-1]]", diffs.toString()); + assertEquals(1, diffs.size()); + + baseNodeDesc = avmService.lookup(-1, baseStore + ":/d-a"); + checkHeadPermissionNotSet(baseNodeDesc, "andy", PermissionService.DELETE, true); + + // update main from layer + System.out.println("update: main from layer"); + avmSyncService.update(diffs, null, false, false, false, false, null, null); + + baseNodeDesc = avmService.lookup(-1, baseStore + ":/d-a"); + checkHeadPermission(baseNodeDesc, "andy", PermissionService.DELETE, true); + + recursiveList(baseStore); + recursiveList(layeredStore); + + diffs = avmSyncService.compare(-1, layeredStore + ":/layer", -1, baseStore + ":/", null); + assertEquals(0, diffs.size()); + + // flatten + System.out.println("flatten: layer to main"); + avmSyncService.flatten(layeredStore + ":/layer", baseStore + ":/"); + + recursiveList(baseStore); + recursiveList(layeredStore); + + diffs = avmSyncService.compare(-1, layeredStore + ":/layer", -1, baseStore + ":/", null); + assertEquals(0, diffs.size()); + + // check that the DELETE permission is still set in main (and appears in layer) + baseNodeDesc = avmService.lookup(-1, baseStore + ":/d-a"); + checkHeadPermission(baseNodeDesc, "andy", PermissionService.DELETE, true); + + layeredNodeDesc = avmService.lookup(-1, layeredStore + ":/layer/d-a"); + checkHeadPermission(layeredNodeDesc, "andy", PermissionService.DELETE, true); + + // check that directory in layer is the same as the one from main + assertEquals(baseNodeDesc, layeredNodeDesc); + } + catch (Throwable t) + { + t.printStackTrace(); + throw t; + } + finally + { + avmService.purgeStore(baseStore); + avmService.purgeStore(layeredStore); + } + } + + /* + * create directory in layer + * set directory permission in layer + * update back to main + * flatten + */ + public void testSimpleDirectoryPermissionDiff2() throws Throwable + { + runAs("admin"); + + String baseStore = "main"; + String layeredStore = "layer"; + + try + { + System.out.println("create store: " + baseStore); + avmService.createStore(baseStore); + + System.out.println("create store: " + layeredStore); + avmService.createStore(layeredStore); + + System.out.println("create LD: " + layeredStore + ":/layer -> " + baseStore + ":/"); + avmService.createLayeredDirectory(baseStore + ":/", layeredStore + ":/", "layer"); + + // create directory in layer + System.out.println("create D: " + layeredStore + ":/layer/d-a"); + avmService.createDirectory(layeredStore + ":/layer", "d-a"); + + recursiveList(baseStore); + recursiveList(layeredStore); + + AVMNodeDescriptor layeredNodeDesc = avmService.lookup(-1, layeredStore + ":/layer/d-a"); + AVMNodeDescriptor baseNodeDesc = avmService.lookup(-1, baseStore + ":/d-a"); + NodeRef layeredNodeRef = AVMNodeConverter.ToNodeRef(-1, layeredNodeDesc.getPath()); + + // set DELETE permission on directory in layer + System.out.println("set P (DELETE): " + layeredStore + ":/layer/d-a"); + checkHeadPermissionNotSet(layeredNodeDesc, "andy", PermissionService.DELETE, true); + permissionService.setPermission(layeredNodeRef, "andy", PermissionService.DELETE, true); + checkHeadPermission(layeredNodeDesc, "andy", PermissionService.DELETE, true); + + List diffs = avmSyncService.compare(-1, layeredStore + ":/layer", -1, baseStore + ":/", null); + assertEquals("["+layeredStore+":/layer/d-a[-1] > "+baseStore+":/d-a[-1]]", diffs.toString()); + assertEquals(1, diffs.size()); + + recursiveList(baseStore); + recursiveList(layeredStore); + + // update main from layer + System.out.println("update: main from layer"); + avmSyncService.update(diffs, null, false, false, false, false, null, null); + + recursiveList(baseStore); + recursiveList(layeredStore); + + diffs = avmSyncService.compare(-1, layeredStore + ":/layer", -1, baseStore + ":/", null); + assertEquals(0, diffs.size()); + + // check that the DELETE permission is now set in main + baseNodeDesc = avmService.lookup(-1, baseStore + ":/d-a"); + checkHeadPermission(baseNodeDesc, "andy", PermissionService.DELETE, true); + + layeredNodeDesc = avmService.lookup(-1, layeredStore + ":/layer/d-a"); + layeredNodeRef = AVMNodeConverter.ToNodeRef(-1, layeredNodeDesc.getPath()); + + // flatten + System.out.println("flatten: layer to main"); + avmSyncService.flatten(layeredStore + ":/layer", baseStore + ":/"); + + recursiveList(baseStore); + recursiveList(layeredStore); + + diffs = avmSyncService.compare(-1, layeredStore + ":/layer", -1, baseStore + ":/", null); + assertEquals(0, diffs.size()); + + // check that the DELETE permission is still set in main (and appears in layer) + baseNodeDesc = avmService.lookup(-1, baseStore + ":/d-a"); + checkHeadPermission(baseNodeDesc, "andy", PermissionService.DELETE, true); + + layeredNodeDesc = avmService.lookup(-1, layeredStore + ":/layer/d-a"); + checkHeadPermission(layeredNodeDesc, "andy", PermissionService.DELETE, true); + + // check that directory in layer is the same as the one from main + assertEquals(baseNodeDesc, layeredNodeDesc); + } + catch (Throwable t) + { + t.printStackTrace(); + throw t; + } + finally + { + avmService.purgeStore(baseStore); + avmService.purgeStore(layeredStore); + } + } + + /* + * create directory in layer + * set directory permission in layer + * update back to main + * flatten + * set another directory permission in layer + * update back to main + * flatten + */ + public void testSimpleDirectoryPermissionDiff3() throws Throwable + { + runAs("admin"); + + String baseStore = "main"; + String layeredStore = "layer"; + + try + { + System.out.println("create store: " + baseStore); + avmService.createStore(baseStore); + + System.out.println("create store: " + layeredStore); + avmService.createStore(layeredStore); + + System.out.println("create LD: " + layeredStore + ":/layer -> " + baseStore + ":/"); + avmService.createLayeredDirectory(baseStore + ":/", layeredStore + ":/", "layer"); + + // create directory in layer + System.out.println("create D: " + layeredStore + ":/layer/d-a"); + avmService.createDirectory(layeredStore + ":/layer", "d-a"); + + recursiveList(baseStore); + recursiveList(layeredStore); + + AVMNodeDescriptor layeredNodeDesc = avmService.lookup(-1, layeredStore + ":/layer/d-a"); + AVMNodeDescriptor baseNodeDesc = avmService.lookup(-1, baseStore + ":/d-a"); + NodeRef layeredNodeRef = AVMNodeConverter.ToNodeRef(-1, layeredNodeDesc.getPath()); + + // set DELETE permission on directory in layer + System.out.println("set P (DELETE): " + layeredStore + ":/layer/d-a"); + checkHeadPermissionNotSet(layeredNodeDesc, "andy", PermissionService.DELETE, true); + permissionService.setPermission(layeredNodeRef, "andy", PermissionService.DELETE, true); + checkHeadPermission(layeredNodeDesc, "andy", PermissionService.DELETE, true); + + List diffs = avmSyncService.compare(-1, layeredStore + ":/layer", -1, baseStore + ":/", null); + assertEquals("["+layeredStore+":/layer/d-a[-1] > "+baseStore+":/d-a[-1]]", diffs.toString()); + assertEquals(1, diffs.size()); + + recursiveList(baseStore); + recursiveList(layeredStore); + + // update main from layer + System.out.println("update: main from layer"); + avmSyncService.update(diffs, null, false, false, false, false, null, null); + + recursiveList(baseStore); + recursiveList(layeredStore); + + diffs = avmSyncService.compare(-1, layeredStore + ":/layer", -1, baseStore + ":/", null); + assertEquals(0, diffs.size()); + + // check that the DELETE permission is now set in main + baseNodeDesc = avmService.lookup(-1, baseStore + ":/d-a"); + checkHeadPermission(baseNodeDesc, "andy", PermissionService.DELETE, true); + + // flatten + System.out.println("flatten: layer to main"); + avmSyncService.flatten(layeredStore + ":/layer", baseStore + ":/"); + + recursiveList(baseStore); + recursiveList(layeredStore); + + diffs = avmSyncService.compare(-1, layeredStore + ":/layer", -1, baseStore + ":/", null); + assertEquals(0, diffs.size()); + + // check that the DELETE permission is still set in main (and appears in layer) + baseNodeDesc = avmService.lookup(-1, baseStore + ":/d-a"); + checkHeadPermission(baseNodeDesc, "andy", PermissionService.DELETE, true); + + layeredNodeDesc = avmService.lookup(-1, layeredStore + ":/layer/d-a"); + checkHeadPermission(layeredNodeDesc, "andy", PermissionService.DELETE, true); + + // check that directory in layer is the same as the one from main + layeredNodeDesc = avmService.lookup(-1, layeredStore + ":/layer/d-a"); + assertEquals(baseNodeDesc, layeredNodeDesc); + + // repeat with another directory permission + + // set WRITE directory permission in layer + System.out.println("set P (WRITE): " + layeredStore + ":/layer/d-a"); + checkHeadPermissionNotSet(layeredNodeDesc, "andy", PermissionService.WRITE, true); + permissionService.setPermission(layeredNodeRef, "andy", PermissionService.WRITE, true); + checkHeadPermission(layeredNodeDesc, "andy", PermissionService.WRITE, true); + + recursiveList(baseStore); + recursiveList(layeredStore); + + diffs = avmSyncService.compare(-1, layeredStore + ":/layer", -1, baseStore + ":/", null); + assertEquals("["+layeredStore+":/layer/d-a[-1] > "+baseStore+":/d-a[-1]]", diffs.toString()); + assertEquals(1, diffs.size()); + + // update main from layer + System.out.println("update: main from layer"); + avmSyncService.update(diffs, null, false, false, false, false, null, null); + + recursiveList(baseStore); + recursiveList(layeredStore); + + // check that the WRITE permission is now set in main + baseNodeDesc = avmService.lookup(-1, baseStore + ":/d-a"); + checkHeadPermission(baseNodeDesc, "andy", PermissionService.WRITE, true); + + // flatten + System.out.println("flatten: layer to main"); + avmSyncService.flatten(layeredStore + ":/layer", baseStore + ":/"); + + recursiveList(baseStore); + recursiveList(layeredStore); + + diffs = avmSyncService.compare(-1, layeredStore + ":/layer", -1, baseStore + ":/", null); + assertEquals(0, diffs.size()); + + // check that the WRITE and DELETE permissions are still set in main (and appears in layer) + baseNodeDesc = avmService.lookup(-1, baseStore + ":/d-a"); + checkHeadPermission(baseNodeDesc, "andy", PermissionService.DELETE, true); + checkHeadPermission(baseNodeDesc, "andy", PermissionService.WRITE, true); + + layeredNodeDesc = avmService.lookup(-1, layeredStore + ":/layer/d-a"); + checkHeadPermission(layeredNodeDesc, "andy", PermissionService.DELETE, true); + checkHeadPermission(layeredNodeDesc, "andy", PermissionService.WRITE, true); + + // check that directory in layer is the same as the one from main + assertEquals(baseNodeDesc, layeredNodeDesc); + } + catch (Throwable t) + { + t.printStackTrace(); + throw t; + } + finally + { + avmService.purgeStore(baseStore); + avmService.purgeStore(layeredStore); + } + } + + /* + * create directory in layer + * set directory permission in layer + * snapshot layer, update back to main, snapshot main + * create file in layer + * snapshot layer, update back to main, snapshot main + * flatten + * set another directory permission in layer + * snapshot layer, update back to main, snapshot main + * flatten + */ + public void testSimpleDirectoryPermissionDiff4() throws Throwable + { + runAs("admin"); + + String baseStore = "main"; + String layeredStore = "layer"; + + try + { + System.out.println("create store: " + baseStore); + avmService.createStore(baseStore); + + System.out.println("create store: " + layeredStore); + avmService.createStore(layeredStore); + + System.out.println("create LD: " + layeredStore + ":/layer -> " + baseStore + ":/"); + avmService.createLayeredDirectory(baseStore + ":/", layeredStore + ":/", "layer"); + + // create directory in layer + System.out.println("create D: " + layeredStore + ":/layer/d-a"); + avmService.createDirectory(layeredStore + ":/layer", "d-a"); + + recursiveList(baseStore); + recursiveList(layeredStore); + + AVMNodeDescriptor layeredNodeDesc = avmService.lookup(-1, layeredStore + ":/layer/d-a"); + AVMNodeDescriptor baseNodeDesc = avmService.lookup(-1, baseStore + ":/d-a"); + NodeRef layeredNodeRef = AVMNodeConverter.ToNodeRef(-1, layeredNodeDesc.getPath()); + + // set DELETE permission on directory in layer + System.out.println("set P (DELETE): " + layeredStore + ":/layer/d-a"); + checkHeadPermissionNotSet(layeredNodeDesc, "andy", PermissionService.DELETE, true); + permissionService.setPermission(layeredNodeRef, "andy", PermissionService.DELETE, true); + checkHeadPermission(layeredNodeDesc, "andy", PermissionService.DELETE, true); + + List diffs = avmSyncService.compare(-1, layeredStore + ":/layer", -1, baseStore + ":/", null); + assertEquals("["+layeredStore+":/layer/d-a[-1] > "+baseStore+":/d-a[-1]]", diffs.toString()); + assertEquals(1, diffs.size()); + + recursiveList(baseStore); + recursiveList(layeredStore); + + // snapshot layer, update main from layer, snapshot main + System.out.println("snapshot: layer"); + avmService.createSnapshot(layeredStore, null, null); + System.out.println("update: main from layer"); + avmSyncService.update(diffs, null, false, false, false, false, null, null); + System.out.println("snapshot: main"); + avmService.createSnapshot(baseStore, null, null); + + recursiveList(baseStore); + recursiveList(layeredStore); + + diffs = avmSyncService.compare(-1, layeredStore + ":/layer", -1, baseStore + ":/", null); + assertEquals(0, diffs.size()); + + // check that the DELETE permission is now set in main + baseNodeDesc = avmService.lookup(-1, baseStore + ":/d-a"); + checkHeadPermission(baseNodeDesc, "andy", PermissionService.DELETE, true); + + // create file in layer + System.out.println("create F: " + layeredStore + ":/layer/d-a/f-aa"); + avmService.createFile(layeredStore + ":/layer/d-a", "f-aa").close(); + + recursiveList(baseStore); + recursiveList(layeredStore); + + diffs = avmSyncService.compare(-1, layeredStore + ":/layer", -1, baseStore + ":/", null); + assertEquals("["+layeredStore+":/layer/d-a/f-aa[-1] > "+baseStore+":/d-a/f-aa[-1]]", diffs.toString()); + assertEquals(1, diffs.size()); + + // snapshot layer, update main from layer, snapshot main + System.out.println("snapshot: layer"); + avmService.createSnapshot(layeredStore, null, null); + System.out.println("update: main from layer"); + avmSyncService.update(diffs, null, false, false, false, false, null, null); + System.out.println("snapshot: main"); + avmService.createSnapshot(baseStore, null, null); + + recursiveList(baseStore); + recursiveList(layeredStore); + + // flatten + System.out.println("flatten: layer to main"); + avmSyncService.flatten(layeredStore + ":/layer", baseStore + ":/"); + + recursiveList(baseStore); + recursiveList(layeredStore); + + diffs = avmSyncService.compare(-1, layeredStore + ":/layer", -1, baseStore + ":/", null); + assertEquals(0, diffs.size()); + + // check that the DELETE permission is still set in main (and appears in layer) + baseNodeDesc = avmService.lookup(-1, baseStore + ":/d-a"); + checkHeadPermission(baseNodeDesc, "andy", PermissionService.DELETE, true); + + layeredNodeDesc = avmService.lookup(-1, layeredStore + ":/layer/d-a"); + checkHeadPermission(layeredNodeDesc, "andy", PermissionService.DELETE, true); + + // check that directory in layer is the same as the one from main + layeredNodeDesc = avmService.lookup(-1, layeredStore + ":/layer/d-a"); + assertEquals(baseNodeDesc, layeredNodeDesc); + + // set another directory permission + + // set WRITE directory permission in layer + System.out.println("set P (WRITE): " + layeredStore + ":/layer/d-a"); + checkHeadPermissionNotSet(layeredNodeDesc, "andy", PermissionService.WRITE, true); + permissionService.setPermission(layeredNodeRef, "andy", PermissionService.WRITE, true); + checkHeadPermission(layeredNodeDesc, "andy", PermissionService.WRITE, true); + + recursiveList(baseStore); + recursiveList(layeredStore); + + diffs = avmSyncService.compare(-1, layeredStore + ":/layer", -1, baseStore + ":/", null); + assertEquals("["+layeredStore+":/layer/d-a[-1] > "+baseStore+":/d-a[-1]]", diffs.toString()); + assertEquals(1, diffs.size()); + + // snapshot layer, update main from layer, snapshot main + System.out.println("snapshot: layer"); + avmService.createSnapshot(layeredStore, null, null); + System.out.println("update: main from layer"); + avmSyncService.update(diffs, null, false, false, false, false, null, null); + System.out.println("snapshot: main"); + avmService.createSnapshot(baseStore, null, null); + + recursiveList(baseStore); + recursiveList(layeredStore); + + // check that the WRITE permission is now set in main + baseNodeDesc = avmService.lookup(-1, baseStore + ":/d-a"); + checkHeadPermission(baseNodeDesc, "andy", PermissionService.WRITE, true); + + // flatten + System.out.println("flatten: layer to main"); + avmSyncService.flatten(layeredStore + ":/layer", baseStore + ":/"); + + recursiveList(baseStore); + recursiveList(layeredStore); + + diffs = avmSyncService.compare(-1, layeredStore + ":/layer", -1, baseStore + ":/", null); + assertEquals(0, diffs.size()); + + // check that the WRITE and DELETE permissions are still set in main (and appears in layer) + baseNodeDesc = avmService.lookup(-1, baseStore + ":/d-a"); + checkHeadPermission(baseNodeDesc, "andy", PermissionService.DELETE, true); + checkHeadPermission(baseNodeDesc, "andy", PermissionService.WRITE, true); + + layeredNodeDesc = avmService.lookup(-1, layeredStore + ":/layer/d-a"); + checkHeadPermission(layeredNodeDesc, "andy", PermissionService.DELETE, true); + checkHeadPermission(layeredNodeDesc, "andy", PermissionService.WRITE, true); + + // check that directory in layer is the same as the one from main + assertEquals(baseNodeDesc, layeredNodeDesc); + } + catch (Throwable t) + { + t.printStackTrace(); + throw t; + } + finally + { + avmService.purgeStore(baseStore); + avmService.purgeStore(layeredStore); + } + } + + /* + * create directory in layer + * set two directory permissions in layer + * snapshot layer, update back to main, snapshot main + * flatten + * remove one of the directory permissions in layer + * snapshot layer, update back to main, snapshot main + * flatten + */ + public void testSimpleDirectoryPermissionDiff5() throws Throwable + { + runAs("admin"); + + String baseStore = "main"; + String layeredStore = "layer"; + + try + { + System.out.println("create store: " + baseStore); + avmService.createStore(baseStore); + + System.out.println("create store: " + layeredStore); + avmService.createStore(layeredStore); + + System.out.println("create LD: " + layeredStore + ":/layer -> " + baseStore + ":/"); + avmService.createLayeredDirectory(baseStore + ":/", layeredStore + ":/", "layer"); + + // create directory in layer + System.out.println("create D: " + layeredStore + ":/layer/d-a"); + avmService.createDirectory(layeredStore + ":/layer", "d-a"); + + recursiveList(baseStore); + recursiveList(layeredStore); + + AVMNodeDescriptor layeredNodeDesc = avmService.lookup(-1, layeredStore + ":/layer/d-a"); + AVMNodeDescriptor baseNodeDesc = avmService.lookup(-1, baseStore + ":/d-a"); + NodeRef layeredNodeRef = AVMNodeConverter.ToNodeRef(-1, layeredNodeDesc.getPath()); + + // set DELETE permission on directory in layer + System.out.println("set P (DELETE): " + layeredStore + ":/layer/d-a"); + checkHeadPermissionNotSet(layeredNodeDesc, "andy", PermissionService.DELETE, true); + permissionService.setPermission(layeredNodeRef, "andy", PermissionService.DELETE, true); + checkHeadPermission(layeredNodeDesc, "andy", PermissionService.DELETE, true); + + // set WRITE permission on directory in layer + System.out.println("set P (WRITE): " + layeredStore + ":/layer/d-a"); + checkHeadPermissionNotSet(layeredNodeDesc, "andy", PermissionService.WRITE, true); + permissionService.setPermission(layeredNodeRef, "andy", PermissionService.WRITE, true); + checkHeadPermission(layeredNodeDesc, "andy", PermissionService.WRITE, true); + + List diffs = avmSyncService.compare(-1, layeredStore + ":/layer", -1, baseStore + ":/", null); + assertEquals("["+layeredStore+":/layer/d-a[-1] > "+baseStore+":/d-a[-1]]", diffs.toString()); + assertEquals(1, diffs.size()); + + recursiveList(baseStore); + recursiveList(layeredStore); + + // snapshot layer, update main from layer, snapshot main + System.out.println("snapshot: layer"); + avmService.createSnapshot(layeredStore, null, null); + System.out.println("update: main from layer"); + avmSyncService.update(diffs, null, false, false, false, false, null, null); + System.out.println("snapshot: main"); + avmService.createSnapshot(baseStore, null, null); + + recursiveList(baseStore); + recursiveList(layeredStore); + + // flatten + System.out.println("flatten: layer to main"); + avmSyncService.flatten(layeredStore + ":/layer", baseStore + ":/"); + + recursiveList(baseStore); + recursiveList(layeredStore); + + diffs = avmSyncService.compare(-1, layeredStore + ":/layer", -1, baseStore + ":/", null); + assertEquals(0, diffs.size()); + + // check that the WRITE and DELETE permissions are still set in main (and appears in layer) + baseNodeDesc = avmService.lookup(-1, baseStore + ":/d-a"); + checkHeadPermission(baseNodeDesc, "andy", PermissionService.DELETE, true); + checkHeadPermission(baseNodeDesc, "andy", PermissionService.WRITE, true); + + layeredNodeDesc = avmService.lookup(-1, layeredStore + ":/layer/d-a"); + checkHeadPermission(layeredNodeDesc, "andy", PermissionService.DELETE, true); + checkHeadPermission(layeredNodeDesc, "andy", PermissionService.WRITE, true); + + // check that directory in layer is the same as the one from main + assertEquals(baseNodeDesc, layeredNodeDesc); + + // remove one of the directory permissions + + // delete DELETE directory permission in layer + System.out.println("delete P (DELETE): " + layeredStore + ":/layer/d-a"); + checkHeadPermission(layeredNodeDesc, "andy", PermissionService.DELETE, true); + permissionService.deletePermission(layeredNodeRef, "andy", PermissionService.DELETE); + checkHeadPermissionNotSet(layeredNodeDesc, "andy", PermissionService.DELETE, true); + + recursiveList(baseStore); + recursiveList(layeredStore); + + diffs = avmSyncService.compare(-1, layeredStore + ":/layer", -1, baseStore + ":/", null); + assertEquals("["+layeredStore+":/layer/d-a[-1] > "+baseStore+":/d-a[-1]]", diffs.toString()); + assertEquals(1, diffs.size()); + + // snapshot layer, update main from layer, snapshot main + System.out.println("snapshot: layer"); + avmService.createSnapshot(layeredStore, null, null); + System.out.println("update: main from layer"); + avmSyncService.update(diffs, null, false, false, false, false, null, null); + System.out.println("snapshot: main"); + avmService.createSnapshot(baseStore, null, null); + + recursiveList(baseStore); + recursiveList(layeredStore); + + // check that the DELETE permission is no longer set in main + baseNodeDesc = avmService.lookup(-1, baseStore + ":/d-a"); + checkHeadPermissionNotSet(baseNodeDesc, "andy", PermissionService.DELETE, true); + + // flatten + System.out.println("flatten: layer to main"); + avmSyncService.flatten(layeredStore + ":/layer", baseStore + ":/"); + + recursiveList(baseStore); + recursiveList(layeredStore); + + diffs = avmSyncService.compare(-1, layeredStore + ":/layer", -1, baseStore + ":/", null); + assertEquals(0, diffs.size()); + + // check that the WRITE permission is still set in main (and appears in layer) + // check that the DELETE permission is not set in main (or layer) + baseNodeDesc = avmService.lookup(-1, baseStore + ":/d-a"); + checkHeadPermission(baseNodeDesc, "andy", PermissionService.WRITE, true); + checkHeadPermissionNotSet(baseNodeDesc, "andy", PermissionService.DELETE, true); + + layeredNodeDesc = avmService.lookup(-1, layeredStore + ":/layer/d-a"); + checkHeadPermission(layeredNodeDesc, "andy", PermissionService.WRITE, true); + checkHeadPermissionNotSet(layeredNodeDesc, "andy", PermissionService.DELETE, true); + + // check that directory in layer is the same as the one from main + assertEquals(baseNodeDesc, layeredNodeDesc); + } + catch (Throwable t) + { + t.printStackTrace(); + throw t; + } + finally + { + avmService.purgeStore(baseStore); + avmService.purgeStore(layeredStore); + } + } + + /* + * create directory in layer + * set two directory permissions in layer + * snapshot layer, update back to main, snapshot main + * flatten + * remove one of the existing directory permissions in layer + * set a different directory permission in layer + * snapshot layer, update back to main, snapshot main + * flatten + */ + public void testSimpleDirectoryPermissionDiff6() throws Throwable + { + runAs("admin"); + + String baseStore = "main"; + String layeredStore = "layer"; + + try + { + System.out.println("create store: " + baseStore); + avmService.createStore(baseStore); + + System.out.println("create store: " + layeredStore); + avmService.createStore(layeredStore); + + System.out.println("create LD: " + layeredStore + ":/layer -> " + baseStore + ":/"); + avmService.createLayeredDirectory(baseStore + ":/", layeredStore + ":/", "layer"); + + // create directory in layer + System.out.println("create D: " + layeredStore + ":/layer/d-a"); + avmService.createDirectory(layeredStore + ":/layer", "d-a"); + + recursiveList(baseStore); + recursiveList(layeredStore); + + AVMNodeDescriptor layeredNodeDesc = avmService.lookup(-1, layeredStore + ":/layer/d-a"); + AVMNodeDescriptor baseNodeDesc = avmService.lookup(-1, baseStore + ":/d-a"); + NodeRef layeredNodeRef = AVMNodeConverter.ToNodeRef(-1, layeredNodeDesc.getPath()); + + // set DELETE permission on directory in layer + System.out.println("set P (DELETE): " + layeredStore + ":/layer/d-a"); + checkHeadPermissionNotSet(layeredNodeDesc, "andy", PermissionService.DELETE, true); + permissionService.setPermission(layeredNodeRef, "andy", PermissionService.DELETE, true); + checkHeadPermission(layeredNodeDesc, "andy", PermissionService.DELETE, true); + + // set WRITE permission on directory in layer + System.out.println("set P (WRITE): " + layeredStore + ":/layer/d-a"); + checkHeadPermissionNotSet(layeredNodeDesc, "andy", PermissionService.WRITE, true); + permissionService.setPermission(layeredNodeRef, "andy", PermissionService.WRITE, true); + checkHeadPermission(layeredNodeDesc, "andy", PermissionService.WRITE, true); + + List diffs = avmSyncService.compare(-1, layeredStore + ":/layer", -1, baseStore + ":/", null); + assertEquals("["+layeredStore+":/layer/d-a[-1] > "+baseStore+":/d-a[-1]]", diffs.toString()); + assertEquals(1, diffs.size()); + + recursiveList(baseStore); + recursiveList(layeredStore); + + // snapshot layer, update main from layer, snapshot main + System.out.println("snapshot: layer"); + avmService.createSnapshot(layeredStore, null, null); + System.out.println("update: main from layer"); + avmSyncService.update(diffs, null, false, false, false, false, null, null); + System.out.println("snapshot: main"); + avmService.createSnapshot(baseStore, null, null); + + recursiveList(baseStore); + recursiveList(layeredStore); + + // flatten + System.out.println("flatten: layer to main"); + avmSyncService.flatten(layeredStore + ":/layer", baseStore + ":/"); + + recursiveList(baseStore); + recursiveList(layeredStore); + + diffs = avmSyncService.compare(-1, layeredStore + ":/layer", -1, baseStore + ":/", null); + assertEquals(0, diffs.size()); + + // check that the WRITE and DELETE permissions are still set in main (and appears in layer) + baseNodeDesc = avmService.lookup(-1, baseStore + ":/d-a"); + checkHeadPermission(baseNodeDesc, "andy", PermissionService.DELETE, true); + checkHeadPermission(baseNodeDesc, "andy", PermissionService.WRITE, true); + + layeredNodeDesc = avmService.lookup(-1, layeredStore + ":/layer/d-a"); + checkHeadPermission(layeredNodeDesc, "andy", PermissionService.DELETE, true); + checkHeadPermission(layeredNodeDesc, "andy", PermissionService.WRITE, true); + + // check that directory in layer is the same as the one from main + assertEquals(baseNodeDesc, layeredNodeDesc); + + // remove one of the directory permissions + + // delete DELETE directory permission in layer + System.out.println("delete P (DELETE): " + layeredStore + ":/layer/d-a"); + checkHeadPermission(layeredNodeDesc, "andy", PermissionService.DELETE, true); + permissionService.deletePermission(layeredNodeRef, "andy", PermissionService.DELETE); + checkHeadPermissionNotSet(layeredNodeDesc, "andy", PermissionService.DELETE, true); + + // set READ permission on directory in layer + System.out.println("set P (READ): " + layeredStore + ":/layer/d-a"); + checkHeadPermissionNotSet(layeredNodeDesc, "andy", PermissionService.READ, true); + permissionService.setPermission(layeredNodeRef, "andy", PermissionService.READ, true); + checkHeadPermission(layeredNodeDesc, "andy", PermissionService.READ, true); + + recursiveList(baseStore); + recursiveList(layeredStore); + + diffs = avmSyncService.compare(-1, layeredStore + ":/layer", -1, baseStore + ":/", null); + assertEquals("["+layeredStore+":/layer/d-a[-1] > "+baseStore+":/d-a[-1]]", diffs.toString()); + assertEquals(1, diffs.size()); + + // snapshot layer, update main from layer, snapshot main + System.out.println("snapshot: layer"); + avmService.createSnapshot(layeredStore, null, null); + System.out.println("update: main from layer"); + avmSyncService.update(diffs, null, false, false, false, false, null, null); + System.out.println("snapshot: main"); + avmService.createSnapshot(baseStore, null, null); + + recursiveList(baseStore); + recursiveList(layeredStore); + + // check that the DELETE permission is no longer set in main + // check that the READ permission is now set in main + baseNodeDesc = avmService.lookup(-1, baseStore + ":/d-a"); + checkHeadPermissionNotSet(baseNodeDesc, "andy", PermissionService.DELETE, true); + checkHeadPermission(baseNodeDesc, "andy", PermissionService.READ, true); + + // flatten + System.out.println("flatten: layer to main"); + avmSyncService.flatten(layeredStore + ":/layer", baseStore + ":/"); + + recursiveList(baseStore); + recursiveList(layeredStore); + + diffs = avmSyncService.compare(-1, layeredStore + ":/layer", -1, baseStore + ":/", null); + assertEquals(0, diffs.size()); + + // check that the WRITE & READ permissions are set in main (and appear in layer) + // check that the DELETE permission is not set in main (or layer) + baseNodeDesc = avmService.lookup(-1, baseStore + ":/d-a"); + checkHeadPermission(baseNodeDesc, "andy", PermissionService.WRITE, true); + checkHeadPermission(baseNodeDesc, "andy", PermissionService.READ, true); + checkHeadPermissionNotSet(baseNodeDesc, "andy", PermissionService.DELETE, true); + + layeredNodeDesc = avmService.lookup(-1, layeredStore + ":/layer/d-a"); + checkHeadPermission(layeredNodeDesc, "andy", PermissionService.WRITE, true); + checkHeadPermission(layeredNodeDesc, "andy", PermissionService.WRITE, true); + checkHeadPermissionNotSet(layeredNodeDesc, "andy", PermissionService.DELETE, true); + + // check that directory in layer is the same as the one from main + assertEquals(baseNodeDesc, layeredNodeDesc); + } + catch (Throwable t) + { + t.printStackTrace(); + throw t; + } + finally + { + avmService.purgeStore(baseStore); + avmService.purgeStore(layeredStore); + } + } private void checkHeadPermissionForPath(String path, String authority, String permission, boolean allow, String[] excludes) { @@ -2214,7 +3252,7 @@ public class AVMServicePermissionsTest extends TestCase DbAccessControlList acl = avmACLDAO.getAccessControlList(nodeRef); System.out.println(path); System.out.println("\t => Ind=" - + desc.getIndirection() + "Deleted,=" + desc.isDeleted() + ",LD=" + desc.isLayeredDirectory() + ",LF=" + desc.isLayeredFile() + ",PD=" + desc.isPlainDirectory() + + desc.getIndirection() + ",Deleted=" + desc.isDeleted() + ",LD=" + desc.isLayeredDirectory() + ",LF=" + desc.isLayeredFile() + ",PD=" + desc.isPlainDirectory() + ",PF=" + desc.isPlainFile() + ",Primary=" + desc.isPrimary()); System.out.println("\t => " + acl); } @@ -2739,4 +3777,62 @@ public class AVMServicePermissionsTest extends TestCase avmService.purgeStore(storeName + "-a-"); } } + + /** + * Helper to write a recursive listing of latest version of an AVMStore. + * @param repoName The name of the AVMStore. + */ + protected void recursiveList(String store) + { + String list = recursiveList(store, -1, true); + System.out.println(store+":"); + System.out.println(list); + } + + /** + * Helper to write a recursive listing of an AVMStore at a given version. + * @param repoName The name of the AVMStore. + * @param version The version to look under. + */ + protected String recursiveList(String repoName, int version, boolean followLinks) + { + return recursiveList(repoName + ":/", version, 0, followLinks); + } + + /** + * Recursive list the given path. + * @param path The path. + * @param version The version. + * @param indent The current indent level. + */ + protected String recursiveList(String path, int version, int indent, boolean followLinks) + { + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < indent; i++) + { + builder.append(' '); + } + builder.append(path.substring(path.lastIndexOf('/') + 1)); + builder.append(' '); + AVMNodeDescriptor desc = avmService.lookup(version, path, true); + builder.append(desc.toString()); + builder.append(" - "); + + AVMNode layeredNode = avmNodeDAO.getByID(desc.getId()); + DbAccessControlList acl = layeredNode.getAcl(); + builder.append(acl); + + builder.append('\n'); + if (desc.getType() == AVMNodeType.PLAIN_DIRECTORY || + (desc.getType() == AVMNodeType.LAYERED_DIRECTORY && followLinks)) + { + String basename = path.endsWith("/") ? path : path + "/"; + Map listing = avmService.getDirectoryListing(version, path); + for (String name : listing.keySet()) + { + builder.append(recursiveList(basename + name, version, indent + 2, followLinks)); + } + } + return builder.toString(); + } } diff --git a/source/java/org/alfresco/repo/avm/AVMServiceTest.java b/source/java/org/alfresco/repo/avm/AVMServiceTest.java index f0423aa491..e7208eb76f 100644 --- a/source/java/org/alfresco/repo/avm/AVMServiceTest.java +++ b/source/java/org/alfresco/repo/avm/AVMServiceTest.java @@ -205,6 +205,10 @@ public class AVMServiceTest extends AVMServiceTestBase e.printStackTrace(); throw e; } + finally + { + fService.purgeStore("I have spaces"); + } } public void testHeadPathsInLayers() throws Exception @@ -234,6 +238,11 @@ public class AVMServiceTest extends AVMServiceTestBase e.printStackTrace(); throw e; } + finally + { + fService.purgeStore("user"); + fService.purgeStore("sandbox"); + } } /** @@ -280,6 +289,8 @@ public class AVMServiceTest extends AVMServiceTestBase fLockingService.removeStoreLocks("main"); fLockingService.removeWebProject("main"); authService.authenticate("admin", "admin".toCharArray()); + + fService.purgeStore("test"); } } @@ -489,6 +500,10 @@ public class AVMServiceTest extends AVMServiceTestBase e.printStackTrace(); throw e; } + finally + { + fService.purgeStore("layer"); + } } public void testBranchLayerSnapshot() throws Exception @@ -524,6 +539,11 @@ public class AVMServiceTest extends AVMServiceTestBase e.printStackTrace(); throw e; } + finally + { + fService.purgeStore("layer"); + fService.purgeStore("branch"); + } } /** @@ -1245,6 +1265,10 @@ public class AVMServiceTest extends AVMServiceTestBase e.printStackTrace(); throw e; } + finally + { + fService.purgeStore("branch"); + } } /** @@ -1266,6 +1290,10 @@ public class AVMServiceTest extends AVMServiceTestBase e.printStackTrace(); throw e; } + finally + { + fService.purgeStore("foo"); + } } /** @@ -1761,6 +1789,10 @@ public class AVMServiceTest extends AVMServiceTestBase e.printStackTrace(System.err); throw e; } + finally + { + fService.purgeStore("layer"); + } } /** @@ -1810,6 +1842,10 @@ public class AVMServiceTest extends AVMServiceTestBase e.printStackTrace(); throw e; } + finally + { + fService.purgeStore("area"); + } } /** @@ -1858,6 +1894,10 @@ public class AVMServiceTest extends AVMServiceTestBase e.printStackTrace(); throw e; } + finally + { + fService.purgeStore("area"); + } } /** @@ -1898,6 +1938,10 @@ public class AVMServiceTest extends AVMServiceTestBase e.printStackTrace(System.err); throw e; } + finally + { + fService.purgeStore("source"); + } } /** @@ -1945,6 +1989,11 @@ public class AVMServiceTest extends AVMServiceTestBase e.printStackTrace(System.err); throw e; } + finally + { + fService.purgeStore("foo-staging"); + fService.purgeStore("area"); + } } /** @@ -2145,6 +2194,11 @@ public class AVMServiceTest extends AVMServiceTestBase e.printStackTrace(System.err); throw e; } + finally + { + fService.purgeStore("source"); + fService.purgeStore("dest"); + } } /** @@ -2394,6 +2448,10 @@ public class AVMServiceTest extends AVMServiceTestBase e.printStackTrace(System.err); throw e; } + finally + { + fService.purgeStore("layer"); + } } /** @@ -3539,9 +3597,8 @@ public class AVMServiceTest extends AVMServiceTestBase setupBasicTree(); fService.createStore("second"); List repos = fService.getStores(); - assertEquals(2, repos.size()); - System.out.println(repos.get(0)); - System.out.println(repos.get(1)); + assertTrue(checkStoreExists("main", repos)); + assertTrue(checkStoreExists("second", repos)); fService.createBranch(-1, "main:/", "second:/", "main"); fService.createSnapshot("second", null, null); System.out.println(recursiveList("second", -1, true)); @@ -3563,6 +3620,22 @@ public class AVMServiceTest extends AVMServiceTestBase e.printStackTrace(System.err); throw e; } + finally + { + fService.purgeStore("second"); + } + } + + private boolean checkStoreExists(String storeName, List stores) + { + for (AVMStoreDescriptor store : stores) + { + if (store.getName().equals(storeName)) + { + return true; + } + } + return false; } /** @@ -3627,6 +3700,10 @@ public class AVMServiceTest extends AVMServiceTestBase e.printStackTrace(System.err); throw e; } + finally + { + fService.purgeStore("second"); + } } /** @@ -5154,7 +5231,6 @@ public class AVMServiceTest extends AVMServiceTestBase fService.createStore("second"); fService.setStoreProperty("second", QName.createQName("", ".dns.alice"), new PropertyValue(null, "alice-space")); Map> matches = fService.queryStoresPropertyKeys(QName.createQName("", ".dns.%")); - assertEquals(2, matches.size()); assertEquals(1, matches.get("main").size()); assertEquals(1, matches.get("second").size()); assertEquals("alice-preview", matches.get("main").get(QName.createQName(null, ".dns.alice--preview")).getStringValue()); @@ -5165,5 +5241,9 @@ public class AVMServiceTest extends AVMServiceTestBase e.printStackTrace(System.err); } + finally + { + fService.purgeStore("second"); + } } } diff --git a/source/java/org/alfresco/repo/avm/AVMServiceTestBase.java b/source/java/org/alfresco/repo/avm/AVMServiceTestBase.java index cc2b1029d0..4957fd41d5 100644 --- a/source/java/org/alfresco/repo/avm/AVMServiceTestBase.java +++ b/source/java/org/alfresco/repo/avm/AVMServiceTestBase.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2007 Alfresco Software Limited. + * Copyright (C) 2005-2008 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 @@ -24,10 +24,11 @@ package org.alfresco.repo.avm; import java.io.IOException; -import java.util.List; import java.util.Map; import java.util.TreeMap; +import junit.framework.TestCase; + import org.alfresco.model.ContentModel; import org.alfresco.repo.content.MimetypeMap; import org.alfresco.repo.search.AVMSnapShotTriggeredIndexingMethodInterceptor; @@ -35,7 +36,6 @@ import org.alfresco.repo.search.IndexerAndSearcher; import org.alfresco.repo.search.impl.lucene.LuceneQueryParser; import org.alfresco.service.cmr.avm.AVMNodeDescriptor; import org.alfresco.service.cmr.avm.AVMService; -import org.alfresco.service.cmr.avm.AVMStoreDescriptor; import org.alfresco.service.cmr.avm.locking.AVMLockingService; import org.alfresco.service.cmr.avmsync.AVMSyncService; import org.alfresco.service.cmr.repository.ContentWriter; @@ -47,8 +47,6 @@ import org.alfresco.service.cmr.security.AuthenticationService; import org.alfresco.service.transaction.TransactionService; import org.springframework.context.support.FileSystemXmlApplicationContext; -import junit.framework.TestCase; - /** * Base class for AVMService tests. * @author britt @@ -161,19 +159,17 @@ public class AVMServiceTestBase extends TestCase } /** - * Cleanup after a test. Purge all stores. Move alf_data - * directory aside. + * Cleanup after a test. Purge main store. */ @Override protected void tearDown() throws Exception { long now = System.currentTimeMillis(); System.out.println("Timing: " + (now - fStartTime) + "ms"); - List descriptors = fService.getStores(); - for (AVMStoreDescriptor desc : descriptors) - { - fService.purgeStore(desc.getName()); - } + + if (fService.getStore("main") != null) { fService.purgeStore("main"); } + + // Move alf_data directory aside. // fContext.close(); // File alfData = new File("alf_data"); // File target = new File("alf_data" + now); diff --git a/source/java/org/alfresco/repo/avm/AVMSyncServiceImpl.java b/source/java/org/alfresco/repo/avm/AVMSyncServiceImpl.java index dc043fa1bb..655de063e6 100644 --- a/source/java/org/alfresco/repo/avm/AVMSyncServiceImpl.java +++ b/source/java/org/alfresco/repo/avm/AVMSyncServiceImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2007 Alfresco Software Limited. + * Copyright (C) 2005-2008 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 @@ -31,8 +31,9 @@ import java.util.Map; import java.util.Set; import org.alfresco.repo.domain.DbAccessControlList; -import org.alfresco.repo.domain.hibernate.DbAccessControlListImpl; +import org.alfresco.repo.domain.PropertyValue; import org.alfresco.repo.security.permissions.ACLCopyMode; +import org.alfresco.repo.security.permissions.ACLType; import org.alfresco.service.cmr.avm.AVMBadArgumentException; import org.alfresco.service.cmr.avm.AVMNodeDescriptor; import org.alfresco.service.cmr.avm.AVMNotFoundException; @@ -40,6 +41,10 @@ import org.alfresco.service.cmr.avm.AVMService; import org.alfresco.service.cmr.avmsync.AVMDifference; import org.alfresco.service.cmr.avmsync.AVMSyncException; import org.alfresco.service.cmr.avmsync.AVMSyncService; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.security.AccessPermission; +import org.alfresco.service.cmr.security.PermissionService; +import org.alfresco.service.namespace.QName; import org.alfresco.util.NameMatcher; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -63,6 +68,11 @@ public class AVMSyncServiceImpl implements AVMSyncService * The AVMRepository. */ private AVMRepository fAVMRepository; + + /** + * The PermissionService + */ + private PermissionService fPermissionService; /** * Do nothing constructor. @@ -84,6 +94,11 @@ public class AVMSyncServiceImpl implements AVMSyncService { fAVMRepository = avmRepository; } + + public void setPermissionService(PermissionService service) + { + fPermissionService = service; + } /** * Get a difference list between two corresponding node trees. @@ -132,7 +147,7 @@ public class AVMSyncServiceImpl implements AVMSyncService else { // Invoke the recursive implementation. - compare(srcVersion, srcDesc, dstVersion, dstDesc, result, excluder); + compare(srcVersion, srcDesc, dstVersion, dstDesc, result, excluder, true); } return result; } @@ -146,7 +161,7 @@ public class AVMSyncServiceImpl implements AVMSyncService */ private void compare(int srcVersion, AVMNodeDescriptor srcDesc, int dstVersion, AVMNodeDescriptor dstDesc, - List result, NameMatcher excluder) + List result, NameMatcher excluder, boolean firstLevel) { // Determine how the source and destination nodes differ. if (excluder != null && (excluder.matches(srcDesc.getPath()) || @@ -154,7 +169,7 @@ public class AVMSyncServiceImpl implements AVMSyncService { return; } - int diffCode = compareOne(srcDesc, dstDesc); + int diffCode = compareOne(srcDesc, dstDesc, false); switch (diffCode) { case AVMDifference.SAME : @@ -179,6 +194,33 @@ public class AVMSyncServiceImpl implements AVMSyncService if (srcDesc.isLayeredDirectory() && srcDesc.getIndirection().equals(dstDesc.getPath()) && srcVersion < 0 && dstVersion < 0) { + // skip firstLevel (root) + if (! firstLevel) + { + // compare directory itself - eg. for an ACL change + int dirDiffCode = compareOne(srcDesc, dstDesc, true); + switch (dirDiffCode) + { + case AVMDifference.OLDER : + case AVMDifference.NEWER : + case AVMDifference.CONFLICT : + { + result.add(new AVMDifference(srcVersion, srcDesc.getPath(), + dstVersion, dstDesc.getPath(), + dirDiffCode)); + return; // short circuit + } + case AVMDifference.SAME : + { + break; + } + default : + { + throw new AVMSyncException("Invalid Difference Code " + dirDiffCode + " - Internal Error."); + } + } + } + // Get only a direct listing, since that's all that can be different. Map srcList = fAVMService.getDirectoryListingDirect(srcDesc, true); @@ -213,7 +255,7 @@ public class AVMSyncServiceImpl implements AVMSyncService // Otherwise recursively invoke. compare(srcVersion, srcChild, dstVersion, dstChild, - result, excluder); + result, excluder, false); } return; } @@ -221,6 +263,33 @@ public class AVMSyncServiceImpl implements AVMSyncService if (dstDesc.isLayeredDirectory() && dstDesc.getIndirection().equals(srcDesc.getPath()) && srcVersion < 0 && dstVersion < 0) { + // skip firstLevel (root) + if (! firstLevel) + { + // compare directory itself - eg. for an ACL change + int dirDiffCode = compareOne(srcDesc, dstDesc, true); + switch (dirDiffCode) + { + case AVMDifference.OLDER : + case AVMDifference.NEWER : + case AVMDifference.CONFLICT : + { + result.add(new AVMDifference(srcVersion, srcDesc.getPath(), + dstVersion, dstDesc.getPath(), + dirDiffCode)); + return; // short circuit + } + case AVMDifference.SAME : + { + break; + } + default : + { + throw new AVMSyncException("Invalid Difference Code " + dirDiffCode + " - Internal Error."); + } + } + } + // Get direct content of destination. Map dstList = fAVMService.getDirectoryListingDirect(dstDesc, true); @@ -254,7 +323,7 @@ public class AVMSyncServiceImpl implements AVMSyncService // Otherwise, recursively invoke. compare(srcVersion, srcChild, dstVersion, dstChild, - result, excluder); + result, excluder, false); } return; } @@ -286,7 +355,7 @@ public class AVMSyncServiceImpl implements AVMSyncService // Otherwise recursive invocation. compare(srcVersion, srcChild, dstVersion, dstChild, - result, excluder); + result, excluder, false); } // Iterate over the destination. for (String name : dstList.keySet()) @@ -312,7 +381,7 @@ public class AVMSyncServiceImpl implements AVMSyncService } default : { - throw new AVMSyncException("Invalid Difference Code, Internal Error."); + throw new AVMSyncException("Invalid Difference Code " + diffCode + " - Internal Error."); } } } @@ -404,73 +473,15 @@ public class AVMSyncServiceImpl implements AVMSyncService int diffCode = AVMDifference.NEWER; if (dstDesc != null) { - diffCode = compareOne(srcDesc, dstDesc); + diffCode = compareOne(srcDesc, dstDesc, false); } // Keep track of stores updated so that they can all be snapshotted // at end of update. String dstPath = diff.getDestinationPath(); destStores.add(dstPath.substring(0, dstPath.indexOf(':'))); - // Dispatch. - switch (diffCode) - { - case AVMDifference.SAME : - { - // Nada to do. - continue; - } - case AVMDifference.NEWER : - { - // You can't delete what isn't there. - linkIn(dstParts[0], dstParts[1], srcDesc, excluder, dstDesc != null && !dstDesc.isDeleted()); - continue; - } - case AVMDifference.OLDER : - { - // You can force it. - if (overrideOlder) - { - linkIn(dstParts[0], dstParts[1], srcDesc, excluder, !dstDesc.isDeleted()); - continue; - } - // You can ignore it. - if (ignoreOlder) - { - continue; - } - // Or it's an error. - throw new AVMSyncException("Older version prevents update."); - } - case AVMDifference.CONFLICT : - { - // You can force it. - if (overrideConflicts) - { - linkIn(dstParts[0], dstParts[1], srcDesc, excluder, true); - continue; - } - // You can ignore it. - if (ignoreConflicts) - { - continue; - } - // Or it's an error. - throw new AVMSyncException("Conflict prevents update."); - } - case AVMDifference.DIRECTORY : - { - // You can only ignore this. - if (ignoreConflicts) - { - continue; - } - // Otherwise it's an error. - throw new AVMSyncException("Directory conflict prevents update."); - } - default : - { - throw new AVMSyncException("Invalid Difference Code: Internal Error."); - } - } + + dispatchUpdate(diffCode, dstParts[0], dstParts[1], excluder, srcDesc, dstDesc, + ignoreConflicts, ignoreOlder, overrideConflicts, overrideOlder); } for (String storeName : destStores) { @@ -481,6 +492,75 @@ public class AVMSyncServiceImpl implements AVMSyncService fgLogger.debug("Raw Update: " + (System.currentTimeMillis() - start)); } } + + private void dispatchUpdate(int diffCode, String parentPath, String name, NameMatcher excluder, AVMNodeDescriptor srcDesc, AVMNodeDescriptor dstDesc, + boolean ignoreConflicts, boolean ignoreOlder, boolean overrideConflicts, boolean overrideOlder) + { + // Dispatch. + switch (diffCode) + { + case AVMDifference.SAME : + { + // Nada to do. + return; + } + case AVMDifference.NEWER : + { + // You can't delete what isn't there. + linkIn(parentPath, name, srcDesc, excluder, dstDesc != null && !dstDesc.isDeleted()); + return; + } + case AVMDifference.OLDER : + { + // You can force it. + if (overrideOlder) + { + linkIn(parentPath, name, srcDesc, excluder, !dstDesc.isDeleted()); + return; + } + // You can ignore it. + if (ignoreOlder) + { + return; + } + // Or it's an error. + throw new AVMSyncException("Older version prevents update."); + } + case AVMDifference.CONFLICT : + { + // You can force it. + if (overrideConflicts) + { + linkIn(parentPath, name, srcDesc, excluder, true); + return; + } + // You can ignore it. + if (ignoreConflicts) + { + return; + } + // Or it's an error. + throw new AVMSyncException("Conflict prevents update."); + } + case AVMDifference.DIRECTORY : + { + int dirDiffCode = compareOne(srcDesc, dstDesc, true); + if (dirDiffCode == AVMDifference.DIRECTORY) + { + // error + throw new AVMSyncException("Unexpected diff code: " + dirDiffCode); + } + + dispatchUpdate(dirDiffCode, parentPath, name, excluder, srcDesc, dstDesc, + ignoreConflicts, ignoreOlder, overrideConflicts, overrideOlder); + return; + } + default : + { + throw new AVMSyncException("Invalid Difference Code " + diffCode + " - Internal Error."); + } + } + } /** * Do the actual work of connecting nodes to the destination tree. @@ -609,7 +689,7 @@ public class AVMSyncServiceImpl implements AVMSyncService recursiveCopy(newParentDesc, entry.getKey(), entry.getValue(), excluder); } } - + /** * The workhorse of comparison and updating. Determine the versioning relationship * of two nodes. @@ -617,7 +697,7 @@ public class AVMSyncServiceImpl implements AVMSyncService * @param dstDesc Descriptor for the destination node. * @return One of SAME, OLDER, NEWER, CONFLICT, DIRECTORY */ - private int compareOne(AVMNodeDescriptor srcDesc, AVMNodeDescriptor dstDesc) + private int compareOne(AVMNodeDescriptor srcDesc, AVMNodeDescriptor dstDesc, boolean compareDir) { if (srcDesc == null) { @@ -625,21 +705,17 @@ public class AVMSyncServiceImpl implements AVMSyncService } if (srcDesc.getId() == dstDesc.getId()) { + // Identical return AVMDifference.SAME; } - // Matched directories that are not identical are nominally in conflict - // but get their own special difference code for comparison logic. The DIRECTORY - // difference code never gets returned to callers of compare. - if (srcDesc.isDirectory() && dstDesc.isDirectory()) - { - return AVMDifference.DIRECTORY; - } + // Check for mismatched fundamental types. if ((srcDesc.isDirectory() && dstDesc.isFile()) || (srcDesc.isFile() && dstDesc.isDirectory())) { return AVMDifference.CONFLICT; } + // A deleted node on either side means uniform handling because // a deleted node can be the descendent of any other type of node. if (srcDesc.isDeleted() || dstDesc.isDeleted()) @@ -660,6 +736,58 @@ public class AVMSyncServiceImpl implements AVMSyncService // Must be a conflict. return AVMDifference.CONFLICT; } + + if (srcDesc.isDirectory() && dstDesc.isDirectory()) + { + // Both source and destination are both some kind of directory. + if (! compareDir) + { + // note: the DIRECTORY difference code never gets returned to external callers of compare. + return AVMDifference.DIRECTORY; + } + else + { + // Matched directories that are not identical should be compared (initially) based on ACLs to see if they're newer, older or in conflict + + if ((srcDesc.isLayeredDirectory() && srcDesc.getIndirection().equals(dstDesc.getPath())) || + (dstDesc.isLayeredDirectory() && dstDesc.getIndirection().equals(srcDesc.getPath()))) + { + // Either: Source is a layered directory and points at the destination plain/layered directory + // Or: Destination is a layered directory and points at the source plain directory + + // Check properties (eg. title/description) + if (compareNodeProps(srcDesc, dstDesc) == AVMDifference.SAME) + { + // Check ACLs + int dirDiffCode = compareACLs(srcDesc, dstDesc); + if (dirDiffCode != AVMDifference.CONFLICT) + { + return dirDiffCode; + } + } + + // drop through to check common ancestor + } + + // Check common ancestor + AVMNodeDescriptor common = fAVMService.getCommonAncestor(srcDesc, dstDesc); + // Conflict case. + if (common == null) + { + return AVMDifference.CONFLICT; + } + if (common.getId() == srcDesc.getId()) + { + return AVMDifference.OLDER; + } + if (common.getId() == dstDesc.getId()) + { + return AVMDifference.NEWER; + } + // They must, finally, be in conflict. + return AVMDifference.CONFLICT; + } + } // At this point both source and destination are both some kind of file. if (srcDesc.isLayeredFile()) { @@ -722,6 +850,156 @@ public class AVMSyncServiceImpl implements AVMSyncService // The must, finally, be in conflict. return AVMDifference.CONFLICT; } + + // compare node properties + private int compareNodeProps(AVMNodeDescriptor srcDesc, AVMNodeDescriptor dstDesc) + { + Map srcProps = fAVMService.getNodeProperties(srcDesc); + Map dstProps = fAVMService.getNodeProperties(dstDesc); + + if (srcProps.size() == dstProps.size()) + { + for (Map.Entry srcEntry : srcProps.entrySet()) + { + PropertyValue srcValue = srcEntry.getValue(); + PropertyValue dstValue = dstProps.get(srcEntry.getKey()); + if ((srcValue == null) && (dstValue == null)) + { + continue; + } + else if ((srcValue != null) && (dstValue != null) && + (srcValue.equals(dstValue))) + { + continue; + } + else + { + return AVMDifference.CONFLICT; + } + } + + return AVMDifference.SAME; + } + + return AVMDifference.CONFLICT; + } + + // compare ACLs + private int compareACLs(AVMNodeDescriptor srcDesc, AVMNodeDescriptor dstDesc) + { + DbAccessControlList srcAcl = getACL(srcDesc.getPath()); + DbAccessControlList dstAcl = getACL(dstDesc.getPath()); + + if ((srcAcl == null) && (dstAcl == null)) + { + return AVMDifference.SAME; + } + else if (srcAcl != null) + { + if ((dstAcl != null) && (srcAcl.getAclId() == dstAcl.getAclId())) + { + return AVMDifference.SAME; + } + + if (srcAcl.getAclType().equals(ACLType.LAYERED)) + { + if ((dstAcl == null) || dstAcl.getAclType().equals(ACLType.SHARED) || dstAcl.getAclType().equals(ACLType.LAYERED) || dstAcl.getAclType().equals(ACLType.DEFINING)) + { + return AVMDifference.SAME; + } + else + { + // TODO review + throw new AVMSyncException("srcAcl type: " + srcAcl.getAclType() + ", unexpected dstAcl type: " + dstAcl.getAclType()); + } + } + else if (srcAcl.getAclType().equals(ACLType.DEFINING)) + { + if ((dstAcl == null) || dstAcl.getAclType().equals(ACLType.SHARED) || dstAcl.getAclType().equals(ACLType.LAYERED)) + { + return AVMDifference.NEWER; + } + else if (dstAcl.getAclType().equals(ACLType.DEFINING)) + { + // compare ACEs + NodeRef srcNodeRef = AVMNodeConverter.ToNodeRef(-1, srcDesc.getPath()); + Set srcSet = fPermissionService.getAllSetPermissions(srcNodeRef); + + NodeRef dstNodeRef = AVMNodeConverter.ToNodeRef(-1, dstDesc.getPath()); + Set dstSet = fPermissionService.getAllSetPermissions(dstNodeRef); + + if (srcSet.size() == dstSet.size()) + { + boolean same = true; + for (AccessPermission srcPerm : srcSet) + { + if (! dstSet.contains(srcPerm)) + { + same = false; + break; + } + } + + if (same) + { + return AVMDifference.SAME; + } + } + } + else + { + // TODO review + throw new AVMSyncException("srcAcl type: " + srcAcl.getAclType() + ", unexpected dstAcl type: " + dstAcl.getAclType()); + } + } + else if (srcAcl.getAclType().equals(ACLType.SHARED)) + { + if ((dstAcl == null) || dstAcl.getAclType().equals(ACLType.SHARED)) + { + // compare ACEs + NodeRef srcNodeRef = AVMNodeConverter.ToNodeRef(-1, srcDesc.getPath()); + Set srcSet = fPermissionService.getAllSetPermissions(srcNodeRef); + + NodeRef dstNodeRef = AVMNodeConverter.ToNodeRef(-1, dstDesc.getPath()); + Set dstSet = fPermissionService.getAllSetPermissions(dstNodeRef); + + if (srcSet.size() == dstSet.size()) + { + boolean same = true; + for (AccessPermission srcPerm : srcSet) + { + if (! dstSet.contains(srcPerm)) + { + same = false; + break; + } + } + + if (same) + { + return AVMDifference.SAME; + } + } + + return AVMDifference.CONFLICT; + } + else + { + // TODO review + throw new AVMSyncException("srcAcl type: " + srcAcl.getAclType() + ", unexpected dstAcl type: " + dstAcl.getAclType()); + } + } + } + else if (srcAcl == null) + { + if (dstAcl != null) + { + return AVMDifference.SAME; + } + } + + return AVMDifference.CONFLICT; + } /** * Flattens a layer so that all all nodes under and including diff --git a/source/java/org/alfresco/repo/avm/AvmBootstrap.java b/source/java/org/alfresco/repo/avm/AvmBootstrap.java index fa1f31cd91..c83c6e4a91 100644 --- a/source/java/org/alfresco/repo/avm/AvmBootstrap.java +++ b/source/java/org/alfresco/repo/avm/AvmBootstrap.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2007 Alfresco Software Limited. + * Copyright (C) 2005-2008 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 @@ -50,6 +50,9 @@ public class AvmBootstrap extends AbstractLifecycleBean private AVMRepository avmRepository; private PermissionService permissionService; + + private AVMSyncServiceImpl avmSyncService; + public AvmBootstrap() { @@ -70,6 +73,11 @@ public class AvmBootstrap extends AbstractLifecycleBean { permissionService = service; } + + public void setAvmSyncService(AVMSyncServiceImpl service) + { + avmSyncService = service; + } /** * Provide a list of {@link Issuer issuers} to bootstrap on context initialization. @@ -93,6 +101,7 @@ public class AvmBootstrap extends AbstractLifecycleBean } avmLockingAwareService.init(); avmRepository.setPermissionService(permissionService); + avmSyncService.setPermissionService(permissionService); } /** NO-OP */ diff --git a/source/java/org/alfresco/repo/domain/hibernate/AbstractPermissionsDaoComponentImpl.java b/source/java/org/alfresco/repo/domain/hibernate/AbstractPermissionsDaoComponentImpl.java index 46a0ffe791..1868d1ba63 100644 --- a/source/java/org/alfresco/repo/domain/hibernate/AbstractPermissionsDaoComponentImpl.java +++ b/source/java/org/alfresco/repo/domain/hibernate/AbstractPermissionsDaoComponentImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2007 Alfresco Software Limited. + * Copyright (C) 2005-2008 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 @@ -26,7 +26,6 @@ package org.alfresco.repo.domain.hibernate; import java.util.ArrayList; import java.util.Collections; -import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -220,6 +219,7 @@ public abstract class AbstractPermissionsDaoComponentImpl implements Permissions default: // Force a copy on write if one is required getACLDAO(nodeRef).forceCopy(nodeRef); + acl = getACLDAO(nodeRef).getAccessControlList(nodeRef); return new CreationReport(acl, Collections. emptyList()); } }