Merged CMIS063 to HEAD

17100: Chemistry: AtomPub TCK updates, Alfresco CMIS URL bindings, Delete Content Stream

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@17258 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
David Caruana
2009-10-30 14:23:42 +00:00
parent ae1cbc22ab
commit be4912981e
80 changed files with 944 additions and 564 deletions

View File

@@ -93,7 +93,7 @@
<author><name>${node.properties.creator}</name></author> <author><name>${node.properties.creator}</name></author>
[@contentstream node/] [@contentstream node/]
<id>urn:uuid:${node.id}</id> <id>urn:uuid:${node.id}</id>
[#assign pwcuri]/api/pwc/[@linksLib.noderef node/][/#assign] [#assign pwcuri]/cmis/pwc/[@linksLib.noderef node/][/#assign]
[@linksLib.linkself href="${pwcuri}"/] [@linksLib.linkself href="${pwcuri}"/]
[@linksLib.linkstream node "enclosure"/] [@linksLib.linkstream node "enclosure"/]
[@linksLib.linknodeedit node/] [@linksLib.linknodeedit node/]
@@ -204,7 +204,7 @@
[/#macro] [/#macro]
[#macro assocCMISLinks assoc] [#macro assocCMISLinks assoc]
[#-- TODO: <link rel="allowableactions" href="${absurl(url.serviceContext)}/api/node/${node.nodeRef.storeRef.protocol}/${node.nodeRef.storeRef.identifier}/${node.nodeRef.id}/permissions"/> --] [#-- TODO: <link rel="allowableactions" href="${absurl(url.serviceContext)}/cmis/node/${node.nodeRef.storeRef.protocol}/${node.nodeRef.storeRef.identifier}/${node.nodeRef.id}/permissions"/> --]
[@linksLib.linktype assoc/] [@linksLib.linktype assoc/]
[@linksLib.linktosource assoc.source/] [@linksLib.linktosource assoc.source/]
[@linksLib.linktotarget assoc.target/] [@linksLib.linktotarget assoc.target/]

View File

@@ -21,7 +21,7 @@
<icon>${absurl(url.context)}/images/logo/AlfrescoLogo16.ico</icon> <icon>${absurl(url.context)}/images/logo/AlfrescoLogo16.ico</icon>
<id>${id}</id> <id>${id}</id>
[#nested] [#-- NOTE: Custom links --] [#nested] [#-- NOTE: Custom links --]
<title>${title}</title> <title>${title?xml}</title>
<updated>${xmldate(date)}</updated> <updated>${xmldate(date)}</updated>
[/#macro] [/#macro]
@@ -36,6 +36,6 @@
<icon>${absurl(url.context)}/images/logo/AlfrescoLogo16.ico</icon> <icon>${absurl(url.context)}/images/logo/AlfrescoLogo16.ico</icon>
<id>urn:uuid:${node.id}[#if kind != ""]-${kind}[/#if]</id> <id>urn:uuid:${node.id}[#if kind != ""]-${kind}[/#if]</id>
[#nested] [#-- NOTE: Custom links --] [#nested] [#-- NOTE: Custom links --]
<title>${node.name}[#if kind != ""] ${kind?capitalize}[/#if]</title> <title>${node.name?xml}[#if kind != ""] ${kind?capitalize}[/#if]</title>
<updated>${xmldate(node.properties.modified)}</updated> <updated>${xmldate(node.properties.modified)}</updated>
[/#macro] [/#macro]

View File

@@ -10,21 +10,21 @@
<atom:title>root collection</atom:title> <atom:title>root collection</atom:title>
<cmisra:collectionType>root</cmisra:collectionType> <cmisra:collectionType>root</cmisra:collectionType>
</collection> </collection>
<collection href="${absurl(url.serviceContext)}/api/types"> <collection href="${absurl(url.serviceContext)}/cmis/types">
<atom:title>type collection</atom:title> <atom:title>type collection</atom:title>
<cmisra:collectionType>types</cmisra:collectionType> <cmisra:collectionType>types</cmisra:collectionType>
</collection> </collection>
<collection href="${absurl(url.serviceContext)}/api/checkedout"> <collection href="${absurl(url.serviceContext)}/cmis/checkedout">
<atom:title>checkedout collection</atom:title> <atom:title>checkedout collection</atom:title>
<accept>${cmisconstants.MIMETYPE_ENTRY}</accept> <accept>${cmisconstants.MIMETYPE_ENTRY}</accept>
<cmisra:collectionType>checkedout</cmisra:collectionType> <cmisra:collectionType>checkedout</cmisra:collectionType>
</collection> </collection>
<collection href="${absurl(url.serviceContext)}/api/unfiled"> <collection href="${absurl(url.serviceContext)}/cmis/unfiled">
<atom:title>unfiled collection</atom:title> <atom:title>unfiled collection</atom:title>
<accept>${cmisconstants.MIMETYPE_ENTRY}</accept> <accept>${cmisconstants.MIMETYPE_ENTRY}</accept>
<cmisra:collectionType>unfiled</cmisra:collectionType> <cmisra:collectionType>unfiled</cmisra:collectionType>
</collection> </collection>
<collection href="${absurl(url.serviceContext)}/api/queries"> <collection href="${absurl(url.serviceContext)}/cmis/queries">
<atom:title>query collection</atom:title> <atom:title>query collection</atom:title>
<accept>${cmisconstants.MIMETYPE_CMIS_QUERY}</accept> <accept>${cmisconstants.MIMETYPE_CMIS_QUERY}</accept>
<cmisra:collectionType>query</cmisra:collectionType> <cmisra:collectionType>query</cmisra:collectionType>
@@ -32,7 +32,7 @@
<atom:link title="root folder tree" type="${cmisconstants.MIMETYPE_CMISTREE}" rel="${cmisconstants.REL_FOLDER_TREE}" href="${absurl(url.serviceContext)}[@linksLib.nodeuri defaultRootFolder/]/tree"/> <atom:link title="root folder tree" type="${cmisconstants.MIMETYPE_CMISTREE}" rel="${cmisconstants.REL_FOLDER_TREE}" href="${absurl(url.serviceContext)}[@linksLib.nodeuri defaultRootFolder/]/tree"/>
<atom:link title="root descendants" type="${cmisconstants.MIMETYPE_CMISTREE}" rel="${cmisconstants.REL_ROOT_DESCENDANTS}" href="${absurl(url.serviceContext)}[@linksLib.nodeuri defaultRootFolder/]/descendants"/> <atom:link title="root descendants" type="${cmisconstants.MIMETYPE_CMISTREE}" rel="${cmisconstants.REL_ROOT_DESCENDANTS}" href="${absurl(url.serviceContext)}[@linksLib.nodeuri defaultRootFolder/]/descendants"/>
<atom:link title="type descendants" type="${cmisconstants.MIMETYPE_CMISTREE}" rel="${cmisconstants.REL_TYPES_DESCENDANTS}" href="${absurl(url.serviceContext)}/api/types/descendants"/> <atom:link title="type descendants" type="${cmisconstants.MIMETYPE_CMISTREE}" rel="${cmisconstants.REL_TYPES_DESCENDANTS}" href="${absurl(url.serviceContext)}/cmis/types/descendants"/>
<cmisra:repositoryInfo> <cmisra:repositoryInfo>
<cmis:repositoryId>${server.id}</cmis:repositoryId> <cmis:repositoryId>${server.id}</cmis:repositoryId>
@@ -70,22 +70,23 @@
</cmisra:repositoryInfo> </cmisra:repositoryInfo>
<cmisra:uritemplate> <cmisra:uritemplate>
<cmisra:template>${absurl(url.serviceContext)}/api/node/{id}?filter={filter}&amp;includeAllowableActions={includeAllowableActions}&amp;includePolicyIds={includePolicyIds}&amp;includeRelationships={includeRelationships}&amp;includeACL={includeACL}&amp;renditionFilter={renditionFilter}</cmisra:template> <cmisra:template>${absurl(url.serviceContext)}/cmis/arg/n?noderef={id}&amp;filter={filter}&amp;includeAllowableActions={includeAllowableActions}&amp;includePolicyIds={includePolicyIds}&amp;includeRelationships={includeRelationships}&amp;includeACL={includeACL}&amp;renditionFilter={renditionFilter}</cmisra:template>
<cmisra:type>${cmisconstants.URI_OBJECT_BY_ID}</cmisra:type> <cmisra:type>${cmisconstants.URI_OBJECT_BY_ID}</cmisra:type>
<cmisra:mediatype>${cmisconstants.MIMETYPE_ENTRY}</cmisra:mediatype> <cmisra:mediatype>${cmisconstants.MIMETYPE_ENTRY}</cmisra:mediatype>
</cmisra:uritemplate> </cmisra:uritemplate>
<cmisra:uritemplate> <cmisra:uritemplate>
<cmisra:template>${absurl(url.serviceContext)}/api/path/{path}?filter={filter}&amp;includeAllowableActions={includeAllowableActions}&amp;includePolicyIds={includePolicyIds}&amp;includeRelationships={includeRelationships}&amp;includeACL={includeACL}&amp;renditionFilter={renditionFilter}</cmisra:template> [#-- NOTE: path provided as URL argument for safe handling by URI template generators --]
<cmisra:template>${absurl(url.serviceContext)}/cmis/s/${defaultRootFolder.storeType}:${defaultRootFolder.storeId}/arg/p?path={path}&amp;filter={filter}&amp;includeAllowableActions={includeAllowableActions}&amp;includePolicyIds={includePolicyIds}&amp;includeRelationships={includeRelationships}&amp;includeACL={includeACL}&amp;renditionFilter={renditionFilter}</cmisra:template>
<cmisra:type>${cmisconstants.URI_OBJECT_BY_PATH}</cmisra:type> <cmisra:type>${cmisconstants.URI_OBJECT_BY_PATH}</cmisra:type>
<cmisra:mediatype>${cmisconstants.MIMETYPE_ENTRY}</cmisra:mediatype> <cmisra:mediatype>${cmisconstants.MIMETYPE_ENTRY}</cmisra:mediatype>
</cmisra:uritemplate> </cmisra:uritemplate>
<cmisra:uritemplate> <cmisra:uritemplate>
<cmisra:template>${absurl(url.serviceContext)}/api/type/{id}</cmisra:template> <cmisra:template>${absurl(url.serviceContext)}/cmis/type/{id}</cmisra:template>
<cmisra:type>${cmisconstants.URI_TYPE_BY_ID}</cmisra:type> <cmisra:type>${cmisconstants.URI_TYPE_BY_ID}</cmisra:type>
<cmisra:mediatype>${cmisconstants.MIMETYPE_ENTRY}</cmisra:mediatype> <cmisra:mediatype>${cmisconstants.MIMETYPE_ENTRY}</cmisra:mediatype>
</cmisra:uritemplate> </cmisra:uritemplate>
<cmisra:uritemplate> <cmisra:uritemplate>
<cmisra:template>${absurl(url.serviceContext)}/api/query?q={q}&amp;searchAllVersions={searchAllVersions}&amp;maxItems={maxItems}&amp;skipCount={skipCount}&amp;includeAllowableActions={includeAllowableActions}&amp;includeRelationships={includeRelationships}</cmisra:template> <cmisra:template>${absurl(url.serviceContext)}/cmis/query?q={q}&amp;searchAllVersions={searchAllVersions}&amp;maxItems={maxItems}&amp;skipCount={skipCount}&amp;includeAllowableActions={includeAllowableActions}&amp;includeRelationships={includeRelationships}</cmisra:template>
<cmisra:type>${cmisconstants.URI_QUERY}</cmisra:type> <cmisra:type>${cmisconstants.URI_QUERY}</cmisra:type>
<cmisra:mediatype>${cmisconstants.MIMETYPE_FEED}</cmisra:mediatype> <cmisra:mediatype>${cmisconstants.MIMETYPE_FEED}</cmisra:mediatype>
</cmisra:uritemplate> </cmisra:uritemplate>

View File

@@ -1,9 +1,11 @@
<webscript> <webscript>
<shortname>CMIS Front Page</shortname> <shortname>CMIS AtomPub Service Document</shortname>
<description> <description>
</description> </description>
<url>/cmis</url> <url>/cmis</url>
<format default="html"/>
<format default="atomsvc"/>
<authentication>none</authentication> <authentication>none</authentication>
<family>CMIS</family> <family>CMIS</family>
</webscript> </webscript>

View File

@@ -1,7 +1,6 @@
var tckRunner = Packages.org.apache.chemistry.tck.atompub.tools.TCKRunner();
model.tckTests = tckRunner.getTestNames();
model.tckOptions = tckRunner.getOptions();
model.cmisVersion = cmis.version; model.cmisVersion = cmis.version;
model.defaultRootFolder = cmis.defaultRootFolder;
model.defaultRootFolderPath = cmis.defaultRootFolderPath;
model.querySupport = cmis.querySupport.label; model.querySupport = cmis.querySupport.label;
model.joinSupport = cmis.joinSupport.label; model.joinSupport = cmis.joinSupport.label;
model.pwcSearchable = cmis.pwcSearchable; model.pwcSearchable = cmis.pwcSearchable;

View File

@@ -0,0 +1,12 @@
<webscript>
<shortname>CMIS Index Page</shortname>
<description>
</description>
<url>/cmis/index</url>
<url>/cmis/index.html</url>
<format default="html"/>
<authentication>none</authentication>
<family>CMIS</family>
</webscript>

View File

@@ -0,0 +1,153 @@
[#ftl]
[#import "/org/alfresco/cmis/links.lib.atom.ftl" as linksLib/]
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Alfresco CMIS</title>
<link rel="stylesheet" href="${url.context}/css-boilerplate/screen.css" type="text/css" media="screen" charset="utf-8">
<!--[if lte IE 6]><link rel="stylesheet" href="${url.context}/css-boilerplate/lib/ie.css" type="text/css" media="screen" charset="utf-8"><![endif]-->
<script type="text/javascript">
function toggleDisplay(toggle)
{
var toggleBody = document.getElementById(toggle.id + "_body");
if (!toggleBody) return true;
if (toggleBody.style.display == "none")
{
toggleBody.style.display = "block";
toggle.innerHTML = "[-]";
}
else
{
toggleBody.style.display = "none";
toggle.innerHTML = "[+]";
}
return true;
}
</script>
</head>
<body>
<div id="page">
<div id="header">
<a href="http://www.alfresco.com"><img id="alflogo" src="${url.context}/images/logo/AlfrescoLogo200.png"/></a><a href="http://www.oasis-open.org/committees/cmis"><img id="alflogo" height="55px" src="${url.context}/images/logo/cmis_logo_100.png"/></a>
</div>
<div id="body" class="wrapper">
<div id="introduction">
<h2>Explore and Test CMIS</h2>
<p>The CMIS (Content Management Interoperability Services) specification is now very close to Public Review.</p>
<p>This site hosts a <a href="#repo">CMIS Repository</a> and <a href="#testatompub">CMIS AtomPub TCK</a> to assist the development of the specification and promote interoperability between up-and-coming implementations. Feel free to use them for building and testing your own CMIS clients and servers.</p>
<p>Frequent updates are made to both the Repository and TCK as issues are resolved or new capabilities added. Currently, <strong class="highlight">version ${cmisVersion}</strong> of the CMIS specification is supported.</p>
<a name="repo"></a>
<h3>Alfresco CMIS Repository</h3>
<p>Point your CMIS client to one of the following Alfresco CMIS bindings (with <strong>user=admin</strong> and <strong>password=admin</strong>).</p>
<ul>
<li>CMIS AtomPub Binding: <a href="${url.serviceContext}/cmis">AtomPub Service Document</a></li>
<li>CMIS Web Services Binding: <a href="${url.context}/cmis">WSDL Documents</a></li>
</ul>
<p>You can also browse this repository via the <a href="${url.context}/cmisbrowse?url=${absurl(url.serviceContext)}/cmis">CMIS FileShare browser</a>.</p>
<h5><span id="repoinfo" class="toggle" onclick="return toggleDisplay(this)">[+]</span> CMIS Repository Information</h5>
<table id="repoinfo_body" style="display: none;">
<tr><td>Version Supported</td><td>${cmisVersion}</td></tr>
<tr><td>Repository Id</td><td>${server.id}</td></tr>
<tr><td>Repository Name</td><td>${server.name}</td></tr>
<tr><td>Repository Description</td><td>[none]</td></tr>
<tr><td>Vendor Name</td><td>Alfresco</td></tr>
<tr><td>Product Name</td><td>Alfresco Repository (${server.edition})</td></tr>
<tr><td>Product Version</td><td>${server.version}</td></tr>
</table>
<h5><span id="repocapabilities" class="toggle" onclick="return toggleDisplay(this)">[+]</span> CMIS Repository Capabilities</h5>
<table id="repocapabilities_body" style="display: none;">
<tr><td>ACL</td><td>none</td></tr>
<tr><td>AllVersionsSearchable</td><td>${allVersionsSearchable?string}</td></tr>
<tr><td>Changes</td><td>[#-- TODO --]none</td></tr>
<tr><td>ContentStreamUpdatability</td><td>anytime</td></tr>
<tr><td>GetDescendants</td><td>true</td></tr>
<tr><td>GetFolderTree</td><td>true</td></tr>
<tr><td>Multifiling</td><td>true</td></tr>
<tr><td>PWCSearchable</td><td>${pwcSearchable?string}</td></tr>
<tr><td>PWCUpdateable</td><td>true</td></tr>
<tr><td>Query</td><td>${querySupport}</td></tr>
<tr><td>Join</td><td>${joinSupport}</td></tr>
<tr><td>Renditions</td><td>none</td></tr>
<tr><td>Unfiling</td><td>false</td></tr>
<tr><td>VersionSpecificFiling</td><td>false</td></tr>
</table>
<p><em>Note: The contents of this repository may be cleaned at any time.</em><p>
<a name="testatompub"></a>
<h3>CMIS AtomPub TCK</h3>
<p>Point the TCK (Test Compatibility Kit) at your CMIS Repository AtomPub Service Document. Provide credentials (or leave blank, if authentication not required) and adjust options as necessary. Hit the '<strong>Start TCK</strong>' button for a test report.</p>
<p><em>Tip: Enable the 'Trace Reqs/Responses' option for examples of conversations with a CMIS Repository via AtomPub.</em></p>
<p><em>Note: This TCK is now contributed to <a href="http://incubator.apache.org/chemistry/">Apache Chemistry</a>.</em></p>
<form action="${url.serviceContext}/cmis/test" method="post" class="hform">
<fieldset>
<legend>CMIS Repository</legend>
<p><label>Service Document</label><input type="text" name="chemistry.tck.serviceUrl" size="50" value="${absurl(url.serviceContext)}/cmis"></p>
<p><label>Username</label><input type="text" name="chemistry.tck.user" value="admin"></p>
<p><label>Password</label><input type="text" name="chemistry.tck.password" value="admin"></p>
</fieldset>
<fieldset>
<legend>Options</legend>
<p class="checkbox"><label>Validate Responses</label><input type="checkbox" name="chemistry.tck.validate" value="true"[#if tckOptions.validate] checked="checked"[/#if]></p>
<p class="checkbox"><label>Fail on Validation Error</label><input type="checkbox" name="chemistry.tck.failOnValidationError" value="true"[#if tckOptions.failOnValidationError] checked="checked"[/#if]></p>
<p class="checkbox"><label>Trace Reqs/Responses</label><input type="checkbox" name="chemistry.tck.traceRequests" value="true"[#if tckOptions.traceRequests] checked="checked"[/#if]><p>
<p><label>Tests</label><input name="chemistry.tck.tests" value="RepositoryServiceTest.testRepository"></p>
<p><label><span id="availtests" class="toggle" onclick="return toggleDisplay(this)">[+]</span> Available Tests</label>
<table id="availtests_body" style="display: none;">
<tr><td>Note: Use wildcard * to execute multiple tests</td></tr>
[#list tckTests as test]<tr><td>${test}</td></tr>[/#list]
</table></p>
</fieldset>
<p><input type="submit" name="submit" value="Start TCK" class="button"></p>
</form>
</div>
<div id="resources">
<h3>CMIS Resources</h3>
<ul>
<li><a href="http://www.oasis-open.org/committees/cmis">OASIS Technical Committee</a></li>
<li><a href="http://xml.coverpages.org/cmis.html">Cover Pages</a></li>
<li><a href="http://www.oasis-open.org/committees/download.php/34413/CMIS-70b3.zip"><strong>Specification v0.7</strong></a></li>
</ul>
<h3>Alfresco Resources</h3>
<ul>
<li><a href="http://wiki.alfresco.com/wiki/CMIS">CMIS Wiki</a></li>
<li><a href="http://blogs.alfresco.com/cmis/">CMIS Blog</a></li>
<li><a href="http://wiki.alfresco.com/wiki/Download_Community_Edition">Download</a> Repository</a></li>
<li><a href="http://wiki.alfresco.com/wiki/Alfresco_SVN_Development_Environment">Source Code</a> for Repository</li>
<li><a href="http://svn.alfresco.com/repos/alfresco-open-mirror/alfresco/HEAD/root/design/changes_v0.62f_to_v0.7.txt">Changes from v0.62 to v0.7</li>
</ul>
<h3>Apache Chemistry</h3>
<ul>
<li><a href="http://incubator.apache.org/chemistry/">Home Page</a></li>
<li><a href="http://svn.apache.org/viewvc/incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/">Source Code</a> for TCK</li>
</ul>
<h3>CMIS FileShare</h3>
<ul>
<li><a href="http://cmisfs.fmui.de/">Home Page</a></li>
</ul>
<h3>Provide Feedback</h3>
<ul>
<li><a href="http://forums.alfresco.com/en/viewforum.php?f=45">CMIS Forum</a></li>
<li><a href="https://issues.alfresco.com/jira/secure/IssueNavigator.jspa?reset=true&mode=hide&pid=10103&sorter/order=DESC&sorter/field=priority&resolution=-1&component=10459">Find / Raise Issues</li>
<li><a href="http://groups.google.com/group/cmis-interop">CMIS Interop Group</a></li>
</ul>
</div>
</div>
<div id="footer">
<p>Last Updated: $Date: 2009-10-16 23:17:08 +0100 (Fri, 16 Oct 2009) $, Alfresco Software, Inc</p>
</div>
</div>
</body>
</html>

View File

@@ -1,6 +1,7 @@
var tckRunner = Packages.org.apache.chemistry.tck.atompub.tools.TCKRunner();
model.tckTests = tckRunner.getTestNames();
model.tckOptions = tckRunner.getOptions();
model.cmisVersion = cmis.version; model.cmisVersion = cmis.version;
model.defaultRootFolder = cmis.defaultRootFolder;
model.defaultRootFolderPath = cmis.defaultRootFolderPath;
model.querySupport = cmis.querySupport.label; model.querySupport = cmis.querySupport.label;
model.joinSupport = cmis.joinSupport.label; model.joinSupport = cmis.joinSupport.label;
model.pwcSearchable = cmis.pwcSearchable; model.pwcSearchable = cmis.pwcSearchable;

View File

@@ -6,7 +6,7 @@
[#-- Link to repository service document --] [#-- Link to repository service document --]
[#macro linkservice] [#macro linkservice]
<link rel="${cmisconstants.REL_SERVICE}" href="${absurl(url.serviceContext)}/api/repository"/> <link rel="${cmisconstants.REL_SERVICE}" href="${absurl(url.serviceContext)}/cmis"/>
[/#macro] [/#macro]
[#-- Link to node allowable actions --] [#-- Link to node allowable actions --]
@@ -111,7 +111,7 @@
[/#macro] [/#macro]
[#macro linkassocedit assoc] [#macro linkassocedit assoc]
<link rel="edit" href="${absurl(url.serviceContext)}[@nodeuri node/]"/> <link rel="edit" href="${absurl(url.serviceContext)}[@assocuri assoc/]"/>
[/#macro] [/#macro]
[#-- Link to via --] [#-- Link to via --]
@@ -125,19 +125,22 @@
[#-- --] [#-- --]
[#-- Helper to render Alfresco service document uri --] [#-- Helper to render Alfresco service document uri --]
[#macro serviceuri]${absurl(url.serviceContext)}/api/repository[/#macro] [#macro serviceuri]${absurl(url.serviceContext)}/cmis[/#macro]
[#-- Helper to render Alfresco content stream uri --] [#-- Helper to render Alfresco content stream uri --]
[#macro contenturi node]${absurl(url.serviceContext)}/api/node/${node.nodeRef.storeRef.protocol}/${node.nodeRef.storeRef.identifier}/${node.nodeRef.id}/content[#if node.properties.name?? && node.properties.name?last_index_of(".") != -1]${encodeuri(node.properties.name?substring(node.properties.name?last_index_of(".")))}[/#if][/#macro] [#macro contenturi node]${absurl(url.serviceContext)}/cmis/[@noderef node/]/content[#if node.properties.name?? && node.properties.name?last_index_of(".") != -1]${encodeuri(node.properties.name?substring(node.properties.name?last_index_of(".")))}[/#if][/#macro]
[#-- Helper to render Store Ref --]
[#macro storeref store]s/${store.protocol}:${store.identifier}[/#macro]
[#-- Helper to render Node Ref --] [#-- Helper to render Node Ref --]
[#macro noderef node]${node.nodeRef.storeRef.protocol}/${node.nodeRef.storeRef.identifier}/${node.nodeRef.id}[/#macro] [#macro noderef node][@storeref node.nodeRef.storeRef/]/i/${node.nodeRef.id}[/#macro]
[#-- Helper to render Alfresco Node uri --] [#-- Helper to render Alfresco Node uri --]
[#macro nodeuri node]/api/node/[@noderef node/][/#macro] [#macro nodeuri node]/cmis/[@noderef node/][/#macro]
[#-- Helper to render Alfresco Assoc uri --] [#-- Helper to render Alfresco Assoc uri --]
[#macro assocuri assoc]/api/rel/[@noderef assoc.source/]/type/${cmistype(assoc).typeId.id!"undefined"}/target/[@noderef assoc.target/][/#macro] [#macro assocuri assoc]/cmis/rel/[@noderef assoc.source/]/type/${cmistype(assoc).typeId.id!"undefined"}/target/[@noderef assoc.target/][/#macro]
[#-- Helper to render Alfresco Type uri --] [#-- Helper to render Alfresco Type uri --]
[#macro typeuri typedef]/api/type/${typedef.typeId.id}[/#macro] [#macro typeuri typedef]/cmis/type/${typedef.typeId.id}[/#macro]

View File

@@ -23,6 +23,7 @@ function createNode(parent, entry, slug)
} }
// construct node of folder or file // construct node of folder or file
var node = null;
var name = (slug !== null) ? slug : entry.title; var name = (slug !== null) ? slug : entry.title;
var baseType = type.typeId.baseTypeId; var baseType = type.typeId.baseTypeId;
if (baseType == DOCUMENT_TYPE_ID) if (baseType == DOCUMENT_TYPE_ID)

View File

@@ -0,0 +1,62 @@
//
// Get Node from URL
//
// @return node (or null, if not found)
function getObjectFromUrl()
{
var ret = new Object();
ret.ref = cmis.createObjectReferenceFromUrl(args, url.templateArgs);
if (ret.ref == null)
{
status.setCode(400, "Cannot determine object reference from URL");
return ret;
}
ret.node = cmis.getNode(ret.ref);
if (ret.node === null)
{
status.setCode(404, "Cannot find object for " + ret.ref.toString());
}
return ret;
}
//
// Get Node from Object Id
//
// @return node (or null, if not found)
function getObjectFromObjectId(objectId)
{
var ret = new Object();
ret.ref = cmis.createObjectIdReference(objectId);
if (ret.ref == null)
{
status.setCode(400, "Cannot create object id reference from " + objectId);
return ret;
}
ret.node = cmis.getNode(ret.ref);
if (ret.node === null)
{
status.setCode(404, "Cannot find object for " + ret.ref.toString());
}
return ret;
}
//
// Get Association from URL
//
// @return association (or null, if not found)
function getAssocFromUrl()
{
var ret = new Object();
ret.ref = cmis.createRelationshipReferenceFromUrl(args, url.templateArgs);
if (ret.ref == null)
{
status.setCode(400, "Cannot determine association reference from URL");
return ret;
}
ret.assoc = cmis.getAssociation(ret.ref);
if (ret.assoc === null)
{
status.setCode(404, "Cannot find association for " + ret.ref.toString());
}
return ret;
}

View File

@@ -13,7 +13,7 @@ boolean trace: true => trace request and response bodies
String tests: names of tests to execute (use * in test name to represent wildcard) (Default: *)<br> String tests: names of tests to execute (use * in test name to represent wildcard) (Default: *)<br>
]]> ]]>
</description> </description>
<url>/api/cmis/test?url={serviceUrl}&amp;user={user?}&amp;validate={validate?}&amp;trace={trace?}&amp;tests={tests?}</url> <url>/cmis/test?url={serviceUrl}&amp;user={user?}&amp;validate={validate?}&amp;trace={trace?}&amp;tests={tests?}</url>
<authentication>none</authentication> <authentication>none</authentication>
<format default="text"/> <format default="text"/>
<family>CMIS</family> <family>CMIS</family>

View File

@@ -1,39 +0,0 @@
<webscript>
<shortname>Repository AtomPub Service Document (getRepositoryInfo)</shortname>
<description>
<![CDATA[
This service is used to retrieve information about the CMIS repository and the capabilities it supports.
<br>
<br>
Outputs:<br>
<br>
ID repositoryId: Repository Id (same as input)<br>
String repositoryName: Repository name<br>
URI repositoryURI: URI for this repository<br>
String repositoryDescription: Description of this repository<br>
ID rootFolderId: Root folder Id<br>
String vendorName: Repository vendor name<br>
String productName: Repository product name<br>
String productVersion: Product Version Information<br>
String cmisVersionsSupported: Version of CMIS standard supported.<br>
XML repositorySpecificInformation: Repository-specific information<br>
<br>
Capabilities:<br>
<br>
boolean capabilityMultifiling<br>
boolean capabilitiyUnfiling<br>
Boolean capabilityVersionSpecificFiling<br>
Boolean capabilityPWCUpdatable<br>
Boolean capabilityAllVersionsSearchable<br>
Boolean capabilityPWCSearchable<br>
Enum capabilityJoin: nojoin, inneronly, innerAndouter<br>
Enum capabilityFulltext: nofulltext, fulltextonly, fulltextandstructured<br>
&lt;Array&gt; relatedRepositories
]]>
</description>
<url>/api/repository</url>
<url>/api/cmis</url>
<format default="atomsvc"/>
<authentication>user</authentication>
<family>CMIS</family>
</webscript>

View File

@@ -66,7 +66,7 @@ script:
} }
// construct query uri // construct query uri
model.queryUri = "/api/query"; model.queryUri = "/cmis/query";
model.queryArgs = cmis.ARG_QUERY_STATEMENT + "=" + model.statement; model.queryArgs = cmis.ARG_QUERY_STATEMENT + "=" + model.statement;
if (model.includeAllowableActions) model.queryArgs += "&" + cmis.ARG_INCLUDE_ALLOWABLE_ACTIONS + "=true"; if (model.includeAllowableActions) model.queryArgs += "&" + cmis.ARG_INCLUDE_ALLOWABLE_ACTIONS + "=true";
model.queryArgs += "&" + cmis.ARG_SKIP_COUNT + "=" + page.number; model.queryArgs += "&" + cmis.ARG_SKIP_COUNT + "=" + page.number;

View File

@@ -29,7 +29,7 @@ It is recommended that “includeAllowableActions” be used with query statemen
"IncludeRelationships" indicates whether relationships are also returned for each returned object. If it is set to "source" or "target", relationships for which the returned object is a source, or respectively a target, will also be returned. If it is set to "both", relationships for which the returned object is either a source or a target will be returned. If it is set to "none", relationships are not returned.<br> "IncludeRelationships" indicates whether relationships are also returned for each returned object. If it is set to "source" or "target", relationships for which the returned object is a source, or respectively a target, will also be returned. If it is set to "both", relationships for which the returned object is either a source or a target will be returned. If it is set to "none", relationships are not returned.<br>
]]> ]]>
</description> </description>
<url>/api/queries</url> <url>/cmis/queries</url>
<authentication>user</authentication> <authentication>user</authentication>
<transaction allow="readonly"/> <transaction allow="readonly"/>
<format default="atomfeed"/> <format default="atomfeed"/>

View File

@@ -29,7 +29,7 @@ It is recommended that “includeAllowableActions” be used with query statemen
"IncludeRelationships" indicates whether relationships are also returned for each returned object. If it is set to "source" or "target", relationships for which the returned object is a source, or respectively a target, will also be returned. If it is set to "both", relationships for which the returned object is either a source or a target will be returned. If it is set to "none", relationships are not returned.<br> "IncludeRelationships" indicates whether relationships are also returned for each returned object. If it is set to "source" or "target", relationships for which the returned object is a source, or respectively a target, will also be returned. If it is set to "both", relationships for which the returned object is either a source or a target will be returned. If it is set to "none", relationships are not returned.<br>
]]> ]]>
</description> </description>
<url>/api/query?q={q}&amp;includeAllowableActions={includeAllowableActions?}&amp;searchAllVersions={searchAllVersions?}&amp;skipCount={skipCount?}&amp;maxItems={maxItems?}</url> <url>/cmis/query?q={q}&amp;includeAllowableActions={includeAllowableActions?}&amp;searchAllVersions={searchAllVersions?}&amp;skipCount={skipCount?}&amp;maxItems={maxItems?}</url>
<authentication>user</authentication> <authentication>user</authentication>
<transaction allow="readonly"/> <transaction allow="readonly"/>
<format default="atomfeed"/> <format default="atomfeed"/>

View File

@@ -1,8 +1,15 @@
<webscript> <webscript>
<shortname>Retrieve Allowable Actions</shortname> <shortname>Retrieve Allowable Actions</shortname>
<description>Retrieve Allowable Actions</description> <description>Retrieve Allowable Actions</description>
<!-- by object id -->
<url>/cmis/i/{id}/allowableactions</url>
<url>/cmis/s/{store}/i/{id}/allowableactions</url>
<!-- by path -->
<url>/cmis/p{path}/allowableactions</url>
<url>/cmis/s/{store}/p{path}/allowableactions</url>
<!-- old style; backwards compatibility -->
<url>/api/node/{store_type}/{store_id}/{id}/allowableactions</url> <url>/api/node/{store_type}/{store_id}/{id}/allowableactions</url>
<url>/api/path/{store_type}/{store_id}/{id}/allowableactions</url> <url>/api/path/{store_type}/{store_id}/{path}/allowableactions</url>
<authentication>guest</authentication> <authentication>guest</authentication>
<transaction allow="readonly"/> <transaction allow="readonly"/>
<format default="cmisallowableactions">argument</format> <format default="cmisallowableactions">argument</format>

View File

@@ -1,17 +1,18 @@
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/cmis/read.lib.js">
script: script:
{ {
// locate node var object = getObjectFromUrl();
var pathSegments = url.match.split("/"); if (object.node == null)
var reference = [ url.templateArgs.store_type, url.templateArgs.store_id ].concat(url.templateArgs.id.split("/")); {
model.node = cmis.findNode(pathSegments[2], reference); break script
if (model.node === null) }
model.node = object.node;
if (model.node == null)
{ {
status.code = 404;
status.message = "Repository " + pathSegments[2] + " " + reference.join("/") + " not found";
status.redirect = true;
break script; break script;
} }
// TODO: handle version?? // TODO: handle version??
} }

View File

@@ -28,7 +28,7 @@ If “includeAllowableActions” is TRUE, the repository will return the allowab
If no “maxItems” value is provided, then the Repository will determine an appropriate number of items to return. How the Repository determines this value is repository-specific and opaque to CMIS.<br> If no “maxItems” value is provided, then the Repository will determine an appropriate number of items to return. How the Repository determines this value is repository-specific and opaque to CMIS.<br>
]]> ]]>
</description> </description>
<url>/api/checkedout?folderId={folderId?}&amp;includeDescendants={includeDescendants?}&amp;filter={filter?}&amp;skipCount={skipCount?}&amp;maxItems={maxItems?}&amp;includeAllowableActions={includeAllowableActions?}</url> <url>/cmis/checkedout?folderId={folderId?}&amp;includeDescendants={includeDescendants?}&amp;filter={filter?}&amp;skipCount={skipCount?}&amp;maxItems={maxItems?}&amp;includeAllowableActions={includeAllowableActions?}</url>
<authentication>user</authentication> <authentication>user</authentication>
<transaction allow="readonly"/> <transaction allow="readonly"/>
<format default="atomfeed"/> <format default="atomfeed"/>

View File

@@ -1,3 +1,5 @@
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/cmis/read.lib.js">
script: script:
{ {
// locate (optional) folder // locate (optional) folder
@@ -5,18 +7,16 @@ script:
var folderId = args[cmis.ARG_FOLDER_ID]; var folderId = args[cmis.ARG_FOLDER_ID];
if (folderId !== null) if (folderId !== null)
{ {
model.folder = cmis.findNode(folderId); var folder = getObjectFromObjectId(folderId);
if (model.folder === null) if (folder.node === null)
{ {
status.code = 400;
status.message = "Folder " + folderId + " not found";
status.redirect = true;
break script; break script;
} }
model.folder = folder.node;
if (!model.folder.isContainer) if (!model.folder.isContainer)
{ {
status.code = 400; status.code = 400;
status.message = "Folder id " + folderId + " does not refer to a folder"; status.message = "Folder id " + folder.ref + " does not refer to a folder";
status.redirect = true; status.redirect = true;
break script; break script;
} }

View File

@@ -1,3 +1,5 @@
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/cmis/read.lib.js">
script: script:
{ {
// ensure atom entry is posted // ensure atom entry is posted
@@ -21,20 +23,18 @@ script:
} }
// locate node // locate node
model.node = cmis.findNode(objectId); var object = getObjectFromObjectId(objectId);
if (model.node === null) if (object.node === null)
{ {
status.code = 400;
status.message = "Repository node " + objectId + " not found";
status.redirect = true;
break script; break script;
} }
model.node = object.node;
// ensure node can be checked-out // ensure node can be checked-out
if (!model.node.isDocument) if (!model.node.isDocument)
{ {
status.code = 400; status.code = 400;
status.message = "Cannot checkout node " + objectId + " as it is not a document"; status.message = "Cannot checkout node " + object.ref + " as it is not a document";
status.redirect = true; status.redirect = true;
break script; break script;
} }
@@ -43,7 +43,7 @@ script:
if (model.node.isLocked || model.node.hasAspect("cm:workingCopy")) if (model.node.isLocked || model.node.hasAspect("cm:workingCopy"))
{ {
status.code = 400; status.code = 400;
status.message = "Cannot checkout node " + objectId + " as it is already checked-out"; status.message = "Cannot checkout node " + object.ref + " as it is already checked-out";
status.redirect = true; status.redirect = true;
break script; break script;
} }
@@ -61,6 +61,6 @@ script:
// setup for 201 Created response // setup for 201 Created response
// TODO: set Content-Location // TODO: set Content-Location
status.code = 201; status.code = 201;
status.location = url.server + url.serviceContext + "/api/pwc/" + model.pwc.nodeRef.storeRef.protocol + "/" + model.pwc.nodeRef.storeRef.identifier + "/" + model.pwc.nodeRef.id; status.location = url.server + url.serviceContext + "/cmis/pwc/s/" + model.pwc.nodeRef.storeRef.protocol + ":" + model.pwc.nodeRef.storeRef.identifier + "/i/" + model.pwc.nodeRef.id;
status.redirect = true; status.redirect = true;
} }

View File

@@ -23,7 +23,7 @@ CheckOut() on a non-document object will throw OperationNotSupportedException.<b
Some repositories may not support updating of private working copies and the updates MUST be supplied via checkIn().<br> Some repositories may not support updating of private working copies and the updates MUST be supplied via checkIn().<br>
]]> ]]>
</description> </description>
<url>/api/checkedout</url> <url>/cmis/checkedout</url>
<authentication>user</authentication> <authentication>user</authentication>
<format default="atomentry"/> <format default="atomentry"/>
<family>CMIS</family> <family>CMIS</family>

View File

@@ -34,8 +34,17 @@ If “includeAllowableActions” is TRUE, the repository will return the allowab
If no “maxItems” value is provided, then the Repository will determine an appropriate number of items to return. How the Repository determines this value is repository-specific and opaque to CMIS.<br> If no “maxItems” value is provided, then the Repository will determine an appropriate number of items to return. How the Repository determines this value is repository-specific and opaque to CMIS.<br>
]]> ]]>
</description> </description>
<!-- by object id -->
<url>/cmis/i/{id}/children?types={types}&amp;filter={filter?}&amp;skipCount={skipCount?}&amp;maxItems={maxItems?}&amp;includeAllowableActions={includeAllowableActions?}</url>
<url>/cmis/s/{store}/i/{id}/children?types={types}&amp;filter={filter?}&amp;skipCount={skipCount?}&amp;maxItems={maxItems?}&amp;includeAllowableActions={includeAllowableActions?}</url>
<!-- by path -->
<url>/cmis/p{path}/children?types={types}&amp;filter={filter?}&amp;skipCount={skipCount?}&amp;maxItems={maxItems?}&amp;includeAllowableActions={includeAllowableActions?}</url>
<url>/cmis/s/{store}/p{path}/children?types={types}&amp;filter={filter?}&amp;skipCount={skipCount?}&amp;maxItems={maxItems?}&amp;includeAllowableActions={includeAllowableActions?}</url>
<!-- alfresco style -->
<url>/api/node/{store_type}/{store_id}/{id}/children?types={types}&amp;filter={filter?}&amp;skipCount={skipCount?}&amp;maxItems={maxItems?}&amp;includeAllowableActions={includeAllowableActions?}</url> <url>/api/node/{store_type}/{store_id}/{id}/children?types={types}&amp;filter={filter?}&amp;skipCount={skipCount?}&amp;maxItems={maxItems?}&amp;includeAllowableActions={includeAllowableActions?}</url>
<url>/api/path/{store_type}/{store_id}/{id}/children?types={types}&amp;filter={filter?}&amp;skipCount={skipCount?}&amp;maxItems={maxItems?}&amp;includeAllowableActions={includeAllowableActions?}</url> <url>/api/path/{store_type}/{store_id}/{path}/children?types={types}&amp;filter={filter?}&amp;skipCount={skipCount?}&amp;maxItems={maxItems?}&amp;includeAllowableActions={includeAllowableActions?}</url>
<authentication>guest</authentication> <authentication>guest</authentication>
<transaction allow="readonly"/> <transaction allow="readonly"/>
<format default="atomfeed">argument</format> <format default="atomfeed">argument</format>

View File

@@ -1,17 +1,15 @@
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/cmis/read.lib.js">
script: script:
{ {
// locate node // locate node
var pathSegments = url.match.split("/"); var object = getObjectFromUrl();
var reference = [ url.templateArgs.store_type, url.templateArgs.store_id ].concat(url.templateArgs.id.split("/")); if (object.node == null)
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; break script;
} }
model.node = object.node;
// handle filters // handle filters
model.types = args[cmis.ARG_TYPES] === null ? cmis.defaultTypesFilter : args[cmis.ARG_TYPES]; model.types = args[cmis.ARG_TYPES] === null ? cmis.defaultTypesFilter : args[cmis.ARG_TYPES];
if (!cmis.isValidTypesFilter(model.types)) if (!cmis.isValidTypesFilter(model.types))

View File

@@ -1,5 +1,6 @@
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/cmis/constants.lib.js"> <import resource="classpath:alfresco/templates/webscripts/org/alfresco/cmis/constants.lib.js">
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/cmis/atomentry.lib.js"> <import resource="classpath:alfresco/templates/webscripts/org/alfresco/cmis/read.lib.js">
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/cmis/modify.lib.js">
script: script:
{ {
@@ -13,16 +14,12 @@ script:
} }
// locate parent node // locate parent node
var pathSegments = url.match.split("/"); var parent = getObjectFromUrl();
var reference = [ url.templateArgs.store_type, url.templateArgs.store_id ].concat(url.templateArgs.id.split("/")); if (parent.node == null)
model.parent = cmis.findNode(pathSegments[2], reference);
if (model.parent === null)
{ {
status.code = 404;
status.message = "Repository " + pathSegments[2] + " " + reference.join("/") + " not found";
status.redirect = true;
break script; break script;
} }
model.parent = parent.node;
// is this a create or move? // is this a create or move?
var object = entry.getExtension(atom.names.cmisra_object); var object = entry.getExtension(atom.names.cmisra_object);
@@ -41,40 +38,45 @@ script:
} }
else else
{ {
// locate node and its source folder
var object = getObjectFromObjectId(objectId);
if (object.node == null)
{
break script;
}
node = object.node;
// move node // move node
var sourceFolderId = args[cmis.ARG_SOURCE_FOLDER_ID]; var sourceFolderId = args[cmis.ARG_SOURCE_FOLDER_ID];
if (sourceFolderId == null) if (sourceFolderId == null)
{ {
status.code = 400; status.code = 400;
status.message = "Move of object " + objectId + " requires sourceFolderId argument"; status.message = "Move of object " + object.ref + " requires sourceFolderId argument";
status.redirect = true; status.redirect = true;
break script; break script;
} }
// locate node and its source folder var sourceFolderObject = getObjectFromObjectId(sourceFolderId);
node = search.findNode(objectId); if (sourceFolderObject.node == null)
if (node == null)
{ {
status.code = 400; status.code = 400;
status.message = "Object " + objectId + " does not exist"; break script;
status.redirect = true; }
break script; if (!sourceFolderObject.node.nodeRef.equals(node.parent.nodeRef))
} {
sourceFolder = search.findNode(sourceFolderId); status.code = 400;
if (sourceFolder == null || !(sourceFolder.nodeRef.equals(node.parent.nodeRef))) status.message = "Source Folder " + sourceFolderObject.ref + " is not parent of object " + object.ref;
{
status.code = 400;
status.message = "Source Folder " + sourceFolderId + " is not valid for object " + objectId;
status.redirect = true; status.redirect = true;
break script; break script;
} }
var sourceFolder = sourceFolderObject.node;
// perform move // perform move
var success = node.move(model.parent); var success = node.move(model.parent);
if (!success) if (!success)
{ {
status.code = 500; status.code = 500;
status.message = "Failed to move object " + objectId + " from folder " + sourceFolderId + " to folder " + model.parent.nodeRef; status.message = "Failed to move object " + object.ref + " from folder " + sourceFolderObject.ref + " to folder " + parent.ref;
status.redirect = true; status.redirect = true;
break script; break script;
} }
@@ -85,6 +87,6 @@ script:
model.node = node; model.node = node;
// TODO: set Content-Location // TODO: set Content-Location
status.code = 201; status.code = 201;
status.location = url.server + url.serviceContext + "/api/node/" + node.nodeRef.storeRef.protocol + "/" + node.nodeRef.storeRef.identifier + "/" + node.nodeRef.id; status.location = url.server + url.serviceContext + "/cmis/s/" + node.nodeRef.storeRef.protocol + ":" + node.nodeRef.storeRef.identifier + "/i/" + node.nodeRef.id;
status.redirect = true; status.redirect = true;
} }

View File

@@ -41,8 +41,16 @@ If the to-be-created Folders Object Type is not one of the “Allowed_Child_O
Root folder can not be created using this service.<br> Root folder can not be created using this service.<br>
]]> ]]>
</description> </description>
<url>/cmis/i/{id}/children?sourceFolderId={sourceFolderId}</url>
<url>/cmis/s/{store}/i/{id}/children?sourceFolderId={sourceFolderId}</url>
<!-- by path -->
<url>/cmis/p{path}/children?sourceFolderId={sourceFolderId}</url>
<url>/cmis/s/{store}/p{path}/children?sourceFolderId={sourceFolderId}</url>
<!-- alfresco style -->
<url>/api/node/{store_type}/{store_id}/{id}/children?sourceFolderId={sourceFolderId}</url> <url>/api/node/{store_type}/{store_id}/{id}/children?sourceFolderId={sourceFolderId}</url>
<url>/api/path/{store_type}/{store_id}/{id}/children?sourceFolderId={sourceFolderId}</url> <url>/api/path/{store_type}/{store_id}/{path}/children?sourceFolderId={sourceFolderId}</url>
<authentication>user</authentication> <authentication>user</authentication>
<format default="atomentry"/> <format default="atomentry"/>
<family>CMIS</family> <family>CMIS</family>

View File

@@ -2,11 +2,20 @@
<shortname>Content Delete (deleteContent)</shortname> <shortname>Content Delete (deleteContent)</shortname>
<description> <description>
</description> </description>
<!-- by object id -->
<url>/cmis/i/{id}/content{property}</url>
<url>/cmis/s/{store}/i/{id}/content{property}</url>
<!-- by path -->
<url>/cmis/p{path}/content{property}</url>
<url>/cmis/s/{store}/p{path}/content{property}</url>
<url>/api/node/content{property}/{store_type}/{store_id}/{id}</url> <url>/api/node/content{property}/{store_type}/{store_id}/{id}</url>
<url>/api/path/content{property}/{store_type}/{store_id}/{id}</url> <url>/api/path/content{property}/{store_type}/{store_id}/{id}</url>
<url>/api/avmpath/content{property}/{store_id}/{id}</url> <url>/api/avmpath/content{property}/{store_id}/{id}</url>
<url>/api/node/{store_type}/{store_id}/{id}/content{property}</url> <url>/api/node/{store_type}/{store_id}/{id}/content{property}</url>
<url>/api/path/{store_type}/{store_id}/{id}/content{property}</url> <url>/api/path/{store_type}/{store_id}/{id}/content{property}</url>
<authentication>guest</authentication> <authentication>guest</authentication>
<format default="atomentry">argument</format> <format default="atomentry">argument</format>
<family>CMIS</family> <family>CMIS</family>

View File

@@ -1,16 +1,14 @@
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/cmis/read.lib.js">
script: script:
{ {
// locate node // locate node
var pathSegments = url.match.split("/"); var object = getObjectFromUrl();
var reference = [ url.templateArgs.store_type, url.templateArgs.store_id ].concat(url.templateArgs.id.split("/")); if (object.node == null)
var node = cmis.findNode(pathSegments[2], reference);
if (node === null)
{ {
status.code = 404;
status.message = "Repository " + pathSegments[2] + " " + reference.join("/") + " not found";
status.redirect = true;
break script; break script;
} }
node = object.node;
if (!node.hasPermission("Delete")) if (!node.hasPermission("Delete"))
{ {

View File

@@ -20,11 +20,21 @@ Some CMIS protocol bindings MAY choose not to explicitly implement a “getConte
Each CMIS protocol binding will provide a way for fetching a sub-range within a content stream, in a manner appropriate to that protocol.<br> Each CMIS protocol binding will provide a way for fetching a sub-range within a content stream, in a manner appropriate to that protocol.<br>
]]> ]]>
</description> </description>
<!-- by object id -->
<url>/cmis/i/{id}/content{property}?a={attach?}</url>
<url>/cmis/s/{store}/i/{id}/content{property}?a={attach?}</url>
<!-- by path -->
<url>/cmis/p{path}/content{property}?a={attach?}</url>
<url>/cmis/s/{store}/p{path}/content{property}?a={attach?}</url>
<!-- alfresco style -->
<url>/api/node/content{property}/{store_type}/{store_id}/{id}?a={attach?}</url> <url>/api/node/content{property}/{store_type}/{store_id}/{id}?a={attach?}</url>
<url>/api/path/content{property}/{store_type}/{store_id}/{id}?a={attach?}</url> <url>/api/path/content{property}/{store_type}/{store_id}/{path}?a={attach?}</url>
<url>/api/avmpath/content{property}/{store_id}/{id}?a={attach?}</url> <url>/api/avmpath/content{property}/{store_id}/{avmpath}?a={attach?}</url>
<url>/api/node/{store_type}/{store_id}/{id}/content{property}?a={attach?}</url> <url>/api/node/{store_type}/{store_id}/{id}/content{property}?a={attach?}</url>
<url>/api/path/{store_type}/{store_id}/{id}/content{property}?a={attach?}</url> <url>/api/path/{store_type}/{store_id}/{path}/content{property}?a={attach?}</url>
<authentication>guest</authentication> <authentication>guest</authentication>
<transaction allow="readonly"/> <transaction allow="readonly"/>
<format default="">argument</format> <format default="">argument</format>

View File

@@ -1,11 +1,21 @@
<webscript> <webscript>
<shortname>Content Write (setContent)</shortname> <shortname>Content Write (setContent)</shortname>
<description>TODO</description> <description>TODO</description>
<!-- by object id -->
<url>/cmis/i/{id}/content{property}?overwriteFlag={overwriteFlag?}</url>
<url>/cmis/s/{store}/i/{id}/content{property}?overwriteFlag={overwriteFlag?}</url>
<!-- by path -->
<url>/cmis/p{path}/content{property}?overwriteFlag={overwriteFlag?}</url>
<url>/cmis/s/{store}/p{path}/content{property}?overwriteFlag={overwriteFlag?}</url>
<!-- alfresco style -->
<url>/api/node/content{property}/{store_type}/{store_id}/{id}?overwriteFlag={overwriteFlag?}</url> <url>/api/node/content{property}/{store_type}/{store_id}/{id}?overwriteFlag={overwriteFlag?}</url>
<url>/api/path/content{property}/{store_type}/{store_id}/{id}?overwriteFlag={overwriteFlag?}</url> <url>/api/path/content{property}/{store_type}/{store_id}/{id}?overwriteFlag={overwriteFlag?}</url>
<url>/api/avmpath/content{property}/{store_id}/{id}?overwriteFlag={overwriteFlag?}</url> <url>/api/avmpath/content{property}/{store_id}/{id}?overwriteFlag={overwriteFlag?}</url>
<url>/api/node/{store_type}/{store_id}/{id}/content{property}?overwriteFlag={overwriteFlag?}</url> <url>/api/node/{store_type}/{store_id}/{id}/content{property}?overwriteFlag={overwriteFlag?}</url>
<url>/api/path/{store_type}/{store_id}/{id}/content{property}?overwriteFlag={overwriteFlag?}</url> <url>/api/path/{store_type}/{store_id}/{id}/content{property}?overwriteFlag={overwriteFlag?}</url>
<authentication>guest</authentication> <authentication>guest</authentication>
<format default="text">argument</format> <format default="text">argument</format>
<family>CMIS</family> <family>CMIS</family>

View File

@@ -29,8 +29,17 @@ Does not specify the order in which delete will happen<br>
o However, any objects that are not deleted (e.g. because a previous object failed to delete), they MUST remain valid CMIS objects (including any applicable filing constraint for each object).<br> o However, any objects that are not deleted (e.g. because a previous object failed to delete), they MUST remain valid CMIS objects (including any applicable filing constraint for each object).<br>
]]> ]]>
</description> </description>
<!-- by object id -->
<url>/cmis/i/{id}/descendants?continueOnFailure={continueOnFailure?}&amp;unfileMultiFiledDocuments={unfileMultiFiledDocuments}</url>
<url>/cmis/s/{store}/i/{id}/descendants?continueOnFailure={continueOnFailure?}&amp;unfileMultiFiledDocuments={unfileMultiFiledDocuments}</url>
<!-- by path -->
<url>/cmis/p{path}/descendants?continueOnFailure={continueOnFailure?}&amp;unfileMultiFiledDocuments={unfileMultiFiledDocuments}</url>
<url>/cmis/s/{store}/p{path}/descendants?continueOnFailure={continueOnFailure?}&amp;unfileMultiFiledDocuments={unfileMultiFiledDocuments}</url>
<!-- alfresco style -->
<url>/api/node/{store_type}/{store_id}/{id}/descendants?continueOnFailure={continueOnFailure?}&amp;unfileMultiFiledDocuments={unfileMultiFiledDocuments}</url> <url>/api/node/{store_type}/{store_id}/{id}/descendants?continueOnFailure={continueOnFailure?}&amp;unfileMultiFiledDocuments={unfileMultiFiledDocuments}</url>
<url>/api/path/{store_type}/{store_id}/{id}/descendants?continueOnFailure={continueOnFailure?}&amp;unfileMultiFiledDocuments={unfileMultiFiledDocuments}</url> <url>/api/path/{store_type}/{store_id}/{path}/descendants?continueOnFailure={continueOnFailure?}&amp;unfileMultiFiledDocuments={unfileMultiFiledDocuments}</url>
<authentication>user</authentication> <authentication>user</authentication>
<format default="atomfeed"/> <format default="atomfeed"/>
<family>CMIS</family> <family>CMIS</family>

View File

@@ -1,16 +1,14 @@
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/cmis/read.lib.js">
script: script:
{ {
// locate node // locate node
var pathSegments = url.match.split("/"); var object = getObjectFromUrl();
var reference = [ url.templateArgs.store_type, url.templateArgs.store_id ].concat(url.templateArgs.id.split("/")); if (object.node == null)
var node = cmis.findNode(pathSegments[2], reference);
if (node === null)
{ {
status.code = 404;
status.message = "Repository " + pathSegments[2] + " " + reference.join("/") + " not found";
status.redirect = true;
break script; break script;
} }
var node = object.node;
// NOTE: Ignore continueOnDelete as complete tree is deleted in single transaction // NOTE: Ignore continueOnDelete as complete tree is deleted in single transaction
// TODO: Throw error on invalid unfileMultiFiledDocuments error // TODO: Throw error on invalid unfileMultiFiledDocuments error
@@ -28,7 +26,7 @@ script:
if (!node.remove()) if (!node.remove())
{ {
status.code = 500; status.code = 500;
status.message = "Failed to delete node " + pathSegments[2] + " " + reference.join("/"); status.message = "Failed to delete object " + object.ref;
status.redirect = true; status.redirect = true;
break script; break script;
} }

View File

@@ -32,8 +32,17 @@ When returning the results of a call where the caller specified “Any” type,
If “includeAllowableActions” is TRUE, the repository will return the allowable actions for the current user for each descendant object as part of the output.<br> If “includeAllowableActions” is TRUE, the repository will return the allowable actions for the current user for each descendant object as part of the output.<br>
"IncludeRelationships" indicates whether relationships are also returned for each returned object. If it is set to "source" or "target", relationships for which the returned object is a source, or respectively a target, will also be returned. If it is set to "both", relationships for which the returned object is either a source or a target will be returned. If it is set to "none", relationships are not returned.]]> "IncludeRelationships" indicates whether relationships are also returned for each returned object. If it is set to "source" or "target", relationships for which the returned object is a source, or respectively a target, will also be returned. If it is set to "both", relationships for which the returned object is either a source or a target will be returned. If it is set to "none", relationships are not returned.]]>
</description> </description>
<!-- by object id -->
<url>/cmis/i/{id}/descendants?types={types}&amp;filter={filter?}&amp;depth={depth?}&amp;includeAllowableActions={includeAllowableActions?}</url>
<url>/cmis/s/{store}/i/{id}/descendants?types={types}&amp;filter={filter?}&amp;depth={depth?}&amp;includeAllowableActions={includeAllowableActions?}</url>
<!-- by path -->
<url>/cmis/p{path}/descendants?types={types}&amp;filter={filter?}&amp;depth={depth?}&amp;includeAllowableActions={includeAllowableActions?}</url>
<url>/cmis/s/{store}/p{path}/descendants?types={types}&amp;filter={filter?}&amp;depth={depth?}&amp;includeAllowableActions={includeAllowableActions?}</url>
<!-- alfresco style -->
<url>/api/node/{store_type}/{store_id}/{id}/descendants?types={types}&amp;filter={filter?}&amp;depth={depth?}&amp;includeAllowableActions={includeAllowableActions?}</url> <url>/api/node/{store_type}/{store_id}/{id}/descendants?types={types}&amp;filter={filter?}&amp;depth={depth?}&amp;includeAllowableActions={includeAllowableActions?}</url>
<url>/api/path/{store_type}/{store_id}/{id}/descendants?types={types}&amp;filter={filter?}&amp;depth={depth?}&amp;includeAllowableActions={includeAllowableActions?}</url> <url>/api/path/{store_type}/{store_id}/{path}/descendants?types={types}&amp;filter={filter?}&amp;depth={depth?}&amp;includeAllowableActions={includeAllowableActions?}</url>
<authentication>guest</authentication> <authentication>guest</authentication>
<transaction allow="readonly"/> <transaction allow="readonly"/>
<format default="atomfeed">argument</format> <format default="atomfeed">argument</format>

View File

@@ -1,17 +1,14 @@
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/cmis/read.lib.js">
script: script:
{ {
// locate node var object = getObjectFromUrl();
var pathSegments = url.match.split("/"); if (object.node == null)
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; break script;
} }
model.node = object.node;
// handle filters // handle filters
model.types = args[cmis.ARG_TYPES] === null ? cmis.defaultTypesFilter : args[ARG_TYPES]; model.types = args[cmis.ARG_TYPES] === null ? cmis.defaultTypesFilter : args[ARG_TYPES];
if (!cmis.isValidTypesFilter(model.types)) if (!cmis.isValidTypesFilter(model.types))

View File

@@ -17,8 +17,17 @@ This service deletes a specific version of a document object. To delete all ver
Deletion of a private working copy (checked out version) is the same as to cancel checkout.<br> Deletion of a private working copy (checked out version) is the same as to cancel checkout.<br>
]]> ]]>
</description> </description>
<!-- by object id -->
<url>/cmis/i/{id}?includeChildren={includeChildren?}</url>
<url>/cmis/s/{store}/i/{id}?includeChildren={includeChildren?}</url>
<!-- by path -->
<url>/cmis/p{path}?includeChildren={includeChildren?}</url>
<url>/cmis/s/{store}/p{path}?includeChildren={includeChildren?}</url>
<!-- alfresco style -->
<url>/api/node/{store_type}/{store_id}/{id}?includeChildren={includeChildren?}</url> <url>/api/node/{store_type}/{store_id}/{id}?includeChildren={includeChildren?}</url>
<url>/api/path/{store_type}/{store_id}/{id}?includeChildren={includeChildren?}</url> <url>/api/path/{store_type}/{store_id}/{path}?includeChildren={includeChildren?}</url>
<authentication>user</authentication> <authentication>user</authentication>
<format default="atomentry"/> <format default="atomentry"/>
<family>CMIS</family> <family>CMIS</family>

