Merged DEV/CMIS_10 to HEAD

18731: SAIL-169: CMIS REST versioning compliance
      - Rendering of "via" link for working copy and "current-version" and "working-copy" links for documents
      - Added ability to dereference object IDs in cmisproperty() template function
      - Fixed broken CMIS index page


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@18896 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Dave Ward
2010-02-27 13:24:10 +00:00
parent ce8d11fef5
commit 7d41c0b8bb
10 changed files with 154 additions and 90 deletions

View File

@@ -17,7 +17,7 @@
[#list results as child]
[#if child.isDocument]
[@entryLib.pwc node=child renditionfilter=renditionFilter propfilter=filter includeallowableactions=includeAllowableActions includerelationships="none"/]
[@entryLib.document node=child renditionfilter=renditionFilter propfilter=filter includeallowableactions=includeAllowableActions includerelationships="none"/]
[/#if]
[/#list]

View File

@@ -6,6 +6,6 @@
<?xml version="1.0" encoding="UTF-8"?>
[#assign namespace][@nsLib.entryNS/][/#assign]
[@entryLib.pwc node=pwc includeallowableactions=true includerelationships="none" ns=namespace/]
[@entryLib.document node=pwc includeallowableactions=true includerelationships="none" ns=namespace/]
[/#compress]

View File

@@ -8,5 +8,6 @@
<format default="html"/>
<authentication>none</authentication>
<transaction>required</transaction>
<family>CMIS</family>
</webscript>

View File

@@ -56,6 +56,13 @@
[@linksLib.linkacl node/]
[@linksLib.linkparents node/]
[@linksLib.linkversions node/]
[#if node.isWorkingCopy]
[#local nodeuri][@linksLib.nodeuri cmisproperty(node, cmisconstants.PROP_VERSION_SERIES_ID, true)/][/#local]
[@linksLib.linkvia href="${nodeuri}"/]
[#else]
[@linksLib.linkcurrentversion node/]
[#if cmisproperty(node, cmisconstants.PROP_IS_VERSION_SERIES_CHECKED_OUT)][@linksLib.linkpwc cmisproperty(node, cmisconstants.PROP_VERSION_SERIES_CHECKED_OUT_ID, true)/][/#if]
[/#if]
[@linksLib.linktype node/]
[@linksLib.linkservice/]
[#local nodeMap=cmisrenditions(node, renditionfilter)/]
@@ -89,37 +96,6 @@
[/@entry]
[/#macro]
[#-- --]
[#-- ATOM Entry for Private Working Copy --]
[#-- --]
[#macro pwc node renditionfilter="cmis:none" propfilter="*" includeallowableactions=false includerelationships="none" ns=""]
[@entry ns]
<author><name>${node.properties.creator!""}</name></author>
[@contentstream node/]
<id>urn:uuid:${node.id}</id>
[#assign pwcuri]/cmis/pwc/[@linksLib.noderef node/][/#assign]
[@linksLib.linkself href="${pwcuri}"/]
[@linksLib.linkstream node "enclosure"/]
[@linksLib.linknodeedit node/]
[@linksLib.linkstream node "edit-media"/]
[@documentCMISLinks node=node renditionfilter=renditionfilter/]
<published>${xmldate(node.properties.created)}</published>
<summary>[@contentsummary node/]</summary>
<title>${node.name?xml}</title>
<updated>${xmldate(node.properties.modified)}</updated>
<app:edited>${xmldate(node.properties.modified)}</app:edited>
<alf:icon>${absurl(url.context)}${node.icon16}</alf:icon>
<cmisra:object>
[@objectCMISProps node propfilter/]
[#if includeallowableactions][@allowableactions node/][/#if]
</cmisra:object>
<cmisra:pathSegment>${node.name?xml}</cmisra:pathSegment>
[/@entry]
[/#macro]
[#-- --]
[#-- ATOM Entry for Folder --]
[#-- --]

View File

@@ -54,6 +54,16 @@
<link rel="${cmisconstants.REL_VERSION_HISTORY}" href="${absurl(url.serviceContext)}[@nodeuri node/]/versions"/>
[/#macro]
[#-- Link to current node version --]
[#macro linkcurrentversion node]
<link rel="${cmisconstants.REL_CURRENT_VERSION}" href="${absurl(url.serviceContext)}[@nodeuri node/]?returnVersion=latest"/>
[/#macro]
[#-- Link to working copy node --]
[#macro linkpwc pwc]
<link rel="${cmisconstants.REL_WORKING_COPY}" href="${absurl(url.serviceContext)}[@pwcuri pwc/]"/>
[/#macro]
[#-- Link to source node --]
[#macro linktosource node]
<link rel="${cmisconstants.REL_ASSOC_SOURCE}" href="${absurl(url.serviceContext)}[@nodeuri node/]"/>
@@ -95,7 +105,7 @@
[/#macro]
[#macro linknodeself node]
<link rel="self" href="${absurl(url.serviceContext)}[@nodeuri node/]"/>
<link rel="self" href="${absurl(url.serviceContext)}[#if node.isWorkingCopy][@pwcuri node/][#else][@nodeuri node/][/#if]"/>
[/#macro]
[#macro linkassocself assoc]
@@ -157,6 +167,9 @@
[#-- Helper to render Alfresco Node uri --]
[#macro nodeuri node]/cmis/[@noderef node/][/#macro]
[#-- Helper to render Alfresco PWC uri --]
[#macro pwcuri node]/cmis/pwc/[@noderef node/][/#macro]
[#-- Helper to render Alfresco Assoc uri --]
[#macro assocuri assoc]/cmis/rel/${assoc.associationRef.id}[/#macro]

View File

@@ -7,6 +7,6 @@
<?xml version="1.0" encoding="UTF-8"?>
[#assign namespace][@nsLib.entryNS/][/#assign]
[@entryLib.pwc node=node renditionfilter=renditionFilter includeallowableactions=false includerelationships="none" ns=namespace/]
[@entryLib.document node=node renditionfilter=renditionFilter propfilter=filter includeallowableactions=includeAllowableActions includerelationships="none" includeacl=includeACL ns=namespace/]
[/#compress]

View File

@@ -1,9 +1,33 @@
<webscript>
<shortname>Retrieve properties of PWC</shortname>
<description>Retrieves the properties of a private working copy</description>
<shortname>Retrieve properties of PWC (getProperties)</shortname>
<description>
<![CDATA[
Returns the properties of an object, and optionally the operations that the user is allowed to perform on the object<br>
<br>
Inputs:<br>
<br>
ID objectId<br>
(Optional) Enum returnVersion: This (Default), Latest, LatestMajor<br>
(Optional) String filter: Filter for properties to be returned<br>
(Optional) Boolean includeAllowableActions: False (default)<br>
(Optional) Enum includeRelationships: none (default), source, target, both<br>
<br>
Outputs:<br>
<br>
Collection propertyCollection<br>
Collection allowableActionCollection<br>
<br>
Notes:<br>
<br>
If “includeAllowableActions” is TRUE, the repository will return the allowable actions for the current user for the object as part of the output.<br>
"IncludeRelationships" indicates whether relationships are also returned for the 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>
Does not return the content-stream of a document<br>
PropertyCollection includes changeToken (if applicable to repository)<br>
]]>
</description>
<url>/cmis/pwc/i/{id}?filter={filter?}&amp;renditionFilter={renditionFilter?}</url>
<url>/cmis/pwc/s/{store}/i/{id}?filter={filter?}&amp;renditionFilter={renditionFilter?}</url>
<url>/cmis/pwc/i/{id}?filter={filter?}&amp;returnVersion={returnVersion?}&amp;includeAllowableActions={includeAllowableActions?}&amp;includeACL={includeACL?}&amp;renditionFilter={renditionFilter?}</url>
<url>/cmis/pwc/s/{store}/i/{id}?filter={filter?}&amp;returnVersion={returnVersion?}&amp;includeAllowableActions={includeAllowableActions?}&amp;includeACL={includeACL?}&amp;renditionFilter={renditionFilter?}</url>
<authentication>user</authentication>
<transaction allow="readonly"/>

View File

@@ -2,14 +2,31 @@
script:
{
// locate node
var object = getObjectFromUrl();
if (object.node == null)
if (object.node === null)
{
break script;
}
model.node = object.node;
// return version
var returnVersion = args[cmis.ARG_RETURN_VERSION];
if (returnVersion === null || returnVersion.length == 0)
{
returnVersion = "this";
}
model.node = cmis.getReturnVersion(model.node, returnVersion);
// property filter
model.filter = args[cmis.ARG_FILTER];
if (model.filter === null || model.filter == "")
{
model.filter = "*";
}
// ACL
model.includeACL = args[cmis.ARG_INCLUDE_ACL] == "true";
// rendition filter
model.renditionFilter = args[cmis.ARG_RENDITION_FILTER];
if (model.renditionFilter === null || model.renditionFilter.length == 0)
@@ -17,6 +34,6 @@ script:
model.renditionFilter = "cmis:none";
}
// TODO: property filters
// include allowable actions
model.includeAllowableActions = args[cmis.ARG_INCLUDE_ALLOWABLE_ACTIONS] == "true";
}

View File

@@ -138,6 +138,8 @@
<entry key="cmisproperty">
<bean class="org.alfresco.repo.cmis.rest.CMISPropertyValueMethod">
<constructor-arg><ref bean="CMISService"/></constructor-arg>
<constructor-arg><ref bean="webscripts.repo.templateprocessor"/></constructor-arg>
<constructor-arg><ref bean="webscripts.repo.imageresolver"/></constructor-arg>
</bean>
</entry>
<entry key="cmisresultset">

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2005-2007 Alfresco Software Limited.
* Copyright (C) 2005-2010 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
@@ -18,7 +18,7 @@
* 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
* FLOSS exception. You should have received a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
@@ -26,14 +26,18 @@ package org.alfresco.repo.cmis.rest;
import java.util.List;
import org.alfresco.cmis.CMISInvalidArgumentException;
import org.alfresco.cmis.CMISServiceException;
import org.alfresco.cmis.CMISServices;
import org.alfresco.repo.template.TemplateAssociation;
import org.alfresco.repo.template.TemplateNode;
import org.alfresco.repo.web.scripts.RepositoryImageResolver;
import org.alfresco.service.cmr.repository.TemplateImageResolver;
import org.alfresco.service.cmr.repository.TemplateValueConverter;
import org.springframework.extensions.webscripts.WebScriptException;
import freemarker.ext.beans.BeanModel;
import freemarker.ext.beans.BeansWrapper;
import freemarker.template.TemplateBooleanModel;
import freemarker.template.TemplateMethodModelEx;
import freemarker.template.TemplateModel;
import freemarker.template.TemplateModelException;
@@ -42,73 +46,100 @@ import freemarker.template.TemplateScalarModel;
/**
* Custom FreeMarker Template language method.
* <p>
* Retrieve the CMIS property value for an Alfresco node
* Retrieve the CMIS property value for an Alfresco node and optionally dereferences it as an objectId.
* <p>
* Usage: cmisproperty(TemplateNode node, String propertyName)
*
* cmisproperty(TemplateNode node, String propertyName, Boolean asObject)
* @author davidc
* @author dward
*/
public final class CMISPropertyValueMethod implements TemplateMethodModelEx
public class CMISPropertyValueMethod implements TemplateMethodModelEx
{
/**
* NULL value marker
*/
public static class NULL {};
public static class NULL
{
};
public static TemplateModel IS_NULL = new BeanModel(new NULL(), BeansWrapper.getDefaultInstance());
private CMISServices cmisService;
private TemplateImageResolver imageResolver;
private TemplateValueConverter templateValueConverter;
/**
* Construct
*/
public CMISPropertyValueMethod(CMISServices cmisService)
public CMISPropertyValueMethod(CMISServices cmisService, RepositoryImageResolver imageResolver,
TemplateValueConverter templateValueConverter)
{
this.cmisService = cmisService;
this.imageResolver = imageResolver.getImageResolver();
this.templateValueConverter = templateValueConverter;
}
/**
* @see freemarker.template.TemplateMethodModel#exec(java.util.List)
*/
@SuppressWarnings("unchecked")
public Object exec(List args) throws TemplateModelException
{
Object result = null;
if (args.size() == 2)
{
Object arg0 = args.get(0);
if (arg0 instanceof BeanModel)
{
// extract property name
Object wrapped = null;
String propertyName = null;
Object arg1 = args.get(1);
if (arg1 instanceof TemplateScalarModel)
boolean asObject = false;
try
{
propertyName = ((TemplateScalarModel)arg1).getAsString();
int i = 0;
// extract object
Object arg = args.get(i++);
if (arg instanceof BeanModel)
{
wrapped = ((BeanModel) arg).getWrappedObject();
}
// extract node
Object wrapped = ((BeanModel)arg0).getWrappedObject();
// extract property name
arg = args.get(i++);
if (arg instanceof TemplateScalarModel)
{
propertyName = ((TemplateScalarModel) arg).getAsString();
}
// extract asObject flag
arg = args.get(i++);
if (arg instanceof TemplateBooleanModel)
{
asObject = ((TemplateBooleanModel) arg).getAsBoolean();
}
}
catch (IndexOutOfBoundsException e)
{
// Ignore optional arguments
}
try
{
Object result = null;
if (wrapped != null && wrapped instanceof TemplateNode)
{
// retrieve property value from node
try
{
result = cmisService.getProperty(((TemplateNode)wrapped).getNodeRef(), propertyName);
}
catch (CMISInvalidArgumentException e)
{
throw new WebScriptException(e.getStatusCode(), e.getMessage(), e);
}
result = cmisService.getProperty(((TemplateNode) wrapped).getNodeRef(), propertyName);
}
else if (wrapped != null && wrapped instanceof TemplateAssociation)
{
// retrieve property value from node
result = cmisService.getProperty(((TemplateAssociation)wrapped).getAssociationRef(), propertyName);
// retrieve property value from association
result = cmisService.getProperty(((TemplateAssociation) wrapped).getAssociationRef(), propertyName);
}
if (asObject && result instanceof String)
{
// convert result to an object if required
result = cmisService.getReadableObject((String) result, Object.class);
}
return result == null ? IS_NULL : templateValueConverter.convertValue(result, imageResolver);
}
catch (CMISServiceException e)
{
throw new WebScriptException(e.getStatusCode(), e.getMessage(), e);
}
return result == null ? IS_NULL : result;
}
}