blob: 270dcfc49d4c7e59a23985f98a2164f41dde315b [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
package org.apache.chemistry.opencmis.jcr;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.chemistry.opencmis.commons.PropertyIds;
import org.apache.chemistry.opencmis.commons.definitions.DocumentTypeDefinition;
import org.apache.chemistry.opencmis.commons.definitions.PropertyDefinition;
import org.apache.chemistry.opencmis.commons.definitions.TypeDefinition;
import org.apache.chemistry.opencmis.commons.definitions.TypeDefinitionContainer;
import org.apache.chemistry.opencmis.commons.definitions.TypeDefinitionList;
import org.apache.chemistry.opencmis.commons.enums.BaseTypeId;
import org.apache.chemistry.opencmis.commons.enums.Cardinality;
import org.apache.chemistry.opencmis.commons.enums.PropertyType;
import org.apache.chemistry.opencmis.commons.enums.Updatability;
import org.apache.chemistry.opencmis.commons.exceptions.CmisInvalidArgumentException;
import org.apache.chemistry.opencmis.commons.exceptions.CmisNotSupportedException;
import org.apache.chemistry.opencmis.commons.impl.WSConverter;
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.TypeDefinitionContainerImpl;
import org.apache.chemistry.opencmis.commons.impl.dataobjects.TypeDefinitionListImpl;
import org.apache.chemistry.opencmis.server.support.TypeManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Type Manager.
*/
public class JcrTypeManager implements TypeManager {
private static final Logger LOG = LoggerFactory.getLogger(JcrTypeManager.class);
public static final String DOCUMENT_TYPE_ID = "cmis:document";
public static final String FOLDER_TYPE_ID = "cmis:folder";
public static final String RELATIONSHIP_TYPE_ID = "cmis:relationship";
public static final String POLICY_TYPE_ID = "cmis:policy";
public static final String NAMESPACE = "http://opencmis.org/jcr";
private final Map<String, TypeDefinitionContainerImpl> fTypes;
public JcrTypeManager() {
fTypes = new HashMap<String, TypeDefinitionContainerImpl>();
}
/**
* Adds a type to collection with inheriting base type properties.
*
* @param type
* type to add
* @return <code>true</code> iff the type was successfully added
*/
public boolean addType(TypeDefinition type) {
if (type == null) {
return false;
}
if (fTypes.containsKey(type.getId())) {
// can't overwrite a type
return false;
}
AbstractTypeDefinition newType = (AbstractTypeDefinition) copyTypeDefinition(type);
if (!newType.getBaseTypeId().value().equals(newType.getId())) {
// find base type
TypeDefinition baseType;
if (newType.getBaseTypeId() == BaseTypeId.CMIS_DOCUMENT) {
baseType = copyTypeDefinition(fTypes.get(DOCUMENT_TYPE_ID).getTypeDefinition());
} else if (newType.getBaseTypeId() == BaseTypeId.CMIS_FOLDER) {
baseType = copyTypeDefinition(fTypes.get(FOLDER_TYPE_ID).getTypeDefinition());
} else if (newType.getBaseTypeId() == BaseTypeId.CMIS_RELATIONSHIP) {
baseType = copyTypeDefinition(fTypes.get(RELATIONSHIP_TYPE_ID).getTypeDefinition());
} else if (newType.getBaseTypeId() == BaseTypeId.CMIS_POLICY) {
baseType = copyTypeDefinition(fTypes.get(POLICY_TYPE_ID).getTypeDefinition());
} else {
return false;
}
// copy property definition
for (PropertyDefinition<?> propDef : baseType.getPropertyDefinitions().values()) {
((AbstractPropertyDefinition<?>) propDef).setIsInherited(true);
newType.addPropertyDefinition(propDef);
}
}
// add it
addTypeInternal(newType);
LOG.info("Added type '" + newType.getId() + "'.");
return true;
}
public TypeDefinition getType(String typeId) {
TypeDefinitionContainer tc = fTypes.get(typeId);
return tc == null ? null : tc.getTypeDefinition();
}
public static boolean isVersionable(TypeDefinition typeDef) {
return typeDef instanceof DocumentTypeDefinition ? ((DocumentTypeDefinition) typeDef).isVersionable() : false;
}
public static TypeDefinition copyTypeDefinition(TypeDefinition type) {
return WSConverter.convert(WSConverter.convert(type));
}
/**
* See CMIS 1.0 section 2.2.2.3 getTypeChildren
*/
public TypeDefinitionList getTypeChildren(String typeId, boolean includePropertyDefinitions, BigInteger maxItems,
BigInteger skipCount) {
TypeDefinitionListImpl result = new TypeDefinitionListImpl(new ArrayList<TypeDefinition>());
int skip = skipCount == null ? 0 : skipCount.intValue();
if (skip < 0) {
skip = 0;
}
int max = maxItems == null ? Integer.MAX_VALUE : maxItems.intValue();
if (max < 1) {
return result;
}
if (typeId == null) {
if (skip < 1) {
result.getList().add(copyTypeDefinition(fTypes.get(FOLDER_TYPE_ID).getTypeDefinition()));
max--;
}
if (skip < 2 && max > 0) {
result.getList().add(copyTypeDefinition(fTypes.get(DOCUMENT_TYPE_ID).getTypeDefinition()));
}
result.setHasMoreItems(result.getList().size() + skip < 2);
result.setNumItems(BigInteger.valueOf(2));
} else {
TypeDefinitionContainer tc = fTypes.get(typeId);
if (tc == null || tc.getChildren() == null) {
return result;
}
for (TypeDefinitionContainer child : tc.getChildren()) {
if (skip > 0) {
skip--;
continue;
}
result.getList().add(copyTypeDefinition(child.getTypeDefinition()));
max--;
if (max == 0) {
break;
}
}
result.setHasMoreItems(result.getList().size() + skip < tc.getChildren().size());
result.setNumItems(BigInteger.valueOf(tc.getChildren().size()));
}
if (!includePropertyDefinitions) {
for (TypeDefinition type : result.getList()) {
type.getPropertyDefinitions().clear();
}
}
return result;
}
/**
* See CMIS 1.0 section 2.2.2.4 getTypeDescendants
*/
public List<TypeDefinitionContainer> getTypesDescendants(String typeId, BigInteger depth,
Boolean includePropertyDefinitions) {
List<TypeDefinitionContainer> result = new ArrayList<TypeDefinitionContainer>();
// check depth
int d = depth == null ? -1 : depth.intValue();
if (d == 0) {
throw new CmisInvalidArgumentException("Depth must not be 0!");
}
// set property definition flag to default value if not set
boolean ipd = Boolean.TRUE.equals(includePropertyDefinitions);
if (typeId == null) {
result.add(getTypesDescendants(d, fTypes.get(FOLDER_TYPE_ID), ipd));
result.add(getTypesDescendants(d, fTypes.get(DOCUMENT_TYPE_ID), ipd));
} else {
TypeDefinitionContainer tc = fTypes.get(typeId);
if (tc != null) {
result.add(getTypesDescendants(d, tc, ipd));
}
}
return result;
}
// ------------------------------------------< JcrTypeManager >---
public TypeDefinitionContainer getTypeById(String typeId) {
return fTypes.get(typeId);
}
public TypeDefinition getTypeByQueryName(String typeQueryName) {
for (TypeDefinitionContainerImpl type : fTypes.values()) {
TypeDefinition typeDef = type.getTypeDefinition();
if (typeDef.getQueryName().equals(typeQueryName)) {
return typeDef;
}
}
return null;
}
public Collection<TypeDefinitionContainer> getTypeDefinitionList() {
Collection<TypeDefinitionContainer> types = new ArrayList<TypeDefinitionContainer>(fTypes.size());
types.addAll(fTypes.values());
return types;
}
public List<TypeDefinitionContainer> getRootTypes() {
List<TypeDefinitionContainer> types = new ArrayList<TypeDefinitionContainer>(2);
types.add(fTypes.get(FOLDER_TYPE_ID));
types.add(fTypes.get(DOCUMENT_TYPE_ID));
return types;
}
public String getPropertyIdForQueryName(TypeDefinition typeDefinition, String propQueryName) {
for (PropertyDefinition<?> pd : typeDefinition.getPropertyDefinitions().values()) {
if (pd.getQueryName().equals(propQueryName)) {
return pd.getId();
}
}
return null;
}
public static void addBasePropertyDefinitions(AbstractTypeDefinition type) {
type.addPropertyDefinition(createPropDef(PropertyIds.BASE_TYPE_ID, "Base Type Id", "Base Type Id",
PropertyType.ID, Cardinality.SINGLE, Updatability.READONLY, false, true));
type.addPropertyDefinition(createPropDef(PropertyIds.OBJECT_ID, "Object Id", "Object Id", PropertyType.ID,
Cardinality.SINGLE, Updatability.READONLY, false, true));
type.addPropertyDefinition(createPropDef(PropertyIds.OBJECT_TYPE_ID, "Type Id", "Type Id", PropertyType.ID,
Cardinality.SINGLE, Updatability.ONCREATE, false, true));
type.addPropertyDefinition(createPropDef(PropertyIds.NAME, "Name", "Name", PropertyType.STRING,
Cardinality.SINGLE, Updatability.READWRITE, false, true));
type.addPropertyDefinition(createPropDef(PropertyIds.CREATED_BY, "Created By", "Created By",
PropertyType.STRING, Cardinality.SINGLE, Updatability.READONLY, false, true));
type.addPropertyDefinition(createPropDef(PropertyIds.CREATION_DATE, "Creation Date", "Creation Date",
PropertyType.DATETIME, Cardinality.SINGLE, Updatability.READONLY, false, true));
type.addPropertyDefinition(createPropDef(PropertyIds.LAST_MODIFIED_BY, "Last Modified By", "Last Modified By",
PropertyType.STRING, Cardinality.SINGLE, Updatability.READONLY, false, true));
type.addPropertyDefinition(createPropDef(PropertyIds.LAST_MODIFICATION_DATE, "Last Modification Date",
"Last Modification Date", PropertyType.DATETIME, Cardinality.SINGLE, Updatability.READONLY, false, true));
type.addPropertyDefinition(createPropDef(PropertyIds.CHANGE_TOKEN, "Change Token", "Change Token",
PropertyType.STRING, Cardinality.SINGLE, Updatability.READONLY, false, false));
}
public static void addFolderPropertyDefinitions(FolderTypeDefinitionImpl type) {
type.addPropertyDefinition(createPropDef(PropertyIds.PARENT_ID, "Parent Id", "Parent Id", PropertyType.ID,
Cardinality.SINGLE, Updatability.READONLY, false, false));
type.addPropertyDefinition(createPropDef(PropertyIds.ALLOWED_CHILD_OBJECT_TYPE_IDS,
"Allowed Child Object Type Ids", "Allowed Child Object Type Ids", PropertyType.ID, Cardinality.MULTI,
Updatability.READONLY, false, false));
type.addPropertyDefinition(createPropDef(PropertyIds.PATH, "Path", "Path", PropertyType.STRING,
Cardinality.SINGLE, Updatability.READONLY, false, false));
}
public static void addDocumentPropertyDefinitions(DocumentTypeDefinitionImpl type) {
type.addPropertyDefinition(createPropDef(PropertyIds.IS_IMMUTABLE, "Is Immutable", "Is Immutable",
PropertyType.BOOLEAN, Cardinality.SINGLE, Updatability.READONLY, false, false));
type.addPropertyDefinition(createPropDef(PropertyIds.IS_LATEST_VERSION, "Is Latest Version",
"Is Latest Version", PropertyType.BOOLEAN, Cardinality.SINGLE, Updatability.READONLY, false, false));
type.addPropertyDefinition(createPropDef(PropertyIds.IS_MAJOR_VERSION, "Is Major Version", "Is Major Version",
PropertyType.BOOLEAN, Cardinality.SINGLE, Updatability.READONLY, false, false));
type.addPropertyDefinition(createPropDef(PropertyIds.IS_LATEST_MAJOR_VERSION, "Is Latest Major Version",
"Is Latest Major Version", PropertyType.BOOLEAN, Cardinality.SINGLE, Updatability.READONLY, false,
false));
type.addPropertyDefinition(createPropDef(PropertyIds.VERSION_LABEL, "Version Label", "Version Label",
PropertyType.STRING, Cardinality.SINGLE, Updatability.READONLY, false, false));
type.addPropertyDefinition(createPropDef(PropertyIds.VERSION_SERIES_ID, "Version Series Id",
"Version Series Id", PropertyType.ID, Cardinality.SINGLE, Updatability.READONLY, false, true));
type.addPropertyDefinition(createPropDef(PropertyIds.IS_VERSION_SERIES_CHECKED_OUT,
"Is Version Series Checked Out", "Is Version Series Checked Out", PropertyType.BOOLEAN,
Cardinality.SINGLE, Updatability.READONLY, false, true));
type.addPropertyDefinition(createPropDef(PropertyIds.VERSION_SERIES_CHECKED_OUT_ID,
"Version Series Checked Out Id", "Version Series Checked Out Id", PropertyType.ID, Cardinality.SINGLE,
Updatability.READONLY, false, false));
type.addPropertyDefinition(createPropDef(PropertyIds.VERSION_SERIES_CHECKED_OUT_BY,
"Version Series Checked Out By", "Version Series Checked Out By", PropertyType.ID, Cardinality.SINGLE,
Updatability.READONLY, false, false));
type.addPropertyDefinition(createPropDef(PropertyIds.CHECKIN_COMMENT, "Checkin Comment", "Checkin Comment",
PropertyType.STRING, Cardinality.SINGLE, Updatability.READONLY, false, false));
type.addPropertyDefinition(createPropDef(PropertyIds.CONTENT_STREAM_LENGTH, "Content Stream Length",
"Content Stream Length", PropertyType.INTEGER, Cardinality.SINGLE, Updatability.READONLY, false, false));
type.addPropertyDefinition(createPropDef(PropertyIds.CONTENT_STREAM_MIME_TYPE, "MIME Type", "MIME Type",
PropertyType.STRING, Cardinality.SINGLE, Updatability.READONLY, false, false));
type.addPropertyDefinition(createPropDef(PropertyIds.CONTENT_STREAM_FILE_NAME, "Filename", "Filename",
PropertyType.STRING, Cardinality.SINGLE, Updatability.READONLY, false, false));
type.addPropertyDefinition(createPropDef(PropertyIds.CONTENT_STREAM_ID, "Content Stream Id",
"Content Stream Id", PropertyType.ID, Cardinality.SINGLE, Updatability.READONLY, false, false));
}
/**
* Creates a property definition object.
*/
public static PropertyDefinition<?> createPropDef(String id, String displayName, String description,
PropertyType datatype, Cardinality cardinality, Updatability updateability, boolean inherited,
boolean required) {
AbstractPropertyDefinition<?> result;
switch (datatype) {
case BOOLEAN:
result = new PropertyBooleanDefinitionImpl();
break;
case DATETIME:
result = new PropertyDateTimeDefinitionImpl();
break;
case DECIMAL:
result = new PropertyDecimalDefinitionImpl();
break;
case HTML:
result = new PropertyHtmlDefinitionImpl();
break;
case ID:
result = new PropertyIdDefinitionImpl();
break;
case INTEGER:
result = new PropertyIntegerDefinitionImpl();
break;
case STRING:
result = new PropertyStringDefinitionImpl();
break;
case URI:
result = new PropertyUriDefinitionImpl();
break;
default:
throw new RuntimeException("Unknown datatype! Spec change?");
}
result.setId(id);
result.setLocalName(id);
result.setDisplayName(displayName);
result.setDescription(description);
result.setPropertyType(datatype);
result.setCardinality(cardinality);
result.setUpdatability(updateability);
result.setIsInherited(inherited);
result.setIsRequired(required);
result.setIsQueryable(false);
result.setQueryName(id);
return result;
}
// ------------------------------------------< private >---
/**
* Adds a type to collection.
*/
private void addTypeInternal(AbstractTypeDefinition type) {
if (type == null) {
return;
}
TypeDefinitionContainerImpl tc = new TypeDefinitionContainerImpl();
tc.setTypeDefinition(type);
// add to parent
if (type.getParentTypeId() != null) {
TypeDefinitionContainerImpl tdc = fTypes.get(type.getParentTypeId());
if (tdc != null) {
if (tdc.getChildren() == null) {
tdc.setChildren(new ArrayList<TypeDefinitionContainer>());
}
tdc.getChildren().add(tc);
}
}
fTypes.put(type.getId(), tc);
}
/**
* Gathers the type descendants tree.
*/
private static TypeDefinitionContainer getTypesDescendants(int depth, TypeDefinitionContainer tc,
boolean includePropertyDefinitions) {
TypeDefinitionContainerImpl result = new TypeDefinitionContainerImpl();
TypeDefinition type = copyTypeDefinition(tc.getTypeDefinition());
if (!includePropertyDefinitions) {
type.getPropertyDefinitions().clear();
}
result.setTypeDefinition(type);
if (depth != 0) {
if (tc.getChildren() != null) {
result.setChildren(new ArrayList<TypeDefinitionContainer>());
for (TypeDefinitionContainer tdc : tc.getChildren()) {
result.getChildren().add(
getTypesDescendants(depth < 0 ? -1 : depth - 1, tdc, includePropertyDefinitions));
}
}
}
return result;
}
public void addTypeDefinition(TypeDefinition typeDefinition, boolean addInheritedProperties) {
throw new CmisNotSupportedException("Method not implemented.");
}
public void updateTypeDefinition(TypeDefinition typeDefinition) {
throw new CmisNotSupportedException("Method not implemented.");
}
public void deleteTypeDefinition(String typeId) {
throw new CmisNotSupportedException("Method not implemented.");
}
}