View File

@@ -1,21 +1,19 @@
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/cmis/read.lib.js">
script: script:
{ {
// locate node // locate node
var pathSegments = url.match.split("/"); var object = getObjectFromUrl();
var reference = [ url.templateArgs.store_type, url.templateArgs.store_id ].concat(url.templateArgs.id.split("/")); if (object.node == null)
var node = cmis.findNode(pathSegments[2], reference);
if (node === null)
{ {
status.code = 404;
status.message = "Repository " + pathSegments[2] + " " + reference.join("/") + " not found";
status.redirect = true;
break script; break script;
} }
var node = object.node;
if (!node.hasPermission("Delete")) if (!node.hasPermission("Delete"))
{ {
status.code = 403; status.code = 403;
status.message = "Permission to delete is denied"; status.message = "Permission to delete object " + object.ref + " is denied";
status.redirect = true; status.redirect = true;
break script; break script;
} }
@@ -28,7 +26,7 @@ script:
if (node.children.length > 0 && !args.includeChildren) if (node.children.length > 0 && !args.includeChildren)
{ {
status.code = 403; status.code = 403;
status.message = "Cannot delete folder " + pathSegments[2] + " " + reference.join("/") + " as it's not empty"; status.message = "Cannot delete folder " + object.ref + " as it's not empty";
status.redirect = true; status.redirect = true;
break script; break script;
} }
@@ -38,7 +36,7 @@ script:
if (!node.remove()) if (!node.remove())
{ {
status.code = 500; status.code = 500;
status.message = "Failed to delete node " + pathSegments[2] + " " + reference.join("/"); status.message = "Failed to delete object " + object.ref;
status.redirect = true; status.redirect = true;
break script; break script;
} }

View File

@@ -26,9 +26,23 @@ PropertyCollection includes changeToken (if applicable to repository)<br>
]]> ]]>
</description> </description>
<!-- TODO: spec issue: returnVersion or returnCurrent? --> <!-- TODO: spec issue: returnVersion or returnCurrent? -->
<!-- by object id -->
<url>/cmis/i/{id}?filter={filter?}&amp;returnVersion={returnVersion?}&amp;includeAllowableActions={includeAllowableActions?}</url>
<url>/cmis/s/{store}/i/{id}?filter={filter?}&amp;returnVersion={returnVersion?}&amp;includeAllowableActions={includeAllowableActions?}</url>
<!-- by object path -->
<url>/cmis/p{path}?filter={filter?}&amp;returnVersion={returnVersion?}&amp;includeAllowableActions={includeAllowableActions?}</url>
<url>/cmis/s/{store}/p{path}?filter={filter?}&amp;returnVersion={returnVersion?}&amp;includeAllowableActions={includeAllowableActions?}</url>
<!-- for CMIS URI template generators -->
<url>/cmis/s/{store}/arg/i?id={id}&amp;filter={filter?}&amp;returnVersion={returnVersion?}&amp;includeAllowableActions={includeAllowableActions?}</url>
<url>/cmis/s/{store}/arg/p?path={path}&amp;filter={filter?}&amp;returnVersion={returnVersion?}&amp;includeAllowableActions={includeAllowableActions?}</url>
<url>/cmis/arg/n?noderef={noderef}&amp;filter={filter?}&amp;returnVersion={returnVersion?}&amp;includeAllowableActions={includeAllowableActions?}</url>
<!-- alfresco style -->
<url>/api/node/{store_type}/{store_id}/{id}?filter={filter?}&amp;returnVersion={returnVersion?}&amp;includeAllowableActions={includeAllowableActions?}</url> <url>/api/node/{store_type}/{store_id}/{id}?filter={filter?}&amp;returnVersion={returnVersion?}&amp;includeAllowableActions={includeAllowableActions?}</url>
<url>/api/path/{store_type}/{store_id}/{id}?filter={filter?}&amp;returnVersion={returnVersion?}&amp;includeAllowableActions={includeAllowableActions?}</url> <url>/api/path/{store_type}/{store_id}/{path}?filter={filter?}&amp;returnVersion={returnVersion?}&amp;includeAllowableActions={includeAllowableActions?}</url>
<!-- TODO: consider /api/node/{store_type}/{store_id}/{id}/{child_node} for atom relative paths -->
<authentication>guest</authentication> <authentication>guest</authentication>
<transaction allow="readonly"/> <transaction allow="readonly"/>
<format default="atomentry">argument</format> <format default="atomentry">argument</format>

