diff --git a/source/java/org/alfresco/repo/action/executer/MailActionExecuter.java b/source/java/org/alfresco/repo/action/executer/MailActionExecuter.java
index 79cecafb08..788ce132c6 100644
--- a/source/java/org/alfresco/repo/action/executer/MailActionExecuter.java
+++ b/source/java/org/alfresco/repo/action/executer/MailActionExecuter.java
@@ -39,13 +39,13 @@ import org.alfresco.repo.action.ParameterDefinitionImpl;
import org.alfresco.repo.template.DateCompareMethod;
import org.alfresco.repo.template.HasAspectMethod;
import org.alfresco.repo.template.I18NMessageMethod;
+import org.alfresco.repo.template.TemplateNode;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.action.Action;
import org.alfresco.service.cmr.action.ParameterDefinition;
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
-import org.alfresco.service.cmr.repository.TemplateNode;
import org.alfresco.service.cmr.repository.TemplateService;
import org.alfresco.service.cmr.security.AuthenticationService;
import org.alfresco.service.cmr.security.AuthorityService;
diff --git a/source/java/org/alfresco/repo/action/scheduled/FreeMarkerWithLuceneExtensionsModelFactory.java b/source/java/org/alfresco/repo/action/scheduled/FreeMarkerWithLuceneExtensionsModelFactory.java
index 90bb093a8c..75ccd27697 100644
--- a/source/java/org/alfresco/repo/action/scheduled/FreeMarkerWithLuceneExtensionsModelFactory.java
+++ b/source/java/org/alfresco/repo/action/scheduled/FreeMarkerWithLuceneExtensionsModelFactory.java
@@ -31,10 +31,10 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import org.alfresco.repo.template.TemplateNode;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.StoreRef;
-import org.alfresco.service.cmr.repository.TemplateNode;
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
import org.alfresco.service.cmr.repository.datatype.Duration;
import org.alfresco.service.cmr.search.ResultSet;
diff --git a/source/java/org/alfresco/repo/jscript/CategoryTemplateNode.java b/source/java/org/alfresco/repo/jscript/CategoryTemplateNode.java
index 6bac982c9d..929439993a 100644
--- a/source/java/org/alfresco/repo/jscript/CategoryTemplateNode.java
+++ b/source/java/org/alfresco/repo/jscript/CategoryTemplateNode.java
@@ -30,11 +30,11 @@ import java.util.Collections;
import java.util.List;
import org.alfresco.model.ContentModel;
+import org.alfresco.repo.template.TemplateNode;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.TemplateImageResolver;
-import org.alfresco.service.cmr.repository.TemplateNode;
import org.alfresco.service.cmr.search.CategoryService;
import org.alfresco.service.namespace.QName;
diff --git a/source/java/org/alfresco/repo/jscript/Node.java b/source/java/org/alfresco/repo/jscript/Node.java
index 0f4f58da74..6bdbf8553c 100644
--- a/source/java/org/alfresco/repo/jscript/Node.java
+++ b/source/java/org/alfresco/repo/jscript/Node.java
@@ -40,6 +40,7 @@ import org.alfresco.repo.action.executer.TransformActionExecuter;
import org.alfresco.repo.content.transform.magick.ImageMagickContentTransformer;
import org.alfresco.repo.search.QueryParameterDefImpl;
import org.alfresco.repo.template.FreeMarkerProcessor;
+import org.alfresco.repo.template.TemplateNode;
import org.alfresco.repo.version.VersionModel;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
@@ -56,7 +57,6 @@ 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.TemplateImageResolver;
-import org.alfresco.service.cmr.repository.TemplateNode;
import org.alfresco.service.cmr.search.QueryParameterDefinition;
import org.alfresco.service.cmr.security.AccessStatus;
import org.alfresco.service.cmr.security.PermissionService;
diff --git a/source/java/org/alfresco/repo/model/filefolder/FileFolderServiceImpl.java b/source/java/org/alfresco/repo/model/filefolder/FileFolderServiceImpl.java
index 7f1a3f87ef..b9251c9e74 100644
--- a/source/java/org/alfresco/repo/model/filefolder/FileFolderServiceImpl.java
+++ b/source/java/org/alfresco/repo/model/filefolder/FileFolderServiceImpl.java
@@ -331,6 +331,20 @@ public class FileFolderServiceImpl implements FileFolderService
}
return childNodeRef;
}
+
+ public NodeRef searchSimple(NodeRef contextNodeRef, String name, QName assocName)
+ {
+ NodeRef childNodeRef = nodeService.getChildByName(contextNodeRef, assocName, name);
+ if (logger.isDebugEnabled())
+ {
+ logger.debug(
+ "Simple name search results: \n" +
+ " parent: " + contextNodeRef + "\n" +
+ " name: " + name + "\n" +
+ " result: " + childNodeRef);
+ }
+ return childNodeRef;
+ }
/**
* @see #search(NodeRef, String, boolean, boolean, boolean)
@@ -822,12 +836,21 @@ public class FileFolderServiceImpl implements FileFolderService
}
// walk the folder tree first
NodeRef parentNodeRef = rootNodeRef;
- StringBuilder currentPath = new StringBuilder(pathElements.size() * 20);
+ StringBuilder currentPath = new StringBuilder(pathElements.size() << 4);
int folderCount = pathElements.size() - 1;
for (int i = 0; i < folderCount; i++)
{
String pathElement = pathElements.get(i);
- NodeRef folderNodeRef = searchSimple(parentNodeRef, pathElement);
+ NodeRef folderNodeRef;
+ if (i == 0 && rootNodeRef.equals(nodeService.getRootNode(rootNodeRef.getStoreRef())))
+ {
+ // store root nodes use a different assoc name to the immediate children
+ folderNodeRef = searchSimple(parentNodeRef, pathElement, ContentModel.ASSOC_CHILDREN);
+ }
+ else
+ {
+ folderNodeRef = searchSimple(parentNodeRef, pathElement);
+ }
if (folderNodeRef == null)
{
StringBuilder sb = new StringBuilder(128);
diff --git a/source/java/org/alfresco/repo/template/BaseContentNode.java b/source/java/org/alfresco/repo/template/BaseContentNode.java
new file mode 100644
index 0000000000..4e072b0cd5
--- /dev/null
+++ b/source/java/org/alfresco/repo/template/BaseContentNode.java
@@ -0,0 +1,292 @@
+/*
+ * Copyright (C) 2005-2007 Alfresco Software Limited.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ * As a special exception to the terms and conditions of version 2.0 of
+ * the GPL, you may redistribute this Program in connection with Free/Libre
+ * and Open Source Software ("FLOSS") applications as described in Alfresco's
+ * FLOSS exception. You should have recieved a copy of the text describing
+ * the FLOSS exception, and it is also available here:
+ * http://www.alfresco.com/legal/licensing
+ */
+package org.alfresco.repo.template;
+
+import java.io.Serializable;
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.text.MessageFormat;
+
+import org.alfresco.model.ContentModel;
+import org.alfresco.repo.content.MimetypeMap;
+import org.alfresco.service.ServiceRegistry;
+import org.alfresco.service.cmr.dictionary.DictionaryService;
+import org.alfresco.service.cmr.repository.ContentData;
+import org.alfresco.service.cmr.repository.ContentReader;
+import org.alfresco.service.cmr.repository.ContentService;
+import org.alfresco.service.cmr.repository.ContentWriter;
+import org.alfresco.service.cmr.repository.TemplateException;
+import org.alfresco.service.namespace.QName;
+import org.springframework.util.StringUtils;
+
+/**
+ * @author Kevin Roast
+ */
+public abstract class BaseContentNode implements TemplateContent
+{
+ protected final static String CONTENT_DEFAULT_URL = "/download/direct/{0}/{1}/{2}/{3}";
+ protected final static String CONTENT_PROP_URL = "/download/direct/{0}/{1}/{2}/{3}?property={4}";
+ protected final static String FOLDER_BROWSE_URL = "/navigate/browse/{0}/{1}/{2}";
+
+ protected ServiceRegistry services = null;
+
+ private Boolean isDocument = null;
+ private Boolean isContainer = null;
+
+ /**
+ * @return true if this Node is a container (i.e. a folder)
+ */
+ public boolean getIsContainer()
+ {
+ if (isContainer == null)
+ {
+ DictionaryService dd = this.services.getDictionaryService();
+ isContainer = Boolean.valueOf( (dd.isSubClass(getType(), ContentModel.TYPE_FOLDER) == true &&
+ dd.isSubClass(getType(), ContentModel.TYPE_SYSTEM_FOLDER) == false) );
+ }
+
+ return isContainer.booleanValue();
+ }
+
+ /**
+ * @return true if this Node is a Document (i.e. with content)
+ */
+ public boolean getIsDocument()
+ {
+ if (isDocument == null)
+ {
+ DictionaryService dd = this.services.getDictionaryService();
+ isDocument = Boolean.valueOf(dd.isSubClass(getType(), ContentModel.TYPE_CONTENT));
+ }
+
+ return isDocument.booleanValue();
+ }
+
+ /**
+ * Override Object.toString() to provide useful debug output
+ */
+ public String toString()
+ {
+ if (this.services.getNodeService().exists(getNodeRef()))
+ {
+ return "Node Type: " + getType() +
+ "\tNode Ref: " + getNodeRef().toString();
+ }
+ else
+ {
+ return "Node no longer exists: " + getNodeRef();
+ }
+ }
+
+
+ // ------------------------------------------------------------------------------
+ // Content API
+
+ /**
+ * @return the content String for this node from the default content property
+ * (@see ContentModel.PROP_CONTENT)
+ */
+ public String getContent()
+ {
+ TemplateContentData content = (TemplateContentData)this.getProperties().get(ContentModel.PROP_CONTENT);
+ return content != null ? content.getContent() : "";
+ }
+
+ /**
+ * @return For a content document, this method returns the URL to the content stream for
+ * the default content property (@see ContentModel.PROP_CONTENT)
+ *
+ * For a container node, this method return the URL to browse to the folder in the web-client
+ */
+ public String getUrl()
+ {
+ if (getIsDocument() == true)
+ {
+ try
+ {
+ return MessageFormat.format(CONTENT_DEFAULT_URL, new Object[] {
+ getNodeRef().getStoreRef().getProtocol(),
+ getNodeRef().getStoreRef().getIdentifier(),
+ getNodeRef().getId(),
+ StringUtils.replace(URLEncoder.encode(getName(), "UTF-8"), "+", "%20") } );
+ }
+ catch (UnsupportedEncodingException err)
+ {
+ throw new TemplateException("Failed to encode content URL for node: " + getNodeRef(), err);
+ }
+ }
+ else
+ {
+ return MessageFormat.format(FOLDER_BROWSE_URL, new Object[] {
+ getNodeRef().getStoreRef().getProtocol(),
+ getNodeRef().getStoreRef().getIdentifier(),
+ getNodeRef().getId() } );
+ }
+ }
+
+ /**
+ * @return The mimetype encoding for content attached to the node from the default content property
+ * (@see ContentModel.PROP_CONTENT)
+ */
+ public String getMimetype()
+ {
+ TemplateContentData content = (TemplateContentData)this.getProperties().get(ContentModel.PROP_CONTENT);
+ return (content != null ? content.getMimetype() : null);
+ }
+
+ /**
+ * @return The size in bytes of the content attached to the node from the default content property
+ * (@see ContentModel.PROP_CONTENT)
+ */
+ public long getSize()
+ {
+ TemplateContentData content = (TemplateContentData)this.getProperties().get(ContentModel.PROP_CONTENT);
+ return (content != null ? content.getSize() : 0L);
+ }
+
+
+ // ------------------------------------------------------------------------------
+ // Inner classes
+
+ /**
+ * Inner class wrapping and providing access to a ContentData property
+ */
+ public class TemplateContentData implements Serializable
+ {
+ /**
+ * Constructor
+ *
+ * @param contentData The ContentData object this object wraps
+ * @param property The property the ContentData is attached too
+ */
+ public TemplateContentData(ContentData contentData, QName property)
+ {
+ this.contentData = contentData;
+ this.property = property;
+ }
+
+ /**
+ * @return the content stream
+ */
+ public String getContent()
+ {
+ ContentService contentService = services.getContentService();
+ ContentReader reader = contentService.getReader(getNodeRef(), property);
+
+ return (reader != null && reader.exists()) ? reader.getContentString() : "";
+ }
+
+ /**
+ * @return the content stream to the specified maximum length in characters
+ */
+ public String getContent(int length)
+ {
+ ContentService contentService = services.getContentService();
+ ContentReader reader = contentService.getReader(getNodeRef(), property);
+
+ return (reader != null && reader.exists()) ? reader.getContentString(length) : "";
+ }
+
+ /**
+ * @param length Length of the character stream to return, or -1 for all
+ *
+ * @return the binary content stream converted to text using any available transformer
+ * if fails to convert then null will be returned
+ */
+ public String getContentAsText(int length)
+ {
+ String result = null;
+
+ if (MimetypeMap.MIMETYPE_TEXT_PLAIN.equals(getMimetype()))
+ {
+ result = getContent(length);
+ }
+ else
+ {
+ // get the content reader
+ ContentService contentService = services.getContentService();
+ ContentReader reader = contentService.getReader(getNodeRef(), property);
+
+ // get the writer and set it up for text convert
+ ContentWriter writer = contentService.getWriter(null, ContentModel.PROP_CONTENT, true);
+ writer.setMimetype("text/plain");
+ writer.setEncoding(reader.getEncoding());
+
+ // try and transform the content
+ if (contentService.isTransformable(reader, writer))
+ {
+ contentService.transform(reader, writer);
+
+ ContentReader resultReader = writer.getReader();
+ if (resultReader != null && reader.exists())
+ {
+ if (length != -1)
+ {
+ result = resultReader.getContentString(length);
+ }
+ else
+ {
+ result = resultReader.getContentString();
+ }
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * @return
+ */
+ public String getUrl()
+ {
+ try
+ {
+ return MessageFormat.format(CONTENT_PROP_URL, new Object[] {
+ getNodeRef().getStoreRef().getProtocol(),
+ getNodeRef().getStoreRef().getIdentifier(),
+ getNodeRef().getId(),
+ StringUtils.replace(URLEncoder.encode(getName(), "UTF-8"), "+", "%20"),
+ StringUtils.replace(URLEncoder.encode(property.toString(), "UTF-8"), "+", "%20") } );
+ }
+ catch (UnsupportedEncodingException err)
+ {
+ throw new TemplateException("Failed to encode content URL for node: " + getNodeRef(), err);
+ }
+ }
+
+ public long getSize()
+ {
+ return contentData.getSize();
+ }
+
+ public String getMimetype()
+ {
+ return contentData.getMimetype();
+ }
+
+ private ContentData contentData;
+ private QName property;
+ }
+}
diff --git a/source/java/org/alfresco/repo/template/BasePathResultsMap.java b/source/java/org/alfresco/repo/template/BasePathResultsMap.java
index b00ea3c2e2..ada739ce32 100644
--- a/source/java/org/alfresco/repo/template/BasePathResultsMap.java
+++ b/source/java/org/alfresco/repo/template/BasePathResultsMap.java
@@ -30,7 +30,6 @@ import java.util.List;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.repository.NodeRef;
-import org.alfresco.service.cmr.repository.TemplateNode;
import org.alfresco.service.cmr.search.QueryParameterDefinition;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
diff --git a/source/java/org/alfresco/repo/template/BasePermissionsNode.java b/source/java/org/alfresco/repo/template/BasePermissionsNode.java
new file mode 100644
index 0000000000..515234f8dc
--- /dev/null
+++ b/source/java/org/alfresco/repo/template/BasePermissionsNode.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2005-2007 Alfresco Software Limited.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ * As a special exception to the terms and conditions of version 2.0 of
+ * the GPL, you may redistribute this Program in connection with Free/Libre
+ * and Open Source Software ("FLOSS") applications as described in Alfresco's
+ * FLOSS exception. You should have recieved a copy of the text describing
+ * the FLOSS exception, and it is also available here:
+ * http://www.alfresco.com/legal/licensing
+ */
+package org.alfresco.repo.template;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+import org.alfresco.service.cmr.security.AccessPermission;
+import org.alfresco.service.cmr.security.AccessStatus;
+
+/**
+ * @author Kevin Roast
+ */
+public abstract class BasePermissionsNode extends BaseContentNode implements TemplatePermissions
+{
+ private List permissions = null;
+
+ // ------------------------------------------------------------------------------
+ // Security API
+
+ /**
+ * @return List of permissions applied to this Node.
+ * Strings returned are of the format [ALLOWED|DENIED];[USERNAME|GROUPNAME];PERMISSION for example
+ * ALLOWED;kevinr;Consumer so can be easily tokenized on the ';' character.
+ */
+ public List getPermissions()
+ {
+ if (this.permissions == null)
+ {
+ String userName = this.services.getAuthenticationService().getCurrentUserName();
+ this.permissions = new ArrayList(4);
+ Set acls = this.services.getPermissionService().getAllSetPermissions(getNodeRef());
+ for (AccessPermission permission : acls)
+ {
+ StringBuilder buf = new StringBuilder(64);
+ buf.append(permission.getAccessStatus())
+ .append(';')
+ .append(permission.getAuthority())
+ .append(';')
+ .append(permission.getPermission());
+ this.permissions.add(buf.toString());
+ }
+ }
+ return this.permissions;
+ }
+
+ /**
+ * @return true if this node inherits permissions from its parent node, false otherwise.
+ */
+ public boolean getInheritsPermissions()
+ {
+ return this.services.getPermissionService().getInheritParentPermissions(getNodeRef());
+ }
+
+ /**
+ * @param permission Permission name to test
+ *
+ * @return true if the current user is granted the specified permission on the node
+ */
+ public boolean hasPermission(String permission)
+ {
+ return (this.services.getPermissionService().hasPermission(getNodeRef(), permission) == AccessStatus.ALLOWED);
+ }
+}
diff --git a/source/java/org/alfresco/repo/template/BaseSearchResultsMap.java b/source/java/org/alfresco/repo/template/BaseSearchResultsMap.java
index abc30e4132..949d2d73c5 100644
--- a/source/java/org/alfresco/repo/template/BaseSearchResultsMap.java
+++ b/source/java/org/alfresco/repo/template/BaseSearchResultsMap.java
@@ -32,7 +32,6 @@ 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.TemplateNode;
import org.alfresco.service.cmr.search.ResultSet;
import org.alfresco.service.cmr.search.ResultSetRow;
import org.alfresco.service.cmr.search.SearchService;
diff --git a/source/java/org/alfresco/repo/template/BaseTemplateExtensionImplementation.java b/source/java/org/alfresco/repo/template/BaseTemplateExtensionImplementation.java
index 4161d46055..82d4a32bf7 100644
--- a/source/java/org/alfresco/repo/template/BaseTemplateExtensionImplementation.java
+++ b/source/java/org/alfresco/repo/template/BaseTemplateExtensionImplementation.java
@@ -1,18 +1,26 @@
/*
- * Copyright (C) 2005 Alfresco, Inc.
+ * Copyright (C) 2005-2007 Alfresco Software Limited.
*
- * Licensed under the Mozilla Public License version 1.1
- * with a permitted attribution clause. You may obtain a
- * copy of the License at
- *
- * http://www.alfresco.org/legal/license.txt
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
- * either express or implied. See the License for the specific
- * language governing permissions and limitations under the
- * License.
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ * As a special exception to the terms and conditions of version 2.0 of
+ * the GPL, you may redistribute this Program in connection with Free/Libre
+ * and Open Source Software ("FLOSS") applications as described in Alfresco's
+ * FLOSS exception. You should have recieved a copy of the text describing
+ * the FLOSS exception, and it is also available here:
+ * http://www.alfresco.com/legal/licensing
*/
package org.alfresco.repo.template;
diff --git a/source/java/org/alfresco/repo/template/BaseTemplateMap.java b/source/java/org/alfresco/repo/template/BaseTemplateMap.java
index ffdc8f3764..bdd012e1e7 100644
--- a/source/java/org/alfresco/repo/template/BaseTemplateMap.java
+++ b/source/java/org/alfresco/repo/template/BaseTemplateMap.java
@@ -27,7 +27,6 @@ package org.alfresco.repo.template;
import java.util.HashMap;
import org.alfresco.service.ServiceRegistry;
-import org.alfresco.service.cmr.repository.TemplateNode;
/**
* An abstract Map class that can be used process the parent Node as part of the get()
diff --git a/source/java/org/alfresco/repo/template/CropContentMethod.java b/source/java/org/alfresco/repo/template/CropContentMethod.java
index 6e0eda4f8f..4f6f7052cc 100644
--- a/source/java/org/alfresco/repo/template/CropContentMethod.java
+++ b/source/java/org/alfresco/repo/template/CropContentMethod.java
@@ -26,9 +26,7 @@ package org.alfresco.repo.template;
import java.util.List;
-import org.alfresco.model.ContentModel;
-import org.alfresco.service.cmr.repository.TemplateNode;
-import org.alfresco.service.cmr.repository.TemplateNode.TemplateContentData;
+import org.alfresco.repo.template.BaseContentNode.TemplateContentData;
import freemarker.ext.beans.BeanModel;
import freemarker.template.TemplateMethodModelEx;
diff --git a/source/java/org/alfresco/repo/template/FreeMarkerProcessor.java b/source/java/org/alfresco/repo/template/FreeMarkerProcessor.java
index 6f6d5924ca..aa55c358e8 100644
--- a/source/java/org/alfresco/repo/template/FreeMarkerProcessor.java
+++ b/source/java/org/alfresco/repo/template/FreeMarkerProcessor.java
@@ -37,7 +37,6 @@ import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.TemplateException;
import org.alfresco.service.cmr.repository.TemplateExtensionImplementation;
import org.alfresco.service.cmr.repository.TemplateImageResolver;
-import org.alfresco.service.cmr.repository.TemplateNode;
import org.alfresco.service.cmr.repository.TemplateProcessor;
import org.apache.log4j.Logger;
diff --git a/source/java/org/alfresco/repo/template/HasAspectMethod.java b/source/java/org/alfresco/repo/template/HasAspectMethod.java
index 5a3c167b08..f08e4d6701 100644
--- a/source/java/org/alfresco/repo/template/HasAspectMethod.java
+++ b/source/java/org/alfresco/repo/template/HasAspectMethod.java
@@ -26,7 +26,6 @@ package org.alfresco.repo.template;
import java.util.List;
-import org.alfresco.service.cmr.repository.TemplateNode;
import freemarker.ext.beans.BeanModel;
import freemarker.template.TemplateMethodModelEx;
diff --git a/source/java/org/alfresco/repo/template/HasPermissionMethod.java b/source/java/org/alfresco/repo/template/HasPermissionMethod.java
index d3b8bb7b10..2f1bc8e28c 100644
--- a/source/java/org/alfresco/repo/template/HasPermissionMethod.java
+++ b/source/java/org/alfresco/repo/template/HasPermissionMethod.java
@@ -26,7 +26,6 @@ package org.alfresco.repo.template;
import java.util.List;
-import org.alfresco.service.cmr.repository.TemplateNode;
import freemarker.ext.beans.BeanModel;
import freemarker.template.TemplateMethodModelEx;
diff --git a/source/java/org/alfresco/repo/template/LuceneSearchResultsMap.java b/source/java/org/alfresco/repo/template/LuceneSearchResultsMap.java
index d94fe2498c..cf2889f84c 100644
--- a/source/java/org/alfresco/repo/template/LuceneSearchResultsMap.java
+++ b/source/java/org/alfresco/repo/template/LuceneSearchResultsMap.java
@@ -31,7 +31,6 @@ import org.alfresco.model.ContentModel;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.NodeRef;
-import org.alfresco.service.cmr.repository.TemplateNode;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
diff --git a/source/java/org/alfresco/repo/template/NamePathResultsMap.java b/source/java/org/alfresco/repo/template/NamePathResultsMap.java
index 4228e0544f..18b64fe1e7 100644
--- a/source/java/org/alfresco/repo/template/NamePathResultsMap.java
+++ b/source/java/org/alfresco/repo/template/NamePathResultsMap.java
@@ -30,7 +30,6 @@ import java.util.StringTokenizer;
import org.alfresco.repo.search.QueryParameterDefImpl;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
-import org.alfresco.service.cmr.repository.TemplateNode;
import org.alfresco.service.cmr.search.QueryParameterDefinition;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
diff --git a/source/java/org/alfresco/repo/template/NodeSearchResultsMap.java b/source/java/org/alfresco/repo/template/NodeSearchResultsMap.java
index 1a1a7c59c5..3c16b7e69b 100644
--- a/source/java/org/alfresco/repo/template/NodeSearchResultsMap.java
+++ b/source/java/org/alfresco/repo/template/NodeSearchResultsMap.java
@@ -28,7 +28,6 @@ import java.util.List;
import org.alfresco.repo.search.impl.lucene.LuceneQueryParser;
import org.alfresco.service.ServiceRegistry;
-import org.alfresco.service.cmr.repository.TemplateNode;
/**
* Provides functionality to execute a Lucene search for a single node by NodeRef.
diff --git a/source/java/org/alfresco/repo/template/SavedSearchResultsMap.java b/source/java/org/alfresco/repo/template/SavedSearchResultsMap.java
index 17b3d4482f..3676d178ba 100644
--- a/source/java/org/alfresco/repo/template/SavedSearchResultsMap.java
+++ b/source/java/org/alfresco/repo/template/SavedSearchResultsMap.java
@@ -31,7 +31,6 @@ import org.alfresco.model.ContentModel;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.NodeRef;
-import org.alfresco.service.cmr.repository.TemplateNode;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
diff --git a/source/java/org/alfresco/repo/template/TemplateContent.java b/source/java/org/alfresco/repo/template/TemplateContent.java
new file mode 100644
index 0000000000..967993b1d0
--- /dev/null
+++ b/source/java/org/alfresco/repo/template/TemplateContent.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2005-2007 Alfresco Software Limited.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ * As a special exception to the terms and conditions of version 2.0 of
+ * the GPL, you may redistribute this Program in connection with Free/Libre
+ * and Open Source Software ("FLOSS") applications as described in Alfresco's
+ * FLOSS exception. You should have recieved a copy of the text describing
+ * the FLOSS exception, and it is also available here:
+ * http://www.alfresco.com/legal/licensing
+ */
+package org.alfresco.repo.template;
+
+
+/**
+ * @author Kevin Roast
+ */
+public interface TemplateContent extends TemplateProperties
+{
+ /**
+ * @return the content String for this node from the default content property
+ * (@see ContentModel.PROP_CONTENT)
+ */
+ public String getContent();
+
+ /**
+ * @return For a content document, this method returns the URL to the content stream for
+ * the default content property (@see ContentModel.PROP_CONTENT)
+ *
+ * For a container node, this method return the URL to browse to the folder in the web-client
+ */
+ public String getUrl();
+
+ /**
+ * @return The mimetype encoding for content attached to the node from the default content property
+ * (@see ContentModel.PROP_CONTENT)
+ */
+ public String getMimetype();
+
+ /**
+ * @return The size in bytes of the content attached to the node from the default content property
+ * (@see ContentModel.PROP_CONTENT)
+ */
+ public long getSize();
+}
diff --git a/source/java/org/alfresco/service/cmr/repository/TemplateNode.java b/source/java/org/alfresco/repo/template/TemplateNode.java
similarity index 61%
rename from source/java/org/alfresco/service/cmr/repository/TemplateNode.java
rename to source/java/org/alfresco/repo/template/TemplateNode.java
index 04cef7283b..f7366a3342 100644
--- a/source/java/org/alfresco/service/cmr/repository/TemplateNode.java
+++ b/source/java/org/alfresco/repo/template/TemplateNode.java
@@ -1,946 +1,638 @@
-/*
- * Copyright (C) 2005-2007 Alfresco Software Limited.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
- * As a special exception to the terms and conditions of version 2.0 of
- * the GPL, you may redistribute this Program in connection with Free/Libre
- * and Open Source Software ("FLOSS") applications as described in Alfresco's
- * FLOSS exception. You should have recieved a copy of the text describing
- * the FLOSS exception, and it is also available here:
- * http://www.alfresco.com/legal/licensing"
- */
-package org.alfresco.service.cmr.repository;
-
-import java.io.Serializable;
-import java.io.StringReader;
-import java.io.UnsupportedEncodingException;
-import java.net.URLEncoder;
-import java.text.MessageFormat;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import org.alfresco.model.ContentModel;
-import org.alfresco.repo.action.executer.TransformActionExecuter;
-import org.alfresco.repo.content.MimetypeMap;
-import org.alfresco.repo.security.permissions.AccessDeniedException;
-import org.alfresco.repo.template.LuceneSearchResultsMap;
-import org.alfresco.repo.template.NamePathResultsMap;
-import org.alfresco.repo.template.NodeSearchResultsMap;
-import org.alfresco.repo.template.SavedSearchResultsMap;
-import org.alfresco.repo.template.XPathResultsMap;
-import org.alfresco.service.ServiceRegistry;
-import org.alfresco.service.cmr.audit.AuditInfo;
-import org.alfresco.service.cmr.dictionary.DictionaryService;
-import org.alfresco.service.cmr.lock.LockStatus;
-import org.alfresco.service.cmr.security.AccessPermission;
-import org.alfresco.service.cmr.security.AccessStatus;
-import org.alfresco.service.cmr.version.Version;
-import org.alfresco.service.cmr.version.VersionHistory;
-import org.alfresco.service.namespace.QName;
-import org.alfresco.service.namespace.QNameMap;
-import org.alfresco.service.namespace.RegexQNamePattern;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.springframework.util.StringUtils;
-import org.xml.sax.InputSource;
-
-import freemarker.ext.dom.NodeModel;
-
-/**
- * Node class specific for use by Template pages that support Bean objects as part of the model.
- * The default template engine FreeMarker can use these objects and they are provided to support it.
- * A single method is completely freemarker specific - getXmlNodeModel()
- *
- * The class exposes Node properties, children as dynamically populated maps and lists.
- *
- * Various helper methods are provided to access common and useful node variables such
- * as the content url and type information.
- *
- * @author Kevin Roast
- */
-public class TemplateNode implements Serializable
-{
- private static final long serialVersionUID = 1234390333739034171L;
-
- private static Log logger = LogFactory.getLog(TemplateNode.class);
-
- protected final static String NAMESPACE_BEGIN = "" + QName.NAMESPACE_BEGIN;
- protected final static String CONTENT_DEFAULT_URL = "/download/direct/{0}/{1}/{2}/{3}";
- private final static String CONTENT_PROP_URL = "/download/direct/{0}/{1}/{2}/{3}?property={4}";
- private final static String FOLDER_BROWSE_URL = "/navigate/browse/{0}/{1}/{2}";
-
- /** The children of this node */
- private List children = null;
-
- /** The target associations from this node */
- private Map> targetAssocs = null;
-
- /** The child associations from this node */
- private Map> childAssocs = null;
-
- /** All associations from this node */
- private Map> assocs = null;
-
- /** Cached values */
- protected NodeRef nodeRef;
- private String name;
- private QName type;
- private String path;
- private String id;
- private Set aspects = null;
- private QNameMap properties;
- private List permissions = null;
- private boolean propsRetrieved = false;
- protected ServiceRegistry services = null;
- private Boolean isDocument = null;
- private Boolean isContainer = null;
- private String displayPath = null;
- private String mimetype = null;
- private Long size = null;
- protected TemplateImageResolver imageResolver = null;
- private TemplateNode parent = null;
- private ChildAssociationRef primaryParentAssoc = null;
- private Boolean isCategory = null;
-
-
- // ------------------------------------------------------------------------------
- // Construction
-
- /**
- * Constructor
- *
- * @param nodeRef The NodeRef this Node wrapper represents
- * @param services The ServiceRegistry the TemplateNode can use to access services
- * @param resolver Image resolver to use to retrieve icons
- */
- public TemplateNode(NodeRef nodeRef, ServiceRegistry services, TemplateImageResolver resolver)
- {
- if (nodeRef == null)
- {
- throw new IllegalArgumentException("NodeRef must be supplied.");
- }
-
- if (services == null)
- {
- throw new IllegalArgumentException("The ServiceRegistry must be supplied.");
- }
-
- this.nodeRef = nodeRef;
- this.id = nodeRef.getId();
- this.services = services;
- this.imageResolver = resolver;
-
- this.properties = new QNameMap(this.services.getNamespaceService());
- }
-
-
- // ------------------------------------------------------------------------------
- // Node API
-
- /**
- * @return The GUID for the node
- */
- public String getId()
- {
- return this.id;
- }
-
- /**
- * @return Returns the NodeRef this Node object represents
- */
- public NodeRef getNodeRef()
- {
- return this.nodeRef;
- }
-
- /**
- * @return Returns the type.
- */
- public QName getType()
- {
- if (this.type == null)
- {
- this.type = this.services.getNodeService().getType(this.nodeRef);
- }
-
- return type;
- }
-
- /**
- * @return The display name for the node
- */
- public String getName()
- {
- if (this.name == null)
- {
- // try and get the name from the properties first
- this.name = (String)getProperties().get("cm:name");
-
- // if we didn't find it as a property get the name from the association name
- if (this.name == null)
- {
- ChildAssociationRef parentRef = this.services.getNodeService().getPrimaryParent(this.nodeRef);
- if (parentRef != null && parentRef.getQName() != null)
- {
- this.name = parentRef.getQName().getLocalName();
- }
- else
- {
- this.name = "";
- }
- }
- }
-
- return this.name;
- }
-
- /**
- * @return The children of this Node as TemplateNode wrappers
- */
- public List getChildren()
- {
- if (this.children == null)
- {
- List childRefs = this.services.getNodeService().getChildAssocs(this.nodeRef);
- this.children = new ArrayList(childRefs.size());
- for (ChildAssociationRef ref : childRefs)
- {
- // create our Node representation from the NodeRef
- TemplateNode child = new TemplateNode(ref.getChildRef(), this.services, this.imageResolver);
- this.children.add(child);
- }
- }
-
- return this.children;
- }
-
- /**
- * @return The child associations for this Node. As a Map of assoc name to a List of TemplateNodes.
- */
- public Map> getChildAssocs()
- {
- if (this.childAssocs == null)
- {
- List refs = this.services.getNodeService().getChildAssocs(this.nodeRef);
- this.childAssocs = new QNameMap>(this.services.getNamespaceService());
- for (ChildAssociationRef ref : refs)
- {
- String qname = ref.getTypeQName().toString();
- List nodes = this.childAssocs.get(qname);
- if (nodes == null)
- {
- // first access for the list for this qname
- nodes = new ArrayList(4);
- this.childAssocs.put(ref.getTypeQName().toString(), nodes);
- }
- nodes.add( new TemplateNode(ref.getChildRef(), this.services, this.imageResolver) );
- }
- }
-
- return this.childAssocs;
- }
-
- /**
- * @return The target associations for this Node. As a Map of assoc name to a List of TemplateNodes.
- */
- public Map> getTargetAssocs()
- {
- if (this.targetAssocs == null)
- {
- List refs = this.services.getNodeService().getTargetAssocs(this.nodeRef, RegexQNamePattern.MATCH_ALL);
- this.targetAssocs = new QNameMap>(this.services.getNamespaceService());
- for (AssociationRef ref : refs)
- {
- String qname = ref.getTypeQName().toString();
- List nodes = this.targetAssocs.get(qname);
- if (nodes == null)
- {
- // first access for the list for this qname
- nodes = new ArrayList(4);
- this.targetAssocs.put(ref.getTypeQName().toString(), nodes);
- }
- nodes.add( new TemplateNode(ref.getTargetRef(), this.services, this.imageResolver) );
- }
- }
-
- return this.targetAssocs;
- }
-
- /**
- * @return All associations for this Node. As a Map of assoc name to a List of TemplateNodes.
- */
- public Map> getAssocs()
- {
- if (this.assocs == null)
- {
- this.assocs = new QNameMap>(this.services.getNamespaceService());
- this.assocs.putAll(getTargetAssocs());
- this.assocs.putAll(getChildAssocs());
- }
- return this.assocs;
- }
-
- /**
- * @return All the properties known about this node.
- */
- public Map getProperties()
- {
- if (this.propsRetrieved == false)
- {
- Map props = this.services.getNodeService().getProperties(this.nodeRef);
-
- for (QName qname : props.keySet())
- {
- Serializable propValue = props.get(qname);
- if (propValue instanceof NodeRef)
- {
- // NodeRef object properties are converted to new TemplateNode objects
- // so they can be used as objects within a template
- propValue = new TemplateNode(((NodeRef)propValue), this.services, this.imageResolver);
- }
- else if (propValue instanceof ContentData)
- {
- // ContentData object properties are converted to TemplateContentData objects
- // so the content and other properties of those objects can be accessed
- propValue = new TemplateContentData((ContentData)propValue, qname);
- }
- this.properties.put(qname.toString(), propValue);
- }
-
- this.propsRetrieved = true;
- }
-
- return this.properties;
- }
-
- /**
- * @return a list of objects representing the version history of this node.
- * @see VersionHistoryNode
- */
- public List getVersionHistory()
- {
- List records = Collections.emptyList();
-
- if (this.getAspects().contains(ContentModel.ASPECT_VERSIONABLE))
- {
- VersionHistory history = this.services.getVersionService().getVersionHistory(this.nodeRef);
- if (history != null)
- {
- records = new ArrayList(8);
- for (Version version : history.getAllVersions())
- {
- // create a wrapper for the version information
- VersionHistoryNode record = new VersionHistoryNode(version, this);
-
- // add the client side version to the list
- records.add(record);
- }
- }
- }
-
- return records;
- }
-
- /**
- * @return true if this Node is a container (i.e. a folder)
- */
- public boolean getIsContainer()
- {
- if (isContainer == null)
- {
- DictionaryService dd = this.services.getDictionaryService();
- isContainer = Boolean.valueOf( (dd.isSubClass(getType(), ContentModel.TYPE_FOLDER) == true &&
- dd.isSubClass(getType(), ContentModel.TYPE_SYSTEM_FOLDER) == false) );
- }
-
- return isContainer.booleanValue();
- }
-
- /**
- * @return true if this Node is a Document (i.e. with content)
- */
- public boolean getIsDocument()
- {
- if (isDocument == null)
- {
- DictionaryService dd = this.services.getDictionaryService();
- isDocument = Boolean.valueOf(dd.isSubClass(getType(), ContentModel.TYPE_CONTENT));
- }
-
- return isDocument.booleanValue();
- }
-
- /**
- * @return The list of aspects applied to this node
- */
- public Set getAspects()
- {
- if (this.aspects == null)
- {
- this.aspects = this.services.getNodeService().getAspects(this.nodeRef);
- }
-
- return this.aspects;
- }
-
- /**
- * @param aspect The aspect name to test for
- *
- * @return true if the node has the aspect false otherwise
- */
- public boolean hasAspect(String aspect)
- {
- if (this.aspects == null)
- {
- this.aspects = this.services.getNodeService().getAspects(this.nodeRef);
- }
-
- if (aspect.startsWith(NAMESPACE_BEGIN))
- {
- return aspects.contains((QName.createQName(aspect)));
- }
- else
- {
- boolean found = false;
- for (QName qname : this.aspects)
- {
- if (qname.toPrefixString(this.services.getNamespaceService()).equals(aspect))
- {
- found = true;
- break;
- }
- }
- return found;
- }
- }
-
- /**
- * @return true if the node is currently locked
- */
- public boolean getIsLocked()
- {
- boolean locked = false;
-
- if (getAspects().contains(ContentModel.ASPECT_LOCKABLE))
- {
- LockStatus lockStatus = this.services.getLockService().getLockStatus(this.nodeRef);
- if (lockStatus == LockStatus.LOCKED || lockStatus == LockStatus.LOCK_OWNER)
- {
- locked = true;
- }
- }
-
- return locked;
- }
-
- /**
- * @return true if the node is a Category instance
- */
- public boolean getIsCategory()
- {
- if (isCategory == null)
- {
- DictionaryService dd = this.services.getDictionaryService();
- isCategory = Boolean.valueOf(dd.isSubClass(getType(), ContentModel.TYPE_CATEGORY));
- }
-
- return isCategory.booleanValue();
- }
-
- /**
- * @return the parent node
- */
- public TemplateNode getParent()
- {
- if (parent == null)
- {
- NodeRef parentRef = this.services.getNodeService().getPrimaryParent(nodeRef).getParentRef();
- // handle root node (no parent!)
- if (parentRef != null)
- {
- parent = new TemplateNode(parentRef, this.services, this.imageResolver);
- }
- }
-
- return parent;
- }
-
- /**
- * @return the primary parent association so we can access the association QName and association type QName.
- */
- public ChildAssociationRef getPrimaryParentAssoc()
- {
- if (primaryParentAssoc == null)
- {
- primaryParentAssoc = this.services.getNodeService().getPrimaryParent(nodeRef);
- }
- return primaryParentAssoc;
- }
-
-
- // ------------------------------------------------------------------------------
- // Content API
-
- /**
- * @return the content String for this node from the default content property
- * (@see ContentModel.PROP_CONTENT)
- */
- public String getContent()
- {
- TemplateContentData content = (TemplateContentData)this.getProperties().get(ContentModel.PROP_CONTENT);
- return content != null ? content.getContent() : "";
- }
-
- /**
- * @return For a content document, this method returns the URL to the content stream for
- * the default content property (@see ContentModel.PROP_CONTENT)
- *
- * For a container node, this method return the URL to browse to the folder in the web-client
- */
- public String getUrl()
- {
- if (getIsDocument() == true)
- {
- try
- {
- return MessageFormat.format(CONTENT_DEFAULT_URL, new Object[] {
- nodeRef.getStoreRef().getProtocol(),
- nodeRef.getStoreRef().getIdentifier(),
- nodeRef.getId(),
- StringUtils.replace(URLEncoder.encode(getName(), "UTF-8"), "+", "%20") } );
- }
- catch (UnsupportedEncodingException err)
- {
- throw new TemplateException("Failed to encode content URL for node: " + nodeRef, err);
- }
- }
- else
- {
- return MessageFormat.format(FOLDER_BROWSE_URL, new Object[] {
- nodeRef.getStoreRef().getProtocol(),
- nodeRef.getStoreRef().getIdentifier(),
- nodeRef.getId() } );
- }
- }
-
- /**
- * @return The mimetype encoding for content attached to the node from the default content property
- * (@see ContentModel.PROP_CONTENT)
- */
- public String getMimetype()
- {
- if (mimetype == null)
- {
- TemplateContentData content = (TemplateContentData)this.getProperties().get(ContentModel.PROP_CONTENT);
- if (content != null)
- {
- mimetype = content.getMimetype();
- }
- }
-
- return mimetype;
- }
-
- /**
- * @return The size in bytes of the content attached to the node from the default content property
- * (@see ContentModel.PROP_CONTENT)
- */
- public long getSize()
- {
- if (size == null)
- {
- TemplateContentData content = (TemplateContentData)this.getProperties().get(ContentModel.PROP_CONTENT);
- if (content != null)
- {
- size = content.getSize();
- }
- }
-
- return size != null ? size.longValue() : 0L;
- }
-
-
- // ------------------------------------------------------------------------------
- // Node Helper API
-
- /**
- * @return FreeMarker NodeModel for the XML content of this node, or null if no parsable XML found
- */
- public NodeModel getXmlNodeModel()
- {
- try
- {
- return NodeModel.parse(new InputSource(new StringReader(getContent())));
- }
- catch (Throwable err)
- {
- if (logger.isDebugEnabled())
- logger.debug(err.getMessage(), err);
-
- return null;
- }
- }
-
- /**
- * @return Display path to this node - the path built of 'cm:name' attribute values.
- */
- public String getDisplayPath()
- {
- if (displayPath == null)
- {
- try
- {
- displayPath = this.services.getNodeService().getPath(this.nodeRef).toDisplayPath(this.services.getNodeService());
- }
- catch (AccessDeniedException err)
- {
- displayPath = "";
- }
- }
-
- return displayPath;
- }
-
- /**
- * @return QName path to this node. This can be used for Lucene PATH: style queries
- */
- public String getQnamePath()
- {
- return this.services.getNodeService().getPath(this.nodeRef).toPrefixString(this.services.getNamespaceService());
- }
-
- /**
- * @return the small icon image for this node
- */
- public String getIcon16()
- {
- if (this.imageResolver != null)
- {
- if (getIsDocument())
- {
- return this.imageResolver.resolveImagePathForName(getName(), true);
- }
- else
- {
- String icon = (String)getProperties().get("app:icon");
- if (icon != null)
- {
- return "/images/icons/" + icon + "-16.gif";
- }
- else
- {
- return "/images/icons/space_small.gif";
- }
- }
- }
- else
- {
- return "/images/filetypes/_default.gif";
- }
- }
-
- /**
- * @return the large icon image for this node
- */
- public String getIcon32()
- {
- if (this.imageResolver != null)
- {
- if (getIsDocument())
- {
- return this.imageResolver.resolveImagePathForName(getName(), false);
- }
- else
- {
- String icon = (String)getProperties().get("app:icon");
- if (icon != null)
- {
- return "/images/icons/" + icon + ".gif";
- }
- else
- {
- return "/images/icons/space-icon-default.gif";
- }
- }
- }
- else
- {
- return "/images/filetypes32/_default.gif";
- }
- }
-
-
- // ------------------------------------------------------------------------------
- // Security API
-
- /**
- * @return List of permissions applied to this Node.
- * Strings returned are of the format [ALLOWED|DENIED];[USERNAME|GROUPNAME];PERMISSION for example
- * ALLOWED;kevinr;Consumer so can be easily tokenized on the ';' character.
- */
- public List getPermissions()
- {
- if (this.permissions == null)
- {
- String userName = this.services.getAuthenticationService().getCurrentUserName();
- this.permissions = new ArrayList(4);
- Set acls = this.services.getPermissionService().getAllSetPermissions(this.nodeRef);
- for (AccessPermission permission : acls)
- {
- StringBuilder buf = new StringBuilder(64);
- buf.append(permission.getAccessStatus())
- .append(';')
- .append(permission.getAuthority())
- .append(';')
- .append(permission.getPermission());
- this.permissions.add(buf.toString());
- }
- }
- return this.permissions;
- }
-
- /**
- * @return true if this node inherits permissions from its parent node, false otherwise.
- */
- public boolean getInheritsPermissions()
- {
- return this.services.getPermissionService().getInheritParentPermissions(this.nodeRef);
- }
-
- /**
- * @param permission Permission name to test
- *
- * @return true if the current user is granted the specified permission on the node
- */
- public boolean hasPermission(String permission)
- {
- return (this.services.getPermissionService().hasPermission(this.nodeRef, permission) == AccessStatus.ALLOWED);
- }
-
-
- // ------------------------------------------------------------------------------
- // Search API
-
- /**
- * @return A map capable of returning the TemplateNode at the specified Path as a child of this node.
- */
- public Map getChildByNamePath()
- {
- return new NamePathResultsMap(this, this.services);
- }
-
- /**
- * @return A map capable of returning a List of TemplateNode objects from an XPath query
- * as children of this node.
- */
- public Map getChildrenByXPath()
- {
- return new XPathResultsMap(this, this.services);
- }
-
- /**
- * @return A map capable of returning a List of TemplateNode objects from an NodeRef to a Saved Search
- * object. The Saved Search is executed and the resulting nodes supplied as a sequence.
- */
- public Map getChildrenBySavedSearch()
- {
- return new SavedSearchResultsMap(this, this.services);
- }
-
- /**
- * @return A map capable of returning a List of TemplateNode objects from an NodeRef to a Lucene search
- * string. The Saved Search is executed and the resulting nodes supplied as a sequence.
- */
- public Map getChildrenByLuceneSearch()
- {
- return new LuceneSearchResultsMap(this, this.services);
- }
-
- /**
- * @return A map capable of returning a TemplateNode for a single specified NodeRef reference.
- */
- public Map getNodeByReference()
- {
- return new NodeSearchResultsMap(this, this.services);
- }
-
-
- // ------------------------------------------------------------------------------
- // Audit API
-
- /**
- * @return a list of AuditInfo objects describing the Audit Trail for this node instance
- */
- public List getAuditTrail()
- {
- return this.services.getAuditService().getAuditTrail(this.nodeRef);
- }
-
-
- // ------------------------------------------------------------------------------
- // Misc helpers
-
- /**
- * @return the image resolver instance used by this node
- */
- public TemplateImageResolver getImageResolver()
- {
- return this.imageResolver;
- }
-
- /**
- * Override Object.toString() to provide useful debug output
- */
- public String toString()
- {
- if (this.services.getNodeService().exists(nodeRef))
- {
- return "Node Type: " + getType() +
- "\tNode Ref: " + this.nodeRef.toString();
- }
- else
- {
- return "Node no longer exists: " + nodeRef;
- }
- }
-
-
- // ------------------------------------------------------------------------------
- // Inner classes
-
- /**
- * Inner class wrapping and providing access to a ContentData property
- */
- public class TemplateContentData implements Serializable
- {
- /**
- * Constructor
- *
- * @param contentData The ContentData object this object wraps
- * @param property The property the ContentData is attached too
- */
- public TemplateContentData(ContentData contentData, QName property)
- {
- this.contentData = contentData;
- this.property = property;
- }
-
- /**
- * @return the content stream
- */
- public String getContent()
- {
- ContentService contentService = services.getContentService();
- ContentReader reader = contentService.getReader(nodeRef, property);
-
- return (reader != null && reader.exists()) ? reader.getContentString() : "";
- }
-
- /**
- * @return the content stream to the specified maximum length in characters
- */
- public String getContent(int length)
- {
- ContentService contentService = services.getContentService();
- ContentReader reader = contentService.getReader(nodeRef, property);
-
- return (reader != null && reader.exists()) ? reader.getContentString(length) : "";
- }
-
- /**
- * @param length Length of the character stream to return, or -1 for all
- *
- * @return the binary content stream converted to text using any available transformer
- * if fails to convert then null will be returned
- */
- public String getContentAsText(int length)
- {
- String result = null;
-
- if (MimetypeMap.MIMETYPE_TEXT_PLAIN.equals(mimetype))
- {
- result = getContent(length);
- }
- else
- {
- // get the content reader
- ContentService contentService = services.getContentService();
- ContentReader reader = contentService.getReader(nodeRef, property);
-
- // get the writer and set it up for text convert
- ContentWriter writer = contentService.getWriter(null, ContentModel.PROP_CONTENT, true);
- writer.setMimetype("text/plain");
- writer.setEncoding(reader.getEncoding());
-
- // try and transform the content
- if (contentService.isTransformable(reader, writer))
- {
- contentService.transform(reader, writer);
-
- ContentReader resultReader = writer.getReader();
- if (resultReader != null && reader.exists())
- {
- if (length != -1)
- {
- result = resultReader.getContentString(length);
- }
- else
- {
- result = resultReader.getContentString();
- }
- }
- }
- }
- return result;
- }
-
- /**
- * @return
- */
- public String getUrl()
- {
- try
- {
- return MessageFormat.format(CONTENT_PROP_URL, new Object[] {
- nodeRef.getStoreRef().getProtocol(),
- nodeRef.getStoreRef().getIdentifier(),
- nodeRef.getId(),
- StringUtils.replace(URLEncoder.encode(getName(), "UTF-8"), "+", "%20"),
- StringUtils.replace(URLEncoder.encode(property.toString(), "UTF-8"), "+", "%20") } );
- }
- catch (UnsupportedEncodingException err)
- {
- throw new TemplateException("Failed to encode content URL for node: " + nodeRef, err);
- }
- }
-
- public long getSize()
- {
- return contentData.getSize();
- }
-
- public String getMimetype()
- {
- return contentData.getMimetype();
- }
-
- private ContentData contentData;
- private QName property;
- }
+/*
+ * Copyright (C) 2005-2007 Alfresco Software Limited.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ * As a special exception to the terms and conditions of version 2.0 of
+ * the GPL, you may redistribute this Program in connection with Free/Libre
+ * and Open Source Software ("FLOSS") applications as described in Alfresco's
+ * FLOSS exception. You should have recieved a copy of the text describing
+ * the FLOSS exception, and it is also available here:
+ * http://www.alfresco.com/legal/licensing"
+ */
+package org.alfresco.repo.template;
+
+import java.io.Serializable;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.alfresco.model.ContentModel;
+import org.alfresco.repo.security.permissions.AccessDeniedException;
+import org.alfresco.service.ServiceRegistry;
+import org.alfresco.service.cmr.audit.AuditInfo;
+import org.alfresco.service.cmr.dictionary.DictionaryService;
+import org.alfresco.service.cmr.lock.LockStatus;
+import org.alfresco.service.cmr.repository.AssociationRef;
+import org.alfresco.service.cmr.repository.ChildAssociationRef;
+import org.alfresco.service.cmr.repository.ContentData;
+import org.alfresco.service.cmr.repository.NodeRef;
+import org.alfresco.service.cmr.repository.TemplateImageResolver;
+import org.alfresco.service.cmr.version.Version;
+import org.alfresco.service.cmr.version.VersionHistory;
+import org.alfresco.service.namespace.QName;
+import org.alfresco.service.namespace.QNameMap;
+import org.alfresco.service.namespace.RegexQNamePattern;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.xml.sax.InputSource;
+
+import freemarker.ext.dom.NodeModel;
+
+/**
+ * Node class specific for use by Template pages that support Bean objects as part of the model.
+ * The default template engine FreeMarker can use these objects and they are provided to support it.
+ * A single method is completely freemarker specific - getXmlNodeModel()
+ *
+ * The class exposes Node properties, children as dynamically populated maps and lists.
+ *
+ * Various helper methods are provided to access common and useful node variables such
+ * as the content url and type information.
+ *
+ * @author Kevin Roast
+ */
+public class TemplateNode extends BasePermissionsNode
+{
+ private static final long serialVersionUID = 1234390333739034171L;
+
+ private static Log logger = LogFactory.getLog(TemplateNode.class);
+
+ protected final static String NAMESPACE_BEGIN = "" + QName.NAMESPACE_BEGIN;
+
+ /** The children of this node */
+ private List children = null;
+
+ /** The target associations from this node */
+ private Map> targetAssocs = null;
+
+ /** The child associations from this node */
+ private Map> childAssocs = null;
+
+ /** All associations from this node */
+ private Map> assocs = null;
+
+ /** Cached values */
+ protected NodeRef nodeRef;
+ private String name;
+ private QName type;
+ private String path;
+ private String id;
+ private Set aspects = null;
+ private QNameMap properties;
+ private boolean propsRetrieved = false;
+ private String displayPath = null;
+ protected TemplateImageResolver imageResolver = null;
+ private TemplateNode parent = null;
+ private ChildAssociationRef primaryParentAssoc = null;
+ private Boolean isCategory = null;
+
+
+ // ------------------------------------------------------------------------------
+ // Construction
+
+ /**
+ * Constructor
+ *
+ * @param nodeRef The NodeRef this Node wrapper represents
+ * @param services The ServiceRegistry the TemplateNode can use to access services
+ * @param resolver Image resolver to use to retrieve icons
+ */
+ public TemplateNode(NodeRef nodeRef, ServiceRegistry services, TemplateImageResolver resolver)
+ {
+ if (nodeRef == null)
+ {
+ throw new IllegalArgumentException("NodeRef must be supplied.");
+ }
+
+ if (services == null)
+ {
+ throw new IllegalArgumentException("The ServiceRegistry must be supplied.");
+ }
+
+ this.nodeRef = nodeRef;
+ this.id = nodeRef.getId();
+ this.services = services;
+ this.imageResolver = resolver;
+
+ this.properties = new QNameMap(this.services.getNamespaceService());
+ }
+
+
+ // ------------------------------------------------------------------------------
+ // TemplateNodeRef contract implementation
+
+ /**
+ * @return The GUID for the node
+ */
+ public String getId()
+ {
+ return this.id;
+ }
+
+ /**
+ * @return Returns the NodeRef this Node object represents
+ */
+ public NodeRef getNodeRef()
+ {
+ return this.nodeRef;
+ }
+
+ /**
+ * @return Returns the type.
+ */
+ public QName getType()
+ {
+ if (this.type == null)
+ {
+ this.type = this.services.getNodeService().getType(this.nodeRef);
+ }
+
+ return type;
+ }
+
+ /**
+ * @return The display name for the node
+ */
+ public String getName()
+ {
+ if (this.name == null)
+ {
+ // try and get the name from the properties first
+ this.name = (String)getProperties().get("cm:name");
+
+ // if we didn't find it as a property get the name from the association name
+ if (this.name == null)
+ {
+ ChildAssociationRef parentRef = this.services.getNodeService().getPrimaryParent(this.nodeRef);
+ if (parentRef != null && parentRef.getQName() != null)
+ {
+ this.name = parentRef.getQName().getLocalName();
+ }
+ else
+ {
+ this.name = "";
+ }
+ }
+ }
+
+ return this.name;
+ }
+
+
+ // ------------------------------------------------------------------------------
+ // TemplateProperties contract implementation
+
+ /**
+ * @return The children of this Node as objects that support the TemplateProperties contract.
+ */
+ public List getChildren()
+ {
+ if (this.children == null)
+ {
+ List childRefs = this.services.getNodeService().getChildAssocs(this.nodeRef);
+ this.children = new ArrayList(childRefs.size());
+ for (ChildAssociationRef ref : childRefs)
+ {
+ // create our Node representation from the NodeRef
+ TemplateNode child = new TemplateNode(ref.getChildRef(), this.services, this.imageResolver);
+ this.children.add(child);
+ }
+ }
+
+ return this.children;
+ }
+
+ /**
+ * @return All the properties known about this node.
+ */
+ public Map getProperties()
+ {
+ if (this.propsRetrieved == false)
+ {
+ Map props = this.services.getNodeService().getProperties(this.nodeRef);
+
+ for (QName qname : props.keySet())
+ {
+ Serializable propValue = props.get(qname);
+ if (propValue instanceof NodeRef)
+ {
+ // NodeRef object properties are converted to new TemplateNode objects
+ // so they can be used as objects within a template
+ propValue = new TemplateNode(((NodeRef)propValue), this.services, this.imageResolver);
+ }
+ else if (propValue instanceof ContentData)
+ {
+ // ContentData object properties are converted to TemplateContentData objects
+ // so the content and other properties of those objects can be accessed
+ propValue = new TemplateContentData((ContentData)propValue, qname);
+ }
+ this.properties.put(qname.toString(), propValue);
+ }
+
+ this.propsRetrieved = true;
+ }
+
+ return this.properties;
+ }
+
+ /**
+ * @return The list of aspects applied to this node
+ */
+ public Set getAspects()
+ {
+ if (this.aspects == null)
+ {
+ this.aspects = this.services.getNodeService().getAspects(this.nodeRef);
+ }
+
+ return this.aspects;
+ }
+
+ /**
+ * @param aspect The aspect name to test for
+ *
+ * @return true if the node has the aspect false otherwise
+ */
+ public boolean hasAspect(String aspect)
+ {
+ if (this.aspects == null)
+ {
+ this.aspects = this.services.getNodeService().getAspects(this.nodeRef);
+ }
+
+ if (aspect.startsWith(NAMESPACE_BEGIN))
+ {
+ return aspects.contains((QName.createQName(aspect)));
+ }
+ else
+ {
+ boolean found = false;
+ for (QName qname : this.aspects)
+ {
+ if (qname.toPrefixString(this.services.getNamespaceService()).equals(aspect))
+ {
+ found = true;
+ break;
+ }
+ }
+ return found;
+ }
+ }
+
+
+ // ------------------------------------------------------------------------------
+ // Repository Node API
+
+ /**
+ * @return The child associations for this Node. As a Map of assoc name to a List of TemplateNodes.
+ */
+ public Map> getChildAssocs()
+ {
+ if (this.childAssocs == null)
+ {
+ List refs = this.services.getNodeService().getChildAssocs(this.nodeRef);
+ this.childAssocs = new QNameMap>(this.services.getNamespaceService());
+ for (ChildAssociationRef ref : refs)
+ {
+ String qname = ref.getTypeQName().toString();
+ List nodes = this.childAssocs.get(qname);
+ if (nodes == null)
+ {
+ // first access for the list for this qname
+ nodes = new ArrayList(4);
+ this.childAssocs.put(ref.getTypeQName().toString(), nodes);
+ }
+ nodes.add( new TemplateNode(ref.getChildRef(), this.services, this.imageResolver) );
+ }
+ }
+
+ return this.childAssocs;
+ }
+
+ /**
+ * @return The target associations for this Node. As a Map of assoc name to a List of TemplateNodes.
+ */
+ public Map> getTargetAssocs()
+ {
+ if (this.targetAssocs == null)
+ {
+ List refs = this.services.getNodeService().getTargetAssocs(this.nodeRef, RegexQNamePattern.MATCH_ALL);
+ this.targetAssocs = new QNameMap>(this.services.getNamespaceService());
+ for (AssociationRef ref : refs)
+ {
+ String qname = ref.getTypeQName().toString();
+ List nodes = this.targetAssocs.get(qname);
+ if (nodes == null)
+ {
+ // first access for the list for this qname
+ nodes = new ArrayList(4);
+ this.targetAssocs.put(ref.getTypeQName().toString(), nodes);
+ }
+ nodes.add( new TemplateNode(ref.getTargetRef(), this.services, this.imageResolver) );
+ }
+ }
+
+ return this.targetAssocs;
+ }
+
+ /**
+ * @return All associations for this Node. As a Map of assoc name to a List of TemplateNodes.
+ */
+ public Map> getAssocs()
+ {
+ if (this.assocs == null)
+ {
+ this.assocs = new QNameMap>(this.services.getNamespaceService());
+ this.assocs.putAll(getTargetAssocs());
+ this.assocs.putAll(getChildAssocs());
+ }
+ return this.assocs;
+ }
+
+ /**
+ * @return true if the node is currently locked
+ */
+ public boolean getIsLocked()
+ {
+ boolean locked = false;
+
+ if (getAspects().contains(ContentModel.ASPECT_LOCKABLE))
+ {
+ LockStatus lockStatus = this.services.getLockService().getLockStatus(this.nodeRef);
+ if (lockStatus == LockStatus.LOCKED || lockStatus == LockStatus.LOCK_OWNER)
+ {
+ locked = true;
+ }
+ }
+
+ return locked;
+ }
+
+ /**
+ * @return true if the node is a Category instance
+ */
+ public boolean getIsCategory()
+ {
+ if (isCategory == null)
+ {
+ DictionaryService dd = this.services.getDictionaryService();
+ isCategory = Boolean.valueOf(dd.isSubClass(getType(), ContentModel.TYPE_CATEGORY));
+ }
+
+ return isCategory.booleanValue();
+ }
+
+ /**
+ * @return the parent node
+ */
+ public TemplateNode getParent()
+ {
+ if (parent == null)
+ {
+ NodeRef parentRef = this.services.getNodeService().getPrimaryParent(nodeRef).getParentRef();
+ // handle root node (no parent!)
+ if (parentRef != null)
+ {
+ parent = new TemplateNode(parentRef, this.services, this.imageResolver);
+ }
+ }
+
+ return parent;
+ }
+
+ /**
+ * @return the primary parent association so we can access the association QName and association type QName.
+ */
+ public ChildAssociationRef getPrimaryParentAssoc()
+ {
+ if (primaryParentAssoc == null)
+ {
+ primaryParentAssoc = this.services.getNodeService().getPrimaryParent(nodeRef);
+ }
+ return primaryParentAssoc;
+ }
+
+ /**
+ * @return a list of objects representing the version history of this node.
+ * @see VersionHistoryNode
+ */
+ public List getVersionHistory()
+ {
+ List records = Collections.emptyList();
+
+ if (this.getAspects().contains(ContentModel.ASPECT_VERSIONABLE))
+ {
+ VersionHistory history = this.services.getVersionService().getVersionHistory(this.nodeRef);
+ if (history != null)
+ {
+ records = new ArrayList(8);
+ for (Version version : history.getAllVersions())
+ {
+ // create a wrapper for the version information
+ VersionHistoryNode record = new VersionHistoryNode(version, this, this.services);
+
+ // add the client side version to the list
+ records.add(record);
+ }
+ }
+ }
+
+ return records;
+ }
+
+
+ // ------------------------------------------------------------------------------
+ // Node Helper API
+
+ /**
+ * @return FreeMarker NodeModel for the XML content of this node, or null if no parsable XML found
+ */
+ public NodeModel getXmlNodeModel()
+ {
+ try
+ {
+ return NodeModel.parse(new InputSource(new StringReader(getContent())));
+ }
+ catch (Throwable err)
+ {
+ if (logger.isDebugEnabled())
+ logger.debug(err.getMessage(), err);
+
+ return null;
+ }
+ }
+
+ /**
+ * @return Display path to this node - the path built of 'cm:name' attribute values.
+ */
+ public String getDisplayPath()
+ {
+ if (displayPath == null)
+ {
+ try
+ {
+ displayPath = this.services.getNodeService().getPath(this.nodeRef).toDisplayPath(this.services.getNodeService());
+ }
+ catch (AccessDeniedException err)
+ {
+ displayPath = "";
+ }
+ }
+
+ return displayPath;
+ }
+
+ /**
+ * @return QName path to this node. This can be used for Lucene PATH: style queries
+ */
+ public String getQnamePath()
+ {
+ return this.services.getNodeService().getPath(this.nodeRef).toPrefixString(this.services.getNamespaceService());
+ }
+
+ /**
+ * @return the small icon image for this node
+ */
+ public String getIcon16()
+ {
+ if (this.imageResolver != null)
+ {
+ if (getIsDocument())
+ {
+ return this.imageResolver.resolveImagePathForName(getName(), true);
+ }
+ else
+ {
+ String icon = (String)getProperties().get("app:icon");
+ if (icon != null)
+ {
+ return "/images/icons/" + icon + "-16.gif";
+ }
+ else
+ {
+ return "/images/icons/space_small.gif";
+ }
+ }
+ }
+ else
+ {
+ return "/images/filetypes/_default.gif";
+ }
+ }
+
+ /**
+ * @return the large icon image for this node
+ */
+ public String getIcon32()
+ {
+ if (this.imageResolver != null)
+ {
+ if (getIsDocument())
+ {
+ return this.imageResolver.resolveImagePathForName(getName(), false);
+ }
+ else
+ {
+ String icon = (String)getProperties().get("app:icon");
+ if (icon != null)
+ {
+ return "/images/icons/" + icon + ".gif";
+ }
+ else
+ {
+ return "/images/icons/space-icon-default.gif";
+ }
+ }
+ }
+ else
+ {
+ return "/images/filetypes32/_default.gif";
+ }
+ }
+
+
+ // ------------------------------------------------------------------------------
+ // Search API
+
+ /**
+ * @return A map capable of returning the TemplateNode at the specified Path as a child of this node.
+ */
+ public Map getChildByNamePath()
+ {
+ return new NamePathResultsMap(this, this.services);
+ }
+
+ /**
+ * @return A map capable of returning a List of TemplateNode objects from an XPath query
+ * as children of this node.
+ */
+ public Map getChildrenByXPath()
+ {
+ return new XPathResultsMap(this, this.services);
+ }
+
+ /**
+ * @return A map capable of returning a List of TemplateNode objects from an NodeRef to a Saved Search
+ * object. The Saved Search is executed and the resulting nodes supplied as a sequence.
+ */
+ public Map getChildrenBySavedSearch()
+ {
+ return new SavedSearchResultsMap(this, this.services);
+ }
+
+ /**
+ * @return A map capable of returning a List of TemplateNode objects from an NodeRef to a Lucene search
+ * string. The Saved Search is executed and the resulting nodes supplied as a sequence.
+ */
+ public Map getChildrenByLuceneSearch()
+ {
+ return new LuceneSearchResultsMap(this, this.services);
+ }
+
+ /**
+ * @return A map capable of returning a TemplateNode for a single specified NodeRef reference.
+ */
+ public Map getNodeByReference()
+ {
+ return new NodeSearchResultsMap(this, this.services);
+ }
+
+
+ // ------------------------------------------------------------------------------
+ // Audit API
+
+ /**
+ * @return a list of AuditInfo objects describing the Audit Trail for this node instance
+ */
+ public List getAuditTrail()
+ {
+ return this.services.getAuditService().getAuditTrail(this.nodeRef);
+ }
+
+
+ // ------------------------------------------------------------------------------
+ // Misc helpers
+
+ /**
+ * @return the image resolver instance used by this node
+ */
+ public TemplateImageResolver getImageResolver()
+ {
+ return this.imageResolver;
+ }
}
\ No newline at end of file
diff --git a/source/java/org/alfresco/repo/template/TemplateNodeRef.java b/source/java/org/alfresco/repo/template/TemplateNodeRef.java
new file mode 100644
index 0000000000..05f68f7c96
--- /dev/null
+++ b/source/java/org/alfresco/repo/template/TemplateNodeRef.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2005-2007 Alfresco Software Limited.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ * As a special exception to the terms and conditions of version 2.0 of
+ * the GPL, you may redistribute this Program in connection with Free/Libre
+ * and Open Source Software ("FLOSS") applications as described in Alfresco's
+ * FLOSS exception. You should have recieved a copy of the text describing
+ * the FLOSS exception, and it is also available here:
+ * http://www.alfresco.com/legal/licensing
+ */
+package org.alfresco.repo.template;
+
+import java.io.Serializable;
+
+import org.alfresco.service.cmr.repository.NodeRef;
+import org.alfresco.service.namespace.QName;
+
+/**
+ * @author Kevin Roast
+ */
+public interface TemplateNodeRef extends Serializable
+{
+ /**
+ * @return The GUID for the node
+ */
+ public String getId();
+
+ /**
+ * @return Returns the NodeRef this Node object represents
+ */
+ public NodeRef getNodeRef();
+
+ /**
+ * @return Returns the type.
+ */
+ public QName getType();
+
+ /**
+ * @return The display name for the node
+ */
+ public String getName();
+}
diff --git a/source/java/org/alfresco/repo/template/TemplatePermissions.java b/source/java/org/alfresco/repo/template/TemplatePermissions.java
new file mode 100644
index 0000000000..fd6a9dd063
--- /dev/null
+++ b/source/java/org/alfresco/repo/template/TemplatePermissions.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2005-2007 Alfresco Software Limited.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ * As a special exception to the terms and conditions of version 2.0 of
+ * the GPL, you may redistribute this Program in connection with Free/Libre
+ * and Open Source Software ("FLOSS") applications as described in Alfresco's
+ * FLOSS exception. You should have recieved a copy of the text describing
+ * the FLOSS exception, and it is also available here:
+ * http://www.alfresco.com/legal/licensing
+ */
+package org.alfresco.repo.template;
+
+import java.util.List;
+
+/**
+ * @author Kevin Roast
+ */
+public interface TemplatePermissions extends TemplateNodeRef
+{
+ /**
+ * @return List of permissions applied to this Node.
+ * Strings returned are of the format [ALLOWED|DENIED];[USERNAME|GROUPNAME];PERMISSION for example
+ * ALLOWED;kevinr;Consumer so can be easily tokenized on the ';' character.
+ */
+ public List getPermissions();
+
+ /**
+ * @return true if this node inherits permissions from its parent node, false otherwise.
+ */
+ public boolean getInheritsPermissions();
+
+ /**
+ * @param permission Permission name to test
+ *
+ * @return true if the current user is granted the specified permission on the node
+ */
+ public boolean hasPermission(String permission);
+}
diff --git a/source/java/org/alfresco/repo/template/TemplateProperties.java b/source/java/org/alfresco/repo/template/TemplateProperties.java
new file mode 100644
index 0000000000..848ced91d3
--- /dev/null
+++ b/source/java/org/alfresco/repo/template/TemplateProperties.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2005-2007 Alfresco Software Limited.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ * As a special exception to the terms and conditions of version 2.0 of
+ * the GPL, you may redistribute this Program in connection with Free/Libre
+ * and Open Source Software ("FLOSS") applications as described in Alfresco's
+ * FLOSS exception. You should have recieved a copy of the text describing
+ * the FLOSS exception, and it is also available here:
+ * http://www.alfresco.com/legal/licensing
+ */
+package org.alfresco.repo.template;
+
+import java.io.Serializable;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.alfresco.service.namespace.QName;
+
+/**
+ * @author Kevin Roast
+ */
+public interface TemplateProperties extends TemplateNodeRef
+{
+ /**
+ * @return The properties available on this node.
+ */
+ public Map getProperties();
+
+ /**
+ * @return The list of aspects applied to this node
+ */
+ public Set getAspects();
+
+ /**
+ * @param aspect The aspect name to test for
+ *
+ * @return true if the node has the aspect false otherwise
+ */
+ public boolean hasAspect(String aspect);
+
+ /**
+ * @return The children of this Node as TemplateNode wrappers
+ */
+ public List getChildren();
+}
diff --git a/source/java/org/alfresco/repo/template/TemplateServiceImplTest.java b/source/java/org/alfresco/repo/template/TemplateServiceImplTest.java
index d22f8e567a..e9e86a65c7 100644
--- a/source/java/org/alfresco/repo/template/TemplateServiceImplTest.java
+++ b/source/java/org/alfresco/repo/template/TemplateServiceImplTest.java
@@ -42,7 +42,6 @@ import org.alfresco.service.cmr.repository.ContentService;
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.TemplateNode;
import org.alfresco.service.cmr.repository.TemplateService;
import org.alfresco.service.transaction.TransactionService;
import org.alfresco.util.ApplicationContextHelper;
diff --git a/source/java/org/alfresco/service/cmr/repository/VersionHistoryNode.java b/source/java/org/alfresco/repo/template/VersionHistoryNode.java
similarity index 84%
rename from source/java/org/alfresco/service/cmr/repository/VersionHistoryNode.java
rename to source/java/org/alfresco/repo/template/VersionHistoryNode.java
index 1a04b60111..24e871baa9 100644
--- a/source/java/org/alfresco/service/cmr/repository/VersionHistoryNode.java
+++ b/source/java/org/alfresco/repo/template/VersionHistoryNode.java
@@ -22,18 +22,22 @@
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
-package org.alfresco.service.cmr.repository;
+package org.alfresco.repo.template;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.text.MessageFormat;
import java.util.Date;
+import java.util.List;
import java.util.Map;
import java.util.Set;
import org.alfresco.model.ContentModel;
-import org.alfresco.service.cmr.repository.TemplateNode.TemplateContentData;
+import org.alfresco.service.ServiceRegistry;
+import org.alfresco.service.cmr.repository.ContentData;
+import org.alfresco.service.cmr.repository.NodeRef;
+import org.alfresco.service.cmr.repository.TemplateException;
import org.alfresco.service.cmr.version.Version;
import org.alfresco.service.cmr.version.VersionType;
import org.alfresco.service.namespace.QName;
@@ -46,7 +50,7 @@ import org.springframework.util.StringUtils;
*
* @author Kevin Roast
*/
-public class VersionHistoryNode implements Serializable
+public class VersionHistoryNode extends BaseContentNode
{
private QNameMap properties;
private boolean propsRetrieved = false;
@@ -59,7 +63,7 @@ public class VersionHistoryNode implements Serializable
*
* @param version Descriptor of the node version information
*/
- public VersionHistoryNode(Version version, TemplateNode parent)
+ public VersionHistoryNode(Version version, TemplateNode parent, ServiceRegistry services)
{
if (version == null)
{
@@ -69,8 +73,13 @@ public class VersionHistoryNode implements Serializable
{
throw new IllegalArgumentException("Parent TemplateNode is mandatory.");
}
+ if (services == null)
+ {
+ throw new IllegalArgumentException("The ServiceRegistry must be supplied.");
+ }
this.version = version;
this.parent = parent;
+ this.services = services;
this.properties = new QNameMap(parent.services.getNamespaceService());
}
@@ -238,26 +247,23 @@ public class VersionHistoryNode implements Serializable
}
}
+ /**
+ * @see org.alfresco.repo.template.TemplateProperties#getChildren()
+ */
+ public List getChildren()
+ {
+ return null;
+ }
+
// ------------------------------------------------------------------------------
// Content API
/**
- * @return the content String for this node from the default content property
- * (@see ContentModel.PROP_CONTENT)
- */
- public String getContent()
- {
- TemplateContentData content = (TemplateContentData)this.getProperties().get(ContentModel.PROP_CONTENT);
- return content != null ? content.getContent() : "";
- }
-
- /**
- * @return For a content document, this method returns the URL to the content stream for
+ * @return Returns the URL to the content stream for the frozen state of the node from
* the default content property (@see ContentModel.PROP_CONTENT)
- *
- * For a container node, this method return the URL to browse to the folder in the web-client
*/
+ @Override
public String getUrl()
{
NodeRef nodeRef = this.version.getFrozenStateNodeRef();
@@ -274,24 +280,4 @@ public class VersionHistoryNode implements Serializable
throw new TemplateException("Failed to encode content URL for node: " + nodeRef, err);
}
}
-
- /**
- * @return The mimetype encoding for content attached to the node from the default content property
- * (@see ContentModel.PROP_CONTENT)
- */
- public String getMimetype()
- {
- TemplateContentData content = (TemplateContentData)this.getProperties().get(ContentModel.PROP_CONTENT);
- return (content != null ? content.getMimetype() : null);
- }
-
- /**
- * @return The size in bytes of the content attached to the node from the default content property
- * (@see ContentModel.PROP_CONTENT)
- */
- public long getSize()
- {
- TemplateContentData content = (TemplateContentData)this.getProperties().get(ContentModel.PROP_CONTENT);
- return (content != null ? content.getSize() : 0L);
- }
}
diff --git a/source/java/org/alfresco/repo/template/XPathResultsMap.java b/source/java/org/alfresco/repo/template/XPathResultsMap.java
index 858ac48ef3..7b0a91e1b8 100644
--- a/source/java/org/alfresco/repo/template/XPathResultsMap.java
+++ b/source/java/org/alfresco/repo/template/XPathResultsMap.java
@@ -25,7 +25,6 @@
package org.alfresco.repo.template;
import org.alfresco.service.ServiceRegistry;
-import org.alfresco.service.cmr.repository.TemplateNode;
/**
* A special Map that executes an XPath against the parent Node as part of the get()