blob: 611358d01af41fa35dbacee89a7c453a5fb90992 [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.inmemory.server;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.chemistry.opencmis.commons.PropertyIds;
import org.apache.chemistry.opencmis.commons.data.Acl;
import org.apache.chemistry.opencmis.commons.data.AllowableActions;
import org.apache.chemistry.opencmis.commons.data.BulkUpdateObjectIdAndChangeToken;
import org.apache.chemistry.opencmis.commons.data.CmisExtensionElement;
import org.apache.chemistry.opencmis.commons.data.ContentStream;
import org.apache.chemistry.opencmis.commons.data.ExtensionsData;
import org.apache.chemistry.opencmis.commons.data.FailedToDeleteData;
import org.apache.chemistry.opencmis.commons.data.ObjectData;
import org.apache.chemistry.opencmis.commons.data.Properties;
import org.apache.chemistry.opencmis.commons.data.PropertyData;
import org.apache.chemistry.opencmis.commons.data.RenditionData;
import org.apache.chemistry.opencmis.commons.definitions.DocumentTypeDefinition;
import org.apache.chemistry.opencmis.commons.definitions.PropertyDefinition;
import org.apache.chemistry.opencmis.commons.definitions.RelationshipTypeDefinition;
import org.apache.chemistry.opencmis.commons.definitions.TypeDefinition;
import org.apache.chemistry.opencmis.commons.definitions.TypeDefinitionContainer;
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.IncludeRelationships;
import org.apache.chemistry.opencmis.commons.enums.UnfileObject;
import org.apache.chemistry.opencmis.commons.enums.Updatability;
import org.apache.chemistry.opencmis.commons.enums.VersioningState;
import org.apache.chemistry.opencmis.commons.exceptions.CmisConstraintException;
import org.apache.chemistry.opencmis.commons.exceptions.CmisContentAlreadyExistsException;
import org.apache.chemistry.opencmis.commons.exceptions.CmisInvalidArgumentException;
import org.apache.chemistry.opencmis.commons.exceptions.CmisNotSupportedException;
import org.apache.chemistry.opencmis.commons.exceptions.CmisObjectNotFoundException;
import org.apache.chemistry.opencmis.commons.exceptions.CmisUpdateConflictException;
import org.apache.chemistry.opencmis.commons.impl.dataobjects.BulkUpdateObjectIdAndChangeTokenImpl;
import org.apache.chemistry.opencmis.commons.impl.dataobjects.CmisExtensionElementImpl;
import org.apache.chemistry.opencmis.commons.impl.dataobjects.ContentStreamImpl;
import org.apache.chemistry.opencmis.commons.impl.dataobjects.FailedToDeleteDataImpl;
import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertiesImpl;
import org.apache.chemistry.opencmis.commons.impl.server.ObjectInfoImpl;
import org.apache.chemistry.opencmis.commons.server.CallContext;
import org.apache.chemistry.opencmis.commons.server.ObjectInfoHandler;
import org.apache.chemistry.opencmis.commons.spi.Holder;
import org.apache.chemistry.opencmis.inmemory.FilterParser;
import org.apache.chemistry.opencmis.inmemory.NameValidator;
import org.apache.chemistry.opencmis.inmemory.storedobj.api.Content;
import org.apache.chemistry.opencmis.inmemory.storedobj.api.Document;
import org.apache.chemistry.opencmis.inmemory.storedobj.api.DocumentVersion;
import org.apache.chemistry.opencmis.inmemory.storedobj.api.Fileable;
import org.apache.chemistry.opencmis.inmemory.storedobj.api.Filing;
import org.apache.chemistry.opencmis.inmemory.storedobj.api.Folder;
import org.apache.chemistry.opencmis.inmemory.storedobj.api.ObjectStore;
import org.apache.chemistry.opencmis.inmemory.storedobj.api.ObjectStoreFiling;
import org.apache.chemistry.opencmis.inmemory.storedobj.api.ObjectStoreFiling.ChildrenResult;
import org.apache.chemistry.opencmis.inmemory.storedobj.api.StoreManager;
import org.apache.chemistry.opencmis.inmemory.storedobj.api.StoredObject;
import org.apache.chemistry.opencmis.inmemory.storedobj.api.VersionedDocument;
import org.apache.chemistry.opencmis.inmemory.types.DocumentTypeCreationHelper;
import org.apache.chemistry.opencmis.inmemory.types.PropertyCreationHelper;
import org.apache.chemistry.opencmis.server.support.TypeManager;
import org.apache.chemistry.opencmis.server.support.TypeValidator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class InMemoryObjectServiceImpl extends InMemoryAbstractServiceImpl {
private static final Logger LOG = LoggerFactory.getLogger(InMemoryServiceFactoryImpl.class.getName());
public InMemoryObjectServiceImpl(StoreManager storeManager) {
super(storeManager);
}
public String createDocument(CallContext context, String repositoryId, Properties properties, String folderId,
ContentStream contentStream, VersioningState versioningState, List<String> policies, Acl addAces,
Acl removeAces, ExtensionsData extension) {
LOG.debug("start createDocument()");
// Attach the CallContext to a thread local context that can be
// accessed from everywhere
StoredObject so = createDocumentIntern(context, repositoryId, properties, folderId, contentStream,
versioningState, policies, addAces, removeAces, extension);
LOG.debug("stop createDocument()");
return so.getId();
}
public String createDocumentFromSource(CallContext context, String repositoryId, String sourceId,
Properties properties, String folderId, VersioningState versioningState, List<String> policies,
Acl addAces, Acl removeAces, ExtensionsData extension) {
LOG.debug("start createDocumentFromSource()");
StoredObject so = validator.createDocumentFromSource(context, repositoryId, sourceId, folderId, policies,
extension);
ObjectStore objectStore = fStoreManager.getObjectStore(repositoryId);
ContentStream content = getContentStream(context, repositoryId, sourceId, null, BigInteger.valueOf(-1),
BigInteger.valueOf(-1), null);
if (so == null) {
throw new CmisObjectNotFoundException("Unknown object id: " + sourceId);
}
// build properties collection
List<String> requestedIds = FilterParser.getRequestedIdsFromFilter("*");
TypeManager tm = fStoreManager.getTypeManager(repositoryId);
Properties existingProps = PropertyCreationHelper.getPropertiesFromObject(so, objectStore, tm, requestedIds, true);
PropertiesImpl newPD = new PropertiesImpl();
// copy all existing properties
for (PropertyData<?> prop : existingProps.getProperties().values()) {
newPD.addProperty(prop);
}
if (null != properties)
// overwrite all new properties
for (PropertyData<?> prop : properties.getProperties().values()) {
newPD.addProperty(prop);
}
String res = createDocument(context, repositoryId, newPD, folderId, content, versioningState, policies,
addAces, removeAces, null);
LOG.debug("stop createDocumentFromSource()");
return res;
}
public String createFolder(CallContext context, String repositoryId, Properties properties, String folderId,
List<String> policies, Acl addAces, Acl removeAces, ExtensionsData extension) {
LOG.debug("start createFolder()");
Folder folder = createFolderIntern(context, repositoryId, properties, folderId, policies, addAces, removeAces,
extension);
LOG.debug("stop createFolder()");
return folder.getId();
}
public String createPolicy(CallContext context, String repositoryId, Properties properties, String folderId,
List<String> policies, Acl addAces, Acl removeAces, ExtensionsData extension) {
LOG.debug("start createPolicy()");
StoredObject so = createPolicyIntern(context, repositoryId, properties, folderId, policies, addAces,
removeAces, extension);
LOG.debug("stop createPolicy()");
return so == null ? null : so.getId();
}
public String createRelationship(CallContext context, String repositoryId, Properties properties,
List<String> policies, Acl addAces, Acl removeAces, ExtensionsData extension) {
LOG.debug("start createRelationship()");
StoredObject so = createRelationshipIntern(context, repositoryId, properties, policies, addAces, removeAces,
extension);
LOG.debug("stop createRelationship()");
return so == null ? null : so.getId();
}
// CMIS 1.1
public String createItem(CallContext context, String repositoryId, Properties properties, String folderId,
List<String> policies, Acl addAces, Acl removeAces, ExtensionsData extension) {
StoredObject so = createItemIntern(context, repositoryId, properties, folderId, policies, addAces, removeAces,
extension);
return so.getId();
}
@SuppressWarnings("unchecked")
public String create(CallContext context, String repositoryId, Properties properties, String folderId,
ContentStream contentStream, VersioningState versioningState, List<String> policies,
ExtensionsData extension, ObjectInfoHandler objectInfos) {
if (null == properties || null == properties.getProperties()) {
throw new CmisInvalidArgumentException("Cannot create object, without properties.");
}
// Find out what kind of object needs to be created
PropertyData<String> pd = (PropertyData<String>) properties.getProperties().get(PropertyIds.OBJECT_TYPE_ID);
String typeId = pd == null ? null : pd.getFirstValue();
if (null == typeId) {
throw new CmisInvalidArgumentException(
"Cannot create object, without a type (no property with id CMIS_OBJECT_TYPE_ID).");
}
TypeDefinitionContainer typeDefC = fStoreManager.getTypeById(repositoryId, typeId);
if (typeDefC == null) {
throw new CmisInvalidArgumentException("Cannot create object, a type with id " + typeId + " is unknown");
}
// check if the given type is a document type
BaseTypeId typeBaseId = typeDefC.getTypeDefinition().getBaseTypeId();
StoredObject so = null;
ObjectStore objStore = fStoreManager.getObjectStore(repositoryId);
if (typeBaseId.equals(DocumentTypeCreationHelper.getCmisDocumentType().getBaseTypeId())) {
so = createDocumentIntern(context, repositoryId, properties, folderId, contentStream, versioningState,
null, null, null, null);
} else if (typeBaseId.equals(DocumentTypeCreationHelper.getCmisFolderType().getBaseTypeId())) {
so = createFolderIntern(context, repositoryId, properties, folderId, null, null, null, null);
} else if (typeBaseId.equals(DocumentTypeCreationHelper.getCmisPolicyType().getBaseTypeId())) {
so = createPolicyIntern(context, repositoryId, properties, folderId, null, null, null, null);
} else if (typeBaseId.equals(DocumentTypeCreationHelper.getCmisRelationshipType().getBaseTypeId())) {
so = createRelationshipIntern(context, repositoryId, properties, null, null, null, null);
} else if (typeBaseId.equals(DocumentTypeCreationHelper.getCmisItemType().getBaseTypeId())) {
so = createItemIntern(context, repositoryId, properties, folderId, null, null, null, null);
} else {
LOG.error("The type contains an unknown base object id, object can't be created");
}
// Make a call to getObject to convert the resulting id into an
// ObjectData
TypeManager tm = fStoreManager.getTypeManager(repositoryId);
ObjectData od = PropertyCreationHelper.getObjectData(tm, objStore, so, null, context.getUsername(), false,
IncludeRelationships.NONE, null, false, false, extension);
if (context.isObjectInfoRequired()) {
ObjectInfoImpl objectInfo = new ObjectInfoImpl();
fAtomLinkProvider.fillInformationForAtomLinks(repositoryId, so, od, objectInfo);
objectInfos.addObjectInfo(objectInfo);
}
return so != null ? so.getId() : null;
}
public void deleteContentStream(CallContext context, String repositoryId, Holder<String> objectId,
Holder<String> changeToken, ExtensionsData extension) {
LOG.debug("start deleteContentStream()");
StoredObject so = validator.deleteContentStream(context, repositoryId, objectId, extension);
if (so == null) {
throw new CmisObjectNotFoundException("Unknown object id: " + objectId);
}
if (so.getChangeToken() != null && (changeToken == null || !so.getChangeToken().equals(changeToken.getValue())))
throw new CmisUpdateConflictException("deleteContentStream failed, ChangeToken does not match.");
if (!(so instanceof Content)) {
throw new CmisObjectNotFoundException("Id" + objectId
+ " does not refer to a document, but only documents can have content");
}
((Content) so).setContent(null, true);
LOG.debug("stop deleteContentStream()");
}
public void deleteObject(CallContext context, String repositoryId, String objectId, Boolean allVersions,
ExtensionsData extension) {
LOG.debug("start deleteObject()");
validator.deleteObject(context, repositoryId, objectId, allVersions, extension);
ObjectStore objectStore = fStoreManager.getObjectStore(repositoryId);
LOG.debug("delete object for id: " + objectId);
// check if it is the root folder
if (objectId.equals(objectStore.getRootFolder().getId())) {
throw new CmisNotSupportedException("You can't delete a root folder");
}
objectStore.deleteObject(objectId, allVersions, context.getUsername());
LOG.debug("stop deleteObject()");
}
public FailedToDeleteData deleteTree(CallContext context, String repositoryId, String folderId,
Boolean allVersions, UnfileObject unfileObjects, Boolean continueOnFailure, ExtensionsData extension) {
LOG.debug("start deleteTree()");
StoredObject so = validator.deleteTree(context, repositoryId, folderId, allVersions, unfileObjects, extension);
List<String> failedToDeleteIds = new ArrayList<String>();
FailedToDeleteDataImpl result = new FailedToDeleteDataImpl();
if (null == allVersions) {
allVersions = true;
}
if (null == unfileObjects) {
unfileObjects = UnfileObject.DELETE;
}
if (null == continueOnFailure) {
continueOnFailure = false;
}
ObjectStore objectStore = fStoreManager.getObjectStore(repositoryId);
if (null == so) {
throw new CmisInvalidArgumentException("Cannot delete object with id " + folderId
+ ". Object does not exist.");
}
if (!(so instanceof Folder)) {
throw new CmisInvalidArgumentException("deleteTree can only be invoked on a folder, but id " + folderId
+ " does not refer to a folder");
}
if (unfileObjects == UnfileObject.UNFILE) {
throw new CmisNotSupportedException("This repository does not support unfile operations.");
}
// check if it is the root folder
if (folderId.equals(objectStore.getRootFolder().getId())) {
throw new CmisNotSupportedException("You can't delete a root folder");
}
// recursively delete folder
deleteRecursive(objectStore, (Folder) so, continueOnFailure, allVersions, failedToDeleteIds,
context.getUsername());
result.setIds(failedToDeleteIds);
LOG.debug("stop deleteTree()");
return result;
}
public AllowableActions getAllowableActions(CallContext context, String repositoryId, String objectId,
ExtensionsData extension) {
LOG.debug("start getAllowableActions()");
StoredObject so = validator.getAllowableActions(context, repositoryId, objectId, extension);
fStoreManager.getObjectStore(repositoryId);
if (so == null) {
throw new CmisObjectNotFoundException("Unknown object id: " + objectId);
}
String user = context.getUsername();
// AllowableActions allowableActions =
// DataObjectCreator.fillAllowableActions(so, user);
AllowableActions allowableActions = so.getAllowableActions(user);
LOG.debug("stop getAllowableActions()");
return allowableActions;
}
public ContentStream getContentStream(CallContext context, String repositoryId, String objectId, String streamId,
BigInteger offset, BigInteger length, ExtensionsData extension) {
LOG.debug("start getContentStream()");
StoredObject so = validator.getContentStream(context, repositoryId, objectId, streamId, extension);
if (so == null) {
throw new CmisObjectNotFoundException("Unknown object id: " + objectId);
}
if (!(so instanceof Content) && objectId.endsWith("-rendition")) {
throw new CmisConstraintException("Id" + objectId
+ " does not refer to a document or version, but only those can have content");
}
ContentStream csd = getContentStream(so, streamId, offset, length);
if (null == csd) {
throw new CmisConstraintException("Object " + so.getId() + " does not have content.");
}
LOG.debug("stop getContentStream()");
return csd;
}
public ObjectData getObject(CallContext context, String repositoryId, String objectId, String filter,
Boolean includeAllowableActions, IncludeRelationships includeRelationships, String renditionFilter,
Boolean includePolicyIds, Boolean includeAcl, ExtensionsData extension, ObjectInfoHandler objectInfos) {
LOG.debug("start getObject()");
StoredObject so = validator.getObject(context, repositoryId, objectId, extension);
ObjectStore objStore = fStoreManager.getObjectStore(repositoryId);
if (so == null) {
throw new CmisObjectNotFoundException("Unknown object id: " + objectId);
}
String user = context.getUsername();
TypeManager tm = fStoreManager.getTypeManager(repositoryId);
ObjectData od = PropertyCreationHelper.getObjectData(tm, objStore, so, filter, user, includeAllowableActions,
includeRelationships, renditionFilter, includePolicyIds, includeAcl, extension);
if (context.isObjectInfoRequired()) {
ObjectInfoImpl objectInfo = new ObjectInfoImpl();
fAtomLinkProvider.fillInformationForAtomLinks(repositoryId, so, objectInfo);
objectInfos.addObjectInfo(objectInfo);
}
// fill an example extension
String ns = "http://apache.org/opencmis/inmemory";
List<CmisExtensionElement> extElements = new ArrayList<CmisExtensionElement>();
Map<String, String> attr = new HashMap<String, String>();
attr.put("type", so.getTypeId());
extElements.add(new CmisExtensionElementImpl(ns, "objectId", attr, objectId));
extElements.add(new CmisExtensionElementImpl(ns, "name", null, so.getName()));
od.setExtensions(Collections.singletonList((CmisExtensionElement) new CmisExtensionElementImpl(ns,
"exampleExtension", null, extElements)));
LOG.debug("stop getObject()");
return od;
}
public ObjectData getObjectByPath(CallContext context, String repositoryId, String path, String filter,
Boolean includeAllowableActions, IncludeRelationships includeRelationships, String renditionFilter,
Boolean includePolicyIds, Boolean includeAcl, ExtensionsData extension, ObjectInfoHandler objectInfos) {
LOG.debug("start getObjectByPath()");
StoredObject so = validator.getObjectByPath(context, repositoryId, path, extension);
if (so instanceof VersionedDocument) {
VersionedDocument verDoc = (VersionedDocument) so;
so = verDoc.getLatestVersion(false);
}
String user = context.getUsername();
ObjectStore objStore = fStoreManager.getObjectStore(repositoryId);
TypeManager tm = fStoreManager.getTypeManager(repositoryId);
ObjectData od = PropertyCreationHelper.getObjectData(tm, objStore, so, filter, user, includeAllowableActions,
includeRelationships, renditionFilter, includePolicyIds, includeAcl, extension);
LOG.debug("stop getObjectByPath()");
// To be able to provide all Atom links in the response we need
// additional information:
if (context.isObjectInfoRequired()) {
ObjectInfoImpl objectInfo = new ObjectInfoImpl();
fAtomLinkProvider.fillInformationForAtomLinks(repositoryId, so, objectInfo);
objectInfos.addObjectInfo(objectInfo);
}
return od;
}
public Properties getProperties(CallContext context, String repositoryId, String objectId, String filter,
ExtensionsData extension) {
LOG.debug("start getProperties()");
StoredObject so = validator.getProperties(context, repositoryId, objectId, extension);
ObjectStore objectStore = fStoreManager.getObjectStore(repositoryId);
if (so == null) {
throw new CmisObjectNotFoundException("Unknown object id: " + objectId);
}
// build properties collection
List<String> requestedIds = FilterParser.getRequestedIdsFromFilter(filter);
TypeManager tm = fStoreManager.getTypeManager(repositoryId);
Properties props = PropertyCreationHelper.getPropertiesFromObject(so, objectStore, tm, requestedIds, true);
LOG.debug("stop getProperties()");
return props;
}
public List<RenditionData> getRenditions(CallContext context, String repositoryId, String objectId,
String renditionFilter, BigInteger maxItems, BigInteger skipCount, ExtensionsData extension) {
LOG.debug("start getRenditions()");
StoredObject so = validator.getRenditions(context, repositoryId, objectId, extension);
if (so == null) {
throw new CmisObjectNotFoundException("Unknown object id: " + objectId);
}
List<RenditionData> renditions = so.getRenditions(renditionFilter, maxItems == null ? 0 : maxItems.longValue(),
skipCount == null ? 0 : skipCount.longValue());
LOG.debug("stop getRenditions()");
return renditions;
}
public ObjectData moveObject(CallContext context, String repositoryId, Holder<String> objectId,
String targetFolderId, String sourceFolderId, ExtensionsData extension, ObjectInfoHandler objectInfos) {
LOG.debug("start moveObject()");
StoredObject[] sos = validator.moveObject(context, repositoryId, objectId, targetFolderId, sourceFolderId,
extension);
StoredObject so = sos[0];
Folder targetFolder = null;
Folder sourceFolder = null;
ObjectStore objectStore = fStoreManager.getObjectStore(repositoryId);
Filing spo = null;
String user = context.getUsername();
if (null == so) {
throw new CmisObjectNotFoundException("Unknown object: " + objectId.getValue());
} else if (so instanceof Filing) {
spo = (Filing) so;
} else {
throw new CmisInvalidArgumentException("Object must be fileable: " + objectId.getValue());
}
StoredObject soTarget = objectStore.getObjectById(targetFolderId);
if (null == soTarget) {
throw new CmisObjectNotFoundException("Unknown target folder: " + targetFolderId);
} else if (soTarget instanceof Folder) {
targetFolder = (Folder) soTarget;
} else {
throw new CmisNotSupportedException("Destination " + targetFolderId
+ " of a move operation must be a folder");
}
StoredObject soSource = objectStore.getObjectById(sourceFolderId);
if (null == soSource) {
throw new CmisObjectNotFoundException("Unknown source folder: " + sourceFolderId);
} else if (soSource instanceof Folder) {
sourceFolder = (Folder) soSource;
} else {
throw new CmisNotSupportedException("Source " + sourceFolderId + " of a move operation must be a folder");
}
boolean foundOldParent = false;
for (String parentId : ((ObjectStoreFiling)objectStore).getParentIds(spo, user)) {
if (parentId.equals(soSource.getId())) {
foundOldParent = true;
break;
}
}
if (!foundOldParent) {
throw new CmisNotSupportedException("Cannot move object, source folder " + sourceFolderId
+ "is not a parent of object " + objectId.getValue());
}
if (so instanceof Folder && hasDescendant(context.getUsername(), objectStore, (Folder) so, targetFolder)) {
throw new CmisNotSupportedException("Destination of a move cannot be a subfolder of the source");
}
if (objectStore instanceof ObjectStoreFiling) {
((ObjectStoreFiling) objectStore).move(so, sourceFolder, targetFolder);
} else {
throw new CmisInvalidArgumentException("Repository " + repositoryId + "does not support Filing");
}
objectId.setValue(so.getId());
LOG.debug("stop moveObject()");
TypeManager tm = fStoreManager.getTypeManager(repositoryId);
ObjectData od = PropertyCreationHelper.getObjectData(tm, objectStore, so, null, user, false, IncludeRelationships.NONE,
null, false, false, extension);
// To be able to provide all Atom links in the response we need
// additional information:
if (context.isObjectInfoRequired()) {
ObjectInfoImpl objectInfo = new ObjectInfoImpl();
fAtomLinkProvider.fillInformationForAtomLinks(repositoryId, so, od, objectInfo);
objectInfos.addObjectInfo(objectInfo);
}
return od;
}
public void setContentStream(CallContext context, String repositoryId, Holder<String> objectId,
Boolean overwriteFlag, Holder<String> changeToken, ContentStream contentStream, ExtensionsData extension) {
LOG.debug("start setContentStream()");
Content content;
if (null == overwriteFlag) {
overwriteFlag = Boolean.TRUE;
}
StoredObject so = validator.setContentStream(context, repositoryId, objectId, overwriteFlag, extension);
if (changeToken != null && changeToken.getValue() != null
&& Long.valueOf(so.getChangeToken()) > Long.valueOf(changeToken.getValue())) {
throw new CmisUpdateConflictException("setContentStream failed: changeToken does not match");
}
if (!(so instanceof Document || so instanceof VersionedDocument || so instanceof DocumentVersion)) {
throw new CmisObjectNotFoundException("Id" + objectId
+ " does not refer to a document, but only documents can have content");
}
// validate content allowed
TypeDefinition typeDef = getTypeDefinition(repositoryId, so);
if (!(typeDef instanceof DocumentTypeDefinition))
throw new CmisInvalidArgumentException("Object does not refer to a document, can't set content");
TypeValidator.validateContentAllowed((DocumentTypeDefinition) typeDef, null != contentStream);
if (so instanceof Document) {
content = ((Document) so);
} else if (so instanceof DocumentVersion) {
// something that is versionable check the proper status of the
// object
String user = context.getUsername();
testHasProperCheckedOutStatus(so, user);
content = (DocumentVersion) so;
} else {
throw new IllegalArgumentException("Content cannot be set on this object (must be document or version)");
}
if (!overwriteFlag && content.getContent(0, -1) != null) {
throw new CmisContentAlreadyExistsException(
"cannot overwrite existing content if overwrite flag is not set");
}
content.setContent(contentStream, true);
so.updateSystemBasePropertiesWhenModified(null, context.getUsername());
LOG.debug("stop setContentStream()");
}
public void updateProperties(CallContext context, String repositoryId, Holder<String> objectId,
Holder<String> changeToken, Properties properties, Acl acl, ExtensionsData extension,
ObjectInfoHandler objectInfos) {
LOG.debug("start updateProperties()");
StoredObject so = validator.updateProperties(context, repositoryId, objectId, extension);
String user = context.getUsername();
ObjectStore objStore = fStoreManager.getObjectStore(repositoryId);
// Validation
TypeDefinition typeDef = getTypeDefinition(repositoryId, so);
boolean isCheckedOut = false;
isCheckedOut = isCheckedOut(so, user);
Map<String, PropertyData<?>> oldProperties = so.getProperties();
// check properties for validity
boolean cmis11 = context.getCmisVersion() != CmisVersion.CMIS_1_0;
validateProperties(repositoryId, so, properties, false, cmis11);
if (changeToken != null && changeToken.getValue() != null
&& Long.valueOf(so.getChangeToken()) > Long.valueOf(changeToken.getValue())) {
throw new CmisUpdateConflictException("updateProperties failed: changeToken does not match");
}
// update properties
boolean hasUpdatedProp = false;
// Find secondary type definitions to consider for update
List<String> existingSecondaryTypeIds = so.getSecondaryTypeIds();
@SuppressWarnings("unchecked")
PropertyData<String> pdSec = (PropertyData<String>) properties.getProperties().get(
PropertyIds.SECONDARY_OBJECT_TYPE_IDS);
List<String> newSecondaryTypeIds = pdSec == null ? null : pdSec.getValues();
Set<String> secondaryTypeIds = new HashSet<String>();
if (null != existingSecondaryTypeIds)
secondaryTypeIds.addAll(existingSecondaryTypeIds);
if (null != newSecondaryTypeIds)
secondaryTypeIds.addAll(newSecondaryTypeIds);
// Find secondary type definitions to delete (null means not set --> do
// not change, empty --> remove all secondary types)
if (null != newSecondaryTypeIds) {
List<String> propertiesIdToDelete = getListOfPropertiesToDeleteFromRemovedSecondaryTypes(repositoryId, so,
newSecondaryTypeIds);
for (String propIdToRemove : propertiesIdToDelete) {
so.getProperties().remove(propIdToRemove);
}
}
// update properties:
if (properties != null) {
for (String key : properties.getProperties().keySet()) {
if (key.equals(PropertyIds.NAME)) {
continue; // ignore here
}
PropertyData<?> value = properties.getProperties().get(key);
PropertyDefinition<?> propDef = typeDef.getPropertyDefinitions().get(key);
if (cmis11 && null == propDef) {
TypeDefinition typeDefSecondary = getSecondaryTypeDefinition(repositoryId, secondaryTypeIds, key);
if (null == typeDefSecondary)
throw new CmisInvalidArgumentException("Cannot update property " + key
+ ": not contained in type");
propDef = typeDefSecondary.getPropertyDefinitions().get(key);
}
if (null == propDef) {
throw new CmisInvalidArgumentException("Unknown property " + key
+ ": not contained in type (or any secondary type)");
}
if (value.getValues() == null || value.getFirstValue() == null) {
// delete property
// check if a required a property
if (propDef.isRequired()) {
throw new CmisConstraintException(
"updateProperties failed, following property can't be deleted, because it is required: "
+ key);
}
oldProperties.remove(key);
hasUpdatedProp = true;
} else {
if (propDef.getUpdatability() == Updatability.WHENCHECKEDOUT) {
if (!isCheckedOut)
throw new CmisUpdateConflictException(
"updateProperties failed, following property can't be updated, because it is not checked-out: "
+ key);
} else if (propDef.getUpdatability() != Updatability.READWRITE) {
throw new CmisConstraintException(
"updateProperties failed, following property can't be updated, because it is not writable: "
+ key);
}
oldProperties.put(key, value);
hasUpdatedProp = true;
}
}
// get name from properties and perform special rename to check if
// path already exists
PropertyData<?> pd = properties.getProperties().get(PropertyIds.NAME);
if (pd != null && so instanceof Filing) {
String newName = (String) pd.getFirstValue();
boolean hasParent = ((Filing) so).hasParent();
if (so instanceof Folder && !hasParent) {
throw new CmisConstraintException("updateProperties failed, you cannot rename the root folder");
}
if (newName == null || newName.equals("")) {
throw new CmisConstraintException("updateProperties failed, name must not be empty.");
}
if (!NameValidator.isValidName(newName)) {
throw new CmisInvalidArgumentException(NameValidator.ERROR_ILLEGAL_NAME);
}
// Note: the test for duplicated name in folder is left to the object store
ObjectStoreFiling objStoreFiling = (ObjectStoreFiling) objStore;
objStoreFiling.rename((Fileable)so, (String) pd.getFirstValue());
hasUpdatedProp = true;
}
}
if (hasUpdatedProp) {
// set user, creation date, etc.
if (user == null) {
user = "unknown";
}
so.updateSystemBasePropertiesWhenModified(properties.getProperties(), user);
// set changeToken
}
if (hasUpdatedProp) {
objectId.setValue(so.getId()); // might have a new id
if (null != changeToken) {
String changeTokenVal = so.getChangeToken();
LOG.debug("updateProperties(), new change token is: " + changeTokenVal);
changeToken.setValue(changeTokenVal);
}
}
if (null != acl) {
// TODO
LOG.warn("Setting ACLs is currently not supported by this implementation, acl is ignored");
// if implemented add this call:
// fAclService.appyAcl(context, repositoryId, acl, null,
// AclPropagation.OBJECTONLY,
// extension);
}
TypeManager tm = fStoreManager.getTypeManager(repositoryId);
ObjectData od = PropertyCreationHelper.getObjectData(tm, objStore, so, null, user, false, IncludeRelationships.NONE,
null, false, false, extension);
// To be able to provide all Atom links in the response we need
// additional information:
if (context.isObjectInfoRequired()) {
ObjectInfoImpl objectInfo = new ObjectInfoImpl();
fAtomLinkProvider.fillInformationForAtomLinks(repositoryId, so, od, objectInfo);
objectInfos.addObjectInfo(objectInfo);
}
LOG.debug("stop updateProperties()");
}
// CMIS 1.1
public void appendContentStream(CallContext context, String repositoryId, Holder<String> objectId,
Holder<String> changeToken, ContentStream contentStream, ExtensionsData extension) {
Content content;
LOG.debug("start appendContentStream()");
StoredObject so = validator.appendContentStream(context, repositoryId, objectId, extension);
if (changeToken != null && changeToken.getValue() != null
&& Long.valueOf(so.getChangeToken()) > Long.valueOf(changeToken.getValue())) {
throw new CmisUpdateConflictException("updateProperties failed: changeToken does not match");
}
if (!(so instanceof Document || so instanceof VersionedDocument || so instanceof DocumentVersion)) {
throw new CmisObjectNotFoundException("Id" + objectId
+ " does not refer to a document, but only documents can have content");
}
// validate content allowed
TypeDefinition typeDef = getTypeDefinition(repositoryId, so);
if (!(typeDef instanceof DocumentTypeDefinition))
throw new CmisInvalidArgumentException("Object does not refer to a document, can't set content");
TypeValidator.validateContentAllowed((DocumentTypeDefinition) typeDef, null != contentStream);
if (so instanceof Document) {
content = ((Document) so);
} else if (so instanceof DocumentVersion) {
// something that is versionable check the proper status of the
// object
String user = context.getUsername();
testHasProperCheckedOutStatus(so, user);
content = (DocumentVersion) so;
} else {
throw new IllegalArgumentException("Content cannot be set on this object (must be document or version)");
}
content.appendContent(contentStream);
so.updateSystemBasePropertiesWhenModified(null, context.getUsername()); }
public List<BulkUpdateObjectIdAndChangeToken> bulkUpdateProperties(CallContext context, String repositoryId,
List<BulkUpdateObjectIdAndChangeToken> objectIdAndChangeToken, Properties properties,
List<String> addSecondaryTypeIds, List<String> removeSecondaryTypeIds, ExtensionsData extension,
ObjectInfoHandler objectInfos) {
List<BulkUpdateObjectIdAndChangeToken> result = new ArrayList<BulkUpdateObjectIdAndChangeToken>();
for (BulkUpdateObjectIdAndChangeToken obj : objectIdAndChangeToken) {
Holder<String> objId = new Holder<String>(obj.getId());
Holder<String> changeToken = new Holder<String>(obj.getChangeToken());
try {
updateProperties(context, repositoryId, objId, changeToken, properties, null, null, objectInfos);
result.add(new BulkUpdateObjectIdAndChangeTokenImpl(obj.getId(), changeToken.getValue()));
} catch (Exception e) {
LOG.error("updating properties in bulk upadate failed for object" + obj.getId() + ": ", e);
}
}
return result;
}
// ///////////////////////////////////////////////////////
// private helper methods
private StoredObject createDocumentIntern(CallContext context, String repositoryId, Properties properties,
String folderId, ContentStream contentStream, VersioningState versioningState, List<String> policies,
Acl addACEs, Acl removeACEs, ExtensionsData extension) {
addACEs = org.apache.chemistry.opencmis.inmemory.TypeValidator.expandAclMakros(context.getUsername(), addACEs);
removeACEs = org.apache.chemistry.opencmis.inmemory.TypeValidator.expandAclMakros(context.getUsername(),
removeACEs);
validator.createDocument(context, repositoryId, folderId, policies, extension);
// Validation stuff
TypeValidator.validateRequiredSystemProperties(properties);
String user = context.getUsername();
TypeDefinition typeDef = getTypeDefinition(repositoryId, properties);
ObjectStore objectStore = fStoreManager.getObjectStore(repositoryId);
Map<String, PropertyData<?>> propMap = properties.getProperties();
// get name from properties
PropertyData<?> pd = propMap.get(PropertyIds.NAME);
String name = (String) pd.getFirstValue();
// validate ACL
TypeValidator.validateAcl(typeDef, addACEs, removeACEs);
Folder folder = null;
if (null != folderId) {
StoredObject so = objectStore.getObjectById(folderId);
if (null == so) {
throw new CmisInvalidArgumentException(" Cannot create document, folderId: " + folderId + " is invalid");
}
if (so instanceof Folder) {
folder = (Folder) so;
} else {
throw new CmisInvalidArgumentException("Can't creat document, folderId does not refer to a folder: "
+ folderId);
}
TypeValidator.validateAllowedChildObjectTypes(typeDef, folder.getAllowedChildObjectTypeIds());
}
// check if the given type is a document type
if (!typeDef.getBaseTypeId().equals(BaseTypeId.CMIS_DOCUMENT)) {
throw new CmisInvalidArgumentException("Cannot create a document, with a non-document type: "
+ typeDef.getId());
}
// check name syntax
if (!NameValidator.isValidName(name)) {
throw new CmisInvalidArgumentException(NameValidator.ERROR_ILLEGAL_NAME + " Name is: " + name);
}
// validate content allowed
TypeValidator.validateContentAllowed((DocumentTypeDefinition) typeDef, null != contentStream);
TypeValidator.validateVersionStateForCreate((DocumentTypeDefinition) typeDef, versioningState);
// set properties that are not set but have a default:
Map<String, PropertyData<?>> propMapNew = setDefaultProperties(typeDef, propMap);
if (propMapNew != propMap) {
properties = new PropertiesImpl(propMapNew.values());
propMap = propMapNew;
}
boolean cmis11 = context.getCmisVersion() != CmisVersion.CMIS_1_0;
validateProperties(repositoryId, null, properties, false, cmis11);
// set user, creation date, etc.
if (user == null) {
user = "unknown";
}
StoredObject so = null;
// check if content stream parameters are set and if not set some
// defaults
if (null != contentStream
&& (contentStream.getFileName() == null || contentStream.getFileName().length() == 0
|| contentStream.getMimeType() == null || contentStream.getMimeType().length() == 0)) {
ContentStreamImpl cs = new ContentStreamImpl();
cs.setStream(contentStream.getStream());
if (contentStream.getFileName() == null || contentStream.getFileName().length() == 0) {
cs.setFileName(name);
} else {
cs.setFileName(contentStream.getFileName());
}
cs.setLength(contentStream.getBigLength());
if (contentStream.getMimeType() == null || contentStream.getMimeType().length() == 0) {
cs.setMimeType("application/octet-stream");
} else {
cs.setMimeType(contentStream.getMimeType());
}
cs.setExtensions(contentStream.getExtensions());
contentStream = cs;
}
// Now we are sure to have document type definition:
if (((DocumentTypeDefinition) typeDef).isVersionable()) {
DocumentVersion version = objectStore.createVersionedDocument(name, propMap, user, folder, policies,
addACEs, removeACEs, contentStream, versioningState);
so = version; // return the version and not the version series to
// caller
} else {
Document doc = objectStore.createDocument(name, propMap, user, folder, policies, addACEs, removeACEs);
doc.setContent(contentStream, false);
so = doc;
}
return so;
}
private Folder createFolderIntern(CallContext context, String repositoryId, Properties properties, String folderId,
List<String> policies, Acl addACEs, Acl removeACEs, ExtensionsData extension) {
addACEs = org.apache.chemistry.opencmis.inmemory.TypeValidator.expandAclMakros(context.getUsername(), addACEs);
removeACEs = org.apache.chemistry.opencmis.inmemory.TypeValidator.expandAclMakros(context.getUsername(),
removeACEs);
validator.createFolder(context, repositoryId, folderId, policies, extension);
TypeValidator.validateRequiredSystemProperties(properties);
String user = context.getUsername();
ObjectStore fs = fStoreManager.getObjectStore(repositoryId);
Folder parent = null;
// get required properties
PropertyData<?> pd = properties.getProperties().get(PropertyIds.NAME);
String folderName = (String) pd.getFirstValue();
if (null == folderName || folderName.length() == 0) {
throw new CmisInvalidArgumentException("Cannot create a folder without a name.");
}
// check name syntax
if (!NameValidator.isValidName(folderName)) {
throw new CmisInvalidArgumentException(NameValidator.ERROR_ILLEGAL_NAME + " Name is: " + folderName);
}
TypeDefinition typeDef = getTypeDefinition(repositoryId, properties);
// check if the given type is a folder type
if (!typeDef.getBaseTypeId().equals(BaseTypeId.CMIS_FOLDER)) {
throw new CmisInvalidArgumentException("Cannot create a folder, with a non-folder type: " + typeDef.getId());
}
Map<String, PropertyData<?>> propMap = properties.getProperties();
Map<String, PropertyData<?>> propMapNew = setDefaultProperties(typeDef, propMap);
if (propMapNew != propMap) {
properties = new PropertiesImpl(propMapNew.values());
}
boolean cmis11 = context.getCmisVersion() != CmisVersion.CMIS_1_0;
validateProperties(repositoryId, null, properties, false, cmis11);
// validate ACL
TypeValidator.validateAcl(typeDef, addACEs, removeACEs);
StoredObject so = null;
// create folder
try {
LOG.debug("get folder for id: " + folderId);
so = fs.getObjectById(folderId);
} catch (Exception e) {
throw new CmisObjectNotFoundException("Failed to retrieve folder.", e);
}
if (so instanceof Folder) {
parent = (Folder) so;
} else {
throw new CmisInvalidArgumentException("Can't create folder, folderId does not refer to a folder: "
+ folderId);
}
if (user == null) {
user = "unknown";
}
ObjectStore objStore = fStoreManager.getObjectStore(repositoryId);
Folder newFolder = objStore.createFolder(folderName, properties.getProperties(), user, parent, policies,
addACEs, removeACEs);
LOG.debug("stop createFolder()");
return newFolder;
}
private StoredObject createPolicyIntern(CallContext context, String repositoryId, Properties properties,
String folderId, List<String> policies, Acl addAces, Acl removeAces, ExtensionsData extension) {
validator.createPolicy(context, repositoryId, folderId, addAces, removeAces, policies, extension);
addAces = org.apache.chemistry.opencmis.inmemory.TypeValidator.expandAclMakros(context.getUsername(), addAces);
removeAces = org.apache.chemistry.opencmis.inmemory.TypeValidator.expandAclMakros(context.getUsername(),
removeAces);
String user = context.getUsername();
Map<String, PropertyData<?>> propMap = properties.getProperties();
// get name from properties
PropertyData<?> pd = propMap.get(PropertyIds.NAME);
String name = (String) pd.getFirstValue();
pd = propMap.get(PropertyIds.POLICY_TEXT);
String policyText = (String) pd.getFirstValue();
ObjectStore objStore = fStoreManager.getObjectStore(repositoryId);
StoredObject storedObject = objStore.createPolicy(name, policyText, propMap, user);
return storedObject;
}
private StoredObject createRelationshipIntern(CallContext context, String repositoryId, Properties properties,
List<String> policies, Acl addACEs, Acl removeACEs, ExtensionsData extension) {
TypeValidator.validateRequiredSystemProperties(properties);
String user = context.getUsername();
addACEs = org.apache.chemistry.opencmis.inmemory.TypeValidator.expandAclMakros(context.getUsername(), addACEs);
removeACEs = org.apache.chemistry.opencmis.inmemory.TypeValidator.expandAclMakros(context.getUsername(),
removeACEs);
// get required properties
PropertyData<?> pd = properties.getProperties().get(PropertyIds.SOURCE_ID);
String sourceId = (String) pd.getFirstValue();
if (null == sourceId || sourceId.length() == 0)
throw new CmisInvalidArgumentException("Cannot create a relationship without a sourceId.");
pd = properties.getProperties().get(PropertyIds.TARGET_ID);
String targetId = (String) pd.getFirstValue();
if (null == targetId || targetId.length() == 0)
throw new CmisInvalidArgumentException("Cannot create a relationship without a targetId.");
TypeDefinition typeDef = getTypeDefinition(repositoryId, properties);
// check if the given type is a relationship type
if (!typeDef.getBaseTypeId().equals(BaseTypeId.CMIS_RELATIONSHIP))
throw new CmisInvalidArgumentException("Cannot create a relationship, with a non-relationship type: "
+ typeDef.getId());
StoredObject[] relationObjects = validator.createRelationship(context, repositoryId, sourceId, targetId,
policies, extension);
// set default properties
Map<String, PropertyData<?>> propMap = properties.getProperties();
Map<String, PropertyData<?>> propMapNew = setDefaultProperties(typeDef, propMap);
if (propMapNew != propMap) {
properties = new PropertiesImpl(propMapNew.values());
}
boolean cmis11 = context.getCmisVersion() != CmisVersion.CMIS_1_0;
validateProperties(repositoryId, null, properties, false, cmis11);
// validate ACL
TypeValidator.validateAcl(typeDef, addACEs, removeACEs);
// validate the allowed types of the relationship
ObjectStore objStore = fStoreManager.getObjectStore(repositoryId);
TypeDefinition sourceTypeDef = fStoreManager.getTypeById(repositoryId,
objStore.getObjectById(sourceId).getTypeId()).getTypeDefinition();
TypeDefinition targetTypeDef = fStoreManager.getTypeById(repositoryId,
objStore.getObjectById(targetId).getTypeId()).getTypeDefinition();
TypeValidator.validateAllowedRelationshipTypes((RelationshipTypeDefinition) typeDef, sourceTypeDef,
targetTypeDef);
// get name from properties
pd = propMap.get(PropertyIds.NAME);
String name = (String) pd.getFirstValue();
// StoredObject storedObject = objStore.createRelationship(
// relationObjects[0], relationObjects[1],
// propMap, user, addACEs, removeACEs);
StoredObject storedObject = objStore.createRelationship(name, relationObjects[0], relationObjects[1], propMap,
user, addACEs, removeACEs);
return storedObject;
}
private StoredObject createItemIntern(CallContext context, String repositoryId, Properties properties,
String folderId, List<String> policies, Acl addACEs, Acl removeACEs, ExtensionsData extension) {
validator.createItem(context, repositoryId, properties, folderId, policies, addACEs, removeACEs, extension);
addACEs = org.apache.chemistry.opencmis.inmemory.TypeValidator.expandAclMakros(context.getUsername(), addACEs);
removeACEs = org.apache.chemistry.opencmis.inmemory.TypeValidator.expandAclMakros(context.getUsername(),
removeACEs);
validator.createDocument(context, repositoryId, folderId, policies, extension);
// Validation stuff
TypeValidator.validateRequiredSystemProperties(properties);
String user = context.getUsername();
TypeDefinition typeDef = getTypeDefinition(repositoryId, properties);
ObjectStore objectStore = fStoreManager.getObjectStore(repositoryId);
Map<String, PropertyData<?>> propMap = properties.getProperties();
// get name from properties
PropertyData<?> pd = propMap.get(PropertyIds.NAME);
String name = (String) pd.getFirstValue();
// validate ACL
TypeValidator.validateAcl(typeDef, addACEs, removeACEs);
Folder folder = null;
if (null != folderId) {
StoredObject so = objectStore.getObjectById(folderId);
if (null == so) {
throw new CmisInvalidArgumentException(" Cannot create item, folderId: " + folderId + " is invalid");
}
if (so instanceof Folder) {
folder = (Folder) so;
} else {
throw new CmisInvalidArgumentException("Can't create item, folderId does not refer to a folder: "
+ folderId);
}
TypeValidator.validateAllowedChildObjectTypes(typeDef, folder.getAllowedChildObjectTypeIds());
}
// check if the given type is an item type
if (!typeDef.getBaseTypeId().equals(BaseTypeId.CMIS_ITEM)) {
throw new CmisInvalidArgumentException("Cannot create an item, with a non-item type: " + typeDef.getId());
}
// check name syntax
if (!NameValidator.isValidName(name)) {
throw new CmisInvalidArgumentException(NameValidator.ERROR_ILLEGAL_NAME + " Name is: " + name);
}
// set properties that are not set but have a default:
Map<String, PropertyData<?>> propMapNew = setDefaultProperties(typeDef, propMap);
if (propMapNew != propMap) {
properties = new PropertiesImpl(propMapNew.values());
propMap = propMapNew;
}
boolean cmis11 = context.getCmisVersion() != CmisVersion.CMIS_1_0;
validateProperties(repositoryId, null, properties, false, cmis11);
// set user, creation date, etc.
if (user == null) {
user = "unknown";
}
StoredObject so = null;
// Now we are sure to have document type definition:
so = objectStore.createItem(name, propMap, user, folder, policies, addACEs, removeACEs);
return so;
}
private boolean hasDescendant(String user, ObjectStore objStore, Folder sourceFolder, Folder targetFolder) {
String sourceId = sourceFolder.getId();
String targetId = targetFolder.getId();
while (targetId != null) {
if (targetId.equals(sourceId)) {
return true;
}
List<String>parentIds = ((ObjectStoreFiling)objStore).getParentIds(targetFolder, user);
targetId = parentIds == null || parentIds.isEmpty() ? null : parentIds.get(0);
if (null != targetId) {
targetFolder = (Folder) objStore.getObjectById(targetId);
}
}
return false;
}
/**
* Recursively delete a tree by traversing it and first deleting all
* children and then the object itself
*
* @param objStore
* @param parentFolder
* @param continueOnFailure
* @param allVersions
* @param failedToDeleteIds
* @return returns true if operation should continue, false if it should
* stop
*/
private boolean deleteRecursive(ObjectStore objStore, Folder parentFolder, boolean continueOnFailure,
boolean allVersions, List<String> failedToDeleteIds, String user) {
ObjectStoreFiling filingStore = (ObjectStoreFiling) objStore;
ChildrenResult childrenResult = filingStore.getChildren(parentFolder, -1, -1, "Admin", true);
List<Fileable> children = childrenResult.getChildren();
if (null == children) {
return true;
}
for (Fileable child : children) {
if (child instanceof Folder) {
boolean mustContinue = deleteRecursive(objStore, (Folder) child, continueOnFailure, allVersions,
failedToDeleteIds, user);
if (!mustContinue && !continueOnFailure) {
return false; // stop further deletions
}
} else {
try {
objStore.deleteObject(child.getId(), allVersions, user);
} catch (Exception e) {
failedToDeleteIds.add(child.getId());
}
}
}
objStore.deleteObject(parentFolder.getId(), allVersions, user);
return true;
}
private static ContentStream getContentStream(StoredObject so, String streamId, BigInteger offset, BigInteger length) {
ContentStream csd = null;
long lOffset = offset == null ? 0 : offset.longValue();
long lLength = length == null ? -1 : length.longValue();
if (streamId == null) {
csd = ((Content) so).getContent(lOffset, lLength);
return csd;
} else if (streamId.endsWith("-rendition")) {
csd = so.getRenditionContent(streamId, lOffset, lLength);
}
return csd;
}
private Map<String, PropertyData<?>> setDefaultProperties(TypeDefinition typeDef,
Map<String, PropertyData<?>> properties) {
Map<String, PropertyDefinition<?>> propDefs = typeDef.getPropertyDefinitions();
boolean hasCopied = false;
for (PropertyDefinition<?> propDef : propDefs.values()) {
String propId = propDef.getId();
List<?> defaultVal = propDef.getDefaultValue();
if (defaultVal != null && null == properties.get(propId)) {
if (!hasCopied) {
properties = new HashMap<String, PropertyData<?>>(properties); // copy
// because
// it
// is
// an
// unmodified
// collection
hasCopied = true;
}
Object value = propDef.getCardinality() == Cardinality.SINGLE ? defaultVal.get(0) : defaultVal;
PropertyData<?> pd = fStoreManager.getObjectFactory().createPropertyData(propDef, value);
// set property:
properties.put(propId, pd);
}
}
return properties;
}
private void validateProperties(String repositoryId, StoredObject so, Properties properties,
boolean checkMandatory, boolean cmis11) {
TypeDefinition typeDef;
if (null != so)
typeDef = getTypeDefinition(repositoryId, so);
else
typeDef = getTypeDefinition(repositoryId, properties);
// check properties for validity
if (!cmis11) {
TypeValidator.validateProperties(typeDef, properties, checkMandatory, cmis11);
return;
}
// CMIS 1.1 secondary types
PropertyData<?> pd = properties.getProperties().get(PropertyIds.SECONDARY_OBJECT_TYPE_IDS);
@SuppressWarnings("unchecked")
List<String> secondaryTypeIds = (List<String>) (pd == null ? null : pd.getValues());
// if no secondary types are passed use the existing ones:
if (null != so && (null == secondaryTypeIds || secondaryTypeIds.size() == 0)) {
secondaryTypeIds = so.getSecondaryTypeIds();
}
if (null != secondaryTypeIds && secondaryTypeIds.size() != 0) {
List<String> allTypeIds = new ArrayList<String>(secondaryTypeIds);
allTypeIds.add(typeDef.getId());
List<TypeDefinition> typeDefs = getTypeDefinition(repositoryId, allTypeIds);
TypeValidator.validateProperties(typeDefs, properties, checkMandatory);
} else {
TypeValidator.validateProperties(typeDef, properties, checkMandatory, true);
}
}
private TypeDefinition getSecondaryTypeDefinition(String repositoryId, Set<String> secondaryTypeIds,
String propertyId) {
if (null == secondaryTypeIds || secondaryTypeIds.isEmpty())
return null;
for (String typeId : secondaryTypeIds) {
TypeDefinitionContainer typeDefC = fStoreManager.getTypeById(repositoryId, typeId);
TypeDefinition typeDef = typeDefC.getTypeDefinition();
if (TypeValidator.typeContainsProperty(typeDef, propertyId)) {
return typeDef;
}
}
return null;
}
private List<String> getListOfPropertiesToDeleteFromRemovedSecondaryTypes(String repositoryId, StoredObject so,
List<String> newSecondaryTypeIds) {
List<String> propertiesToDelete = new ArrayList<String>(); // properties
// id to be
// removed
// calculate delta to be removed
List<String> existingSecondaryTypeIds = so.getSecondaryTypeIds();
List<String> delta = new ArrayList<String>(existingSecondaryTypeIds);
delta.removeAll(newSecondaryTypeIds);
for (String typeDefId : delta) {
TypeDefinitionContainer typeDefC = fStoreManager.getTypeById(repositoryId, typeDefId);
TypeDefinition typeDef = typeDefC.getTypeDefinition();
propertiesToDelete.addAll(typeDef.getPropertyDefinitions().keySet());
}
// TODO: the list may contain too many properties, if the same property
// is also in a type not to be removed
return propertiesToDelete;
}
}