View File

@@ -1,22 +1,19 @@
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/cmis/read.lib.js">
script: script:
{ {
// locate node var object = getObjectFromUrl();
var pathSegments = url.match.split("/"); if (object.node === null)
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; break script;
} }
model.node = object.node;
// TODO: handle version?? // TODO: handle version??
// property filter // property filter
model.filter = args[cmis.ARG_FILTER]; model.filter = args[cmis.ARG_FILTER];
if (model.filter === null) if (model.filter === null || model.filter == "")
{ {
model.filter = "*"; model.filter = "*";
} }

View File

@@ -1,5 +1,6 @@
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/cmis/constants.lib.js"> <import resource="classpath:alfresco/templates/webscripts/org/alfresco/cmis/constants.lib.js">
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/cmis/atomentry.lib.js"> <import resource="classpath:alfresco/templates/webscripts/org/alfresco/cmis/read.lib.js">
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/cmis/modify.lib.js">
script: script:
{ {
@@ -13,16 +14,12 @@ script:
} }
// locate node // locate node
var pathSegments = url.match.split("/"); var object = getObjectFromUrl();
var reference = [ url.templateArgs.store_type, url.templateArgs.store_id ].concat(url.templateArgs.id.split("/")); if (object.node == null)
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; break script;
} }
model.node = object.node;
// update properties // update properties
var updated = updateNode(model.node, entry, null, function(propDef) {return patchValidator(propDef, false);}); var updated = updateNode(model.node, entry, null, function(propDef) {return patchValidator(propDef, false);});

