From c67a5c18d21f46c1775882a77d6b5c6e7b6b46d3 Mon Sep 17 00:00:00 2001 From: Derek Hulley Date: Tue, 19 Jan 2010 14:07:10 +0000 Subject: [PATCH] Merged V3.2 to HEAD 17363: Fix to DbNodeServiceImple to allow restored nodes. 17384: Minor comments 17451: Fix ETHREEOH-2751 / ETWOONE-340 - specialising a node through an action doesn't set default values from model 17459: ETHREEOH-2391 - Invite pending task now has lots of properties 17465: Repo side fix for ETHREEOH-3010: Inbound and outbound Mltext multiple property are not converted correctly 17478: Fix ETHREEOH-3340 - WCM - Revert to snapshot failure (fix AVM getListing -> AVNSync compare -> WCM revertSnapshot) 17483: (record only) Merged V3.1 to V3.2 (record-only) 17482: (record-only) due to earlier back-merge 17493: Fix for ETHREEOH-3342: index.recovery.mode example is incorrect 17494: Fix for ETHREEOH-3027: missingFullTextReindexTrigger (from index-recovery-context.xml) job does not work. 17510: Fix for ETHREEOH-1147: Indexing large indices can lead to Java Heap space. 17511: Fix for ETHREEOH-1271: It is possible to add one category more than one time to the same content or space 17513: ETHREEOH_3366: Altered DictionaryDAOImpl so that passing a null QName into getType and getAspect does not result in an NPE 17531: ETHREEOH-1186: Corrected rssfeed.get.js so a user can configure a RSS Feed dashlet that has been placed on their own dashboard 17550: ETHREEOH-2317: Rule not fired when document has no content 17556: Fixed ETHREEOH-1229: Can't delete space that contains "translation without content" 17558: Fix for ETHREEOH-3356: Forms fail to persist if property or association name has an _ (underscore) in it 17572: Changed caching of person NodeRefs so that duplicates are detected better 17573: Fixed UTF-8 for file with encoded chars 17576: LockAcquisitionException message specific to failed release of taken-over lock ___________________________________________________________________ Modified: svn:mergeinfo Merged /alfresco/BRANCHES/V3.2:r17363,17384,17451,17459,17465,17478,17483,17493-17494,17510-17511,17513,17531,17550,17556,17558,17572-17573,17576 git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@18140 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- config/alfresco/core-services-context.xml | 23 +- .../index-recovery-context.xml.sample | 3 + .../messages/patch-service.properties | 3 + .../messages/system-messages.properties | 1 + .../alfresco/patch/patch-services-context.xml | 17 + config/alfresco/repository.properties | 9 +- config/alfresco/version.properties | 2 +- .../invitation-nominated-workflow-model.xml | 80 +- .../repo/avm/AVMServiceLocalTest.java | 6052 +++++++++-------- .../repo/avm/LayeredDirectoryNodeImpl.java | 2 +- .../repo/dictionary/DictionaryDAOImpl.java | 66 +- .../domain/locks/AbstractLockDAOImpl.java | 727 +- .../repo/forms/FormServiceImplTest.java | 8 +- .../node/ContentModelFormProcessor.java | 19 +- .../repo/lock/LockAcquisitionException.java | 7 + .../model/ml/MultilingualDocumentAspect.java | 14 +- .../repo/node/BaseNodeServiceTest.java | 35 +- .../repo/node/FullNodeServiceTest.java | 174 +- .../repo/node/MLPropertyInterceptor.java | 147 +- .../NodeRefPropertyMethodInterceptor.java | 16 +- .../NodeRefPropertyMethodInterceptorTest.java | 9 +- .../repo/node/db/DbNodeServiceImpl.java | 40 +- .../ruletrigger/CreateNodeRuleTrigger.java | 31 +- ...stractLuceneIndexerAndSearcherFactory.java | 162 +- .../repo/search/impl/lucene/LuceneConfig.java | 34 +- .../search/impl/lucene/index/IndexInfo.java | 116 +- .../security/person/PersonServiceImpl.java | 64 +- .../repo/security/person/PersonTest.java | 18 +- 28 files changed, 4343 insertions(+), 3536 deletions(-) diff --git a/config/alfresco/core-services-context.xml b/config/alfresco/core-services-context.xml index c46ce19805..3e78b23f49 100644 --- a/config/alfresco/core-services-context.xml +++ b/config/alfresco/core-services-context.xml @@ -642,8 +642,11 @@ ${lucene.indexer.mergerMergeBlockingFactor} - - ${lucene.indexer.mergerMinMergeDocs} + + ${lucene.indexer.mergerMaxBufferedDocs} + + + ${lucene.indexer.mergerRamBufferSizeMb} @@ -652,8 +655,11 @@ ${lucene.indexer.writerMergeFactor} - - ${lucene.indexer.writerMinMergeDocs} + + ${lucene.indexer.writerMaxBufferedDocs} + + + ${lucene.indexer.writerRamBufferSizeMb} @@ -668,6 +674,15 @@ ${lucene.indexer.maxDocsForInMemoryMerge} + + ${lucene.indexer.maxRamInMbForInMemoryMerge} + + + ${lucene.indexer.maxDocsForInMemoryIndex} + + + ${lucene.indexer.maxRamInMbForInMemoryIndex} + ${lucene.indexer.termIndexInterval} diff --git a/config/alfresco/extension/index-recovery-context.xml.sample b/config/alfresco/extension/index-recovery-context.xml.sample index 76de980518..1a9088af32 100644 --- a/config/alfresco/extension/index-recovery-context.xml.sample +++ b/config/alfresco/extension/index-recovery-context.xml.sample @@ -15,6 +15,9 @@ + + ${alfresco.cluster.name} + diff --git a/config/alfresco/messages/patch-service.properties b/config/alfresco/messages/patch-service.properties index 9c73533789..2d514a57b0 100644 --- a/config/alfresco/messages/patch-service.properties +++ b/config/alfresco/messages/patch-service.properties @@ -286,3 +286,6 @@ patch.fixNameCrcValues.unableToChange=Failed to update the CRC32 value for node patch.personUsagePatch.description=Add person 'cm:sizeCurrent' property (if missing). patch.personUsagePatch.result1=Added 'cm:sizeCurrent' property to {0} people that were missing this property. patch.personUsagePatch.result2=No people were missing the 'cm:sizeCurrent' property. + +patch.redeployNominatedInvitationProcessWithPropsForShare.description=Redeploy nominated invitation workflow +patch.redeployNominatedInvitationProcessWithPropsForShare.result=Nominated invitation workflow redeployed \ No newline at end of file diff --git a/config/alfresco/messages/system-messages.properties b/config/alfresco/messages/system-messages.properties index a62e694849..6431e00ac9 100644 --- a/config/alfresco/messages/system-messages.properties +++ b/config/alfresco/messages/system-messages.properties @@ -24,6 +24,7 @@ system.openoffice.err.connection_remade=The OpenOffice connection was re-establi system.locks.err.failed_to_acquire_lock=Failed to get lock ''{0}'' using token ''{1}''. system.locks.err.lock_resource_missing=Failed to manipulate lock ''{0}'' using token ''{1}''. The lock resource no longer exists. system.locks.err.lock_update_count=Failed to update lock ''{0}'' using token ''{1}''. {2} locks were updated when {3} should have been. +system.locks.err.failed_to_release_lock=Failed to release lock ''{0}'' using token ''{1}''. The lock has expired and been taken by another process. system.locks.err.excl_lock_exists=Failed to get lock ''{0}'' using token ''{1}''. An exclusive lock exists: {2} # Multi-Tenant diff --git a/config/alfresco/patch/patch-services-context.xml b/config/alfresco/patch/patch-services-context.xml index de266089f5..7d5fa8ce94 100644 --- a/config/alfresco/patch/patch-services-context.xml +++ b/config/alfresco/patch/patch-services-context.xml @@ -1992,4 +1992,21 @@ + + + patch.redeployNominatedInvitationProcessWithPropsForShare + patch.redeployNominatedInvitationProcessWithPropsForShare.description + 0 + 4000 + 4001 + + + + jbpm + alfresco/workflow/invitation-nominated_processdefinition.xml + text/xml + + + + diff --git a/config/alfresco/repository.properties b/config/alfresco/repository.properties index 10c7552b82..bba14e857b 100644 --- a/config/alfresco/repository.properties +++ b/config/alfresco/repository.properties @@ -176,14 +176,16 @@ lucene.indexer.maxTypeCacheSize=10000 lucene.indexer.mergerMaxMergeDocs=1000000 lucene.indexer.mergerMergeFactor=5 lucene.indexer.mergerMergeBlockingFactor=1 -lucene.indexer.mergerMinMergeDocs=1000 +lucene.indexer.mergerMaxBufferedDocs=-1 +lucene.indexer.mergerRamBufferSizeMb=16 # # Properties for delta indexes (not this does not affect the final index segment which will be optimised) # Max merge docs only applies to the index building process not the resulting index which will be optimised. # lucene.indexer.writerMaxMergeDocs=1000000 lucene.indexer.writerMergeFactor=5 -lucene.indexer.writerMinMergeDocs=1000 +lucene.indexer.writerMaxBufferedDocs=-1 +lucene.indexer.writerRamBufferSizeMb=16 # # Target number of indexes and deltas in the overall index and what index size to merge in memory # @@ -191,6 +193,9 @@ lucene.indexer.mergerTargetIndexCount=5 lucene.indexer.mergerTargetOverlayCount=5 lucene.indexer.mergerTargetOverlaysBlockingFactor=1 lucene.indexer.maxDocsForInMemoryMerge=10000 +lucene.indexer.maxRamInMbForInMemoryMerge=16 +lucene.indexer.maxDocsForInMemoryIndex=10000 +lucene.indexer.maxRamInMbForInMemoryIndex=16 # # Other lucene properties # diff --git a/config/alfresco/version.properties b/config/alfresco/version.properties index 1918f9ad55..7be41d462d 100644 --- a/config/alfresco/version.properties +++ b/config/alfresco/version.properties @@ -19,4 +19,4 @@ version.build=@build-number@ # Schema number -version.schema=4000 +version.schema=4001 diff --git a/config/alfresco/workflow/invitation-nominated-workflow-model.xml b/config/alfresco/workflow/invitation-nominated-workflow-model.xml index 2f873422ac..99e1b7a75c 100644 --- a/config/alfresco/workflow/invitation-nominated-workflow-model.xml +++ b/config/alfresco/workflow/invitation-nominated-workflow-model.xml @@ -32,6 +32,51 @@ d:text + + d:text + + + + bpm:assignee + inwf:nominatedInvitationStats + + + + + bpm:workflowTask + + inwf:nominatedInvitationStats + + + + + bpm:workflowTask + + inwf:nominatedInvitationStats + + + + + bpm:workflowTask + + inwf:nominatedInvitationStats + + + + + + + + + + d:text + + + d:text + + + d:text + d:text @@ -47,35 +92,8 @@ d:text - - d:text - - - d:text - - - d:text - - - d:text - - - - bpm:assignee - - - - - bpm:workflowTask - - - - bpm:workflowTask - - - - bpm:workflowTask - - - + + + + diff --git a/source/java/org/alfresco/repo/avm/AVMServiceLocalTest.java b/source/java/org/alfresco/repo/avm/AVMServiceLocalTest.java index b7a3d36056..be436e7776 100644 --- a/source/java/org/alfresco/repo/avm/AVMServiceLocalTest.java +++ b/source/java/org/alfresco/repo/avm/AVMServiceLocalTest.java @@ -1,2951 +1,3101 @@ -/* - * Copyright (C) 2005-2009 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; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.io.PrintStream; -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.repo.security.authentication.AuthenticationUtil; -import org.alfresco.service.cmr.avm.AVMNodeDescriptor; -import org.alfresco.service.cmr.avm.AVMNotFoundException; -import org.alfresco.service.cmr.avm.AVMStoreDescriptor; -import org.alfresco.service.cmr.avm.VersionDescriptor; -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.ApplicationContextHelper; -import org.alfresco.util.NameMatcher; -import org.springframework.extensions.surf.util.Pair; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.context.ApplicationContext; - -/** - * Local unit tests of AVM (AVMSyncService & AVMService) - */ -public class AVMServiceLocalTest extends TestCase -{ - private static Log logger = LogFactory.getLog(AVMServiceLocalTest.class); - - /** - * The AVMRemote - can be local (AVMRemoteLocal) or remote (AVMRemote) - */ - protected static AVMRemote fService; - - /** - * The AVMSyncService - can be local (AVMSyncService) or remote (AVMSyncServiceRemote) - */ - protected static AVMSyncService fSyncService; - - /** - * The application context. - */ - protected static ApplicationContext fContext; - - protected static NameMatcher excluder; - - - protected void setUp() throws Exception - { - if (fContext == null) - { - // local (embedded) test setup - fContext = ApplicationContextHelper.getApplicationContext(); - fService = (AVMRemote)fContext.getBean("avmRemote"); - fSyncService = (AVMSyncService)fContext.getBean("AVMSyncService"); - excluder = (NameMatcher) fContext.getBean("globalPathExcluder"); - - AuthenticationService authService = (AuthenticationService)fContext.getBean("AuthenticationService"); - authService.authenticate(AuthenticationUtil.getAdminUserName(), "admin".toCharArray()); - } - - if (fService.getStore("main") == null) - { - fService.createStore("main"); - } - if (fService.getStore("layer") == null) - { - fService.createStore("layer"); - } - } - - @Override - protected void tearDown() throws Exception - { - fService.purgeStore("main"); - fService.purgeStore("layer"); - } - - public void testSetup() throws Exception - { - setUp(); - } - - public void testGetAPath() throws Exception - { - try - { - fService.createStore("test2932"); - fService.createDirectory("test2932:/", "a"); - fService.createFile("test2932:/a", "foo.txt").close(); - AVMNodeDescriptor found = fService.lookup(-1, "test2932:/a/foo.txt"); - Pair path = fService.getAPath(found); - assertEquals(path.getSecond(), "test2932:/a/foo.txt"); - explorePaths("test2932:/"); - } - catch (Exception e) - { - e.printStackTrace(); - throw e; - } - finally - { - fService.purgeStore("test2932"); - } - } - - /** - * Do a simple hello world test. - */ - public void testSimple() throws Throwable - { - try - { - List stores = fService.getStores(); - - for (AVMStoreDescriptor store : stores) - { - if (logger.isDebugEnabled()) { logger.debug(store); } - } - } - catch (Exception e) - { - e.printStackTrace(System.err); - throw e; - } - } - - protected void explorePaths(String path) throws Exception - { - Map listing = fService.getDirectoryListing(-1, path); - for (Map.Entry entry : listing.entrySet()) - { - Pair childPath = fService.getAPath(entry.getValue()); - if (logger.isDebugEnabled()) { logger.debug(childPath); } - if (entry.getValue().isDirectory()) - { - explorePaths(entry.getValue().getPath()); - } - } - } - - /** - * Test reading and writing. - */ - public void testReadWrite() throws Throwable - { - try - { - // Create a test store. - fService.createStore("test2933"); - // Create a directory. - fService.createDirectory("test2933:/", "a"); - // Write out a file. - OutputStream out = - fService.createFile("test2933:/a", "foo.txt"); - byte [] buff = "This is a plain old text file.\n".getBytes(); - out.write(buff); - buff = "It contains text.\n".getBytes(); - out.write(buff); - out.close(); - // Read back that file. - InputStream in = - fService.getFileInputStream(-1, "test2933:/a/foo.txt"); - buff = new byte[1024]; - assertEquals(49, in.read(buff)); - if (logger.isDebugEnabled()) { logger.debug(new String(buff)); } - assertEquals(-1, in.read(buff)); - } - catch (Exception e) - { - e.printStackTrace(System.err); - throw e; - } - finally - { - fService.purgeStore("test2933"); - } - } - - /** - * Another test of reading. - */ - public void testRead() throws Throwable - { - try - { - fService.createStore("froo"); - // Create a file. - byte [] buff = new byte[64]; - for (int i = 0; i < 64; i++) - { - buff[i] = (byte)i; - } - OutputStream out = - fService.createFile("froo:/", "foo.dat"); - out.write(buff, 32, 32); - out.close(); - // Read it back in. - InputStream in = - fService.getFileInputStream(-1, "froo:/foo.dat"); - buff = new byte[1024]; - assertEquals(32, in.read(buff)); - in.close(); - } - catch (Exception e) - { - e.printStackTrace(System.err); - throw e; - } - finally - { - fService.purgeStore("froo"); - } - } - - /** - * Test a call that should return null; - */ - public void testErrorState() throws Throwable - { - try - { - assertNull(fService.lookup(-1, "main:/fizz/fazz")); - } - catch (Exception e) - { - e.printStackTrace(System.err); - throw e; - } - } - - - /** - * Test update to branch - */ - public void testSimpleUpdateBR() throws Throwable - { - try - { - // Create a store. - fService.createStore("froo"); - // Create a directory. - fService.createDirectory("froo:/", "a"); - // Create a file. - fService.createFile("froo:/a", "foo").close(); - // Create another store. - fService.createStore("broo"); - // Create a branch. - fService.createBranch(-1, "froo:/a", "broo:/", "a"); - List diffs = fSyncService.compare(-1, "froo:/a", -1, "broo:/a", null); - assertEquals(0, diffs.size()); - fService.createFile("froo:/a", "bar").close(); - diffs = fSyncService.compare(-1, "froo:/a", -1, "broo:/a", null); - assertEquals(1, diffs.size()); - assertEquals("[froo:/a/bar[-1] > broo:/a/bar[-1]]", diffs.toString()); - // Update. - fSyncService.update(diffs, null, false, false, false, false, "flippy", "Stuff"); - diffs = fSyncService.compare(-1, "froo:/a", -1, "broo:/a", null); - assertEquals(0, diffs.size()); - } - catch (Exception e) - { - e.printStackTrace(); - throw e; - } - finally - { - fService.purgeStore("broo"); - fService.purgeStore("froo"); - } - } - - // - // 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 directory b and file foo in layer - fService.createDirectory("layer:/layer", "b"); - 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:/"); - - fService.createStore("layer2"); - fService.createLayeredDirectory("layer:/layer", "layer2:/", "layer"); - - // create directory c and file foo in layer2 - fService.createDirectory("layer2:/layer/", "c"); - 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("main"); - recursiveList("layer"); - recursiveList("layer2"); - } - catch (Exception e) - { - e.printStackTrace(System.err); - throw e; - } - finally - { - fService.purgeStore("layer2"); - } - } - - public void testSimpleUpdateLD5() throws Exception - { - try - { - logger.debug("created 2 stores: main, layer"); - - fService.createLayeredDirectory("main:/", "layer:/", "layer"); - - logger.debug("created layered dir: layer:/layer -> main:/"); - - fService.createDirectory("layer:/layer", "b"); - - logger.debug("created dir in layer: layer:/layer/b"); - - List diffs = fSyncService.compare(-1, "layer:/layer", -1, "main:/", null); - assertEquals(1, diffs.size()); - assertEquals("[layer:/layer/b[-1] > main:/b[-1]]", diffs.toString()); - - fSyncService.update(diffs, null, false, false, false, false, null, null); - - diffs = fSyncService.compare(-1, "layer:/layer", -1, "main:/", null); - assertEquals(0, diffs.size()); - - fSyncService.flatten("layer:/layer", "main:/"); - - logger.debug("updated & flattened: created directory: main:/b"); - - fService.createFile("layer:/layer/b", "foo").close(); - fService.createFile("layer:/layer/b", "bar").close(); - - logger.debug("created 2 files in layer: layer:/layer/b/foo and layer:/layer/b/bar"); - - diffs = fSyncService.compare(-1, "layer:/layer", -1, "main:/", null); - assertEquals(2, diffs.size()); - assertEquals("[layer:/layer/b/bar[-1] > main:/b/bar[-1], layer:/layer/b/foo[-1] > main:/b/foo[-1]]", diffs.toString()); - - // submit only first diff - List selected = new ArrayList(1); - selected.add(diffs.get(1)); - - assertEquals("[layer:/layer/b/foo[-1] > main:/b/foo[-1]]", selected.toString()); - - fSyncService.update(selected, null, false, false, false, false, null, null); - - diffs = fSyncService.compare(-1, "layer:/layer", -1, "main:/", null); - assertEquals(1, diffs.size()); - assertEquals("[layer:/layer/b/bar[-1] > main:/b/bar[-1]]", diffs.toString()); - - fSyncService.flatten("layer:/layer", "main:/"); - - logger.debug("updated & flattened: created file: main:/b/foo"); - - fService.removeNode("layer:/layer", "b"); - fService.createSnapshot("layer", null, null); - - logger.debug("removed dir in layer & snapshot: layer:/layer/b"); - - // ETWOTWO-1266 - diffs = fSyncService.compare(-1, "layer:/layer", -1, "main:/", null); - assertEquals(1, diffs.size()); - assertEquals("[layer:/layer/b[-1] > main:/b[-1]]", diffs.toString()); - - fSyncService.update(diffs, null, false, false, false, false, null, null); - - diffs = fSyncService.compare(-1, "layer:/layer", -1, "main:/", null); - assertEquals(0, diffs.size()); - - fSyncService.flatten("layer:/layer", "main:/"); - - logger.debug("updated & flattened: deleted dir: main:/b"); - - recursiveList("main"); - recursiveList("layer"); - } - catch (Exception e) - { - e.printStackTrace(System.err); - throw e; - } - } - - public void testDeleteLD1() throws Exception - { - try - { - logger.debug("created 2 stores: main, layer"); - - fService.createDirectory("main:/", "a"); - - OutputStream o = fService.createFile("main:/a", "foo"); - PrintStream out = new PrintStream(o); - out.println("I am main:/a/foo"); - out.close(); - - logger.debug("created file in main: main:/a/foo"); - - fService.createLayeredDirectory("main:/a", "layer:/", "a"); - - logger.debug("created layered dir: layer:/a -> main:/a"); - - BufferedReader reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "layer:/a/foo"))); - String line = reader.readLine(); - reader.close(); - assertEquals("I am main:/a/foo", line); - - reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "main:/a/foo"))); - line = reader.readLine(); - reader.close(); - assertEquals("I am main:/a/foo", line); - - out = new PrintStream(fService.getFileOutputStream("layer:/a/foo")); - out.println("I am layer:/a/foo"); - out.close(); - - logger.debug("update file in layer: layer:/a/foo"); - - reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "layer:/a/foo"))); - line = reader.readLine(); - reader.close(); - assertEquals("I am layer:/a/foo", line); - - reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "main:/a/foo"))); - line = reader.readLine(); - reader.close(); - assertEquals("I am main:/a/foo", line); - - List diffs = fSyncService.compare(-1, "layer:/a", -1, "main:/a", null); - assertEquals(1, diffs.size()); - assertEquals("[layer:/a/foo[-1] > main:/a/foo[-1]]", diffs.toString()); - - fSyncService.update(diffs, null, false, false, false, false, null, null); - - diffs = fSyncService.compare(-1, "layer:/a", -1, "main:/a", null); - assertEquals(0, diffs.size()); - - fSyncService.flatten("layer:/a", "main:/a"); - - logger.debug("updated & flattened: updated file: main:/a/foo"); - - reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "layer:/a/foo"))); - line = reader.readLine(); - reader.close(); - assertEquals("I am layer:/a/foo", line); - - reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "main:/a/foo"))); - line = reader.readLine(); - reader.close(); - assertEquals("I am layer:/a/foo", line); - - fService.removeNode("main:/", "a"); - fService.createSnapshot("main", null, null); - - logger.debug("remove directory in main & snapshot: main:/a"); - - assertNotNull(fService.lookup(-1, "layer:/a")); - assertNull(fService.lookup(-1, "layer:/a/foo")); - - try - { - fService.getFileInputStream(-1, "layer:/a/foo"); - fail(); - } - catch (AVMNotFoundException nfe) - { - // expected - } - - try - { - fService.getFileOutputStream("layer:/a/foo"); - fail(); - } - catch (AVMNotFoundException nfe) - { - // expected - } - - recursiveList("main"); - recursiveList("layer"); - } - catch (Exception e) - { - e.printStackTrace(System.err); - throw e; - } - } - - public void testDeleteLD2() throws Exception - { - try - { - logger.debug("created 2 stores: main, layer"); - - fService.createDirectory("main:/", "a"); - - OutputStream o = fService.createFile("main:/a", "foo"); - PrintStream out = new PrintStream(o); - out.println("I am main:/a/foo"); - out.close(); - - logger.debug("created file in main: main:/a/foo"); - - fService.createLayeredDirectory("main:/a", "layer:/", "a"); - - logger.debug("created layered dir: layer:/a -> main:/a"); - - BufferedReader reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "layer:/a/foo"))); - String line = reader.readLine(); - reader.close(); - assertEquals("I am main:/a/foo", line); - - reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "main:/a/foo"))); - line = reader.readLine(); - reader.close(); - assertEquals("I am main:/a/foo", line); - - out = new PrintStream(fService.getFileOutputStream("layer:/a/foo")); - out.println("I am layer:/a/foo"); - out.close(); - - logger.debug("update file in layer: layer:/a/foo"); - - reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "layer:/a/foo"))); - line = reader.readLine(); - reader.close(); - assertEquals("I am layer:/a/foo", line); - - reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "main:/a/foo"))); - line = reader.readLine(); - reader.close(); - assertEquals("I am main:/a/foo", line); - - fService.removeNode("main:/", "a"); - - logger.debug("remove directory in main: main:/a"); - - fService.createSnapshot("main", null, null); - - logger.debug("snapshot: main:/a"); - - assertNull(fService.lookup(-1, "main:/a")); - assertNull(fService.lookup(-1, "main:/a/foo")); - - try - { - fService.getFileInputStream(-1, "main:/a/foo"); - fail(); - } - catch (AVMNotFoundException nfe) - { - // expected - } - - assertNotNull(fService.lookup(-1, "layer:/a")); - assertNotNull(fService.lookup(-1, "layer:/a/foo")); - - reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "layer:/a/foo"))); - line = reader.readLine(); - reader.close(); - assertEquals("I am layer:/a/foo", line); - - out = new PrintStream(fService.getFileOutputStream("layer:/a/foo")); - out.println("I am layer:/a/foo V2"); - out.close(); - - List diffs = fSyncService.compare(-1, "layer:/a", -1, "main:/a", null); - assertEquals(1, diffs.size()); - assertEquals("[layer:/a[-1] > main:/a[-1]]", diffs.toString()); - - fSyncService.update(diffs, null, false, false, false, false, null, null); - - diffs = fSyncService.compare(-1, "layer:/a", -1, "main:/a", null); - assertEquals(0, diffs.size()); - - logger.debug("updated: updated dir & file: main:/a/foo"); - - fSyncService.flatten("layer:/a", "main:/a"); - - logger.debug("flattened: layer:/a -> main:/a"); - - reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "layer:/a/foo"))); - line = reader.readLine(); - reader.close(); - assertEquals("I am layer:/a/foo V2", line); - - reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "main:/a/foo"))); - line = reader.readLine(); - reader.close(); - assertEquals("I am layer:/a/foo V2", line); - - recursiveList("main"); - recursiveList("layer"); - } - catch (Exception e) - { - e.printStackTrace(System.err); - throw e; - } - } - - /** - * Test bulk update (using layered directory). - */ - public void testBulkUpdateLD() throws Exception - { - try - { - RemoteBulkLoader loader = new RemoteBulkLoader(); - loader.setAvmRemoteService(fService); - - fService.createLayeredDirectory("main:/", "layer:/", "layer"); - loader.recursiveLoad("config/alfresco/bootstrap", "layer:/layer"); - List diffs = fSyncService.compare(-1, "layer:/layer", -1, "main:/", null); - assertEquals(1, diffs.size()); - assertEquals("[layer:/layer/bootstrap[-1] > main:/bootstrap[-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"); - loader.recursiveLoad("config/alfresco/bootstrap", "layer2:/layer/bootstrap"); - fService.createSnapshot("layer2", null, null); - diffs = fSyncService.compare(-1, "layer2:/layer", -1, "layer:/layer", null); - assertEquals(1, diffs.size()); - assertEquals("[layer2:/layer/bootstrap/bootstrap[-1] > layer:/layer/bootstrap/bootstrap[-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/bootstrap/bootstrap[-1] > main:/bootstrap/bootstrap[-1]]", diffs.toString()); - recursiveList("layer2"); - recursiveList("layer"); - recursiveList("main"); - } - catch (Exception e) - { - e.printStackTrace(System.err); - throw e; - } - finally - { - fService.purgeStore("layer2"); - } - } - - /** - * Test the flatten operation, with a little bit of compare and update. - */ - public void testFlatten() throws Exception - { - try - { - setupBasicTree(); - fService.createLayeredDirectory("main:/a", "main:/", "layer"); - fService.createSnapshot("main", null, null); - recursiveList("main"); - // Change some stuff. - fService.createFile("main:/layer/b", "fig").close(); - fService.getFileOutputStream("main:/layer/b/c/foo").close(); - fService.createSnapshot("main", null, null); - recursiveList("main"); - // Do a compare. - List diffs = fSyncService.compare(-1, "main:/layer", -1, "main:/a", null); - assertEquals(2, diffs.size()); - assertEquals("[main:/layer/b/c/foo[-1] > main:/a/b/c/foo[-1], main:/layer/b/fig[-1] > main:/a/b/fig[-1]]", diffs.toString()); - // Update. - fSyncService.update(diffs, null, false, false, false, false, null, null); - recursiveList("main"); - // Flatten. - fSyncService.flatten("main:/layer", "main:/a"); - recursiveList("main"); - } - catch (Exception e) - { - e.printStackTrace(System.err); - throw e; - } - } - - /** - * Test partial flatten. - */ - public void testPartialFlatten() throws Exception - { - try - { - setupBasicTree(); - fService.createLayeredDirectory("main:/a", "layer:/", "a"); - fService.getFileOutputStream("layer:/a/b/c/foo").close(); - fService.createFile("layer:/a/b", "bing").close(); - List diffs = new ArrayList(); - diffs.add(new AVMDifference(-1, "layer:/a/b/c/foo", -1, "main:/a/b/c/foo", AVMDifference.NEWER)); - fSyncService.update(diffs, null, false, false, false, false, null, null); - fSyncService.flatten("layer:/a", "main:/a"); - AVMNodeDescriptor b = fService.lookup(-1, "layer:/a/b"); - assertTrue(b.isLayeredDirectory()); - AVMNodeDescriptor c = fService.lookup(-1, "layer:/a/b/c"); - assertTrue(c.isPlainDirectory()); - diffs = fSyncService.compare(-1, "layer:/a", -1, "main:/a", null); - assertEquals(1, diffs.size()); - assertEquals("[layer:/a/b/bing[-1] > main:/a/b/bing[-1]]", diffs.toString()); - } - catch (Exception e) - { - e.printStackTrace(System.err); - throw e; - } - } - - /** - * Test AVMSyncService resetLayer. - */ - public void testResetLayer() throws Exception - { - try - { - setupBasicTree(); - fService.createLayeredDirectory("main:/a", "main:/", "layer"); - fService.createFile("main:/layer", "figs").close(); - assertFalse(recursiveContents("main:/a", -1, true).equals(recursiveContents("main:/layer", -1, true))); - recursiveList("main"); - fSyncService.resetLayer("main:/layer"); - assertEquals(recursiveContents("main:/a", -1, true), recursiveContents("main:/layer", -1, true)); - recursiveList("main"); - } - catch (Exception e) - { - e.printStackTrace(System.err); - throw e; - } - } - - /** - * Test AVMSyncService update. - */ - public void testUpdate() throws Exception - { - try - { - setupBasicTree(); - // Try branch to branch update. - fService.createBranch(-1, "main:/a", "main:/", "abranch"); - fService.createFile("main:/abranch", "monkey").close(); - fService.createFile("main:/abranch", "#foo").close(); - fService.createFile("main:/abranch", "figs.tmp").close(); - fService.getFileOutputStream("main:/abranch/b/c/foo").close(); - recursiveList("main"); - List cmp = fSyncService.compare(-1, "main:/abranch", -1, "main:/a", excluder); - assertEquals(2, cmp.size()); - assertEquals("[main:/abranch/b/c/foo[-1] > main:/a/b/c/foo[-1], main:/abranch/monkey[-1] > main:/a/monkey[-1]]", cmp.toString()); - List diffs = new ArrayList(); - diffs.add(new AVMDifference(-1, "main:/abranch/monkey", -1, "main:/a/monkey", AVMDifference.NEWER)); - diffs.add(new AVMDifference(-1, "main:/abranch/b/c/foo", -1, "main:/a/b/c/foo", AVMDifference.NEWER)); - fSyncService.update(diffs, null, false, false, false, false, null, null); - fService.createSnapshot("main", null, null); - recursiveList("main"); - assertEquals(fService.lookup(-1, "main:/abranch/monkey").getId(), fService.lookup(-1, "main:/a/monkey").getId()); - assertEquals(fService.lookup(-1, "main:/abranch/b/c/foo").getId(), fService.lookup(-1, "main:/a/b/c/foo").getId()); - // Try updating a deletion. - fService.removeNode("main:/abranch", "monkey"); - recursiveList("main"); - cmp = fSyncService.compare(-1, "main:/abranch", -1, "main:/a", excluder); - assertEquals(1, cmp.size()); - assertEquals("[main:/abranch/monkey[-1] > main:/a/monkey[-1]]", cmp.toString()); - diffs.clear(); - diffs.add(new AVMDifference(-1, "main:/abranch/monkey", -1, "main:/a/monkey", AVMDifference.NEWER)); - fSyncService.update(diffs, null, false, false, false, false, null, null); - assertEquals(0, fSyncService.compare(-1, "main:/abranch", -1, "main:/a", excluder).size()); - fService.createSnapshot("main", null, null); - recursiveList("main"); - assertEquals(fService.lookup(-1, "main:/abranch/monkey", true).getId(), fService.lookup(-1, "main:/a/monkey", true).getId()); - // Try one that should fail. - fService.createFile("main:/abranch", "monkey").close(); - cmp = fSyncService.compare(-1, "main:/abranch", -1, "main:/a", excluder); - assertEquals(1, cmp.size()); - assertEquals("[main:/abranch/monkey[-1] > main:/a/monkey[-1]]", cmp.toString()); - diffs.clear(); - diffs.add(new AVMDifference(-1, "main:/a/monkey", -1, "main:/abranch/monkey", AVMDifference.NEWER)); - try - { - fSyncService.update(diffs, null, false, false, false, false, null, null); - fail(); - } - catch (AVMSyncException se) - { - // Do nothing. - } - // Get synced again by doing an override older. - recursiveList("main"); - diffs.clear(); - diffs.add(new AVMDifference(-1, "main:/a/monkey", -1, "main:/abranch/monkey", AVMDifference.NEWER)); - fSyncService.update(diffs, null, false, false, false, true, null, null); - assertEquals(0, fSyncService.compare(-1, "main:/abranch", -1, "main:/a", excluder).size()); - fService.createSnapshot("main", null, null); - recursiveList("main"); - assertEquals(fService.lookup(-1, "main:/a/monkey", true).getId(), fService.lookup(-1, "main:/abranch/monkey", true).getId()); - // Cleanup for layered tests. - fService.purgeStore("main"); - fService.createStore("main"); - setupBasicTree(); - fService.createLayeredDirectory("main:/a", "main:/", "layer"); - fService.createFile("main:/layer", "monkey").close(); - fService.getFileOutputStream("main:/layer/b/c/foo").close(); - cmp = fSyncService.compare(-1, "main:/layer", -1, "main:/a", excluder); - assertEquals(2, cmp.size()); - assertEquals("[main:/layer/b/c/foo[-1] > main:/a/b/c/foo[-1], main:/layer/monkey[-1] > main:/a/monkey[-1]]", cmp.toString()); - recursiveList("main"); - diffs.clear(); - diffs.add(new AVMDifference(-1, "main:/layer/monkey", -1, "main:/a/monkey", AVMDifference.NEWER)); - diffs.add(new AVMDifference(-1, "main:/layer/b/c/foo", -1, "main:/a/b/c/foo", AVMDifference.NEWER)); - fSyncService.update(diffs, null, false, false, false, false, null, null); - assertEquals(0, fSyncService.compare(-1, "main:/layer", -1, "main:/a", excluder).size()); - fService.createSnapshot("main", null, null); - recursiveList("main"); - assertEquals(fService.lookup(-1, "main:/layer/monkey").getId(), fService.lookup(-1, "main:/a/monkey").getId()); - assertEquals(fService.lookup(-1, "main:/layer/b/c/foo").getId(), fService.lookup(-1, "main:/a/b/c/foo").getId()); - // Try updating a deletion. - fService.removeNode("main:/layer", "monkey"); - recursiveList("main"); - cmp = fSyncService.compare(-1, "main:/layer", -1, "main:/a", excluder); - assertEquals(1, cmp.size()); - assertEquals("[main:/layer/monkey[-1] > main:/a/monkey[-1]]", cmp.toString()); - diffs.clear(); - diffs.add(new AVMDifference(-1, "main:/layer/monkey", -1, "main:/a/monkey", AVMDifference.NEWER)); - fSyncService.update(diffs, null, false, false, false, false, null, null); - assertEquals(0, fSyncService.compare(-1, "main:/layer", -1, "main:/a", excluder).size()); - fService.createSnapshot("main", null, null); - recursiveList("main"); - assertEquals(fService.lookup(-1, "main:/layer/monkey", true).getId(), fService.lookup(-1, "main:/a/monkey", true).getId()); - // Try one that should fail. - fService.createFile("main:/layer", "monkey").close(); - cmp = fSyncService.compare(-1, "main:/layer", -1, "main:/a", excluder); - assertEquals(1, cmp.size()); - assertEquals("[main:/layer/monkey[-1] > main:/a/monkey[-1]]", cmp.toString()); - diffs.clear(); - diffs.add(new AVMDifference(-1, "main:/a/monkey", -1, "main:/layer/monkey", AVMDifference.NEWER)); - try - { - fSyncService.update(diffs, null, false, false, false, false, null, null); - fail(); - } - catch (AVMSyncException se) - { - // Do nothing. - } - // Get synced again by doing an override older. - recursiveList("main"); - diffs.clear(); - diffs.add(new AVMDifference(-1, "main:/a/monkey", -1, "main:/layer/monkey", AVMDifference.NEWER)); - fSyncService.update(diffs, null, false, false, false, true, null, null); - assertEquals(0, fSyncService.compare(-1, "main:/layer", -1, "main:/a", excluder).size()); - fService.createSnapshot("main", null, null); - recursiveList("main"); - assertEquals(fService.lookup(-1, "main:/a/monkey", true).getId(), fService.lookup(-1, "main:/layer/monkey", true).getId()); - } - catch (Exception e) - { - e.printStackTrace(System.err); - throw e; - } - } - - /** - * Test that an update forces a snapshot on the source. - */ - public void testUpdateSnapshot() throws Exception - { - try - { - setupBasicTree(); - fService.createStore("branch"); - fService.createBranch(-1, "main:/", "branch:/", "branch"); - // Modify some things in the branch. - fService.createFile("branch:/branch/a/b", "fing").close(); - fService.getFileOutputStream("branch:/branch/a/b/c/foo").close(); - fService.removeNode("branch:/branch/a/b/c", "bar"); - List diffs = fSyncService.compare(-1, "branch:/branch", -1, "main:/", null); - assertEquals(3, diffs.size()); - assertEquals("[branch:/branch/a/b/c/bar[-1] > main:/a/b/c/bar[-1], branch:/branch/a/b/c/foo[-1] > main:/a/b/c/foo[-1], branch:/branch/a/b/fing[-1] > main:/a/b/fing[-1]]", diffs.toString()); - // Now update. - fSyncService.update(diffs, null, false, false, false, false, null, null); - diffs = fSyncService.compare(-1, "branch:/branch", -1, "main:/", null); - assertEquals(0, diffs.size()); - fService.getFileOutputStream("branch:/branch/a/b/fing").close(); - assertTrue(fService.lookup(-1, "branch:/branch/a/b/fing").getId() != fService.lookup(-1, "main:/a/b/fing").getId()); - } - catch (Exception e) - { - e.printStackTrace(System.err); - throw e; - } - finally - { - fService.purgeStore("branch"); - } - } - - /** - * Test a noodle update. - */ - public void testNoodleUpdate() throws Exception - { - try - { - setupBasicTree(); - fService.createStore("staging"); - List diffs = fSyncService.compare(-1, "main:/", -1, "staging:/", null); - assertEquals(2, diffs.size()); - assertEquals("[main:/a[-1] > staging:/a[-1], main:/d[-1] > staging:/d[-1]]", diffs.toString()); - List noodle = new ArrayList(); - noodle.add(new AVMDifference(-1, "main:/a/b/c/foo", -1, "staging:/a/b/c/foo", AVMDifference.NEWER)); - noodle.add(new AVMDifference(-1, "main:/d", -1, "staging:/d", AVMDifference.NEWER)); - fSyncService.update(noodle, null, false, false, false, false, null, null); - diffs = fSyncService.compare(-1, "main:/", -1, "staging:/", null); - assertEquals(1, diffs.size()); - assertEquals("[main:/a/b/c/bar[-1] > staging:/a/b/c/bar[-1]]", diffs.toString()); - assertEquals("main:/a/b/c/bar", diffs.get(0).getSourcePath()); - } - catch (Exception e) - { - e.printStackTrace(System.err); - throw e; - } - finally - { - fService.purgeStore("staging"); - } - } - - - public void testRename6() throws Exception - { - try - { - setupBasicTree(); - fService.createLayeredDirectory("main:/a", "layer:/", "a"); - fService.rename("layer:/a/b", "c", "layer:/a/b", "z"); - recursiveContents("layer:/"); - List diffs = fSyncService.compare(-1, "layer:/a", -1, "main:/a", null); - assertEquals(2, diffs.size()); - assertEquals("[layer:/a/b/c[-1] > main:/a/b/c[-1], layer:/a/b/z[-1] > main:/a/b/z[-1]]", diffs.toString()); - fSyncService.update(diffs, null, false, false, false, false, null, null); - recursiveContents("layer:/"); - recursiveContents("main:/"); - fSyncService.flatten("layer:/a", "main:/a"); - recursiveContents("layer:/"); - recursiveContents("main:/"); - fService.createFile("layer:/a/b/z", "fudge").close(); - fService.rename("layer:/a/b", "z", "layer:/a/b", "y"); - recursiveContents("layer:/"); - diffs = fSyncService.compare(-1, "layer:/a", -1, "main:/a", null); - assertEquals(2, diffs.size()); - assertEquals("[layer:/a/b/y[-1] > main:/a/b/y[-1], layer:/a/b/z[-1] > main:/a/b/z[-1]]", diffs.toString()); - fSyncService.update(diffs, null, false, false, false, false, null, null); - recursiveContents("layer:/"); - recursiveContents("main:/"); - fSyncService.flatten("layer:/a", "main:/a"); - recursiveContents("layer:/"); - recursiveContents("main:/"); - } - catch (Exception e) - { - e.printStackTrace(); - 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; - } - } - - public void testSimpleUpdateLF1() throws Exception - { - try - { - List snapshots = fService.getStoreVersions("main"); - assertEquals(1, snapshots.size()); - assertEquals(0, snapshots.get(0).getVersionID()); - - snapshots = fService.getStoreVersions("layer"); - assertEquals(1, snapshots.size()); - assertEquals(0, snapshots.get(0).getVersionID()); - - fService.createDirectory("main:/", "a"); - fService.createDirectory("layer:/", "a"); - - logger.debug("created 2 plain dirs: main:/a, layer:/a"); - - fService.createFile("main:/a", "foo"); - - assertEquals(1, fService.lookup(-1, "main:/a/foo").getVersionID()); - - PrintStream out = new PrintStream(fService.getFileOutputStream("main:/a/foo")); - out.println("I am main:/a/foo"); - out.close(); - - AVMNodeDescriptor node = fService.lookup(-1, "main:/a/foo"); - assertEquals(1, node.getVersionID()); - List history = fService.getHistory(node, -1); - assertEquals(0, history.size()); - - fService.createSnapshot("main", null, null); - - snapshots = fService.getStoreVersions("main"); - assertEquals(2, snapshots.size()); - assertEquals(1, snapshots.get(snapshots.size()-1).getVersionID()); - - snapshots = fService.getStoreVersions("layer"); - assertEquals(1, snapshots.size()); - assertEquals(0, snapshots.get(0).getVersionID()); - - assertEquals(1, fService.lookup(-1, "main:/a/foo").getVersionID()); - assertEquals(1, fService.lookup(1, "main:/a/foo").getVersionID()); - - logger.debug("created plain file: main:/a/foo"); - - fService.createLayeredFile("main:/a/foo", "layer:/a", "foo"); - - assertEquals(1, fService.lookup(-1, "layer:/a/foo").getVersionID()); - - BufferedReader reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "layer:/a/foo"))); - String line = reader.readLine(); - reader.close(); - assertEquals("I am main:/a/foo", line); - - node = fService.lookup(-1, "layer:/a/foo"); - assertEquals(1, node.getVersionID()); - - history = fService.getHistory(node, -1); - assertEquals(0, history.size()); - - fService.createSnapshot("layer", null, null); - - snapshots = fService.getStoreVersions("main"); - assertEquals(2, snapshots.size()); - assertEquals(1, snapshots.get(snapshots.size()-1).getVersionID()); - - snapshots = fService.getStoreVersions("layer"); - assertEquals(2, snapshots.size()); - assertEquals(1, snapshots.get(snapshots.size()-1).getVersionID()); - - assertEquals(1, fService.lookup(-1, "layer:/a/foo").getVersionID()); - assertEquals(1, fService.lookup(1, "layer:/a/foo").getVersionID()); - - List diffs = fSyncService.compare(-1, "layer:/a", -1, "main:/a", null); - assertEquals(0, diffs.size()); - - reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "layer:/a/foo"))); - line = reader.readLine(); - reader.close(); - assertEquals("I am main:/a/foo", line); - - logger.debug("created layered file: layer:/a/foo -> main:/a/foo"); - - out = new PrintStream(fService.getFileOutputStream("layer:/a/foo")); - out.println("I am layer:/a/foo"); - out.close(); - - logger.debug("modified file: layer:/a/foo"); - - assertEquals(2, fService.lookup(-1, "layer:/a/foo").getVersionID()); - - reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "main:/a/foo"))); - line = reader.readLine(); - reader.close(); - assertEquals("I am main:/a/foo", line); - - diffs = fSyncService.compare(-1, "layer:/a", -1, "main:/a", null); - assertEquals(1, diffs.size()); - - // TODO - review behaviour - assertEquals("[layer:/a/foo[-1] > main:/a/foo[-1]]", diffs.toString()); - fSyncService.update(diffs, null, false, false, false, false, "one", "one"); - - // update will implicitly snapshot (src and dst) - snapshots = fService.getStoreVersions("main"); - assertEquals(3, snapshots.size()); - assertEquals(2, snapshots.get(snapshots.size()-1).getVersionID()); - - snapshots = fService.getStoreVersions("layer"); - assertEquals(3, snapshots.size()); - assertEquals(2, snapshots.get(snapshots.size()-1).getVersionID()); - - node = fService.lookup(-1, "layer:/a/foo"); - assertEquals(2, node.getVersionID()); - history = fService.getHistory(node, -1); - - assertEquals(1, history.size()); - assertEquals(1, history.get(0).getVersionID()); - - assertEquals(1, fService.lookup(1, "layer:/a/foo").getVersionID()); - assertEquals(2, fService.lookup(2, "layer:/a/foo").getVersionID()); - - logger.debug("submitted/updated file: layer:/a/foo -> main:/a/foo"); - - fSyncService.flatten("layer:/a", "main:/a"); - - logger.debug("flatten dir: layer:/a -> main:/a"); - - reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "layer:/a/foo"))); - line = reader.readLine(); - reader.close(); - assertEquals("I am layer:/a/foo", line); - - reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "main:/a/foo"))); - line = reader.readLine(); - reader.close(); - assertEquals("I am layer:/a/foo", line); - - snapshots = fService.getStoreVersions("main"); - assertEquals(3, snapshots.size()); - assertEquals(2, snapshots.get(snapshots.size()-1).getVersionID()); - - snapshots = fService.getStoreVersions("layer"); - assertEquals(3, snapshots.size()); - assertEquals(2, snapshots.get(snapshots.size()-1).getVersionID()); - - recursiveList("main"); - recursiveList("layer"); - } - catch (Exception e) - { - e.printStackTrace(System.err); - throw e; - } - } - - public void testSimpleUpdateLF2() throws Exception - { - try - { - fService.createStore("mainA"); - fService.createStore("mainB"); - fService.createStore("mainB--layer"); - - List snapshots = fService.getStoreVersions("mainA"); - assertEquals(1, snapshots.size()); - assertEquals(0, snapshots.get(0).getVersionID()); - - snapshots = fService.getStoreVersions("mainB"); - assertEquals(1, snapshots.size()); - assertEquals(0, snapshots.get(0).getVersionID()); - - snapshots = fService.getStoreVersions("mainB--layer"); - assertEquals(1, snapshots.size()); - assertEquals(0, snapshots.get(0).getVersionID()); - - logger.debug("created 3 stores: mainA, mainB, mainB-layer"); - - fService.createDirectory("mainA:/", "a"); - fService.createDirectory("mainB:/", "a"); - - logger.debug("created 2 plain dirs: mainA:/a, mainB:/a"); - - fService.createLayeredDirectory("mainB:/a", "mainB--layer:/", "a"); - - logger.debug("created layered dir: mainB--layer:/a -> mainB:/a"); - - // note: unlike WCM, edit staging directly (ie. don't bother with mainA--layer for now) - fService.createFile("mainA:/a", "foo"); - - assertEquals(1, fService.lookup(-1, "mainA:/a/foo").getVersionID()); - assertNull(fService.lookup(-1, "mainB:/a/foo")); - assertNull(fService.lookup(-1, "mainB--layer:/a/foo")); - - PrintStream out = new PrintStream(fService.getFileOutputStream("mainA:/a/foo")); - out.println("I am mainA:/a/foo"); - out.close(); - - logger.debug("created plain file: mainA:/a/foo"); - - fService.createSnapshot("mainA", null, null); - - assertEquals(1, fService.lookup(-1, "mainA:/a/foo").getVersionID()); - assertNull(fService.lookup(-1, "mainB:/a/foo")); - assertNull(fService.lookup(-1, "mainB--layer:/a/foo")); - - snapshots = fService.getStoreVersions("mainA"); - assertEquals(2, snapshots.size()); - assertEquals(1, snapshots.get(snapshots.size()-1).getVersionID()); - - logger.debug("created snapshot: mainA"); - - // note: WCM does not expose layered file (between web project staging sandboxes) - fService.createLayeredFile("mainA:/a/foo", "mainB:/a", "foo"); - - assertEquals(1, fService.lookup(-1, "mainA:/a/foo").getVersionID()); - assertEquals(1, fService.lookup(-1, "mainB:/a/foo").getVersionID()); - assertEquals(1, fService.lookup(-1, "mainB--layer:/a/foo").getVersionID()); - - BufferedReader reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB--layer:/a/foo"))); - String line = reader.readLine(); - reader.close(); - assertEquals("I am mainA:/a/foo", line); - - reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB:/a/foo"))); - line = reader.readLine(); - reader.close(); - assertEquals("I am mainA:/a/foo", line); - - reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainA:/a/foo"))); - line = reader.readLine(); - reader.close(); - assertEquals("I am mainA:/a/foo", line); - - logger.debug("created layered file: mainB:/a/foo -> mainA:/a/foo"); - - // modify file in user's sandbox - out = new PrintStream(fService.getFileOutputStream("mainB--layer:/a/foo")); - out.println("I am mainB--layer:/a/foo"); - out.close(); - - assertEquals(1, fService.lookup(-1, "mainA:/a/foo").getVersionID()); - assertEquals(1, fService.lookup(-1, "mainB:/a/foo").getVersionID()); - assertEquals(2, fService.lookup(-1, "mainB--layer:/a/foo").getVersionID()); - - logger.debug("modified file: mainB--layer:/a/foo"); - - reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB--layer:/a/foo"))); - line = reader.readLine(); - reader.close(); - assertEquals("I am mainB--layer:/a/foo", line); - - reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB:/a/foo"))); - line = reader.readLine(); - reader.close(); - assertEquals("I am mainA:/a/foo", line); - - reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainA:/a/foo"))); - line = reader.readLine(); - reader.close(); - assertEquals("I am mainA:/a/foo", line); - - List diffs = fSyncService.compare(-1, "mainB--layer:/a", -1, "mainB:/a", null); - assertEquals(1, diffs.size()); - - // TODO - review behaviour - assertEquals("[mainB--layer:/a/foo[-1] > mainB:/a/foo[-1]]", diffs.toString()); - fSyncService.update(diffs, null, false, false, false, false, "one", "one"); - - fSyncService.flatten("mainB--layer:/a", "mainB:/a"); - - assertEquals(1, fService.lookup(-1, "mainA:/a/foo").getVersionID()); - assertEquals(2, fService.lookup(-1, "mainB:/a/foo").getVersionID()); - assertEquals(2, fService.lookup(-1, "mainB--layer:/a/foo").getVersionID()); - - snapshots = fService.getStoreVersions("mainB--layer"); - assertEquals(2, snapshots.size()); - assertEquals(1, snapshots.get(snapshots.size()-1).getVersionID()); - - snapshots = fService.getStoreVersions("mainB"); - assertEquals(3, snapshots.size()); - assertEquals(2, snapshots.get(snapshots.size()-1).getVersionID()); - - logger.debug("submit/update file: mainB--layer:/a/foo -> mainB:/a/foo"); - - fSyncService.flatten("mainB--layer:/a", "mainB:/a"); - - logger.debug("flatten dir: mainB--layer:/a/foo -> mainB:/a/foo"); - - reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB--layer:/a/foo"))); - line = reader.readLine(); - reader.close(); - assertEquals("I am mainB--layer:/a/foo", line); - - reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB:/a/foo"))); - line = reader.readLine(); - reader.close(); - assertEquals("I am mainB--layer:/a/foo", line); - - reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainA:/a/foo"))); - line = reader.readLine(); - reader.close(); - assertEquals("I am mainA:/a/foo", line); - - recursiveList("mainA"); - recursiveList("mainB"); - recursiveList("mainB--layer"); - } - catch (Exception e) - { - e.printStackTrace(System.err); - throw e; - } - finally - { - fService.purgeStore("mainA"); - fService.purgeStore("mainB"); - fService.purgeStore("mainB--layer"); - } - } - - public void testSimpleUpdateLF3() throws Exception - { - try - { - fService.createStore("mainA"); - fService.createStore("mainB"); - fService.createStore("mainB--layer"); - - List snapshots = fService.getStoreVersions("mainA"); - assertEquals(1, snapshots.size()); - assertEquals(0, snapshots.get(0).getVersionID()); - - snapshots = fService.getStoreVersions("mainB"); - assertEquals(1, snapshots.size()); - assertEquals(0, snapshots.get(0).getVersionID()); - - snapshots = fService.getStoreVersions("mainB--layer"); - assertEquals(1, snapshots.size()); - assertEquals(0, snapshots.get(0).getVersionID()); - - logger.debug("created 3 stores: mainA, mainB, mainB-layer"); - - fService.createDirectory("mainA:/", "a"); - fService.createDirectory("mainB:/", "a"); - - logger.debug("created 2 plain dirs: mainA:/a, mainB:/a"); - - fService.createLayeredDirectory("mainB:/a", "mainB--layer:/", "a"); - - logger.debug("created layered dir: mainB--layer:/a -> mainB:/a"); - - // note: unlike WCM, edit staging directly (ie. don't bother with mainA--layer for now) - fService.createFile("mainA:/a", "foo"); - - assertEquals(1, fService.lookup(-1, "mainA:/a/foo").getVersionID()); - assertNull(fService.lookup(-1, "mainB:/a/foo")); - assertNull(fService.lookup(-1, "mainB--layer:/a/foo")); - - PrintStream out = new PrintStream(fService.getFileOutputStream("mainA:/a/foo")); - out.println("I am mainA:/a/foo"); - out.close(); - - logger.debug("created plain file: mainA:/a/foo"); - - fService.createSnapshot("mainA", null, null); - - assertEquals(1, fService.lookup(-1, "mainA:/a/foo").getVersionID()); - assertNull(fService.lookup(-1, "mainB:/a/foo")); - assertNull(fService.lookup(-1, "mainB--layer:/a/foo")); - - snapshots = fService.getStoreVersions("mainA"); - assertEquals(2, snapshots.size()); - assertEquals(1, snapshots.get(snapshots.size()-1).getVersionID()); - - logger.debug("created snapshot: mainA"); - - // note: WCM does not expose layered file (between web project staging sandboxes) - fService.createLayeredFile("mainA:/a/foo", "mainB:/a", "foo"); - - assertEquals(1, fService.lookup(-1, "mainA:/a/foo").getVersionID()); - assertEquals(1, fService.lookup(-1, "mainB:/a/foo").getVersionID()); - - AVMNodeDescriptor foo = fService.lookup(-1, "mainB--layer:/a/foo"); - assertEquals(1, foo.getVersionID()); - assertTrue(foo.isLayeredFile()); - - BufferedReader reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB--layer:/a/foo"))); - String line = reader.readLine(); - reader.close(); - assertEquals("I am mainA:/a/foo", line); - - reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB:/a/foo"))); - line = reader.readLine(); - reader.close(); - assertEquals("I am mainA:/a/foo", line); - - reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainA:/a/foo"))); - line = reader.readLine(); - reader.close(); - assertEquals("I am mainA:/a/foo", line); - - logger.debug("created layered file: mainB:/a/foo -> mainA:/a/foo"); - - // add dir in user's sandbox - fService.createDirectory("mainB--layer:/a", "b"); - - assertEquals(1, fService.lookup(-1, "mainA:/a/foo").getVersionID()); - assertEquals(1, fService.lookup(-1, "mainB:/a/foo").getVersionID()); - assertEquals(1, fService.lookup(-1, "mainB--layer:/a/b").getVersionID()); - - foo = fService.lookup(-1, "mainB--layer:/a/foo"); - assertEquals(1, foo.getVersionID()); - assertTrue(foo.isLayeredFile()); - - logger.debug("created dir: mainB--layer:/a/b"); - - List diffs = fSyncService.compare(-1, "mainB--layer:/a", -1, "mainB:/a", null); - assertEquals(1, diffs.size()); - - foo = fService.lookup(-1, "mainB--layer:/a/foo"); - assertTrue(foo.isLayeredFile()); - - assertEquals("[mainB--layer:/a/b[-1] > mainB:/a/b[-1]]", diffs.toString()); - fSyncService.update(diffs, null, false, false, false, false, "one", "one"); - - foo = fService.lookup(-1, "mainB--layer:/a/foo"); - assertTrue(foo.isLayeredFile()); - - fSyncService.flatten("mainB--layer:/a", "mainB:/a"); - - foo = fService.lookup(-1, "mainB--layer:/a/foo"); - assertTrue(foo.isLayeredFile()); - - assertEquals(1, fService.lookup(-1, "mainA:/a/foo").getVersionID()); - assertEquals(2, fService.lookup(-1, "mainB:/a/foo").getVersionID()); - assertEquals(2, fService.lookup(-1, "mainB--layer:/a/foo").getVersionID()); - - snapshots = fService.getStoreVersions("mainB--layer"); - assertEquals(2, snapshots.size()); - assertEquals(1, snapshots.get(snapshots.size()-1).getVersionID()); - - snapshots = fService.getStoreVersions("mainB"); - assertEquals(3, snapshots.size()); - assertEquals(2, snapshots.get(snapshots.size()-1).getVersionID()); - - logger.debug("submitted dir: mainB--layer:/a/b -> mainB:/a/b"); - - foo = fService.lookup(-1, "mainB--layer:/a/foo"); - assertEquals(2, foo.getVersionID()); - assertTrue(foo.isLayeredFile()); - - reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainA:/a/foo"))); - line = reader.readLine(); - reader.close(); - assertEquals("I am mainA:/a/foo", line); - - reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB:/a/foo"))); - line = reader.readLine(); - reader.close(); - assertEquals("I am mainA:/a/foo", line); - - reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB--layer:/a/foo"))); - line = reader.readLine(); - reader.close(); - assertEquals("I am mainA:/a/foo", line); - - recursiveList("mainA"); - recursiveList("mainB"); - recursiveList("mainB--layer"); - } - catch (Exception e) - { - e.printStackTrace(System.err); - throw e; - } - finally - { - fService.purgeStore("mainA"); - fService.purgeStore("mainB"); - fService.purgeStore("mainB--layer"); - } - } - - public void testLayeredFolder1() throws Exception - { - try - { - fService.createStore("mainA"); - fService.createStore("mainB"); - - fService.createDirectory("mainA:/", "a"); - fService.createDirectory("mainA:/a", "b"); - - fService.createDirectory("mainB:/", "a"); - - fService.createStore("mainB--layer"); - - fService.createLayeredDirectory("mainB:/a", "mainB--layer:/", "a"); - - // note: short-cut - created directly in "staging" area (don't bother with sandbox mainA--layer for now) - fService.createFile("mainA:/a/b", "foo"); - - PrintStream out = new PrintStream(fService.getFileOutputStream("mainA:/a/b/foo")); - out.println("I am mainA:/a/b/foo"); - out.close(); - - logger.debug("created file: mainA:/a/b/c/foo"); - - // create equivalent of WCM layered folder between web project staging sandboxes (mainB:/a/b pointing to mainA:/a/b) - fService.createLayeredDirectory("mainA:/a/b", "mainB:/a", "b"); - - fService.createSnapshot("mainA", null, null); - fService.createSnapshot("mainB", null, null); - - assertTrue(fService.lookup(-1, "mainB--layer:/a/b").isLayeredDirectory()); - - logger.debug("created layered directory: mainB:/a/b -> mainA:/a/b"); - - fService.createDirectory("mainB--layer:/a", "c"); - - fService.createSnapshot("mainB--layer", null, null); - - logger.debug("created dir: mainB--layer:/a/c"); - - List diffs = fSyncService.compare(-1, "mainB--layer:/a", -1, "mainB:/a", null); - assertEquals(1, diffs.size()); - assertEquals("[mainB--layer:/a/c[-1] > mainB:/a/c[-1]]", diffs.toString()); - - fSyncService.update(diffs, null, false, false, false, false, "one", "one"); - fSyncService.flatten("mainB--layer:/a", "mainB:/a"); - - logger.debug("updated: created dir: mainB:/a/d"); - - assertTrue(fService.lookup(-1, "mainB--layer:/a/b").isLayeredDirectory()); - - fService.createDirectory("mainB--layer:/a/b", "c"); - - assertTrue(fService.lookup(-1, "mainB--layer:/a/b").isLayeredDirectory()); - - fService.createSnapshot("mainB--layer", null, null); - - logger.debug("created dir: mainB--layer:/a/b/c"); - - diffs = fSyncService.compare(-1, "mainB--layer:/a", -1, "mainB:/a", null); - assertEquals(1, diffs.size()); - assertEquals("[mainB--layer:/a/b/c[-1] > mainB:/a/b/c[-1]]", diffs.toString()); - - fSyncService.update(diffs, null, false, false, false, false, "one", "one"); - fSyncService.flatten("mainB--layer:/a", "mainB:/a"); - - logger.debug("updated: created dir: mainB:/a/b/c"); - - assertTrue(fService.lookup(-1, "mainB--layer:/a/b").isLayeredDirectory()); - - recursiveList("mainA"); - recursiveList("mainB"); - recursiveList("mainB--layer"); - } - catch (Exception e) - { - e.printStackTrace(System.err); - throw e; - } - finally - { - fService.purgeStore("mainA"); - fService.purgeStore("mainB"); - fService.purgeStore("mainB--layer"); - } - } - - public void testLayeredFolderDelete1() throws Exception - { - try - { - fService.createStore("mainA"); - fService.createStore("mainB"); - - fService.createDirectory("mainA:/", "a"); - fService.createDirectory("mainA:/a", "b"); - - fService.createDirectory("mainB:/", "a"); - - fService.createStore("mainB--layer"); - - fService.createLayeredDirectory("mainB:/a", "mainB--layer:/", "a"); - - // note: short-cut - created directly in "staging" area (don't bother with sandbox mainA--layer for now) - fService.createFile("mainA:/a/b", "foo"); - - PrintStream out = new PrintStream(fService.getFileOutputStream("mainA:/a/b/foo")); - out.println("I am mainA:/a/b/foo"); - out.close(); - - logger.debug("created file: mainA:/a/b/foo"); - - // create equivalent of WCM layered folder between web project staging sandboxes (mainB:/a/b pointing to ,mainA:/a/b) - fService.createLayeredDirectory("mainA:/a/b", "mainB:/a", "b"); - - fService.createSnapshot("mainA", null, null); - fService.createSnapshot("mainB", null, null); - - logger.debug("created layered directory: mainB:/a/b -> mainA:/a/b"); - - BufferedReader reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB--layer:/a/b/foo"))); - String line = reader.readLine(); - reader.close(); - assertEquals("I am mainA:/a/b/foo", line); - - out = new PrintStream(fService.getFileOutputStream("mainB--layer:/a/b/foo")); - out.println("I am mainB--layer:/a/b/foo"); - out.close(); - - fService.createSnapshot("mainB--layer", null, null); - - logger.debug("updated file: mainB--layer:/a/b/foo"); - - reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainA:/a/b/foo"))); - line = reader.readLine(); - reader.close(); - assertEquals("I am mainA:/a/b/foo", line); - - reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB:/a/b/foo"))); - line = reader.readLine(); - reader.close(); - assertEquals("I am mainA:/a/b/foo", line); - - reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB--layer:/a/b/foo"))); - line = reader.readLine(); - reader.close(); - assertEquals("I am mainB--layer:/a/b/foo", line); - - List diffs = fSyncService.compare(-1, "mainB--layer:/a", -1, "mainB:/a", null); - assertEquals(1, diffs.size()); - assertEquals("[mainB--layer:/a/b/foo[-1] > mainB:/a/b/foo[-1]]", diffs.toString()); - - fSyncService.update(diffs, null, false, false, false, false, "one", "one"); - fSyncService.flatten("mainB--layer:/a", "mainB:/a"); - - logger.debug("updated: created file: mainB:/a/b/foo"); - - reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB:/a/b/foo"))); - line = reader.readLine(); - reader.close(); - assertEquals("I am mainB--layer:/a/b/foo", line); - - // delete file - note: short-cut - removed directly from "staging" area (don't bother with sandbox mainA--layer for now) - fService.removeNode("mainA:/a/b", "foo"); - fService.createSnapshot("mainA", null, null); - - logger.debug("removed file & snapshot: mainA:/a/b/foo"); - - // ETHREEOH-2297 - fService.removeNode("mainB--layer:/a/b", "foo"); - fService.createSnapshot("mainB--layer", null, null); - - diffs = fSyncService.compare(-1, "mainB--layer:/a", -1, "mainB:/a", null); - assertEquals(1, diffs.size()); - assertEquals("[mainB--layer:/a/b/foo[-1] > mainB:/a/b/foo[-1]]", diffs.toString()); - - fSyncService.update(diffs, null, false, false, false, false, "one", "one"); - fSyncService.flatten("mainB--layer:/a", "mainB:/a"); - - fService.createSnapshot("mainB", null, null); - - logger.debug("updated: removed file: mainB:/a/b/foo"); - - recursiveList("mainA"); - recursiveList("mainB"); - recursiveList("mainB--layer"); - } - catch (Exception e) - { - e.printStackTrace(System.err); - throw e; - } - finally - { - fService.purgeStore("mainA"); - fService.purgeStore("mainB"); - fService.purgeStore("mainB--layer"); - } - } - - public void testLayeredFolderDelete2() throws Exception - { - try - { - fService.createStore("mainA"); - fService.createStore("mainB"); - - fService.createDirectory("mainA:/", "a"); - fService.createDirectory("mainA:/a", "b"); - - fService.createDirectory("mainB:/", "a"); - - fService.createStore("mainB--layer"); - - fService.createLayeredDirectory("mainB:/a", "mainB--layer:/", "a"); - - // note: short-cut - created directly in "staging" area (don't bother with sandbox mainA--layer for now) - fService.createFile("mainA:/a/b", "foo"); - - PrintStream out = new PrintStream(fService.getFileOutputStream("mainA:/a/b/foo")); - out.println("I am mainA:/a/b/foo"); - out.close(); - - logger.debug("created file: mainA:/a/b/foo"); - - // create equivalent of WCM layered folder between web project staging sandboxes (mainB:/a/b pointing to ,mainA:/a/b) - fService.createLayeredDirectory("mainA:/a/b", "mainB:/a", "b"); - - fService.createSnapshot("mainA", null, null); - fService.createSnapshot("mainB", null, null); - - logger.debug("created layered directory: mainB:/a/b -> mainA:/a/b"); - - BufferedReader reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB--layer:/a/b/foo"))); - String line = reader.readLine(); - reader.close(); - assertEquals("I am mainA:/a/b/foo", line); - - out = new PrintStream(fService.getFileOutputStream("mainB--layer:/a/b/foo")); - out.println("I am mainB--layer:/a/b/foo"); - out.close(); - - fService.createSnapshot("mainB--layer", null, null); - - logger.debug("updated file: mainB--layer:/a/b/foo"); - - reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainA:/a/b/foo"))); - line = reader.readLine(); - reader.close(); - assertEquals("I am mainA:/a/b/foo", line); - - reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB:/a/b/foo"))); - line = reader.readLine(); - reader.close(); - assertEquals("I am mainA:/a/b/foo", line); - - reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB--layer:/a/b/foo"))); - line = reader.readLine(); - reader.close(); - assertEquals("I am mainB--layer:/a/b/foo", line); - - List diffs = fSyncService.compare(-1, "mainB--layer:/a", -1, "mainB:/a", null); - assertEquals(1, diffs.size()); - assertEquals("[mainB--layer:/a/b/foo[-1] > mainB:/a/b/foo[-1]]", diffs.toString()); - - fSyncService.update(diffs, null, false, false, false, false, "one", "one"); - fSyncService.flatten("mainB--layer:/a", "mainB:/a"); - - logger.debug("updated: created file: mainB:/a/b/foo"); - - reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB:/a/b/foo"))); - line = reader.readLine(); - reader.close(); - assertEquals("I am mainB--layer:/a/b/foo", line); - - // delete folder - note: short-cut - remove directly from "staging" area (don't bother with sandbox mainA--layer for now) - fService.removeNode("mainA:/a", "b"); - fService.createSnapshot("mainA", null, null); - - logger.debug("removed folder & snapshot: mainA:/a/b"); - - fService.removeNode("mainB--layer:/a/b", "foo"); - fService.createSnapshot("mainB--layer", null, null); - - logger.debug("removed file & snapshot: mainB--layer:/a/b/foo"); - - diffs = fSyncService.compare(-1, "mainB--layer:/a", -1, "mainB:/a", null); - assertEquals(1, diffs.size()); - assertEquals("[mainB--layer:/a/b/foo[-1] > mainB:/a/b/foo[-1]]", diffs.toString()); - - fSyncService.update(diffs, null, false, false, false, false, "one", "one"); - fSyncService.flatten("mainB--layer:/a", "mainB:/a"); - - logger.debug("updated & flattened: removed file: mainB:/a/b/foo"); - - recursiveList("mainA"); - recursiveList("mainB"); - recursiveList("mainB--layer"); - } - catch (Exception e) - { - e.printStackTrace(System.err); - throw e; - } - finally - { - fService.purgeStore("mainA"); - fService.purgeStore("mainB"); - fService.purgeStore("mainB--layer"); - } - } - - public void testLayeredFolderDelete3() throws Exception - { - try - { - fService.createStore("mainA"); - fService.createStore("mainB"); - - fService.createDirectory("mainA:/", "a"); - fService.createDirectory("mainA:/a", "b"); - - fService.createDirectory("mainB:/", "a"); - - fService.createStore("mainB--layer"); - - fService.createLayeredDirectory("mainB:/a", "mainB--layer:/", "a"); - - // note: short-cut - created directly in "staging" area (don't bother with sandbox mainA--layer for now) - fService.createFile("mainA:/a/b", "foo"); - - PrintStream out = new PrintStream(fService.getFileOutputStream("mainA:/a/b/foo")); - out.println("I am mainA:/a/b/foo"); - out.close(); - - logger.debug("created file: mainA:/a/b/foo"); - - // create equivalent of WCM layered folder between web project staging sandboxes (mainB:/a/b pointing to ,mainA:/a/b) - fService.createLayeredDirectory("mainA:/a/b", "mainB:/a", "b"); - - fService.createSnapshot("mainA", null, null); - fService.createSnapshot("mainB", null, null); - - logger.debug("created layered directory: mainB:/a/b -> mainA:/a/b"); - - BufferedReader reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB--layer:/a/b/foo"))); - String line = reader.readLine(); - reader.close(); - assertEquals("I am mainA:/a/b/foo", line); - - out = new PrintStream(fService.getFileOutputStream("mainB--layer:/a/b/foo")); - out.println("I am mainB--layer:/a/b/foo"); - out.close(); - - logger.debug("updated file: mainB--layer:/a/b/foo"); - - reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainA:/a/b/foo"))); - line = reader.readLine(); - reader.close(); - assertEquals("I am mainA:/a/b/foo", line); - - reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB:/a/b/foo"))); - line = reader.readLine(); - reader.close(); - assertEquals("I am mainA:/a/b/foo", line); - - reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB--layer:/a/b/foo"))); - line = reader.readLine(); - reader.close(); - assertEquals("I am mainB--layer:/a/b/foo", line); - - List diffs = fSyncService.compare(-1, "mainB--layer:/a", -1, "mainB:/a", null); - assertEquals(1, diffs.size()); - assertEquals("[mainB--layer:/a/b/foo[-1] > mainB:/a/b/foo[-1]]", diffs.toString()); - - fSyncService.update(diffs, null, false, false, false, false, "one", "one"); - fSyncService.flatten("mainB--layer:/a", "mainB:/a"); - - logger.debug("updated: created file: mainB:/a/b/foo"); - - reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB:/a/b/foo"))); - line = reader.readLine(); - reader.close(); - assertEquals("I am mainB--layer:/a/b/foo", line); - - // delete folder - note: short-cut - remove directly from "staging" area (don't bother with sandbox mainA--layer for now) - fService.removeNode("mainA:/a", "b"); - fService.createSnapshot("mainA", null, null); - - logger.debug("removed folder & snapshot: mainA:/a/b"); - - fService.createFile("mainB--layer:/a/b", "bar"); - - out = new PrintStream(fService.getFileOutputStream("mainB--layer:/a/b/bar")); - out.println("I am mainB--layer:/a/b/bar"); - out.close(); - - logger.debug("created file: mainB--layer:/a/b/bar"); - - diffs = fSyncService.compare(-1, "mainB--layer:/a", -1, "mainB:/a", null); - assertEquals(1, diffs.size()); - assertEquals("[mainB--layer:/a/b/bar[-1] > mainB:/a/b/bar[-1]]", diffs.toString()); - - fSyncService.update(diffs, null, false, false, false, false, "two", "two"); - fSyncService.flatten("mainB--layer:/a", "mainB:/a"); - - logger.debug("updated & flattened: created file: mainB:/a/b/bar"); - - recursiveList("mainA"); - recursiveList("mainB"); - recursiveList("mainB--layer"); - } - catch (Exception e) - { - e.printStackTrace(System.err); - throw e; - } - finally - { - fService.purgeStore("mainA"); - fService.purgeStore("mainB"); - fService.purgeStore("mainB--layer"); - } - } - - public void testLayeredFolderDelete4() throws Exception - { - try - { - fService.createStore("mainA"); - fService.createStore("mainB"); - - fService.createDirectory("mainA:/", "a"); - fService.createDirectory("mainA:/a", "b"); - - fService.createDirectory("mainB:/", "a"); - - fService.createStore("mainB--layer"); - - fService.createLayeredDirectory("mainB:/a", "mainB--layer:/", "a"); - - // note: short-cut - created directly in "staging" area (don't bother with sandbox mainA--layer for now) - fService.createFile("mainA:/a/b", "foo"); - - PrintStream out = new PrintStream(fService.getFileOutputStream("mainA:/a/b/foo")); - out.println("I am mainA:/a/b/foo"); - out.close(); - - logger.debug("created file: mainA:/a/b/foo"); - - // create equivalent of WCM layered folder between web project staging sandboxes (mainB:/a/b pointing to ,mainA:/a/b) - fService.createLayeredDirectory("mainA:/a/b", "mainB:/a", "b"); - - fService.createSnapshot("mainA", null, null); - fService.createSnapshot("mainB", null, null); - - logger.debug("created layered directory: mainB:/a/b -> mainA:/a/b"); - - BufferedReader reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB--layer:/a/b/foo"))); - String line = reader.readLine(); - reader.close(); - assertEquals("I am mainA:/a/b/foo", line); - - out = new PrintStream(fService.getFileOutputStream("mainB--layer:/a/b/foo")); - out.println("I am mainB--layer:/a/b/foo"); - out.close(); - - logger.debug("updated file: mainB--layer:/a/b/foo"); - - reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainA:/a/b/foo"))); - line = reader.readLine(); - reader.close(); - assertEquals("I am mainA:/a/b/foo", line); - - reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB:/a/b/foo"))); - line = reader.readLine(); - reader.close(); - assertEquals("I am mainA:/a/b/foo", line); - - reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB--layer:/a/b/foo"))); - line = reader.readLine(); - reader.close(); - assertEquals("I am mainB--layer:/a/b/foo", line); - - List diffs = fSyncService.compare(-1, "mainB--layer:/a", -1, "mainB:/a", null); - assertEquals(1, diffs.size()); - assertEquals("[mainB--layer:/a/b/foo[-1] > mainB:/a/b/foo[-1]]", diffs.toString()); - - fSyncService.update(diffs, null, false, false, false, false, "one", "one"); - fSyncService.flatten("mainB--layer:/a", "mainB:/a"); - - logger.debug("updated & flattened: updated file: mainB:/a/b/foo"); - - reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB:/a/b/foo"))); - line = reader.readLine(); - reader.close(); - assertEquals("I am mainB--layer:/a/b/foo", line); - - // delete folder - note: short-cut - remove directly from "staging" area (don't bother with sandbox mainA--layer for now) - fService.removeNode("mainA:/a", "b"); - fService.createSnapshot("mainA", null, null); - - logger.debug("removed folder & snapshot: mainA:/a/b"); - - reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB--layer:/a/b/foo"))); - line = reader.readLine(); - reader.close(); - assertEquals("I am mainB--layer:/a/b/foo", line); - - out = new PrintStream(fService.getFileOutputStream("mainB--layer:/a/b/foo")); - out.println("I am mainB--layer:/a/b/foo V2"); - out.close(); - - reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB--layer:/a/b/foo"))); - line = reader.readLine(); - reader.close(); - assertEquals("I am mainB--layer:/a/b/foo V2", line); - - reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB:/a/b/foo"))); - line = reader.readLine(); - reader.close(); - assertEquals("I am mainB--layer:/a/b/foo", line); - - logger.debug("updated file: mainB--layer:/a/b/foo"); - - diffs = fSyncService.compare(-1, "mainB--layer:/a", -1, "mainB:/a", null); - assertEquals(1, diffs.size()); - assertEquals("[mainB--layer:/a/b/foo[-1] > mainB:/a/b/foo[-1]]", diffs.toString()); - - fSyncService.update(diffs, null, false, false, false, false, "two", "two"); - fSyncService.flatten("mainB--layer:/a", "mainB:/a"); - - logger.debug("updated & flattened: updated file: mainB:/a/b/foo"); - - reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB:/a/b/foo"))); - line = reader.readLine(); - reader.close(); - assertEquals("I am mainB--layer:/a/b/foo V2", line); - - recursiveList("mainA"); - recursiveList("mainB"); - recursiveList("mainB--layer"); - } - catch (Exception e) - { - e.printStackTrace(System.err); - throw e; - } - finally - { - fService.purgeStore("mainA"); - fService.purgeStore("mainB"); - fService.purgeStore("mainB--layer"); - } - } - - public void testLayeredFileDeleteFile1() throws Exception - { - try - { - fService.createStore("mainA"); - fService.createStore("mainB"); - fService.createStore("mainB--layer"); - - logger.debug("created 3 stores: mainA, mainB, mainB--layer"); - - fService.createDirectory("mainA:/", "a"); - fService.createDirectory("mainB:/", "a"); - - logger.debug("created 2 plain dirs: mainA:/a and mainB:/a"); - - fService.createLayeredDirectory("mainB:/a", "mainB--layer:/", "a"); - - logger.debug("created layered dir: mainB--layer:/a -> mainB:/a"); - - // note: short-cut - created directly in "staging" area (don't bother with sandbox mainA--layer for now) - fService.createFile("mainA:/a", "foo"); - - PrintStream out = new PrintStream(fService.getFileOutputStream("mainA:/a/foo")); - out.println("I am mainA:/a/foo"); - out.close(); - - logger.debug("created file: mainA:/a/foo"); - - // create equivalent of WCM layered folder between web project staging sandboxes (mainB:/a/b pointing to ,mainA:/a/b) - fService.createLayeredFile("mainA:/a/foo", "mainB:/a", "foo"); - - logger.debug("created layered file: mainB:/a/foo -> mainA:/a/foo"); - - fService.createSnapshot("mainA", null, null); - fService.createSnapshot("mainB", null, null); - - logger.debug("created 2 snapshots: mainA and mainB"); - - BufferedReader reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB--layer:/a/foo"))); - String line = reader.readLine(); - reader.close(); - assertEquals("I am mainA:/a/foo", line); - - reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB:/a/foo"))); - line = reader.readLine(); - reader.close(); - assertEquals("I am mainA:/a/foo", line); - - reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainA:/a/foo"))); - line = reader.readLine(); - reader.close(); - assertEquals("I am mainA:/a/foo", line); - - List diffs = fSyncService.compare(-1, "mainB--layer:/a", -1, "mainB:/a", null); - assertEquals(0, diffs.size()); - - fService.removeNode("mainB--layer:/a", "foo"); - fService.createSnapshot("mainB--layer", null, null); - - logger.debug("removed file & snapshot: mainB--layer:/a/foo"); - - diffs = fSyncService.compare(-1, "mainB--layer:/a", -1, "mainB:/a", null); - assertEquals("[mainB--layer:/a/foo[-1] > mainB:/a/foo[-1]]", diffs.toString()); - - // ETHREEOH-2844 - fSyncService.update(diffs, null, false, false, false, false, "one", "one"); - fSyncService.flatten("mainB--layer:/a", "mainB:/a"); - - logger.debug("updated & flattened: removed file: mainB:/a/foo"); - - recursiveList("mainA"); - recursiveList("mainB"); - recursiveList("mainB--layer"); - } - catch (Exception e) - { - e.printStackTrace(System.err); - throw e; - } - finally - { - fService.purgeStore("mainA"); - fService.purgeStore("mainB"); - fService.purgeStore("mainB--layer"); - } - } - - public void testLayeredFileDeleteFile2() throws Exception - { - try - { - fService.createStore("mainA"); - fService.createStore("mainB"); - fService.createStore("mainB--layer"); - - logger.debug("created 3 stores: mainA, mainB, mainB--layer"); - - fService.createDirectory("mainA:/", "a"); - fService.createDirectory("mainB:/", "a"); - - logger.debug("created 2 plain dirs: mainA:/a and mainB:/a"); - - fService.createLayeredDirectory("mainB:/a", "mainB--layer:/", "a"); - - logger.debug("created layered dir: mainB--layer:/a -> mainB:/a"); - - // note: short-cut - created directly in "staging" area (don't bother with sandbox mainA--layer for now) - fService.createFile("mainA:/a", "foo"); - - PrintStream out = new PrintStream(fService.getFileOutputStream("mainA:/a/foo")); - out.println("I am mainA:/a/foo"); - out.close(); - - logger.debug("created file: mainA:/a/foo"); - - // create equivalent of WCM layered folder between web project staging sandboxes (mainB:/a/b pointing to ,mainA:/a/b) - fService.createLayeredFile("mainA:/a/foo", "mainB:/a", "foo"); - - logger.debug("created layered file: mainB:/a/foo -> mainA:/a/foo"); - - fService.createSnapshot("mainA", null, null); - fService.createSnapshot("mainB", null, null); - - logger.debug("created 2 snapshots: mainA and mainB"); - - BufferedReader reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB--layer:/a/foo"))); - String line = reader.readLine(); - reader.close(); - assertEquals("I am mainA:/a/foo", line); - - reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB:/a/foo"))); - line = reader.readLine(); - reader.close(); - assertEquals("I am mainA:/a/foo", line); - - reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainA:/a/foo"))); - line = reader.readLine(); - reader.close(); - assertEquals("I am mainA:/a/foo", line); - - List diffs = fSyncService.compare(-1, "mainB--layer:/a", -1, "mainB:/a", null); - assertEquals(0, diffs.size()); - - // note: short-cut - removed directly from "staging" area (don't bother with sandbox mainA--layer for now) - fService.removeNode("mainA:/a", "foo"); - fService.createSnapshot("mainA", null, null); - - logger.debug("removed file & snapshot: mainA:/a/foo"); - - try - { - fService.getFileInputStream(-1, "mainA:/a/foo"); - fail("Unexpected"); - } - catch (AVMNotFoundException nfe) - { - // expected - } - - try - { - fService.getFileInputStream(-1, "mainB:/a/foo"); - fail("Unexpected"); - } - catch (AVMNotFoundException nfe) - { - // expected - } - - try - { - fService.getFileInputStream(-1, "mainB--layer:/a/foo"); - fail("Unexpected"); - } - catch (AVMNotFoundException nfe) - { - // expected - } - - fService.removeNode("mainB--layer:/a", "foo"); - fService.createSnapshot("mainB--layer", null, null); - - logger.debug("removed file & snapshot: mainB--layer:/a/foo"); - - diffs = fSyncService.compare(-1, "mainB--layer:/a", -1, "mainB:/a", null); - assertEquals("[mainB--layer:/a/foo[-1] > mainB:/a/foo[-1]]", diffs.toString()); - - // ETHREEOH-2829 - fSyncService.update(diffs, null, false, false, false, false, "one", "one"); - fSyncService.flatten("mainB--layer:/a", "mainB:/a"); - - logger.debug("updated & flattened: removed file: mainB:/a/foo"); - - recursiveList("mainA"); - recursiveList("mainB"); - recursiveList("mainB--layer"); - } - catch (Exception e) - { - e.printStackTrace(System.err); - throw e; - } - finally - { - fService.purgeStore("mainA"); - fService.purgeStore("mainB"); - fService.purgeStore("mainB--layer"); - } - } - - public void testLayeredFileDeleteFile3() throws Exception - { - try - { - fService.createStore("mainB"); - fService.createStore("mainB--layer"); - - logger.debug("created 2 stores: mainB, mainB--layer"); - - fService.createDirectory("mainB:/", "a"); - - logger.debug("created plain dir: mainB:/a"); - - fService.createLayeredDirectory("mainB:/a", "mainB--layer:/", "a"); - - logger.debug("created layered dir: mainB--layer:/a -> mainB:/a"); - - // create equivalent of WCM layered file between web project staging sandboxes (mainB:/a/b/foo pointing to mainA:/a/b/foo) - fService.createLayeredFile("mainA:/a/foo", "mainB:/a", "foo"); // note: unbacked/stale here ... even store does not exist !! - - logger.debug("created layered file: mainB:/a/foo -> mainA:/a/foo"); - - List diffs = fSyncService.compare(-1, "mainB--layer:/a", -1, "mainB:/a", null); - assertEquals(0, diffs.size()); - - // create file - fService.createFile("mainB--layer:/a", "bar"); - - logger.debug("created file: mainB--layer:/a/bar"); - - diffs = fSyncService.compare(-1, "mainB--layer:/a", -1, "mainB:/a", null); - assertEquals("[mainB--layer:/a/bar[-1] > mainB:/a/bar[-1]]", diffs.toString()); - - fSyncService.update(diffs, null, false, false, false, false, "one", "one"); - - logger.debug("updated: created file: mainB:/a/bar"); - - fSyncService.flatten("mainB--layer:/a", "mainB:/a"); - - logger.debug("flattened: created file: mainB:/a/bar"); - - // delete layered file (from mainB--layer) - fService.removeNode("mainB--layer:/a", "foo"); - fService.createSnapshot("mainB--layer", null, null); - - logger.debug("removed file & snapshot: mainB--layer:/a/foo"); - - diffs = fSyncService.compare(-1, "mainB--layer:/a", -1, "mainB:/a", null); - assertEquals("[mainB--layer:/a/foo[-1] > mainB:/a/foo[-1]]", diffs.toString()); - - fService.createStore("mainB--workflow1"); - - logger.debug("created store: mainB--workflow1"); - - recursiveList("mainB--workflow1"); - - fService.createLayeredDirectory("mainB:/a", "mainB--workflow1:/", "a"); - - logger.debug("created layered dir: mainB--workflow1:/a -> mainB:/a"); - - recursiveList("mainB"); - recursiveList("mainB--layer"); - recursiveList("mainB--workflow1"); - - diffs = fSyncService.compare(-1, "mainB--workflow1:/a", -1, "mainB:/a", null); - assertEquals(0, diffs.size()); - - diffs = new ArrayList(1); - diffs.add(new AVMDifference(-1, "mainB--layer:/a/foo", -1, "mainB--workflow1:/a/foo", AVMDifference.NEWER)); - - // ETHREEOH-2868 - fSyncService.update(diffs, null, false, false, false, false, null, null); - - logger.debug("updated: removed file: mainB--workflow1:/a/foo"); - - recursiveList("mainB"); - recursiveList("mainB--layer"); - recursiveList("mainB--workflow1"); - - diffs = fSyncService.compare(-1, "mainB--workflow1:/a", -1, "mainB:/a", null); - assertEquals("[mainB--workflow1:/a/foo[-1] > mainB:/a/foo[-1]]", diffs.toString()); - - fSyncService.update(diffs, null, false, false, true, true, "one", "one"); - fSyncService.flatten("mainB--workflow1:/a", "mainB:/a"); - - logger.debug("updated & flattened: removed file: mainB:/a/foo"); - - diffs = fSyncService.compare(-1, "mainB--workflow1:/a", -1, "mainB:/a", null); - assertEquals(0, diffs.size()); - - diffs = fSyncService.compare(-1, "mainB--workflow1:/a", -1, "mainB--layer:/a", null); - assertEquals(0, diffs.size()); - - fSyncService.update(diffs, null, true, true, false, false, null, null); - fSyncService.flatten("mainB--layer:/a", "mainB--workflow1:/a"); - - recursiveList("mainB"); - recursiveList("mainB--layer"); - } - catch (Exception e) - { - e.printStackTrace(System.err); - throw e; - } - finally - { - fService.purgeStore("mainB"); - fService.purgeStore("mainB--layer"); - if (fService.getStore("mainB--workflow1") != null) { fService.purgeStore("mainB--workflow1"); } - } - } - - public void testLayeredFileDeleteFile4() throws Exception - { - try - { - fService.createStore("mainA"); - fService.createStore("mainB"); - fService.createStore("mainB--layer"); - - logger.debug("created 3 stores: mainA, mainB, mainB--layer"); - - fService.createDirectory("mainA:/", "a"); - fService.createDirectory("mainB:/", "a"); - - logger.debug("created 2 plain dirs: mainA:/a and mainB:/a"); - - fService.createSnapshot("mainA", null, null); - fService.createSnapshot("mainB", null, null); - - logger.debug("created 2 snapshots: mainA and mainB"); - - fService.createLayeredDirectory("mainB:/a", "mainB--layer:/", "a"); - - logger.debug("created layered dir: mainB--layer:/a -> mainB:/a"); - - // note: short-cut - created directly in "staging" areas (don't bother with sandbox mainA--layer or mainB--layer for now) - fService.createDirectory("mainA:/a", "b"); - fService.createDirectory("mainB:/a", "b"); - - logger.debug("created directories: mainA:/a/b & mainB:/a/b"); - - fService.createFile("mainA:/a/b", "foo"); - - PrintStream out = new PrintStream(fService.getFileOutputStream("mainA:/a/b/foo")); - out.println("I am mainA:/a/b/foo"); - out.close(); - - logger.debug("created file: mainA:/a/b/foo"); - - // create equivalent of WCM layered file between web project staging sandboxes (mainB:/a/b/foo pointing to mainA:/a/b/foo) - fService.createLayeredFile("mainA:/a/b/foo", "mainB:/a/b", "foo"); - - logger.debug("created layered file: mainB:/a/b/foo -> mainA:/a/b/foo"); - - BufferedReader reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB--layer:/a/b/foo"))); - String line = reader.readLine(); - reader.close(); - assertEquals("I am mainA:/a/b/foo", line); - - reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB:/a/b/foo"))); - line = reader.readLine(); - reader.close(); - assertEquals("I am mainA:/a/b/foo", line); - - reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainA:/a/b/foo"))); - line = reader.readLine(); - reader.close(); - assertEquals("I am mainA:/a/b/foo", line); - - List diffs = fSyncService.compare(-1, "mainB--layer:/a/b", -1, "mainB:/a/b", null); - assertEquals(0, diffs.size()); - - // create file - fService.createFile("mainB--layer:/a/b", "bar"); - - logger.debug("created file: mainB--layer:/a/b/bar"); - - diffs = fSyncService.compare(-1, "mainB--layer:/a/b", -1, "mainB:/a/b", null); - assertEquals("[mainB--layer:/a/b/bar[-1] > mainB:/a/b/bar[-1]]", diffs.toString()); - - fSyncService.update(diffs, null, false, false, false, false, "one", "one"); - fSyncService.flatten("mainB--layer:/a/b", "mainB:/a/b"); - - logger.debug("updated & flattened: created file: mainB:/a/b/bar"); - - // delete layered file (from mainB--layer) - fService.removeNode("mainB--layer:/a/b", "foo"); - fService.createSnapshot("mainB--layer", null, null); - - logger.debug("removed file & snapshot: mainB--layer:/a/b/foo"); - - diffs = fSyncService.compare(-1, "mainB--layer:/a/b", -1, "mainB:/a/b", null); - assertEquals("[mainB--layer:/a/b/foo[-1] > mainB:/a/b/foo[-1]]", diffs.toString()); - - fService.createStore("mainB--workflow1"); - - fService.createLayeredDirectory("mainB:/a", "mainB--workflow1:/", "a"); - - logger.debug("created layered dir: mainB--workflow1:/a -> mainB:/a"); - - recursiveList("mainA"); - recursiveList("mainB"); - recursiveList("mainB--layer"); - recursiveList("mainB--workflow1"); - - diffs = fSyncService.compare(-1, "mainB--workflow1:/a/b", -1, "mainB:/a/b", null); - assertEquals(0, diffs.size()); - - diffs = new ArrayList(1); - diffs.add(new AVMDifference(-1, "mainB--layer:/a/b/foo", -1, "mainB--workflow1:/a/b/foo", AVMDifference.NEWER)); - - // ETHREEOH-2868 - fSyncService.update(diffs, null, false, false, false, false, null, null); - - logger.debug("updated: removed file: mainB--workflow1:/a/b/foo"); - - recursiveList("mainA"); - recursiveList("mainB"); - recursiveList("mainB--layer"); - recursiveList("mainB--workflow1"); - - diffs = fSyncService.compare(-1, "mainB--workflow1:/a/b", -1, "mainB:/a/b", null); - assertEquals("[mainB--workflow1:/a/b/foo[-1] > mainB:/a/b/foo[-1]]", diffs.toString()); - - fSyncService.update(diffs, null, false, false, true, true, "one", "one"); - fSyncService.flatten("mainB--workflow1:/a/b", "mainB:/a/b"); - - logger.debug("updated & flattened: removed file: mainB:/a/b/foo"); - - diffs = fSyncService.compare(-1, "mainB--workflow1:/a/b", -1, "mainB:/a/b", null); - assertEquals(0, diffs.size()); - - diffs = fSyncService.compare(-1, "mainB--workflow1:/a/b", -1, "mainB--layer:/a/b", null); - assertEquals(0, diffs.size()); - - fSyncService.update(diffs, null, true, true, false, false, null, null); - fSyncService.flatten("mainB--layer:/a/b", "mainB--workflow1:/a/b"); - - recursiveList("mainA"); - recursiveList("mainB"); - recursiveList("mainB--layer"); - } - catch (Exception e) - { - e.printStackTrace(System.err); - throw e; - } - finally - { - fService.purgeStore("mainA"); - fService.purgeStore("mainB"); - fService.purgeStore("mainB--layer"); - if (fService.getStore("mainB--workflow1") != null) { fService.purgeStore("mainB--workflow1"); } - } - } - - protected void recursiveContents(String path) - { - String contentsStr = recursiveContents(path, -1, true); - if (logger.isDebugEnabled()) - { - logger.debug(contentsStr); - } - } - - /** - * Get the recursive contents of the given path and version. - * @param path - * @param version - * @return A string representation of the contents. - */ - protected String recursiveContents(String path, int version, boolean followLinks) - { - String val = recursiveList(path, version, 0, followLinks); - return val.substring(val.indexOf('\n')); - } - - protected void recursiveList(String store) - { - String list = recursiveList(store, -1, true); - if (logger.isDebugEnabled()) - { - logger.debug("\n\n"+store+":"+"\n"+list+"\n"); - } - } - - /** - * 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 = fService.lookup(version, path, true); - builder.append(desc.toString()); - - List ancs = fService.getHistory(desc, -1); - for (AVMNodeDescriptor anc : ancs) - { - builder.append("--->").append(anc.toString()); - } - - builder.append('\n'); - if (desc.getType() == AVMNodeType.PLAIN_DIRECTORY || - (desc.getType() == AVMNodeType.LAYERED_DIRECTORY && followLinks)) - { - String basename = path.endsWith("/") ? path : path + "/"; - Map listing = fService.getDirectoryListing(version, path); - for (String name : listing.keySet()) - { - if (logger.isTraceEnabled()) { logger.trace(name); } - builder.append(recursiveList(basename + name, version, indent + 2, followLinks)); - } - List deletedList = fService.getDeleted(version, path); - for (String name : deletedList) - { - if (logger.isTraceEnabled()) { logger.trace(name); } - builder.append(recursiveList(basename + name, version, indent + 2, followLinks)); - } - } - return builder.toString(); - } - - /** - * Setup a basic tree. - */ - protected void setupBasicTree() - throws IOException - { - fService.createDirectory("main:/", "a"); - fService.createDirectory("main:/a", "b"); - fService.createDirectory("main:/a/b", "c"); - fService.createDirectory("main:/", "d"); - fService.createDirectory("main:/d", "e"); - fService.createDirectory("main:/d/e", "f"); - - - OutputStream out = fService.createFile("main:/a/b/c", "foo"); - byte [] buff = "I am main:/a/b/c/foo".getBytes(); - out.write(buff); - out.close(); - - /* - fService.createFile("main:/a/b/c", "foo").close(); - ContentWriter writer = fService.getContentWriter("main:/a/b/c/foo"); - writer.setEncoding("UTF-8"); - writer.setMimetype(MimetypeMap.MIMETYPE_TEXT_PLAIN); - writer.putContent("I am main:/a/b/c/foo"); - */ - - out = fService.createFile("main:/a/b/c", "bar"); - buff = "I am main:/a/b/c/bar".getBytes(); - out.write(buff); - out.close(); - - /* - fService.createFile("main:/a/b/c", "bar").close(); - writer = fService.getContentWriter("main:/a/b/c/bar"); - // Force a conversion - writer.setEncoding("UTF-16"); - writer.setMimetype(MimetypeMap.MIMETYPE_TEXT_PLAIN); - writer.putContent("I am main:/a/b/c/bar"); - */ - - fService.createSnapshot("main", null, null); - } -} +/* + * Copyright (C) 2005-2009 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; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.PrintStream; +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.repo.security.authentication.AuthenticationUtil; +import org.alfresco.service.cmr.avm.AVMNodeDescriptor; +import org.alfresco.service.cmr.avm.AVMNotFoundException; +import org.alfresco.service.cmr.avm.AVMStoreDescriptor; +import org.alfresco.service.cmr.avm.VersionDescriptor; +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.ApplicationContextHelper; +import org.alfresco.util.NameMatcher; +import org.springframework.extensions.surf.util.Pair; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.context.ApplicationContext; + +/** + * Local unit tests of AVM (AVMSyncService & AVMService) + */ +public class AVMServiceLocalTest extends TestCase +{ + private static Log logger = LogFactory.getLog(AVMServiceLocalTest.class); + + /** + * The AVMRemote - can be local (AVMRemoteLocal) or remote (AVMRemote) + */ + protected static AVMRemote fService; + + /** + * The AVMSyncService - can be local (AVMSyncService) or remote (AVMSyncServiceRemote) + */ + protected static AVMSyncService fSyncService; + + /** + * The application context. + */ + protected static ApplicationContext fContext; + + protected static NameMatcher excluder; + + + protected void setUp() throws Exception + { + if (fContext == null) + { + // local (embedded) test setup + fContext = ApplicationContextHelper.getApplicationContext(); + fService = (AVMRemote)fContext.getBean("avmRemote"); + fSyncService = (AVMSyncService)fContext.getBean("AVMSyncService"); + excluder = (NameMatcher) fContext.getBean("globalPathExcluder"); + + AuthenticationService authService = (AuthenticationService)fContext.getBean("AuthenticationService"); + authService.authenticate(AuthenticationUtil.getAdminUserName(), "admin".toCharArray()); + } + + if (fService.getStore("main") == null) + { + fService.createStore("main"); + } + if (fService.getStore("layer") == null) + { + fService.createStore("layer"); + } + } + + @Override + protected void tearDown() throws Exception + { + fService.purgeStore("main"); + fService.purgeStore("layer"); + } + + public void testSetup() throws Exception + { + setUp(); + } + + public void testGetAPath() throws Exception + { + try + { + fService.createStore("test2932"); + fService.createDirectory("test2932:/", "a"); + fService.createFile("test2932:/a", "foo.txt").close(); + AVMNodeDescriptor found = fService.lookup(-1, "test2932:/a/foo.txt"); + Pair path = fService.getAPath(found); + assertEquals(path.getSecond(), "test2932:/a/foo.txt"); + explorePaths("test2932:/"); + } + catch (Exception e) + { + e.printStackTrace(); + throw e; + } + finally + { + fService.purgeStore("test2932"); + } + } + + /** + * Do a simple hello world test. + */ + public void testSimple() throws Throwable + { + try + { + List stores = fService.getStores(); + + for (AVMStoreDescriptor store : stores) + { + if (logger.isDebugEnabled()) { logger.debug(store); } + } + } + catch (Exception e) + { + e.printStackTrace(System.err); + throw e; + } + } + + protected void explorePaths(String path) throws Exception + { + Map listing = fService.getDirectoryListing(-1, path); + for (Map.Entry entry : listing.entrySet()) + { + Pair childPath = fService.getAPath(entry.getValue()); + if (logger.isDebugEnabled()) { logger.debug(childPath); } + if (entry.getValue().isDirectory()) + { + explorePaths(entry.getValue().getPath()); + } + } + } + + /** + * Test reading and writing. + */ + public void testReadWrite() throws Throwable + { + try + { + // Create a test store. + fService.createStore("test2933"); + // Create a directory. + fService.createDirectory("test2933:/", "a"); + // Write out a file. + OutputStream out = + fService.createFile("test2933:/a", "foo.txt"); + byte [] buff = "This is a plain old text file.\n".getBytes(); + out.write(buff); + buff = "It contains text.\n".getBytes(); + out.write(buff); + out.close(); + // Read back that file. + InputStream in = + fService.getFileInputStream(-1, "test2933:/a/foo.txt"); + buff = new byte[1024]; + assertEquals(49, in.read(buff)); + if (logger.isDebugEnabled()) { logger.debug(new String(buff)); } + assertEquals(-1, in.read(buff)); + } + catch (Exception e) + { + e.printStackTrace(System.err); + throw e; + } + finally + { + fService.purgeStore("test2933"); + } + } + + /** + * Another test of reading. + */ + public void testRead() throws Throwable + { + try + { + fService.createStore("froo"); + // Create a file. + byte [] buff = new byte[64]; + for (int i = 0; i < 64; i++) + { + buff[i] = (byte)i; + } + OutputStream out = + fService.createFile("froo:/", "foo.dat"); + out.write(buff, 32, 32); + out.close(); + // Read it back in. + InputStream in = + fService.getFileInputStream(-1, "froo:/foo.dat"); + buff = new byte[1024]; + assertEquals(32, in.read(buff)); + in.close(); + } + catch (Exception e) + { + e.printStackTrace(System.err); + throw e; + } + finally + { + fService.purgeStore("froo"); + } + } + + /** + * Test a call that should return null; + */ + public void testErrorState() throws Throwable + { + try + { + assertNull(fService.lookup(-1, "main:/fizz/fazz")); + } + catch (Exception e) + { + e.printStackTrace(System.err); + throw e; + } + } + + + /** + * Test update to branch + */ + public void testSimpleUpdateBR() throws Throwable + { + try + { + // Create a store. + fService.createStore("froo"); + // Create a directory. + fService.createDirectory("froo:/", "a"); + // Create a file. + fService.createFile("froo:/a", "foo").close(); + // Create another store. + fService.createStore("broo"); + // Create a branch. + fService.createBranch(-1, "froo:/a", "broo:/", "a"); + List diffs = fSyncService.compare(-1, "froo:/a", -1, "broo:/a", null); + assertEquals(0, diffs.size()); + fService.createFile("froo:/a", "bar").close(); + diffs = fSyncService.compare(-1, "froo:/a", -1, "broo:/a", null); + assertEquals(1, diffs.size()); + assertEquals("[froo:/a/bar[-1] > broo:/a/bar[-1]]", diffs.toString()); + // Update. + fSyncService.update(diffs, null, false, false, false, false, "flippy", "Stuff"); + diffs = fSyncService.compare(-1, "froo:/a", -1, "broo:/a", null); + assertEquals(0, diffs.size()); + } + catch (Exception e) + { + e.printStackTrace(); + throw e; + } + finally + { + fService.purgeStore("broo"); + fService.purgeStore("froo"); + } + } + + // + // 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 directory b and file foo in layer + fService.createDirectory("layer:/layer", "b"); + 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:/"); + + fService.createStore("layer2"); + fService.createLayeredDirectory("layer:/layer", "layer2:/", "layer"); + + // create directory c and file foo in layer2 + fService.createDirectory("layer2:/layer/", "c"); + 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("main"); + recursiveList("layer"); + recursiveList("layer2"); + } + catch (Exception e) + { + e.printStackTrace(System.err); + throw e; + } + finally + { + fService.purgeStore("layer2"); + } + } + + public void testSimpleUpdateLD5() throws Exception + { + try + { + logger.debug("created 2 stores: main, layer"); + + fService.createLayeredDirectory("main:/", "layer:/", "layer"); + + logger.debug("created layered dir: layer:/layer -> main:/"); + + fService.createDirectory("layer:/layer", "b"); + + logger.debug("created dir in layer: layer:/layer/b"); + + List diffs = fSyncService.compare(-1, "layer:/layer", -1, "main:/", null); + assertEquals(1, diffs.size()); + assertEquals("[layer:/layer/b[-1] > main:/b[-1]]", diffs.toString()); + + fSyncService.update(diffs, null, false, false, false, false, null, null); + + diffs = fSyncService.compare(-1, "layer:/layer", -1, "main:/", null); + assertEquals(0, diffs.size()); + + fSyncService.flatten("layer:/layer", "main:/"); + + logger.debug("updated & flattened: created directory: main:/b"); + + fService.createFile("layer:/layer/b", "foo").close(); + fService.createFile("layer:/layer/b", "bar").close(); + + logger.debug("created 2 files in layer: layer:/layer/b/foo and layer:/layer/b/bar"); + + diffs = fSyncService.compare(-1, "layer:/layer", -1, "main:/", null); + assertEquals(2, diffs.size()); + assertEquals("[layer:/layer/b/bar[-1] > main:/b/bar[-1], layer:/layer/b/foo[-1] > main:/b/foo[-1]]", diffs.toString()); + + // submit only first diff + List selected = new ArrayList(1); + selected.add(diffs.get(1)); + + assertEquals("[layer:/layer/b/foo[-1] > main:/b/foo[-1]]", selected.toString()); + + fSyncService.update(selected, null, false, false, false, false, null, null); + + diffs = fSyncService.compare(-1, "layer:/layer", -1, "main:/", null); + assertEquals(1, diffs.size()); + assertEquals("[layer:/layer/b/bar[-1] > main:/b/bar[-1]]", diffs.toString()); + + fSyncService.flatten("layer:/layer", "main:/"); + + logger.debug("updated & flattened: created file: main:/b/foo"); + + fService.removeNode("layer:/layer", "b"); + fService.createSnapshot("layer", null, null); + + logger.debug("removed dir in layer & snapshot: layer:/layer/b"); + + // ETWOTWO-1266 + diffs = fSyncService.compare(-1, "layer:/layer", -1, "main:/", null); + assertEquals(1, diffs.size()); + assertEquals("[layer:/layer/b[-1] > main:/b[-1]]", diffs.toString()); + + fSyncService.update(diffs, null, false, false, false, false, null, null); + + diffs = fSyncService.compare(-1, "layer:/layer", -1, "main:/", null); + assertEquals(0, diffs.size()); + + fSyncService.flatten("layer:/layer", "main:/"); + + logger.debug("updated & flattened: deleted dir: main:/b"); + + recursiveList("main"); + recursiveList("layer"); + } + catch (Exception e) + { + e.printStackTrace(System.err); + throw e; + } + } + + public void testDeleteLD1() throws Exception + { + try + { + logger.debug("created 2 stores: main, layer"); + + fService.createDirectory("main:/", "a"); + + OutputStream o = fService.createFile("main:/a", "foo"); + PrintStream out = new PrintStream(o); + out.println("I am main:/a/foo"); + out.close(); + + logger.debug("created file in main: main:/a/foo"); + + fService.createLayeredDirectory("main:/a", "layer:/", "a"); + + logger.debug("created layered dir: layer:/a -> main:/a"); + + BufferedReader reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "layer:/a/foo"))); + String line = reader.readLine(); + reader.close(); + assertEquals("I am main:/a/foo", line); + + reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "main:/a/foo"))); + line = reader.readLine(); + reader.close(); + assertEquals("I am main:/a/foo", line); + + out = new PrintStream(fService.getFileOutputStream("layer:/a/foo")); + out.println("I am layer:/a/foo"); + out.close(); + + logger.debug("update file in layer: layer:/a/foo"); + + reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "layer:/a/foo"))); + line = reader.readLine(); + reader.close(); + assertEquals("I am layer:/a/foo", line); + + reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "main:/a/foo"))); + line = reader.readLine(); + reader.close(); + assertEquals("I am main:/a/foo", line); + + List diffs = fSyncService.compare(-1, "layer:/a", -1, "main:/a", null); + assertEquals(1, diffs.size()); + assertEquals("[layer:/a/foo[-1] > main:/a/foo[-1]]", diffs.toString()); + + fSyncService.update(diffs, null, false, false, false, false, null, null); + + diffs = fSyncService.compare(-1, "layer:/a", -1, "main:/a", null); + assertEquals(0, diffs.size()); + + fSyncService.flatten("layer:/a", "main:/a"); + + logger.debug("updated & flattened: updated file: main:/a/foo"); + + reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "layer:/a/foo"))); + line = reader.readLine(); + reader.close(); + assertEquals("I am layer:/a/foo", line); + + reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "main:/a/foo"))); + line = reader.readLine(); + reader.close(); + assertEquals("I am layer:/a/foo", line); + + fService.removeNode("main:/", "a"); + fService.createSnapshot("main", null, null); + + logger.debug("remove directory in main & snapshot: main:/a"); + + assertNotNull(fService.lookup(-1, "layer:/a")); + assertNull(fService.lookup(-1, "layer:/a/foo")); + + try + { + fService.getFileInputStream(-1, "layer:/a/foo"); + fail(); + } + catch (AVMNotFoundException nfe) + { + // expected + } + + try + { + fService.getFileOutputStream("layer:/a/foo"); + fail(); + } + catch (AVMNotFoundException nfe) + { + // expected + } + + recursiveList("main"); + recursiveList("layer"); + } + catch (Exception e) + { + e.printStackTrace(System.err); + throw e; + } + } + + public void testDeleteLD2() throws Exception + { + try + { + logger.debug("created 2 stores: main, layer"); + + fService.createDirectory("main:/", "a"); + + OutputStream o = fService.createFile("main:/a", "foo"); + PrintStream out = new PrintStream(o); + out.println("I am main:/a/foo"); + out.close(); + + logger.debug("created file in main: main:/a/foo"); + + fService.createLayeredDirectory("main:/a", "layer:/", "a"); + + logger.debug("created layered dir: layer:/a -> main:/a"); + + BufferedReader reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "layer:/a/foo"))); + String line = reader.readLine(); + reader.close(); + assertEquals("I am main:/a/foo", line); + + reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "main:/a/foo"))); + line = reader.readLine(); + reader.close(); + assertEquals("I am main:/a/foo", line); + + out = new PrintStream(fService.getFileOutputStream("layer:/a/foo")); + out.println("I am layer:/a/foo"); + out.close(); + + logger.debug("update file in layer: layer:/a/foo"); + + reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "layer:/a/foo"))); + line = reader.readLine(); + reader.close(); + assertEquals("I am layer:/a/foo", line); + + reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "main:/a/foo"))); + line = reader.readLine(); + reader.close(); + assertEquals("I am main:/a/foo", line); + + fService.removeNode("main:/", "a"); + + logger.debug("remove directory in main: main:/a"); + + fService.createSnapshot("main", null, null); + + logger.debug("snapshot: main:/a"); + + assertNull(fService.lookup(-1, "main:/a")); + assertNull(fService.lookup(-1, "main:/a/foo")); + + try + { + fService.getFileInputStream(-1, "main:/a/foo"); + fail(); + } + catch (AVMNotFoundException nfe) + { + // expected + } + + assertNotNull(fService.lookup(-1, "layer:/a")); + assertNotNull(fService.lookup(-1, "layer:/a/foo")); + + reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "layer:/a/foo"))); + line = reader.readLine(); + reader.close(); + assertEquals("I am layer:/a/foo", line); + + out = new PrintStream(fService.getFileOutputStream("layer:/a/foo")); + out.println("I am layer:/a/foo V2"); + out.close(); + + List diffs = fSyncService.compare(-1, "layer:/a", -1, "main:/a", null); + assertEquals(1, diffs.size()); + assertEquals("[layer:/a[-1] > main:/a[-1]]", diffs.toString()); + + fSyncService.update(diffs, null, false, false, false, false, null, null); + + diffs = fSyncService.compare(-1, "layer:/a", -1, "main:/a", null); + assertEquals(0, diffs.size()); + + logger.debug("updated: updated dir & file: main:/a/foo"); + + fSyncService.flatten("layer:/a", "main:/a"); + + logger.debug("flattened: layer:/a -> main:/a"); + + reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "layer:/a/foo"))); + line = reader.readLine(); + reader.close(); + assertEquals("I am layer:/a/foo V2", line); + + reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "main:/a/foo"))); + line = reader.readLine(); + reader.close(); + assertEquals("I am layer:/a/foo V2", line); + + recursiveList("main"); + recursiveList("layer"); + } + catch (Exception e) + { + e.printStackTrace(System.err); + throw e; + } + } + + /** + * Test bulk update (using layered directory). + */ + public void testBulkUpdateLD() throws Exception + { + try + { + RemoteBulkLoader loader = new RemoteBulkLoader(); + loader.setAvmRemoteService(fService); + + fService.createLayeredDirectory("main:/", "layer:/", "layer"); + loader.recursiveLoad("config/alfresco/bootstrap", "layer:/layer"); + List diffs = fSyncService.compare(-1, "layer:/layer", -1, "main:/", null); + assertEquals(1, diffs.size()); + assertEquals("[layer:/layer/bootstrap[-1] > main:/bootstrap[-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"); + loader.recursiveLoad("config/alfresco/bootstrap", "layer2:/layer/bootstrap"); + fService.createSnapshot("layer2", null, null); + diffs = fSyncService.compare(-1, "layer2:/layer", -1, "layer:/layer", null); + assertEquals(1, diffs.size()); + assertEquals("[layer2:/layer/bootstrap/bootstrap[-1] > layer:/layer/bootstrap/bootstrap[-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/bootstrap/bootstrap[-1] > main:/bootstrap/bootstrap[-1]]", diffs.toString()); + recursiveList("layer2"); + recursiveList("layer"); + recursiveList("main"); + } + catch (Exception e) + { + e.printStackTrace(System.err); + throw e; + } + finally + { + fService.purgeStore("layer2"); + } + } + + /** + * Test the flatten operation, with a little bit of compare and update. + */ + public void testFlatten() throws Exception + { + try + { + setupBasicTree(); + fService.createLayeredDirectory("main:/a", "main:/", "layer"); + fService.createSnapshot("main", null, null); + recursiveList("main"); + // Change some stuff. + fService.createFile("main:/layer/b", "fig").close(); + fService.getFileOutputStream("main:/layer/b/c/foo").close(); + fService.createSnapshot("main", null, null); + recursiveList("main"); + // Do a compare. + List diffs = fSyncService.compare(-1, "main:/layer", -1, "main:/a", null); + assertEquals(2, diffs.size()); + assertEquals("[main:/layer/b/c/foo[-1] > main:/a/b/c/foo[-1], main:/layer/b/fig[-1] > main:/a/b/fig[-1]]", diffs.toString()); + // Update. + fSyncService.update(diffs, null, false, false, false, false, null, null); + recursiveList("main"); + // Flatten. + fSyncService.flatten("main:/layer", "main:/a"); + recursiveList("main"); + } + catch (Exception e) + { + e.printStackTrace(System.err); + throw e; + } + } + + /** + * Test partial flatten. + */ + public void testPartialFlatten() throws Exception + { + try + { + setupBasicTree(); + fService.createLayeredDirectory("main:/a", "layer:/", "a"); + fService.getFileOutputStream("layer:/a/b/c/foo").close(); + fService.createFile("layer:/a/b", "bing").close(); + List diffs = new ArrayList(); + diffs.add(new AVMDifference(-1, "layer:/a/b/c/foo", -1, "main:/a/b/c/foo", AVMDifference.NEWER)); + fSyncService.update(diffs, null, false, false, false, false, null, null); + fSyncService.flatten("layer:/a", "main:/a"); + AVMNodeDescriptor b = fService.lookup(-1, "layer:/a/b"); + assertTrue(b.isLayeredDirectory()); + AVMNodeDescriptor c = fService.lookup(-1, "layer:/a/b/c"); + assertTrue(c.isPlainDirectory()); + diffs = fSyncService.compare(-1, "layer:/a", -1, "main:/a", null); + assertEquals(1, diffs.size()); + assertEquals("[layer:/a/b/bing[-1] > main:/a/b/bing[-1]]", diffs.toString()); + } + catch (Exception e) + { + e.printStackTrace(System.err); + throw e; + } + } + + /** + * Test AVMSyncService resetLayer. + */ + public void testResetLayer() throws Exception + { + try + { + setupBasicTree(); + fService.createLayeredDirectory("main:/a", "main:/", "layer"); + fService.createFile("main:/layer", "figs").close(); + assertFalse(recursiveContents("main:/a", -1, true).equals(recursiveContents("main:/layer", -1, true))); + recursiveList("main"); + fSyncService.resetLayer("main:/layer"); + assertEquals(recursiveContents("main:/a", -1, true), recursiveContents("main:/layer", -1, true)); + recursiveList("main"); + } + catch (Exception e) + { + e.printStackTrace(System.err); + throw e; + } + } + + /** + * Test AVMSyncService update. + */ + public void testUpdate() throws Exception + { + try + { + setupBasicTree(); + // Try branch to branch update. + fService.createBranch(-1, "main:/a", "main:/", "abranch"); + fService.createFile("main:/abranch", "monkey").close(); + fService.createFile("main:/abranch", "#foo").close(); + fService.createFile("main:/abranch", "figs.tmp").close(); + fService.getFileOutputStream("main:/abranch/b/c/foo").close(); + recursiveList("main"); + List cmp = fSyncService.compare(-1, "main:/abranch", -1, "main:/a", excluder); + assertEquals(2, cmp.size()); + assertEquals("[main:/abranch/b/c/foo[-1] > main:/a/b/c/foo[-1], main:/abranch/monkey[-1] > main:/a/monkey[-1]]", cmp.toString()); + List diffs = new ArrayList(); + diffs.add(new AVMDifference(-1, "main:/abranch/monkey", -1, "main:/a/monkey", AVMDifference.NEWER)); + diffs.add(new AVMDifference(-1, "main:/abranch/b/c/foo", -1, "main:/a/b/c/foo", AVMDifference.NEWER)); + fSyncService.update(diffs, null, false, false, false, false, null, null); + fService.createSnapshot("main", null, null); + recursiveList("main"); + assertEquals(fService.lookup(-1, "main:/abranch/monkey").getId(), fService.lookup(-1, "main:/a/monkey").getId()); + assertEquals(fService.lookup(-1, "main:/abranch/b/c/foo").getId(), fService.lookup(-1, "main:/a/b/c/foo").getId()); + // Try updating a deletion. + fService.removeNode("main:/abranch", "monkey"); + recursiveList("main"); + cmp = fSyncService.compare(-1, "main:/abranch", -1, "main:/a", excluder); + assertEquals(1, cmp.size()); + assertEquals("[main:/abranch/monkey[-1] > main:/a/monkey[-1]]", cmp.toString()); + diffs.clear(); + diffs.add(new AVMDifference(-1, "main:/abranch/monkey", -1, "main:/a/monkey", AVMDifference.NEWER)); + fSyncService.update(diffs, null, false, false, false, false, null, null); + assertEquals(0, fSyncService.compare(-1, "main:/abranch", -1, "main:/a", excluder).size()); + fService.createSnapshot("main", null, null); + recursiveList("main"); + assertEquals(fService.lookup(-1, "main:/abranch/monkey", true).getId(), fService.lookup(-1, "main:/a/monkey", true).getId()); + // Try one that should fail. + fService.createFile("main:/abranch", "monkey").close(); + cmp = fSyncService.compare(-1, "main:/abranch", -1, "main:/a", excluder); + assertEquals(1, cmp.size()); + assertEquals("[main:/abranch/monkey[-1] > main:/a/monkey[-1]]", cmp.toString()); + diffs.clear(); + diffs.add(new AVMDifference(-1, "main:/a/monkey", -1, "main:/abranch/monkey", AVMDifference.NEWER)); + try + { + fSyncService.update(diffs, null, false, false, false, false, null, null); + fail(); + } + catch (AVMSyncException se) + { + // Do nothing. + } + // Get synced again by doing an override older. + recursiveList("main"); + diffs.clear(); + diffs.add(new AVMDifference(-1, "main:/a/monkey", -1, "main:/abranch/monkey", AVMDifference.NEWER)); + fSyncService.update(diffs, null, false, false, false, true, null, null); + assertEquals(0, fSyncService.compare(-1, "main:/abranch", -1, "main:/a", excluder).size()); + fService.createSnapshot("main", null, null); + recursiveList("main"); + assertEquals(fService.lookup(-1, "main:/a/monkey", true).getId(), fService.lookup(-1, "main:/abranch/monkey", true).getId()); + // Cleanup for layered tests. + fService.purgeStore("main"); + fService.createStore("main"); + setupBasicTree(); + fService.createLayeredDirectory("main:/a", "main:/", "layer"); + fService.createFile("main:/layer", "monkey").close(); + fService.getFileOutputStream("main:/layer/b/c/foo").close(); + cmp = fSyncService.compare(-1, "main:/layer", -1, "main:/a", excluder); + assertEquals(2, cmp.size()); + assertEquals("[main:/layer/b/c/foo[-1] > main:/a/b/c/foo[-1], main:/layer/monkey[-1] > main:/a/monkey[-1]]", cmp.toString()); + recursiveList("main"); + diffs.clear(); + diffs.add(new AVMDifference(-1, "main:/layer/monkey", -1, "main:/a/monkey", AVMDifference.NEWER)); + diffs.add(new AVMDifference(-1, "main:/layer/b/c/foo", -1, "main:/a/b/c/foo", AVMDifference.NEWER)); + fSyncService.update(diffs, null, false, false, false, false, null, null); + assertEquals(0, fSyncService.compare(-1, "main:/layer", -1, "main:/a", excluder).size()); + fService.createSnapshot("main", null, null); + recursiveList("main"); + assertEquals(fService.lookup(-1, "main:/layer/monkey").getId(), fService.lookup(-1, "main:/a/monkey").getId()); + assertEquals(fService.lookup(-1, "main:/layer/b/c/foo").getId(), fService.lookup(-1, "main:/a/b/c/foo").getId()); + // Try updating a deletion. + fService.removeNode("main:/layer", "monkey"); + recursiveList("main"); + cmp = fSyncService.compare(-1, "main:/layer", -1, "main:/a", excluder); + assertEquals(1, cmp.size()); + assertEquals("[main:/layer/monkey[-1] > main:/a/monkey[-1]]", cmp.toString()); + diffs.clear(); + diffs.add(new AVMDifference(-1, "main:/layer/monkey", -1, "main:/a/monkey", AVMDifference.NEWER)); + fSyncService.update(diffs, null, false, false, false, false, null, null); + assertEquals(0, fSyncService.compare(-1, "main:/layer", -1, "main:/a", excluder).size()); + fService.createSnapshot("main", null, null); + recursiveList("main"); + assertEquals(fService.lookup(-1, "main:/layer/monkey", true).getId(), fService.lookup(-1, "main:/a/monkey", true).getId()); + // Try one that should fail. + fService.createFile("main:/layer", "monkey").close(); + cmp = fSyncService.compare(-1, "main:/layer", -1, "main:/a", excluder); + assertEquals(1, cmp.size()); + assertEquals("[main:/layer/monkey[-1] > main:/a/monkey[-1]]", cmp.toString()); + diffs.clear(); + diffs.add(new AVMDifference(-1, "main:/a/monkey", -1, "main:/layer/monkey", AVMDifference.NEWER)); + try + { + fSyncService.update(diffs, null, false, false, false, false, null, null); + fail(); + } + catch (AVMSyncException se) + { + // Do nothing. + } + // Get synced again by doing an override older. + recursiveList("main"); + diffs.clear(); + diffs.add(new AVMDifference(-1, "main:/a/monkey", -1, "main:/layer/monkey", AVMDifference.NEWER)); + fSyncService.update(diffs, null, false, false, false, true, null, null); + assertEquals(0, fSyncService.compare(-1, "main:/layer", -1, "main:/a", excluder).size()); + fService.createSnapshot("main", null, null); + recursiveList("main"); + assertEquals(fService.lookup(-1, "main:/a/monkey", true).getId(), fService.lookup(-1, "main:/layer/monkey", true).getId()); + } + catch (Exception e) + { + e.printStackTrace(System.err); + throw e; + } + } + + /** + * Test that an update forces a snapshot on the source. + */ + public void testUpdateSnapshot() throws Exception + { + try + { + setupBasicTree(); + fService.createStore("branch"); + fService.createBranch(-1, "main:/", "branch:/", "branch"); + // Modify some things in the branch. + fService.createFile("branch:/branch/a/b", "fing").close(); + fService.getFileOutputStream("branch:/branch/a/b/c/foo").close(); + fService.removeNode("branch:/branch/a/b/c", "bar"); + List diffs = fSyncService.compare(-1, "branch:/branch", -1, "main:/", null); + assertEquals(3, diffs.size()); + assertEquals("[branch:/branch/a/b/c/bar[-1] > main:/a/b/c/bar[-1], branch:/branch/a/b/c/foo[-1] > main:/a/b/c/foo[-1], branch:/branch/a/b/fing[-1] > main:/a/b/fing[-1]]", diffs.toString()); + // Now update. + fSyncService.update(diffs, null, false, false, false, false, null, null); + diffs = fSyncService.compare(-1, "branch:/branch", -1, "main:/", null); + assertEquals(0, diffs.size()); + fService.getFileOutputStream("branch:/branch/a/b/fing").close(); + assertTrue(fService.lookup(-1, "branch:/branch/a/b/fing").getId() != fService.lookup(-1, "main:/a/b/fing").getId()); + } + catch (Exception e) + { + e.printStackTrace(System.err); + throw e; + } + finally + { + fService.purgeStore("branch"); + } + } + + /** + * Test a noodle update. + */ + public void testNoodleUpdate() throws Exception + { + try + { + setupBasicTree(); + fService.createStore("staging"); + List diffs = fSyncService.compare(-1, "main:/", -1, "staging:/", null); + assertEquals(2, diffs.size()); + assertEquals("[main:/a[-1] > staging:/a[-1], main:/d[-1] > staging:/d[-1]]", diffs.toString()); + List noodle = new ArrayList(); + noodle.add(new AVMDifference(-1, "main:/a/b/c/foo", -1, "staging:/a/b/c/foo", AVMDifference.NEWER)); + noodle.add(new AVMDifference(-1, "main:/d", -1, "staging:/d", AVMDifference.NEWER)); + fSyncService.update(noodle, null, false, false, false, false, null, null); + diffs = fSyncService.compare(-1, "main:/", -1, "staging:/", null); + assertEquals(1, diffs.size()); + assertEquals("[main:/a/b/c/bar[-1] > staging:/a/b/c/bar[-1]]", diffs.toString()); + assertEquals("main:/a/b/c/bar", diffs.get(0).getSourcePath()); + } + catch (Exception e) + { + e.printStackTrace(System.err); + throw e; + } + finally + { + fService.purgeStore("staging"); + } + } + + + public void testRename6() throws Exception + { + try + { + setupBasicTree(); + fService.createLayeredDirectory("main:/a", "layer:/", "a"); + fService.rename("layer:/a/b", "c", "layer:/a/b", "z"); + recursiveContents("layer:/"); + List diffs = fSyncService.compare(-1, "layer:/a", -1, "main:/a", null); + assertEquals(2, diffs.size()); + assertEquals("[layer:/a/b/c[-1] > main:/a/b/c[-1], layer:/a/b/z[-1] > main:/a/b/z[-1]]", diffs.toString()); + fSyncService.update(diffs, null, false, false, false, false, null, null); + recursiveContents("layer:/"); + recursiveContents("main:/"); + fSyncService.flatten("layer:/a", "main:/a"); + recursiveContents("layer:/"); + recursiveContents("main:/"); + fService.createFile("layer:/a/b/z", "fudge").close(); + fService.rename("layer:/a/b", "z", "layer:/a/b", "y"); + recursiveContents("layer:/"); + diffs = fSyncService.compare(-1, "layer:/a", -1, "main:/a", null); + assertEquals(2, diffs.size()); + assertEquals("[layer:/a/b/y[-1] > main:/a/b/y[-1], layer:/a/b/z[-1] > main:/a/b/z[-1]]", diffs.toString()); + fSyncService.update(diffs, null, false, false, false, false, null, null); + recursiveContents("layer:/"); + recursiveContents("main:/"); + fSyncService.flatten("layer:/a", "main:/a"); + recursiveContents("layer:/"); + recursiveContents("main:/"); + } + catch (Exception e) + { + e.printStackTrace(); + 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; + } + } + + public void testSimpleUpdateLF1() throws Exception + { + try + { + List snapshots = fService.getStoreVersions("main"); + assertEquals(1, snapshots.size()); + assertEquals(0, snapshots.get(0).getVersionID()); + + snapshots = fService.getStoreVersions("layer"); + assertEquals(1, snapshots.size()); + assertEquals(0, snapshots.get(0).getVersionID()); + + fService.createDirectory("main:/", "a"); + fService.createDirectory("layer:/", "a"); + + logger.debug("created 2 plain dirs: main:/a, layer:/a"); + + fService.createFile("main:/a", "foo"); + + assertEquals(1, fService.lookup(-1, "main:/a/foo").getVersionID()); + + PrintStream out = new PrintStream(fService.getFileOutputStream("main:/a/foo")); + out.println("I am main:/a/foo"); + out.close(); + + AVMNodeDescriptor node = fService.lookup(-1, "main:/a/foo"); + assertEquals(1, node.getVersionID()); + List history = fService.getHistory(node, -1); + assertEquals(0, history.size()); + + fService.createSnapshot("main", null, null); + + snapshots = fService.getStoreVersions("main"); + assertEquals(2, snapshots.size()); + assertEquals(1, snapshots.get(snapshots.size()-1).getVersionID()); + + snapshots = fService.getStoreVersions("layer"); + assertEquals(1, snapshots.size()); + assertEquals(0, snapshots.get(0).getVersionID()); + + assertEquals(1, fService.lookup(-1, "main:/a/foo").getVersionID()); + assertEquals(1, fService.lookup(1, "main:/a/foo").getVersionID()); + + logger.debug("created plain file: main:/a/foo"); + + fService.createLayeredFile("main:/a/foo", "layer:/a", "foo"); + + assertEquals(1, fService.lookup(-1, "layer:/a/foo").getVersionID()); + + BufferedReader reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "layer:/a/foo"))); + String line = reader.readLine(); + reader.close(); + assertEquals("I am main:/a/foo", line); + + node = fService.lookup(-1, "layer:/a/foo"); + assertEquals(1, node.getVersionID()); + + history = fService.getHistory(node, -1); + assertEquals(0, history.size()); + + fService.createSnapshot("layer", null, null); + + snapshots = fService.getStoreVersions("main"); + assertEquals(2, snapshots.size()); + assertEquals(1, snapshots.get(snapshots.size()-1).getVersionID()); + + snapshots = fService.getStoreVersions("layer"); + assertEquals(2, snapshots.size()); + assertEquals(1, snapshots.get(snapshots.size()-1).getVersionID()); + + assertEquals(1, fService.lookup(-1, "layer:/a/foo").getVersionID()); + assertEquals(1, fService.lookup(1, "layer:/a/foo").getVersionID()); + + List diffs = fSyncService.compare(-1, "layer:/a", -1, "main:/a", null); + assertEquals(0, diffs.size()); + + reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "layer:/a/foo"))); + line = reader.readLine(); + reader.close(); + assertEquals("I am main:/a/foo", line); + + logger.debug("created layered file: layer:/a/foo -> main:/a/foo"); + + out = new PrintStream(fService.getFileOutputStream("layer:/a/foo")); + out.println("I am layer:/a/foo"); + out.close(); + + logger.debug("modified file: layer:/a/foo"); + + assertEquals(2, fService.lookup(-1, "layer:/a/foo").getVersionID()); + + reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "main:/a/foo"))); + line = reader.readLine(); + reader.close(); + assertEquals("I am main:/a/foo", line); + + diffs = fSyncService.compare(-1, "layer:/a", -1, "main:/a", null); + assertEquals(1, diffs.size()); + + // TODO - review behaviour + assertEquals("[layer:/a/foo[-1] > main:/a/foo[-1]]", diffs.toString()); + fSyncService.update(diffs, null, false, false, false, false, "one", "one"); + + // update will implicitly snapshot (src and dst) + snapshots = fService.getStoreVersions("main"); + assertEquals(3, snapshots.size()); + assertEquals(2, snapshots.get(snapshots.size()-1).getVersionID()); + + snapshots = fService.getStoreVersions("layer"); + assertEquals(3, snapshots.size()); + assertEquals(2, snapshots.get(snapshots.size()-1).getVersionID()); + + node = fService.lookup(-1, "layer:/a/foo"); + assertEquals(2, node.getVersionID()); + history = fService.getHistory(node, -1); + + assertEquals(1, history.size()); + assertEquals(1, history.get(0).getVersionID()); + + assertEquals(1, fService.lookup(1, "layer:/a/foo").getVersionID()); + assertEquals(2, fService.lookup(2, "layer:/a/foo").getVersionID()); + + logger.debug("submitted/updated file: layer:/a/foo -> main:/a/foo"); + + fSyncService.flatten("layer:/a", "main:/a"); + + logger.debug("flatten dir: layer:/a -> main:/a"); + + reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "layer:/a/foo"))); + line = reader.readLine(); + reader.close(); + assertEquals("I am layer:/a/foo", line); + + reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "main:/a/foo"))); + line = reader.readLine(); + reader.close(); + assertEquals("I am layer:/a/foo", line); + + snapshots = fService.getStoreVersions("main"); + assertEquals(3, snapshots.size()); + assertEquals(2, snapshots.get(snapshots.size()-1).getVersionID()); + + snapshots = fService.getStoreVersions("layer"); + assertEquals(3, snapshots.size()); + assertEquals(2, snapshots.get(snapshots.size()-1).getVersionID()); + + recursiveList("main"); + recursiveList("layer"); + } + catch (Exception e) + { + e.printStackTrace(System.err); + throw e; + } + } + + public void testSimpleUpdateLF2() throws Exception + { + try + { + fService.createStore("mainA"); + fService.createStore("mainB"); + fService.createStore("mainB--layer"); + + List snapshots = fService.getStoreVersions("mainA"); + assertEquals(1, snapshots.size()); + assertEquals(0, snapshots.get(0).getVersionID()); + + snapshots = fService.getStoreVersions("mainB"); + assertEquals(1, snapshots.size()); + assertEquals(0, snapshots.get(0).getVersionID()); + + snapshots = fService.getStoreVersions("mainB--layer"); + assertEquals(1, snapshots.size()); + assertEquals(0, snapshots.get(0).getVersionID()); + + logger.debug("created 3 stores: mainA, mainB, mainB-layer"); + + fService.createDirectory("mainA:/", "a"); + fService.createDirectory("mainB:/", "a"); + + logger.debug("created 2 plain dirs: mainA:/a, mainB:/a"); + + fService.createLayeredDirectory("mainB:/a", "mainB--layer:/", "a"); + + logger.debug("created layered dir: mainB--layer:/a -> mainB:/a"); + + // note: unlike WCM, edit staging directly (ie. don't bother with mainA--layer for now) + fService.createFile("mainA:/a", "foo"); + + assertEquals(1, fService.lookup(-1, "mainA:/a/foo").getVersionID()); + assertNull(fService.lookup(-1, "mainB:/a/foo")); + assertNull(fService.lookup(-1, "mainB--layer:/a/foo")); + + PrintStream out = new PrintStream(fService.getFileOutputStream("mainA:/a/foo")); + out.println("I am mainA:/a/foo"); + out.close(); + + logger.debug("created plain file: mainA:/a/foo"); + + fService.createSnapshot("mainA", null, null); + + assertEquals(1, fService.lookup(-1, "mainA:/a/foo").getVersionID()); + assertNull(fService.lookup(-1, "mainB:/a/foo")); + assertNull(fService.lookup(-1, "mainB--layer:/a/foo")); + + snapshots = fService.getStoreVersions("mainA"); + assertEquals(2, snapshots.size()); + assertEquals(1, snapshots.get(snapshots.size()-1).getVersionID()); + + logger.debug("created snapshot: mainA"); + + // note: WCM does not expose layered file (between web project staging sandboxes) + fService.createLayeredFile("mainA:/a/foo", "mainB:/a", "foo"); + + assertEquals(1, fService.lookup(-1, "mainA:/a/foo").getVersionID()); + assertEquals(1, fService.lookup(-1, "mainB:/a/foo").getVersionID()); + assertEquals(1, fService.lookup(-1, "mainB--layer:/a/foo").getVersionID()); + + BufferedReader reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB--layer:/a/foo"))); + String line = reader.readLine(); + reader.close(); + assertEquals("I am mainA:/a/foo", line); + + reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB:/a/foo"))); + line = reader.readLine(); + reader.close(); + assertEquals("I am mainA:/a/foo", line); + + reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainA:/a/foo"))); + line = reader.readLine(); + reader.close(); + assertEquals("I am mainA:/a/foo", line); + + logger.debug("created layered file: mainB:/a/foo -> mainA:/a/foo"); + + // modify file in user's sandbox + out = new PrintStream(fService.getFileOutputStream("mainB--layer:/a/foo")); + out.println("I am mainB--layer:/a/foo"); + out.close(); + + assertEquals(1, fService.lookup(-1, "mainA:/a/foo").getVersionID()); + assertEquals(1, fService.lookup(-1, "mainB:/a/foo").getVersionID()); + assertEquals(2, fService.lookup(-1, "mainB--layer:/a/foo").getVersionID()); + + logger.debug("modified file: mainB--layer:/a/foo"); + + reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB--layer:/a/foo"))); + line = reader.readLine(); + reader.close(); + assertEquals("I am mainB--layer:/a/foo", line); + + reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB:/a/foo"))); + line = reader.readLine(); + reader.close(); + assertEquals("I am mainA:/a/foo", line); + + reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainA:/a/foo"))); + line = reader.readLine(); + reader.close(); + assertEquals("I am mainA:/a/foo", line); + + List diffs = fSyncService.compare(-1, "mainB--layer:/a", -1, "mainB:/a", null); + assertEquals(1, diffs.size()); + + // TODO - review behaviour + assertEquals("[mainB--layer:/a/foo[-1] > mainB:/a/foo[-1]]", diffs.toString()); + fSyncService.update(diffs, null, false, false, false, false, "one", "one"); + + fSyncService.flatten("mainB--layer:/a", "mainB:/a"); + + assertEquals(1, fService.lookup(-1, "mainA:/a/foo").getVersionID()); + assertEquals(2, fService.lookup(-1, "mainB:/a/foo").getVersionID()); + assertEquals(2, fService.lookup(-1, "mainB--layer:/a/foo").getVersionID()); + + snapshots = fService.getStoreVersions("mainB--layer"); + assertEquals(2, snapshots.size()); + assertEquals(1, snapshots.get(snapshots.size()-1).getVersionID()); + + snapshots = fService.getStoreVersions("mainB"); + assertEquals(3, snapshots.size()); + assertEquals(2, snapshots.get(snapshots.size()-1).getVersionID()); + + logger.debug("submit/update file: mainB--layer:/a/foo -> mainB:/a/foo"); + + fSyncService.flatten("mainB--layer:/a", "mainB:/a"); + + logger.debug("flatten dir: mainB--layer:/a/foo -> mainB:/a/foo"); + + reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB--layer:/a/foo"))); + line = reader.readLine(); + reader.close(); + assertEquals("I am mainB--layer:/a/foo", line); + + reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB:/a/foo"))); + line = reader.readLine(); + reader.close(); + assertEquals("I am mainB--layer:/a/foo", line); + + reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainA:/a/foo"))); + line = reader.readLine(); + reader.close(); + assertEquals("I am mainA:/a/foo", line); + + recursiveList("mainA"); + recursiveList("mainB"); + recursiveList("mainB--layer"); + } + catch (Exception e) + { + e.printStackTrace(System.err); + throw e; + } + finally + { + fService.purgeStore("mainA"); + fService.purgeStore("mainB"); + fService.purgeStore("mainB--layer"); + } + } + + public void testSimpleUpdateLF3() throws Exception + { + try + { + fService.createStore("mainA"); + fService.createStore("mainB"); + fService.createStore("mainB--layer"); + + List snapshots = fService.getStoreVersions("mainA"); + assertEquals(1, snapshots.size()); + assertEquals(0, snapshots.get(0).getVersionID()); + + snapshots = fService.getStoreVersions("mainB"); + assertEquals(1, snapshots.size()); + assertEquals(0, snapshots.get(0).getVersionID()); + + snapshots = fService.getStoreVersions("mainB--layer"); + assertEquals(1, snapshots.size()); + assertEquals(0, snapshots.get(0).getVersionID()); + + logger.debug("created 3 stores: mainA, mainB, mainB-layer"); + + fService.createDirectory("mainA:/", "a"); + fService.createDirectory("mainB:/", "a"); + + logger.debug("created 2 plain dirs: mainA:/a, mainB:/a"); + + fService.createLayeredDirectory("mainB:/a", "mainB--layer:/", "a"); + + logger.debug("created layered dir: mainB--layer:/a -> mainB:/a"); + + // note: unlike WCM, edit staging directly (ie. don't bother with mainA--layer for now) + fService.createFile("mainA:/a", "foo"); + + assertEquals(1, fService.lookup(-1, "mainA:/a/foo").getVersionID()); + assertNull(fService.lookup(-1, "mainB:/a/foo")); + assertNull(fService.lookup(-1, "mainB--layer:/a/foo")); + + PrintStream out = new PrintStream(fService.getFileOutputStream("mainA:/a/foo")); + out.println("I am mainA:/a/foo"); + out.close(); + + logger.debug("created plain file: mainA:/a/foo"); + + fService.createSnapshot("mainA", null, null); + + assertEquals(1, fService.lookup(-1, "mainA:/a/foo").getVersionID()); + assertNull(fService.lookup(-1, "mainB:/a/foo")); + assertNull(fService.lookup(-1, "mainB--layer:/a/foo")); + + snapshots = fService.getStoreVersions("mainA"); + assertEquals(2, snapshots.size()); + assertEquals(1, snapshots.get(snapshots.size()-1).getVersionID()); + + logger.debug("created snapshot: mainA"); + + // note: WCM does not expose layered file (between web project staging sandboxes) + fService.createLayeredFile("mainA:/a/foo", "mainB:/a", "foo"); + + assertEquals(1, fService.lookup(-1, "mainA:/a/foo").getVersionID()); + assertEquals(1, fService.lookup(-1, "mainB:/a/foo").getVersionID()); + + AVMNodeDescriptor foo = fService.lookup(-1, "mainB--layer:/a/foo"); + assertEquals(1, foo.getVersionID()); + assertTrue(foo.isLayeredFile()); + + BufferedReader reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB--layer:/a/foo"))); + String line = reader.readLine(); + reader.close(); + assertEquals("I am mainA:/a/foo", line); + + reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB:/a/foo"))); + line = reader.readLine(); + reader.close(); + assertEquals("I am mainA:/a/foo", line); + + reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainA:/a/foo"))); + line = reader.readLine(); + reader.close(); + assertEquals("I am mainA:/a/foo", line); + + logger.debug("created layered file: mainB:/a/foo -> mainA:/a/foo"); + + // add dir in user's sandbox + fService.createDirectory("mainB--layer:/a", "b"); + + assertEquals(1, fService.lookup(-1, "mainA:/a/foo").getVersionID()); + assertEquals(1, fService.lookup(-1, "mainB:/a/foo").getVersionID()); + assertEquals(1, fService.lookup(-1, "mainB--layer:/a/b").getVersionID()); + + foo = fService.lookup(-1, "mainB--layer:/a/foo"); + assertEquals(1, foo.getVersionID()); + assertTrue(foo.isLayeredFile()); + + logger.debug("created dir: mainB--layer:/a/b"); + + List diffs = fSyncService.compare(-1, "mainB--layer:/a", -1, "mainB:/a", null); + assertEquals(1, diffs.size()); + + foo = fService.lookup(-1, "mainB--layer:/a/foo"); + assertTrue(foo.isLayeredFile()); + + assertEquals("[mainB--layer:/a/b[-1] > mainB:/a/b[-1]]", diffs.toString()); + fSyncService.update(diffs, null, false, false, false, false, "one", "one"); + + foo = fService.lookup(-1, "mainB--layer:/a/foo"); + assertTrue(foo.isLayeredFile()); + + fSyncService.flatten("mainB--layer:/a", "mainB:/a"); + + foo = fService.lookup(-1, "mainB--layer:/a/foo"); + assertTrue(foo.isLayeredFile()); + + assertEquals(1, fService.lookup(-1, "mainA:/a/foo").getVersionID()); + assertEquals(2, fService.lookup(-1, "mainB:/a/foo").getVersionID()); + assertEquals(2, fService.lookup(-1, "mainB--layer:/a/foo").getVersionID()); + + snapshots = fService.getStoreVersions("mainB--layer"); + assertEquals(2, snapshots.size()); + assertEquals(1, snapshots.get(snapshots.size()-1).getVersionID()); + + snapshots = fService.getStoreVersions("mainB"); + assertEquals(3, snapshots.size()); + assertEquals(2, snapshots.get(snapshots.size()-1).getVersionID()); + + logger.debug("submitted dir: mainB--layer:/a/b -> mainB:/a/b"); + + foo = fService.lookup(-1, "mainB--layer:/a/foo"); + assertEquals(2, foo.getVersionID()); + assertTrue(foo.isLayeredFile()); + + reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainA:/a/foo"))); + line = reader.readLine(); + reader.close(); + assertEquals("I am mainA:/a/foo", line); + + reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB:/a/foo"))); + line = reader.readLine(); + reader.close(); + assertEquals("I am mainA:/a/foo", line); + + reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB--layer:/a/foo"))); + line = reader.readLine(); + reader.close(); + assertEquals("I am mainA:/a/foo", line); + + recursiveList("mainA"); + recursiveList("mainB"); + recursiveList("mainB--layer"); + } + catch (Exception e) + { + e.printStackTrace(System.err); + throw e; + } + finally + { + fService.purgeStore("mainA"); + fService.purgeStore("mainB"); + fService.purgeStore("mainB--layer"); + } + } + + public void testLayeredFolder1() throws Exception + { + try + { + fService.createStore("mainA"); + fService.createStore("mainB"); + + fService.createDirectory("mainA:/", "a"); + fService.createDirectory("mainA:/a", "b"); + + fService.createDirectory("mainB:/", "a"); + + fService.createStore("mainB--layer"); + + fService.createLayeredDirectory("mainB:/a", "mainB--layer:/", "a"); + + // note: short-cut - created directly in "staging" area (don't bother with sandbox mainA--layer for now) + fService.createFile("mainA:/a/b", "foo"); + + PrintStream out = new PrintStream(fService.getFileOutputStream("mainA:/a/b/foo")); + out.println("I am mainA:/a/b/foo"); + out.close(); + + logger.debug("created file: mainA:/a/b/foo"); + + // create equivalent of WCM layered folder between web project staging sandboxes (mainB:/a/b pointing to mainA:/a/b) + fService.createLayeredDirectory("mainA:/a/b", "mainB:/a", "b"); + + fService.createSnapshot("mainA", null, null); + fService.createSnapshot("mainB", null, null); + + assertTrue(fService.lookup(-1, "mainB--layer:/a/b").isLayeredDirectory()); + + logger.debug("created layered directory: mainB:/a/b -> mainA:/a/b"); + + fService.createDirectory("mainB--layer:/a", "c"); + + fService.createSnapshot("mainB--layer", null, null); + + logger.debug("created dir: mainB--layer:/a/c"); + + List diffs = fSyncService.compare(-1, "mainB--layer:/a", -1, "mainB:/a", null); + assertEquals(1, diffs.size()); + assertEquals("[mainB--layer:/a/c[-1] > mainB:/a/c[-1]]", diffs.toString()); + + fSyncService.update(diffs, null, false, false, false, false, "one", "one"); + fSyncService.flatten("mainB--layer:/a", "mainB:/a"); + + logger.debug("updated: created dir: mainB:/a/c"); + + assertTrue(fService.lookup(-1, "mainB--layer:/a/b").isLayeredDirectory()); + + fService.createDirectory("mainB--layer:/a/b", "c"); + + assertTrue(fService.lookup(-1, "mainB--layer:/a/b").isLayeredDirectory()); + + fService.createSnapshot("mainB--layer", null, null); + + logger.debug("created dir: mainB--layer:/a/b/c"); + + diffs = fSyncService.compare(-1, "mainB--layer:/a", -1, "mainB:/a", null); + assertEquals(1, diffs.size()); + assertEquals("[mainB--layer:/a/b/c[-1] > mainB:/a/b/c[-1]]", diffs.toString()); + + fSyncService.update(diffs, null, false, false, false, false, "one", "one"); + fSyncService.flatten("mainB--layer:/a", "mainB:/a"); + + logger.debug("updated: created dir: mainB:/a/b/c"); + + assertTrue(fService.lookup(-1, "mainB--layer:/a/b").isLayeredDirectory()); + + recursiveList("mainA"); + recursiveList("mainB"); + recursiveList("mainB--layer"); + } + catch (Exception e) + { + e.printStackTrace(System.err); + throw e; + } + finally + { + fService.purgeStore("mainA"); + fService.purgeStore("mainB"); + fService.purgeStore("mainB--layer"); + } + } + + public void testLayeredFolder2() throws Exception + { + try + { + fService.createStore("mainA"); + fService.createStore("mainB"); + + fService.createDirectory("mainA:/", "a"); + fService.createDirectory("mainA:/a", "b"); + + fService.createDirectory("mainB:/", "a"); + + fService.createStore("mainB--layer"); + + recursiveList("mainA"); + recursiveList("mainB"); + recursiveList("mainB--layer"); + + List snapshots = fService.getStoreVersions("mainA"); + assertEquals(1, snapshots.size()); + assertEquals(0, snapshots.get(0).getVersionID()); + + snapshots = fService.getStoreVersions("mainB"); + assertEquals(1, snapshots.size()); + assertEquals(0, snapshots.get(0).getVersionID()); + + snapshots = fService.getStoreVersions("mainB--layer"); + assertEquals(1, snapshots.size()); + assertEquals(0, snapshots.get(0).getVersionID()); + + fService.createLayeredDirectory("mainB:/a", "mainB--layer:/", "a"); + + // note: short-cut - created directly in "staging" area (don't bother with sandbox mainA--layer for now) + fService.createFile("mainA:/a/b", "foo"); + + PrintStream out = new PrintStream(fService.getFileOutputStream("mainA:/a/b/foo")); + out.println("I am mainA:/a/b/foo"); + out.close(); + + logger.debug("created file: mainA:/a/b/foo"); + + recursiveList("mainA"); + recursiveList("mainB"); + recursiveList("mainB--layer"); + + // create equivalent of WCM layered folder between web project staging sandboxes (mainB:/a/b pointing to mainA:/a/b) + fService.createLayeredDirectory("mainA:/a/b", "mainB:/a", "b"); + + logger.debug("created layered directory: mainB:/a/b -> mainA:/a/b"); + + recursiveList("mainA"); + recursiveList("mainB"); + recursiveList("mainB--layer"); + + fService.createFile("mainB--layer:/a/b", "bar"); + + out = new PrintStream(fService.getFileOutputStream("mainB--layer:/a/b/bar")); + out.println("I am mainB--layer:/a/b/bar"); + out.close(); + + logger.debug("created file: mainB--layer:/a/b/bar"); + + recursiveList("mainA"); + recursiveList("mainB"); + recursiveList("mainB--layer"); + + List diffs = fSyncService.compare(-1, "mainB--layer:/a", -1, "mainB:/a", null); + assertEquals(1, diffs.size()); + assertEquals("[mainB--layer:/a/b/bar[-1] > mainB:/a/b/bar[-1]]", diffs.toString()); + + snapshots = fService.getStoreVersions("mainB"); + assertEquals(1, snapshots.size()); + + fSyncService.update(diffs, null, false, false, false, false, "one", "one"); + + snapshots = fService.getStoreVersions("mainB"); + assertEquals(3, snapshots.size()); + + fSyncService.flatten("mainB--layer:/a", "mainB:/a"); + + logger.debug("updated: created file: mainB:/a/b/bar"); + + recursiveList("mainA"); + recursiveList("mainB"); + recursiveList("mainB--layer"); + + snapshots = fService.getStoreVersions("mainB"); + assertEquals(3, snapshots.size()); + assertEquals(2, snapshots.get(snapshots.size()-1).getVersionID()); + + // note: short-cut - created directly in "staging" area (don't bother with sandbox mainA--layer for now) + fService.createFile("mainA:/a/b", "baz"); + + out = new PrintStream(fService.getFileOutputStream("mainA:/a/b/baz")); + out.println("I am mainA:/a/b/baz"); + out.close(); + + logger.debug("created file: mainA:/a/b/baz"); + + recursiveList("mainA"); + recursiveList("mainB"); + recursiveList("mainB--layer"); + + fService.createSnapshot("mainB", "two", "two"); + + logger.debug("snapshot: mainB"); + + recursiveList("mainA"); + recursiveList("mainB"); + recursiveList("mainB--layer"); + + snapshots = fService.getStoreVersions("mainB"); + assertEquals(4, snapshots.size()); + assertEquals(3, snapshots.get(snapshots.size()-1).getVersionID()); + + // ETHREEOH-3340 + diffs = fSyncService.compare(2, "mainB:/a", 3, "mainB:/a", null); + assertEquals(1, diffs.size()); + assertEquals("[mainB:/a/b/baz[2] < mainB:/a/b/baz[3]]", diffs.toString()); + + recursiveList("mainA"); + recursiveList("mainB"); + recursiveList("mainB--layer"); + + logger.debug("list mainB [2]"); + + recursiveList("mainB", 2); + + logger.debug("list mainB [3]"); + + recursiveList("mainB", 3); + } + catch (Exception e) + { + e.printStackTrace(System.err); + throw e; + } + finally + { + fService.purgeStore("mainA"); + fService.purgeStore("mainB"); + fService.purgeStore("mainB--layer"); + } + } + + public void testLayeredFolderDelete1() throws Exception + { + try + { + fService.createStore("mainA"); + fService.createStore("mainB"); + + fService.createDirectory("mainA:/", "a"); + fService.createDirectory("mainA:/a", "b"); + + fService.createDirectory("mainB:/", "a"); + + fService.createStore("mainB--layer"); + + fService.createLayeredDirectory("mainB:/a", "mainB--layer:/", "a"); + + // note: short-cut - created directly in "staging" area (don't bother with sandbox mainA--layer for now) + fService.createFile("mainA:/a/b", "foo"); + + PrintStream out = new PrintStream(fService.getFileOutputStream("mainA:/a/b/foo")); + out.println("I am mainA:/a/b/foo"); + out.close(); + + logger.debug("created file: mainA:/a/b/foo"); + + // create equivalent of WCM layered folder between web project staging sandboxes (mainB:/a/b pointing to ,mainA:/a/b) + fService.createLayeredDirectory("mainA:/a/b", "mainB:/a", "b"); + + fService.createSnapshot("mainA", null, null); + fService.createSnapshot("mainB", null, null); + + logger.debug("created layered directory: mainB:/a/b -> mainA:/a/b"); + + BufferedReader reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB--layer:/a/b/foo"))); + String line = reader.readLine(); + reader.close(); + assertEquals("I am mainA:/a/b/foo", line); + + out = new PrintStream(fService.getFileOutputStream("mainB--layer:/a/b/foo")); + out.println("I am mainB--layer:/a/b/foo"); + out.close(); + + fService.createSnapshot("mainB--layer", null, null); + + logger.debug("updated file: mainB--layer:/a/b/foo"); + + reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainA:/a/b/foo"))); + line = reader.readLine(); + reader.close(); + assertEquals("I am mainA:/a/b/foo", line); + + reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB:/a/b/foo"))); + line = reader.readLine(); + reader.close(); + assertEquals("I am mainA:/a/b/foo", line); + + reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB--layer:/a/b/foo"))); + line = reader.readLine(); + reader.close(); + assertEquals("I am mainB--layer:/a/b/foo", line); + + List diffs = fSyncService.compare(-1, "mainB--layer:/a", -1, "mainB:/a", null); + assertEquals(1, diffs.size()); + assertEquals("[mainB--layer:/a/b/foo[-1] > mainB:/a/b/foo[-1]]", diffs.toString()); + + fSyncService.update(diffs, null, false, false, false, false, "one", "one"); + fSyncService.flatten("mainB--layer:/a", "mainB:/a"); + + logger.debug("updated: created file: mainB:/a/b/foo"); + + reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB:/a/b/foo"))); + line = reader.readLine(); + reader.close(); + assertEquals("I am mainB--layer:/a/b/foo", line); + + // delete file - note: short-cut - removed directly from "staging" area (don't bother with sandbox mainA--layer for now) + fService.removeNode("mainA:/a/b", "foo"); + fService.createSnapshot("mainA", null, null); + + logger.debug("removed file & snapshot: mainA:/a/b/foo"); + + // ETHREEOH-2297 + fService.removeNode("mainB--layer:/a/b", "foo"); + fService.createSnapshot("mainB--layer", null, null); + + diffs = fSyncService.compare(-1, "mainB--layer:/a", -1, "mainB:/a", null); + assertEquals(1, diffs.size()); + assertEquals("[mainB--layer:/a/b/foo[-1] > mainB:/a/b/foo[-1]]", diffs.toString()); + + fSyncService.update(diffs, null, false, false, false, false, "one", "one"); + fSyncService.flatten("mainB--layer:/a", "mainB:/a"); + + fService.createSnapshot("mainB", null, null); + + logger.debug("updated: removed file: mainB:/a/b/foo"); + + recursiveList("mainA"); + recursiveList("mainB"); + recursiveList("mainB--layer"); + } + catch (Exception e) + { + e.printStackTrace(System.err); + throw e; + } + finally + { + fService.purgeStore("mainA"); + fService.purgeStore("mainB"); + fService.purgeStore("mainB--layer"); + } + } + + public void testLayeredFolderDelete2() throws Exception + { + try + { + fService.createStore("mainA"); + fService.createStore("mainB"); + + fService.createDirectory("mainA:/", "a"); + fService.createDirectory("mainA:/a", "b"); + + fService.createDirectory("mainB:/", "a"); + + fService.createStore("mainB--layer"); + + fService.createLayeredDirectory("mainB:/a", "mainB--layer:/", "a"); + + // note: short-cut - created directly in "staging" area (don't bother with sandbox mainA--layer for now) + fService.createFile("mainA:/a/b", "foo"); + + PrintStream out = new PrintStream(fService.getFileOutputStream("mainA:/a/b/foo")); + out.println("I am mainA:/a/b/foo"); + out.close(); + + logger.debug("created file: mainA:/a/b/foo"); + + // create equivalent of WCM layered folder between web project staging sandboxes (mainB:/a/b pointing to ,mainA:/a/b) + fService.createLayeredDirectory("mainA:/a/b", "mainB:/a", "b"); + + fService.createSnapshot("mainA", null, null); + fService.createSnapshot("mainB", null, null); + + logger.debug("created layered directory: mainB:/a/b -> mainA:/a/b"); + + BufferedReader reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB--layer:/a/b/foo"))); + String line = reader.readLine(); + reader.close(); + assertEquals("I am mainA:/a/b/foo", line); + + out = new PrintStream(fService.getFileOutputStream("mainB--layer:/a/b/foo")); + out.println("I am mainB--layer:/a/b/foo"); + out.close(); + + fService.createSnapshot("mainB--layer", null, null); + + logger.debug("updated file: mainB--layer:/a/b/foo"); + + reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainA:/a/b/foo"))); + line = reader.readLine(); + reader.close(); + assertEquals("I am mainA:/a/b/foo", line); + + reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB:/a/b/foo"))); + line = reader.readLine(); + reader.close(); + assertEquals("I am mainA:/a/b/foo", line); + + reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB--layer:/a/b/foo"))); + line = reader.readLine(); + reader.close(); + assertEquals("I am mainB--layer:/a/b/foo", line); + + List diffs = fSyncService.compare(-1, "mainB--layer:/a", -1, "mainB:/a", null); + assertEquals(1, diffs.size()); + assertEquals("[mainB--layer:/a/b/foo[-1] > mainB:/a/b/foo[-1]]", diffs.toString()); + + fSyncService.update(diffs, null, false, false, false, false, "one", "one"); + fSyncService.flatten("mainB--layer:/a", "mainB:/a"); + + logger.debug("updated: created file: mainB:/a/b/foo"); + + reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB:/a/b/foo"))); + line = reader.readLine(); + reader.close(); + assertEquals("I am mainB--layer:/a/b/foo", line); + + // delete folder - note: short-cut - remove directly from "staging" area (don't bother with sandbox mainA--layer for now) + fService.removeNode("mainA:/a", "b"); + fService.createSnapshot("mainA", null, null); + + logger.debug("removed folder & snapshot: mainA:/a/b"); + + fService.removeNode("mainB--layer:/a/b", "foo"); + fService.createSnapshot("mainB--layer", null, null); + + logger.debug("removed file & snapshot: mainB--layer:/a/b/foo"); + + diffs = fSyncService.compare(-1, "mainB--layer:/a", -1, "mainB:/a", null); + assertEquals(1, diffs.size()); + assertEquals("[mainB--layer:/a/b/foo[-1] > mainB:/a/b/foo[-1]]", diffs.toString()); + + fSyncService.update(diffs, null, false, false, false, false, "one", "one"); + fSyncService.flatten("mainB--layer:/a", "mainB:/a"); + + logger.debug("updated & flattened: removed file: mainB:/a/b/foo"); + + recursiveList("mainA"); + recursiveList("mainB"); + recursiveList("mainB--layer"); + } + catch (Exception e) + { + e.printStackTrace(System.err); + throw e; + } + finally + { + fService.purgeStore("mainA"); + fService.purgeStore("mainB"); + fService.purgeStore("mainB--layer"); + } + } + + public void testLayeredFolderDelete3() throws Exception + { + try + { + fService.createStore("mainA"); + fService.createStore("mainB"); + + fService.createDirectory("mainA:/", "a"); + fService.createDirectory("mainA:/a", "b"); + + fService.createDirectory("mainB:/", "a"); + + fService.createStore("mainB--layer"); + + fService.createLayeredDirectory("mainB:/a", "mainB--layer:/", "a"); + + // note: short-cut - created directly in "staging" area (don't bother with sandbox mainA--layer for now) + fService.createFile("mainA:/a/b", "foo"); + + PrintStream out = new PrintStream(fService.getFileOutputStream("mainA:/a/b/foo")); + out.println("I am mainA:/a/b/foo"); + out.close(); + + logger.debug("created file: mainA:/a/b/foo"); + + // create equivalent of WCM layered folder between web project staging sandboxes (mainB:/a/b pointing to ,mainA:/a/b) + fService.createLayeredDirectory("mainA:/a/b", "mainB:/a", "b"); + + fService.createSnapshot("mainA", null, null); + fService.createSnapshot("mainB", null, null); + + logger.debug("created layered directory: mainB:/a/b -> mainA:/a/b"); + + BufferedReader reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB--layer:/a/b/foo"))); + String line = reader.readLine(); + reader.close(); + assertEquals("I am mainA:/a/b/foo", line); + + out = new PrintStream(fService.getFileOutputStream("mainB--layer:/a/b/foo")); + out.println("I am mainB--layer:/a/b/foo"); + out.close(); + + logger.debug("updated file: mainB--layer:/a/b/foo"); + + reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainA:/a/b/foo"))); + line = reader.readLine(); + reader.close(); + assertEquals("I am mainA:/a/b/foo", line); + + reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB:/a/b/foo"))); + line = reader.readLine(); + reader.close(); + assertEquals("I am mainA:/a/b/foo", line); + + reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB--layer:/a/b/foo"))); + line = reader.readLine(); + reader.close(); + assertEquals("I am mainB--layer:/a/b/foo", line); + + List diffs = fSyncService.compare(-1, "mainB--layer:/a", -1, "mainB:/a", null); + assertEquals(1, diffs.size()); + assertEquals("[mainB--layer:/a/b/foo[-1] > mainB:/a/b/foo[-1]]", diffs.toString()); + + fSyncService.update(diffs, null, false, false, false, false, "one", "one"); + fSyncService.flatten("mainB--layer:/a", "mainB:/a"); + + logger.debug("updated: created file: mainB:/a/b/foo"); + + reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB:/a/b/foo"))); + line = reader.readLine(); + reader.close(); + assertEquals("I am mainB--layer:/a/b/foo", line); + + // delete folder - note: short-cut - remove directly from "staging" area (don't bother with sandbox mainA--layer for now) + fService.removeNode("mainA:/a", "b"); + fService.createSnapshot("mainA", null, null); + + logger.debug("removed folder & snapshot: mainA:/a/b"); + + fService.createFile("mainB--layer:/a/b", "bar"); + + out = new PrintStream(fService.getFileOutputStream("mainB--layer:/a/b/bar")); + out.println("I am mainB--layer:/a/b/bar"); + out.close(); + + logger.debug("created file: mainB--layer:/a/b/bar"); + + diffs = fSyncService.compare(-1, "mainB--layer:/a", -1, "mainB:/a", null); + assertEquals(1, diffs.size()); + assertEquals("[mainB--layer:/a/b/bar[-1] > mainB:/a/b/bar[-1]]", diffs.toString()); + + fSyncService.update(diffs, null, false, false, false, false, "two", "two"); + fSyncService.flatten("mainB--layer:/a", "mainB:/a"); + + logger.debug("updated & flattened: created file: mainB:/a/b/bar"); + + recursiveList("mainA"); + recursiveList("mainB"); + recursiveList("mainB--layer"); + } + catch (Exception e) + { + e.printStackTrace(System.err); + throw e; + } + finally + { + fService.purgeStore("mainA"); + fService.purgeStore("mainB"); + fService.purgeStore("mainB--layer"); + } + } + + public void testLayeredFolderDelete4() throws Exception + { + try + { + fService.createStore("mainA"); + fService.createStore("mainB"); + + fService.createDirectory("mainA:/", "a"); + fService.createDirectory("mainA:/a", "b"); + + fService.createDirectory("mainB:/", "a"); + + fService.createStore("mainB--layer"); + + fService.createLayeredDirectory("mainB:/a", "mainB--layer:/", "a"); + + // note: short-cut - created directly in "staging" area (don't bother with sandbox mainA--layer for now) + fService.createFile("mainA:/a/b", "foo"); + + PrintStream out = new PrintStream(fService.getFileOutputStream("mainA:/a/b/foo")); + out.println("I am mainA:/a/b/foo"); + out.close(); + + logger.debug("created file: mainA:/a/b/foo"); + + // create equivalent of WCM layered folder between web project staging sandboxes (mainB:/a/b pointing to ,mainA:/a/b) + fService.createLayeredDirectory("mainA:/a/b", "mainB:/a", "b"); + + fService.createSnapshot("mainA", null, null); + fService.createSnapshot("mainB", null, null); + + logger.debug("created layered directory: mainB:/a/b -> mainA:/a/b"); + + BufferedReader reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB--layer:/a/b/foo"))); + String line = reader.readLine(); + reader.close(); + assertEquals("I am mainA:/a/b/foo", line); + + out = new PrintStream(fService.getFileOutputStream("mainB--layer:/a/b/foo")); + out.println("I am mainB--layer:/a/b/foo"); + out.close(); + + logger.debug("updated file: mainB--layer:/a/b/foo"); + + reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainA:/a/b/foo"))); + line = reader.readLine(); + reader.close(); + assertEquals("I am mainA:/a/b/foo", line); + + reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB:/a/b/foo"))); + line = reader.readLine(); + reader.close(); + assertEquals("I am mainA:/a/b/foo", line); + + reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB--layer:/a/b/foo"))); + line = reader.readLine(); + reader.close(); + assertEquals("I am mainB--layer:/a/b/foo", line); + + List diffs = fSyncService.compare(-1, "mainB--layer:/a", -1, "mainB:/a", null); + assertEquals(1, diffs.size()); + assertEquals("[mainB--layer:/a/b/foo[-1] > mainB:/a/b/foo[-1]]", diffs.toString()); + + fSyncService.update(diffs, null, false, false, false, false, "one", "one"); + fSyncService.flatten("mainB--layer:/a", "mainB:/a"); + + logger.debug("updated & flattened: updated file: mainB:/a/b/foo"); + + reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB:/a/b/foo"))); + line = reader.readLine(); + reader.close(); + assertEquals("I am mainB--layer:/a/b/foo", line); + + // delete folder - note: short-cut - remove directly from "staging" area (don't bother with sandbox mainA--layer for now) + fService.removeNode("mainA:/a", "b"); + fService.createSnapshot("mainA", null, null); + + logger.debug("removed folder & snapshot: mainA:/a/b"); + + reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB--layer:/a/b/foo"))); + line = reader.readLine(); + reader.close(); + assertEquals("I am mainB--layer:/a/b/foo", line); + + out = new PrintStream(fService.getFileOutputStream("mainB--layer:/a/b/foo")); + out.println("I am mainB--layer:/a/b/foo V2"); + out.close(); + + reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB--layer:/a/b/foo"))); + line = reader.readLine(); + reader.close(); + assertEquals("I am mainB--layer:/a/b/foo V2", line); + + reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB:/a/b/foo"))); + line = reader.readLine(); + reader.close(); + assertEquals("I am mainB--layer:/a/b/foo", line); + + logger.debug("updated file: mainB--layer:/a/b/foo"); + + diffs = fSyncService.compare(-1, "mainB--layer:/a", -1, "mainB:/a", null); + assertEquals(1, diffs.size()); + assertEquals("[mainB--layer:/a/b/foo[-1] > mainB:/a/b/foo[-1]]", diffs.toString()); + + fSyncService.update(diffs, null, false, false, false, false, "two", "two"); + fSyncService.flatten("mainB--layer:/a", "mainB:/a"); + + logger.debug("updated & flattened: updated file: mainB:/a/b/foo"); + + reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB:/a/b/foo"))); + line = reader.readLine(); + reader.close(); + assertEquals("I am mainB--layer:/a/b/foo V2", line); + + recursiveList("mainA"); + recursiveList("mainB"); + recursiveList("mainB--layer"); + } + catch (Exception e) + { + e.printStackTrace(System.err); + throw e; + } + finally + { + fService.purgeStore("mainA"); + fService.purgeStore("mainB"); + fService.purgeStore("mainB--layer"); + } + } + + public void testLayeredFileDeleteFile1() throws Exception + { + try + { + fService.createStore("mainA"); + fService.createStore("mainB"); + fService.createStore("mainB--layer"); + + logger.debug("created 3 stores: mainA, mainB, mainB--layer"); + + fService.createDirectory("mainA:/", "a"); + fService.createDirectory("mainB:/", "a"); + + logger.debug("created 2 plain dirs: mainA:/a and mainB:/a"); + + fService.createLayeredDirectory("mainB:/a", "mainB--layer:/", "a"); + + logger.debug("created layered dir: mainB--layer:/a -> mainB:/a"); + + // note: short-cut - created directly in "staging" area (don't bother with sandbox mainA--layer for now) + fService.createFile("mainA:/a", "foo"); + + PrintStream out = new PrintStream(fService.getFileOutputStream("mainA:/a/foo")); + out.println("I am mainA:/a/foo"); + out.close(); + + logger.debug("created file: mainA:/a/foo"); + + // create equivalent of WCM layered folder between web project staging sandboxes (mainB:/a/b pointing to ,mainA:/a/b) + fService.createLayeredFile("mainA:/a/foo", "mainB:/a", "foo"); + + logger.debug("created layered file: mainB:/a/foo -> mainA:/a/foo"); + + fService.createSnapshot("mainA", null, null); + fService.createSnapshot("mainB", null, null); + + logger.debug("created 2 snapshots: mainA and mainB"); + + BufferedReader reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB--layer:/a/foo"))); + String line = reader.readLine(); + reader.close(); + assertEquals("I am mainA:/a/foo", line); + + reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB:/a/foo"))); + line = reader.readLine(); + reader.close(); + assertEquals("I am mainA:/a/foo", line); + + reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainA:/a/foo"))); + line = reader.readLine(); + reader.close(); + assertEquals("I am mainA:/a/foo", line); + + List diffs = fSyncService.compare(-1, "mainB--layer:/a", -1, "mainB:/a", null); + assertEquals(0, diffs.size()); + + fService.removeNode("mainB--layer:/a", "foo"); + fService.createSnapshot("mainB--layer", null, null); + + logger.debug("removed file & snapshot: mainB--layer:/a/foo"); + + diffs = fSyncService.compare(-1, "mainB--layer:/a", -1, "mainB:/a", null); + assertEquals("[mainB--layer:/a/foo[-1] > mainB:/a/foo[-1]]", diffs.toString()); + + // ETHREEOH-2844 + fSyncService.update(diffs, null, false, false, false, false, "one", "one"); + fSyncService.flatten("mainB--layer:/a", "mainB:/a"); + + logger.debug("updated & flattened: removed file: mainB:/a/foo"); + + recursiveList("mainA"); + recursiveList("mainB"); + recursiveList("mainB--layer"); + } + catch (Exception e) + { + e.printStackTrace(System.err); + throw e; + } + finally + { + fService.purgeStore("mainA"); + fService.purgeStore("mainB"); + fService.purgeStore("mainB--layer"); + } + } + + public void testLayeredFileDeleteFile2() throws Exception + { + try + { + fService.createStore("mainA"); + fService.createStore("mainB"); + fService.createStore("mainB--layer"); + + logger.debug("created 3 stores: mainA, mainB, mainB--layer"); + + fService.createDirectory("mainA:/", "a"); + fService.createDirectory("mainB:/", "a"); + + logger.debug("created 2 plain dirs: mainA:/a and mainB:/a"); + + fService.createLayeredDirectory("mainB:/a", "mainB--layer:/", "a"); + + logger.debug("created layered dir: mainB--layer:/a -> mainB:/a"); + + // note: short-cut - created directly in "staging" area (don't bother with sandbox mainA--layer for now) + fService.createFile("mainA:/a", "foo"); + + PrintStream out = new PrintStream(fService.getFileOutputStream("mainA:/a/foo")); + out.println("I am mainA:/a/foo"); + out.close(); + + logger.debug("created file: mainA:/a/foo"); + + // create equivalent of WCM layered folder between web project staging sandboxes (mainB:/a/b pointing to ,mainA:/a/b) + fService.createLayeredFile("mainA:/a/foo", "mainB:/a", "foo"); + + logger.debug("created layered file: mainB:/a/foo -> mainA:/a/foo"); + + fService.createSnapshot("mainA", null, null); + fService.createSnapshot("mainB", null, null); + + logger.debug("created 2 snapshots: mainA and mainB"); + + BufferedReader reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB--layer:/a/foo"))); + String line = reader.readLine(); + reader.close(); + assertEquals("I am mainA:/a/foo", line); + + reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB:/a/foo"))); + line = reader.readLine(); + reader.close(); + assertEquals("I am mainA:/a/foo", line); + + reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainA:/a/foo"))); + line = reader.readLine(); + reader.close(); + assertEquals("I am mainA:/a/foo", line); + + List diffs = fSyncService.compare(-1, "mainB--layer:/a", -1, "mainB:/a", null); + assertEquals(0, diffs.size()); + + // note: short-cut - removed directly from "staging" area (don't bother with sandbox mainA--layer for now) + fService.removeNode("mainA:/a", "foo"); + fService.createSnapshot("mainA", null, null); + + logger.debug("removed file & snapshot: mainA:/a/foo"); + + try + { + fService.getFileInputStream(-1, "mainA:/a/foo"); + fail("Unexpected"); + } + catch (AVMNotFoundException nfe) + { + // expected + } + + try + { + fService.getFileInputStream(-1, "mainB:/a/foo"); + fail("Unexpected"); + } + catch (AVMNotFoundException nfe) + { + // expected + } + + try + { + fService.getFileInputStream(-1, "mainB--layer:/a/foo"); + fail("Unexpected"); + } + catch (AVMNotFoundException nfe) + { + // expected + } + + fService.removeNode("mainB--layer:/a", "foo"); + fService.createSnapshot("mainB--layer", null, null); + + logger.debug("removed file & snapshot: mainB--layer:/a/foo"); + + diffs = fSyncService.compare(-1, "mainB--layer:/a", -1, "mainB:/a", null); + assertEquals("[mainB--layer:/a/foo[-1] > mainB:/a/foo[-1]]", diffs.toString()); + + // ETHREEOH-2829 + fSyncService.update(diffs, null, false, false, false, false, "one", "one"); + fSyncService.flatten("mainB--layer:/a", "mainB:/a"); + + logger.debug("updated & flattened: removed file: mainB:/a/foo"); + + recursiveList("mainA"); + recursiveList("mainB"); + recursiveList("mainB--layer"); + } + catch (Exception e) + { + e.printStackTrace(System.err); + throw e; + } + finally + { + fService.purgeStore("mainA"); + fService.purgeStore("mainB"); + fService.purgeStore("mainB--layer"); + } + } + + public void testLayeredFileDeleteFile3() throws Exception + { + try + { + fService.createStore("mainB"); + fService.createStore("mainB--layer"); + + logger.debug("created 2 stores: mainB, mainB--layer"); + + fService.createDirectory("mainB:/", "a"); + + logger.debug("created plain dir: mainB:/a"); + + fService.createLayeredDirectory("mainB:/a", "mainB--layer:/", "a"); + + logger.debug("created layered dir: mainB--layer:/a -> mainB:/a"); + + // create equivalent of WCM layered file between web project staging sandboxes (mainB:/a/b/foo pointing to mainA:/a/b/foo) + fService.createLayeredFile("mainA:/a/foo", "mainB:/a", "foo"); // note: unbacked/stale here ... even store does not exist !! + + logger.debug("created layered file: mainB:/a/foo -> mainA:/a/foo"); + + List diffs = fSyncService.compare(-1, "mainB--layer:/a", -1, "mainB:/a", null); + assertEquals(0, diffs.size()); + + // create file + fService.createFile("mainB--layer:/a", "bar"); + + logger.debug("created file: mainB--layer:/a/bar"); + + diffs = fSyncService.compare(-1, "mainB--layer:/a", -1, "mainB:/a", null); + assertEquals("[mainB--layer:/a/bar[-1] > mainB:/a/bar[-1]]", diffs.toString()); + + fSyncService.update(diffs, null, false, false, false, false, "one", "one"); + + logger.debug("updated: created file: mainB:/a/bar"); + + fSyncService.flatten("mainB--layer:/a", "mainB:/a"); + + logger.debug("flattened: created file: mainB:/a/bar"); + + // delete layered file (from mainB--layer) + fService.removeNode("mainB--layer:/a", "foo"); + fService.createSnapshot("mainB--layer", null, null); + + logger.debug("removed file & snapshot: mainB--layer:/a/foo"); + + diffs = fSyncService.compare(-1, "mainB--layer:/a", -1, "mainB:/a", null); + assertEquals("[mainB--layer:/a/foo[-1] > mainB:/a/foo[-1]]", diffs.toString()); + + fService.createStore("mainB--workflow1"); + + logger.debug("created store: mainB--workflow1"); + + recursiveList("mainB--workflow1"); + + fService.createLayeredDirectory("mainB:/a", "mainB--workflow1:/", "a"); + + logger.debug("created layered dir: mainB--workflow1:/a -> mainB:/a"); + + recursiveList("mainB"); + recursiveList("mainB--layer"); + recursiveList("mainB--workflow1"); + + diffs = fSyncService.compare(-1, "mainB--workflow1:/a", -1, "mainB:/a", null); + assertEquals(0, diffs.size()); + + diffs = new ArrayList(1); + diffs.add(new AVMDifference(-1, "mainB--layer:/a/foo", -1, "mainB--workflow1:/a/foo", AVMDifference.NEWER)); + + // ETHREEOH-2868 + fSyncService.update(diffs, null, false, false, false, false, null, null); + + logger.debug("updated: removed file: mainB--workflow1:/a/foo"); + + recursiveList("mainB"); + recursiveList("mainB--layer"); + recursiveList("mainB--workflow1"); + + diffs = fSyncService.compare(-1, "mainB--workflow1:/a", -1, "mainB:/a", null); + assertEquals("[mainB--workflow1:/a/foo[-1] > mainB:/a/foo[-1]]", diffs.toString()); + + fSyncService.update(diffs, null, false, false, true, true, "one", "one"); + fSyncService.flatten("mainB--workflow1:/a", "mainB:/a"); + + logger.debug("updated & flattened: removed file: mainB:/a/foo"); + + diffs = fSyncService.compare(-1, "mainB--workflow1:/a", -1, "mainB:/a", null); + assertEquals(0, diffs.size()); + + diffs = fSyncService.compare(-1, "mainB--workflow1:/a", -1, "mainB--layer:/a", null); + assertEquals(0, diffs.size()); + + fSyncService.update(diffs, null, true, true, false, false, null, null); + fSyncService.flatten("mainB--layer:/a", "mainB--workflow1:/a"); + + recursiveList("mainB"); + recursiveList("mainB--layer"); + } + catch (Exception e) + { + e.printStackTrace(System.err); + throw e; + } + finally + { + fService.purgeStore("mainB"); + fService.purgeStore("mainB--layer"); + if (fService.getStore("mainB--workflow1") != null) { fService.purgeStore("mainB--workflow1"); } + } + } + + public void testLayeredFileDeleteFile4() throws Exception + { + try + { + fService.createStore("mainA"); + fService.createStore("mainB"); + fService.createStore("mainB--layer"); + + logger.debug("created 3 stores: mainA, mainB, mainB--layer"); + + fService.createDirectory("mainA:/", "a"); + fService.createDirectory("mainB:/", "a"); + + logger.debug("created 2 plain dirs: mainA:/a and mainB:/a"); + + fService.createSnapshot("mainA", null, null); + fService.createSnapshot("mainB", null, null); + + logger.debug("created 2 snapshots: mainA and mainB"); + + fService.createLayeredDirectory("mainB:/a", "mainB--layer:/", "a"); + + logger.debug("created layered dir: mainB--layer:/a -> mainB:/a"); + + // note: short-cut - created directly in "staging" areas (don't bother with sandbox mainA--layer or mainB--layer for now) + fService.createDirectory("mainA:/a", "b"); + fService.createDirectory("mainB:/a", "b"); + + logger.debug("created directories: mainA:/a/b & mainB:/a/b"); + + fService.createFile("mainA:/a/b", "foo"); + + PrintStream out = new PrintStream(fService.getFileOutputStream("mainA:/a/b/foo")); + out.println("I am mainA:/a/b/foo"); + out.close(); + + logger.debug("created file: mainA:/a/b/foo"); + + // create equivalent of WCM layered file between web project staging sandboxes (mainB:/a/b/foo pointing to mainA:/a/b/foo) + fService.createLayeredFile("mainA:/a/b/foo", "mainB:/a/b", "foo"); + + logger.debug("created layered file: mainB:/a/b/foo -> mainA:/a/b/foo"); + + BufferedReader reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB--layer:/a/b/foo"))); + String line = reader.readLine(); + reader.close(); + assertEquals("I am mainA:/a/b/foo", line); + + reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainB:/a/b/foo"))); + line = reader.readLine(); + reader.close(); + assertEquals("I am mainA:/a/b/foo", line); + + reader = new BufferedReader(new InputStreamReader(fService.getFileInputStream(-1, "mainA:/a/b/foo"))); + line = reader.readLine(); + reader.close(); + assertEquals("I am mainA:/a/b/foo", line); + + List diffs = fSyncService.compare(-1, "mainB--layer:/a/b", -1, "mainB:/a/b", null); + assertEquals(0, diffs.size()); + + // create file + fService.createFile("mainB--layer:/a/b", "bar"); + + logger.debug("created file: mainB--layer:/a/b/bar"); + + diffs = fSyncService.compare(-1, "mainB--layer:/a/b", -1, "mainB:/a/b", null); + assertEquals("[mainB--layer:/a/b/bar[-1] > mainB:/a/b/bar[-1]]", diffs.toString()); + + fSyncService.update(diffs, null, false, false, false, false, "one", "one"); + fSyncService.flatten("mainB--layer:/a/b", "mainB:/a/b"); + + logger.debug("updated & flattened: created file: mainB:/a/b/bar"); + + // delete layered file (from mainB--layer) + fService.removeNode("mainB--layer:/a/b", "foo"); + fService.createSnapshot("mainB--layer", null, null); + + logger.debug("removed file & snapshot: mainB--layer:/a/b/foo"); + + diffs = fSyncService.compare(-1, "mainB--layer:/a/b", -1, "mainB:/a/b", null); + assertEquals("[mainB--layer:/a/b/foo[-1] > mainB:/a/b/foo[-1]]", diffs.toString()); + + fService.createStore("mainB--workflow1"); + + fService.createLayeredDirectory("mainB:/a", "mainB--workflow1:/", "a"); + + logger.debug("created layered dir: mainB--workflow1:/a -> mainB:/a"); + + recursiveList("mainA"); + recursiveList("mainB"); + recursiveList("mainB--layer"); + recursiveList("mainB--workflow1"); + + diffs = fSyncService.compare(-1, "mainB--workflow1:/a/b", -1, "mainB:/a/b", null); + assertEquals(0, diffs.size()); + + diffs = new ArrayList(1); + diffs.add(new AVMDifference(-1, "mainB--layer:/a/b/foo", -1, "mainB--workflow1:/a/b/foo", AVMDifference.NEWER)); + + // ETHREEOH-2868 + fSyncService.update(diffs, null, false, false, false, false, null, null); + + logger.debug("updated: removed file: mainB--workflow1:/a/b/foo"); + + recursiveList("mainA"); + recursiveList("mainB"); + recursiveList("mainB--layer"); + recursiveList("mainB--workflow1"); + + diffs = fSyncService.compare(-1, "mainB--workflow1:/a/b", -1, "mainB:/a/b", null); + assertEquals("[mainB--workflow1:/a/b/foo[-1] > mainB:/a/b/foo[-1]]", diffs.toString()); + + fSyncService.update(diffs, null, false, false, true, true, "one", "one"); + fSyncService.flatten("mainB--workflow1:/a/b", "mainB:/a/b"); + + logger.debug("updated & flattened: removed file: mainB:/a/b/foo"); + + diffs = fSyncService.compare(-1, "mainB--workflow1:/a/b", -1, "mainB:/a/b", null); + assertEquals(0, diffs.size()); + + diffs = fSyncService.compare(-1, "mainB--workflow1:/a/b", -1, "mainB--layer:/a/b", null); + assertEquals(0, diffs.size()); + + fSyncService.update(diffs, null, true, true, false, false, null, null); + fSyncService.flatten("mainB--layer:/a/b", "mainB--workflow1:/a/b"); + + recursiveList("mainA"); + recursiveList("mainB"); + recursiveList("mainB--layer"); + } + catch (Exception e) + { + e.printStackTrace(System.err); + throw e; + } + finally + { + fService.purgeStore("mainA"); + fService.purgeStore("mainB"); + fService.purgeStore("mainB--layer"); + if (fService.getStore("mainB--workflow1") != null) { fService.purgeStore("mainB--workflow1"); } + } + } + + protected void recursiveContents(String path) + { + String contentsStr = recursiveContents(path, -1, true); + if (logger.isDebugEnabled()) + { + logger.debug(contentsStr); + } + } + + /** + * Get the recursive contents of the given path and version. + * @param path + * @param version + * @return A string representation of the contents. + */ + protected String recursiveContents(String path, int version, boolean followLinks) + { + String val = recursiveList(path, version, 0, followLinks); + return val.substring(val.indexOf('\n')); + } + + protected void recursiveList(String store) + { + recursiveList(store, -1); + } + + protected void recursiveList(String store, int version) + { + String list = recursiveList(store, version, true); + if (logger.isDebugEnabled()) + { + logger.debug("\n\n"+store+":"+"\n"+list+"\n"); + } + } + + /** + * 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 = fService.lookup(version, path, true); + builder.append(desc.toString()); + + List ancs = fService.getHistory(desc, -1); + for (AVMNodeDescriptor anc : ancs) + { + builder.append("--->").append(anc.toString()); + } + + builder.append('\n'); + if (desc.getType() == AVMNodeType.PLAIN_DIRECTORY || + (desc.getType() == AVMNodeType.LAYERED_DIRECTORY && followLinks)) + { + String basename = path.endsWith("/") ? path : path + "/"; + Map listing = fService.getDirectoryListing(version, path); + for (String name : listing.keySet()) + { + if (logger.isTraceEnabled()) { logger.trace(name); } + builder.append(recursiveList(basename + name, version, indent + 2, followLinks)); + } + List deletedList = fService.getDeleted(version, path); + for (String name : deletedList) + { + if (logger.isTraceEnabled()) { logger.trace(name); } + builder.append(recursiveList(basename + name, version, indent + 2, followLinks)); + } + } + return builder.toString(); + } + + /** + * Setup a basic tree. + */ + protected void setupBasicTree() + throws IOException + { + fService.createDirectory("main:/", "a"); + fService.createDirectory("main:/a", "b"); + fService.createDirectory("main:/a/b", "c"); + fService.createDirectory("main:/", "d"); + fService.createDirectory("main:/d", "e"); + fService.createDirectory("main:/d/e", "f"); + + + OutputStream out = fService.createFile("main:/a/b/c", "foo"); + byte [] buff = "I am main:/a/b/c/foo".getBytes(); + out.write(buff); + out.close(); + + /* + fService.createFile("main:/a/b/c", "foo").close(); + ContentWriter writer = fService.getContentWriter("main:/a/b/c/foo"); + writer.setEncoding("UTF-8"); + writer.setMimetype(MimetypeMap.MIMETYPE_TEXT_PLAIN); + writer.putContent("I am main:/a/b/c/foo"); + */ + + out = fService.createFile("main:/a/b/c", "bar"); + buff = "I am main:/a/b/c/bar".getBytes(); + out.write(buff); + out.close(); + + /* + fService.createFile("main:/a/b/c", "bar").close(); + writer = fService.getContentWriter("main:/a/b/c/bar"); + // Force a conversion + writer.setEncoding("UTF-16"); + writer.setMimetype(MimetypeMap.MIMETYPE_TEXT_PLAIN); + writer.putContent("I am main:/a/b/c/bar"); + */ + + fService.createSnapshot("main", null, null); + } +} diff --git a/source/java/org/alfresco/repo/avm/LayeredDirectoryNodeImpl.java b/source/java/org/alfresco/repo/avm/LayeredDirectoryNodeImpl.java index 27f004a34b..d2f4c55010 100644 --- a/source/java/org/alfresco/repo/avm/LayeredDirectoryNodeImpl.java +++ b/source/java/org/alfresco/repo/avm/LayeredDirectoryNodeImpl.java @@ -593,7 +593,7 @@ public class LayeredDirectoryNodeImpl extends DirectoryNodeImpl implements Layer // If we are not opaque, get the underlying base listing. if (!getOpacity()) { - Lookup lookup = AVMRepository.GetInstance().lookupDirectory(-1, dir.getIndirection()); + Lookup lookup = AVMRepository.GetInstance().lookupDirectory(dir.getIndirectionVersion(), dir.getIndirection()); if (lookup != null) { DirectoryNode dirNode = (DirectoryNode) lookup.getCurrentNode(); diff --git a/source/java/org/alfresco/repo/dictionary/DictionaryDAOImpl.java b/source/java/org/alfresco/repo/dictionary/DictionaryDAOImpl.java index a2451749a5..8dee217801 100644 --- a/source/java/org/alfresco/repo/dictionary/DictionaryDAOImpl.java +++ b/source/java/org/alfresco/repo/dictionary/DictionaryDAOImpl.java @@ -469,15 +469,17 @@ public class DictionaryDAOImpl implements DictionaryDAO */ public DataTypeDefinition getDataType(QName typeName) { - List models = getModelsForUri(typeName.getNamespaceURI()); - for (CompiledModel model : models) - { - DataTypeDefinition dataType = model.getDataType(typeName); - if (dataType != null) - { - return dataType; - } - } + if (typeName != null) { + List models = getModelsForUri(typeName.getNamespaceURI()); + for (CompiledModel model : models) + { + DataTypeDefinition dataType = model.getDataType(typeName); + if (dataType != null) + { + return dataType; + } + } + } return null; } @@ -542,19 +544,21 @@ public class DictionaryDAOImpl implements DictionaryDAO */ public TypeDefinition getType(QName typeName) { - List models = getModelsForUri(typeName.getNamespaceURI()); - for (CompiledModel model : models) - { - TypeDefinition type = model.getType(typeName); - if (type != null) - { - return type; - } - } - - if (logger.isWarnEnabled()) - { - logger.warn("Type not found: "+typeName); + if (typeName != null) { + List models = getModelsForUri(typeName.getNamespaceURI()); + for (CompiledModel model : models) + { + TypeDefinition type = model.getType(typeName); + if (type != null) + { + return type; + } + } + + if (logger.isWarnEnabled()) + { + logger.warn("Type not found: "+typeName); + } } return null; } @@ -614,14 +618,16 @@ public class DictionaryDAOImpl implements DictionaryDAO */ public AspectDefinition getAspect(QName aspectName) { - List models = getModelsForUri(aspectName.getNamespaceURI()); - for (CompiledModel model : models) - { - AspectDefinition aspect = model.getAspect(aspectName); - if (aspect != null) - { - return aspect; - } + if (aspectName != null) { + List models = getModelsForUri(aspectName.getNamespaceURI()); + for (CompiledModel model : models) + { + AspectDefinition aspect = model.getAspect(aspectName); + if (aspect != null) + { + return aspect; + } + } } return null; } diff --git a/source/java/org/alfresco/repo/domain/locks/AbstractLockDAOImpl.java b/source/java/org/alfresco/repo/domain/locks/AbstractLockDAOImpl.java index b4e4558300..fd8551026c 100644 --- a/source/java/org/alfresco/repo/domain/locks/AbstractLockDAOImpl.java +++ b/source/java/org/alfresco/repo/domain/locks/AbstractLockDAOImpl.java @@ -1,359 +1,368 @@ -/* - * Copyright (C) 2005-2009 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.domain.locks; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.StringTokenizer; - -import org.alfresco.repo.domain.QNameDAO; -import org.alfresco.repo.lock.LockAcquisitionException; -import org.alfresco.service.namespace.QName; -import org.alfresco.util.EqualsHelper; -import org.springframework.dao.ConcurrencyFailureException; - -/** - * Abstract implementation of the Locks DAO. - * - * @author Derek Hulley - * @since 3.2 - */ -public abstract class AbstractLockDAOImpl implements LockDAO -{ - private static final String LOCK_TOKEN_RELEASED = "not-locked"; - - private QNameDAO qnameDAO; - - /** - * @return Returns the DAO for namespace ID resolution - */ - protected QNameDAO getQNameDAO() - { - return qnameDAO; - } - - /** - * @param qnameDAO DAO for namespace ID resolution - */ - public void setQnameDAO(QNameDAO qnameDAO) - { - this.qnameDAO = qnameDAO; - } - - public void getLock(QName lockQName, String lockToken, long timeToLive) - { - String qnameNamespaceUri = lockQName.getNamespaceURI(); - String qnameLocalName = lockQName.getLocalName(); - // Force lower case for case insensitivity - if (!qnameLocalName.toLowerCase().equals(qnameLocalName)) - { - lockQName = QName.createQName(qnameNamespaceUri, qnameLocalName.toLowerCase()); - qnameLocalName = lockQName.getLocalName(); - } - // Force the lock token to lowercase - lockToken = lockToken.toLowerCase(); - - // Resolve the namespace - Long qnameNamespaceId = qnameDAO.getOrCreateNamespace(qnameNamespaceUri).getFirst(); - - // Get the lock resource for the exclusive lock. - // All the locks that are created will need the exclusive case. - LockResourceEntity exclusiveLockResource = getLockResource(qnameNamespaceId, qnameLocalName); - if (exclusiveLockResource == null) - { - // Create it - exclusiveLockResource = createLockResource(qnameNamespaceId, qnameLocalName); - } - Long requiredExclusiveLockResourceId = exclusiveLockResource.getId(); - // Split the lock name - List lockQNames = splitLockQName(lockQName); - List requiredLockResourceIds = new ArrayList(lockQNames.size()); - // Create the lock resources - for (QName lockQNameIter : lockQNames) - { - String localname = lockQNameIter.getLocalName(); - // Get the basic lock resource, forcing a create - LockResourceEntity lockResource = getLockResource(qnameNamespaceId, localname); - if (lockResource == null) - { - // Create it - lockResource = createLockResource(qnameNamespaceId, localname); - } - requiredLockResourceIds.add(lockResource.getId()); - } - - // Now, get all locks for the resources we will need - List existingLocks = getLocksBySharedResourceIds(requiredLockResourceIds); - Map existingLocksMap = new HashMap(); - // Check them and make sure they don't prevent locks - for (LockEntity existingLock : existingLocks) - { - boolean canTakeLock = canTakeLock(existingLock, lockToken, requiredExclusiveLockResourceId); - if (!canTakeLock) - { - throw new LockAcquisitionException( - LockAcquisitionException.ERR_EXCLUSIVE_LOCK_EXISTS, - lockQName, lockToken, existingLock); - } - existingLocksMap.put(existingLock, existingLock); - } - // Take the locks for the resources. - // Existing locks must be updated, if required. - for (Long requiredLockResourceId : requiredLockResourceIds) - { - LockEntity requiredLock = new LockEntity(); - requiredLock.setSharedResourceId(requiredLockResourceId); - requiredLock.setExclusiveResourceId(requiredExclusiveLockResourceId); - // Does it exist? - if (existingLocksMap.containsKey(requiredLock)) - { - requiredLock = existingLocksMap.get(requiredLock); - // Do an update - updateLock(requiredLock, lockToken, timeToLive); - } - else - { - // Create it - requiredLock = createLock( - requiredLockResourceId, - requiredExclusiveLockResourceId, - lockToken, - timeToLive); - } - } - // Done - } - - public void refreshLock(QName lockQName, String lockToken, long timeToLive) - { - updateLocks(lockQName, lockToken, lockToken, timeToLive); - } - - public void releaseLock(QName lockQName, String lockToken) - { - updateLocks(lockQName, lockToken, LOCK_TOKEN_RELEASED, 0L); - } - - /** - * Put new values against the given exclusive lock. This works against the related locks as - * well. - * @throws LockAcquisitionException on failure - */ - private void updateLocks(QName lockQName, String lockToken, String newLockToken, long timeToLive) - { - String qnameNamespaceUri = lockQName.getNamespaceURI(); - String qnameLocalName = lockQName.getLocalName(); - // Force lower case for case insensitivity - if (!qnameLocalName.toLowerCase().equals(qnameLocalName)) - { - lockQName = QName.createQName(qnameNamespaceUri, qnameLocalName.toLowerCase()); - qnameLocalName = lockQName.getLocalName(); - } - // Force the lock token to lowercase - lockToken = lockToken.toLowerCase(); - - // Resolve the namespace - Long qnameNamespaceId = qnameDAO.getOrCreateNamespace(qnameNamespaceUri).getFirst(); - - // Get the lock resource for the exclusive lock. - // All the locks that are created will need the exclusive case. - LockResourceEntity exclusiveLockResource = getLockResource(qnameNamespaceId, qnameLocalName); - if (exclusiveLockResource == null) - { - // If the exclusive lock doesn't exist, the locks don't exist - throw new LockAcquisitionException( - LockAcquisitionException.ERR_LOCK_RESOURCE_MISSING, - lockQName, lockToken); - } - Long exclusiveLockResourceId = exclusiveLockResource.getId(); - // Split the lock name - List lockQNames = splitLockQName(lockQName); - // We just need to know how many resources needed updating. - // They will all share the same exclusive lock resource - int requiredUpdateCount = lockQNames.size(); - // Update - int updateCount = updateLocks(exclusiveLockResourceId, lockToken, newLockToken, timeToLive); - // Check - if (updateCount != requiredUpdateCount) - { - throw new LockAcquisitionException( - LockAcquisitionException.ERR_LOCK_UPDATE_COUNT, - lockQName, lockToken, new Integer(updateCount), new Integer(requiredUpdateCount)); - } - // Done - } - - /** - * Validate if a lock can be taken or not. - */ - private boolean canTakeLock(LockEntity existingLock, String lockToken, Long desiredExclusiveLock) - { - if (EqualsHelper.nullSafeEquals(existingLock.getLockToken(), lockToken)) - { - // The lock token is the same. - // Regardless of lock expiry, the lock can be taken - return true; - } - else if (existingLock.hasExpired()) - { - // Expired locks are fair game - return true; - } - else if (existingLock.isExclusive()) - { - // It's a valid, exclusive lock held using a different token ... - return false; - } - else if (desiredExclusiveLock.equals(existingLock.getSharedResourceId())) - { - // We can't take an exclusive lock if a shared lock is active - return false; - } - else - { - // Good to go - return true; - } - } - - /** - * Override to get the unique, lock resource entity if one exists. - * - * @param qnameNamespaceId the namespace entity ID - * @param qnameLocalName the lock localname - * @return Returns the lock resource entity, - * or null if it doesn't exist - */ - protected abstract LockResourceEntity getLockResource(Long qnameNamespaceId, String qnameLocalName); - - /** - * Create a unique lock resource - * - * @param qnameNamespaceId the namespace entity ID - * @param qnameLocalName the lock localname - * @return Returns the newly created lock resource entity - */ - protected abstract LockResourceEntity createLockResource(Long qnameNamespaceId, String qnameLocalName); - - /** - * @param id the lock instance ID - * @return Returns the lock, if it exists, otherwise null - */ - protected abstract LockEntity getLock(Long id); - - /** - * @param sharedResourceId the shared lock resource ID - * @param exclusiveResourceId the exclusive lock resource ID - * @return Returns the lock, if it exists, otherwise null - */ - protected abstract LockEntity getLock(Long sharedResourceId, Long exclusiveResourceId); - - /** - * Get any existing lock data for the shared resources. The locks returned are not filtered and - * may be expired. - * - * @param lockResourceIds a list of shared resource IDs for which to retrieve the current locks - * @return Returns a list of locks (expired or not) for the given lock resources - */ - protected abstract List getLocksBySharedResourceIds(List sharedLockResourceIds); - - /** - * Create a new lock. - * @param sharedResourceId the specific resource to lock - * @param exclusiveResourceId the exclusive lock that is being sought - * @param lockToken the lock token to assign - * @param timeToLive the time, in milliseconds, for the lock to remain valid - * @return Returns the new lock - * @throws ConcurrencyFailureException if the lock was already taken at the time of creation - */ - protected abstract LockEntity createLock( - Long sharedResourceId, - Long exclusiveResourceId, - String lockToken, - long timeToLive); - - /** - * Update an existing lock - * @param lockEntity the specific lock to update - * @param lockApplicant the new lock token - * @param timeToLive the new lock time, in milliseconds, for the lock to remain valid - * @return Returns the updated lock - */ - protected abstract LockEntity updateLock( - LockEntity lockEntity, - String lockToken, - long timeToLive); - - /** - * @param exclusiveLockResourceId the exclusive resource ID being locks - * @param oldLockToken the lock token to change from - * @param newLockToken the new lock token - * @param timeToLive the new time to live (in milliseconds) - * @return the number of rows updated - */ - protected abstract int updateLocks( - Long exclusiveLockResourceId, - String oldLockToken, - String newLockToken, - long timeToLive); - - /** - * Split a lock's qualified name into the component parts using the '.' (period) as a - * separator on the localname. The namespace is preserved. The provided qualified - * name will always be the last component in the returned list. - * - * @param lockQName the lock name to split into it's higher-level paths - * @return Returns the namespace ID along with the ordered localnames - */ - protected List splitLockQName(QName lockQName) - { - String ns = lockQName.getNamespaceURI(); - String name = lockQName.getLocalName(); - - StringTokenizer tokenizer = new StringTokenizer(name, "."); - List ret = new ArrayList(tokenizer.countTokens()); - StringBuilder sb = new StringBuilder(); - // Fill it - boolean first = true; - while (tokenizer.hasMoreTokens()) - { - if (first) - { - first = false; - } - else - { - sb.append("."); - } - sb.append(tokenizer.nextToken()); - QName parentLockQName = QName.createQName(ns, sb.toString()); - ret.add(parentLockQName); - } - // Done - return ret; - } -} +/* + * Copyright (C) 2005-2009 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.domain.locks; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.StringTokenizer; + +import org.alfresco.repo.domain.QNameDAO; +import org.alfresco.repo.lock.LockAcquisitionException; +import org.alfresco.service.namespace.QName; +import org.alfresco.util.EqualsHelper; +import org.springframework.dao.ConcurrencyFailureException; + +/** + * Abstract implementation of the Locks DAO. + * + * @author Derek Hulley + * @since 3.2 + */ +public abstract class AbstractLockDAOImpl implements LockDAO +{ + private static final String LOCK_TOKEN_RELEASED = "not-locked"; + + private QNameDAO qnameDAO; + + /** + * @return Returns the DAO for namespace ID resolution + */ + protected QNameDAO getQNameDAO() + { + return qnameDAO; + } + + /** + * @param qnameDAO DAO for namespace ID resolution + */ + public void setQnameDAO(QNameDAO qnameDAO) + { + this.qnameDAO = qnameDAO; + } + + public void getLock(QName lockQName, String lockToken, long timeToLive) + { + String qnameNamespaceUri = lockQName.getNamespaceURI(); + String qnameLocalName = lockQName.getLocalName(); + // Force lower case for case insensitivity + if (!qnameLocalName.toLowerCase().equals(qnameLocalName)) + { + lockQName = QName.createQName(qnameNamespaceUri, qnameLocalName.toLowerCase()); + qnameLocalName = lockQName.getLocalName(); + } + // Force the lock token to lowercase + lockToken = lockToken.toLowerCase(); + + // Resolve the namespace + Long qnameNamespaceId = qnameDAO.getOrCreateNamespace(qnameNamespaceUri).getFirst(); + + // Get the lock resource for the exclusive lock. + // All the locks that are created will need the exclusive case. + LockResourceEntity exclusiveLockResource = getLockResource(qnameNamespaceId, qnameLocalName); + if (exclusiveLockResource == null) + { + // Create it + exclusiveLockResource = createLockResource(qnameNamespaceId, qnameLocalName); + } + Long requiredExclusiveLockResourceId = exclusiveLockResource.getId(); + // Split the lock name + List lockQNames = splitLockQName(lockQName); + List requiredLockResourceIds = new ArrayList(lockQNames.size()); + // Create the lock resources + for (QName lockQNameIter : lockQNames) + { + String localname = lockQNameIter.getLocalName(); + // Get the basic lock resource, forcing a create + LockResourceEntity lockResource = getLockResource(qnameNamespaceId, localname); + if (lockResource == null) + { + // Create it + lockResource = createLockResource(qnameNamespaceId, localname); + } + requiredLockResourceIds.add(lockResource.getId()); + } + + // Now, get all locks for the resources we will need + List existingLocks = getLocksBySharedResourceIds(requiredLockResourceIds); + Map existingLocksMap = new HashMap(); + // Check them and make sure they don't prevent locks + for (LockEntity existingLock : existingLocks) + { + boolean canTakeLock = canTakeLock(existingLock, lockToken, requiredExclusiveLockResourceId); + if (!canTakeLock) + { + throw new LockAcquisitionException( + LockAcquisitionException.ERR_EXCLUSIVE_LOCK_EXISTS, + lockQName, lockToken, existingLock); + } + existingLocksMap.put(existingLock, existingLock); + } + // Take the locks for the resources. + // Existing locks must be updated, if required. + for (Long requiredLockResourceId : requiredLockResourceIds) + { + LockEntity requiredLock = new LockEntity(); + requiredLock.setSharedResourceId(requiredLockResourceId); + requiredLock.setExclusiveResourceId(requiredExclusiveLockResourceId); + // Does it exist? + if (existingLocksMap.containsKey(requiredLock)) + { + requiredLock = existingLocksMap.get(requiredLock); + // Do an update + updateLock(requiredLock, lockToken, timeToLive); + } + else + { + // Create it + requiredLock = createLock( + requiredLockResourceId, + requiredExclusiveLockResourceId, + lockToken, + timeToLive); + } + } + // Done + } + + public void refreshLock(QName lockQName, String lockToken, long timeToLive) + { + updateLocks(lockQName, lockToken, lockToken, timeToLive); + } + + public void releaseLock(QName lockQName, String lockToken) + { + updateLocks(lockQName, lockToken, LOCK_TOKEN_RELEASED, 0L); + } + + /** + * Put new values against the given exclusive lock. This works against the related locks as + * well. + * @throws LockAcquisitionException on failure + */ + private void updateLocks(QName lockQName, String lockToken, String newLockToken, long timeToLive) + { + String qnameNamespaceUri = lockQName.getNamespaceURI(); + String qnameLocalName = lockQName.getLocalName(); + // Force lower case for case insensitivity + if (!qnameLocalName.toLowerCase().equals(qnameLocalName)) + { + lockQName = QName.createQName(qnameNamespaceUri, qnameLocalName.toLowerCase()); + qnameLocalName = lockQName.getLocalName(); + } + // Force the lock token to lowercase + lockToken = lockToken.toLowerCase(); + + // Resolve the namespace + Long qnameNamespaceId = qnameDAO.getOrCreateNamespace(qnameNamespaceUri).getFirst(); + + // Get the lock resource for the exclusive lock. + // All the locks that are created will need the exclusive case. + LockResourceEntity exclusiveLockResource = getLockResource(qnameNamespaceId, qnameLocalName); + if (exclusiveLockResource == null) + { + // If the exclusive lock doesn't exist, the locks don't exist + throw new LockAcquisitionException( + LockAcquisitionException.ERR_LOCK_RESOURCE_MISSING, + lockQName, lockToken); + } + Long exclusiveLockResourceId = exclusiveLockResource.getId(); + // Split the lock name + List lockQNames = splitLockQName(lockQName); + // We just need to know how many resources needed updating. + // They will all share the same exclusive lock resource + int requiredUpdateCount = lockQNames.size(); + // Update + int updateCount = updateLocks(exclusiveLockResourceId, lockToken, newLockToken, timeToLive); + // Check + if (updateCount != requiredUpdateCount) + { + if (LOCK_TOKEN_RELEASED.equals(newLockToken)) + { + throw new LockAcquisitionException( + LockAcquisitionException.ERR_FAILED_TO_RELEASE_LOCK, + lockQName, lockToken); + } + else + { + throw new LockAcquisitionException( + LockAcquisitionException.ERR_LOCK_UPDATE_COUNT, + lockQName, lockToken, new Integer(updateCount), new Integer(requiredUpdateCount)); + } + } + // Done + } + + /** + * Validate if a lock can be taken or not. + */ + private boolean canTakeLock(LockEntity existingLock, String lockToken, Long desiredExclusiveLock) + { + if (EqualsHelper.nullSafeEquals(existingLock.getLockToken(), lockToken)) + { + // The lock token is the same. + // Regardless of lock expiry, the lock can be taken + return true; + } + else if (existingLock.hasExpired()) + { + // Expired locks are fair game + return true; + } + else if (existingLock.isExclusive()) + { + // It's a valid, exclusive lock held using a different token ... + return false; + } + else if (desiredExclusiveLock.equals(existingLock.getSharedResourceId())) + { + // We can't take an exclusive lock if a shared lock is active + return false; + } + else + { + // Good to go + return true; + } + } + + /** + * Override to get the unique, lock resource entity if one exists. + * + * @param qnameNamespaceId the namespace entity ID + * @param qnameLocalName the lock localname + * @return Returns the lock resource entity, + * or null if it doesn't exist + */ + protected abstract LockResourceEntity getLockResource(Long qnameNamespaceId, String qnameLocalName); + + /** + * Create a unique lock resource + * + * @param qnameNamespaceId the namespace entity ID + * @param qnameLocalName the lock localname + * @return Returns the newly created lock resource entity + */ + protected abstract LockResourceEntity createLockResource(Long qnameNamespaceId, String qnameLocalName); + + /** + * @param id the lock instance ID + * @return Returns the lock, if it exists, otherwise null + */ + protected abstract LockEntity getLock(Long id); + + /** + * @param sharedResourceId the shared lock resource ID + * @param exclusiveResourceId the exclusive lock resource ID + * @return Returns the lock, if it exists, otherwise null + */ + protected abstract LockEntity getLock(Long sharedResourceId, Long exclusiveResourceId); + + /** + * Get any existing lock data for the shared resources. The locks returned are not filtered and + * may be expired. + * + * @param lockResourceIds a list of shared resource IDs for which to retrieve the current locks + * @return Returns a list of locks (expired or not) for the given lock resources + */ + protected abstract List getLocksBySharedResourceIds(List sharedLockResourceIds); + + /** + * Create a new lock. + * @param sharedResourceId the specific resource to lock + * @param exclusiveResourceId the exclusive lock that is being sought + * @param lockToken the lock token to assign + * @param timeToLive the time, in milliseconds, for the lock to remain valid + * @return Returns the new lock + * @throws ConcurrencyFailureException if the lock was already taken at the time of creation + */ + protected abstract LockEntity createLock( + Long sharedResourceId, + Long exclusiveResourceId, + String lockToken, + long timeToLive); + + /** + * Update an existing lock + * @param lockEntity the specific lock to update + * @param lockApplicant the new lock token + * @param timeToLive the new lock time, in milliseconds, for the lock to remain valid + * @return Returns the updated lock + */ + protected abstract LockEntity updateLock( + LockEntity lockEntity, + String lockToken, + long timeToLive); + + /** + * @param exclusiveLockResourceId the exclusive resource ID being locks + * @param oldLockToken the lock token to change from + * @param newLockToken the new lock token + * @param timeToLive the new time to live (in milliseconds) + * @return the number of rows updated + */ + protected abstract int updateLocks( + Long exclusiveLockResourceId, + String oldLockToken, + String newLockToken, + long timeToLive); + + /** + * Split a lock's qualified name into the component parts using the '.' (period) as a + * separator on the localname. The namespace is preserved. The provided qualified + * name will always be the last component in the returned list. + * + * @param lockQName the lock name to split into it's higher-level paths + * @return Returns the namespace ID along with the ordered localnames + */ + protected List splitLockQName(QName lockQName) + { + String ns = lockQName.getNamespaceURI(); + String name = lockQName.getLocalName(); + + StringTokenizer tokenizer = new StringTokenizer(name, "."); + List ret = new ArrayList(tokenizer.countTokens()); + StringBuilder sb = new StringBuilder(); + // Fill it + boolean first = true; + while (tokenizer.hasMoreTokens()) + { + if (first) + { + first = false; + } + else + { + sb.append("."); + } + sb.append(tokenizer.nextToken()); + QName parentLockQName = QName.createQName(ns, sb.toString()); + ret.add(parentLockQName); + } + // Done + return ret; + } +} diff --git a/source/java/org/alfresco/repo/forms/FormServiceImplTest.java b/source/java/org/alfresco/repo/forms/FormServiceImplTest.java index c4fd9e5189..39adba6350 100644 --- a/source/java/org/alfresco/repo/forms/FormServiceImplTest.java +++ b/source/java/org/alfresco/repo/forms/FormServiceImplTest.java @@ -739,9 +739,15 @@ public class FormServiceImplTest extends BaseAlfrescoSpringTest // add an association to the child doc (as an attachment which is defined on an aspect not applied) //data.addField("assoc_cm_attachments_added", this.childDoc.toString()); - // try and update non-existent properties (make sure there are no exceptions) + // try and update non-existent properties and assocs (make sure there are no exceptions) data.addFieldData("prop_cm_wrong", "This should not be persisted"); data.addFieldData("cm_wrong", "This should not be persisted"); + data.addFieldData("prop_cm_wrong_property", "This should not be persisted"); + data.addFieldData("prop_cm_wrong_property_name", "This should not be persisted"); + data.addFieldData("assoc_cm_wrong_association", "This should be ignored"); + data.addFieldData("assoc_cm_wrong_association_added", "This should be ignored"); + data.addFieldData("assoc_cm_wrong_association_removed", "This should be ignored"); + data.addFieldData("assoc_cm_added", "This should be ignored"); // persist the data this.formService.saveForm(new Item(NODE_FORM_ITEM_KIND, this.document.toString()), data); diff --git a/source/java/org/alfresco/repo/forms/processor/node/ContentModelFormProcessor.java b/source/java/org/alfresco/repo/forms/processor/node/ContentModelFormProcessor.java index b83c362b51..0c0ef953ed 100644 --- a/source/java/org/alfresco/repo/forms/processor/node/ContentModelFormProcessor.java +++ b/source/java/org/alfresco/repo/forms/processor/node/ContentModelFormProcessor.java @@ -111,7 +111,7 @@ public abstract class ContentModelFormProcessor extends * names will look like "prop_cm_name". The pattern can also be * used to extract the "cm" and the "name" parts. */ - protected Pattern propertyNamePattern = Pattern.compile(PROP_DATA_PREFIX + "(.*){1}?_(.*){1}?"); + protected Pattern propertyNamePattern = Pattern.compile(PROP_DATA_PREFIX + "([a-zA-Z0-9]+)_(.*)"); /** * A regular expression which can be used to match tranisent property names. @@ -126,7 +126,7 @@ public abstract class ContentModelFormProcessor extends * pattern can also be used to extract the "cm", the "name" and the suffix * parts. */ - protected Pattern associationNamePattern = Pattern.compile(ASSOC_DATA_PREFIX + "(.*){1}?_(.*){1}?(_[a-zA-Z]+)"); + protected Pattern associationNamePattern = Pattern.compile(ASSOC_DATA_PREFIX + "([a-zA-Z0-9]+)_(.*)(_[a-zA-Z]+)"); /** * Sets the node service @@ -1115,8 +1115,9 @@ public abstract class ContentModelFormProcessor extends { if (getLogger().isWarnEnabled()) { - getLogger().warn("Definition for association " + fullQName + " not recognised and not persisted."); + getLogger().warn("Ignoring field '" + fieldName + "' as an association definition can not be found"); } + return; } @@ -1162,10 +1163,10 @@ public abstract class ContentModelFormProcessor extends if (getLogger().isWarnEnabled()) { StringBuilder msg = new StringBuilder(); - msg.append("fieldName ").append(fieldName).append( - " does not have one of the expected suffixes [").append( - ASSOC_DATA_ADDED_SUFFIX).append(", ").append(ASSOC_DATA_REMOVED_SUFFIX) - .append("] and has been ignored."); + msg.append("Ignoring 'fieldName ").append(fieldName).append( + "' as it does not have one of the expected suffixes (").append( + ASSOC_DATA_ADDED_SUFFIX).append(" or ").append(ASSOC_DATA_REMOVED_SUFFIX) + .append(")"); getLogger().warn(msg.toString()); } } @@ -1183,6 +1184,10 @@ public abstract class ContentModelFormProcessor extends } } } + else if (getLogger().isWarnEnabled()) + { + getLogger().warn("Ignoring unrecognised field '" + fieldName + "'"); + } } /** diff --git a/source/java/org/alfresco/repo/lock/LockAcquisitionException.java b/source/java/org/alfresco/repo/lock/LockAcquisitionException.java index 753a14c54f..fbb8ffcc58 100644 --- a/source/java/org/alfresco/repo/lock/LockAcquisitionException.java +++ b/source/java/org/alfresco/repo/lock/LockAcquisitionException.java @@ -60,6 +60,13 @@ public class LockAcquisitionException extends AlfrescoRuntimeException * */ public static final String ERR_LOCK_UPDATE_COUNT = "system.locks.err.lock_update_count"; + /** + *
    + *
  • 1: the qname
  • + *
  • 2: the lock token
  • + *
