diff --git a/config/alfresco/templates/webscripts/org/alfresco/cmis/atomentry.lib.atom.ftl b/config/alfresco/templates/webscripts/org/alfresco/cmis/atomentry.lib.atom.ftl index 96a93c1cfd..84d5fefefa 100644 --- a/config/alfresco/templates/webscripts/org/alfresco/cmis/atomentry.lib.atom.ftl +++ b/config/alfresco/templates/webscripts/org/alfresco/cmis/atomentry.lib.atom.ftl @@ -28,6 +28,7 @@ + [/#macro] [#macro documentCMISProps node] @@ -119,6 +120,7 @@ + [/#macro] [#macro folderCMISProps node] @@ -136,6 +138,109 @@ [/#macro] +[#-- --] +[#-- ATOM Entry for Type Definition --] +[#-- --] + +[#macro typedef typedef includeProperties=true includeInheritedProperties=true] +[#if true] [#-- TODO: spec issue 40 --] +[@typedefCMISProps typedef includeProperties includeInheritedProperties/] +[#else] +${person.properties.userName} +${typedef.objectTypeId} [#-- TODO --] +urn:uuid:type-${typedef.objectTypeId} + +[@typedefCMISLinks typedef/] +${typedef.description!typedef.objectTypeDisplayName} +${typedef.objectTypeDisplayName} +${xmldate(date)} [#-- TODO --] +[@typedefCMISProps typedef includeProperties/] +[/#if] +[/#macro] + +[#macro typedefCMISLinks typedef] + + + + +[/#macro] + +[#macro typedefCMISProps typedef includeProperties=true includeInheritedProperties=true] + + ${typedef.objectTypeId} + [@cmisBaseType typedef.rootTypeQueryName/] [#-- TODO: remove spec issue 36 --] + ${xmldate(date)} [#-- TODO: remove spec issue 36 --] + ${xmldate(date)} [#-- TODO: remove spec issue 36 --] + ${typedef.objectTypeQueryName} + [#if typedef.objectTypeDisplayName??]${typedef.objectTypeDisplayName?xml}[/#if] + ${typedef.rootTypeQueryName} + ${typedef.parentTypeId!""} + [#if typedef.description??]${typedef.description?xml}[/#if] + ${typedef.creatable?string} + ${typedef.fileable?string} + ${typedef.queryable?string} + ${typedef.controllable?string} + ${typedef.versionable?string} + [@cmisContentStreamAllowed typedef.contentStreamAllowed/] [#-- TODO: spec issue 37 --] + [#if includeProperties] + [#list typedef.propertyDefinitions?values as propdef] + [#if includeInheritedProperties || !propdef.inherited] + [@propdefCMISProps propdef/] + [/#if] + [/#list] + [/#if] + +[/#macro] + +[#macro propdefCMISProps propdef] + + ${propdef.propertyName} + ${propdef.propertyId} + [#if propdef.displayName??]${propdef.displayName?xml}[/#if] + [#if propdef.description??]${propdef.description?xml}[/#if] + ${propdef.inherited?string} + ${propdef.propertyType} + [@cmisCardinality propdef.cardinality/] + [#if propdef.maximumLength != -1] + ${propdef.maximumLength} + [/#if] + [@cmisChoices propdef.choices/] + ${propdef.openChoice?string} + ${propdef.required?string} + ${propdef.defaultValue!""} + [@cmisUpdatability propdef.updatability/] [#-- TODO spec issue 38 --] + ${propdef.queryable?string} + ${propdef.orderable?string} + +[/#macro] + +[#-- TODO: spec issue 40 --] +[#macro cmisBaseType rootType] +[#if rootType = "DOCUMENT_OBJECT_TYPE"]document[#elseif rootType = "FOLDER_OBJECT_TYPE"]folder[#elseif rootType = "RELATIONSHIP_OBJECT_TYPE"]relationship[#elseif rootType = "POLICY_OBJECT_TYPE"]policy[#else][/#if][/#macro] + +[#-- TODO: spec issue 37 --] +[#macro cmisContentStreamAllowed allowed] +[#if allowed = "NOT_ALLOWED"]notallowed[#elseif allowed = "ALLOWED"]allowed[#elseif allowed = "REQUIRED"]required[#else][/#if][/#macro] + +[#-- TODO: spec issue 37 --] +[#macro cmisCardinality cardinality] +[#if cardinality = "SINGLE_VALUED"]Single[#elseif cardinality = "MULTI_VALUED"]Multi[#else][/#if][/#macro] + +[#-- TODO: spec issue 37/38 --] +[#macro cmisUpdatability updatability] +[#if updatability = "READ_ONLY"]ro[#elseif updatability = "READ_AND_WRITE"]rw[#elseif updatability = "READ_AND_WRITE_WHEN_CHECKED_OUT"]checkedout[/#if][/#macro] + +[#-- TODO: spec issue 39 --] +[#macro cmisChoices choices] +[#if choices?exists] +[#list choices as choice] +${choice.value} +[@cmisChoices choice.children/] + +[/#list] +[/#if] +[/#macro] + [#-- Helper to render Alfresco content type to Atom content type --] [#macro contenttype type][#if type == "text/html"]text[#elseif type == "text/xhtml"]xhtml[#elseif type == "text/plain"]text<#else>${type}[/#if][/#macro] diff --git a/config/alfresco/templates/webscripts/org/alfresco/paging.lib.atom.ftl b/config/alfresco/templates/webscripts/org/alfresco/paging.lib.atom.ftl index e96f34c570..eb4b2eb5a8 100644 --- a/config/alfresco/templates/webscripts/org/alfresco/paging.lib.atom.ftl +++ b/config/alfresco/templates/webscripts/org/alfresco/paging.lib.atom.ftl @@ -1,29 +1,29 @@ -<#macro links cursor pageArg="pageNo" skipArg="skipCount"> +<#macro links cursor pageNo="pageNo" pageSize="pageSize" skipCount="skipCount" maxItems="maxItems"> <#if cursor.pageType = "PAGE"> <#if cursor.hasFirstPage> - + <#if cursor.hasLastPage> - + <#if cursor.hasPrevPage> - + <#if cursor.hasNextPage> - + <#else> <#if cursor.hasFirstPage> - + <#if cursor.hasLastPage> - + <#if cursor.hasPrevPage> - + <#if cursor.hasNextPage> - + diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/repository.get.atom.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/repository.get.atom.ftl index 6a03f60954..790562811f 100644 --- a/config/alfresco/templates/webscripts/org/alfresco/repository/repository.get.atom.ftl +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/repository.get.atom.ftl @@ -4,8 +4,6 @@ ${server.name} - <#-- TODO: cmis version --> - ${server.id} ${server.name} @@ -35,10 +33,8 @@ unfiled collection - - <#-- TODO: collection resources --> - - CMIS Types + + type collection diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/store/checkedout.get.atomfeed.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/store/checkedout.get.atomfeed.ftl index 0925648634..e8dc4a612b 100644 --- a/config/alfresco/templates/webscripts/org/alfresco/repository/store/checkedout.get.atomfeed.ftl +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/store/checkedout.get.atomfeed.ftl @@ -8,7 +8,7 @@ -[@feedLib.generic id="urn:uuid:checkedout" title="Checked out Documents" author="${person.properties.userName}"] +[@feedLib.generic "urn:uuid:checkedout" "Checked out Documents" "${person.properties.userName}"] [@pagingLib.links cursor=cursor/] [/@feedLib.generic] diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/store/checkedout.get.js b/config/alfresco/templates/webscripts/org/alfresco/repository/store/checkedout.get.js index 0e2370c893..71aa2b6965 100644 --- a/config/alfresco/templates/webscripts/org/alfresco/repository/store/checkedout.get.js +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/store/checkedout.get.js @@ -29,7 +29,7 @@ script: // TODO: includeAllowableActions // retrieve checked-out - var page = paging.createPageOrWindow(args.pageNo, args.pageSize, cmis.findArg(args.skipCount, headers["CMIS-skipCount"]), cmis.findArg(args.maxItems, headers["CMIS-maxItems"])); + var page = paging.createPageOrWindow(args, headers); var paged = cmis.queryCheckedOut(person.properties.userName, model.folder, model.includeDescendants, page); model.results = paged.results; model.cursor = paged.cursor; diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/store/children.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/repository/store/children.get.desc.xml index 1e1abd1043..67808ac71e 100644 --- a/config/alfresco/templates/webscripts/org/alfresco/repository/store/children.get.desc.xml +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/store/children.get.desc.xml @@ -1,8 +1,8 @@ Retrieve list of children Retrieve list of child folders and/or documents - /api/node/{store_type}/{store_id}/{id}/children?types={types}&filter={filter?}&skipCount={skipCount?}&maxChildren={maxChildren?} - /api/path/{store_type}/{store_id}/{id}/children?types={types}&filter={filter?}&skipCount={skipCount?}&maxChildren={maxChildren?} + /api/node/{store_type}/{store_id}/{id}/children?types={types}&filter={filter?}&skipCount={skipCount?}&maxItems={maxItems?} + /api/path/{store_type}/{store_id}/{id}/children?types={types}&filter={filter?}&skipCount={skipCount?}&maxItems={maxItems?} guest argument CMIS diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/store/children.get.js b/config/alfresco/templates/webscripts/org/alfresco/repository/store/children.get.js index 83894485ae..c1e38fa576 100644 --- a/config/alfresco/templates/webscripts/org/alfresco/repository/store/children.get.js +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/store/children.get.js @@ -24,7 +24,7 @@ script: // TODO: property filters // retrieve children - var page = paging.createPageOrWindow(args.pageNo, args.pageSize, cmis.findArg(args.skipCount, headers["CMIS-skipCount"]), cmis.findArg(args.maxItems, headers["CMIS-maxItems"])); + var page = paging.createPageOrWindow(args, headers); var paged = cmis.queryChildren(model.node, model.types, page); model.results = paged.results; model.cursor = paged.cursor; diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/store/type.get.atomentry.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/store/type.get.atomentry.ftl new file mode 100644 index 0000000000..1bf6c73615 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/store/type.get.atomentry.ftl @@ -0,0 +1,11 @@ +[#ftl] +[#import "/org/alfresco/cmis/ns.lib.atom.ftl" as nsLib/] +[#import "/org/alfresco/cmis/atomentry.lib.atom.ftl" as entryLib/] +[#compress] + + + + [@entryLib.typedef typedef true includeInheritedProperties/] + + +[/#compress] diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/store/type.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/repository/store/type.get.desc.xml new file mode 100644 index 0000000000..15b367cced --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/store/type.get.desc.xml @@ -0,0 +1,8 @@ + + Retrieve a Type + Retrieve a Type Definition + /api/type/{typeId}?includeInheritedProperties={includeInheritedProperties?} + user + + CMIS + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/store/type.get.js b/config/alfresco/templates/webscripts/org/alfresco/repository/store/type.get.js new file mode 100644 index 0000000000..d5bf5b5de0 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/store/type.get.js @@ -0,0 +1,17 @@ +script: +{ + // query type + var typeId = url.templateArgs.typeId; + model.typedef = cmis.queryType(typeId); + if (model.typedef === null) + { + status.code = 404; + status.message = "Type " + typeId + " not found"; + status.redirect = true; + break script; + } + + // handle inherited properties + var includeInheritedProperties = cmis.findArg(args.includeInheritedProperties, headers["CMIS-includeInheritedProperties"]); + model.includeInheritedProperties = includeInheritedProperties == "false" ? false : true; +} diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/store/typechildren.get.atomfeed.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/store/typechildren.get.atomfeed.ftl new file mode 100644 index 0000000000..6f3decc280 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/store/typechildren.get.atomfeed.ftl @@ -0,0 +1,26 @@ +[#ftl] +[#import "/org/alfresco/cmis/ns.lib.atom.ftl" as nsLib/] +[#import "/org/alfresco/cmis/atomfeed.lib.atom.ftl" as feedLib/] +[#import "/org/alfresco/cmis/atomentry.lib.atom.ftl" as entryLib/] +[#import "/org/alfresco/paging.lib.atom.ftl" as pagingLib/] +[#compress] + + + + +[@feedLib.generic "urn:uuid:type-${typedef.objectTypeId}-children" "Child types of ${typedef.objectTypeId}" "${person.properties.userName}"] + [@pagingLib.links cursor=cursor/] +[/@feedLib.generic] + +[#list results as child] + + [@entryLib.typedef typedef=child includeProperties=returnPropertyDefinitions/] + +[/#list] + +[@feedLib.hasMore more=cursor/] +[@pagingLib.opensearch cursor=cursor/] + + + +[/#compress] diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/store/typechildren.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/repository/store/typechildren.get.desc.xml new file mode 100644 index 0000000000..50950eb17f --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/store/typechildren.get.desc.xml @@ -0,0 +1,8 @@ + + Retrieve list of child Types + Retrieve list of all child Types + /api/type/{typeId}/children?includePropertyDefinitions={includePropertyDefinitions?}&skipCount={skipCount?}&maxItems={maxItems?} + user + + CMIS + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/store/typechildren.get.js b/config/alfresco/templates/webscripts/org/alfresco/repository/store/typechildren.get.js new file mode 100644 index 0000000000..7246cf6209 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/store/typechildren.get.js @@ -0,0 +1,24 @@ +script: +{ + // query type + var typeId = url.templateArgs.typeId; + model.typedef = cmis.queryType(typeId); + if (model.typedef === null) + { + status.code = 404; + status.message = "Type " + typeId + " not found"; + status.redirect = true; + break script; + } + + // query type children + var page = paging.createPageOrWindow(args, headers); + var paged = cmis.queryTypeHierarchy(model.typedef, false, page); + model.results = paged.results; + model.cursor = paged.cursor; + + // handle property definitions + // TODO: spec issue 34 + var returnPropertyDefinitions = cmis.findArg(args.includePropertyDefinitions, headers["CMIS-includePropertyDefinitions"]); + model.returnPropertyDefinitions = returnPropertyDefinitions == "true" ? true : false; +} diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/store/typedescendants.get.atomfeed.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/store/typedescendants.get.atomfeed.ftl new file mode 100644 index 0000000000..0745bfc1a7 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/store/typedescendants.get.atomfeed.ftl @@ -0,0 +1,26 @@ +[#ftl] +[#import "/org/alfresco/cmis/ns.lib.atom.ftl" as nsLib/] +[#import "/org/alfresco/cmis/atomfeed.lib.atom.ftl" as feedLib/] +[#import "/org/alfresco/cmis/atomentry.lib.atom.ftl" as entryLib/] +[#import "/org/alfresco/paging.lib.atom.ftl" as pagingLib/] +[#compress] + + + + +[@feedLib.generic "urn:uuid:type-${typedef.objectTypeId}-descendants" "Descendant types of ${typedef.objectTypeId}" "${person.properties.userName}"] + [@pagingLib.links cursor=cursor/] +[/@feedLib.generic] + +[#list results as child] + + [@entryLib.typedef typedef=child includeProperties=returnPropertyDefinitions/] + +[/#list] + +[@feedLib.hasMore more=cursor/] +[@pagingLib.opensearch cursor=cursor/] + + + +[/#compress] diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/store/typedescendants.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/repository/store/typedescendants.get.desc.xml new file mode 100644 index 0000000000..ea10576f49 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/store/typedescendants.get.desc.xml @@ -0,0 +1,8 @@ + + Retrieve list of descendant Types + Retrieve list of all descendant Types + /api/type/{typeId}/descendants?includePropertyDefinitions={includePropertyDefinitions?}&skipCount={skipCount?}&maxItems={maxItems?} + user + + CMIS + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/store/typedescendants.get.js b/config/alfresco/templates/webscripts/org/alfresco/repository/store/typedescendants.get.js new file mode 100644 index 0000000000..ecd3486a15 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/store/typedescendants.get.js @@ -0,0 +1,24 @@ +script: +{ + // query type + var typeId = url.templateArgs.typeId; + model.typedef = cmis.queryType(typeId); + if (model.typedef === null) + { + status.code = 404; + status.message = "Type " + typeId + " not found"; + status.redirect = true; + break script; + } + + // query type descendants + var page = paging.createPageOrWindow(args, headers); + var paged = cmis.queryTypeHierarchy(model.typedef, true, page); + model.results = paged.results; + model.cursor = paged.cursor; + + // handle property definitions + // TODO: spec issue 34 + var returnPropertyDefinitions = cmis.findArg(args.includePropertyDefinitions, headers["CMIS-includePropertyDefinitions"]); + model.returnPropertyDefinitions = returnPropertyDefinitions == "true" ? true : false; +} diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/store/types.get.atomfeed.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/store/types.get.atomfeed.ftl new file mode 100644 index 0000000000..79d05adde5 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/store/types.get.atomfeed.ftl @@ -0,0 +1,27 @@ +[#ftl] +[#import "/org/alfresco/cmis/ns.lib.atom.ftl" as nsLib/] +[#import "/org/alfresco/cmis/atomfeed.lib.atom.ftl" as feedLib/] +[#import "/org/alfresco/cmis/atomentry.lib.atom.ftl" as entryLib/] +[#import "/org/alfresco/paging.lib.atom.ftl" as pagingLib/] +[#compress] + + + + +[#assign title][#if type = "all"]All Types[#else]Type ${type}[/#if][/#assign] +[@feedLib.generic "urn:uuid:types-${type}" "${title}" "${person.properties.userName}"] + [@pagingLib.links cursor=cursor/] +[/@feedLib.generic] + +[#list results as child] +[#-- TODO: spec issue 40 --] + [@entryLib.typedef typedef=child includeProperties=returnPropertyDefinitions/] +[#-- TODO: spec issue 40 --] +[/#list] + +[@feedLib.hasMore more=cursor/] +[@pagingLib.opensearch cursor=cursor/] + + + +[/#compress] diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/store/types.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/repository/store/types.get.desc.xml new file mode 100644 index 0000000000..e7c92c5785 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/store/types.get.desc.xml @@ -0,0 +1,8 @@ + + Retrieve list of all Types + Retrieve list of all Types + /api/types?type={type?}&includePropertyDefinitions={includePropertyDefinitions?}&skipCount={skipCount?}&maxItems={maxItems?} + user + + CMIS + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/store/types.get.js b/config/alfresco/templates/webscripts/org/alfresco/repository/store/types.get.js new file mode 100644 index 0000000000..9c9bb80071 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/store/types.get.js @@ -0,0 +1,38 @@ +script: +{ + // process paging + var page = paging.createPageOrWindow(args, headers); + + // query types + // TODO: spec issue 34 + var typeId = cmis.findArg(args.type, headers["CMIS-type"]); + if (typeId === null) + { + // query all types + var paged = cmis.queryTypes(page); + model.results = paged.results; + model.cursor = paged.cursor; + model.type = "all"; + } + else + { + // query a specific type and its descendants + var typedef = cmis.queryType(typeId); + if (typedef === null) + { + status.code = 404; + status.message = "Type " + typeId + " not found"; + status.redirect = true; + break script; + } + var paged = cmis.queryTypeHierarchy(typedef, true, page); + model.results = paged.results; + model.cursor = paged.cursor; + model.type = typeId; + } + + // handle property definitions + // TODO: spec issue 34 + var returnPropertyDefinitions = cmis.findArg(args.includePropertyDefinitions, headers["CMIS-includePropertyDefinitions"]); + model.returnPropertyDefinitions = returnPropertyDefinitions == "true" ? true : false; +} diff --git a/config/alfresco/web-scripts-application-context.xml b/config/alfresco/web-scripts-application-context.xml index 1913bec0fa..9ab16ddb98 100644 --- a/config/alfresco/web-scripts-application-context.xml +++ b/config/alfresco/web-scripts-application-context.xml @@ -100,6 +100,15 @@ + + + + + + + + + @@ -395,6 +404,7 @@ + diff --git a/source/java/org/alfresco/repo/cmis/rest/CMISScript.java b/source/java/org/alfresco/repo/cmis/rest/CMISScript.java index a3c6f16589..87fe215273 100644 --- a/source/java/org/alfresco/repo/cmis/rest/CMISScript.java +++ b/source/java/org/alfresco/repo/cmis/rest/CMISScript.java @@ -24,8 +24,15 @@ */ package org.alfresco.repo.cmis.rest; +import java.util.Collection; +import java.util.Iterator; + import org.alfresco.cmis.CMISService; import org.alfresco.cmis.CMISService.TypesFilter; +import org.alfresco.cmis.dictionary.CMISDictionaryService; +import org.alfresco.cmis.dictionary.CMISTypeDefinition; +import org.alfresco.cmis.dictionary.CMISTypeId; +import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.repo.jscript.BaseScopableProcessorExtension; import org.alfresco.repo.jscript.ScriptNode; import org.alfresco.repo.model.Repository; @@ -49,6 +56,7 @@ public class CMISScript extends BaseScopableProcessorExtension private ServiceRegistry services; private Repository repository; private CMISService cmisService; + private CMISDictionaryService cmisDictionaryService; private Paging paging; @@ -83,7 +91,7 @@ public class CMISScript extends BaseScopableProcessorExtension } /** - * Set the CMIS Navigation helper + * Set the CMIS Service * * @param cmisService */ @@ -91,7 +99,17 @@ public class CMISScript extends BaseScopableProcessorExtension { this.cmisService = cmisService; } - + + /** + * Set the CMIS Dictionary Service + * + * @param cmisDictionaryService + */ + public void setCMISDictionaryService(CMISDictionaryService cmisDictionaryService) + { + this.cmisDictionaryService = cmisDictionaryService; + } + /** * Gets the supported CMIS Version * @@ -273,6 +291,83 @@ public class CMISScript extends BaseScopableProcessorExtension return results; } + /** + * Query for all Type Definitions + * + * @param page + * @return paged result set of types + */ + public PagedResults queryTypes(Page page) + { + Collection typeIds = cmisDictionaryService.getAllObjectTypeIds(); + Cursor cursor = paging.createCursor(typeIds.size(), page); + + // skip + Iterator iterTypeIds = typeIds.iterator(); + for (int i = 0; i < cursor.getStartRow(); i++) + { + iterTypeIds.next(); + } + + // get types for page + CMISTypeDefinition[] types = new CMISTypeDefinition[cursor.getRowCount()]; + for (int i = cursor.getStartRow(); i <= cursor.getEndRow(); i++) + { + types[i - cursor.getStartRow()] = cmisDictionaryService.getType(iterTypeIds.next()); + } + + PagedResults results = paging.createPagedResults(types, cursor); + 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 typeIds = cmisDictionaryService.getChildTypeIds(typedef.getObjectTypeId(), descendants); + Cursor cursor = paging.createCursor(typeIds.size(), page); + + // skip + Iterator iterTypeIds = typeIds.iterator(); + for (int i = 0; i < cursor.getStartRow(); i++) + { + iterTypeIds.next(); + } + + // get types for page + CMISTypeDefinition[] types = new CMISTypeDefinition[cursor.getRowCount()]; + for (int i = cursor.getStartRow(); i <= cursor.getEndRow(); i++) + { + types[i - cursor.getStartRow()] = cmisDictionaryService.getType(iterTypeIds.next()); + } + + PagedResults results = paging.createPagedResults(types, cursor); + return results; + } + + /** + * Query for all Type Definitions + * + * @param page + * @return paged result set of types + */ + public CMISTypeDefinition queryType(String typeId) + { + try + { + CMISTypeId cmisTypeId = cmisDictionaryService.getCMISMapping().getCmisTypeId(typeId); + return cmisDictionaryService.getType(cmisTypeId); + } + catch(AlfrescoRuntimeException e) + { + return null; + } + } + /** * Resolve to a Types Filter * diff --git a/source/java/org/alfresco/repo/cmis/rest/CMISTest.java b/source/java/org/alfresco/repo/cmis/rest/CMISTest.java index 6bdfcf1175..ce50fd641c 100644 --- a/source/java/org/alfresco/repo/cmis/rest/CMISTest.java +++ b/source/java/org/alfresco/repo/cmis/rest/CMISTest.java @@ -26,7 +26,9 @@ package org.alfresco.repo.cmis.rest; import java.io.StringReader; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; +import java.util.Set; import org.alfresco.util.GUID; import org.alfresco.web.scripts.Format; @@ -132,6 +134,15 @@ public class CMISTest extends BaseCMISWebScriptTest return rootHREF; } + private IRI getTypesCollection(Service service) + { + Collection root = service.getCollection("Main Repository", "type collection"); + assertNotNull(root); + IRI rootHREF = root.getHref(); + assertNotNull(rootHREF); + return rootHREF; + } + private Entry createFolder(IRI parent, String name) throws Exception { @@ -247,8 +258,7 @@ public class CMISTest extends BaseCMISWebScriptTest public void testRepository() throws Exception { - Service service = getRepository(); - IRI rootHREF = getRootCollection(service); + IRI rootHREF = getRootCollection(getRepository()); sendRequest(new GetRequest(rootHREF.toString()), 200, getAtomValidator()); } @@ -331,7 +341,7 @@ public class CMISTest extends BaseCMISWebScriptTest assertNotNull(documentRes); String documentXML = documentRes.getContentAsString(); assertNotNull(documentXML); - IRI checkedoutHREF = getCheckedOutCollection(service); + IRI checkedoutHREF = getCheckedOutCollection(getRepository()); Response pwcRes = sendRequest(new PostRequest(checkedoutHREF.toString(), documentXML, Format.ATOMENTRY.mimetype()), 201, getAtomValidator()); assertNotNull(pwcRes); Entry pwc = abdera.parseEntry(new StringReader(pwcRes.getContentAsString()), null); @@ -344,10 +354,49 @@ public class CMISTest extends BaseCMISWebScriptTest assertNotNull(children.getEntry(document2.getId().toString())); assertNotNull(children.getEntry(document3.getId().toString())); assertNull(children.getEntry(pwc.getId().toString())); - - // TODO: paging } - + + public void testChildrenPaging() + throws Exception + { + // create multiple children + Set docIds = new HashSet(); + Entry testFolder = createTestFolder("testChildrenPaging"); + Link childrenLink = testFolder.getLink(CMISConstants.REL_CHILDREN); + assertNotNull(childrenLink); + for (int i = 0; i < 15; i++) + { + Entry document = createDocument(childrenLink.getHref(), "testChildrenPaging" + i); + assertNotNull(document); + docIds.add(document.getId()); + } + assertEquals(15, docIds.size()); + + // get children, ensure they exist (but not private working copy) + int nextCount = 0; + Map args = new HashMap(); + args.put("maxItems", "4"); + IRI childrenHREF = childrenLink.getHref(); + while (childrenHREF != null) + { + nextCount++; + Feed types = getFeed(childrenHREF, args); + assertNotNull(types); + assertEquals(nextCount < 4 ? 4 : 3, types.getEntries().size()); + for (Entry entry : types.getEntries()) + { + docIds.remove(entry.getId()); + } + + // next page + Link nextLink = types.getLink("next"); + childrenHREF = (nextLink != null) ? nextLink.getHref() : null; + args = null; + }; + assertEquals(4, nextCount); + assertEquals(0, docIds.size()); + } + public void testGetParent() throws Exception { @@ -480,7 +529,7 @@ public class CMISTest extends BaseCMISWebScriptTest // retrieve checkouts within scope of test checkout folder Service repository = getRepository(); assertNotNull(repository); - IRI checkedoutHREF = getCheckedOutCollection(service); + IRI checkedoutHREF = getCheckedOutCollection(getRepository()); Map args = new HashMap(); args.put("folderId", scopeId); Feed checkedout = getFeed(new IRI(checkedoutHREF.toString()), args); @@ -503,7 +552,7 @@ public class CMISTest extends BaseCMISWebScriptTest assertNotNull(documentXML); // checkout - IRI checkedoutHREF = getCheckedOutCollection(service); + IRI checkedoutHREF = getCheckedOutCollection(getRepository()); Response pwcRes = sendRequest(new PostRequest(checkedoutHREF.toString(), documentXML, Format.ATOMENTRY.mimetype()), 201, getAtomValidator()); assertNotNull(pwcRes); // TODO: test private working copy properties @@ -533,7 +582,7 @@ public class CMISTest extends BaseCMISWebScriptTest assertNotNull(xml); // checkout - IRI checkedoutHREF = getCheckedOutCollection(service); + IRI checkedoutHREF = getCheckedOutCollection(getRepository()); Response pwcRes = sendRequest(new PostRequest(checkedoutHREF.toString(), xml, Format.ATOMENTRY.mimetype()), 201, getAtomValidator()); assertNotNull(pwcRes); String pwcXml = pwcRes.getContentAsString(); @@ -578,7 +627,7 @@ public class CMISTest extends BaseCMISWebScriptTest assertNotNull(xml); // checkout - IRI checkedoutHREF = getCheckedOutCollection(service); + IRI checkedoutHREF = getCheckedOutCollection(getRepository()); Response pwcRes = sendRequest(new PostRequest(checkedoutHREF.toString(), xml, Format.ATOMENTRY.mimetype()), 201, getAtomValidator()); assertNotNull(pwcRes); Entry pwc = abdera.parseEntry(new StringReader(pwcRes.getContentAsString()), null); @@ -651,7 +700,7 @@ public class CMISTest extends BaseCMISWebScriptTest assertNotNull(xml); // checkout - IRI checkedoutHREF = getCheckedOutCollection(service); + IRI checkedoutHREF = getCheckedOutCollection(getRepository()); Response pwcRes = sendRequest(new PostRequest(checkedoutHREF.toString(), xml, Format.ATOMENTRY.mimetype()), 201, getAtomValidator()); assertNotNull(pwcRes); Entry pwc = abdera.parseEntry(new StringReader(pwcRes.getContentAsString()), null); @@ -712,7 +761,7 @@ public class CMISTest extends BaseCMISWebScriptTest String xml = documentRes.getContentAsString(); assertNotNull(xml); - IRI checkedoutHREF = getCheckedOutCollection(service); + IRI checkedoutHREF = getCheckedOutCollection(getRepository()); for (int i = 0; i < NUMBER_OF_VERSIONS; i++) { // checkout @@ -751,7 +800,52 @@ public class CMISTest extends BaseCMISWebScriptTest } } - + public void testGetAllTypeDefinitions() + throws Exception + { + IRI typesHREF = getTypesCollection(getRepository()); + Feed types = getFeed(typesHREF); + assertNotNull(types); + Feed typesWithProps = getFeed(typesHREF); + assertNotNull(typesWithProps); + // TODO: spec issue 40 + for (Entry type : types.getEntries()) + { + Entry retrievedType = getEntry(type.getSelfLink().getHref()); + assertEquals(type.getId(), retrievedType.getId()); + assertEquals(type.getTitle(), retrievedType.getTitle()); + // TODO: type specific properties - extension to Abdera + } + } + + public void testGetHierarchyTypeDefinitions() + throws Exception + { + IRI typesHREF = getTypesCollection(getRepository()); + Map args = new HashMap(); + args.put("type", "FOLDER_OBJECT_TYPE"); + args.put("includePropertyDefinitions", "true"); + args.put("maxItems", "5"); + while (typesHREF != null) + { + Feed types = getFeed(typesHREF, args); + + // TODO: spec issue 40 + for (Entry type : types.getEntries()) + { + Entry retrievedType = getEntry(type.getSelfLink().getHref()); + assertEquals(type.getId(), retrievedType.getId()); + assertEquals(type.getTitle(), retrievedType.getTitle()); + // TODO: type specific properties - extension to Abdera + } + + // next page + Link nextLink = types.getLink("next"); + typesHREF = (nextLink != null) ? nextLink.getHref() : null; + args.remove("maxItems"); + }; + } + // public void testUnfiled() // { // } diff --git a/source/java/org/alfresco/repo/cmis/rest/CMISTypeIdMethod.java b/source/java/org/alfresco/repo/cmis/rest/CMISTypeIdMethod.java new file mode 100644 index 0000000000..3f2df04d8d --- /dev/null +++ b/source/java/org/alfresco/repo/cmis/rest/CMISTypeIdMethod.java @@ -0,0 +1,98 @@ +/* + * 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.cmis.rest; + +import java.util.List; + +import org.alfresco.cmis.dictionary.CMISMapping; +import org.alfresco.cmis.dictionary.CMISTypeId; +import org.alfresco.repo.jscript.ScriptNode; +import org.alfresco.repo.template.TemplateNode; +import org.alfresco.service.namespace.QName; + +import freemarker.ext.beans.BeanModel; +import freemarker.template.TemplateMethodModelEx; +import freemarker.template.TemplateModelException; + +/** + * Custom FreeMarker Template language method. + *

+ * Retrieve the CMIS Type Id for an Alfresco node + *

+ * Usage: cmisTypeId(ScriptNode node) + * cmisTypeId(QName nodeType) + * + * @author davidc + */ +public final class CMISTypeIdMethod implements TemplateMethodModelEx +{ + private CMISMapping mappingService; + + /** + * Construct + */ + public CMISTypeIdMethod(CMISMapping mappingService) + { + this.mappingService = mappingService; + } + + /** + * @see freemarker.template.TemplateMethodModel#exec(java.util.List) + */ + public Object exec(List args) throws TemplateModelException + { + CMISTypeId result = null; + + if (args.size() == 1) + { + Object arg0 = args.get(0); + if (arg0 instanceof BeanModel) + { + // extract node type qname + QName nodeType = null; + Object wrapped = ((BeanModel)arg0).getWrappedObject(); + if (wrapped != null) + { + if (wrapped instanceof TemplateNode) + { + nodeType = ((TemplateNode)wrapped).getType(); + } + else if (wrapped instanceof QName) + { + nodeType = (QName)wrapped; + } + } + + // convert to CMIS type id + if (nodeType != null) + { + result = mappingService.getCmisTypeId(nodeType); + } + } + } + + return result; + } +} diff --git a/source/java/org/alfresco/repo/web/scripts/RepositoryContainer.java b/source/java/org/alfresco/repo/web/scripts/RepositoryContainer.java index 5639dce413..f8ef4c63cf 100644 --- a/source/java/org/alfresco/repo/web/scripts/RepositoryContainer.java +++ b/source/java/org/alfresco/repo/web/scripts/RepositoryContainer.java @@ -180,7 +180,6 @@ public class RepositoryContainer extends AbstractRuntimeContainer implements Ten Map params = new HashMap(); params.putAll(super.getTemplateParameters()); params.put(TemplateService.KEY_IMAGE_RESOLVER, imageResolver.getImageResolver()); - params.put("cropContent", new CropContentMethod()); addRepoParameters(params); return params; } diff --git a/source/java/org/alfresco/repo/web/scripts/TestWebScriptRepoServer.java b/source/java/org/alfresco/repo/web/scripts/TestWebScriptRepoServer.java index 9a64634fba..8155e1e2eb 100644 --- a/source/java/org/alfresco/repo/web/scripts/TestWebScriptRepoServer.java +++ b/source/java/org/alfresco/repo/web/scripts/TestWebScriptRepoServer.java @@ -156,5 +156,5 @@ public class TestWebScriptRepoServer extends TestWebScriptServer } }, username); } - + } diff --git a/source/java/org/alfresco/repo/web/util/paging/Paging.java b/source/java/org/alfresco/repo/web/util/paging/Paging.java index bc4f3255ab..fa29066ba9 100644 --- a/source/java/org/alfresco/repo/web/util/paging/Paging.java +++ b/source/java/org/alfresco/repo/web/util/paging/Paging.java @@ -24,6 +24,8 @@ */ package org.alfresco.repo.web.util.paging; +import java.util.Map; + /** * Paging. A utility for maintaining paged indexes for a collection of N items. * @@ -134,6 +136,90 @@ public class Paging { return zeroBasedRow; } + + /** + * Create a Page or Window from standardised request arguments / headers + * + * For Paged based index (take precedence over window based index, if both are specified): + * + * - request args + * pageNo => page number index + * pageSize => size of page + * + * For Window based index (as defined by CMIS): + * + * - request args (take precedence over header values if both are specified) + * skipCount => row number start index + * maxItems => size of page + * + * - header values + * CMIS-skipCount => row number start index + * CMIS-maxItems => size of page + * + * @param args request args + * @param headers request headers + * @return page (if pageNumber driven) or window (if skipCount driven) + */ + public Page createPageOrWindow(Map args, Map headers) + { + // page number + String strPageNo = args.get("pageNo"); + Integer pageNo = null; + if (strPageNo != null) + { + try + { + pageNo = new Integer(strPageNo); + } + catch(NumberFormatException e) {}; + } + + // page size + String strPageSize = args.get("pageSize"); + Integer pageSize = null; + if (strPageSize != null) + { + try + { + pageSize = new Integer(strPageSize); + } + catch(NumberFormatException e) {}; + } + + // skip count + String strSkipCount = args.get("skipCount"); + if (strSkipCount == null) + { + strSkipCount = (headers == null) ? null : headers.get("CMIS-skipCount"); + } + Integer skipCount = null; + if (strSkipCount != null) + { + try + { + skipCount = new Integer(strSkipCount); + } + catch(NumberFormatException e) {}; + } + + // max items + String strMaxItems = args.get("maxItems"); + if (strMaxItems == null) + { + strMaxItems = (headers == null) ? null : headers.get("CMIS-maxItems"); + } + Integer maxItems = null; + if (strMaxItems != null) + { + try + { + maxItems = new Integer(strMaxItems); + } + catch(NumberFormatException e) {}; + } + + return createPageOrWindow(pageNo, pageSize, skipCount, maxItems); + } /** * Create a Page or Window @@ -146,13 +232,13 @@ public class Paging */ public Page createPageOrWindow(Integer pageNumber, Integer pageSize, Integer skipCount, Integer maxItems) { - if (pageNumber != null) + if (pageNumber != null || pageSize != null) { - return createPage(pageNumber, pageSize == null ? 0 : pageSize); + return createPage(pageNumber == null ? isZeroBasedPage() ? 0 : 1 : pageNumber, pageSize == null ? 0 : pageSize); } - else if (skipCount != null) + else if (skipCount != null || maxItems != null) { - return createWindow(skipCount, maxItems == null ? 0 : maxItems); + return createWindow(skipCount == null ? isZeroBasedRow() ? 0 : 1 : skipCount, maxItems == null ? 0 : maxItems); } return createUnlimitedPage(); }