View File

@@ -27,8 +27,17 @@ If this is a private working copy, some repositories may not support updates.<br
Because repositories MAY automatically create new Document Versions on a users behalf, the objectId returned may not match the one provided as an input to this method.<br> Because repositories MAY automatically create new Document Versions on a users behalf, the objectId returned may not match the one provided as an input to this method.<br>
]]> ]]>
</description> </description>
<!-- by object id -->
<url>/cmis/i/{id}</url>
<url>/cmis/s/{store}/i/{id}</url>
<!-- by path -->
<url>/cmis/p{path}</url>
<url>/cmis/s/{store}/p{path}</url>
<!-- alfresco style -->
<url>/api/node/{store_type}/{store_id}/{id}</url> <url>/api/node/{store_type}/{store_id}/{id}</url>
<url>/api/path/{store_type}/{store_id}/{id}</url> <url>/api/path/{store_type}/{store_id}/{path}</url>
<authentication>user</authentication> <authentication>user</authentication>
<format default="atomentry">argument</format> <format default="atomentry">argument</format>
<family>CMIS</family> <family>CMIS</family>

View File

@@ -1,5 +1,6 @@
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/cmis/constants.lib.js"> <import resource="classpath:alfresco/templates/webscripts/org/alfresco/cmis/constants.lib.js">
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/cmis/atomentry.lib.js"> <import resource="classpath:alfresco/templates/webscripts/org/alfresco/cmis/read.lib.js">
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/cmis/modify.lib.js">
script: script:
{ {
@@ -13,16 +14,12 @@ script:
} }
// locate node // locate node
var pathSegments = url.match.split("/"); var object = getObjectFromUrl();
var reference = [ url.templateArgs.store_type, url.templateArgs.store_id ].concat(url.templateArgs.id.split("/")); if (object.node == null)
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; break script;
} }
model.node = object.node;
// update properties // update properties
var updated = updateNode(model.node, entry, null, function(propDef) {return putValidator(propDef, false);}); var updated = updateNode(model.node, entry, null, function(propDef) {return putValidator(propDef, false);});