+ */ + public static final String ERR_FAILED_TO_RELEASE_LOCK = "system.locks.err.failed_to_release_lock"; /** *
    *
  • 1: the qname
  • diff --git a/source/java/org/alfresco/repo/model/ml/MultilingualDocumentAspect.java b/source/java/org/alfresco/repo/model/ml/MultilingualDocumentAspect.java index 2f30a892ef..9e05a10b11 100644 --- a/source/java/org/alfresco/repo/model/ml/MultilingualDocumentAspect.java +++ b/source/java/org/alfresco/repo/model/ml/MultilingualDocumentAspect.java @@ -124,20 +124,12 @@ public class MultilingualDocumentAspect implements } /** - * If this is not an empty translation, then ensure that the node is properly - * unhooked from the translation mechanism first. + * Ensure that the node is properly unhooked from the translation mechanism first. */ public void beforeDeleteNode(NodeRef nodeRef) { - if (nodeService.hasAspect(nodeRef, ContentModel.ASPECT_MULTILINGUAL_EMPTY_TRANSLATION)) - { - // We just let it get deleted - } - else - { - // First unhook it - multilingualContentService.unmakeTranslation(nodeRef); - } + // First unhook it + multilingualContentService.unmakeTranslation(nodeRef); } /** diff --git a/source/java/org/alfresco/repo/node/BaseNodeServiceTest.java b/source/java/org/alfresco/repo/node/BaseNodeServiceTest.java index 62af5cf676..abee4c560f 100644 --- a/source/java/org/alfresco/repo/node/BaseNodeServiceTest.java +++ b/source/java/org/alfresco/repo/node/BaseNodeServiceTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2007 Alfresco Software Limited. + * Copyright (C) 2005-2009 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 @@ -105,6 +105,10 @@ public abstract class BaseNodeServiceTest extends BaseSpringTest { public static final String NAMESPACE = "http://www.alfresco.org/test/BaseNodeServiceTest"; public static final String TEST_PREFIX = "test"; + + public static final String DEFAULT_VALUE = "defaultValue"; + public static final String NOT_DEFAULT_VALUE = "notDefaultValue"; + public static final QName TYPE_QNAME_TEST_CONTENT = QName.createQName(NAMESPACE, "content"); public static final QName TYPE_QNAME_TEST_MANY_PROPERTIES = QName.createQName(NAMESPACE, "many-properties"); public static final QName TYPE_QNAME_TEST_MANY_ML_PROPERTIES = QName.createQName(NAMESPACE, "many-ml-properties"); @@ -134,8 +138,8 @@ public abstract class BaseNodeServiceTest extends BaseSpringTest public static final QName PROP_QNAME_LOCALE_VALUE = QName.createQName(NAMESPACE, "localeValue"); public static final QName PROP_QNAME_NULL_VALUE = QName.createQName(NAMESPACE, "nullValue"); public static final QName PROP_QNAME_MULTI_VALUE = QName.createQName(NAMESPACE, "multiValue"); - public static final QName PROP_QNAME_PERIOD_VALUE = QName.createQName(NAMESPACE, "periodValue"); - public static final QName PROP_QNAME_MULTI_ML_VALUE = QName.createQName(NAMESPACE, "multiMLValue"); + public static final QName PROP_QNAME_PERIOD_VALUE = QName.createQName(NAMESPACE, "periodValue"); + public static final QName PROP_QNAME_MULTI_ML_VALUE = QName.createQName(NAMESPACE, "multiMLValue"); public static final QName PROP_QNAME_MARKER_PROP = QName.createQName(NAMESPACE, "markerProp"); public static final QName PROP_QNAME_PROP1 = QName.createQName(NAMESPACE, "prop1"); public static final QName PROP_QNAME_PROP2 = QName.createQName(NAMESPACE, "prop2"); @@ -566,12 +570,19 @@ public abstract class BaseNodeServiceTest extends BaseSpringTest rootNodeRef, ASSOC_TYPE_QNAME_TEST_CHILDREN, QName.createQName("setTypeTest"), - TYPE_QNAME_TEST_CONTENT).getChildRef(); + TYPE_QNAME_TEST_CONTENT).getChildRef(); assertEquals(TYPE_QNAME_TEST_CONTENT, this.nodeService.getType(nodeRef)); + assertNull(this.nodeService.getProperty(nodeRef, PROP_QNAME_PROP1)); + // Now change the type this.nodeService.setType(nodeRef, TYPE_QNAME_EXTENDED_CONTENT); - assertEquals(TYPE_QNAME_EXTENDED_CONTENT, this.nodeService.getType(nodeRef)); + assertEquals(TYPE_QNAME_EXTENDED_CONTENT, this.nodeService.getType(nodeRef)); + + // Check new defaults + Serializable defaultValue = this.nodeService.getProperty(nodeRef, PROP_QNAME_PROP1); + assertNotNull("No default property value assigned", defaultValue); + assertEquals(DEFAULT_VALUE, defaultValue); } /** @@ -2409,25 +2420,25 @@ public abstract class BaseNodeServiceTest extends BaseSpringTest rootNodeRef, ASSOC_TYPE_QNAME_TEST_CHILDREN, QName.createQName("testDefaultValues"), - TYPE_QNAME_EXTENDED_CONTENT).getChildRef(); - assertEquals("defaultValue", this.nodeService.getProperty(nodeRef, PROP_QNAME_PROP1)); + TYPE_QNAME_EXTENDED_CONTENT).getChildRef(); + assertEquals(DEFAULT_VALUE, this.nodeService.getProperty(nodeRef, PROP_QNAME_PROP1)); this.nodeService.addAspect(nodeRef, ASPECT_QNAME_WITH_DEFAULT_VALUE, null); - assertEquals("defaultValue", this.nodeService.getProperty(nodeRef, PROP_QNAME_PROP2)); + assertEquals(DEFAULT_VALUE, this.nodeService.getProperty(nodeRef, PROP_QNAME_PROP2)); // Ensure that default values do not overrite already set values Map props = new HashMap(1); - props.put(PROP_QNAME_PROP1, "notDefaultValue"); + props.put(PROP_QNAME_PROP1, NOT_DEFAULT_VALUE); NodeRef nodeRef2 = nodeService.createNode( rootNodeRef, ASSOC_TYPE_QNAME_TEST_CHILDREN, QName.createQName("testDefaultValues"), TYPE_QNAME_EXTENDED_CONTENT, props).getChildRef(); - assertEquals("notDefaultValue", this.nodeService.getProperty(nodeRef2, PROP_QNAME_PROP1)); + assertEquals(NOT_DEFAULT_VALUE, this.nodeService.getProperty(nodeRef2, PROP_QNAME_PROP1)); Map prop2 = new HashMap(1); - prop2.put(PROP_QNAME_PROP2, "notDefaultValue"); + prop2.put(PROP_QNAME_PROP2, NOT_DEFAULT_VALUE); this.nodeService.addAspect(nodeRef2, ASPECT_QNAME_WITH_DEFAULT_VALUE, prop2); - assertEquals("notDefaultValue", this.nodeService.getProperty(nodeRef2, PROP_QNAME_PROP2)); + assertEquals(NOT_DEFAULT_VALUE, this.nodeService.getProperty(nodeRef2, PROP_QNAME_PROP2)); } diff --git a/source/java/org/alfresco/repo/node/FullNodeServiceTest.java b/source/java/org/alfresco/repo/node/FullNodeServiceTest.java index 4c632a0b8d..3c18068dd6 100644 --- a/source/java/org/alfresco/repo/node/FullNodeServiceTest.java +++ b/source/java/org/alfresco/repo/node/FullNodeServiceTest.java @@ -25,17 +25,25 @@ package org.alfresco.repo.node; import java.io.Serializable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; import java.util.HashMap; +import java.util.HashSet; +import java.util.List; import java.util.Locale; import java.util.Map; -import org.springframework.extensions.surf.util.I18NUtil; +import javax.transaction.UserTransaction; + import org.alfresco.repo.node.db.DbNodeServiceImpl; +import org.alfresco.service.cmr.dictionary.DictionaryException; import org.alfresco.service.cmr.repository.MLText; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter; import org.alfresco.service.namespace.QName; +import org.springframework.extensions.surf.util.I18NUtil; /** * Tests the fully-intercepted version of the NodeService @@ -245,4 +253,168 @@ public class FullNodeServiceTest extends BaseNodeServiceTest String strValue = mlTextValue.getDefaultValue(); checkProperties.put(PROP_QNAME_ML_TEXT_VALUE, strValue); } + + @SuppressWarnings("unchecked") + public void testMultiProp() throws Exception + { + QName undeclaredPropQName = QName.createQName(NAMESPACE, getName()); + // create node + NodeRef nodeRef = nodeService.createNode( + rootNodeRef, + ASSOC_TYPE_QNAME_TEST_CHILDREN, + QName.createQName("pathA"), + TYPE_QNAME_TEST_MULTIPLE_TESTER).getChildRef(); + ArrayList values = new ArrayList(1); + values.add("ABC"); + values.add("DEF"); + // test allowable conditions + nodeService.setProperty(nodeRef, PROP_QNAME_STRING_PROP_SINGLE, "ABC"); + // nodeService.setProperty(nodeRef, PROP_QNAME_STRING_PROP_SINGLE, values); -- should fail + nodeService.setProperty(nodeRef, PROP_QNAME_STRING_PROP_MULTIPLE, "ABC"); + nodeService.setProperty(nodeRef, PROP_QNAME_STRING_PROP_MULTIPLE, values); + nodeService.setProperty(nodeRef, PROP_QNAME_ANY_PROP_SINGLE, "ABC"); + nodeService.setProperty(nodeRef, PROP_QNAME_ANY_PROP_SINGLE, values); + nodeService.setProperty(nodeRef, PROP_QNAME_ANY_PROP_MULTIPLE, "ABC"); + nodeService.setProperty(nodeRef, PROP_QNAME_ANY_PROP_MULTIPLE, values); + nodeService.setProperty(nodeRef, undeclaredPropQName, "ABC"); + nodeService.setProperty(nodeRef, undeclaredPropQName, values); + + // commit as we will be breaking the transaction in the next test + setComplete(); + endTransaction(); + + UserTransaction txn = transactionService.getUserTransaction(); + try + { + txn.begin(); + // this should fail as we are passing multiple values into a non-any that is multiple=false + nodeService.setProperty(nodeRef, PROP_QNAME_STRING_PROP_SINGLE, values); + } + catch (DictionaryException e) + { + // expected + } + finally + { + try { txn.rollback(); } catch (Throwable e) {} + } + + txn = transactionService.getUserTransaction(); + try + { + txn.begin(); + // Check that multi-valued d:mltext can be collections of MLText + values.clear(); + values.add(new MLText("ABC")); + values.add(new MLText("DEF")); + nodeService.setProperty(nodeRef, PROP_QNAME_MULTI_ML_VALUE, values); + List checkValues = (List) nodeService.getProperty( + nodeRef, PROP_QNAME_MULTI_ML_VALUE); + assertEquals("Expected 2 MLText values back", 2, checkValues.size()); + assertTrue("Incorrect type in collection", checkValues.get(0) instanceof String); + assertTrue("Incorrect type in collection", checkValues.get(1) instanceof String); + + // Check that multi-valued d:any properties can be collections of collections (empty) + // We put ArrayLists and HashSets into the Collection of d:any, so that is exactly what should come out + values.clear(); + ArrayList arrayListVal = new ArrayList(2); + HashSet hashSetVal = new HashSet(2); + values.add(arrayListVal); + values.add(hashSetVal); + nodeService.setProperty(nodeRef, PROP_QNAME_ANY_PROP_MULTIPLE, values); + checkValues = (List) nodeService.getProperty( + nodeRef, PROP_QNAME_ANY_PROP_MULTIPLE); + assertEquals("Expected 2 Collection values back", 2, checkValues.size()); + assertTrue("Incorrect type in collection", checkValues.get(0) instanceof ArrayList); // ArrayList in - ArrayList out + assertTrue("Incorrect type in collection", checkValues.get(1) instanceof HashSet); // HashSet in - HashSet out + + // Check that multi-valued d:any properties can be collections of collections (with values) + // We put ArrayLists and HashSets into the Collection of d:any, so that is exactly what should come out + arrayListVal.add("ONE"); + arrayListVal.add("TWO"); + hashSetVal.add("ONE"); + hashSetVal.add("TWO"); + values.clear(); + values.add(arrayListVal); + values.add(hashSetVal); + nodeService.setProperty(nodeRef, PROP_QNAME_ANY_PROP_MULTIPLE, values); + checkValues = (List) nodeService.getProperty( + nodeRef, PROP_QNAME_ANY_PROP_MULTIPLE); + assertEquals("Expected 2 Collection values back", 2, checkValues.size()); + assertTrue("Incorrect type in collection", checkValues.get(0) instanceof ArrayList); // ArrayList in - ArrayList out + assertTrue("Incorrect type in collection", checkValues.get(1) instanceof HashSet); // HashSet in - HashSet out + assertEquals("First collection incorrect", 2, ((Collection)checkValues.get(0)).size()); + assertEquals("Second collection incorrect", 2, ((Collection)checkValues.get(1)).size()); + } + catch (DictionaryException e) + { + // expected + } + finally + { + try { txn.rollback(); } catch (Throwable e) {} + } + } + + @SuppressWarnings("unchecked") + public void testMultiValueMLTextProperties() throws Exception + { + NodeRef nodeRef = nodeService.createNode( + rootNodeRef, + ASSOC_TYPE_QNAME_TEST_CHILDREN, + QName.createQName("pathA"), + TYPE_QNAME_TEST_MANY_ML_PROPERTIES).getChildRef(); + + // Create MLText properties and add to a collection + List mlTextCollection = new ArrayList(2); + MLText mlText0 = new MLText(); + mlText0.addValue(Locale.ENGLISH, "Hello"); + mlText0.addValue(Locale.FRENCH, "Bonjour"); + mlTextCollection.add(mlText0); + MLText mlText1 = new MLText(); + mlText1.addValue(Locale.ENGLISH, "Bye bye"); + mlText1.addValue(Locale.FRENCH, "Au revoir"); + mlTextCollection.add(mlText1); + + nodeService.setProperty(nodeRef, PROP_QNAME_MULTI_ML_VALUE, (Serializable) mlTextCollection); + + I18NUtil.setContentLocale(Locale.ENGLISH); + Collection mlTextCollectionCheck = (Collection) nodeService.getProperty(nodeRef, PROP_QNAME_MULTI_ML_VALUE); + assertEquals("MLText collection didn't come back correctly.", Arrays.asList(new String[]{"Hello", "Bye bye"}), mlTextCollectionCheck); + + I18NUtil.setContentLocale(Locale.FRENCH); + mlTextCollectionCheck = (Collection) nodeService.getProperty(nodeRef, PROP_QNAME_MULTI_ML_VALUE); + assertEquals("MLText collection didn't come back correctly.", Arrays.asList(new String[]{"Bonjour", "Au revoir"}), mlTextCollectionCheck); + + I18NUtil.setContentLocale(Locale.GERMAN); + nodeService.setProperty(nodeRef, PROP_QNAME_MULTI_ML_VALUE, (Serializable)Arrays.asList(new String[]{"eins", "zwei", "drie", "vier"})); + + I18NUtil.setContentLocale(Locale.ENGLISH); + mlTextCollectionCheck = (Collection) nodeService.getProperty(nodeRef, PROP_QNAME_MULTI_ML_VALUE); + assertEquals("MLText collection didn't come back correctly.", Arrays.asList(new String[]{"Hello", "Bye bye"}), mlTextCollectionCheck); + + I18NUtil.setContentLocale(Locale.FRENCH); + mlTextCollectionCheck = (Collection) nodeService.getProperty(nodeRef, PROP_QNAME_MULTI_ML_VALUE); + assertEquals("MLText collection didn't come back correctly.", Arrays.asList(new String[]{"Bonjour", "Au revoir"}), mlTextCollectionCheck); + + I18NUtil.setContentLocale(Locale.GERMAN); + mlTextCollectionCheck = (Collection) nodeService.getProperty(nodeRef, PROP_QNAME_MULTI_ML_VALUE); + assertEquals("MLText collection didn't come back correctly.", Arrays.asList(new String[]{"eins", "zwei", "drie", "vier"}), mlTextCollectionCheck); + + I18NUtil.setContentLocale(Locale.GERMAN); + nodeService.setProperty(nodeRef, PROP_QNAME_MULTI_ML_VALUE, (Serializable)Arrays.asList(new String[]{"eins"})); + + I18NUtil.setContentLocale(Locale.ENGLISH); + mlTextCollectionCheck = (Collection) nodeService.getProperty(nodeRef, PROP_QNAME_MULTI_ML_VALUE); + assertEquals("MLText collection didn't come back correctly.", Arrays.asList(new String[]{"Hello", "Bye bye"}), mlTextCollectionCheck); + + I18NUtil.setContentLocale(Locale.FRENCH); + mlTextCollectionCheck = (Collection) nodeService.getProperty(nodeRef, PROP_QNAME_MULTI_ML_VALUE); + assertEquals("MLText collection didn't come back correctly.", Arrays.asList(new String[]{"Bonjour", "Au revoir"}), mlTextCollectionCheck); + + I18NUtil.setContentLocale(Locale.GERMAN); + mlTextCollectionCheck = (Collection) nodeService.getProperty(nodeRef, PROP_QNAME_MULTI_ML_VALUE); + assertEquals("MLText collection didn't come back correctly.", Arrays.asList(new String[]{"eins"}), mlTextCollectionCheck); + + } } diff --git a/source/java/org/alfresco/repo/node/MLPropertyInterceptor.java b/source/java/org/alfresco/repo/node/MLPropertyInterceptor.java index 24ffd9995d..57209b6b18 100644 --- a/source/java/org/alfresco/repo/node/MLPropertyInterceptor.java +++ b/source/java/org/alfresco/repo/node/MLPropertyInterceptor.java @@ -25,11 +25,15 @@ package org.alfresco.repo.node; import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.HashMap; +import java.util.HashSet; import java.util.Locale; import java.util.Map; +import java.util.Set; import org.springframework.extensions.surf.util.I18NUtil; import org.alfresco.model.ContentModel; @@ -352,6 +356,22 @@ public class MLPropertyInterceptor implements MethodInterceptor MLText mlText = (MLText) outboundValue; ret = mlText.getClosestValue(contentLocale); } + else if(isCollectionOfMLText(outboundValue)) + { + Collection col = (Collection)outboundValue; + ArrayList answer = new ArrayList(col.size()); + Locale closestLocale = getClosestLocale(col, contentLocale); + for(Object o : col) + { + MLText mlText = (MLText) o; + String value = mlText.get(closestLocale); + if(value != null) + { + answer.add(value); + } + } + ret = answer; + } else if (pivotNodeRef != null) // It is an empty translation { if (propertyQName.equals(ContentModel.PROP_MODIFIED)) @@ -397,6 +417,58 @@ public class MLPropertyInterceptor implements MethodInterceptor return ret; } + public Locale getClosestLocale(Collection collection, Locale locale) + { + if (collection.size() == 0) + { + return null; + } + // Use the available keys as options + HashSet locales = new HashSet(); + for(Object o : collection) + { + MLText mlText = (MLText)o; + locales.addAll(mlText.keySet()); + } + // Get a match + Locale match = I18NUtil.getNearestLocale(locale, locales); + if (match == null) + { + // No close matches for the locale - go for the default locale + locale = I18NUtil.getLocale(); + match = I18NUtil.getNearestLocale(locale, locales); + if (match == null) + { + // just get any locale + match = I18NUtil.getNearestLocale(null, locales); + } + } + return match; + } + + /** + * @param outboundValue + * @return + */ + private boolean isCollectionOfMLText(Serializable outboundValue) + { + if(outboundValue instanceof Collection) + { + for(Object o : (Collection)outboundValue) + { + if(!(o instanceof MLText)) + { + return false; + } + } + return true; + } + else + { + return false; + } + } + private Map convertInboundProperties( Map currentProperties, Map newProperties, @@ -443,10 +515,83 @@ public class MLPropertyInterceptor implements MethodInterceptor else if (propertyDef.getDataType().getName().equals(DataTypeDefinition.MLTEXT)) { // Don't mess with multivalued properties or instances already of type MLText - if (propertyDef.isMultiValued() || (inboundValue instanceof MLText) ) + if (inboundValue instanceof MLText) { ret = inboundValue; } + else if(propertyDef.isMultiValued()) + { + // leave collectios of ML text alone + if(isCollectionOfMLText(inboundValue)) + { + ret = inboundValue; + } + else + { + // Anything else we assume is localised + if (currentValue == null && nodeRef != null) + { + currentValue = nodeService.getProperty(nodeRef, propertyQName); + } + ArrayList returnMLList = new ArrayList(); + if (currentValue != null) + { + Collection currentCollection = DefaultTypeConverter.INSTANCE.getCollection(MLText.class, currentValue); + returnMLList.addAll(currentCollection); + } + Collection inboundCollection = DefaultTypeConverter.INSTANCE.getCollection(String.class, inboundValue); + int count = 0; + for(String current : inboundCollection) + { + MLText newMLValue; + if(count < returnMLList.size()) + { + MLText currentMLValue = returnMLList.get(count); + newMLValue = new MLText(); + if (currentMLValue != null) + { + newMLValue.putAll(currentMLValue); + } + } + else + { + newMLValue = new MLText(); + } + newMLValue.addValue(contentLocale, current); + if(count < returnMLList.size()) + { + returnMLList.set(count, newMLValue); + } + else + { + returnMLList.add(newMLValue); + } + count++; + } + // remove locale settings for anything after + for(int i = count; i < returnMLList.size(); i++) + { + MLText currentMLValue = returnMLList.get(i); + MLText newMLValue = new MLText(); + if (currentMLValue != null) + { + newMLValue.putAll(currentMLValue); + } + newMLValue.remove(contentLocale); + returnMLList.set(i, newMLValue); + } + // tidy up empty locales + ArrayList tidy = new ArrayList(); + for(MLText mlText : returnMLList) + { + if(mlText.keySet().size() > 0) + { + tidy.add(mlText); + } + } + ret = tidy; + } + } else { // This is a multilingual single-valued property diff --git a/source/java/org/alfresco/repo/node/NodeRefPropertyMethodInterceptor.java b/source/java/org/alfresco/repo/node/NodeRefPropertyMethodInterceptor.java index 3cb470613d..9551e39984 100644 --- a/source/java/org/alfresco/repo/node/NodeRefPropertyMethodInterceptor.java +++ b/source/java/org/alfresco/repo/node/NodeRefPropertyMethodInterceptor.java @@ -28,6 +28,7 @@ import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; import org.alfresco.model.ContentModel; @@ -85,7 +86,7 @@ public class NodeRefPropertyMethodInterceptor implements MethodInterceptor { this.dictionaryService = dictionaryService; } - + private DictionaryService getDictionaryService() { return dictionaryService; @@ -95,12 +96,12 @@ public class NodeRefPropertyMethodInterceptor implements MethodInterceptor { this.nodeService = nodeService; } - + private NodeService getNodeService() { return nodeService; } - + public void init() { PropertyCheck.mandatory(this, "dictionaryService", dictionaryService); @@ -302,7 +303,8 @@ public class NodeRefPropertyMethodInterceptor implements MethodInterceptor { if (inboundValue instanceof Collection) { - Collection in = (Collection) inboundValue; + HashSet categories = new HashSet(); + Collection in = (Collection) inboundValue; ArrayList out = new ArrayList(in.size()); for (Object o : in) { @@ -323,7 +325,11 @@ public class NodeRefPropertyMethodInterceptor implements MethodInterceptor QName type = getNodeService().getType(test); if (getDictionaryService().isSubClass(type, ContentModel.TYPE_CATEGORY)) { - out.add(test); + if (!categories.contains(test)) + { + out.add(test); + categories.add(test); + } } } else diff --git a/source/java/org/alfresco/repo/node/NodeRefPropertyMethodInterceptorTest.java b/source/java/org/alfresco/repo/node/NodeRefPropertyMethodInterceptorTest.java index e1d9d923aa..4a7f3e25ad 100644 --- a/source/java/org/alfresco/repo/node/NodeRefPropertyMethodInterceptorTest.java +++ b/source/java/org/alfresco/repo/node/NodeRefPropertyMethodInterceptorTest.java @@ -1436,6 +1436,7 @@ public class NodeRefPropertyMethodInterceptorTest extends BaseSpringTest ArrayList values = new ArrayList(); values.add(cat); + values.add(cat); nodeService.setProperty(n1, typeCategoriesProp, values); nodeService.setProperty(n1, typeNoderefsProp, values); @@ -1443,19 +1444,19 @@ public class NodeRefPropertyMethodInterceptorTest extends BaseSpringTest assertNotNull(mlAwareNodeService.getProperty(n1, typeCategoriesProp)); assertEquals(1, ((Collection) mlAwareNodeService.getProperty(n1, typeCategoriesProp)).size()); assertNotNull(mlAwareNodeService.getProperty(n1, typeNoderefsProp)); - assertEquals(1, ((Collection) mlAwareNodeService.getProperty(n1, typeNoderefsProp)).size()); + assertEquals(2, ((Collection) mlAwareNodeService.getProperty(n1, typeNoderefsProp)).size()); assertNotNull(mlAwareNodeService.getProperties(n1).get(typeCategoriesProp)); assertEquals(1, ((Collection) mlAwareNodeService.getProperties(n1).get(typeCategoriesProp)).size()); assertNotNull(mlAwareNodeService.getProperties(n1).get(typeNoderefsProp)); - assertEquals(1, ((Collection) mlAwareNodeService.getProperties(n1).get(typeNoderefsProp)).size()); + assertEquals(2, ((Collection) mlAwareNodeService.getProperties(n1).get(typeNoderefsProp)).size()); assertNotNull(nodeService.getProperty(n1, typeCategoriesProp)); assertEquals(1, ((Collection) nodeService.getProperty(n1, typeCategoriesProp)).size()); assertNotNull(nodeService.getProperty(n1, typeNoderefsProp)); - assertEquals(1, ((Collection) nodeService.getProperty(n1, typeNoderefsProp)).size()); + assertEquals(2, ((Collection) nodeService.getProperty(n1, typeNoderefsProp)).size()); assertNotNull(nodeService.getProperties(n1).get(typeCategoriesProp)); assertEquals(1, ((Collection) nodeService.getProperties(n1).get(typeCategoriesProp)).size()); assertNotNull(nodeService.getProperties(n1).get(typeNoderefsProp)); - assertEquals(1, ((Collection) nodeService.getProperties(n1).get(typeNoderefsProp)).size()); + assertEquals(2, ((Collection) nodeService.getProperties(n1).get(typeNoderefsProp)).size()); } public void testSetPropertyMixedList() diff --git a/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java b/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java index 52e9524fb8..4235ff3779 100644 --- a/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java +++ b/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java @@ -45,7 +45,6 @@ import org.alfresco.repo.node.StoreArchiveMap; import org.alfresco.repo.node.index.NodeIndexer; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.transaction.AlfrescoTransactionSupport; -import org.alfresco.repo.transaction.TransactionListener; import org.alfresco.repo.transaction.TransactionListenerAdapter; import org.alfresco.repo.transaction.TransactionalResourceHelper; import org.alfresco.service.cmr.dictionary.AspectDefinition; @@ -276,18 +275,20 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl properties = Collections.emptyMap(); } - // check the parent node has not been deleted in this txn - if(isDeletedNodeRef(parentRef)) - { - throw new InvalidNodeRefException("The parent node has been deleted", parentRef); - } - // get/generate an ID for the node String newUuid = generateGuid(properties); // Remove any system properties extractIntrinsicProperties(properties); + /** + * Check the parent node has not been deleted in this txn. + */ + if(isDeletedNodeRef(parentRef)) + { + throw new InvalidNodeRefException("The parent node has been deleted", parentRef); + } + // Invoke policy behaviour invokeBeforeCreateNode(parentRef, assocTypeQName, assocQName, nodeTypeQName); @@ -348,6 +349,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl * now and commit! */ trackNewNodeRef(childAssocRef.getChildRef()); + untrackDeletedNodeRef(childAssocRef.getChildRef()); // Index nodeIndexer.indexCreateNode(childAssocRef); @@ -393,6 +395,22 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl deletedNodes.add(deletedNodeRef); } + /** + * Untrack a deleted node ref + * + * Used when a deleted node is restored. + * + * @param deletedNodeRef + */ + private void untrackDeletedNodeRef(NodeRef deletedNodeRef) + { + Set deletedNodes = TransactionalResourceHelper.getSet(KEY_DELETED_NODES); + if (deletedNodes.size() > 0) + { + deletedNodes.remove(deletedNodeRef); + } + } + private boolean isDeletedNodeRef(NodeRef deletedNodeRef) { Set deletedNodes = TransactionalResourceHelper.getSet(KEY_DELETED_NODES); @@ -654,8 +672,8 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl // Set the type nodeDaoService.updateNode(nodePair.getFirst(), null, null, typeQName); - // Add the default aspects to the node (update the properties with any new default values) - addDefaultAspects(nodePair, typeQName); + // Add the default aspects and properties required for the given type. Existing values will not be overridden. + addDefaults(nodePair, typeQName); // Index nodeIndexer.indexUpdateNode(nodeRef); @@ -936,7 +954,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl } else { - /** + /* * Go ahead and archive the node * * Archiving will take responsibility for firing the policy behaviours on @@ -1007,7 +1025,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl nodeDaoService.deleteNode(childNodeId); invokeOnDeleteNode(childParentAssocRef, childNodeType, childNodeQNames, false); - // loose interest in tracking this node ref + // lose interest in tracking this node ref untrackNewNodeRef(childNodeRef); } } diff --git a/source/java/org/alfresco/repo/rule/ruletrigger/CreateNodeRuleTrigger.java b/source/java/org/alfresco/repo/rule/ruletrigger/CreateNodeRuleTrigger.java index 8288071442..8d56362828 100644 --- a/source/java/org/alfresco/repo/rule/ruletrigger/CreateNodeRuleTrigger.java +++ b/source/java/org/alfresco/repo/rule/ruletrigger/CreateNodeRuleTrigger.java @@ -32,6 +32,7 @@ import org.alfresco.service.cmr.dictionary.DataTypeDefinition; import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.dictionary.PropertyDefinition; import org.alfresco.service.cmr.repository.ChildAssociationRef; +import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.QName; import org.apache.commons.logging.Log; @@ -104,16 +105,30 @@ public class CreateNodeRuleTrigger extends RuleTriggerAbstractBase // Only fire the rule if the node is question has no potential to contain content // TODO we need to find a better way to do this .. how can this be resolved in CIFS?? boolean triggerRule = false; - QName type = this.nodeService.getType(childAssocRef.getChildRef()); - ClassDefinition classDefinition = this.dictionaryService.getClass(type); - if (classDefinition != null) + + NodeRef nodeRef = childAssocRef.getChildRef(); + + // This is a "tempory" fix to identify object created via a web client and trigger the rule immediately + Boolean value = (Boolean)nodeService.getProperty(nodeRef, QName.createQName(NamespaceService.APP_MODEL_1_0_URI, "editInline")); + boolean editInline = false; + if (value != null) { - for (PropertyDefinition propertyDefinition : classDefinition.getProperties().values()) + editInline = value.booleanValue(); + } + + if (editInline == false) + { + QName type = this.nodeService.getType(nodeRef); + ClassDefinition classDefinition = this.dictionaryService.getClass(type); + if (classDefinition != null) { - if (propertyDefinition.getDataType().getName().equals(DataTypeDefinition.CONTENT) == true) + for (PropertyDefinition propertyDefinition : classDefinition.getProperties().values()) { - triggerRule = true; - break; + if (propertyDefinition.getDataType().getName().equals(DataTypeDefinition.CONTENT) == true) + { + triggerRule = true; + break; + } } } } @@ -132,7 +147,7 @@ public class CreateNodeRuleTrigger extends RuleTriggerAbstractBase triggerRules(childAssocRef.getParentRef(), childAssocRef.getChildRef()); } - // Reguadless of whether the rule is triggered, mark this transaction as having created this node + // Regardless of whether the rule is triggered, mark this transaction as having created this node AlfrescoTransactionSupport.bindResource(childAssocRef.getChildRef().toString(), childAssocRef.getChildRef().toString()); } } diff --git a/source/java/org/alfresco/repo/search/impl/lucene/AbstractLuceneIndexerAndSearcherFactory.java b/source/java/org/alfresco/repo/search/impl/lucene/AbstractLuceneIndexerAndSearcherFactory.java index 73e0205943..2dd9336fc5 100644 --- a/source/java/org/alfresco/repo/search/impl/lucene/AbstractLuceneIndexerAndSearcherFactory.java +++ b/source/java/org/alfresco/repo/search/impl/lucene/AbstractLuceneIndexerAndSearcherFactory.java @@ -87,15 +87,14 @@ import org.springframework.transaction.support.TransactionSynchronizationManager * @author andyh */ -public abstract class AbstractLuceneIndexerAndSearcherFactory implements LuceneIndexerAndSearcher, XAResource, - ApplicationContextAware +public abstract class AbstractLuceneIndexerAndSearcherFactory implements LuceneIndexerAndSearcher, XAResource, ApplicationContextAware { private static Log logger = LogFactory.getLog(AbstractLuceneIndexerAndSearcherFactory.class); private int queryMaxClauses; private int indexerBatchSize; - + protected Map queryLanguages = new HashMap(); /** @@ -155,6 +154,12 @@ public abstract class AbstractLuceneIndexerAndSearcherFactory implements LuceneI private int maxDocsForInMemoryMerge = 10000; + private int maxDocsForInMemoryIndex = 10000; + + private double maxRamInMbForInMemoryMerge = 16.0; + + private double maxRamInMbForInMemoryIndex = 16.0; + private int maxDocumentCacheSize = 100; private int maxIsCategoryCacheSize = -1; @@ -172,8 +177,10 @@ public abstract class AbstractLuceneIndexerAndSearcherFactory implements LuceneI private int mergerMergeFactor = 5; private int mergerMergeBlockingFactor = 1; - - private int mergerMinMergeDocs = 1000; + + private int mergerMaxBufferedDocs = IndexWriter.DISABLE_AUTO_FLUSH; + + private double mergerRamBufferSizeMb = 16.0; private int mergerTargetIndexCount = 5; @@ -181,7 +188,7 @@ public abstract class AbstractLuceneIndexerAndSearcherFactory implements LuceneI private int mergerTargetOverlaysBlockingFactor = 1; - private int termIndexInterval =IndexWriter.DEFAULT_TERM_INDEX_INTERVAL; + private int termIndexInterval = IndexWriter.DEFAULT_TERM_INDEX_INTERVAL; private boolean useNioMemoryMapping = true; @@ -189,7 +196,9 @@ public abstract class AbstractLuceneIndexerAndSearcherFactory implements LuceneI private int writerMergeFactor = 5; - private int writerMinMergeDocs = 1000; + private int writerMaxBufferedDocs = IndexWriter.DISABLE_AUTO_FLUSH; + + private double writerRamBufferSizeMb = 16.0; private boolean cacheEnabled = true; @@ -206,7 +215,6 @@ public abstract class AbstractLuceneIndexerAndSearcherFactory implements LuceneI super(); } - /* * (non-Javadoc) * @seeorg.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context. @@ -219,6 +227,7 @@ public abstract class AbstractLuceneIndexerAndSearcherFactory implements LuceneI /* * (non-Javadoc) + * * @see org.alfresco.repo.search.impl.lucene.LuceneConfig#getApplicationContext() */ public ConfigurableApplicationContext getApplicationContext() @@ -404,7 +413,7 @@ public abstract class AbstractLuceneIndexerAndSearcherFactory implements LuceneI if (indexers == null) { indexers = new HashMap(); - AlfrescoTransactionSupport.bindResource(indexersKey, indexers); + AlfrescoTransactionSupport.bindResource(indexersKey, indexers); } LuceneIndexer indexer = indexers.get(storeRef); if (indexer == null) @@ -431,8 +440,7 @@ public abstract class AbstractLuceneIndexerAndSearcherFactory implements LuceneI } else if (TransactionSynchronizationManager.isSynchronizationActive()) { - Map indexers = (Map) AlfrescoTransactionSupport - .getResource(indexersKey); + Map indexers = (Map) AlfrescoTransactionSupport.getResource(indexersKey); if (indexers != null) { LuceneIndexer indexer = indexers.get(storeRef); @@ -474,7 +482,7 @@ public abstract class AbstractLuceneIndexerAndSearcherFactory implements LuceneI LuceneSearcher searcher = getSearcher(storeRef, indexer); return searcher; } - + /** * Get node-based searcher (for "selectNodes / selectProperties") */ @@ -776,7 +784,7 @@ public abstract class AbstractLuceneIndexerAndSearcherFactory implements LuceneI if (indexers != null) { indexers.clear(); - AlfrescoTransactionSupport.unbindResource(indexersKey); + AlfrescoTransactionSupport.unbindResource(indexersKey); } } } @@ -1031,7 +1039,7 @@ public abstract class AbstractLuceneIndexerAndSearcherFactory implements LuceneI * * @author Derek Hulley */ - public static class LuceneIndexBackupComponent /*implements InitializingBean*/ + public static class LuceneIndexBackupComponent /* implements InitializingBean */ { ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock(); @@ -1590,7 +1598,6 @@ public abstract class AbstractLuceneIndexerAndSearcherFactory implements LuceneI defaultMLSearchAnalysisMode = mode; } - public int getMaxDocIdCacheSize() { return maxDocIdCacheSize; @@ -1690,7 +1697,7 @@ public abstract class AbstractLuceneIndexerAndSearcherFactory implements LuceneI { this.mergerMergeFactor = mergerMergeFactor; } - + public int getMergerMergeBlockingFactor() { return mergerMergeBlockingFactor; @@ -1701,14 +1708,14 @@ public abstract class AbstractLuceneIndexerAndSearcherFactory implements LuceneI this.mergerMergeBlockingFactor = mergerMergeBlockingFactor; } - public int getMergerMinMergeDocs() + public int getMergerMaxBufferedDocs() { - return mergerMinMergeDocs; + return mergerMaxBufferedDocs; } - public void setMergerMinMergeDocs(int mergerMinMergeDocs) + public void setMergerMaxBufferedDocs(int mergerMaxBufferedDocs) { - this.mergerMinMergeDocs = mergerMinMergeDocs; + this.mergerMaxBufferedDocs = mergerMaxBufferedDocs; } public int getMergerTargetIndexCount() @@ -1730,7 +1737,7 @@ public abstract class AbstractLuceneIndexerAndSearcherFactory implements LuceneI { this.mergerTargetOverlayCount = mergerTargetOverlayCount; } - + public int getMergerTargetOverlaysBlockingFactor() { return mergerTargetOverlaysBlockingFactor; @@ -1781,14 +1788,14 @@ public abstract class AbstractLuceneIndexerAndSearcherFactory implements LuceneI this.writerMergeFactor = writerMergeFactor; } - public int getWriterMinMergeDocs() + public int getWriterMaxBufferedDocs() { - return writerMinMergeDocs; + return writerMaxBufferedDocs; } - public void setWriterMinMergeDocs(int writerMinMergeDocs) + public void setWriterMaxBufferedDocs(int writerMaxBufferedDocs) { - this.writerMinMergeDocs = writerMinMergeDocs; + this.writerMaxBufferedDocs = writerMaxBufferedDocs; } public boolean isCacheEnabled() @@ -1800,29 +1807,112 @@ public abstract class AbstractLuceneIndexerAndSearcherFactory implements LuceneI { this.cacheEnabled = cacheEnabled; } - + public boolean getPostSortDateTime() { - return postSortDateTime; - } - - public void setPostSortDateTime(boolean postSortDateTime) - { - this.postSortDateTime = postSortDateTime; + return postSortDateTime; + } + + public void setPostSortDateTime(boolean postSortDateTime) + { + this.postSortDateTime = postSortDateTime; } - public void registerQueryLanguage(LuceneQueryLanguageSPI queryLanguage) { this.queryLanguages.put(queryLanguage.getName().toLowerCase(), queryLanguage); } - + + /** + * @return the maxDocsForInMemoryIndex + */ + public int getMaxDocsForInMemoryIndex() + { + return maxDocsForInMemoryIndex; + } + + /** + * @param maxDocsForInMemoryIndex + * the maxDocsForInMemoryIndex to set + */ + public void setMaxDocsForInMemoryIndex(int maxDocsForInMemoryIndex) + { + this.maxDocsForInMemoryIndex = maxDocsForInMemoryIndex; + } + + /** + * @return the maxRamInMbForInMemoryMerge + */ + public double getMaxRamInMbForInMemoryMerge() + { + return maxRamInMbForInMemoryMerge; + } + + /** + * @param maxRamInMbForInMemoryMerge + * the maxRamInMbForInMemoryMerge to set + */ + public void setMaxRamInMbForInMemoryMerge(double maxRamInMbForInMemoryMerge) + { + this.maxRamInMbForInMemoryMerge = maxRamInMbForInMemoryMerge; + } + + /** + * @return the maxRamInMbForInMemoryIndex + */ + public double getMaxRamInMbForInMemoryIndex() + { + return maxRamInMbForInMemoryIndex; + } + + /** + * @param maxRamInMbForInMemoryIndex + * the maxRamInMbForInMemoryIndex to set + */ + public void setMaxRamInMbForInMemoryIndex(double maxRamInMbForInMemoryIndex) + { + this.maxRamInMbForInMemoryIndex = maxRamInMbForInMemoryIndex; + } + + /** + * @return the mergerRamBufferSizeMb + */ + public double getMergerRamBufferSizeMb() + { + return mergerRamBufferSizeMb; + } + + /** + * @param mergerRamBufferSizeMb + * the mergerRamBufferSizeMb to set + */ + public void setMergerRamBufferSizeMb(double mergerRamBufferSizeMb) + { + this.mergerRamBufferSizeMb = mergerRamBufferSizeMb; + } + + /** + * @return the writerRamBufferSizeMb + */ + public double getWriterRamBufferSizeMb() + { + return writerRamBufferSizeMb; + } + + /** + * @param writerRamBufferSizeMb + * the writerRamBufferSizeMb to set + */ + public void setWriterRamBufferSizeMb(double writerRamBufferSizeMb) + { + this.writerRamBufferSizeMb = writerRamBufferSizeMb; + } + protected LuceneQueryLanguageSPI getQueryLanguage(String name) { return this.queryLanguages.get(name); } - - + protected abstract List getAllStores(); public R doWithAllWriteLocks(WithAllWriteLocksWork lockWork) diff --git a/source/java/org/alfresco/repo/search/impl/lucene/LuceneConfig.java b/source/java/org/alfresco/repo/search/impl/lucene/LuceneConfig.java index ea887faa0f..031fee310f 100644 --- a/source/java/org/alfresco/repo/search/impl/lucene/LuceneConfig.java +++ b/source/java/org/alfresco/repo/search/impl/lucene/LuceneConfig.java @@ -110,7 +110,7 @@ public interface LuceneConfig * Lucene writer config * @return */ - public int getWriterMinMergeDocs(); + public int getWriterMaxBufferedDocs(); /** * Lucene writer config @@ -128,7 +128,7 @@ public interface LuceneConfig * Lucene merger config * @return */ - public int getMergerMinMergeDocs(); + public int getMergerMaxBufferedDocs(); /** * Lucene merger config @@ -244,4 +244,34 @@ public interface LuceneConfig */ public ConfigurableApplicationContext getApplicationContext(); + /** + * Ram based limit for in memory merges + * @return + */ + public double getMaxRamInMbForInMemoryMerge(); + + /** + * Ram based limit for in memory portion of writer index. + * @return + */ + public double getWriterRamBufferSizeMb(); + + /** + * Ram based limit for in memory portion of merger index. + * @return + */ + public double getMergerRamBufferSizeMb(); + + /** + * Max docs to allow for in memory indexes (does no apply to merges) + * @return + */ + public int getMaxDocsForInMemoryIndex(); + + /** + * Max Ram to allow for in memory indexes (does not apply to merges) + * @return + */ + public double getMaxRamInMbForInMemoryIndex(); + } diff --git a/source/java/org/alfresco/repo/search/impl/lucene/index/IndexInfo.java b/source/java/org/alfresco/repo/search/impl/lucene/index/IndexInfo.java index d940967a3c..67a05bf09b 100644 --- a/source/java/org/alfresco/repo/search/impl/lucene/index/IndexInfo.java +++ b/source/java/org/alfresco/repo/search/impl/lucene/index/IndexInfo.java @@ -74,6 +74,7 @@ import org.alfresco.service.namespace.NamespaceService; import org.alfresco.util.ApplicationContextHelper; import org.alfresco.util.GUID; import org.alfresco.util.TraceableThreadFactory; +import org.apache.commons.io.FileUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.lucene.analysis.Analyzer; @@ -99,6 +100,7 @@ import org.apache.lucene.store.FSDirectory; import org.apache.lucene.store.IndexInput; import org.apache.lucene.store.IndexOutput; import org.apache.lucene.store.RAMDirectory; +import org.apache.xml.dtm.ref.sax2dtm.SAX2DTM2.FollowingSiblingIterator; import org.safehaus.uuid.UUID; import org.saxpath.SAXPathException; import org.springframework.context.ApplicationContext; @@ -229,7 +231,7 @@ public class IndexInfo implements IndexMonitor * Lock for the index entries */ private ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock(); - + /** * Read only index readers that also do reference counting. */ @@ -295,14 +297,22 @@ public class IndexInfo implements IndexMonitor */ private static HashMap indexInfos = new HashMap(); - // Properties that cotrol lucene indexing + // Properties that control lucene indexing // -------------------------------------- // Properties for indexes that are created by transactions ... private int maxDocsForInMemoryMerge = 10000; + + private int maxDocsForInMemoryIndex = 10000; - private int writerMinMergeDocs = 1000; + private double maxRamInMbForInMemoryMerge = 16.0; + + private double maxRamInMbForInMemoryIndex = 16.0; + + private int writerMaxBufferedDocs = IndexWriter.DISABLE_AUTO_FLUSH; + + private double writerRamBufferSizeMb = 16.0; private int writerMergeFactor = 5; @@ -312,7 +322,9 @@ public class IndexInfo implements IndexMonitor // Properties for indexes created by merging - private int mergerMinMergeDocs = 1000; + private int mergerMaxBufferedDocs = IndexWriter.DISABLE_AUTO_FLUSH; + + private double mergerRamBufferSizeMb = 16.0; private int mergerMergeFactor = 5; @@ -404,10 +416,15 @@ public class IndexInfo implements IndexMonitor this.threadPoolExecutor = config.getThreadPoolExecutor(); IndexInfo.useNIOMemoryMapping = config.getUseNioMemoryMapping(); this.maxDocsForInMemoryMerge = config.getMaxDocsForInMemoryMerge(); - this.writerMinMergeDocs = config.getWriterMinMergeDocs(); + this.maxRamInMbForInMemoryMerge = config.getMaxRamInMbForInMemoryMerge(); + this.maxDocsForInMemoryIndex = config.getMaxDocsForInMemoryIndex(); + this.maxRamInMbForInMemoryIndex = config.getMaxRamInMbForInMemoryIndex(); + this.writerMaxBufferedDocs = config.getWriterMaxBufferedDocs(); + this.writerRamBufferSizeMb = config.getWriterRamBufferSizeMb(); this.writerMergeFactor = config.getWriterMergeFactor(); this.writerMaxMergeDocs = config.getWriterMaxMergeDocs(); - this.mergerMinMergeDocs = config.getMergerMinMergeDocs(); + this.mergerMaxBufferedDocs = config.getMergerMaxBufferedDocs(); + this.mergerRamBufferSizeMb = config.getMergerRamBufferSizeMb(); this.mergerMergeFactor = config.getMergerMergeFactor(); this.mergerMergeBlockingFactor = config.getMergerMergeBlockingFactor(); this.mergerMaxMergeDocs = config.getMergerMaxMergeDocs(); @@ -464,7 +481,8 @@ public class IndexInfo implements IndexMonitor { writer = new IndexWriter(emptyIndex, new AlfrescoStandardAnalyser(), true, MaxFieldLength.LIMITED); writer.setUseCompoundFile(writerUseCompoundFile); - writer.setMaxBufferedDocs(writerMinMergeDocs); + writer.setMaxBufferedDocs(writerMaxBufferedDocs); + writer.setRAMBufferSizeMB(writerRamBufferSizeMb); writer.setMergeFactor(writerMergeFactor); writer.setMaxMergeDocs(writerMaxMergeDocs); writer.setWriteLockTimeout(writeLockTimeout); @@ -531,7 +549,8 @@ public class IndexInfo implements IndexMonitor { writer = new IndexWriter(oldIndex, new AlfrescoStandardAnalyser(), false, MaxFieldLength.LIMITED); writer.setUseCompoundFile(writerUseCompoundFile); - writer.setMaxBufferedDocs(writerMinMergeDocs); + writer.setMaxBufferedDocs(writerMaxBufferedDocs); + writer.setRAMBufferSizeMB(writerRamBufferSizeMb); writer.setMergeFactor(writerMergeFactor); writer.setMaxMergeDocs(writerMaxMergeDocs); writer.setWriteLockTimeout(writeLockTimeout); @@ -821,7 +840,7 @@ public class IndexInfo implements IndexMonitor { indexEntries.put(id, new IndexEntry(IndexType.DELTA, id, "", TransactionStatus.ACTIVE, "", 0, 0, false)); } - + } finally { // Downgrade lock @@ -858,7 +877,8 @@ public class IndexInfo implements IndexMonitor writer = new IndexWriter(location, analyzer, false, MaxFieldLength.LIMITED); } writer.setUseCompoundFile(writerUseCompoundFile); - writer.setMaxBufferedDocs(writerMinMergeDocs); + writer.setMaxBufferedDocs(writerMaxBufferedDocs); + writer.setRAMBufferSizeMB(writerRamBufferSizeMb); writer.setMergeFactor(writerMergeFactor); writer.setMaxMergeDocs(writerMaxMergeDocs); writer.setWriteLockTimeout(writeLockTimeout); @@ -1081,7 +1101,7 @@ public class IndexInfo implements IndexMonitor getWriteLock(); try { - mainIndexReader = null; + mainIndexReader = null; } finally { @@ -1116,7 +1136,7 @@ public class IndexInfo implements IndexMonitor mainIndexReader = createMainIndexReader(); } - + } finally { @@ -1128,17 +1148,18 @@ public class IndexInfo implements IndexMonitor mainIndexReader.incRef(); if (s_logger.isDebugEnabled()) { - s_logger.debug("Main index reader references = " + ((ReferenceCounting)mainIndexReader).getReferenceCount()); + s_logger.debug("Main index reader references = " + ((ReferenceCounting) mainIndexReader).getReferenceCount()); } - + // Prevent close calls from really closing the main reader - return new FilterIndexReader(mainIndexReader) { - + return new FilterIndexReader(mainIndexReader) + { + @Override protected void doClose() throws IOException { in.decRef(); - } + } }; } @@ -1239,11 +1260,12 @@ public class IndexInfo implements IndexMonitor filterReader.decRef(); } - // The reference count would have been incremented automatically by MultiReader / FilterIndexReaderByStringId + // The reference count would have been incremented automatically by MultiReader / + // FilterIndexReaderByStringId deltaReader.decRef(); if (s_logger.isDebugEnabled()) { - s_logger.debug("Main index reader references = " + ((ReferenceCounting)mainIndexReader).getReferenceCount()); + s_logger.debug("Main index reader references = " + ((ReferenceCounting) mainIndexReader).getReferenceCount()); } reader = ReferenceCountingReadOnlyIndexReaderFactory.createReader(MAIN_READER + id, reader, false, config); ReferenceCounting refCounting = (ReferenceCounting) reader; @@ -1298,8 +1320,7 @@ public class IndexInfo implements IndexMonitor } getReadLock(); } - - + releaseReadLock(); getWriteLock(); try @@ -1992,13 +2013,53 @@ public class IndexInfo implements IndexMonitor referenceCountingReadOnlyIndexReaders.put(id, reader); } + private double getSizeInMb(File file) + { + long size = getSize(file); + return size/1024.0d/1024.0d; + } + + private long getSize(File file) + { + long size = 0l; + if (file == null) + { + return size; + } + if (file.isFile()) + { + return file.length(); + } + else + { + File[] files = file.listFiles(); + if(files == null) + { + return size; + } + for (File current : files) + { + if (current.isDirectory()) + { + size += getSize(current); + } + else + { + size += current.length(); + } + } + } + return size; + } + private IndexReader buildReferenceCountingIndexReader(String id, long size) throws IOException { IndexReader reader; File location = new File(indexDirectory, id).getCanonicalFile(); + double folderSize = getSizeInMb(location); if (IndexReader.indexExists(location)) { - if ((config != null) && (size < config.getMaxDocsForInMemoryMerge())) + if ((size < maxDocsForInMemoryIndex) && (folderSize < maxRamInMbForInMemoryIndex)) { RAMDirectory rd = new RAMDirectory(location); reader = IndexReader.open(rd); @@ -2947,9 +3008,9 @@ public class IndexInfo implements IndexMonitor private abstract class AbstractSchedulable implements Schedulable, Runnable { ScheduledState scheduledState = ScheduledState.UN_SCHEDULED; - + private int scheduledCount; - + public synchronized int getScheduledCount() { return scheduledCount; @@ -3767,6 +3828,7 @@ public class IndexInfo implements IndexMonitor IndexWriter writer = null; File outputLocation = null; + double mergeSize = 0; for (IndexEntry entry : toMerge.values()) { File location = new File(indexDirectory, entry.getName()).getCanonicalFile(); @@ -3784,12 +3846,13 @@ public class IndexInfo implements IndexMonitor } readers[count++] = reader; docCount += entry.getDocumentCount(); + mergeSize += getSizeInMb(location); } else if (entry.getStatus() == TransactionStatus.MERGE_TARGET) { mergeTargetId = entry.getName(); outputLocation = location; - if (docCount < maxDocsForInMemoryMerge) + if ((docCount < maxDocsForInMemoryMerge) && (mergeSize < maxRamInMbForInMemoryMerge)) { ramDirectory = new RAMDirectory(); writer = new IndexWriter(ramDirectory, new AlfrescoStandardAnalyser(), true, MaxFieldLength.UNLIMITED); @@ -3800,7 +3863,8 @@ public class IndexInfo implements IndexMonitor } writer.setUseCompoundFile(mergerUseCompoundFile); - writer.setMaxBufferedDocs(mergerMinMergeDocs); + writer.setMaxBufferedDocs(mergerMaxBufferedDocs); + writer.setRAMBufferSizeMB(mergerRamBufferSizeMb); writer.setMergeFactor(mergerMergeFactor); writer.setMaxMergeDocs(mergerMaxMergeDocs); writer.setWriteLockTimeout(writeLockTimeout); diff --git a/source/java/org/alfresco/repo/security/person/PersonServiceImpl.java b/source/java/org/alfresco/repo/security/person/PersonServiceImpl.java index 001ac8d5f3..8de6eafd79 100644 --- a/source/java/org/alfresco/repo/security/person/PersonServiceImpl.java +++ b/source/java/org/alfresco/repo/security/person/PersonServiceImpl.java @@ -31,19 +31,19 @@ import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.HashSet; -import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; -import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.model.ContentModel; import org.alfresco.repo.cache.SimpleCache; -import org.alfresco.repo.domain.hibernate.DirtySessionMethodInterceptor; import org.alfresco.repo.node.NodeServicePolicies; +import org.alfresco.repo.node.NodeServicePolicies.BeforeDeleteNodePolicy; +import org.alfresco.repo.node.NodeServicePolicies.OnCreateNodePolicy; +import org.alfresco.repo.node.NodeServicePolicies.OnUpdatePropertiesPolicy; import org.alfresco.repo.policy.JavaBehaviour; import org.alfresco.repo.policy.PolicyComponent; import org.alfresco.repo.security.authentication.AuthenticationException; @@ -141,7 +141,7 @@ public class PersonServiceImpl extends TransactionListenerAdapter implements Per private PermissionsManager permissionsManager; /** a transactionally-safe cache to be injected */ - private SimpleCache> personCache; + private SimpleCache> personCache; /** People Container ref cache (Tennant aware) */ private Map peopleContainerRefs = new ConcurrentHashMap(4); @@ -190,12 +190,18 @@ public class PersonServiceImpl extends TransactionListenerAdapter implements Per PropertyCheck.mandatory(this, "aclDao", aclDao); PropertyCheck.mandatory(this, "homeFolderManager", homeFolderManager); - this.policyComponent - .bindClassBehaviour(QName.createQName(NamespaceService.ALFRESCO_URI, "onCreateNode"), ContentModel.TYPE_PERSON, new JavaBehaviour(this, "onCreateNode")); - this.policyComponent.bindClassBehaviour(QName.createQName(NamespaceService.ALFRESCO_URI, "beforeDeleteNode"), ContentModel.TYPE_PERSON, new JavaBehaviour(this, - "beforeDeleteNode")); - this.policyComponent.bindClassBehaviour(QName.createQName(NamespaceService.ALFRESCO_URI, "onUpdateProperties"), ContentModel.TYPE_PERSON, new JavaBehaviour(this, - "onUpdateProperties")); + this.policyComponent.bindClassBehaviour( + OnCreateNodePolicy.QNAME, + ContentModel.TYPE_PERSON, + new JavaBehaviour(this, "onCreateNode")); + this.policyComponent.bindClassBehaviour( + BeforeDeleteNodePolicy.QNAME, + ContentModel.TYPE_PERSON, + new JavaBehaviour(this, "beforeDeleteNode")); + this.policyComponent.bindClassBehaviour( + OnUpdatePropertiesPolicy.QNAME, + ContentModel.TYPE_PERSON, + new JavaBehaviour(this, "onUpdateProperties")); } public UserNameMatcher getUserNameMatcher() @@ -254,7 +260,7 @@ public class PersonServiceImpl extends TransactionListenerAdapter implements Per * @param personCache * a transactionally safe cache */ - public void setPersonCache(SimpleCache> personCache) + public void setPersonCache(SimpleCache> personCache) { this.personCache = personCache; } @@ -346,30 +352,32 @@ public class PersonServiceImpl extends TransactionListenerAdapter implements Per private NodeRef getPersonOrNull(String searchUserName) { String cacheKey = searchUserName.toLowerCase(); - Map allRefs = this.personCache.get(cacheKey); + Set allRefs = this.personCache.get(cacheKey); if (allRefs == null) { - List childRefs = nodeService.getChildAssocs(getPeopleContainer(), - ContentModel.ASSOC_CHILDREN, QName.createQName("cm", searchUserName.toLowerCase(), - namespacePrefixResolver), false); - allRefs = new LinkedHashMap(childRefs.size() * 2); + List childRefs = nodeService.getChildAssocs( + getPeopleContainer(), + ContentModel.ASSOC_CHILDREN, + QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, searchUserName.toLowerCase()), + false); + allRefs = new LinkedHashSet(childRefs.size() * 2); // add to cache personCache.put(cacheKey, allRefs); for (ChildAssociationRef childRef : childRefs) { NodeRef nodeRef = childRef.getChildRef(); - Serializable value = nodeService.getProperty(nodeRef, ContentModel.PROP_USERNAME); - String realUserName = DefaultTypeConverter.INSTANCE.convert(String.class, value); - allRefs.put(realUserName, nodeRef); + allRefs.add(nodeRef); } } List refs = new ArrayList(allRefs.size()); - for (Entry entry : allRefs.entrySet()) + for (NodeRef nodeRef : allRefs) { - if (userNameMatcher.matches(searchUserName, entry.getKey())) + Serializable value = nodeService.getProperty(nodeRef, ContentModel.PROP_USERNAME); + String realUserName = DefaultTypeConverter.INSTANCE.convert(String.class, value); + if (userNameMatcher.matches(searchUserName, realUserName)) { - refs.add(entry.getValue()); + refs.add(nodeRef); } } NodeRef returnRef = null; @@ -836,10 +844,8 @@ public class PersonServiceImpl extends TransactionListenerAdapter implements Per // Policies - /* - * (non-Javadoc) - * - * @see org.alfresco.repo.node.NodeServicePolicies.OnCreateNodePolicy#onCreateNode(org.alfresco.service.cmr.repository.ChildAssociationRef) + /** + * {@inheritDoc} */ public void onCreateNode(ChildAssociationRef childAssocRef) { @@ -854,10 +860,8 @@ public class PersonServiceImpl extends TransactionListenerAdapter implements Per homeFolderManager.onCreateNode(childAssocRef); } - /* - * (non-Javadoc) - * - * @see org.alfresco.repo.node.NodeServicePolicies.BeforeDeleteNodePolicy#beforeDeleteNode(org.alfresco.service.cmr.repository.NodeRef) + /** + * {@inheritDoc} */ public void beforeDeleteNode(NodeRef nodeRef) { diff --git a/source/java/org/alfresco/repo/security/person/PersonTest.java b/source/java/org/alfresco/repo/security/person/PersonTest.java index 40995383ed..9542338125 100644 --- a/source/java/org/alfresco/repo/security/person/PersonTest.java +++ b/source/java/org/alfresco/repo/security/person/PersonTest.java @@ -477,7 +477,6 @@ public class PersonTest extends BaseSpringTest private void testProperties(NodeRef nodeRef, String userName, String firstName, String lastName, String email, String orgId) { - Map props = nodeService.getProperties(nodeRef); assertEquals(userName, DefaultTypeConverter.INSTANCE.convert(String.class, nodeService.getProperty(nodeRef, ContentModel.PROP_USERNAME))); assertNotNull(nodeService.getProperty(nodeRef, ContentModel.PROP_HOMEFOLDER)); assertEquals(firstName, DefaultTypeConverter.INSTANCE.convert(String.class, nodeService.getProperty(nodeRef, ContentModel.PROP_FIRSTNAME))); @@ -597,8 +596,23 @@ public class PersonTest extends BaseSpringTest transactionService.getRetryingTransactionHelper().doInTransaction(deletePersonWork, false, true); } + + public void testSplitPersonCleanupManyTimes() throws Throwable + { + for (int i = 0; i < 100; i++) // Bump this number up to 1000 for 'real' testing + { + try + { + forceSplitPersonCleanup(); + } + catch (Throwable e) + { + throw new RuntimeException("Failed on iteration " + i + " of forcing split person.", e); + } + } + } - public void testSplitPersonCleanup() throws Exception + private void forceSplitPersonCleanup() throws Exception { // Kill the annoying Spring-managed txn super.setComplete();