/* * (C) Copyright 2006-2011 Nuxeo SA (http://nuxeo.com/) and others. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Contributors: */ package org.nuxeo.ecm.core.opencmis.impl.server; import java.util.HashMap; import java.util.Map; import org.apache.chemistry.opencmis.commons.PropertyIds; import org.apache.chemistry.opencmis.commons.definitions.PropertyDefinition; import org.apache.chemistry.opencmis.commons.definitions.TypeDefinition; import org.apache.chemistry.opencmis.commons.enums.BaseTypeId; import org.apache.chemistry.opencmis.commons.enums.Cardinality; import org.apache.chemistry.opencmis.commons.enums.CmisVersion; import org.apache.chemistry.opencmis.commons.enums.ContentStreamAllowed; import org.apache.chemistry.opencmis.commons.enums.PropertyType; import org.apache.chemistry.opencmis.commons.enums.Updatability; import org.apache.chemistry.opencmis.commons.impl.dataobjects.AbstractPropertyDefinition; import org.apache.chemistry.opencmis.commons.impl.dataobjects.AbstractTypeDefinition; import org.apache.chemistry.opencmis.commons.impl.dataobjects.DocumentTypeDefinitionImpl; import org.apache.chemistry.opencmis.commons.impl.dataobjects.FolderTypeDefinitionImpl; import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyBooleanDefinitionImpl; import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyDateTimeDefinitionImpl; import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyDecimalDefinitionImpl; import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyHtmlDefinitionImpl; import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyIdDefinitionImpl; import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyIntegerDefinitionImpl; import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyStringDefinitionImpl; import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyUriDefinitionImpl; import org.apache.chemistry.opencmis.commons.impl.dataobjects.RelationshipTypeDefinitionImpl; import org.apache.chemistry.opencmis.commons.impl.dataobjects.SecondaryTypeDefinitionImpl; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.nuxeo.common.utils.Path; import org.nuxeo.ecm.core.api.DocumentModel; import org.nuxeo.ecm.core.api.blobholder.BlobHolder; import org.nuxeo.ecm.core.api.impl.DocumentModelImpl; import org.nuxeo.ecm.core.schema.DocumentType; import org.nuxeo.ecm.core.schema.FacetNames; import org.nuxeo.ecm.core.schema.Namespace; import org.nuxeo.ecm.core.schema.SchemaManager; import org.nuxeo.ecm.core.schema.types.CompositeType; import org.nuxeo.ecm.core.schema.types.Field; import org.nuxeo.ecm.core.schema.types.ListType; import org.nuxeo.ecm.core.schema.types.Schema; import org.nuxeo.ecm.core.schema.types.SimpleType; import org.nuxeo.ecm.core.schema.types.Type; import org.nuxeo.ecm.core.schema.types.primitives.BooleanType; import org.nuxeo.ecm.core.schema.types.primitives.DateType; import org.nuxeo.ecm.core.schema.types.primitives.DoubleType; import org.nuxeo.ecm.core.schema.types.primitives.LongType; import org.nuxeo.ecm.core.schema.types.primitives.StringType; import org.nuxeo.runtime.api.Framework; /** * Nuxeo Type Utilities. * <p> * Maps Nuxeo types to CMIS types using the following rules: * <ul> * <li>Only types containing dublincore are exposed,</li> * <li>cmis:document and cmis:folder expose dublincore, and are not creatable,</li> * <li>The Document type is not exposed,</li> * <li>Types inheriting from Document are exposed as inheriting cmis:document,</li> * <li>The Folder type is mapped to a concrete subtype of cmis:folder,</li> * <li>Other folderish types directly under Folder are mapped to subtypes of cmis:folder as well.</li> * </ul> */ public class NuxeoTypeHelper { private static final Log log = LogFactory.getLog(NuxeoTypeHelper.class); public static final String NUXEO_DOCUMENT = "Document"; public static final String NUXEO_FOLDER = "Folder"; public static final String NUXEO_RELATION = "Relation"; public static final String NUXEO_RELATION_DEFAULT = "DefaultRelation"; public static final String NUXEO_FILE = "File"; public static final String NUXEO_ORDERED_FOLDER = "OrderedFolder"; public static final String FACET_TYPE_PREFIX = "facet:"; public static final String NX_DUBLINCORE = "dublincore"; public static final String NX_DC_TITLE = "dc:title"; public static final String NX_DC_DESCRIPTION = "dc:description"; public static final String NX_DC_CREATED = "dc:created"; public static final String NX_DC_CREATOR = "dc:creator"; public static final String NX_DC_MODIFIED = "dc:modified"; public static final String NX_DC_LAST_CONTRIBUTOR = "dc:lastContributor"; public static final String NX_ICON = "common:icon"; public static final String NX_REL_SOURCE = "relation:source"; public static final String NX_REL_TARGET = "relation:target"; public static final String NX_DIGEST = "nuxeo:contentStreamDigest"; public static final String NX_ISVERSION = "nuxeo:isVersion"; public static final String NX_ISCHECKEDIN = "nuxeo:isCheckedIn"; public static final String NX_FACETS = "nuxeo:secondaryObjectTypeIds"; public static final String NX_LIFECYCLE_STATE = "nuxeo:lifecycleState"; public static final String NX_PARENT_ID = "nuxeo:parentId"; public static final String NX_PATH_SEGMENT = "nuxeo:pathSegment"; public static final String ENABLE_COMPLEX_PROPERTIES = "org.nuxeo.cmis.enableComplexProperties"; /** @since 6.0 */ public static final String NX_POS = "nuxeo:pos"; private static final String NAMESPACE = "http://ns.nuxeo.org/cmis/type/"; private static final String NAMESPACE_FACET = "http://ns.nuxeo.org/cmis/facet/"; protected static boolean isComplexPropertiesEnabled() { return !Framework.isBooleanPropertyFalse(ENABLE_COMPLEX_PROPERTIES); } protected AbstractTypeDefinition t; // used to track down and log duplicates protected Map<String, String> propertyToSchema; protected CmisVersion cmisVersion; /** * Helper to construct one CMIS type from a {@link DocumentType}. */ protected NuxeoTypeHelper(String id, String parentId, BaseTypeId baseTypeId, DocumentType documentType, String nuxeoTypeId, boolean creatable, CmisVersion cmisVersion) { propertyToSchema = new HashMap<String, String>(); this.cmisVersion = cmisVersion; constructBaseDocumentType(id, parentId, baseTypeId, documentType, nuxeoTypeId, creatable); } /** * Helper to construct one CMIS type from a secondary type. */ protected NuxeoTypeHelper(String id, String nuxeoTypeId, CmisVersion cmisVersion) { propertyToSchema = new HashMap<String, String>(); this.cmisVersion = cmisVersion; constructBaseSecondaryType(id, nuxeoTypeId); } /** * Gets the remapped parent type id, or {@code null} if the type is to be ignored. */ public static String getParentTypeId(DocumentType documentType) { if (!documentType.hasSchema(NX_DUBLINCORE)) { // ignore type without dublincore return null; } if (documentType.getFacets().contains(FacetNames.HIDDEN_IN_NAVIGATION)) { // ignore hiddeninnavigation type except if it's a relation if (getBaseTypeId(documentType) != BaseTypeId.CMIS_RELATIONSHIP) { return null; } } String nuxeoTypeId = documentType.getName(); // NUXEO_DOCUMENT already excluded be previous checks if (NUXEO_FOLDER.equals(nuxeoTypeId)) { // Folder has artificial parent cmis:folder return BaseTypeId.CMIS_FOLDER.value(); } if (NUXEO_RELATION.equals(nuxeoTypeId)) { // Relation has artificial parent cmis:relationship return BaseTypeId.CMIS_RELATIONSHIP.value(); } DocumentType superType = (DocumentType) documentType.getSuperType(); if (superType == null) { return null; } String parentId = mappedId(superType.getName()); if (NUXEO_FOLDER.equals(parentId)) { // reparent Folder child under cmis:folder parentId = BaseTypeId.CMIS_FOLDER.value(); } if (NUXEO_RELATION.equals(parentId)) { // reparent Relation child under cmis:relationship parentId = BaseTypeId.CMIS_RELATIONSHIP.value(); } if (NUXEO_DOCUMENT.equals(parentId)) { // reparent Document child under cmis:document parentId = BaseTypeId.CMIS_DOCUMENT.value(); } return parentId; } public static TypeDefinition constructDocumentType(DocumentType documentType, String parentId, CmisVersion cmisVersion) { String nuxeoTypeId = documentType.getName(); String id = mappedId(nuxeoTypeId); NuxeoTypeHelper h = new NuxeoTypeHelper(id, parentId, getBaseTypeId(documentType), documentType, nuxeoTypeId, true, cmisVersion); // Nuxeo Property Definitions for (Schema schema : documentType.getSchemas()) { h.addSchemaPropertyDefinitions(schema); } return h.t; } public static TypeDefinition constructSecondaryType(CompositeType type, CmisVersion cmisVersion) { String nuxeoTypeId = type.getName(); String id = FACET_TYPE_PREFIX + nuxeoTypeId; NuxeoTypeHelper h = new NuxeoTypeHelper(id, nuxeoTypeId, cmisVersion); // Nuxeo Property Definitions for (Schema schema : type.getSchemas()) { h.addSchemaPropertyDefinitions(schema); } return h.t; } /** * Constructs a base type, not mapped to a Nuxeo type. If not a secondary, it has the dublincore schema. */ public static TypeDefinition constructCmisBase(BaseTypeId baseTypeId, SchemaManager schemaManager, CmisVersion cmisVersion) { NuxeoTypeHelper h; if (baseTypeId != BaseTypeId.CMIS_SECONDARY) { h = new NuxeoTypeHelper(baseTypeId.value(), null, baseTypeId, null, null, true, cmisVersion); DocumentType dt = schemaManager.getDocumentType(NUXEO_FOLDER); // has dc h.addSchemaPropertyDefinitions(dt.getSchema(NX_DUBLINCORE)); } else { h = new NuxeoTypeHelper(baseTypeId.value(), null, cmisVersion); } return h.t; } protected void addSchemaPropertyDefinitions(Schema schema) { for (Field field : schema.getFields()) { PropertyType propertyType; Cardinality cardinality; Type fieldType = field.getType(); String schemaName = schema.getName(); boolean queryable; boolean orderable; if (fieldType.isComplexType()) { if (isComplexPropertiesEnabled()) { // content is specifically excluded from the properties if ("content".equals(fieldType.getName())) { log.debug("Ignoring complex type: " + schemaName + '/' + field.getName() + " in type: " + t.getId()); continue; } // complex types get exposed to CMIS as a single string value; // the NuxeoPropertyData class will marshal/unmarshal them as JSON. cardinality = Cardinality.SINGLE; propertyType = PropertyType.STRING; queryable = false; orderable = false; } else { log.debug("Ignoring complex type: " + schemaName + '/' + field.getName() + " in type: " + t.getId()); continue; } } else { if (fieldType.isListType()) { Type listFieldType = ((ListType) fieldType).getFieldType(); if (!listFieldType.isSimpleType()) { if (isComplexPropertiesEnabled()) { // complex lists get exposed to CMIS as a list of string values; // the NuxeoPropertyData class will marshal/unmarshal them as JSON. cardinality = Cardinality.MULTI; propertyType = PropertyType.STRING; queryable = false; orderable = false; } else { log.debug("Ignoring complex type: " + schemaName + '/' + field.getName() + "in type: " + t.getId()); continue; } } else { // array: use a collection table cardinality = Cardinality.MULTI; propertyType = getPropertType((SimpleType) listFieldType); queryable = false; orderable = false; } } else { // primitive type cardinality = Cardinality.SINGLE; propertyType = getPropertType((SimpleType) fieldType); queryable = true; orderable = true; } } String name = field.getName().getPrefixedName(); PropertyDefinition<?> pd = newPropertyDefinition(name, name, propertyType, cardinality, Updatability.READWRITE, false, false, queryable, orderable); if (t.getPropertyDefinitions().containsKey(pd.getId())) { log.error("Type '" + t.getId() + "' has duplicate property '" + name + "' in schemas '" + propertyToSchema.get(pd.getId()) + "' and '" + schemaName + "', ignoring the one in '" + schemaName + "'"); continue; } propertyToSchema.put(pd.getId(), schemaName); t.addPropertyDefinition(pd); } } /** * Constructs the base for a {@link DocumentType}. */ protected void constructBaseDocumentType(String id, String parentId, BaseTypeId baseTypeId, DocumentType documentType, String nuxeoTypeId, boolean creatable) { if (baseTypeId == BaseTypeId.CMIS_FOLDER) { t = new FolderTypeDefinitionImpl(); } else if (baseTypeId == BaseTypeId.CMIS_RELATIONSHIP) { t = new RelationshipTypeDefinitionImpl(); } else { t = new DocumentTypeDefinitionImpl(); } t.setBaseTypeId(baseTypeId); t.setId(id); t.setParentTypeId(parentId); t.setDescription(id); t.setDisplayName(id); t.setLocalName(nuxeoTypeId == null ? id : nuxeoTypeId); Namespace ns = documentType == null ? null : documentType.getNamespace(); t.setLocalNamespace(ns == null ? NAMESPACE : ns.uri); t.setQueryName(id); t.setIsCreatable(Boolean.valueOf(creatable)); t.setIsQueryable(Boolean.TRUE); t.setIsIncludedInSupertypeQuery(Boolean.TRUE); t.setIsFulltextIndexed(Boolean.TRUE); t.setIsControllableAcl(Boolean.TRUE); t.setIsControllablePolicy(Boolean.FALSE); addBasePropertyDefinitions(); if (t instanceof FolderTypeDefinitionImpl) { t.setIsFileable(Boolean.TRUE); FolderTypeDefinitionImpl ft = (FolderTypeDefinitionImpl) t; addFolderPropertyDefinitions(ft); } else if (t instanceof RelationshipTypeDefinitionImpl) { RelationshipTypeDefinitionImpl rt = (RelationshipTypeDefinitionImpl) t; rt.setAllowedSourceTypes(null); rt.setAllowedTargetTypes(null); addRelationshipPropertyDefinitions(rt); t.setIsFileable(Boolean.FALSE); } else { DocumentTypeDefinitionImpl dt = (DocumentTypeDefinitionImpl) t; boolean versionable = documentType == null ? false : documentType.getFacets().contains( FacetNames.VERSIONABLE); dt.setIsVersionable(Boolean.valueOf(versionable)); t.setIsFileable(Boolean.TRUE); ContentStreamAllowed csa = (documentType != null && supportsBlobHolder(documentType)) ? ContentStreamAllowed.ALLOWED : ContentStreamAllowed.NOTALLOWED; dt.setContentStreamAllowed(csa); addDocumentPropertyDefinitions(dt); } } /** * Constructs the base for a secondary type. */ protected void constructBaseSecondaryType(String id, String nuxeoTypeId) { t = new SecondaryTypeDefinitionImpl(); t.setBaseTypeId(BaseTypeId.CMIS_SECONDARY); t.setId(id); t.setParentTypeId(nuxeoTypeId == null ? null : BaseTypeId.CMIS_SECONDARY.value()); t.setDescription(id); t.setDisplayName(id); t.setLocalName(nuxeoTypeId == null ? id : nuxeoTypeId); t.setLocalNamespace(NAMESPACE_FACET); t.setQueryName(id); t.setIsCreatable(Boolean.FALSE); t.setIsQueryable(Boolean.TRUE); t.setIsIncludedInSupertypeQuery(Boolean.TRUE); t.setIsFulltextIndexed(Boolean.TRUE); t.setIsControllableAcl(Boolean.FALSE); t.setIsControllablePolicy(Boolean.FALSE); t.setIsFileable(Boolean.FALSE); } protected void addBasePropertyDefinitions() { t.addPropertyDefinition(newPropertyDefinition(PropertyIds.OBJECT_ID, "Object ID", PropertyType.ID, Cardinality.SINGLE, Updatability.READONLY, false, false, true, true)); t.addPropertyDefinition(newPropertyDefinition(PropertyIds.OBJECT_TYPE_ID, "Type ID", PropertyType.ID, Cardinality.SINGLE, Updatability.ONCREATE, false, true, false, false)); t.addPropertyDefinition(newPropertyDefinition(PropertyIds.BASE_TYPE_ID, "Base Type ID", PropertyType.ID, Cardinality.SINGLE, Updatability.READONLY, false, false, false, false)); if (cmisVersion != CmisVersion.CMIS_1_0) { t.addPropertyDefinition(newPropertyDefinition(PropertyIds.SECONDARY_OBJECT_TYPE_IDS, "Secondary Type IDs", PropertyType.ID, Cardinality.MULTI, Updatability.READONLY, false, false, false, false)); } t.addPropertyDefinition(newPropertyDefinition(PropertyIds.NAME, "Name", PropertyType.STRING, Cardinality.SINGLE, Updatability.READWRITE, false, true, true, true)); if (cmisVersion != CmisVersion.CMIS_1_0) { t.addPropertyDefinition(newPropertyDefinition(PropertyIds.DESCRIPTION, "Description", PropertyType.STRING, Cardinality.SINGLE, Updatability.READWRITE, false, false, true, true)); } t.addPropertyDefinition(newPropertyDefinition(PropertyIds.CREATED_BY, "Created By", PropertyType.STRING, Cardinality.SINGLE, Updatability.READONLY, false, false, true, true)); t.addPropertyDefinition(newPropertyDefinition(PropertyIds.CREATION_DATE, "Creation Date", PropertyType.DATETIME, Cardinality.SINGLE, Updatability.READONLY, false, false, true, true)); t.addPropertyDefinition(newPropertyDefinition(PropertyIds.LAST_MODIFIED_BY, "Last Modified By", PropertyType.STRING, Cardinality.SINGLE, Updatability.READONLY, false, false, true, true)); t.addPropertyDefinition(newPropertyDefinition(PropertyIds.LAST_MODIFICATION_DATE, "Last Modification Date", PropertyType.DATETIME, Cardinality.SINGLE, Updatability.READONLY, false, false, true, true)); t.addPropertyDefinition(newPropertyDefinition(PropertyIds.CHANGE_TOKEN, "Change Token", PropertyType.STRING, Cardinality.SINGLE, Updatability.READONLY, false, false, false, false)); // Nuxeo system properties t.addPropertyDefinition(newPropertyDefinition(NX_LIFECYCLE_STATE, "Lifecycle State", PropertyType.STRING, Cardinality.SINGLE, Updatability.READONLY, false, false, true, true)); t.addPropertyDefinition(newPropertyDefinition(NX_FACETS, "Facets", PropertyType.ID, Cardinality.MULTI, Updatability.READONLY, false, false, true, false)); t.addPropertyDefinition(newPropertyDefinition(NX_PARENT_ID, "Nuxeo Parent ID", PropertyType.ID, Cardinality.SINGLE, Updatability.READONLY, false, false, true, true)); t.addPropertyDefinition(newPropertyDefinition(NX_PATH_SEGMENT, "Path Segment", PropertyType.STRING, Cardinality.SINGLE, Updatability.READONLY, false, false, true, true)); t.addPropertyDefinition(newPropertyDefinition(NX_POS, "Position", PropertyType.INTEGER, Cardinality.SINGLE, Updatability.READONLY, false, false, true, true)); } protected static void addFolderPropertyDefinitions(FolderTypeDefinitionImpl t) { t.addPropertyDefinition(newPropertyDefinition(PropertyIds.PARENT_ID, "Parent ID", PropertyType.ID, Cardinality.SINGLE, Updatability.READONLY, false, false, true, true)); t.addPropertyDefinition(newPropertyDefinition(PropertyIds.PATH, "Path", PropertyType.STRING, Cardinality.SINGLE, Updatability.READONLY, false, false, false, false)); t.addPropertyDefinition(newPropertyDefinition(PropertyIds.ALLOWED_CHILD_OBJECT_TYPE_IDS, "Allowed Child Object Type IDs", PropertyType.ID, Cardinality.MULTI, Updatability.READONLY, false, false, false, false)); } protected static void addRelationshipPropertyDefinitions(RelationshipTypeDefinitionImpl t) { t.addPropertyDefinition(newPropertyDefinition(PropertyIds.SOURCE_ID, "Source ID", PropertyType.ID, Cardinality.SINGLE, Updatability.READWRITE, false, true, true, true)); t.addPropertyDefinition(newPropertyDefinition(PropertyIds.TARGET_ID, "Target ID", PropertyType.ID, Cardinality.SINGLE, Updatability.READWRITE, false, true, true, true)); } protected void addDocumentPropertyDefinitions(DocumentTypeDefinitionImpl t) { t.addPropertyDefinition(newPropertyDefinition(PropertyIds.IS_IMMUTABLE, "Is Immutable", PropertyType.BOOLEAN, Cardinality.SINGLE, Updatability.READONLY, false, false, false, false)); t.addPropertyDefinition(newPropertyDefinition(PropertyIds.IS_LATEST_VERSION, "Is Latest Version", PropertyType.BOOLEAN, Cardinality.SINGLE, Updatability.READONLY, false, false, true, true)); t.addPropertyDefinition(newPropertyDefinition(PropertyIds.IS_MAJOR_VERSION, "Is Major Version", PropertyType.BOOLEAN, Cardinality.SINGLE, Updatability.READONLY, false, false, false, false)); t.addPropertyDefinition(newPropertyDefinition(PropertyIds.IS_LATEST_MAJOR_VERSION, "Is Latest Major Version", PropertyType.BOOLEAN, Cardinality.SINGLE, Updatability.READONLY, false, false, true, true)); t.addPropertyDefinition(newPropertyDefinition(PropertyIds.VERSION_LABEL, "Version Label", PropertyType.STRING, Cardinality.SINGLE, Updatability.READONLY, false, false, true, true)); t.addPropertyDefinition(newPropertyDefinition(PropertyIds.VERSION_SERIES_ID, "Version Series ID", PropertyType.ID, Cardinality.SINGLE, Updatability.READONLY, false, false, false, false)); t.addPropertyDefinition(newPropertyDefinition(PropertyIds.IS_VERSION_SERIES_CHECKED_OUT, "Is Version Series Checked Out", PropertyType.BOOLEAN, Cardinality.SINGLE, Updatability.READONLY, false, false, false, false)); t.addPropertyDefinition(newPropertyDefinition(PropertyIds.VERSION_SERIES_CHECKED_OUT_BY, "Version Series Checked Out By", PropertyType.STRING, Cardinality.SINGLE, Updatability.READONLY, false, false, false, false)); t.addPropertyDefinition(newPropertyDefinition(PropertyIds.VERSION_SERIES_CHECKED_OUT_ID, "Version Series Checked Out ID", PropertyType.ID, Cardinality.SINGLE, Updatability.READONLY, false, false, false, false)); t.addPropertyDefinition(newPropertyDefinition(PropertyIds.CHECKIN_COMMENT, "Checkin Comment", PropertyType.STRING, Cardinality.SINGLE, Updatability.READONLY, false, false, false, false)); // mandatory properties even when content stream not allowed t.addPropertyDefinition(newPropertyDefinition(PropertyIds.CONTENT_STREAM_LENGTH, "Content Stream Length", PropertyType.INTEGER, Cardinality.SINGLE, Updatability.READONLY, false, false, false, false)); t.addPropertyDefinition(newPropertyDefinition(PropertyIds.CONTENT_STREAM_MIME_TYPE, "MIME Type", PropertyType.STRING, Cardinality.SINGLE, Updatability.READONLY, false, false, false, false)); t.addPropertyDefinition(newPropertyDefinition(PropertyIds.CONTENT_STREAM_FILE_NAME, "Filename", PropertyType.STRING, Cardinality.SINGLE, Updatability.READONLY, false, false, false, false)); t.addPropertyDefinition(newPropertyDefinition(PropertyIds.CONTENT_STREAM_ID, "Content Stream ID", PropertyType.ID, Cardinality.SINGLE, Updatability.READONLY, false, false, false, false)); t.addPropertyDefinition(newPropertyDefinition(PropertyIds.CONTENT_STREAM_HASH, "Content Stream Hashes", PropertyType.STRING, Cardinality.MULTI, Updatability.READONLY, false, false, false, false)); // Nuxeo system properties // TODO: make digest queryable at some point t.addPropertyDefinition(newPropertyDefinition(NX_DIGEST, "Content Stream Digest", PropertyType.STRING, Cardinality.SINGLE, Updatability.READONLY, false, false, false, false)); t.addPropertyDefinition(newPropertyDefinition(NX_ISVERSION, "Is Version", PropertyType.BOOLEAN, Cardinality.SINGLE, Updatability.READONLY, false, false, true, true)); t.addPropertyDefinition(newPropertyDefinition(NX_ISCHECKEDIN, "Is Checked In PWC", PropertyType.BOOLEAN, Cardinality.SINGLE, Updatability.READONLY, false, false, true, true)); if (cmisVersion != CmisVersion.CMIS_1_0) { t.addPropertyDefinition(newPropertyDefinition(PropertyIds.IS_PRIVATE_WORKING_COPY, "Is PWC", PropertyType.BOOLEAN, Cardinality.SINGLE, Updatability.READONLY, false, false, false, false)); } } protected static PropertyDefinition<?> newPropertyDefinition(String id, String displayName, PropertyType propertyType, Cardinality cardinality, Updatability updatability, boolean inherited, boolean required, boolean queryable, boolean orderable) { AbstractPropertyDefinition<?> p; switch (propertyType) { case BOOLEAN: p = new PropertyBooleanDefinitionImpl(); break; case DATETIME: p = new PropertyDateTimeDefinitionImpl(); break; case DECIMAL: p = new PropertyDecimalDefinitionImpl(); break; case HTML: p = new PropertyHtmlDefinitionImpl(); break; case ID: p = new PropertyIdDefinitionImpl(); break; case INTEGER: p = new PropertyIntegerDefinitionImpl(); break; case STRING: p = new PropertyStringDefinitionImpl(); break; case URI: p = new PropertyUriDefinitionImpl(); break; default: throw new RuntimeException(propertyType.toString()); } p.setId(id); p.setDescription(displayName); p.setDisplayName(displayName); p.setLocalName(id); p.setLocalNamespace(null); // TODO p.setQueryName(id); p.setPropertyType(propertyType); p.setCardinality(cardinality); p.setUpdatability(updatability); p.setIsInherited(Boolean.valueOf(inherited)); p.setIsRequired(Boolean.valueOf(required)); p.setIsQueryable(Boolean.valueOf(queryable)); p.setIsOrderable(Boolean.valueOf(orderable)); return p; } // TODO update BlobHolderAdapterService to be able to do this // without constructing a fake document protected static boolean supportsBlobHolder(DocumentType documentType) { DocumentModel doc = new DocumentModelImpl(null, documentType.getName(), null, new Path("/"), null, null, null, documentType.getSchemaNames(), documentType.getFacets(), null, "default"); return doc.getAdapter(BlobHolder.class) != null; } /** * Turns a Nuxeo type into a CMIS type. */ protected static String mappedId(String id) { // we don't map any Nuxeo type anymore to cmis:document or cmis:folder return id; } protected static PropertyType getPropertType(SimpleType type) { SimpleType primitive = type.getPrimitiveType(); if (primitive == StringType.INSTANCE) { return PropertyType.STRING; } else if (primitive == BooleanType.INSTANCE) { return PropertyType.BOOLEAN; } else if (primitive == DateType.INSTANCE) { return PropertyType.DATETIME; } else if (primitive == LongType.INSTANCE) { return PropertyType.INTEGER; } else if (primitive == DoubleType.INSTANCE) { return PropertyType.DECIMAL; } else { return PropertyType.STRING; } } public static BaseTypeId getBaseTypeId(DocumentType type) { if (type.isFolder()) { return BaseTypeId.CMIS_FOLDER; } DocumentType t = type; do { if (NUXEO_RELATION.equals(t.getName())) { return BaseTypeId.CMIS_RELATIONSHIP; } t = (DocumentType) t.getSuperType(); } while (t != null); return BaseTypeId.CMIS_DOCUMENT; } public static BaseTypeId getBaseTypeId(DocumentModel doc) { return getBaseTypeId(doc.getDocumentType()); } }