View File

@@ -27,8 +27,17 @@ If this is a private working copy, some repositories may not support updates.<br
Because repositories MAY automatically create new Document Versions on a users behalf, the objectId returned may not match the one provided as an input to this method.<br> Because repositories MAY automatically create new Document Versions on a users behalf, the objectId returned may not match the one provided as an input to this method.<br>
]]> ]]>
</description> </description>
<!-- by object id -->
<url>/cmis/i/{id}</url>
<url>/cmis/s/{store}/i/{id}</url>
<!-- by path -->
<url>/cmis/p{path}</url>
<url>/cmis/s/{store}/p{path}</url>
<!-- alfresco style -->
<url>/api/node/{store_type}/{store_id}/{id}</url> <url>/api/node/{store_type}/{store_id}/{id}</url>
<url>/api/path/{store_type}/{store_id}/{id}</url> <url>/api/path/{store_type}/{store_id}/{path}</url>
<authentication>user</authentication> <authentication>user</authentication>
<format default="atomentry">argument</format> <format default="atomentry">argument</format>
<family>CMIS</family> <family>CMIS</family>

View File

@@ -2,8 +2,17 @@
<shortname>Retrieve Parent Folder (getFolderParent)</shortname> <shortname>Retrieve Parent Folder (getFolderParent)</shortname>
<description> <description>
</description> </description>
<!-- by object id -->
<url>/cmis/i/{id}/parent?filter={filter?}&amp;includeAllowableActions={includeAllowableActions?}</url>
<url>/cmis/s/{store}/i/{id}/parent?filter={filter?}&amp;includeAllowableActions={includeAllowableActions?}</url>
<!-- by path -->
<url>/cmis/p{path}/parent?filter={filter?}&amp;includeAllowableActions={includeAllowableActions?}</url>
<url>/cmis/s/{store}/p{path}/parent?filter={filter?}&amp;includeAllowableActions={includeAllowableActions?}</url>
<!-- alfresco style -->
<url>/api/node/{store_type}/{store_id}/{id}/parent?filter={filter?}&amp;includeAllowableActions={includeAllowableActions?}</url> <url>/api/node/{store_type}/{store_id}/{id}/parent?filter={filter?}&amp;includeAllowableActions={includeAllowableActions?}</url>
<url>/api/path/{store_type}/{store_id}/{id}/parent?filter={filter?}&amp;includeAllowableActions={includeAllowableActions?}</url> <url>/api/path/{store_type}/{store_id}/{path}/parent?filter={filter?}&amp;includeAllowableActions={includeAllowableActions?}</url>
<authentication>guest</authentication> <authentication>guest</authentication>
<transaction allow="readonly"/> <transaction allow="readonly"/>
<format default="atomentry">argument</format> <format default="atomentry">argument</format>

View File

@@ -1,22 +1,20 @@
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/cmis/read.lib.js">
script: script:
{ {
// locate node // locate node
var pathSegments = url.match.split("/"); var object = getObjectFromUrl();
var reference = [ url.templateArgs.store_type, url.templateArgs.store_id ].concat(url.templateArgs.id.split("/")); if (object.node == null)
var node = cmis.findNode(pathSegments[2], reference);
if (node === null)
{ {
status.code = 404;
status.message = "Repository " + pathSegments[2] + " " + reference.join("/") + " not found";
status.redirect = true;
break script; break script;
} }
var node = object.node;
// locate parent // locate parent
if (node.id == cmis.defaultRootFolder.id) if (node.id == cmis.defaultRootFolder.id)
{ {
status.code = 404; status.code = 404;
status.message = "Repository " + pathSegments[2] + " " + reference.join("/") + " parent not found"; status.message = "Object " + object.ref + " parent not found";
status.redirect = true; status.redirect = true;
break script; break script;
} }

View File

@@ -23,8 +23,17 @@ If “includeAllowableActions” is TRUE, the repository will return the allowab
"IncludeRelationships" indicates whether relationships are also returned for each returned object. If it is set to "source" or "target", relationships for which the returned object is a source, or respectively a target, will also be returned. If it is set to "both", relationships for which the returned object is either a source or a target will be returned. If it is set to "none", relationships are not returned.<br> "IncludeRelationships" indicates whether relationships are also returned for each returned object. If it is set to "source" or "target", relationships for which the returned object is a source, or respectively a target, will also be returned. If it is set to "both", relationships for which the returned object is either a source or a target will be returned. If it is set to "none", relationships are not returned.<br>
]]> ]]>
</description> </description>
<!-- by object id -->
<url>/cmis/i/{id}/parents?filter={filter?}&amp;includeAllowableActions={includeAllowableActions?}</url>
<url>/cmis/s/{store}/i/{id}/parents?filter={filter?}&amp;includeAllowableActions={includeAllowableActions?}</url>
<!-- by path -->
<url>/cmis/p{path}/parents?filter={filter?}&amp;includeAllowableActions={includeAllowableActions?}</url>
<url>/cmis/s/{store}/p{path}/parents?filter={filter?}&amp;includeAllowableActions={includeAllowableActions?}</url>
<!-- alfresco style -->
<url>/api/node/{store_type}/{store_id}/{id}/parents?filter={filter?}&amp;includeAllowableActions={includeAllowableActions?}</url> <url>/api/node/{store_type}/{store_id}/{id}/parents?filter={filter?}&amp;includeAllowableActions={includeAllowableActions?}</url>
<url>/api/path/{store_type}/{store_id}/{id}/parents?filter={filter?}&amp;includeAllowableActions={includeAllowableActions?}</url> <url>/api/path/{store_type}/{store_id}/{path}/parents?filter={filter?}&amp;includeAllowableActions={includeAllowableActions?}</url>
<authentication>guest</authentication> <authentication>guest</authentication>
<transaction allow="readonly"/> <transaction allow="readonly"/>
<format default="atomfeed">argument</format> <format default="atomfeed">argument</format>

View File

@@ -1,20 +1,15 @@
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/cmis/read.lib.js">
script: script:
{ {
// locate node // locate node and parent
var pathSegments = url.match.split("/"); var object = getObjectFromUrl();
var reference = [ url.templateArgs.store_type, url.templateArgs.store_id ].concat(url.templateArgs.id.split("/")); if (object.node == null)
var node = cmis.findNode(pathSegments[2], reference);
if (node === null)
{ {
status.code = 404;
status.message = "Repository " + pathSegments[2] + " " + reference.join("/") + " not found";
status.redirect = true;
break script; break script;
} }
model.node = object.node;
// locate parent model.parent = model.node.parent;
model.node = node;
model.parent = node.parent;
// property filter // property filter
model.filter = args[cmis.ARG_FILTER]; model.filter = args[cmis.ARG_FILTER];

View File

@@ -14,7 +14,11 @@ It is repository specific on who can cancel a checkout (user, admin, larger grou
Throws OperationNotSupportedException if the object is not checked out<br> Throws OperationNotSupportedException if the object is not checked out<br>
]]> ]]>
</description> </description>
<url>/api/pwc/{store_type}/{store_id}/{id}</url>
<!-- by object id -->
<url>/cmis/pwc/i/{id}</url>
<url>/cmis/pwc/s/{store}/i/{id}</url>
<authentication>user</authentication> <authentication>user</authentication>
<format default="atomentry"/> <format default="atomentry"/>
<family>CMIS</family> <family>CMIS</family>

View File

@@ -1,21 +1,18 @@
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/cmis/read.lib.js">
script: script:
{ {
// locate node var object = getObjectFromUrl();
var pathSegments = url.match.split("/"); if (object.node == null)
var reference = [ url.templateArgs.store_type, url.templateArgs.store_id ].concat(url.templateArgs.id.split("/"));
var node = cmis.findNode("node", reference);
if (node === null || !node.hasAspect("cm:workingcopy"))
{ {
status.code = 404;
status.message = "Private working copy " + reference.join("/") + " not found";
status.redirect = true;
break script; break script;
} }
var node = object.node;
if (!node.hasPermission("CancelCheckOut")) if (!node.hasPermission("CancelCheckOut"))
{ {
status.code = 403; status.code = 403;
status.message = "Permission to cancel checkout is denied"; status.message = "Permission to cancel checkout of " + object.ref + " is denied";
status.redirect = true; status.redirect = true;
break script; break script;
} }

View File

@@ -1,7 +1,10 @@
<webscript> <webscript>
<shortname>Retrieve properties of PWC</shortname> <shortname>Retrieve properties of PWC</shortname>
<description>Retrieves the properties of a private working copy</description> <description>Retrieves the properties of a private working copy</description>
<url>/api/pwc/{store_type}/{store_id}/{id}?filter={filter?}</url>
<url>/cmis/pwc/i/{id}?filter={filter?}</url>
<url>/cmis/pwc/s/{store}/i/{id}?filter={filter?}</url>
<authentication>user</authentication> <authentication>user</authentication>
<transaction allow="readonly"/> <transaction allow="readonly"/>
<format default="atomentry">argument</format> <format default="atomentry">argument</format>

View File

@@ -1,17 +1,15 @@
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/cmis/read.lib.js">
script: script:
{ {
// locate node // locate node
var pathSegments = url.match.split("/"); var object = getObjectFromUrl();
var reference = [ url.templateArgs.store_type, url.templateArgs.store_id ].concat(url.templateArgs.id.split("/")); if (object.node == null)
model.node = cmis.findNode("node", reference);
if (model.node === null || !model.node.hasAspect("cm:workingcopy"))
{ {
status.code = 404;
status.message = "Private working copy " + reference.join("/") + " not found";
status.redirect = true;
break script; break script;
} }
model.node = object.node;
// TODO: property filters // TODO: property filters
} }

View File

@@ -1,26 +1,23 @@
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/cmis/constants.lib.js"> <import resource="classpath:alfresco/templates/webscripts/org/alfresco/cmis/constants.lib.js">
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/cmis/atomentry.lib.js"> <import resource="classpath:alfresco/templates/webscripts/org/alfresco/cmis/read.lib.js">
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/cmis/modify.lib.js">
script: script:
{ {
// locate node // locate node
var pathSegments = url.match.split("/"); var object = getObjectFromUrl();
var reference = [ url.templateArgs.store_type, url.templateArgs.store_id ].concat(url.templateArgs.id.split("/")); if (object.node == null)
model.node = cmis.findNode("node", reference);
if (model.node === null || !model.node.hasAspect("cm:workingcopy"))
{ {
status.code = 404;
status.message = "Private working copy " + reference.join("/") + " not found";
status.redirect = true;
break script; break script;
} }
model.node = object.node;
// check permissions // check permissions
model.checkin = args[cmis.ARG_CHECKIN] == "true" ? true : false; model.checkin = args[cmis.ARG_CHECKIN] == "true" ? true : false;
if (model.checkin && !model.node.hasPermission("CheckIn")) if (model.checkin && !model.node.hasPermission("CheckIn"))
{ {
status.code = 403; status.code = 403;
status.message = "Permission to checkin is denied"; status.message = "Permission to checkin " + object.ref + " is denied";
status.redirect = true; status.redirect = true;
break script; break script;
} }

View File

@@ -25,7 +25,10 @@ If Document is not checked out, throw OperationNotSupportedException.<br>
If the Document has “Content_Stream_Allowed” set to FALSE, and a call is made to checkIn that includes a content-stream, throw ConstraintViolationException.<br> If the Document has “Content_Stream_Allowed” set to FALSE, and a call is made to checkIn that includes a content-stream, throw ConstraintViolationException.<br>
]]> ]]>
</description> </description>
<url>/api/pwc/{store_type}/{store_id}/{id}?checkinComment={checkinComment?}&amp;major={major?}&amp;checkin={checkin?}</url>
<url>/cmis/pwc/i/{id}?checkinComment={checkinComment?}&amp;major={major?}&amp;checkin={checkin?}</url>
<url>/cmis/pwc/s/{store}/i/{id}?checkinComment={checkinComment?}&amp;major={major?}&amp;checkin={checkin?}</url>
<authentication>user</authentication> <authentication>user</authentication>
<format default="atomentry"/> <format default="atomentry"/>
<family>CMIS</family> <family>CMIS</family>

View File

