From f4f0f51a7d25a2015242886c39e93ee6ade38b46 Mon Sep 17 00:00:00 2001 From: Derek Hulley Date: Tue, 11 Sep 2007 03:39:41 +0000 Subject: [PATCH] Merged V2.1 to HEAD 6609: Portlet UI (doclist, myspaces, mytasks) updates following design review 6610: AR-1270 6611: debugging WCM-778. 6612: Improved API documentation. 6613: Added store lookup cache to EHCache config for default and extended cluster sample 6614: AWC-1531 and AWC-1146. Link objects that have targets which the user does not have access to are now filtered from the view. 6615: AR-1664: Bootstraping from full export fails if file names differs only with a space: my file, my file 6616: Fixed AR-1519: Possible duplicate entries when moving nodes between stores 6617: Removed deprecated aspects; Added emailed aspect to messages; Added OOo command line options 6618: Fix for AWC-1350 6619: Fix for AWC-1509 6620: AWC-1179: Searching for users in Invite User Wizard is slow with large number of users 6621: Changed shutdown logic to avoid classloader cleanup race. 6622: Fix for AWC-1533 (can't save office docs to Company Home) 6623: Fix for AR-1705 6624: Better fix for AWC-1256 (links generated by tinyMCE editor) 6625: Fixed AR-1713: Transformers that do nothing don't break full text indexing 6626: Fixed AWC-1438: Added explcit TXT to PDF converter that wraps the PDFBox TextToPDF class 6627: Portlet templates now handle missing description property on web form 6628: Fix WCM-788 6635: Make workflow available for users who cannot see company home Resolved conflicted state of 'root\projects\repository\source\java\org\alfresco\repo\workflow\jbpm\JBPMEngine.java' git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@6748 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- config/alfresco/cache-context.xml | 4 +- config/alfresco/content-services-context.xml | 13 + config/alfresco/ehcache-default.xml | 8 +- .../ehcache-custom.xml.sample.cluster | 17 +- .../messages/content-model.properties | 13 + config/alfresco/node-services-context.xml | 2 +- config/alfresco/workflow-context.xml | 1 + .../filesys/smb/server/NTProtocolHandler.java | 4 + .../repo/avm/AVMLockingAwareService.java | 4 + .../repo/content/ContentTestSuite.java | 2 + .../transform/MailContentTransformer.java | 12 +- .../repo/exporter/ViewXMLExporter.java | 7 +- .../org/alfresco/repo/jscript/ScriptNode.java | 17 +- .../node/archive/ArchiveAndRestoreTest.java | 52 +- .../repo/node/db/DbNodeServiceImpl.java | 13 + .../node/index/AVMRemoteSnapshotTracker.java | 28 +- .../impl/lucene/ADMLuceneIndexerImpl.java | 13 +- .../repo/template/BaseSearchResultsMap.java | 5 +- .../repo/workflow/jbpm/JBPMEngine.java | 15 +- .../alfresco/service/cmr/avm/AVMService.java | 886 ++++++++-------- .../service/cmr/remote/AVMRemote.java | 947 +++++++++++++----- 21 files changed, 1362 insertions(+), 701 deletions(-) diff --git a/config/alfresco/cache-context.xml b/config/alfresco/cache-context.xml index 5cca3d25be..d08050e537 100644 --- a/config/alfresco/cache-context.xml +++ b/config/alfresco/cache-context.xml @@ -277,7 +277,7 @@ org.alfresco.repo.avm.lookupTransactionalCache - 50 + 100 @@ -313,7 +313,7 @@ org.alfresco.repo.avm.storeLookupTransactionalCache - 100 + 200 diff --git a/config/alfresco/content-services-context.xml b/config/alfresco/content-services-context.xml index 127cda5071..67e725495a 100644 --- a/config/alfresco/content-services-context.xml +++ b/config/alfresco/content-services-context.xml @@ -190,6 +190,19 @@ + + + + + text/plain + application/pdf + + + + + diff --git a/config/alfresco/ehcache-default.xml b/config/alfresco/ehcache-default.xml index 7718efcfd2..63d829114e 100644 --- a/config/alfresco/ehcache-default.xml +++ b/config/alfresco/ehcache-default.xml @@ -258,7 +258,13 @@ + diff --git a/config/alfresco/extension/ehcache-custom.xml.sample.cluster b/config/alfresco/extension/ehcache-custom.xml.sample.cluster index 6ca32332f7..1bc67dcd83 100644 --- a/config/alfresco/extension/ehcache-custom.xml.sample.cluster +++ b/config/alfresco/extension/ehcache-custom.xml.sample.cluster @@ -376,7 +376,22 @@ + + + + + diff --git a/config/alfresco/messages/content-model.properties b/config/alfresco/messages/content-model.properties index dbf9b83510..320109c5f6 100644 --- a/config/alfresco/messages/content-model.properties +++ b/config/alfresco/messages/content-model.properties @@ -215,3 +215,16 @@ cm_contentmodel.property.cm_categories.description=Categories cm_contentmodel.aspect.cm_attachable.title=Attachable cm_contentmodel.aspect.cm_attachable.description=Allows other repository objects to be attached +cm_contentmodel.aspect.cm_emailed.title=Emailed +cm_contentmodel.aspect.cm_emailed.description=Emailed +cm_contentmodel.property.cm_originator.title=Originator +cm_contentmodel.property.cm_originator.description=Originator +cm_contentmodel.property.cm_addressee.title=Addressee +cm_contentmodel.property.cm_addressee.description=Addressee +cm_contentmodel.property.cm_addressees.title=Addressees +cm_contentmodel.property.cm_addressees.description=Addressees +cm_contentmodel.property.cm_subjectline.title=Subject +cm_contentmodel.property.cm_subjectline.description=Subject +cm_contentmodel.property.cm_sentdate.title=Sent Date +cm_contentmodel.property.cm_sentdate.description=Sent Date + diff --git a/config/alfresco/node-services-context.xml b/config/alfresco/node-services-context.xml index fccc3b0805..bd65e0bac5 100644 --- a/config/alfresco/node-services-context.xml +++ b/config/alfresco/node-services-context.xml @@ -36,7 +36,7 @@ - nodeRefPropertyInterceptor + nodeRefPropertyInterceptor mlPropertyInterceptor diff --git a/config/alfresco/workflow-context.xml b/config/alfresco/workflow-context.xml index d9bc0de942..fc68deb781 100644 --- a/config/alfresco/workflow-context.xml +++ b/config/alfresco/workflow-context.xml @@ -100,6 +100,7 @@ ${spaces.store} /${spaces.company_home.childname} + diff --git a/source/java/org/alfresco/filesys/smb/server/NTProtocolHandler.java b/source/java/org/alfresco/filesys/smb/server/NTProtocolHandler.java index ed2c98c236..a8668a640a 100644 --- a/source/java/org/alfresco/filesys/smb/server/NTProtocolHandler.java +++ b/source/java/org/alfresco/filesys/smb/server/NTProtocolHandler.java @@ -4354,6 +4354,10 @@ public class NTProtocolHandler extends CoreProtocolHandler return; } + // Get the current file size from the open file + + fileInfo.setFileSize( netFile.getFileSize()); + // Pack the file information into the return data packet dataLen = QueryInfoPacker.packInfo(fileInfo, replyBuf, infoLevl, true); diff --git a/source/java/org/alfresco/repo/avm/AVMLockingAwareService.java b/source/java/org/alfresco/repo/avm/AVMLockingAwareService.java index 2856f6318d..615830089a 100644 --- a/source/java/org/alfresco/repo/avm/AVMLockingAwareService.java +++ b/source/java/org/alfresco/repo/avm/AVMLockingAwareService.java @@ -676,6 +676,8 @@ public class AVMLockingAwareService implements AVMService, ApplicationContextAwa { grabLock(parent + '/' + name); fService.removeNode(parent, name); + String[] storePath = parent.split(":"); + fService.createSnapshot(storePath[0], null, null); } /* (non-Javadoc) @@ -685,6 +687,8 @@ public class AVMLockingAwareService implements AVMService, ApplicationContextAwa { grabLock(path); fService.removeNode(path); + String[] storePath = path.split(":"); + fService.createSnapshot(storePath[0], null, null); } /* (non-Javadoc) diff --git a/source/java/org/alfresco/repo/content/ContentTestSuite.java b/source/java/org/alfresco/repo/content/ContentTestSuite.java index acb22bd42d..21f6565e39 100644 --- a/source/java/org/alfresco/repo/content/ContentTestSuite.java +++ b/source/java/org/alfresco/repo/content/ContentTestSuite.java @@ -48,6 +48,7 @@ import org.alfresco.repo.content.transform.PoiHssfContentTransformerTest; import org.alfresco.repo.content.transform.RuntimeExecutableContentTransformerTest; import org.alfresco.repo.content.transform.StringExtractingContentTransformerTest; import org.alfresco.repo.content.transform.TextMiningContentTransformerTest; +import org.alfresco.repo.content.transform.TextToPdfContentTransformerTest; import junit.framework.Test; import junit.framework.TestSuite; @@ -86,6 +87,7 @@ public class ContentTestSuite extends TestSuite suite.addTestSuite(RuntimeExecutableContentTransformerTest.class); suite.addTestSuite(StringExtractingContentTransformerTest.class); suite.addTestSuite(TextMiningContentTransformerTest.class); + suite.addTestSuite(TextToPdfContentTransformerTest.class); suite.addTestSuite(MailContentTransformerTest.class); suite.addTestSuite(ContentDataTest.class); suite.addTestSuite(MimetypeMapTest.class); diff --git a/source/java/org/alfresco/repo/content/transform/MailContentTransformer.java b/source/java/org/alfresco/repo/content/transform/MailContentTransformer.java index 6b55e154b5..010d766bb6 100644 --- a/source/java/org/alfresco/repo/content/transform/MailContentTransformer.java +++ b/source/java/org/alfresco/repo/content/transform/MailContentTransformer.java @@ -72,9 +72,10 @@ public class MailContentTransformer extends AbstractContentTransformer * @see org.alfresco.repo.content.transform.AbstractContentTransformer#transformInternal(org.alfresco.service.cmr.repository.ContentReader, org.alfresco.service.cmr.repository.ContentWriter, java.util.Map) */ @Override - protected void transformInternal(final ContentReader reader, final ContentWriter writer, Map options) + protected void transformInternal(final ContentReader reader, ContentWriter writer, Map options) throws Exception { + final StringBuilder sb = new StringBuilder(); POIFSReaderListener readerListener = new POIFSReaderListener() { public void processPOIFSReaderEvent(final POIFSReaderEvent event) @@ -87,7 +88,7 @@ public class MailContentTransformer extends AbstractContentTransformer String result = handler.process(); if (result != null) { - writer.putContent(result); + sb.append(result); } } } @@ -113,7 +114,12 @@ public class MailContentTransformer extends AbstractContentTransformer { // probably not an Outlook format MSG - ignore for now if (logger.isWarnEnabled()) - logger.warn("Unable to extract meta-data from message: " + err.getMessage()); + logger.warn("Unable to extract text from message: " + err.getMessage()); + } + finally + { + // Append the text to the writer + writer.putContent(sb.toString()); } } finally diff --git a/source/java/org/alfresco/repo/exporter/ViewXMLExporter.java b/source/java/org/alfresco/repo/exporter/ViewXMLExporter.java index a239436774..0ae131a259 100644 --- a/source/java/org/alfresco/repo/exporter/ViewXMLExporter.java +++ b/source/java/org/alfresco/repo/exporter/ViewXMLExporter.java @@ -569,7 +569,12 @@ import org.xml.sax.helpers.AttributesImpl; String strValue = (String)DefaultTypeConverter.INSTANCE.convert(String.class, value); if (strValue != null) { - contentHandler.characters(strValue.toCharArray(), 0, strValue.length()); + for (int i = 0; i < strValue.length(); i++) + { + char[] temp = new char[]{strValue.charAt(i)}; + contentHandler.characters(temp, 0, 1); + } + } // output value wrapper if property data type is any diff --git a/source/java/org/alfresco/repo/jscript/ScriptNode.java b/source/java/org/alfresco/repo/jscript/ScriptNode.java index b534f1bd7f..fc8bbf6930 100644 --- a/source/java/org/alfresco/repo/jscript/ScriptNode.java +++ b/source/java/org/alfresco/repo/jscript/ScriptNode.java @@ -1905,16 +1905,25 @@ public class ScriptNode implements Serializable, Scopeable { if (this.nodeService.exists(nodeRef)) { - // TODO: DC: Allow debug output of property values - for now it's disabled as this could potentially - // follow a large network of nodes. Unfortunately, JBPM issues unprotected debug statements - // where node.toString is used - will request this is fixed in next release of JBPM. - return "Node Type: " + getType() + ", Node Aspects: " + this.getAspects().toString(); + if (this.services.getPermissionService().hasPermission(nodeRef, PermissionService.READ_PROPERTIES) == AccessStatus.ALLOWED) + { + // TODO: DC: Allow debug output of property values - for now it's disabled as this could potentially + // follow a large network of nodes. Unfortunately, JBPM issues unprotected debug statements + // where node.toString is used - will request this is fixed in next release of JBPM. + return "Node Type: " + getType() + ", Node Aspects: " + this.getAspects().toString(); + } + else + { + return "Access denied to node " + nodeRef; + } + } else { return "Node no longer exists: " + nodeRef; } } + /** * Helper to create a QName from either a fully qualified or short-name QName string diff --git a/source/java/org/alfresco/repo/node/archive/ArchiveAndRestoreTest.java b/source/java/org/alfresco/repo/node/archive/ArchiveAndRestoreTest.java index 48337d38f3..aa4cb680ff 100644 --- a/source/java/org/alfresco/repo/node/archive/ArchiveAndRestoreTest.java +++ b/source/java/org/alfresco/repo/node/archive/ArchiveAndRestoreTest.java @@ -39,7 +39,6 @@ import org.alfresco.repo.node.StoreArchiveMap; import org.alfresco.repo.node.archive.RestoreNodeReport.RestoreStatus; import org.alfresco.repo.node.integrity.IntegrityChecker; import org.alfresco.repo.security.authentication.AuthenticationComponent; -import org.alfresco.repo.transaction.AlfrescoTransactionSupport; import org.alfresco.service.ServiceRegistry; import org.alfresco.service.cmr.repository.AssociationRef; import org.alfresco.service.cmr.repository.ChildAssociationRef; @@ -622,8 +621,6 @@ public class ArchiveAndRestoreTest extends TestCase */ public void testPermissionsForRestore() throws Exception { - - // user A deletes 'a' authenticationService.authenticate(USER_A, USER_A.toCharArray()); nodeService.deleteNode(a); @@ -653,4 +650,53 @@ public class ArchiveAndRestoreTest extends TestCase RestoreNodeReport report = nodeArchiveService.restoreArchivedNode(b_); assertEquals("Expected permission denied status", RestoreStatus.FAILURE_PERMISSION, report.getStatus()); } + + /** + * Check that the existence of the node in the archive store doesn't prevent archival. + * It is possible to restore a node to the SpacesStore from some other source. When + * that node is archived, the currently archived node must be overwritten. + * @throws Exception + */ + public void testAR1519ArchiveCleansDuplicateUuid() throws Exception + { + // Delete the child node + nodeService.deleteNode(b); + verifyNodeExistence(b_, true); + // Delete the original parent node + nodeService.deleteNode(a); + verifyNodeExistence(a_, true); + // Now recreate a and b (they have been separated in the archive store) + Map props = new HashMap(1); + props.put(ContentModel.PROP_NODE_UUID, a.getId()); + NodeRef aRecreated = nodeService.createNode( + workStoreRootNodeRef, + ContentModel.ASSOC_CHILDREN, + ContentModel.ASSOC_CHILDREN, + ContentModel.TYPE_CONTENT, + props).getChildRef(); + assertEquals("NodeRef for recreated node should be the same as the original", a, aRecreated); + props.put(ContentModel.PROP_NODE_UUID, b.getId()); + NodeRef bRecreated = nodeService.createNode( + a, + ContentModel.ASSOC_CHILDREN, + ContentModel.ASSOC_CHILDREN, + ContentModel.TYPE_CONTENT, + props).getChildRef(); + assertEquals("NodeRef for recreated node should be the same as the original", b, bRecreated); + + // Check existence + verifyNodeExistence(a, true); + verifyNodeExistence(b, true); + verifyNodeExistence(a_, true); + verifyNodeExistence(b_, true); + + // Now check that the parent a can be deleted and the conflict is handled + nodeService.deleteNode(a); + + // Check existence + verifyNodeExistence(a, false); + verifyNodeExistence(b, false); + verifyNodeExistence(a_, true); + verifyNodeExistence(b_, true); + } } diff --git a/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java b/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java index 21c70b49f0..24f66e1ba6 100644 --- a/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java +++ b/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java @@ -1713,6 +1713,19 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl // move each node into the archive store for (NodeStatus oldNodeStatus : nodeStatusesById.values()) { + // Check if the target node (node in the store) is already there + NodeRef targetStoreNodeRef = new NodeRef(store.getStoreRef(), oldNodeStatus.getKey().getGuid()); + if (exists(targetStoreNodeRef)) + { + // It is there already. It must be an archive of an earlier version, so just wipe it out + Node archivedNode = getNodeNotNull(targetStoreNodeRef); + nodeDaoService.deleteNode(archivedNode, true); + // We need to flush here as the node deletion may not take effect before the node creation + // is done. As this will only occur during a clash, it is not going to add extra overhead + // to the general system performance. + nodeDaoService.flush(); + } + Node nodeToMove = oldNodeStatus.getNode(); NodeRef oldNodeRef = nodeToMove.getNodeRef(); nodeToMove.setStore(store); diff --git a/source/java/org/alfresco/repo/node/index/AVMRemoteSnapshotTracker.java b/source/java/org/alfresco/repo/node/index/AVMRemoteSnapshotTracker.java index e66a2c8e7b..42ce700d81 100644 --- a/source/java/org/alfresco/repo/node/index/AVMRemoteSnapshotTracker.java +++ b/source/java/org/alfresco/repo/node/index/AVMRemoteSnapshotTracker.java @@ -27,6 +27,7 @@ package org.alfresco.repo.node.index; import java.util.List; import org.alfresco.repo.search.AVMSnapShotTriggeredIndexingMethodInterceptor; +import org.alfresco.repo.search.IndexMode; import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; import org.alfresco.service.cmr.avm.AVMService; import org.alfresco.service.cmr.avm.AVMStoreDescriptor; @@ -64,9 +65,8 @@ public class AVMRemoteSnapshotTracker extends AbstractReindexComponent } /** - * Loop throught the avm stores and compare the latest snapshot to that in the index. - * Update the index if it has fallen behind. - * + * Loop throught the avm stores and compare the latest snapshot to that in the index. Update the index if it has + * fallen behind. */ private void processStores() { @@ -86,21 +86,25 @@ public class AVMRemoteSnapshotTracker extends AbstractReindexComponent { break; } - int current = avmService.getLatestSnapshotID(store.getName()); - int lastIndexed = avmSnapShotTriggeredIndexingMethodInterceptor.getLastIndexedSnapshot(store.getName()); - if (lastIndexed < current) + if (avmSnapShotTriggeredIndexingMethodInterceptor.getIndexMode(store.getName()) != IndexMode.UNINDEXED) { - if(logger.isDebugEnabled()) + int current = avmService.getLatestSnapshotID(store.getName()); + int lastIndexed = avmSnapShotTriggeredIndexingMethodInterceptor.getLastIndexedSnapshot(store.getName()); + + if (lastIndexed < current) { - logger.debug("Updating index for store "+store.getName()+" from snapshot "+lastIndexed+ " to "+current); + if (logger.isDebugEnabled()) + { + logger.debug("Updating index for store " + store.getName() + " from snapshot " + lastIndexed + " to " + current); + } + recoverSnapShot(store.getName(), lastIndexed, current); + upToDate = false; } - recoverSnapShot(store.getName(), lastIndexed, current); - upToDate = false; } } } - while(!upToDate); + while (!upToDate); } @@ -118,7 +122,7 @@ public class AVMRemoteSnapshotTracker extends AbstractReindexComponent { public Object execute() throws Exception { - if(lastIndexed == -1) + if (lastIndexed == -1) { avmSnapShotTriggeredIndexingMethodInterceptor.createIndex(store); } diff --git a/source/java/org/alfresco/repo/search/impl/lucene/ADMLuceneIndexerImpl.java b/source/java/org/alfresco/repo/search/impl/lucene/ADMLuceneIndexerImpl.java index 7041795e40..bb10662cef 100644 --- a/source/java/org/alfresco/repo/search/impl/lucene/ADMLuceneIndexerImpl.java +++ b/source/java/org/alfresco/repo/search/impl/lucene/ADMLuceneIndexerImpl.java @@ -836,10 +836,17 @@ public class ADMLuceneIndexerImpl extends AbstractLuceneIndexerImpl imp writer.setEncoding("UTF-8"); try { - transformer.transform(reader, writer); // point the reader to the new-written content reader = writer.getReader(); + // Check that the reader is a view onto something concrete + if (!reader.exists()) + { + throw new ContentIOException( + "The transformation did not write any content, yet: \n" + + " transformer: " + transformer + "\n" + + " temp writer: " + writer); + } } catch (ContentIOException e) { @@ -850,10 +857,6 @@ public class ADMLuceneIndexerImpl extends AbstractLuceneIndexerImpl imp } // don't index from the reader readerReady = false; - // not indexed: transformation - // failed - // doc.add(new Field("TEXT", NOT_INDEXED_TRANSFORMATION_FAILED, Field.Store.NO, - // Field.Index.TOKENIZED, Field.TermVector.NO)); doc.add(new Field(attributeName, NOT_INDEXED_TRANSFORMATION_FAILED, Field.Store.NO, Field.Index.TOKENIZED, Field.TermVector.NO)); } } diff --git a/source/java/org/alfresco/repo/template/BaseSearchResultsMap.java b/source/java/org/alfresco/repo/template/BaseSearchResultsMap.java index 949d2d73c5..1b6d8a9120 100644 --- a/source/java/org/alfresco/repo/template/BaseSearchResultsMap.java +++ b/source/java/org/alfresco/repo/template/BaseSearchResultsMap.java @@ -32,6 +32,7 @@ import java.util.List; import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.service.ServiceRegistry; import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.search.ResultSet; import org.alfresco.service.cmr.search.ResultSetRow; import org.alfresco.service.cmr.search.SearchService; @@ -76,11 +77,13 @@ public abstract class BaseSearchResultsMap extends BaseTemplateMap if (results.length() != 0) { + NodeService nodeService = this.services.getNodeService(); + nodes = new ArrayList(results.length()); for (ResultSetRow row : results) { NodeRef nodeRef = row.getNodeRef(); - if (!nodeRefs.contains(nodeRef)) + if (!nodeRefs.contains(nodeRef) && (nodeService.exists(nodeRef))) { nodes.add(new TemplateNode(nodeRef, services, this.parent.getImageResolver())); nodeRefs.add(nodeRef); diff --git a/source/java/org/alfresco/repo/workflow/jbpm/JBPMEngine.java b/source/java/org/alfresco/repo/workflow/jbpm/JBPMEngine.java index cdf8ee3de3..e1d83a3b15 100644 --- a/source/java/org/alfresco/repo/workflow/jbpm/JBPMEngine.java +++ b/source/java/org/alfresco/repo/workflow/jbpm/JBPMEngine.java @@ -59,6 +59,7 @@ import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter; +import org.alfresco.service.cmr.search.SearchService; import org.alfresco.service.cmr.security.AuthorityType; import org.alfresco.service.cmr.security.PersonService; import org.alfresco.service.cmr.workflow.WorkflowDefinition; @@ -136,6 +137,7 @@ public class JBPMEngine extends BPMEngine protected PersonService personService; protected AuthorityDAO authorityDAO; protected JbpmTemplate jbpmTemplate; + protected SearchService unprotectedSearchService; // Company Home protected StoreRef companyHomeStore; @@ -278,6 +280,17 @@ public class JBPMEngine extends BPMEngine this.companyHomeStore = new StoreRef(companyHomeStore); } + /** + * Set the unprotected search service - so we can find the node ref for company home when folk do not have read access to company home + * TODO: review use with DC + * + * @param unprotectedSearchService + */ + public void setUnprotectedSearchService(SearchService unprotectedSearchService) + { + this.unprotectedSearchService = unprotectedSearchService; + } + // // Workflow Definition... @@ -2600,7 +2613,7 @@ public class JBPMEngine extends BPMEngine } else { - List refs = serviceRegistry.getSearchService().selectNodes(nodeService.getRootNode(companyHomeStore), companyHomePath, null, namespaceService, false); + List refs = unprotectedSearchService.selectNodes(nodeService.getRootNode(companyHomeStore), companyHomePath, null, namespaceService, false); if (refs.size() != 1) { throw new IllegalStateException("Invalid company home path: " + companyHomePath + " - found: " + refs.size()); diff --git a/source/java/org/alfresco/service/cmr/avm/AVMService.java b/source/java/org/alfresco/service/cmr/avm/AVMService.java index 744a2fb9ed..b4660c2cf9 100644 --- a/source/java/org/alfresco/service/cmr/avm/AVMService.java +++ b/source/java/org/alfresco/service/cmr/avm/AVMService.java @@ -1,25 +1,26 @@ -/* - * Copyright (C) 2005-2007 Alfresco Software Limited. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * As a special exception to the terms and conditions of version 2.0 of - * the GPL, you may redistribute this Program in connection with Free/Libre - * and Open Source Software ("FLOSS") applications as described in Alfresco's - * FLOSS exception. You should have recieved a copy of the text describing - * the FLOSS exception, and it is also available here: - * http://www.alfresco.com/legal/licensing" */ +/*----------------------------------------------------------------------------- +* Copyright 2005-2007 Alfresco Inc. +* +* 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 received a copy of the text describing the FLOSS exception, +* and it is also available here: http://www.alfresco.com/legal/licensing +* +*----------------------------------------------------------------------------*/ package org.alfresco.service.cmr.avm; @@ -39,12 +40,15 @@ import org.alfresco.service.namespace.QName; import org.alfresco.util.Pair; /** - * This is the service interface for the - * Alfresco Versioning Model (AVM). + * Service interface for the Alfresco Versioning Model (AVM).
+ * For the remote API, see: {@link org.alfresco.service.cmr.remote.AVMRemote AVMRemote}. + *

