diff --git a/config/alfresco/templates/webscripts/org/alfresco/cmis/entries.lib.atom.ftl b/config/alfresco/templates/webscripts/org/alfresco/cmis/entries.lib.atom.ftl
new file mode 100644
index 0000000000..02a767909b
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/cmis/entries.lib.atom.ftl
@@ -0,0 +1,39 @@
+<#macro document node>
+ <#-- TODO: link elements (both APP and CMIS) -->
+
+ ${node.name}
+
+ urn:uuid:${node.id}
+ ${xmldate(node.properties.modified)}
+ ${xmldate(node.properties.created)}
+ ${node.properties.description!""}
+ ${node.properties.creator}
+ ${node.nodeRef}
+ ${absurl(url.context)}${node.icon16}
+ <#-- TODO: full cmis schema -->
+
+ ${node.id}
+ document
+
+
+#macro>
+
+<#macro folder node>
+ <#-- TODO: link elements (both APP and CMIS) -->
+
+ ${node.name}
+
+ urn:uuid:${node.id}
+ ${xmldate(node.properties.modified)}
+ ${xmldate(node.properties.created)}
+ ${node.properties.description!""}
+ ${node.properties.creator!""}
+ ${node.nodeRef}
+ ${absurl(url.context)}${node.icon16}
+ <#-- TODO: full cmis schema -->
+
+ ${node.id}
+ folder
+
+
+#macro>
\ No newline at end of file
diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/repository.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/repository/repository.get.desc.xml
index 12cbe3638c..94138e82b3 100644
--- a/config/alfresco/templates/webscripts/org/alfresco/repository/repository.get.desc.xml
+++ b/config/alfresco/templates/webscripts/org/alfresco/repository/repository.get.desc.xml
@@ -4,4 +4,5 @@
/api/repository
none
+
\ No newline at end of file
diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/store/children.get.atomfeed.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/store/children.get.atomfeed.ftl
index 1864bfc9e9..2a0a2d7ee4 100644
--- a/config/alfresco/templates/webscripts/org/alfresco/repository/store/children.get.atomfeed.ftl
+++ b/config/alfresco/templates/webscripts/org/alfresco/repository/store/children.get.atomfeed.ftl
@@ -1,4 +1,5 @@
<#import "/org/alfresco/paging.lib.atom.ftl" as pagingLib/>
+<#import "/org/alfresco/cmis/entries.lib.atom.ftl" as entriesLib/>
Alfresco (${server.edition})
@@ -12,16 +13,10 @@
<@pagingLib.cursor cursor=cursor/>
<#list results as child>
-
- ${child.name}
-
- urn:uuid:${child.id}
- ${xmldate(child.properties.modified)}
- ${xmldate(child.properties.created)}
- ${child.properties.description!""}
- ${child.properties.creator}
- ${child.nodeRef}
- ${absurl(url.context)}${child.icon16}
-
+<#if child.isDocument>
+ <@entriesLib.document node=child/>
+<#else>
+ <@entriesLib.folder node=child/>
+#if>
#list>
\ No newline at end of file
diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/store/children.get.js b/config/alfresco/templates/webscripts/org/alfresco/repository/store/children.get.js
index 4fafb37f7b..ee85e3058d 100644
--- a/config/alfresco/templates/webscripts/org/alfresco/repository/store/children.get.js
+++ b/config/alfresco/templates/webscripts/org/alfresco/repository/store/children.get.js
@@ -2,7 +2,7 @@ script:
{
// locate node
var pathSegments = url.match.split("/");
- var reference = [ url.templateArgs.store_type, url.templateArgs.store_id, url.templateArgs.id ];
+ var reference = [ url.templateArgs.store_type, url.templateArgs.store_id ].concat(url.templateArgs.id.split("/"));
model.node = cmis.findNode(pathSegments[2], reference);
if (model.node === null)
{
diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/store/parent.get.atomfeed.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/store/parent.get.atomfeed.ftl
new file mode 100644
index 0000000000..f79d53f12d
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/repository/store/parent.get.atomfeed.ftl
@@ -0,0 +1,23 @@
+<#import "/org/alfresco/cmis/entries.lib.atom.ftl" as entriesLib/>
+
+
+ Alfresco (${server.edition})
+ ${node.name}
+ ${xmldate(node.properties.modified)}
+ ${absurl(url.context)}/images/logo/AlfrescoLogo16.ico
+
+ ${node.properties.creator!""}
+
+ urn:uuid:${node.id}
+
+ <@parent node=node.parent recurse=returnToRoot/>
+
+
+<#macro parent node recurse=false>
+ <#if node?exists && node.isContainer>
+ <@entriesLib.folder node=node/>
+ <#if recurse>
+ <@parent node=node.parent recurse=true/>
+ #if>
+ #if>
+#macro>
\ No newline at end of file
diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/store/parent.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/repository/store/parent.get.desc.xml
new file mode 100644
index 0000000000..aa8e8e03eb
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/repository/store/parent.get.desc.xml
@@ -0,0 +1,8 @@
+
+ Retrieve Parent Folder
+ Retrieve parent folder
+ /api/node/{store_type}/{store_id}/{id}/parent?returnToRoot={returnToRoot}
+ /api/path/{store_type}/{store_id}/{id}/parent?returnToRoot={returnToRoot}
+ guest
+ argument
+
\ No newline at end of file
diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/store/parent.get.js b/config/alfresco/templates/webscripts/org/alfresco/repository/store/parent.get.js
new file mode 100644
index 0000000000..553d520fce
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/repository/store/parent.get.js
@@ -0,0 +1,20 @@
+script:
+{
+ // locate node
+ var pathSegments = url.match.split("/");
+ var reference = [ url.templateArgs.store_type, url.templateArgs.store_id ].concat(url.templateArgs.id.split("/"));
+ model.node = cmis.findNode(pathSegments[2], reference);
+ if (model.node === null)
+ {
+ status.code = 404;
+ status.message = "Repository " + pathSegments[2] + " " + reference.join("/") + " not found";
+ status.redirect = true;
+ break script;
+ }
+
+ // TODO: property filters
+
+ // retrieve parent
+ var returnToRoot = cmis.findArg(args.returnToRoot, headers["CMIS-returnToRoot"]);
+ model.returnToRoot = returnToRoot == "true" ? true : false;
+}
diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/store/parents.get.atomfeed.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/store/parents.get.atomfeed.ftl
new file mode 100644
index 0000000000..c790833014
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/repository/store/parents.get.atomfeed.ftl
@@ -0,0 +1,24 @@
+<#import "/org/alfresco/cmis/entries.lib.atom.ftl" as entriesLib/>
+
+
+ Alfresco (${server.edition})
+ ${node.name}
+ ${xmldate(node.properties.modified)}
+ ${absurl(url.context)}/images/logo/AlfrescoLogo16.ico
+
+ ${node.properties.creator!""}
+
+ urn:uuid:${node.id}
+
+ <@parent node=node.parent recurse=returnToRoot/>
+ <#-- TODO: secondary parents loop -->
+
+
+<#macro parent node recurse=false>
+ <#if node?exists && node.isContainer>
+ <@entriesLib.folder node=node/>
+ <#if recurse>
+ <@parent node=node.parent recurse=true/>
+ #if>
+ #if>
+#macro>
\ No newline at end of file
diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/store/parents.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/repository/store/parents.get.desc.xml
new file mode 100644
index 0000000000..669ad14305
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/repository/store/parents.get.desc.xml
@@ -0,0 +1,9 @@
+
+ Retrieve Parent Folders
+ Retrieve parent folders (primary and secondary)
+
+ /api/node/{store_type}/{store_id}/{id}/parents
+ /api/path/{store_type}/{store_id}/{id}/parents
+ guest
+ argument
+
\ No newline at end of file
diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/store/parents.get.js b/config/alfresco/templates/webscripts/org/alfresco/repository/store/parents.get.js
new file mode 100644
index 0000000000..924644527e
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/repository/store/parents.get.js
@@ -0,0 +1,21 @@
+script:
+{
+ // locate node
+ var pathSegments = url.match.split("/");
+ var reference = [ url.templateArgs.store_type, url.templateArgs.store_id ].concat(url.templateArgs.id.split("/"));
+ model.node = cmis.findNode(pathSegments[2], reference);
+ if (model.node === null)
+ {
+ status.code = 404;
+ status.message = "Repository " + pathSegments[2] + " " + reference.join("/") + " not found";
+ status.redirect = true;
+ break script;
+ }
+
+ // TODO: property filters
+
+ // TODO: check returnToRoot is required for getDocumentParents
+ // retrieve parent
+ var returnToRoot = cmis.findArg(args.returnToRoot, headers["CMIS-returnToRoot"]);
+ model.returnToRoot = returnToRoot == "true" ? true : false;
+}
diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/store/unfiled.get.atomfeed.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/store/unfiled.get.atomfeed.ftl
new file mode 100644
index 0000000000..3a2bdce3ed
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/repository/store/unfiled.get.atomfeed.ftl
@@ -0,0 +1,13 @@
+
+
+ Alfresco (${server.edition})
+ Unfiled Documents
+ ${xmldate(date)}
+ ${absurl(url.context)}/images/logo/AlfrescoLogo16.ico
+
+ System
+
+ urn:uuid:unfiled
+
+ <#-- NOTE: Alfresco does not yet support unfiled documents -->
+
diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/store/unfiled.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/repository/store/unfiled.get.desc.xml
new file mode 100644
index 0000000000..43c1637069
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/repository/store/unfiled.get.desc.xml
@@ -0,0 +1,7 @@
+
+ Unfiled Documents
+ Retrieve list of documents that are not in any folder
+ /api/unfiled
+ guest
+
+
\ No newline at end of file
diff --git a/config/alfresco/web-scripts-application-context.xml b/config/alfresco/web-scripts-application-context.xml
index d58e5f2185..f08f170509 100644
--- a/config/alfresco/web-scripts-application-context.xml
+++ b/config/alfresco/web-scripts-application-context.xml
@@ -149,6 +149,8 @@
+
+
@@ -403,5 +405,14 @@
+
+
+
+
+
+
+
+
+
diff --git a/source/java/org/alfresco/repo/cmis/CMISDescription.java b/source/java/org/alfresco/repo/cmis/CMISDescription.java
new file mode 100644
index 0000000000..c011123e6e
--- /dev/null
+++ b/source/java/org/alfresco/repo/cmis/CMISDescription.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2005-2008 Alfresco Software Limited.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * 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.cmis;
+
+import java.io.InputStream;
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.alfresco.web.scripts.DescriptionExtension;
+import org.alfresco.web.scripts.WebScriptException;
+import org.dom4j.Document;
+import org.dom4j.DocumentException;
+import org.dom4j.Element;
+import org.dom4j.io.SAXReader;
+
+
+/**
+ * Web Script Descriptor Extension
+ *
+ *
+ *
+ * @author davidc
+ */
+public class CMISDescription implements DescriptionExtension
+{
+
+ /* (non-Javadoc)
+ * @see org.alfresco.web.scripts.DescriptionExtension#parseExtensions(java.lang.String, java.io.InputStream)
+ */
+ public Map parseExtensions(String serviceDescPath, InputStream serviceDesc)
+ {
+ SAXReader reader = new SAXReader();
+ try
+ {
+ Map extensions = null;
+ Document document = reader.read(serviceDesc);
+ Element rootElement = document.getRootElement();
+ Element cmisElement = rootElement.element("cmis");
+ if (cmisElement != null)
+ {
+ extensions = new HashMap();
+ String version = cmisElement.attributeValue("version");
+ if (version == null || version.length() == 0)
+ {
+ throw new WebScriptException("Expected 'version' attribute on element");
+ }
+ extensions.put("cmis_version", version);
+ }
+ return extensions;
+ }
+ catch(DocumentException e)
+ {
+ throw new WebScriptException("Failed to parse web script description document " + serviceDescPath, e);
+ }
+ }
+
+}