@@ -1,20 +1,17 @@
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/cmis/constants.lib.js"> <import resource="classpath:alfresco/templates/webscripts/org/alfresco/cmis/constants.lib.js">
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/cmis/atomentry.lib.js"> <import resource="classpath:alfresco/templates/webscripts/org/alfresco/cmis/read.lib.js">
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/cmis/modify.lib.js">
script: script:
{ {
// locate node // locate node
var pathSegments = url.match.split("/"); var object = getObjectFromUrl();
var reference = [ url.templateArgs.store_type, url.templateArgs.store_id ].concat(url.templateArgs.id.split("/")); if (object.node === null || !object.node.hasAspect("cm:workingcopy"))
model.node = cmis.findNode("node", reference);
if (model.node === null || !model.node.hasAspect("cm:workingcopy"))
{ {
status.code = 404;
status.message = "Private working copy " + reference.join("/") + " not found";
status.redirect = true;
break script; break script;
} }
model.node = object.node;
// check permissions // check permissions
model.checkin = args[cmis.ARG_CHECKIN] == "true" ? true : false; model.checkin = args[cmis.ARG_CHECKIN] == "true" ? true : false;
if (model.checkin && !model.node.hasPermission("CheckIn")) if (model.checkin && !model.node.hasPermission("CheckIn"))

View File

@@ -25,7 +25,10 @@ If Document is not checked out, throw OperationNotSupportedException.<br>
If the Document has “Content_Stream_Allowed” set to FALSE, and a call is made to checkIn that includes a content-stream, throw ConstraintViolationException.<br> If the Document has “Content_Stream_Allowed” set to FALSE, and a call is made to checkIn that includes a content-stream, throw ConstraintViolationException.<br>
]]> ]]>
</description> </description>
<url>/api/pwc/{store_type}/{store_id}/{id}?checkinComment={checkinComment?}&amp;major={major?}&amp;checkin={checkin?}</url>
<url>/cmis/pwc/i/{id}?checkinComment={checkinComment?}&amp;major={major?}&amp;checkin={checkin?}</url>
<url>/cmis/pwc/s/{store}/i/{id}?checkinComment={checkinComment?}&amp;major={major?}&amp;checkin={checkin?}</url>
<authentication>user</authentication> <authentication>user</authentication>
<format default="atomentry"/> <format default="atomentry"/>
<family>CMIS</family> <family>CMIS</family>

View File

@@ -2,7 +2,9 @@
<shortname>Delete relationship (deleteRelationship)</shortname> <shortname>Delete relationship (deleteRelationship)</shortname>
<description> <description>
</description> </description>
<url>/api/rel/{store_type}/{store_id}/{id}/type/{rel_type}/target/{target_store_type}/{target_store_id}/{target_id}</url>
<url>/cmis/rel/s/{store}/i/{id}/type/{rel_type}/target/s/{target_store}/i/{target_id}</url>
<authentication>user</authentication> <authentication>user</authentication>
<format default="atomentry"/> <format default="atomentry"/>
<family>CMIS</family> <family>CMIS</family>

View File

@@ -1,32 +1,14 @@
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/cmis/constants.lib.js"> <import resource="classpath:alfresco/templates/webscripts/org/alfresco/cmis/constants.lib.js">
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/cmis/read.lib.js">
script: script:
{ {
// relationship type var rel = getAssocFromUrl();
var relType = url.templateArgs.rel_type; if (rel.assoc == null)
model.relTypeDef = cmis.queryType(relType);
if (model.relTypeDef === null)
{ {
status.setCode(400, "Relationship type " + relType + " unknown");
break script;
}
if (model.relTypeDef.baseType.typeId != RELATIONSHIP_TYPE_ID)
{
status.setCode(400, "Type + " + relType + " is not a relationship type");
break script;
}
// source and target
var source = [url.templateArgs.store_type, url.templateArgs.store_id, url.templateArgs.id];
var target = [url.templateArgs.target_store_type, url.templateArgs.target_store_id, url.templateArgs.target_id];
// locate association
var assoc = cmis.findRelationship(model.relTypeDef, source, target);
if (assoc === null)
{
status.setCode(404, "Assoc " + source.join("/") + "/" + relType + "/" + target.join("/") + " not found");
break script; break script;
} }
var assoc = rel.assoc;
// TODO: check permission // TODO: check permission
// if (!assoc.source.hasPermission("DeleteAssociations")) // if (!assoc.source.hasPermission("DeleteAssociations"))

View File

@@ -2,9 +2,11 @@
<shortname>Retrieve relationship (getProperties)</shortname> <shortname>Retrieve relationship (getProperties)</shortname>
<description> <description>
</description> </description>
<url>/api/rel/{store_type}/{store_id}/{id}/type/{rel_type}/target/{target_store_type}/{target_store_id}/{target_id}?filter={filter?}&amp;includeAllowableActions={includeAllowableActions?}</url>
<url>/cmis/rel/s/{store}/i/{id}/type/{rel_type}/target/s/{target_store}/i/{target_id}?filter={filter?}&amp;includeAllowableActions={includeAllowableActions?}</url>
<authentication>guest</authentication> <authentication>guest</authentication>
<transaction allow="readonly"/> <transaction allow="readonly"/>
<format default="atomentry">argument</format> <format default="atomentry">argument</format>
<family>CMIS</family> <family>CMIS</family>
</webscript> </webscript>

View File

@@ -1,24 +1,15 @@
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/cmis/constants.lib.js"> <import resource="classpath:alfresco/templates/webscripts/org/alfresco/cmis/constants.lib.js">
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/cmis/read.lib.js">
script: script:
{ {
// relationship type // locate association
var relType = url.templateArgs.rel_type; var rel = getAssocFromUrl();
model.relTypeDef = cmis.queryType(relType); if (rel.assoc == null)
if (model.relTypeDef === null)
{ {
status.setCode(400, "Relationship type " + relType + " unknown");
break script; break script;
} }
if (model.relTypeDef.baseType.typeId != RELATIONSHIP_TYPE_ID) model.assoc = rel.assoc;
{
status.setCode(400, "Type + " + relType + " is not a relationship type");
break script;
}
// source and target
var source = [url.templateArgs.store_type, url.templateArgs.store_id, url.templateArgs.id];
var target = [url.templateArgs.target_store_type, url.templateArgs.target_store_id, url.templateArgs.target_id];
// property filter // property filter
model.filter = args[cmis.ARG_FILTER]; model.filter = args[cmis.ARG_FILTER];
@@ -30,12 +21,4 @@ script:
// include allowable actions // include allowable actions
var includeAllowableActions = args[cmis.ARG_INCLUDE_ALLOWABLE_ACTIONS]; var includeAllowableActions = args[cmis.ARG_INCLUDE_ALLOWABLE_ACTIONS];
model.includeAllowableActions = (includeAllowableActions == "true" ? true : false); model.includeAllowableActions = (includeAllowableActions == "true" ? true : false);
// locate association
model.assoc = cmis.findRelationship(model.relTypeDef, source, target);
if (model.assoc === null)
{
status.setCode(404, "Assoc " + source.join("/") + "/" + relType + "/" + target.join("/") + " not found");
break script;
}
} }

View File

@@ -2,6 +2,15 @@
<shortname>Retrieve list of relationships (getRelationships)</shortname> <shortname>Retrieve list of relationships (getRelationships)</shortname>
<description> <description>
</description> </description>
<!-- by object id -->
<url>/cmis/i/{id}/rels?filter={filter?}&amp;relationshipType={relationshipType?}&amp;includeSubRelationshipTypes={includeSubRelationshipTypes?}&amp;direction={direction?}&amp;skipCount={skipCount?}&amp;maxItems={maxItems?}&amp;includeAllowableActions={includeAllowableActions?}</url>
<url>/cmis/s/{store}/i/{id}/rels?filter={filter?}&amp;relationshipType={relationshipType?}&amp;includeSubRelationshipTypes={includeSubRelationshipTypes?}&amp;direction={direction?}&amp;skipCount={skipCount?}&amp;maxItems={maxItems?}&amp;includeAllowableActions={includeAllowableActions?}</url>
<!-- by path -->
<url>/cmis/p{path}/rels?filter={filter?}&amp;relationshipType={relationshipType?}&amp;includeSubRelationshipTypes={includeSubRelationshipTypes?}&amp;direction={direction?}&amp;skipCount={skipCount?}&amp;maxItems={maxItems?}&amp;includeAllowableActions={includeAllowableActions?}</url>
<url>/cmis/s/{store}/p{path}/rels?filter={filter?}&amp;relationshipType={relationshipType?}&amp;includeSubRelationshipTypes={includeSubRelationshipTypes?}&amp;direction={direction?}&amp;skipCount={skipCount?}&amp;maxItems={maxItems?}&amp;includeAllowableActions={includeAllowableActions?}</url>
<!-- alfresco style -->
<url>/api/node/{store_type}/{store_id}/{id}/rels?filter={filter?}&amp;relationshipType={relationshipType?}&amp;includeSubRelationshipTypes={includeSubRelationshipTypes?}&amp;direction={direction?}&amp;skipCount={skipCount?}&amp;maxItems={maxItems?}&amp;includeAllowableActions={includeAllowableActions?}</url> <url>/api/node/{store_type}/{store_id}/{id}/rels?filter={filter?}&amp;relationshipType={relationshipType?}&amp;includeSubRelationshipTypes={includeSubRelationshipTypes?}&amp;direction={direction?}&amp;skipCount={skipCount?}&amp;maxItems={maxItems?}&amp;includeAllowableActions={includeAllowableActions?}</url>
<url>/api/path/{store_type}/{store_id}/{id}/rels?filter={filter?}&amp;relationshipType={relationshipType?}&amp;includeSubRelationshipTypes={includeSubRelationshipTypes?}&amp;direction={direction?}&amp;skipCount={skipCount?}&amp;maxItems={maxItems?}&amp;includeAllowableActions={includeAllowableActions?}</url> <url>/api/path/{store_type}/{store_id}/{id}/rels?filter={filter?}&amp;relationshipType={relationshipType?}&amp;includeSubRelationshipTypes={includeSubRelationshipTypes?}&amp;direction={direction?}&amp;skipCount={skipCount?}&amp;maxItems={maxItems?}&amp;includeAllowableActions={includeAllowableActions?}</url>
<authentication>guest</authentication> <authentication>guest</authentication>

View File

@@ -1,16 +1,15 @@
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/cmis/read.lib.js">
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/cmis/constants.lib.js"> <import resource="classpath:alfresco/templates/webscripts/org/alfresco/cmis/constants.lib.js">
script: script:
{ {
// locate node // locate node
var pathSegments = url.match.split("/"); var object = getObjectFromUrl();
var reference = [ url.templateArgs.store_type, url.templateArgs.store_id ].concat(url.templateArgs.id.split("/")); if (object.node == null)
model.node = cmis.findNode(pathSegments[2], reference);
if (model.node === null)
{ {
status.setCode(404, "Repository " + pathSegments[2] + " " + reference.join("/") + " not found");
break script; break script;
} }
model.node = object.node;
// property filter // property filter
model.filter = args[cmis.ARG_FILTER]; model.filter = args[cmis.ARG_FILTER];

View File

@@ -1,5 +1,6 @@
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/cmis/constants.lib.js"> <import resource="classpath:alfresco/templates/webscripts/org/alfresco/cmis/constants.lib.js">
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/cmis/atomentry.lib.js"> <import resource="classpath:alfresco/templates/webscripts/org/alfresco/cmis/read.lib.js">
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/cmis/modify.lib.js">
script: script:
{ {
@@ -13,16 +14,12 @@ script:
} }
// locate source node // locate source node
var pathSegments = url.match.split("/"); var object = getObjectFromUrl();
var reference = [ url.templateArgs.store_type, url.templateArgs.store_id ].concat(url.templateArgs.id.split("/")); if (object.node == null)
model.source = cmis.findNode(pathSegments[2], reference);
if (model.source === null)
{ {
status.code = 404;
status.message = "Repository " + pathSegments[2] + " " + reference.join("/") + " not found";
status.redirect = true;
break script; break script;
} }
model.source = object.node;
// create // create
var assoc = createAssociation(model.source, entry); var assoc = createAssociation(model.source, entry);
@@ -36,6 +33,6 @@ script:
// TODO: set Content-Location // TODO: set Content-Location
status.code = 201; status.code = 201;
// TODO: complete url mapping // TODO: complete url mapping
status.location = url.server + url.serviceContext + "/api/rel/" + model.source.nodeRef.storeRef.protocol + "/" + model.source.nodeRef.storeRef.identifier + "/" + model.source.nodeRef.id; status.location = url.server + url.serviceContext + "/cmis/rel/" + model.source.nodeRef.storeRef.protocol + "/" + model.source.nodeRef.storeRef.identifier + "/" + model.source.nodeRef.id;
status.redirect = true; status.redirect = true;
} }

View File

@@ -2,8 +2,18 @@
<shortname>Create relationship (createRelationship)</shortname> <shortname>Create relationship (createRelationship)</shortname>
<description> <description>
</description> </description>
<!-- by object id -->
<url>/cmis/i/{id}/rels</url>
<url>/cmis/s/{store}/i/{id}/rels</url>
<!-- by path -->
<url>/cmis/p{path}/rels</url>
<url>/cmis/s/{store}/p{path}/rels</url>
<!-- alfresco style -->
<url>/api/node/{store_type}/{store_id}/{id}/rels</url> <url>/api/node/{store_type}/{store_id}/{id}/rels</url>
<url>/api/path/{store_type}/{store_id}/{id}/rels</url> <url>/api/path/{store_type}/{store_id}/{id}/rels</url>
<authentication>guest</authentication> <authentication>guest</authentication>
<format default="atomentry">argument</format> <format default="atomentry">argument</format>
<family>CMIS</family> <family>CMIS</family>

View File

@@ -2,8 +2,17 @@
<shortname>Delete tree (deleteTree)</shortname> <shortname>Delete tree (deleteTree)</shortname>
<description> <description>
</description> </description>
<!-- by object id -->
<url>/cmis/i/{id}/tree?continueOnFailure={continueOnFailure?}&amp;unfileMultiFiledDocuments={unfileMultiFiledDocuments}</url>
<url>/cmis/s/{store}/i/{id}/tree?continueOnFailure={continueOnFailure?}&amp;unfileMultiFiledDocuments={unfileMultiFiledDocuments}</url>
<!-- by path -->
<url>/cmis/p{path}/tree?continueOnFailure={continueOnFailure?}&amp;unfileMultiFiledDocuments={unfileMultiFiledDocuments}</url>
<url>/cmis/s/{store}/p{path}/tree?continueOnFailure={continueOnFailure?}&amp;unfileMultiFiledDocuments={unfileMultiFiledDocuments}</url>
<!-- alfresco style -->
<url>/api/node/{store_type}/{store_id}/{id}/tree?continueOnFailure={continueOnFailure?}&amp;unfileMultiFiledDocuments={unfileMultiFiledDocuments}</url> <url>/api/node/{store_type}/{store_id}/{id}/tree?continueOnFailure={continueOnFailure?}&amp;unfileMultiFiledDocuments={unfileMultiFiledDocuments}</url>
<url>/api/path/{store_type}/{store_id}/{id}/tree?continueOnFailure={continueOnFailure?}&amp;unfileMultiFiledDocuments={unfileMultiFiledDocuments}</url> <url>/api/path/{store_type}/{store_id}/{path}/tree?continueOnFailure={continueOnFailure?}&amp;unfileMultiFiledDocuments={unfileMultiFiledDocuments}</url>
<authentication>user</authentication> <authentication>user</authentication>
<format default="atomfeed"/> <format default="atomfeed"/>
<family>CMIS</family> <family>CMIS</family>

View File

@@ -1,17 +1,15 @@
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/cmis/read.lib.js">
script: script:
{ {
// locate node // locate node
var pathSegments = url.match.split("/"); var object = getObjectFromUrl();
var reference = [ url.templateArgs.store_type, url.templateArgs.store_id ].concat(url.templateArgs.id.split("/")); if (object.node == null)
var node = cmis.findNode(pathSegments[2], reference);
if (node === null)
{ {
status.code = 404;
status.message = "Repository " + pathSegments[2] + " " + reference.join("/") + " not found";
status.redirect = true;
break script; break script;
} }
var node = object.node;
// NOTE: Ignore continueOnDelete as complete tree is deleted in single transaction // NOTE: Ignore continueOnDelete as complete tree is deleted in single transaction
// TODO: Throw error on invalid unfileMultiFiledDocuments error // TODO: Throw error on invalid unfileMultiFiledDocuments error
@@ -28,7 +26,7 @@ script:
if (!node.remove()) if (!node.remove())
{ {
status.code = 500; status.code = 500;
status.message = "Failed to delete node " + pathSegments[2] + " " + reference.join("/"); status.message = "Failed to delete object " + object.ref;
status.redirect = true; status.redirect = true;
break script; break script;
} }

View File

@@ -2,8 +2,17 @@
<shortname>Retrieve folder tree (getFolderTree)</shortname> <shortname>Retrieve folder tree (getFolderTree)</shortname>
<description> <description>
</description> </description>
<!-- by object id -->
<url>/cmis/i/{id}/tree?filter={filter?}&amp;depth={depth?}&amp;includeAllowableActions={includeAllowableActions?}</url>
<url>/cmis/s/{store}/i/{id}/tree?filter={filter?}&amp;depth={depth?}&amp;includeAllowableActions={includeAllowableActions?}</url>
<!-- by path -->
<url>/cmis/p{path}/tree?filter={filter?}&amp;depth={depth?}&amp;includeAllowableActions={includeAllowableActions?}</url>
<url>/cmis/s/{store}/p{path}/tree?filter={filter?}&amp;depth={depth?}&amp;includeAllowableActions={includeAllowableActions?}</url>
<!-- alfresco style -->
<url>/api/node/{store_type}/{store_id}/{id}/tree?filter={filter?}&amp;depth={depth?}&amp;includeAllowableActions={includeAllowableActions?}</url> <url>/api/node/{store_type}/{store_id}/{id}/tree?filter={filter?}&amp;depth={depth?}&amp;includeAllowableActions={includeAllowableActions?}</url>
<url>/api/path/{store_type}/{store_id}/{id}/tree?filter={filter?}&amp;depth={depth?}&amp;includeAllowableActions={includeAllowableActions?}</url> <url>/api/path/{store_type}/{store_id}/{path}/tree?filter={filter?}&amp;depth={depth?}&amp;includeAllowableActions={includeAllowableActions?}</url>
<authentication>guest</authentication> <authentication>guest</authentication>
<transaction allow="readonly"/> <transaction allow="readonly"/>
<format default="atomfeed">argument</format> <format default="atomfeed">argument</format>

View File

@@ -1,21 +1,19 @@
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/cmis/read.lib.js">
script: script:
{ {
// locate node // locate node
var pathSegments = url.match.split("/"); var object = getObjectFromUrl();
var reference = [ url.templateArgs.store_type, url.templateArgs.store_id ].concat(url.templateArgs.id.split("/")); if (object.node == null)
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; break script;
} }
model.node = object.node;
if (model.node.isDocument) if (model.node.isDocument)
{ {
status.code = 404; status.code = 404;
status.message = "Repository " + pathSegments[2] + " " + reference.join("/") + " not a folder"; status.message = "Object " + object.ref + " is not a folder";
status.redirect = true; status.redirect = true;
break script; break script;
} }

View File

@@ -19,7 +19,7 @@ canCreateInstances if false, the user MUST NOT be able to create instances of th
When includeInheritedProperties is true, the repository SHOULD return all properties defined for the Object Type, including any properties inherited from its parent. If false, only Properties defined on the Object Type (but not its parent) SHOULD be returned. When includeInheritedProperties is true, the repository SHOULD return all properties defined for the Object Type, including any properties inherited from its parent. If false, only Properties defined on the Object Type (but not its parent) SHOULD be returned.
]]> ]]>
</description> </description>
<url>/api/type/{typeId}?includeInheritedProperties={includeInheritedProperties?}</url> <url>/cmis/type/{typeId}?includeInheritedProperties={includeInheritedProperties?}</url>
<authentication>user</authentication> <authentication>user</authentication>
<transaction allow="readonly"/> <transaction allow="readonly"/>
<format default="atomentry"/> <format default="atomentry"/>