* - * Because the AVM is a versioning repository, fully explicit - * references to the nodes within it consist of an absolute AVM path, - * and a version ID. Absolute AVM paths are of + * Because the AVM is a + * + * versioning repository, + * fully explicit references to the nodes within it consist of an + * absolute AVM path, and a version ID. Absolute AVM paths are of * the form:  <store-name>:<store-relative-path>. *

* For example:  mystore:/www/avm_webapps/ROOT/x/y/z.html @@ -70,11 +74,13 @@ import org.alfresco.util.Pair; * {@link #createSnapshot(String store, String tag, String description) createSnapshot}, * or implicitly by various APIs in this interface and in * {@link org.alfresco.service.cmr.avmsync.AVMSyncService AVMSyncService}. - * While a new snapshot of a store will have version a ID one higher + * Although a new snapshot of a store will have version a ID one higher * than the previous snapshot in that store, the history of an AMV store * does not necessarily contain a continuous range of version ID values, * because {@link #purgeVersion(int version, String name) purgeVersion} - * may have been called. However, version ID values are never recycled + * may have been called. Regardless of whether + * {@link #purgeVersion(int version, String name) purgeVersion} + * has been called, the AVM never recycles version ID values * within a store. * * @author britt @@ -105,7 +111,6 @@ public interface AVMService */ public InputStream getFileInputStream(AVMNodeDescriptor desc); - /** * Get an output stream to write to a file * identified by an AVM path. This file must already exist. @@ -121,34 +126,6 @@ public interface AVMService * @throws AVMWrongTypeException */ public OutputStream getFileOutputStream(String path); - - - /** - * Low-level internal function:   Fetch a content reader for a file node. - * - * This function is similar to - * {@link getFileInputStream(int version, String path) getFileInputStream}; - * however, it can be used to fetch either InputStream or a - * random-access nio channel. - * - * @param version The version ID of the file. - * @param path The absolute AVM path to the file. - * @return A ContentReader. - * @throws AVMNotFoundException - * @throws AVMWrongTypeException - */ - public ContentReader getContentReader(int version, String path); - - - /** - * Low-level internal function:   Fetch a ContentWriter to a file node. - * - * @param path The path to the file. - * @return A ContentWriter. - * @throws AVMNotFoundException - * @throws AVMWrongTypeException - */ - public ContentWriter getContentWriter(String path); /** @@ -164,26 +141,6 @@ public interface AVMService * @throws AVMWrongTypeException */ public SortedMap getDirectoryListing(int version, String path); - - - /** - * Get a non-recursive listing of a directory node identified by its - * version ID and path; optionally, deleted notes can be included in - * this listing. - *

- * If instead, you wish to obtain a list of only - * the deleted nodes within a directory, see: - * {@link #getDeleted(int version, String path) getDeleted}. - * - * @param version The version ID to look in. - * @param path The absolute AVM path to the file. - * @param includeDeleted Whether to include deleted nodes - * @return A Map of names to descriptors. - * @throws AVMNotFoundException - * @throws AVMWrongTypeException - */ - public SortedMap getDirectoryListing(int version, String path, - boolean includeDeleted); /** * Get a non-recursive listing of nodes contained by a directory identified @@ -200,106 +157,23 @@ public interface AVMService * @throws AVMNotFoundException * @throws AVMWrongTypeException */ - public SortedMap + public SortedMap getDirectoryListingDirect(int version, String path); - - /** - * Get a non-recursive listing of nodes contained directly, - * but exclude all nodes that are only contained "indirectly" - * (i.e.: via layering). This function is identical to - * {@link #getDirectoryListingDirect(int version, String path) getDirectoryListingDirect} - * but it has the option of including deleted nodes in the listing. - * - * @param version The version to look up. - * @param path The absolute AVM directory path to get a listing for. - * @param includeDeleted Whether to include deleted nodes. - * @return A Map of names to descriptors. - * @throws AVMNotFoundException - * @throws AVMWrongTypeException - */ - public SortedMap - getDirectoryListingDirect(int version, String path, boolean includeDeleted); - - - /** - * A convenience method to get a directory listing - * as an Array of AVMNodeDescriptors; this function - * is otherwise equivalent to - * {@link #getDirectoryListing(int version, String path, boolean includeDeleted) getDirectoryListing} - * - * @param version The version to look under. - * @param path The path to the directory to be listed. - * @param includeDeleted Whether to include deleted nodes - * @return An array of AVMNodeDescriptors. - * @throws AVMNotFoundException - * @throws AVMWrongTypeException - */ - public AVMNodeDescriptor [] getDirectoryListingArray(int version, String path, - boolean includeDeleted); - - /** - * Get a non-recursive listing of all the nodes contained by a directory - * identified by an AVMNodeDescriptor, excluding those that are only - * present "indirectly" via layering; optionally, deleted nodes that - * are directly contained can be included this listing. - * - * @param dir The directory descriptor. - * @param includeDeleted Whether to include directly contained deleted nodes - * @return A Map of Strings to descriptors. - * @throws AVMNotFoundException - * @throws AVMWrongTypeException - */ - public SortedMap - getDirectoryListingDirect(AVMNodeDescriptor dir, boolean includeDeleted); - /** * Get a non-recursive directory listing of a directory node * identified by a node descriptor. * * @param dir The directory node descriptor. - * @return A Map of names to node descriptors. + * @return A sorted Map of names to node descriptors. * @throws AVMNotFoundException * @throws AVMWrongTypeException */ public SortedMap getDirectoryListing(AVMNodeDescriptor dir); - - /** - * Get a non-recursive directory listing of a directory identified - * by a node descriptor; optionally, deleted nodes can be included - * in this listing. - * - * @param dir The directory node descriptor. - * @param includeDeleted Whether to include deleted nodes. - * @return A Map of names to node descriptors. - * @throws AVMNotFoundException If the descriptor is stale. - * @throws AVMWrongTypeException If the descriptor does not point at a directory. - */ - public SortedMap getDirectoryListing(AVMNodeDescriptor dir, - boolean includeDeleted); - - /** - * A convenience method to get a non-recursive directory listing - * as an Array from a directory identified by a node descriptor; - * optionally, deleted nodes can be included in this listing. - * - * This function is identical to - * {@link getDirectoryListing(AVMNodeDescriptor dir,boolean includeDeleted) getDirectoryListing} - * except that it returns an array. - * - * @param dir The descriptor pointing at the directory to list. - * @param includeDeleted Whether include deleted nodes - * @return An array of AVMNodeDescriptors. - * @throws AVMNotFoundException - * @throws AVMWrongTypeException - */ - public AVMNodeDescriptor [] getDirectoryListingArray(AVMNodeDescriptor dir, - boolean includeDeleted); - /** - * Get the names of nodes that have been deleted in a directory - * identified by a version ID and a path. + * Non-recursively get the names of nodes that have been deleted in + * a directory identified by a version ID and a path * * @param version The version to look under. * @param path The path of the directory. @@ -321,42 +195,10 @@ public interface AVMService * @throws AVMNotFound * @throws AVMExists * @throws AVMWrongType + * @return An opaque handle to a server side output stream. */ public OutputStream createFile(String path, String name); - /** - * Create a new "plain" (non-layered) file. - * Guarantees that the entire contents of the - * input stream will be loaded atomically. - * The directory identified by path must already exist. - * - * @param path The path of the directory containing the created file. - * @param name The name of the new file - * @param in An input stream with data for the file. - * @throws AVMNotFound - * @throws AVMExists - * @throws AVMWrongType - */ - public void createFile(String path, String name, InputStream in); - - - /** - * Create a new "plain" (non-layered) file. - * Guarantees that the entire contents of the - * input stream will be loaded atomically. - * The directory identified by path must already exist. - * - * @param path The path of the directory containing the created file. - * @param name The name of the new file - * @param in An input stream with data for the file. - * @param aspect A list of aspects to give the file. - * @param properties A map of properties to give the file. - * @throws AVMNotFound - * @throws AVMExists - * @throws AVMWrongType - */ - public void createFile(String path, String name, InputStream in, List aspects, Map properties); - /** * Create a new directory. * If path is within a layer, the new directory will be a layered directory; @@ -369,21 +211,6 @@ public interface AVMService * @throws AVMWrongType */ public void createDirectory(String path, String name); - - /** - * Create a new directory. - * If path is within a layer, the new directory will be a layered directory; - * otherwise, the new directory will be a plain directory. - * - * @param path The simple absolute path to the parent. - * @param name The name to give the directory. - * @param aspects A list of aspects to add. - * @param properties A Map of properties to add. - * @throws AVMNotFound - * @throws AVMExists - * @throws AVMWrongType - */ - public void createDirectory(String path, String name, List aspects, Map properties); /** * Create a new layered file. @@ -449,7 +276,7 @@ public interface AVMService * name. If a store is removed via * {@link purgeStore(String name) purgeStore}, the name of * the deleted store can be reused in a later call to - * @{link createStore(String name) createStore}. + * {@link createStore(String name) createStore}. *

* The store name must be non-null, cannot be the empty string, * and must not contain characters that are illegal in @@ -513,18 +340,7 @@ public interface AVMService * @throws AVMWrongTypeException */ public void removeNode(String parent, String name); - - /** - * A convenience method that removes a node specified by an AVM path. - * It merely parses an absolute path into a parent directory and a child - * name, then calls {@link #removeNode(parent, name) removeNode}. - * - * @param path The full path to the node to remove. - * @throws AVMNotFoundException - * @throws AVMWrongTypeException - */ - public void removeNode(String path); /** @@ -572,7 +388,7 @@ public interface AVMService * @throws AVMExistsException */ public void rename(String srcParent, String srcName, String dstParent, String dstName); - + /** * If a layered directory dirPath @@ -595,24 +411,6 @@ public interface AVMService public void uncover(String dirPath, String name); - /** - * Atomically delete name within dirPath - * and {@link uncover(String dirPath, String name) uncover} - * it so whatever is underneath can be seen via transparency. - * If name corresponds to a deletion already, - * then the deletion step is skipped, and the "uncover" - * operation is performed. - * - * @param dirPath The path to the layered directory. - * @param name The name of the item this method will - * {@link org.alfresco.service.cmr.avmsync.AVMSyncService#flatten(String layerPath, String underlyingPath) flatten} - * - * @throws AVMNotFoundException - * @throws AVMWrongTypeException - */ - public void makeTransparent(String dirPath, String name); - - /** * Gets the ID that the next snapshotted version of a store * will have. @@ -627,7 +425,7 @@ public interface AVMService * @throws AVMNotFoundException */ public int getNextVersionID(String storeName); - + /** * Get the latest snapshot ID of a store. @@ -725,18 +523,6 @@ public interface AVMService * @return A List of all AVMStores. */ public List getStores(); - - - - /** - * Low-level internal function:   - * Retrieve the reserved "system" store. - * This method isn't currently used, - * but may be in some future release. - * - * @return The descriptor. - */ - public AVMStoreDescriptor getSystemStore(); /** @@ -745,7 +531,7 @@ public interface AVMService * @return A Descriptor, or null if not found. */ public AVMStoreDescriptor getStore(String name); - + /** * A convenience method for getting the specified @@ -758,7 +544,7 @@ public interface AVMService */ public AVMNodeDescriptor getStoreRoot(int version, String name); - + /** * Lookup a node identified by version ID and path. * @@ -767,7 +553,7 @@ public interface AVMService * @return An AVMNodeDescriptor, or null if the node does not exist. */ public AVMNodeDescriptor lookup(int version, String path); - + /** * Lookup a node identified by version ID and path; optionally, * if the node is deleted, its descriptor can still @@ -789,7 +575,8 @@ public interface AVMService * @throws AVMWrongTypeException If dir does not refer to a directory. */ public AVMNodeDescriptor lookup(AVMNodeDescriptor dir, String name); - + + /** * Lookup a node identified by the directory that contains it, and its name; * optionally, the lookup can retrive the descriptor of a node even if @@ -803,73 +590,16 @@ public interface AVMService * @throws AVMWrongTypeException */ public AVMNodeDescriptor lookup(AVMNodeDescriptor dir, String name, boolean includeDeleted); - - - /** - * Get a list of all paths that a given node has. - * This can be an extremely expensive operation due to the large number - * of paths to an AVMNodeDescriptor that can be generated - * via branching and versioning. For example, if an asset - * is present in the initial version of a store, and - * that store has been versioned 10,000 times, - * there are a minimum of 10,000 paths that lead to it. - * The effect of branching is multiplicative. - *

- * Note: paths that only access desc - * via transparency are not returned by this function; - * only "direct" containment relationships are considered. - *

- * For those concerned with records management applications, - * it's worth noting that once every path to an asset has - * been deleted, the system will purge it entirely in an - * asynchronous manner. - * - * @param desc The node descriptor to get paths for. - * @return A List of version, path Pairs. - * @throws AVMNotFoundException - */ - public List> getPaths(AVMNodeDescriptor desc); - /** * Get a single valid path to a given node. - * @param desc The node descriptor to get a path for. - * @return AVMNotFoundException + * @param desc The descriptor of the node to which a version and path will be fetched. + * @return version and path. + * @throws AVMNotFoundException */ public Pair getAPath(AVMNodeDescriptor desc); - - /** - * Get all paths that a given node has that are in the - * HEAD version ( -1 ). - * This can be an expensive operation but less so than getPaths(). - * - * @param desc The node descriptor to get paths for. - * @return A List of version, path Pairs. - * @throws AVMNotFoundException - */ - public List> getHeadPaths(AVMNodeDescriptor desc); - - /** - * Get all paths to a node starting at the - * HEAD version ( -1 ) - * of a store. This can be an expensive operation but less so than getHeadPaths(). - * - * @param desc The node descriptor. - * @param store The store. - * @return A List of all paths meeting the criteria. - * @throws AVMNotFoundException - */ - public List> getPathsInStoreHead(AVMNodeDescriptor desc, String store); - - /** - * Get all paths to a given node in a single store in a single non-head version. - * @param desc The node descriptor. - * @param store The name of the store. - * @param version The version. - * @return A List of AVM paths. - */ - public List getPathsInStoreVersion(AVMNodeDescriptor desc, String store, int version); - + + /** * Get the indirection path for a node in a layered context * whether that indirection path is primary or non-primary @@ -896,7 +626,8 @@ public interface AVMService * @throws AVMWrongTypeException */ public String getIndirectionPath(int version, String path); - + + /** * Purge an AVMStore. * This completely removes an AVMStore. @@ -1030,17 +761,12 @@ public interface AVMService * @throws AVMNotFoundException */ public Map getNodeProperties(int version, String path); - - /** - * Get all the properties associated with a node identified by a descriptor. - * @param desc The node descriptor - * @return A Map of the properties. - * @throws AVMNotFoundException - */ - public Map getNodeProperties(AVMNodeDescriptor desc); - + + /** * Delete a property. + *

+ * Note: to remove an apsect, see: {@link #removeAspect(String path, QName aspectName) removeAspect} * * @param path The path to the node. * @param name The QName of the property to delete. @@ -1050,6 +776,8 @@ public interface AVMService /** * Delete all the properties attached to an AVM node. + *

+ * Note: to remove an apsect, see: {@link #removeAspect(String path, QName aspectName) removeAspect} * * @param path The path to the node. * @throws AVMNotFoundException @@ -1084,7 +812,7 @@ public interface AVMService * @throws AVMNotFoundException */ public PropertyValue getStoreProperty(String store, QName name); - + /** * Get all the properties associated with a store. * @@ -1103,18 +831,11 @@ public interface AVMService */ public Map queryStorePropertyKey(String store, QName keyPattern); - /** - * Queries all AVM stores for properties with keys that match a given pattern. - * - * @param keyPattern The sql 'like' pattern, inserted into a QName. - * @return A Map of store names to Maps of property key value pairs that match - * the pattern. - */ - public Map> - queryStoresPropertyKeys(QName keyPattern); /** * Delete a property on a store by name. + *

+ * Note: to remove an apsect, see: {@link #removeAspect(String path, QName aspectName) removeAspect} * * @param store The name of the store. * @param name The name of the property to delete. @@ -1123,60 +844,6 @@ public interface AVMService public void deleteStoreProperty(String store, QName name); - /** - * Low-level internal function:   Get the ContentData for - * a node in a read context. Only applies to a file. - * - * @param version The version to look under. - * @param path The path to the node. - * @return The ContentData object. - * @throws AVMNotFoundException - * @throws AVMWrongTypeException - */ - public ContentData getContentDataForRead(int version, String path); - - /** - * Get ContentData using only a node descriptor. - * @param desc The node descriptor. - * @return The ContentData - * @throws AVMNotFoundException - */ - public ContentData getContentDataForRead(AVMNodeDescriptor desc); - - - /** - * Low-level internal function:   Get the ContentData for - * a node in a write context. - * - * @param path The path to the node. - * @return The ContentData object. - * @throws AVMNotFoundException - * @throws AVMWrongTypeException - */ - public ContentData getContentDataForWrite(String path); - - - /** - * Low-level internal function:   Set the content data on a file. - * - * @param path The path to the file. - * @param data The ContentData to set. - * @throws AVMNotFoundException - * @throws AVMWrongTypeException - */ - public void setContentData(String path, ContentData data); - - - /** - * Set all metadata on a node from another node. Aspects, properties, ACLs. - * - * @param path The path to the node to set. - * @param from The descriptor for the node to get metadata from. - * @throws AVMNotFoundException - */ - public void setMetaDataFrom(String path, AVMNodeDescriptor from); - - /** * Add an aspect to an AVM node. * @@ -1186,7 +853,7 @@ public interface AVMService * @throws AVMExistsException */ public void addAspect(String path, QName aspectName); - + /** * Get all the aspects on an AVM node. * @@ -1197,13 +864,7 @@ public interface AVMService */ public Set getAspects(int version, String path); - /** - * Get all the aspects from a node descriptor. - * @param desc The node descriptor. - * @return The Set of Aspects. - */ - public Set getAspects(AVMNodeDescriptor desc); - + /** * Remove an aspect and its properties from a node. * @@ -1223,8 +884,265 @@ public interface AVMService * @throws AVMNotFoundException */ public boolean hasAspect(int version, String path, QName aspectName); + + + /** + * Rename a store. + * + * @param sourceName The original name. + * @param destName The new name. + * @throws AVMNotFoundException + * @throws AVMExistsException + */ + public void renameStore(String sourceName, String destName); + + /** + * Revert a HEAD path to a given version. + * This works by cloning the version to revert to, and then linking + * that new version into HEAD. + * The reverted version will have the previous + * HEAD version as ancestor. + * + * @param path The path to the node to revert. + * @param toRevertTo The descriptor of the version to revert to. + * @throws AVMNotFoundException + */ + public void revert(String path, AVMNodeDescriptor toRevertTo); + + + /** + * Set the GUID on a node. The GUID of a node uniquely identifies + * the state of a node, i.e. its content, metadata, and aspects. + * @param path The path to the node. + * @param guid The GUID to set. + */ + public void setGuid(String path, String guid); + + /** + * Set the mime type. + * @param path The path of the file. + * @param mimeType The mime type. + */ + public void setMimeType(String path, String mimeType); + + /** + * Set the encoding. + * @param path The path of the file. + * @param encoding The encoding. + */ + public void setEncoding(String path, String encoding); + + /** + * Queries all AVM stores for properties with keys that match a given pattern. + * + * @param keyPattern The sql 'like' pattern, inserted into a QName. + * @return A Map of store names to Maps of property key value pairs that match + * the pattern. + */ + public Map> + queryStoresPropertyKeys(QName keyPattern); + + //------------------------------------------------------------------------- + // NOTE: The functions below should probably be included in AVMRemote + // but currently are not: + //------------------------------------------------------------------------- + + /** + * Create a new directory with aspects and properties. + * If path is within a layer, the new directory will be a layered directory; + * otherwise, the new directory will be a plain directory. + * + * @param path The simple absolute path to the parent. + * @param name The name to give the directory. + * @param aspects A list of aspects to add. + * @param properties A Map of properties to add. + * @throws AVMNotFound + * @throws AVMExists + * @throws AVMWrongType + */ + + public void createDirectory(String path, String name, List aspects, Map properties); + /** + * Create a new "plain" (non-layered) file. + * Guarantees that the entire contents of the + * input stream will be loaded atomically. + * The directory identified by path must already exist. + * + * @param path The path of the directory containing the created file. + * @param name The name of the new file + * @param in An input stream with data for the file. + * @throws AVMNotFound + * @throws AVMExists + * @throws AVMWrongType + */ + public void createFile(String path, String name, InputStream in); + + + /** + * Create a new "plain" (non-layered) file with aspects and properties. + * Guarantees that the entire contents of the + * input stream will be loaded atomically. + * The directory identified by path must already exist. + * + * @param path The path of the directory containing the created file. + * @param name The name of the new file + * @param in An input stream with data for the file. + * @param aspect A list of aspects to give the file. + * @param properties A map of properties to give the file. + * @throws AVMNotFound + * @throws AVMExists + * @throws AVMWrongType + */ + public void createFile(String path, String name, InputStream in, List aspects, Map properties); + + /** + * Get a non-recursive directory listing of a directory identified + * by a node descriptor; optionally, deleted nodes can be included + * in this listing. + * + * @param dir The directory node descriptor. + * @param includeDeleted Whether to include deleted nodes. + * @return A Map of names to node descriptors. + * @throws AVMNotFoundException If the descriptor is stale. + * @throws AVMWrongTypeException If the descriptor does not point at a directory. + */ + public SortedMap getDirectoryListing(AVMNodeDescriptor dir, + boolean includeDeleted); + + /** + * A convenience method to get a non-recursive directory listing + * as an Array from a directory identified by a node descriptor; + * optionally, deleted nodes can be included in this listing. + * + * This function is identical to + * {@link getDirectoryListing(AVMNodeDescriptor dir,boolean includeDeleted) getDirectoryListing} + * except that it returns an array. + * + * @param dir The descriptor pointing at the directory to list. + * @param includeDeleted Whether include deleted nodes + * @return An array of AVMNodeDescriptors. + * @throws AVMNotFoundException + * @throws AVMWrongTypeException + */ + public AVMNodeDescriptor [] getDirectoryListingArray(AVMNodeDescriptor dir, + boolean includeDeleted); + + /** + * Get a non-recursive listing of nodes contained directly, + * but exclude all nodes that are only contained "indirectly" + * (i.e.: via layering). This function is identical to + * {@link #getDirectoryListingDirect(int version, String path) getDirectoryListingDirect} + * but it has the option of including deleted nodes in the listing. + * + * @param version The version to look up. + * @param path The absolute AVM directory path to get a listing for. + * @param includeDeleted Whether to include deleted nodes. + * @return A Map of names to descriptors. + * @throws AVMNotFoundException + * @throws AVMWrongTypeException + */ + public SortedMap + getDirectoryListingDirect(int version, String path, boolean includeDeleted); + + + /** + * A convenience method to get a directory listing + * as an Array of AVMNodeDescriptors; this function + * is otherwise equivalent to + * {@link #getDirectoryListing(int version, String path, boolean includeDeleted) getDirectoryListing} + * + * @param version The version to look under. + * @param path The path to the directory to be listed. + * @param includeDeleted Whether to include deleted nodes + * @return An array of AVMNodeDescriptors. + * @throws AVMNotFoundException + * @throws AVMWrongTypeException + */ + public AVMNodeDescriptor [] getDirectoryListingArray(int version, String path, + boolean includeDeleted); + + /** + * Get a non-recursive listing of all the nodes contained by a directory + * identified by an AVMNodeDescriptor, excluding those that are only + * present "indirectly" via layering; optionally, deleted nodes that + * are directly contained can be included this listing. + * + * @param dir The directory descriptor. + * @param includeDeleted Whether to include directly contained deleted nodes + * @return A Map of Strings to descriptors. + * @throws AVMNotFoundException + * @throws AVMWrongTypeException + */ + public SortedMap + getDirectoryListingDirect(AVMNodeDescriptor dir, boolean includeDeleted); + /** + * Get a non-recursive listing of a directory node identified by its + * version ID and path; optionally, deleted notes can be included in + * this listing. + *

+ * If instead, you wish to obtain a list of only + * the deleted nodes within a directory, see: + * {@link #getDeleted(int version, String path) getDeleted}. + * + * @param version The version ID to look in. + * @param path The absolute AVM path to the file. + * @param includeDeleted Whether to include deleted nodes + * @return A Map of names to descriptors. + * @throws AVMNotFoundException + * @throws AVMWrongTypeException + */ + public SortedMap getDirectoryListing(int version, String path, + boolean includeDeleted); + + /** + * A convenience method that removes a node specified by an AVM path. + * It merely parses an absolute path into a parent directory and a child + * name, then calls {@link #removeNode(parent, name) removeNode}. + * + * @param path The full path to the node to remove. + * @throws AVMNotFoundException + * @throws AVMWrongTypeException + */ + public void removeNode(String path); + + /** + * Atomically delete name within dirPath + * and {@link uncover(String dirPath, String name) uncover} + * it so whatever is underneath can be seen via transparency. + * If name corresponds to a deletion already, + * then the deletion step is skipped, and the "uncover" + * operation is performed. + * + * @param dirPath The path to the layered directory. + * @param name The name of the item this method will + * {@link org.alfresco.service.cmr.avmsync.AVMSyncService#flatten(String layerPath, String underlyingPath) flatten} + * + * @throws AVMNotFoundException + * @throws AVMWrongTypeException + */ + public void makeTransparent(String dirPath, String name); + + /** + * Low-level internal function:   + * Retrieve the reserved "system" store. + * This method isn't currently used, + * but may be in some future release. + * + * @return The descriptor. + */ + public AVMStoreDescriptor getSystemStore(); + + /** + * Set all metadata on a node from another node. Aspects, properties, ACLs. + * + * @param path The path to the node to set. + * @param from The descriptor for the node to get metadata from. + * @throws AVMNotFoundException + */ + public void setMetaDataFrom(String path, AVMNodeDescriptor from); + /** * Low-level internal function:   Insert a node * into a parent directly. Caution: this is not something @@ -1265,47 +1183,151 @@ public interface AVMService /** - * Rename a store. + * Get a list of all paths that a given node has. + * This can be an extremely expensive operation due to the large number + * of paths to an AVMNodeDescriptor that can be generated + * via branching and versioning. For example, if an asset + * is present in the initial version of a store, and + * that store has been versioned 10,000 times, + * there are a minimum of 10,000 paths that lead to it. + * The effect of branching is multiplicative. + *

+ * Note: paths that only access desc + * via transparency are not returned by this function; + * only "direct" containment relationships are considered. + *

+ * For those concerned with records management applications, + * it's worth noting that once every path to an asset has + * been deleted, the system will purge it entirely in an + * asynchronous manner. * - * @param sourceName The original name. - * @param destName The new name. - * @throws AVMNotFoundException - * @throws AVMExistsException + * @param desc The node descriptor to get paths for. + * @return A List of version, path Pairs. + * @throws AVMNotFoundException */ - public void renameStore(String sourceName, String destName); + public List> getPaths(AVMNodeDescriptor desc); /** - * Revert a HEAD path to a given version. - * This works by cloning the version to revert to, and then linking - * that new version into HEAD. - * The reverted version will have the previous - * HEAD version as ancestor. + * Get all paths that a given node has that are in the + * HEAD version ( -1 ). + * This can be an expensive operation but less so than getPaths(). * - * @param path The path to the node to revert. - * @param toRevertTo The descriptor of the version to revert to. - * @throws AVMNotFoundException + * @param desc The node descriptor to get paths for. + * @return A List of version, path Pairs. + * @throws AVMNotFoundException */ - public void revert(String path, AVMNodeDescriptor toRevertTo); + public List> getHeadPaths(AVMNodeDescriptor desc); /** - * Set the GUID on a node. The GUID of a node uniquely identifies - * the state of a node, i.e. its content, metadata, and aspects. + * Get all paths to a node starting at the + * HEAD version ( -1 ) + * of a store. This can be an expensive operation but less so than getHeadPaths(). + * + * @param desc The node descriptor. + * @param store The store. + * @return A List of all paths meeting the criteria. + * @throws AVMNotFoundException + */ + public List> getPathsInStoreHead(AVMNodeDescriptor desc, String store); + + /** + * Get all paths to a given node in a single store in a single non-head version. + * @param desc The node descriptor. + * @param store The name of the store. + * @param version The version. + * @return A List of AVM paths. + */ + public List getPathsInStoreVersion(AVMNodeDescriptor desc, String store, int version); + + /** + * Get all the properties associated with a node identified by a descriptor. + * @param desc The node descriptor + * @return A Map of the properties. + * @throws AVMNotFoundException + */ + public Map getNodeProperties(AVMNodeDescriptor desc); + + /** + * Get all the aspects from a node descriptor. + * @param desc The node descriptor. + * @return The Set of Aspects. + */ + public Set getAspects(AVMNodeDescriptor desc); + + + + + + //------------------------------------------------------------------------- + // NOTE: The functions from here down will never be part of AVMRemote + //------------------------------------------------------------------------- + + /** + * Low-level internal function:   Fetch a content reader for a file node. + * + * This function is similar to + * {@link getFileInputStream(int version, String path) getFileInputStream}; + * however, it can be used to fetch either InputStream or a + * random-access nio channel. + * + * @param version The version ID of the file. + * @param path The absolute AVM path to the file. + * @return A ContentReader. + * @throws AVMNotFoundException + * @throws AVMWrongTypeException + */ + public ContentReader getContentReader(int version, String path); + + /** + * Low-level internal function:   Fetch a ContentWriter to a file node. + * + * @param path The path to the file. + * @return A ContentWriter. + * @throws AVMNotFoundException + * @throws AVMWrongTypeException + */ + public ContentWriter getContentWriter(String path); + + /** + * Low-level internal function:   Get the ContentData for + * a node in a read context. Only applies to a file. + * + * @param version The version to look under. * @param path The path to the node. - * @param guid The GUID to set. + * @return The ContentData object. + * @throws AVMNotFoundException + * @throws AVMWrongTypeException */ - public void setGuid(String path, String guid); + public ContentData getContentDataForRead(int version, String path); /** - * Set the mime type. - * @param path The path of the file. - * @param mimeType The mime type. + * Get ContentData using only a node descriptor. + * @param desc The node descriptor. + * @return The ContentData + * @throws AVMNotFoundException */ - public void setMimeType(String path, String mimeType); + public ContentData getContentDataForRead(AVMNodeDescriptor desc); + /** - * Set the encoding. - * @param path The path of the file. - * @param encoding The encoding. + * Low-level internal function:   Get the ContentData for + * a node in a write context. + * + * @param path The path to the node. + * @return The ContentData object. + * @throws AVMNotFoundException + * @throws AVMWrongTypeException */ - public void setEncoding(String path, String encoding); + public ContentData getContentDataForWrite(String path); + + /** + * Low-level internal function:   Set the content data on a file. + * + * @param path The path to the file. + * @param data The ContentData to set. + * @throws AVMNotFoundException + * @throws AVMWrongTypeException + */ + public void setContentData(String path, ContentData data); + } diff --git a/source/java/org/alfresco/service/cmr/remote/AVMRemote.java b/source/java/org/alfresco/service/cmr/remote/AVMRemote.java index ffd86ac09d..a6bcd93361 100644 --- a/source/java/org/alfresco/service/cmr/remote/AVMRemote.java +++ b/source/java/org/alfresco/service/cmr/remote/AVMRemote.java @@ -1,25 +1,26 @@ -/* - * Copyright (C) 2005-2007 Alfresco Software Limited. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * As a special exception to the terms and conditions of version 2.0 of - * the GPL, you may redistribute this Program in connection with Free/Libre - * and Open Source Software ("FLOSS") applications as described in Alfresco's - * FLOSS exception. You should have recieved a copy of the text describing - * the FLOSS exception, and it is also available here: - * http://www.alfresco.com/legal/licensing" */ +/*----------------------------------------------------------------------------- +* Copyright 2005-2007 Alfresco Inc. +* +* 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 received a copy of the text describing the FLOSS exception, +* and it is also available here: http://www.alfresco.com/legal/licensing +* +*----------------------------------------------------------------------------*/ package org.alfresco.service.cmr.remote; @@ -42,207 +43,518 @@ import org.alfresco.service.namespace.QName; import org.alfresco.util.Pair; /** - * Remote interface for AVM. + * Remote interface for Alfresco Versioning Model (AVM).
+ * For the in-process API, see: + * {@link org.alfresco.service.cmr.avm.AVMService AVMService}. + *

+ * + * Because the AVM is a + * + * versioning repository, + * fully explicit references to the nodes within it consist of an + * absolute AVM path, and a version ID. Absolute AVM paths are of + * the form:  <store-name>:<store-relative-path>. + *

+ * For example:  mystore:/www/avm_webapps/ROOT/x/y/z.html + *

+ * Within AVMService, whenever an API takes a path + * and a name, the path is the parent + * directory in which the name appears. + * Whenever just a path is needed by an API, it is an absolute + * path to a file or directory. + *

+ * The special version ID -1 (negative one) + * refers to the latest read/write version at the given absolute AVM path. + * Non-negative version ID values refer to read-only snapshots of a store. + * For this reason, the version ID -1 + * is implicit for all write operations. Sometimes, + * -1 is referred to as the + * HEAD version (a term that should be + * already be familiar to users of other versioning systems like + * CVS + * and SVN). + *

+ * Snapshots can be created explicitly via a call to + * {@link #createSnapshot(String store, String tag, String description) createSnapshot}, + * or implicitly by various APIs in this interface and in + * {@link org.alfresco.service.cmr.avmsync.AVMSyncService AVMSyncService}. + * Although a new snapshot of a store will have version a ID one higher + * than the previous snapshot in that store, the history of an AMV store + * does not necessarily contain a continuous range of version ID values, + * because {@link #purgeVersion(int version, String name) purgeVersion} + * may have been called. Regardless of whether + * {@link #purgeVersion(int version, String name) purgeVersion} + * has been called, the AVM never recycles version ID values + * within a store. + * * @author britt */ public interface AVMRemote { /** - * Get an input handle. A handle is an opaque reference - * to a server side input stream. - * @param version The version to look under. - * @param path The path to the file. - * @return An InputStream. + * Get an InputStream for reading the contents of a + * file identified by its version ID and AVM path. + * This method can be used for either plain or layered files. + * + * @param version The version ID to look in. + * @param path The absolute path to the file. + * @return An InputStream for the designated file. + * @throws AVMNotFoundException + * @throws AVMWrongTypeException */ public InputStream getFileInputStream(int version, String path); /** - * Get an InputStream from a descriptor directly. + * Get an InputStream for reading the contents of a + * file node identified by its descriptor. + * This method can be used for either plain or layered files. + * * @param desc The descriptor. * @return An InputStream. + * @throws AVMNotFoundException */ public InputStream getFileInputStream(AVMNodeDescriptor desc); /** - * Get an opaque handle to a server side output stream. - * @param path The path to the existing file. - * @return An opaque handle. + * Get an output stream to write to a file + * identified by an AVM path. This file must already exist. + * This method can be used for either plain or layered files. + * + * To create a plain file, see: + * {@link #createFile(String path, String name) createFile}. + * To create a layered file, see: + * {@link #createLayeredFile(String targetPath, String parent, String name) createLayeredFile}. + * + * @param path The absolute path to the file. + * @throws AVMNotFoundException + * @throws AVMWrongTypeException */ public OutputStream getFileOutputStream(String path); + + + /** + * Get a non-recursive listing of a directory + * identified by its version ID and path. + * If path does not refer to a directory + * node, AVMWrongTypeException is thrown. + * + * @param version The version ID to look in. + * @param path The absolute AVM path to the file. + * @return A Map of names to descriptors. + * @throws AVMNotFoundException + * @throws AVMWrongTypeException + */ + public SortedMap getDirectoryListing(int version, String path); /** - * Get a listing of a directories direct contents. - * @param version The version to look under. - * @param path The path to the directory. - * @return A sorted listing. + * Get a non-recursive listing of nodes contained by a directory identified + * by its version ID and path, but exclude all nodes that are only + * contained "indirectly" via layering. + *

+ * If this function is called on a "plain" (non-layered) directory, + * it is equivalent to + * {@link #getDirectoryListing(int version, String path) getDirectoryListing}. + * + * @param version The version to look up. + * @param path The full path to get listing for. + * @return A Map of names to descriptors. + * @throws AVMNotFoundException + * @throws AVMWrongTypeException */ public SortedMap getDirectoryListingDirect(int version, String path); - + /** - * Get a listing of a directory. - * @param version The version to look under. - * @param path The path to the directory. - * @return A sorted listing. - */ - public SortedMap - getDirectoryListing(int version, String path); - - /** - * Get a directory listing from a node descriptor. + * Get a non-recursive directory listing of a directory node + * identified by a node descriptor. + * * @param dir The directory node descriptor. - * @return A sorted listing. + * @return A sorted Map of names to node descriptors. + * @throws AVMNotFoundException + * @throws AVMWrongTypeException */ - public SortedMap - getDirectoryListing(AVMNodeDescriptor dir); - + public SortedMap getDirectoryListing(AVMNodeDescriptor dir); + /** - * Get the names of nodes that have been deleted in a directory. + * Non-recursively get the names of nodes that have been deleted in + * a directory identified by a version ID and a path + * * @param version The version to look under. - * @param path The path to the directory. - * @return A list of deleted names. + * @param path The path of the directory. + * @return A List of names. + * @throws AVMNotFoundException + * @throws AVMWrongTypeException */ public List getDeleted(int version, String path); + /** - * Create a file and return a handle to an output stream. - * @param path The path to the file. - * @param name The name of the file to create. + * Create a new "plain" (non-layered) file within a path. + * This function fails if the file already exists, + * or if the directory identified by path + * does not exist. + * + * @param path The path of the directory containing the created file. + * @param name The name of the new file + * @throws AVMNotFound + * @throws AVMExists + * @throws AVMWrongType * @return An opaque handle to a server side output stream. */ public OutputStream createFile(String path, String name); /** - * Create a directory. - * @param path The path to the containing directory. - * @param name The name for the new directory. - */ + * Create a new directory. + * If path is within a layer, the new directory will be a layered directory; + * otherwise, the new directory will be a plain directory. + * + * @param path The simple absolute path to the parent. + * @param name The name to give the directory. + * @throws AVMNotFound + * @throws AVMExists + * @throws AVMWrongType + */ public void createDirectory(String path, String name); - + /** - * Create a new layered file. - * @param targetPath The path that is targeted. - * @param parent The path to the parent directory. - * @param name The name for the new file. + * Create a new layered file. + *

+ * Note: the target of the indirection does not need to exist at + * the time the layered file node is created. + * + * @param targetPath The absolute path of the underlying file being pointed at + * @param parent The absolute path of the directory containing layered file to be created + * @param name The name of the layered file to be created + * @throws AVMNotFound + * @throws AVMExists + * @throws AVMWrongType */ public void createLayeredFile(String targetPath, String parent, String name); + /** - * Create a layered directory. - * @param targetPath The path that is targeted. - * @param parent The parent directory. - * @param name The name of the new directory. + * Create a new layered directory. In whatever context this is created, this + * will be a layered directory that has a primary indirection. + *

+ * Note: a "primary" indirection is one in which the target is explicitly set; + * "non-primary" indirect nodes compute their effective target dynamically + * on the basis of their relative position to the closest "primary" + * indirect node that contains them. Therefore, changing the target of a + * "primary" layered directory node immediately alters the indirection + * targets computed by the "non-primary" layered nodes it contains. + *

+ * Note: the target of the indirection does not need to exist at + * the time the layered directory node is created. + * + * @param targetPath The absolute path to the underlying directory that + * the layered directory being created will point at. + * @param parent The absolute path to directory containing the layered directory being created. + * @param name The name of the layered directory being created + * @throws AVMNotFound + * @throws AVMExists + * @throws AVMWrongType */ public void createLayeredDirectory(String targetPath, String parent, String name); - + + /** - * Set a layered directory node to point at a different target. - * @param path The path to the layered directory node. - * @param target The new target. + * Retarget a layered directory. + * Change the target pointed to by a layered directory node. + * This has the side effect of making the layered directory + * a primary indirection if the layered directory's indirection + * was "non-primary". + * + * @param path Path to the layered directory. + * @param target The new indirection target of the layered directory + * @throws AVMNotFoundException + * @throws AVMWrongTypeException */ public void retargetLayeredDirectory(String path, String target); + /** - * Create a new AVMStore. - * @param name The name to give the new store. + * Create a new AVMStore. + * All stores are top level objects within the AVM repository. + * The AVM is a forest of versioned trees; each versioned + * tree is contained within a AVM store with a unique + * name. If a store is removed via + * {@link purgeStore(String name) purgeStore}, the name of + * the deleted store can be reused in a later call to + * {@link createStore(String name) createStore}. + *

+ * The store name must be non-null, cannot be the empty string, + * and must not contain characters that are illegal in + * normal file names. + * + * @param name The name of the new AVMStore. + * @throws AVMExistsException */ public void createStore(String name); + /** - * Create a new branch. - * @param version The version to look under for the source node. - * @param srcPath The path to the source node. - * @param dstPath The path to the destination directory. - * @param name The name of the new branch. + * Create a branch from a given version and path. As a side effect, + * an automatic snapshot is taken of the store that contains the + * node that is being branched from. + * + * @param version The version number from which to make the branch. + * @param srcPath The path to the node to branch from. + * @param dstPath The path to the directory to contain the new branch. + * @param name The name to give the new branch. + * @throws AVMNotFoundException + * @throws AVMExistsException + * @throws AVMWrongTypeException */ public void createBranch(int version, String srcPath, String dstPath, String name); + /** - * Remove a node. - * @param parent The path to the parent directory. - * @param name The name of the node to remove. + * Remove a file or directory from its parent directory. + * In a layered context, the newly deleted node will hide + * a file of the same name in the corresponding layer below. + *

+ * If instead you want to make the file in the lower layer visible + * via transparency, see: + * {@link uncover(String dirPath, String name) uncover}. + * If you want to perform a removal and an uncover + * operation atomically, see: + * {@link #makeTransparent(String dirPath, String name) makeTransparent}. + * + * + *

+ * Caution: this removes directories even if they are not empty. + * + *

+ * Note: developers of records management systems must also + * be aware that the AVMNode corresponding to the + * parent directory and name + * provided might still be accessible via different + * path lookups after this function has completed; + * this because branching and versioning operations create + * manifestations of nodes in a manner that is similar + * to a UNIX hard link. If you need to discover every + * possible path that could retrieve the associated AVMNode, see: + * {@link #getPaths(AVMNodeDescriptor desc) getPaths}, + * {@link #getHeadPaths(AVMNodeDescriptor desc) getHeadPaths}, and + * {@link #getPathsInStoreHead(AVMNodeDescriptor desc) getPathsInStoreHead}. + * + * @param parent The absolute path to the parent directory. + * @param name The name of the child to remove. + * @throws AVMNotFoundException + * @throws AVMWrongTypeException */ public void removeNode(String parent, String name); + + /** - * Rename a node. - * @param srcParent The source directory path. - * @param srcName The source node name. - * @param dstParent The destination directory path. - * @param dstName The destination name for the node. + * Rename a file or directory. + * There are a number of things to note about the + * interaction of rename and layering: + *

+ *

    + *
  • If you rename a layered directory into a non layered context, + * the layered directory continues to point to the same place + * it did before it was renamed, and automatically becomes a + * primary indirection node. + *
  • + * + *
  • If a plain directory is renamed into a layered context it + * remains a plain directory, thus acting as an opaque node + * in its new layered home. + *
  • + * + *
  • Renaming a layered node into a layered node leaves the renamed + * node pointing to the same place it did before the rename and + * makes it automatically a primary indirection node. + *
  • + * + *
  • After a layered node or directory is renamed, + * the directory that contained it acquires a + * "deleted" node in its place; therefore, + * if a layer beneath it contains a file or directory + * with the same name as the "deleted" node, it + * will not be visible via transparency + * (unless an {@link uncover(String dirPath, String name) uncover} + * operation is performed afterwards). + *
  • + *
+ *

+ * + * Note: if instead you want to rename an AVM store, see + * {@link #renameStore(String sourceName, String destName) renameStore}. + * + * @param srcParent The absolute path to the parent directory. + * @param srcName The name of the node in the src directory. + * @param dstParent The absolute path to the destination directory. + * @param dstName The name that the node will have in the destination directory. + * @throws AVMNotFoundException + * @throws AVMExistsException */ public void rename(String srcParent, String srcName, String dstParent, String dstName); + /** - * Uncover a name in a layered directory. - * @param dirPath The path to the directory. - * @param name The name to uncover. + * If a layered directory dirPath + * has a deleted entry of the given name, + * remove that name from the deleted list, + * so that if a layer below it contains an entry + * of this name, it can be seen via transparency + * from dirPath. + *

+ * Note: if you are looking for an atomic operation + * that first deletes an object, then performs + * an "uncover" operation to make it transparent, see + * {@link #makeTransparent(String dirPath, String name) makeTransparent}. + * + * @param dirPath The path to the layered directory. + * @param name The name to uncover. + * @throws AVMNotFoundException + * @throws AVMWrongTypeException */ public void uncover(String dirPath, String name); + /** - * Get the next version id of the given AVMStore. + * Gets the ID that the next snapshotted version of a store + * will have. + * + *

+ * Note: unless the operations that require this value + * to be valid are performed within a transaction, + * this value can become "stale". + * * @param storeName The name of the AVMStore. - * @return The latest version id. + * @return The next version ID of the AVMStore. + * @throws AVMNotFoundException */ public int getNextVersionID(String storeName); + /** - * Get the id of the latest extant snpashot. - * @param storeName The name of the store. - * @return The id. + * Get the latest snapshot ID of a store. + * Note: All stores have at least one snapshot ID: 0; + * this is the "empty" snapshot taken when + * the store is first created. + * + * @param storeName The store name. + * @return The ID of the latest extant version of the store. + * @throws AVMNotFoundException */ public int getLatestSnapshotID(String storeName); + /** - * Snapshot an AVMStore. + * Snapshot the given AVMStore. + * When files have been modified since the previous snapshot, + * a new snapshot version is created; otherwise, no extra + * snapshot is actually taken. + *

+ * When no snapshot is actually taken, but either 'tag' + * or 'store' are non-null, they will override the value for + * the last snapshot (i.e.: the old values will be discarded); + * however, if both 'tag' and 'description' are null then + * invoking createSnapshot when no files have been modified + * becomes a true no-op. + * * @param store The name of the AVMStore to snapshot. - * @return The map of implicitely and explicitely snapshotted stores. + * @param tag The short description. + * @param description The thick description. + * @return A Map of all implicitly or explicitly snapshotted stores to last + * version id. + * @throws AVMNotFoundException */ - public Map createSnapshot(String store, String label, String comment); + public Map createSnapshot(String store, String tag, String description); + /** - * Get a List of all versions in a given store. - * @param name The name of the store. - * @return A List of VersionDescriptors. + * Get the set of versions in an AVMStore. The version ID values + * within this list will always be may appear out of order, + * and may contain missing values (due to the possibility that + * {@link #purgeStore(String name) purgeStore} operations have + * been performed). + * + * Because the number of versions that a store can contain + * may become large, this call can be a resource-intensive, + * and may even causing Out of Memory exceptions. + * + * @param name The name of the AVMStore. + * @return A Set of version descriptors. + * @throws AVMNotFoundException */ public List getStoreVersions(String name); + /** - * Get AVMStore versions between given dates. - * @param name The name of the store. - * @param from The date from which (inclusive). - * @param to The date to which (inclusive). - * @return A List of VersionDescriptors. + * Get AVMStore version descriptors by creation date. Either + * from or to can be null but not both. + *

+ *

    + *
  • + * If from is null, all versions earlier than + * to will be returned. + *
  • + * + *
  • + * If to is null, all versions later than + * from will be returned. + *
  • + *
+ *

+ * + * The order of the values returned is not guaranteed, nor are the version + * IDs necessarily free of "missing" values (due to the possibility that + * {@link #purgeStore(String name) purgeStore} operations have + * been performed). + * + *

+ * Note: for portability, all dates are stored as 64-bit longs, with a + * time resolution of one millisecond. Therefore, aliasing/wrapping + * are not a concern unless you need to plan 292.4 million years ahead. + * If so, please contact your system administrator. + * + * @param name The name of the AVMStore. + * @param from Earliest date of version to include. + * @param to Latest date of version to include. + * @return The Set of version descriptors that match. + * @throws AVMNotFoundException */ public List getStoreVersions(String name, Date from, Date to); /** - * Get a list of all AVM stores. - * @return A List of AVMStoreDescriptors. + * Get the descriptors of all AVMStores in the repository. + * + * @return A List of all AVMStores. */ public List getStores(); + /** - * Get the descriptor for a given AVMStore. - * @param name The name of the store. - * @return An AVMStoreDescriptor. + * Get a descriptor for an AVMStore. + * @param name The AVMStore's name. + * @return A Descriptor, or null if not found. */ public AVMStoreDescriptor getStore(String name); - + + /** - * Get the specified root of the specified store. - * @param version The version number to fetch. - * @param name The name of the store. - * @return The AVMNodeDescriptor for the root. + * A convenience method for getting the specified + * root directory of an AVMStore (e.g.: "mysite:/"). + * + * @param version The version to look up. + * @param name The name of the AVMStore. + * @return A descriptor for the specified root. + * @throws AVMNotFoundException */ public AVMNodeDescriptor getStoreRoot(int version, String name); - + + /** - * Get a descriptor for the specified node. - * @param version The version to look under. - * @param path The path to the node. - * @return An AVMNodeDescriptor. + * Lookup a node identified by version ID and path. + * + * @param version The version ID to look under. + * @param path The simple absolute path to the parent directory. + * @return An AVMNodeDescriptor, or null if the node does not exist. */ public AVMNodeDescriptor lookup(int version, String path); @@ -259,13 +571,16 @@ public interface AVMRemote public AVMNodeDescriptor lookup(int version, String path, boolean includeDeleted); /** - * Get a descriptor for the specified node. - * @param dir The descriptor for the directory node. - * @param name The name of the node to lookup. - * @return An AVMNodeDescriptor. + * Lookup a node identified by the directory node that contains it, and its name. + * + * @param dir The descriptor for the directory node. + * @param name The name to lookup. + * @return The descriptor for the child. + * @throws AVMWrongTypeException If dir does not refer to a directory. */ public AVMNodeDescriptor lookup(AVMNodeDescriptor dir, String name); + /** * Lookup a node identified by the directory that contains it, and its name; * optionally, the lookup can retrive the descriptor of a node even if @@ -279,227 +594,341 @@ public interface AVMRemote * @throws AVMWrongTypeException */ public AVMNodeDescriptor lookup(AVMNodeDescriptor dir, String name, boolean includeDeleted); - + /** - * Get the indirection path for a node. - * @param version The version to look under. - * @param path The path to the node. - * @return The indirection path/target. + * Get a single valid path to a given node. + * @param desc The descriptor of the node to which a version and path will be fetched. + * @return version and path. + * @throws AVMNotFoundException + */ + public Pair getAPath(AVMNodeDescriptor desc); + + + /** + * Get the indirection path for a node in a layered context + * whether that indirection path is primary or non-primary + * (or seen via transparency). + * + * If you call getIndirectionPath on a layered node, + * you'll fetch its explicitly set target; if you call + * this function on a non-primary indirection node or a + * node seen via transparency, you'll get back the path + * to the corresponding node in the underlying target. + *

+ * For example, if "mysite--alice:/www" is a layered + * directory that targets "mysite:/www", and "mysite--alice" + * contains no content directly, then if the path + * path "mysite:/www/avm_webapps/ROOT/x/y/z" is valid, + * calling getIndirectionPath on + * "mysite--alice:/www/avm_webapps/ROOT/x/y/z" will yield + * "mysite:/www/avm_webapps/ROOT/x/y/z". + * + * @param version The version number to get. + * @param path The path to the node of interest. + * @return The indirection path, or null if the path is not in a layered context. + * @throws AVMNotFoundException + * @throws AVMWrongTypeException */ public String getIndirectionPath(int version, String path); - + + /** - * Purge an AVMStore. - * @param name The name of the store to purge. + * Purge an AVMStore. + * This completely removes an AVMStore. + *

+ * Note: while the store being purged disappears from view + * immediately, any nodes that become unreachable as a result + * are deleted asynchronously. + * + * @param name The name of the AVMStore. + * @throws AVMNotFoundException */ public void purgeStore(String name); /** - * Purge a given version from a given store. - * @param version The version id. - * @param name The name of the store. + * Purge a version from an AVMStore. + * Deletes everything that lives in the given version only. + * + * @param version The version to purge. + * @param name The name of the AVMStore from which to purge it. + * @throws AVMNotFoundException If name or version + * do not exist. */ public void purgeVersion(int version, String name); + /** - * Turn a directory into a primary indirection node. - * @param path The path to the directory. + * Make a directory into a primary indirection node. + * @param path The full path. + * @throws AVMNotFoundException + * @throws AVMWrongTypeException */ public void makePrimary(String path); + /** - * Get a list of ancestors of a node. - * @param desc The descriptor of the node whose history is to be fetched. - * @param count The maximum number of ancestors that will be returned. - * @return A List of descriptors for ancestors starting most recent first. + * Get a list of up to count nodes in the history chain of a node. + * The initial element of the list returned will be desc + * (as long as the count is non-zero). + * + * @param desc The descriptor for a node to find ancestors for. + * @param count maximum number of ancestors to return in the list + * (the value -1 means + * "no limit -- return them all") + * @return A List of ancestors starting with the most recent. + * @throws AVMNotFoundException */ public List getHistory(AVMNodeDescriptor desc, int count); /** - * Turn on or off a directory's opacity. - * @param path The path to the directory. - * @param opacity Whether the directory should be opaque or not. + * Set the opacity of a layered directory. + * An opaque layered directory hides the contents of its indirection. + * + * @param path The path to the layered directory. + * @throws AVMNotFoundException + * @throws AVMWrongTypeException */ public void setOpacity(String path, boolean opacity); /** - * Get the most recent common ancestor of two nodes. - * @param left One node. - * @param right The other node. - * @return The common ancestor. + * Get the common ancestor of two nodes if a common ancestor exists. + * This function is useful for detecting and merging conflicts. + * + * @param left The first node. + * @param right The second node. + * @return The common ancestor. There are four possible results. Null means + * that there is no common ancestor. Left returned means that left is strictly + * an ancestor of right. Right returned means that right is strictly an + * ancestor of left. Any other non null return is the common ancestor and + * indicates that left and right are in conflict. + * @throws AVMNotFoundException */ - public AVMNodeDescriptor getCommonAncestor(AVMNodeDescriptor left, AVMNodeDescriptor right); + public AVMNodeDescriptor getCommonAncestor(AVMNodeDescriptor left, + AVMNodeDescriptor right); /** * Get layering information about a path. + * The LayeringDescriptor returned can be used to determine + * whether a node is in the background (and if so, which + * AVM store contains it directly), or if it is directly + * contained by the AVM store referenced by path. + * + * * @param version The version to look under. - * @param path The path to the node. - * @return A LayeringDescriptor. + * @param path The absolute AVM path. + * @return A LayeringDescriptor. + * @throws AVMNotFoundException + * @throws AVMWrongTypeException */ public LayeringDescriptor getLayeringInfo(int version, String path); /** * Set a property on a node. - * @param path The path to the node. - * @param name The name of the property. - * @param value The value to give the property. + * + * @param path The path to the node to set the property on. + * @param name The QName of the property. + * @param value The property to set. + * @throws AVMNotFoundException + * @throws AVMWrongTypeException */ public void setNodeProperty(String path, QName name, PropertyValue value); /** - * Set a group of properties on a node. - * @param path The path to the node. - * @param properties A Map of QNames to PropertyValues to set. + * Set a collection of properties on a node. + * + * @param path The path to the node. + * @param properties The Map of properties to set. + * @throws AVMNotFoundException + * @throws AVMWrongTypeException */ public void setNodeProperties(String path, Map properties); /** - * Get the value of a node property. + * Get a property of a node by QName. + * * @param version The version to look under. - * @param path The path to the node. - * @param name The name of the property. - * @return A PropertyValue. + * @param path The path to the node. + * @param name The QName. + * @return The PropertyValue or null if it doesn't exist. + * @throws AVMNotFoundException + * @throws AVMWrongTypeException */ public PropertyValue getNodeProperty(int version, String path, QName name); /** - * Get all properties of a node. - * @param version The version. - * @param path The path to the node. - * @return A Map of QNames to PropertyValues. + * Get all the properties associated with a node that is identified + * by a version ID and a path. + * + * @param version The version to look under. + * @param path The path to the node. + * @return A Map of QNames to PropertyValues. + * @throws AVMNotFoundException */ public Map getNodeProperties(int version, String path); - + + /** - * Delete a property from a node. + * Delete a property. + *

+ * Note: to remove an apsect, see: {@link #removeAspect(String path, QName aspectName) removeAspect} + * * @param path The path to the node. - * @param name The name of the property. + * @param name The QName of the property to delete. + * @throws AVMNotFoundException */ public void deleteNodeProperty(String path, QName name); /** - * Delete all properties from a node. + * Delete all the properties attached to an AVM node. + *

+ * Note: to remove an apsect, see: {@link #removeAspect(String path, QName aspectName) removeAspect} + * * @param path The path to the node. + * @throws AVMNotFoundException */ public void deleteNodeProperties(String path); /** - * Set a property on a store. - * @param store The name of the store. - * @param name The name of the property to set. - * @param value The value of the property to set. + * Set a property on a store. If the property exists it will be overwritten. + * + * @param store The store to set the property on. + * @param name The name of the property. + * @param value The value of the property. + * @throws AVMNotFoundException */ public void setStoreProperty(String store, QName name, PropertyValue value); /** - * Set a group of properties on a store. + * Set a group of properties on a store. Existing properties will be overwritten. + * * @param store The name of the store. - * @param props A Map of QNames to PropertyValues to set. + * @param props A Map of the properties to set. + * @throws AVMNotFoundException */ public void setStoreProperties(String store, Map props); /** * Get a property from a store. + * * @param store The name of the store. - * @param name The name of the property. - * @return A PropertyValue. + * @param name The name of the property. + * @return A PropertyValue or null if non-existent. + * @throws AVMNotFoundException */ public PropertyValue getStoreProperty(String store, QName name); - + /** - * Query a store for keys that match a pattern. - * @param store The store name. - * @param keyPattern The sql 'like' pattern. - * @return A Map of keys to values. + * Get all the properties associated with a store. + * + * @param store The name of the store. + * @return A Map of the stores properties. + * @throws AVMNotFoundException + */ + public Map getStoreProperties(String store); + + /** + * Queries a given store for properties with keys that match a given pattern. + * + * @param store The name of the store. + * @param keyPattern The sql 'like' pattern, inserted into a QName. + * @return A Map of the matching key value pairs. */ public Map queryStorePropertyKey(String store, QName keyPattern); - + + /** - * Query all stores for keys that match a pattern. - * @param keyPattern The sql 'like' pattern. - * @return A Map of store names to Maps of matching keys to values. + * Queries a given store for properties with keys that match a given pattern. + * + * @param store The name of the store. + * @param keyPattern The sql 'like' pattern, inserted into a QName. + * @return A Map of the matching key value pairs. */ public Map> queryStoresPropertyKey(QName keyPattern); - /** - * Get all the properties on a store. - * @param store The name of the store. - * @return A Map of QNames to PropertyValues. - */ - public Map getStoreProperties(String store); /** - * Delete a property from a store. + * Delete a property on a store by name. + *

+ * Note: to remove an apsect, see: {@link #removeAspect(String path, QName aspectName) removeAspect} + * * @param store The name of the store. - * @param name The name of the property. + * @param name The name of the property to delete. + * @throws AVMNotFoundException */ public void deleteStoreProperty(String store, QName name); - /** - * Rename a store. - * @param sourceName The original name. - * @param destName The new name. - */ - public void renameStore(String sourceName, String destName); /** * Add an aspect to an AVM node. - * @param path The path to the node. + * + * @param path The path to the node. * @param aspectName The QName of the aspect. - * @throws AVMNotFoundException - * @throws AVMExistsException + * @throws AVMNotFoundException + * @throws AVMExistsException */ public void addAspect(String path, QName aspectName); - + /** * Get all the aspects on an AVM node. + * * @param version The version to look under. - * @param path The path to the node. - * @return A List of the QNames of the aspects. - * @throws AVMNotFoundException + * @param path The path to the node. + * @return A Set of the QNames of the aspects. + * @throws AVMNotFoundException */ public Set getAspects(int version, String path); + /** * Remove an aspect and its properties from a node. - * @param path The path to the node. + * + * @param path The path to the node. * @param aspectName The name of the aspect. - * @throws AVMNotFoundException + * @throws AVMNotFoundException */ public void removeAspect(String path, QName aspectName); /** - * Does a node have a particular aspect. - * @param version The version to look under. - * @param path The path to the node. + * Determines whether a node has a particular aspect. + * + * @param version The version to look under. + * @param path The path to the node. * @param aspectName The aspect name to check. - * @return Whether the given node has the given aspect. - * @throws AVMNotFoundException + * @return Whether the given node has the given aspect. + * @throws AVMNotFoundException */ public boolean hasAspect(int version, String path, QName aspectName); + + + /** + * Rename a store. + * + * @param sourceName The original name. + * @param destName The new name. + * @throws AVMNotFoundException + * @throws AVMExistsException + */ + public void renameStore(String sourceName, String destName); /** - * Revert a head path to a given version. This works by cloning - * the version to revert to, and then linking that new version into head. - * The reverted version will have the previous head version as ancestor. - * @param path The path to the node to revert. + * Revert a HEAD path to a given version. + * This works by cloning the version to revert to, and then linking + * that new version into HEAD. + * The reverted version will have the previous + * HEAD version as ancestor. + * + * @param path The path to the node to revert. * @param toRevertTo The descriptor of the version to revert to. - * @throws AVMNotFoundException + * @throws AVMNotFoundException */ - public void revert(String path, AVMNodeDescriptor toRevertTo); - + public void revert(String path, AVMNodeDescriptor toRevertTo); + + /** - * Get a version and path of a node. - * @param desc The descriptor for the node to which we want a path. - * @return version and path. - * @throws AVMNotFoundException - */ - public Pair getAPath(AVMNodeDescriptor desc); - - /** - * Set the GUID of a node. + * Set the GUID on a node. The GUID of a node uniquely identifies + * the state of a node, i.e. its content, metadata, and aspects. * @param path The path to the node. - * @param guid The GUID. + * @param guid The GUID to set. */ public void setGuid(String path, String guid); @@ -516,4 +945,54 @@ public interface AVMRemote * @param encoding The encoding. */ public void setEncoding(String path, String encoding); + + + // To be included in AVMRemote eventually (y/n) + // | + // V + // + // n public ContentReader getContentReader(int version, String path); + // n public ContentWriter getContentWriter(String path); + // n public ContentData getContentDataForRead(int version, String path); + // n public ContentData getContentDataForRead(AVMNodeDescriptor desc); + // n public ContentData getContentDataForWrite(String path); + // n public void setContentData(String path, ContentData data); + // y public SortedMap getDirectoryListing(int version, String path, + // boolean includeDeleted); + // y public SortedMap + // getDirectoryListingDirect(int version, String path, boolean includeDeleted); + // + // y public AVMNodeDescriptor [] getDirectoryListingArray(int version, String path, + // boolean includeDeleted); + // + // y public SortedMap getDirectoryListing(AVMNodeDescriptor dir, + // boolean includeDeleted); + // + // y public AVMNodeDescriptor [] getDirectoryListingArray(AVMNodeDescriptor dir, + // boolean includeDeleted); + // + // + // y public void createFile(String path, String name, InputStream in); + // y public void createFile(String path, String name, InputStream in, List aspects, Map properties); + // + // y public void createDirectory(String path, String name, List aspects, Map properties); + // y public void removeNode(String path); + // y public void makeTransparent(String dirPath, String name); + // y public AVMStoreDescriptor getSystemStore(); + // y public List> getPaths(AVMNodeDescriptor desc); + // y public List> getHeadPaths(AVMNodeDescriptor desc); + // y public List> getPathsInStoreHead(AVMNodeDescriptor desc, String store); + // y public List getPathsInStoreVersion(AVMNodeDescriptor desc, String store, int version); + // y public Map getNodeProperties(AVMNodeDescriptor desc); + // + // y public Map> + // queryStoresPropertyKeys(QName keyPattern); + // + // y public void setMetaDataFrom(String path, AVMNodeDescriptor from); + // y public Set getAspects(AVMNodeDescriptor desc); + // y public void link(String parentPath, String name, AVMNodeDescriptor toLink); + // y public AVMNodeDescriptor forceCopy(String path); + // y public void copy(int srcVersion, String srcPath, String dstPath, String name); + + }