View File

@@ -1,8 +1,8 @@
<webscript> <webscript>
<shortname>Retrieve list of child Types</shortname> <shortname>Retrieve list of child Types</shortname>
<description>Retrieve list of all child Types</description> <description>Retrieve list of all child Types</description>
<url>/api/type/{typeId}/children?includePropertyDefinitions={includePropertyDefinitions?}&amp;skipCount={skipCount?}&amp;maxItems={maxItems?}</url> <url>/cmis/type/{typeId}/children?includePropertyDefinitions={includePropertyDefinitions?}&amp;skipCount={skipCount?}&amp;maxItems={maxItems?}</url>
<url>/api/types?typeId={typeId?}&amp;includePropertyDefinitions={includePropertyDefinitions?}&amp;skipCount={skipCount?}&amp;maxItems={maxItems?}</url> <url>/cmis/types?typeId={typeId?}&amp;includePropertyDefinitions={includePropertyDefinitions?}&amp;skipCount={skipCount?}&amp;maxItems={maxItems?}</url>
<authentication>user</authentication> <authentication>user</authentication>
<transaction allow="readonly"/> <transaction allow="readonly"/>
<format default="atomfeed"/> <format default="atomfeed"/>

View File

@@ -1,8 +1,8 @@
<webscript> <webscript>
<shortname>Retrieve list of descendant Types</shortname> <shortname>Retrieve list of descendant Types</shortname>
<description>Retrieve list of all descendant Types</description> <description>Retrieve list of all descendant Types</description>
<url>/api/type/{typeId}/descendants?includePropertyDefinitions={includePropertyDefinitions?}&amp;depth={depth?}</url> <url>/cmis/type/{typeId}/descendants?includePropertyDefinitions={includePropertyDefinitions?}&amp;depth={depth?}</url>
<url>/api/types/descendants?typeId={typeId?}&amp;includePropertyDefinitions={includePropertyDefinitions?}&amp;depth={depth?}</url> <url>/cmis/types/descendants?typeId={typeId?}&amp;includePropertyDefinitions={includePropertyDefinitions?}&amp;depth={depth?}</url>
<authentication>user</authentication> <authentication>user</authentication>
<transaction allow="readonly"/> <transaction allow="readonly"/>
<format default="atomfeed"/> <format default="atomfeed"/>

View File

@@ -1,7 +1,7 @@
<webscript> <webscript>
<shortname>Unfiled Documents</shortname> <shortname>Unfiled Documents</shortname>
<description>Retrieve list of documents that are not in any folder</description> <description>Retrieve list of documents that are not in any folder</description>
<url>/api/unfiled</url> <url>/cmis/unfiled</url>
<authentication>guest</authentication> <authentication>guest</authentication>
<transaction allow="readonly"/> <transaction allow="readonly"/>
<format default="atomfeed"/> <format default="atomfeed"/>

View File

@@ -18,8 +18,17 @@ Notes:<br>
Returns all versions the user can access including checked-out version and private working copy.<br> Returns all versions the user can access including checked-out version and private working copy.<br>
]]> ]]>
</description> </description>
<!-- by object id -->
<url>/cmis/i/{id}/versions?filter={filter?}</url>
<url>/cmis/s/{store}/i/{id}/versions?filter={filter?}</url>
<!-- by path -->
<url>/cmis/p{path}/versions?filter={filter?}</url>
<url>/cmis/s/{store}/p{path}/versions?filter={filter?}</url>
<!-- alfresco style -->
<url>/api/node/{store_type}/{store_id}/{id}/versions?filter={filter?}</url> <url>/api/node/{store_type}/{store_id}/{id}/versions?filter={filter?}</url>
<url>/api/path/{store_type}/{store_id}/{id}/versions?filter={filter?}</url> <url>/api/path/{store_type}/{store_id}/{path}/versions?filter={filter?}</url>
<authentication>user</authentication> <authentication>user</authentication>
<transaction allow="readonly"/> <transaction allow="readonly"/>
<format default="atomfeed">argument</format> <format default="atomfeed">argument</format>

View File

@@ -1,17 +1,15 @@
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/cmis/read.lib.js">
script: script:
{ {
// locate version series
// NOTE: version series is identified by noderef (as this is constant during lifetime of node) // NOTE: version series is identified by noderef (as this is constant during lifetime of node)
var pathSegments = url.match.split("/"); var object = getObjectFromUrl();
var reference = [ url.templateArgs.store_type, url.templateArgs.store_id ].concat(url.templateArgs.id.split("/")); if (object.node == null || !object.node.isVersioned)
model.node = cmis.findNode(pathSegments[2], reference);
if (model.node === null || !model.node.isVersioned)
{ {
status.code = 404; status.message = "Versions series " + object.ref + " not found";
status.message = "Versions series " + pathSegments[2] + " " + reference.join("/") + " not found";
status.redirect = true;
break script; break script;
} }
model.node = object.node;
// property filter // property filter
model.filter = args[cmis.ARG_FILTER]; model.filter = args[cmis.ARG_FILTER];

View File

@@ -224,10 +224,10 @@
<bean id="webscripts.js.cmis" parent="baseJavaScriptExtension" class="org.alfresco.repo.cmis.rest.CMISScript"> <bean id="webscripts.js.cmis" parent="baseJavaScriptExtension" class="org.alfresco.repo.cmis.rest.CMISScript">
<property name="extensionName"><value>cmis</value></property> <property name="extensionName"><value>cmis</value></property>
<property name="serviceRegistry" ref="ServiceRegistry" /> <property name="serviceRegistry" ref="ServiceRegistry" />
<property name="repository" ref="repositoryHelper" />
<property name="CMISService" ref="CMISService" /> <property name="CMISService" ref="CMISService" />
<property name="CMISDictionaryService" ref="CMISDictionaryService" /> <property name="CMISDictionaryService" ref="CMISDictionaryService" />
<property name="CMISQueryService" ref="CMISQueryService" /> <property name="CMISQueryService" ref="CMISQueryService" />
<property name="CMISReferenceFactory" ref="CMISReferenceFactory" />
<property name="paging" ref="webscripts.js.paging" /> <property name="paging" ref="webscripts.js.paging" />
</bean> </bean>
@@ -292,7 +292,7 @@
<!-- Content Retrieval --> <!-- Content Retrieval -->
<bean id="webscript.org.alfresco.repository.store.content.get" class="org.alfresco.repo.web.scripts.content.ContentGet" parent="webscript"> <bean id="webscript.org.alfresco.repository.store.content.get" class="org.alfresco.repo.web.scripts.content.ContentGet" parent="webscript">
<property name="repository" ref="repositoryHelper" /> <property name="referenceFactory" ref="CMISReferenceFactory" />
<property name="namespaceService" ref="NamespaceService" /> <property name="namespaceService" ref="NamespaceService" />
<property name="permissionService" ref="PermissionService" /> <property name="permissionService" ref="PermissionService" />
<property name="nodeService" ref="NodeService" /> <property name="nodeService" ref="NodeService" />
@@ -309,12 +309,19 @@
<!-- Content Write --> <!-- Content Write -->
<bean id="webscript.org.alfresco.repository.store.content.put" class="org.alfresco.repo.web.scripts.content.ContentSet" parent="webscript"> <bean id="webscript.org.alfresco.repository.store.content.put" class="org.alfresco.repo.web.scripts.content.ContentSet" parent="webscript">
<property name="repository" ref="repositoryHelper" /> <property name="referenceFactory" ref="CMISReferenceFactory" />
<property name="dictionaryService" ref="DictionaryService" /> <property name="dictionaryService" ref="DictionaryService" />
<property name="namespaceService" ref="NamespaceService" /> <property name="namespaceService" ref="NamespaceService" />
<property name="contentService" ref="ContentService" /> <property name="contentService" ref="ContentService" />
<property name="mimetypeService" ref="MimetypeService" /> <property name="mimetypeService" ref="MimetypeService" />
</bean> </bean>
<!-- Content Delete -->
<bean id="webscript.org.alfresco.repository.store.content.delete" class="org.alfresco.repo.web.scripts.content.ContentDelete" parent="webscript">
<property name="referenceFactory" ref="CMISReferenceFactory" />
<property name="namespaceService" ref="NamespaceService" />
<property name="nodeService" ref="NodeService" />
</bean>
<!-- Remote Store service - AVM --> <!-- Remote Store service - AVM -->
<bean id="webscript.org.alfresco.repository.store.remoteavm.get" class="org.alfresco.repo.web.scripts.bean.AVMRemoteStore" parent="webscript"> <bean id="webscript.org.alfresco.repository.store.remoteavm.get" class="org.alfresco.repo.web.scripts.bean.AVMRemoteStore" parent="webscript">

View File

@@ -26,26 +26,29 @@ package org.alfresco.repo.cmis.rest;
import java.util.Collection; import java.util.Collection;
import java.util.Iterator; import java.util.Iterator;
import java.util.regex.Matcher; import java.util.Map;
import java.util.regex.Pattern;
import org.alfresco.cmis.CMISDictionaryService; import org.alfresco.cmis.CMISDictionaryService;
import org.alfresco.cmis.CMISJoinEnum; import org.alfresco.cmis.CMISJoinEnum;
import org.alfresco.cmis.CMISObjectReference;
import org.alfresco.cmis.CMISPropertyDefinition; import org.alfresco.cmis.CMISPropertyDefinition;
import org.alfresco.cmis.CMISQueryEnum; import org.alfresco.cmis.CMISQueryEnum;
import org.alfresco.cmis.CMISQueryOptions; import org.alfresco.cmis.CMISQueryOptions;
import org.alfresco.cmis.CMISQueryService; import org.alfresco.cmis.CMISQueryService;
import org.alfresco.cmis.CMISRelationshipDirectionEnum; import org.alfresco.cmis.CMISRelationshipDirectionEnum;
import org.alfresco.cmis.CMISRelationshipReference;
import org.alfresco.cmis.CMISRepositoryReference;
import org.alfresco.cmis.CMISResultSet; import org.alfresco.cmis.CMISResultSet;
import org.alfresco.cmis.CMISServices; import org.alfresco.cmis.CMISServices;
import org.alfresco.cmis.CMISTypeDefinition; import org.alfresco.cmis.CMISTypeDefinition;
import org.alfresco.cmis.CMISTypesFilterEnum; import org.alfresco.cmis.CMISTypesFilterEnum;
import org.alfresco.cmis.CMISQueryOptions.CMISQueryMode; import org.alfresco.cmis.CMISQueryOptions.CMISQueryMode;
import org.alfresco.cmis.reference.NodeRefReference;
import org.alfresco.cmis.reference.ReferenceFactory;
import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.repo.jscript.Association; import org.alfresco.repo.jscript.Association;
import org.alfresco.repo.jscript.BaseScopableProcessorExtension; import org.alfresco.repo.jscript.BaseScopableProcessorExtension;
import org.alfresco.repo.jscript.ScriptNode; import org.alfresco.repo.jscript.ScriptNode;
import org.alfresco.repo.model.Repository;
import org.alfresco.repo.web.util.paging.Cursor; import org.alfresco.repo.web.util.paging.Cursor;
import org.alfresco.repo.web.util.paging.Page; import org.alfresco.repo.web.util.paging.Page;
import org.alfresco.repo.web.util.paging.PagedResults; import org.alfresco.repo.web.util.paging.PagedResults;
@@ -101,15 +104,11 @@ public class CMISScript extends BaseScopableProcessorExtension
// service dependencies // service dependencies
private ServiceRegistry services; private ServiceRegistry services;
private Repository repository;
private CMISServices cmisService; private CMISServices cmisService;
private CMISDictionaryService cmisDictionaryService; private CMISDictionaryService cmisDictionaryService;
private CMISQueryService cmisQueryService; private CMISQueryService cmisQueryService;
private Paging paging; private Paging paging;
private ReferenceFactory referenceFactory;
// versioned objectId pattern
// TODO: encapsulate elsewhere
private static final Pattern versionedObjectIdPattern = Pattern.compile(".+://.+/.+/.+");
/** /**
@@ -122,16 +121,6 @@ public class CMISScript extends BaseScopableProcessorExtension
this.services = services; this.services = services;
} }
/**
* Set the repository
*
* @param repository
*/
public void setRepository(Repository repository)
{
this.repository = repository;
}
/** /**
* Set the paging helper * Set the paging helper
* *
@@ -172,6 +161,16 @@ public class CMISScript extends BaseScopableProcessorExtension
this.cmisQueryService = cmisQueryService; this.cmisQueryService = cmisQueryService;
} }
/**
* Set the CMIS Reference Factory
*
* @param referenceFactory
*/
public void setCMISReferenceFactory(ReferenceFactory referenceFactory)
{
this.referenceFactory = referenceFactory;
}
/** /**
* Gets the supported CMIS Version * Gets the supported CMIS Version
* *
@@ -238,63 +237,83 @@ public class CMISScript extends BaseScopableProcessorExtension
} }
/** /**
* Finds a Node given a repository reference * Create CMIS Repository Reference from URL segments
* *
* @param referenceType node, path * @param args url arguments
* @param reference node => id, path => path * @param templateArgs url template arguments
* @return node (or null, if not found) * @return Repository Reference (or null, in case of bad url)
*/ */
public ScriptNode findNode(String referenceType, String[] reference) public CMISRepositoryReference createRepoReferenceFromUrl(Map<String, String> args, Map<String, String> templateArgs)
{ {
ScriptNode node = null; return referenceFactory.createRepoReferenceFromUrl(args, templateArgs);
NodeRef nodeRef = repository.findNodeRef(referenceType, reference); }
if (nodeRef != null)
{ /**
node = new ScriptNode(nodeRef, services, getScope()); * Create CMIS Object Reference from URL segments
} *
return node; * @param args url arguments
* @param templateArgs url template arguments
* @return Repository Reference (or null, in case of bad url)
*/
public CMISObjectReference createObjectReferenceFromUrl(Map<String, String> args, Map<String, String> templateArgs)
{
return referenceFactory.createObjectReferenceFromUrl(args, templateArgs);
} }
/** /**
* Finds a Node given CMIS ObjectId * Create CMIS Relationship Reference from URL segments
* *
* @param objectId * @param args url arguments
* @return node (or null, if not found) * @param templateArgs url template arguments
* @return Repository Reference (or null, in case of bad url)
*/ */
public ScriptNode findNode(String objectId) public CMISRelationshipReference createRelationshipReferenceFromUrl(Map<String, String> args, Map<String, String> templateArgs)
{ {
NodeRef nodeRef; return referenceFactory.createRelationshipReferenceFromUrl(args, templateArgs);
Matcher matcher = versionedObjectIdPattern.matcher(objectId);
if (matcher.matches())
{
// TODO: handle version id
nodeRef = new NodeRef(objectId.substring(0, objectId.lastIndexOf("/")));
}
else
{
nodeRef = new NodeRef(objectId);
}
String[] reference = new String[] {nodeRef.getStoreRef().getProtocol(), nodeRef.getStoreRef().getIdentifier(), nodeRef.getId()};
return findNode("node", reference);
} }
/** /**
* Finds an Association * Create Object Reference
* *
* @param sourceType * @param repo repository reference
* @param source * @param object id object id (NodeRef.toString() format)
* @param relDef * @return object id reference
* @param targetType
* @param target
*
* @return
*/ */
public Association findRelationship(CMISTypeDefinition relDef, String[] sourceRef, String[] targetRef) public CMISObjectReference createObjectIdReference(String objectId)
{ {
NodeRef source = new NodeRef(sourceRef[0], sourceRef[1], sourceRef[2]); return new NodeRefReference(cmisService, objectId);
NodeRef target = new NodeRef(targetRef[0], targetRef[1], targetRef[2]); }
AssociationRef assocRef = cmisService.getRelationship(relDef, source, target);
return (assocRef == null) ? null : new Association(services, assocRef); /**
* Get Node from Object Reference
*
* @param ref object reference
* @return node
*/
public ScriptNode getNode(CMISObjectReference ref)
{
NodeRef nodeRef = ref.getNodeRef();
if (nodeRef == null)
{
return null;
}
return new ScriptNode(nodeRef, services, getScope());
}
/**
* Get Association from Relationship Reference
*
* @param ref relationship reference
* @return association
*/
public Association getAssociation(CMISRelationshipReference ref)
{
AssociationRef assocRef = ref.getAssocRef();
if (assocRef == null)
{
return null;
}
return new Association(services, assocRef);
} }
/** /**
@@ -424,35 +443,6 @@ public class CMISScript extends BaseScopableProcessorExtension
return results; return results;
} }
/**
* Query for all Type Definitions in a type hierarchy
*
* @param page
* @return paged result set of types
*/
// public PagedResults queryTypeHierarchy(CMISTypeDefinition typeDef, boolean descendants, Page page)
// {
// Collection<CMISTypeDefinition> subTypes = typeDef.getSubTypes(descendants);
// Cursor cursor = paging.createCursor(subTypes.size(), page);
//
// // skip
// Iterator<CMISTypeDefinition> iterSubTypes = subTypes.iterator();
// for (int i = 0; i < cursor.getStartRow(); i++)
// {
// iterSubTypes.next();
// }
//
// // get types for page
// CMISTypeDefinition[] types = new CMISTypeDefinition[cursor.getRowCount()];
// for (int i = cursor.getStartRow(); i <= cursor.getEndRow(); i++)
// {
// types[i - cursor.getStartRow()] = iterSubTypes.next();
// }
//
// PagedResults results = paging.createPagedResults(types, cursor);
// return results;
// }
/** /**
* Query for a Type Definition given a CMIS Type Id * Query for a Type Definition given a CMIS Type Id
* *

View File

@@ -782,8 +782,6 @@ public class RepositoryContainer extends AbstractRuntimeContainer implements Ten
{ {
try try
{ {
if (logger.isDebugEnabled())
logger.debug("Writing Transactional response: size=" + outputStream.size());
if (outputWriter != null) if (outputWriter != null)
{ {
@@ -792,6 +790,9 @@ public class RepositoryContainer extends AbstractRuntimeContainer implements Ten
} }
else if (outputStream != null) else if (outputStream != null)
{ {
if (logger.isDebugEnabled())
logger.debug("Writing Transactional response: size=" + outputStream.size());
outputStream.flush(); outputStream.flush();
outputStream.writeTo(res.getOutputStream()); outputStream.writeTo(res.getOutputStream());
} }

View File

@@ -0,0 +1,138 @@
/*
* 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.web.scripts.content;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;
import org.alfresco.cmis.CMISObjectReference;
import org.alfresco.cmis.reference.ReferenceFactory;
import org.alfresco.model.ContentModel;
import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.web.scripts.AbstractWebScript;
import org.alfresco.web.scripts.WebScriptException;
import org.alfresco.web.scripts.WebScriptRequest;
import org.alfresco.web.scripts.WebScriptResponse;
/**
* Content Delete Service
*
* Delete content stream from the Repository.
*
* @author davidc
*/
public class ContentDelete extends AbstractWebScript
{
// Component dependencies
private ReferenceFactory referenceFactory;
private NamespaceService namespaceService;
private NodeService nodeService;
/**
* @param reference factory
*/
public void setReferenceFactory(ReferenceFactory referenceFactory)
{
this.referenceFactory = referenceFactory;
}
/**
* @param namespaceService
*/
public void setNamespaceService(NamespaceService namespaceService)
{
this.namespaceService = namespaceService;
}
/**
* @param nodeService
*/
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
/**
* @see org.alfresco.web.scripts.WebScript#execute(org.alfresco.web.scripts.WebScriptRequest, org.alfresco.web.scripts.WebScriptResponse)
*/
public void execute(WebScriptRequest req, WebScriptResponse res)
throws IOException
{
// create map of args
String[] names = req.getParameterNames();
Map<String, String> args = new HashMap<String, String>(names.length, 1.0f);
for (String name : names)
{
args.put(name, req.getParameter(name));
}
// create map of template vars
Map<String, String> templateVars = req.getServiceMatch().getTemplateVars();
// create object reference from url
CMISObjectReference reference = referenceFactory.createObjectReferenceFromUrl(args, templateVars);
NodeRef nodeRef = reference.getNodeRef();
if (nodeRef == null)
{
throw new WebScriptException(HttpServletResponse.SC_NOT_FOUND, "Unable to find " + reference.toString());
}
// determine content property
QName propertyQName = ContentModel.PROP_CONTENT;
String contentPart = templateVars.get("property");
if (contentPart.length() > 0 && contentPart.charAt(0) == ';')
{
if (contentPart.length() < 2)
{
throw new WebScriptException(HttpServletResponse.SC_BAD_REQUEST, "Content property malformed");
}
String propertyName = contentPart.substring(1);
if (propertyName.length() > 0)
{
propertyQName = QName.createQName(propertyName, namespaceService);
}
}
// retrieve content property
ContentData contentData = (ContentData)nodeService.getProperty(nodeRef, propertyQName);
if (contentData != null)
{
contentData = new ContentData(null, null, 0, null);
nodeService.setProperty(nodeRef, propertyQName, contentData);
}
// no content returned
res.setStatus(204);
}
}

View File

@@ -25,13 +25,14 @@
package org.alfresco.repo.web.scripts.content; package org.alfresco.repo.web.scripts.content;
import java.io.IOException; import java.io.IOException;
import java.util.Arrays; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import org.alfresco.cmis.CMISObjectReference;
import org.alfresco.cmis.reference.ReferenceFactory;
import org.alfresco.model.ContentModel; import org.alfresco.model.ContentModel;
import org.alfresco.repo.model.Repository;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.QName;
@@ -56,15 +57,15 @@ public class ContentGet extends StreamContent
private static final Log logger = LogFactory.getLog(ContentGet.class); private static final Log logger = LogFactory.getLog(ContentGet.class);
// Component dependencies // Component dependencies
private Repository repository; private ReferenceFactory referenceFactory;
private NamespaceService namespaceService; private NamespaceService namespaceService;
/** /**
* @param repository * @param reference factory
*/ */
public void setRepository(Repository repository) public void setReferenceFactory(ReferenceFactory referenceFactory)
{ {
this.repository = repository; this.referenceFactory = referenceFactory;
} }
/** /**
@@ -80,20 +81,24 @@ public class ContentGet extends StreamContent
*/ */
public void execute(WebScriptRequest req, WebScriptResponse res) public void execute(WebScriptRequest req, WebScriptResponse res)
throws IOException throws IOException
{ {
// convert web script URL to node reference in Repository // create map of args
String match = req.getServiceMatch().getPath(); String[] names = req.getParameterNames();
String[] matchParts = match.split("/"); Map<String, String> args = new HashMap<String, String>(names.length, 1.0f);
for (String name : names)
{
args.put(name, req.getParameter(name));
}
// create map of template vars
Map<String, String> templateVars = req.getServiceMatch().getTemplateVars(); Map<String, String> templateVars = req.getServiceMatch().getTemplateVars();
String[] id = templateVars.get("id").split("/");
String[] path = new String[id.length + 2]; // create object reference from url
path[0] = templateVars.get("store_type"); CMISObjectReference reference = referenceFactory.createObjectReferenceFromUrl(args, templateVars);
path[1] = templateVars.get("store_id"); NodeRef nodeRef = reference.getNodeRef();
System.arraycopy(id, 0, path, 2, id.length);
NodeRef nodeRef = repository.findNodeRef(matchParts[2], path);
if (nodeRef == null) if (nodeRef == null)
{ {
throw new WebScriptException(HttpServletResponse.SC_NOT_FOUND, "Unable to find " + matchParts[2] + " reference " + Arrays.toString(path)); throw new WebScriptException(HttpServletResponse.SC_NOT_FOUND, "Unable to find " + reference.toString());
} }
// determine content property // determine content property

View File

@@ -28,14 +28,16 @@ import java.io.BufferedInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.util.Arrays; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import org.alfresco.cmis.CMISObjectReference;
import org.alfresco.cmis.reference.ObjectPathReference;
import org.alfresco.cmis.reference.ReferenceFactory;
import org.alfresco.model.ContentModel; import org.alfresco.model.ContentModel;
import org.alfresco.repo.content.encoding.ContentCharsetFinder; import org.alfresco.repo.content.encoding.ContentCharsetFinder;
import org.alfresco.repo.model.Repository;
import org.alfresco.service.cmr.dictionary.DataTypeDefinition; import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.dictionary.PropertyDefinition; import org.alfresco.service.cmr.dictionary.PropertyDefinition;
@@ -68,18 +70,18 @@ public class ContentSet extends AbstractWebScript
private static final Log logger = LogFactory.getLog(ContentSet.class); private static final Log logger = LogFactory.getLog(ContentSet.class);
// Component dependencies // Component dependencies
private Repository repository; private ReferenceFactory referenceFactory;
private DictionaryService dictionaryService; private DictionaryService dictionaryService;
private NamespaceService namespaceService; private NamespaceService namespaceService;
private ContentService contentService; private ContentService contentService;
private MimetypeService mimetypeService; private MimetypeService mimetypeService;
/** /**
* @param repository * @param reference factory
*/ */
public void setRepository(Repository repository) public void setReferenceFactory(ReferenceFactory referenceFactory)
{ {
this.repository = repository; this.referenceFactory = referenceFactory;
} }
/** /**
@@ -119,20 +121,24 @@ public class ContentSet extends AbstractWebScript
*/ */
public void execute(WebScriptRequest req, WebScriptResponse res) public void execute(WebScriptRequest req, WebScriptResponse res)
throws IOException throws IOException
{ {
// convert web script URL to node reference in Repository // create map of args
String match = req.getServiceMatch().getPath(); String[] names = req.getParameterNames();
String[] matchParts = match.split("/"); Map<String, String> args = new HashMap<String, String>(names.length, 1.0f);
for (String name : names)
{
args.put(name, req.getParameter(name));
}
// create map of template vars
Map<String, String> templateVars = req.getServiceMatch().getTemplateVars(); Map<String, String> templateVars = req.getServiceMatch().getTemplateVars();
String[] id = templateVars.get("id").split("/");
String[] path = new String[id.length + 2]; // create object reference from url
path[0] = templateVars.get("store_type"); CMISObjectReference reference = referenceFactory.createObjectReferenceFromUrl(args, templateVars);
path[1] = templateVars.get("store_id"); NodeRef nodeRef = reference.getNodeRef();
System.arraycopy(id, 0, path, 2, id.length);
NodeRef nodeRef = repository.findNodeRef(matchParts[2], path);
if (nodeRef == null) if (nodeRef == null)
{ {
throw new WebScriptException(HttpServletResponse.SC_NOT_FOUND, "Unable to find " + matchParts[2] + " reference " + Arrays.toString(path)); throw new WebScriptException(HttpServletResponse.SC_NOT_FOUND, "Unable to find " + reference.toString());
} }
// determine content property // determine content property
@@ -153,7 +159,7 @@ public class ContentSet extends AbstractWebScript
PropertyDefinition propertyDef = dictionaryService.getProperty(propertyQName); PropertyDefinition propertyDef = dictionaryService.getProperty(propertyQName);
if (propertyDef == null) if (propertyDef == null)
{ {
throw new WebScriptException(HttpServletResponse.SC_NOT_FOUND, "Unable to find " + matchParts[2] + " reference " + Arrays.toString(path) + " content property " + propertyQName); throw new WebScriptException(HttpServletResponse.SC_NOT_FOUND, "Unable to find content property " + propertyQName + " of " + reference.toString());
} }
if (!propertyDef.getDataType().getName().equals(DataTypeDefinition.CONTENT)) if (!propertyDef.getDataType().getName().equals(DataTypeDefinition.CONTENT))
{ {
@@ -180,9 +186,9 @@ public class ContentSet extends AbstractWebScript
String mimetype = req.getContentType(); String mimetype = req.getContentType();
if (mimetype == null) if (mimetype == null)
{ {
if (matchParts[2].equals("path") || matchParts[2].equals("avmpath")) if (reference instanceof ObjectPathReference)
{ {
mimetype = mimetypeService.guessMimetype(templateVars.get("id")); mimetype = mimetypeService.guessMimetype(((ObjectPathReference)reference).getPath());
} }
} }
if (mimetype != null) if (mimetype != null)

View File

@@ -1,14 +0,0 @@
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN//EN' 'http://www.springframework.org/dtd/spring-beans.dtd'>
<beans>
<bean id="cmis.test.dictionaryBootstrap" parent="dictionaryModelBootstrap" depends-on="dictionaryBootstrap">
<property name="models">
<list>
<value>cmis/cmisCustomModel.xml</value>
</list>
</property>
</bean>
</beans>

View File

@@ -1,61 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<model name="cmiscustom:model" xmlns="http://www.alfresco.org/model/dictionary/1.0">
<description>CMIS Custom Model</description>
<author>Alfresco</author>
<version>1.0</version>
<imports>
<import uri="http://www.alfresco.org/model/dictionary/1.0" prefix="d"/>
<import uri="http://www.alfresco.org/model/content/1.0" prefix="cm"/>
<import uri="http://www.alfresco.org/model/system/1.0" prefix="sys"/>
</imports>
<namespaces>
<namespace uri="http://www.alfresco.org/model/cmis/custom" prefix="cmiscustom"/>
</namespaces>
<types>
<type name="cmiscustom:folder">
<title>Custom Folder</title>
<parent>cm:folder</parent>
<properties>
<property name="cmiscustom:folderprop_string">
<title>Custom Folder Property (string)</title>
<type>d:text</type>
</property>
</properties>
</type>
<type name="cmiscustom:document">
<title>Custom Document</title>
<parent>cm:content</parent>
<properties>
<property name="cmiscustom:docprop_string">
<title>Custom Document Property (string)</title>
<type>d:text</type>
</property>
<property name="cmiscustom:docprop_boolean_multi">
<title>Custom Document Property (multi-valued boolean)</title>
<type>d:boolean</type>
<multiple>true</multiple>
</property>
</properties>
<associations>
<association name="cmiscustom:assoc">
<source>
<mandatory>false</mandatory>
<many>false</many>
</source>
<target>
<class>cm:content</class>
<mandatory>false</mandatory>
<many>true</many>
</target>
</association>
</associations>
</type>
</types>
</model>