
org.structr.files.cmis.CMISObjectService Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of structr-ui Show documentation
Show all versions of structr-ui Show documentation
Structr is an open source framework based on the popular Neo4j graph database.
The newest version!
/**
* Copyright (C) 2010-2016 Structr GmbH
*
* This file is part of Structr .
*
* Structr is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* Structr is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Structr. If not, see .
*/
package org.structr.files.cmis;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigInteger;
import java.util.LinkedList;
import java.util.List;
import java.util.Map.Entry;
import java.util.logging.Level;
import java.util.logging.Logger;
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.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.RenditionData;
import org.apache.chemistry.opencmis.commons.enums.BaseTypeId;
import org.apache.chemistry.opencmis.commons.enums.IncludeRelationships;
import org.apache.chemistry.opencmis.commons.enums.UnfileObject;
import org.apache.chemistry.opencmis.commons.enums.VersioningState;
import org.apache.chemistry.opencmis.commons.exceptions.CmisConstraintException;
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.CmisPermissionDeniedException;
import org.apache.chemistry.opencmis.commons.exceptions.CmisRuntimeException;
import org.apache.chemistry.opencmis.commons.impl.IOUtils;
import org.apache.chemistry.opencmis.commons.impl.dataobjects.ContentStreamImpl;
import org.apache.chemistry.opencmis.commons.impl.dataobjects.FailedToDeleteDataImpl;
import org.apache.chemistry.opencmis.commons.spi.Holder;
import org.apache.chemistry.opencmis.commons.spi.ObjectService;
import org.structr.cmis.CMISInfo;
import org.structr.cmis.wrapper.CMISObjectWrapper;
import org.structr.common.Permission;
import org.structr.common.SecurityContext;
import org.structr.common.error.FrameworkException;
import org.structr.core.GraphObject;
import org.structr.core.app.App;
import org.structr.core.app.StructrApp;
import org.structr.core.entity.Principal;
import org.structr.core.graph.NodeInterface;
import org.structr.core.graph.Tx;
import org.structr.core.property.PropertyKey;
import org.structr.core.property.PropertyMap;
import org.structr.dynamic.File;
import org.structr.files.cmis.wrapper.CMISContentStream;
import org.structr.files.cmis.wrapper.CMISPagingListWrapper;
import org.structr.web.common.FileHelper;
import org.structr.web.entity.AbstractFile;
import org.structr.web.entity.FileBase;
import org.structr.web.entity.Folder;
/**
*
*
*/
public class CMISObjectService extends AbstractStructrCmisService implements ObjectService {
private static final Logger logger = Logger.getLogger(CMISObjectService.class.getName());
public CMISObjectService(final StructrCMISService parentService, final SecurityContext securityContext) {
super(parentService, securityContext);
}
@Override
public String createDocument(final String repositoryId, final Properties properties, final String folderId, final ContentStream contentStream, final VersioningState versioningState, final List policies, final Acl addAces, final Acl removeAces, final ExtensionsData extension) {
final App app = StructrApp.getInstance(securityContext);
File newFile = null;
String uuid = null;
try (final Tx tx = app.tx()) {
final String objectTypeId = getStringValue(properties, PropertyIds.OBJECT_TYPE_ID);
final String fileName = getStringValue(properties, PropertyIds.NAME);
final Class type = typeFromObjectTypeId(objectTypeId, BaseTypeId.CMIS_DOCUMENT, File.class);
// check if type exists
if (type != null) {
// check that base type is cmis:folder
final BaseTypeId baseTypeId = getBaseTypeId(type);
if (baseTypeId != null && BaseTypeId.CMIS_DOCUMENT.equals(baseTypeId)) {
final String mimeType = contentStream != null ? contentStream.getMimeType() : null;
// create file
newFile = FileHelper.createFile(securityContext, new byte[0], mimeType, type, fileName);
// find and set parent if it exists
if (!CMISInfo.ROOT_FOLDER_ID.equals(folderId)) {
final Folder parent = app.get(Folder.class, folderId);
if (parent != null) {
newFile.setProperty(Folder.parent, parent);
} else {
throw new CmisObjectNotFoundException("Folder with ID " + folderId + " does not exist");
}
}
uuid = newFile.getUuid();
if (contentStream != null) {
final InputStream inputStream = contentStream.getStream();
if (inputStream != null) {
// copy file and update metadata
try (final OutputStream outputStream = newFile.getOutputStream(false)) {
IOUtils.copy(inputStream, outputStream);
}
inputStream.close();
FileHelper.updateMetadata(newFile);
}
}
} else {
throw new CmisConstraintException("Cannot create cmis:document of type " + objectTypeId);
}
} else {
throw new CmisObjectNotFoundException("Type with ID " + objectTypeId + " does not exist");
}
tx.success();
} catch (Throwable t) {
throw new CmisRuntimeException("New document could not be created: " + t.getMessage());
}
// start indexing after transaction is finished
if (newFile != null) {
newFile.notifyUploadCompletion();
}
return uuid;
}
@Override
public String createDocumentFromSource(String repositoryId, String sourceId, Properties properties, String folderId, VersioningState versioningState, List policies, Acl addAces, Acl removeAces, ExtensionsData extension) {
// copy existing document
final App app = StructrApp.getInstance(securityContext);
String uuid = null;
try (final Tx tx = app.tx()) {
final FileBase existingDocument = app.get(FileBase.class, sourceId);
if (existingDocument != null) {
try (final InputStream inputStream = existingDocument.getInputStream()) {
final ContentStreamImpl copyContentStream = new ContentStreamImpl();
copyContentStream.setFileName(existingDocument.getName());
copyContentStream.setMimeType(existingDocument.getContentType());
copyContentStream.setLength(BigInteger.valueOf(existingDocument.getSize()));
copyContentStream.setStream(inputStream);
uuid = createDocument(repositoryId, properties, folderId, copyContentStream, versioningState, policies, addAces, removeAces, extension);
}
} else {
throw new CmisObjectNotFoundException("Document with ID " + sourceId + " does not exist");
}
tx.success();
} catch (Throwable t) {
throw new CmisRuntimeException("New document could not be created: " + t.getMessage());
}
return uuid;
}
@Override
public String createFolder(final String repositoryId, final Properties properties, final String folderId, final List policies, final Acl addAces, final Acl removeAces, final ExtensionsData extension) {
final App app = StructrApp.getInstance(securityContext);
String uuid = null;
try (final Tx tx = app.tx()) {
final String objectTypeId = getStringValue(properties, PropertyIds.OBJECT_TYPE_ID);
final Class type = typeFromObjectTypeId(objectTypeId, BaseTypeId.CMIS_FOLDER, Folder.class);
// check if type exists
if (type != null) {
// check that base type is cmis:folder
final BaseTypeId baseTypeId = getBaseTypeId(type);
if (baseTypeId != null && BaseTypeId.CMIS_FOLDER.equals(baseTypeId)) {
// create folder
final NodeInterface newFolder = app.create(type, PropertyMap.cmisTypeToJavaType(securityContext, type, properties));
// find and set parent if it exists
if (!CMISInfo.ROOT_FOLDER_ID.equals(folderId)) {
final Folder parent = app.get(Folder.class, folderId);
if (parent != null) {
newFolder.setProperty(Folder.parent, parent);
} else {
throw new CmisObjectNotFoundException("Folder with ID " + folderId + " does not exist");
}
}
uuid = newFolder.getUuid();
} else {
throw new CmisConstraintException("Cannot create cmis:folder of type " + objectTypeId);
}
} else {
throw new CmisObjectNotFoundException("Type with ID " + objectTypeId + " does not exist");
}
tx.success();
} catch (Throwable t) {
throw new CmisRuntimeException("New folder could not be created: " + t.getMessage());
}
return uuid;
}
@Override
public String createRelationship(String repositoryId, Properties properties, List policies, Acl addAces, Acl removeAces, ExtensionsData extension) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public String createPolicy(String repositoryId, Properties properties, String folderId, List policies, Acl addAces, Acl removeAces, ExtensionsData extension) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public String createItem(String repositoryId, Properties properties, String folderId, List policies, Acl addAces, Acl removeAces, ExtensionsData extension) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public AllowableActions getAllowableActions(String repositoryId, String objectId, ExtensionsData extension) {
final ObjectData obj = getObject(repositoryId, objectId, null, true, IncludeRelationships.NONE, null, false, false, extension);
if (obj != null) {
return obj.getAllowableActions();
}
throw new CmisObjectNotFoundException("Object with ID " + objectId + " does not exist");
}
@Override
public ObjectData getObject(final String repositoryId, final String objectId, final String propertyFilter, final Boolean includeAllowableActions, final IncludeRelationships includeRelationships, final String renditionFilter, final Boolean includePolicyIds, final Boolean includeAcl, final ExtensionsData extension) {
final App app = StructrApp.getInstance();
try (final Tx tx = app.tx()) {
final GraphObject obj = app.get(objectId);
if (obj != null) {
final ObjectData data = CMISObjectWrapper.wrap(obj, propertyFilter, includeAllowableActions);
tx.success();
return data;
}
} catch (Throwable t) {
logger.log(Level.WARNING, "", t);
}
throw new CmisObjectNotFoundException("Object with ID " + objectId + " does not exist");
}
@Override
public Properties getProperties(final String repositoryId, final String objectId, final String propertyFilter, final ExtensionsData extension) {
final ObjectData obj = getObject(repositoryId, objectId, propertyFilter, false, IncludeRelationships.NONE, null, false, false, extension);
if (obj != null) {
return obj.getProperties();
}
throw new CmisObjectNotFoundException("Object with ID " + objectId + " does not exist");
}
@Override
public List getRenditions(final String repositoryId, final String objectId, final String renditionFilter, final BigInteger maxItems, final BigInteger skipCount, final ExtensionsData extension) {
final ObjectData obj = getObject(repositoryId, objectId, renditionFilter, false, IncludeRelationships.NONE, null, false, false, extension);
if (obj != null) {
return new CMISPagingListWrapper<>(obj.getRenditions(), maxItems, skipCount).getPagedList();
}
throw new CmisObjectNotFoundException("Object with ID " + objectId + " does not exist");
}
@Override
public ObjectData getObjectByPath(final String repositoryId, final String path, final String propertyFilter, final Boolean includeAllowableActions, final IncludeRelationships includeRelationships, final String renditionFilter, final Boolean includePolicyIds, final Boolean includeAcl, final ExtensionsData extension) {
final App app = StructrApp.getInstance();
ObjectData result = null;
try (final Tx tx = app.tx()) {
final AbstractFile file = app.nodeQuery(AbstractFile.class).and(AbstractFile.path, path).getFirst();
if (file != null) {
result = CMISObjectWrapper.wrap(file, propertyFilter, includeAllowableActions);
}
tx.success();
} catch (Throwable t) {
logger.log(Level.WARNING, "", t);
}
if (result != null) {
return result;
}
throw new CmisObjectNotFoundException("Object with path " + path + " does not exist");
}
@Override
public ContentStream getContentStream(final String repositoryId, final String objectId, final String streamId, final BigInteger offset, final BigInteger length, final ExtensionsData extension) {
final App app = StructrApp.getInstance();
ContentStreamImpl result = null;
try (final Tx tx = app.tx()) {
final FileBase file = app.get(FileBase.class, objectId);
if (file != null) {
return new CMISContentStream(file, offset, length);
}
tx.success();
} catch (Throwable t) {
logger.log(Level.WARNING, "", t);
}
if (result != null) {
return result;
}
throw new CmisObjectNotFoundException("Object with ID " + objectId + " does not exist");
}
@Override
public void updateProperties(final String repositoryId, final Holder objectId, final Holder changeToken, final Properties properties, final ExtensionsData extension) {
final App app = StructrApp.getInstance();
final String id = objectId.getValue();
try (final Tx tx = app.tx()) {
final GraphObject obj = app.get(id);
if (obj != null) {
final PropertyMap propertyMap = PropertyMap.cmisTypeToJavaType(securityContext, obj.getClass(), properties);
if (propertyMap != null) {
for (final Entry entry : propertyMap.entrySet()) {
obj.setProperty(entry.getKey(), entry.getValue());
}
}
} else {
throw new CmisObjectNotFoundException("Object with ID " + objectId + " does not exist");
}
tx.success();
} catch (FrameworkException fex) {
throw new CmisConstraintException(fex.getMessage(), fex);
}
}
@Override
public List bulkUpdateProperties(final String repositoryId, final List objectIdsAndChangeTokens, final Properties properties, final List addSecondaryTypeIds, final List removeSecondaryTypeIds, final ExtensionsData extension) {
final List result = new LinkedList<>();
final App app = StructrApp.getInstance(securityContext);
try (final Tx tx = app.tx()) {
for (final BulkUpdateObjectIdAndChangeToken token : objectIdsAndChangeTokens) {
final GraphObject obj = app.get(token.getId());
if (obj != null) {
final PropertyMap propertyMap = PropertyMap.cmisTypeToJavaType(securityContext, obj.getClass(), properties);
if (propertyMap != null) {
for (final Entry entry : propertyMap.entrySet()) {
obj.setProperty(entry.getKey(), entry.getValue());
}
}
result.add(token);
}
}
tx.success();
} catch (FrameworkException fex) {
throw new CmisConstraintException(fex.getMessage(), fex);
}
return result;
}
@Override
public void moveObject(String repositoryId, final Holder objectId, final String targetFolderId, final String sourceFolderId, final ExtensionsData extension) {
if (sourceFolderId != null && targetFolderId != null) {
if (sourceFolderId.equals(targetFolderId)) {
return;
}
final App app = StructrApp.getInstance(securityContext);
try (final Tx tx = app.tx()) {
final FileBase file = get(app, FileBase.class, objectId.getValue());
final Folder parent = file.getProperty(FileBase.parent);
// check if the file to be moved is filed in the root folder (=> null parent)
if (CMISInfo.ROOT_FOLDER_ID.equals(sourceFolderId) && parent != null) {
throw new CmisInvalidArgumentException("Object with ID " + objectId.getValue() + " is not filed in folder with ID " + sourceFolderId);
}
// check if the file to be moved is filed in the given source folder
if (parent != null && !sourceFolderId.equals(parent.getUuid())) {
throw new CmisInvalidArgumentException("Object with ID " + objectId.getValue() + " is not filed in folder with ID " + sourceFolderId);
}
// check if the target folder is the root folder
if (CMISInfo.ROOT_FOLDER_ID.equals(targetFolderId)) {
// root folder => null parent
file.setProperty(FileBase.parent, null);
} else {
// get will throw an exception if the folder doesn't exist
file.setProperty(FileBase.parent, get(app, Folder.class, targetFolderId));
}
tx.success();
} catch (FrameworkException fex) {
throw new CmisConstraintException(fex.getMessage(), fex);
}
} else {
throw new CmisInvalidArgumentException("Source and target folder must be set");
}
}
@Override
public void deleteObject(String repositoryId, String objectId, Boolean allVersions, ExtensionsData extension) {
final App app = StructrApp.getInstance(securityContext);
try (final Tx tx = app.tx()) {
final Principal principal = securityContext.getUser(false);
final GraphObject obj = app.get(objectId);
if (obj != null) {
if (principal.isGranted(Permission.delete, securityContext)) {
if (obj.isNode()) {
// getSyncNode() returns the node or null
app.delete(obj.getSyncNode());
} else {
// getSyncRelationship() return the relationship or null
app.delete(obj.getSyncRelationship());
}
} else {
throw new CmisPermissionDeniedException("Cannot delete object with ID " + objectId);
}
} else {
throw new CmisObjectNotFoundException("Object with ID " + objectId + " does not exist");
}
tx.success();
} catch (FrameworkException fex) {
throw new CmisConstraintException(fex.getMessage(), fex);
}
}
@Override
public FailedToDeleteData deleteTree(final String repositoryId, final String folderId, final Boolean allVersions, final UnfileObject unfileObjects, final Boolean continueOnFailure, final ExtensionsData extension) {
/**
* - allVersions can be ignored as long as we don't support versioning
* - unfileObjects
*/
if (UnfileObject.UNFILE.equals(unfileObjects)) {
throw new CmisNotSupportedException("Unfiling not supported");
}
final App app = StructrApp.getInstance(securityContext);
final FailedToDeleteDataImpl result = new FailedToDeleteDataImpl();
result.setIds(new LinkedList());
try (final Tx tx = app.tx()) {
final Folder folder = app.get(Folder.class, folderId);
if (folder != null) {
recursivelyCheckAndDeleteFiles(app, result, folder, continueOnFailure);
} else {
throw new CmisObjectNotFoundException("Folder with ID " + folderId + " does not exist");
}
tx.success();
} catch (final FrameworkException fex) {
logger.log(Level.WARNING, "", fex);
}
return result;
}
@Override
public void setContentStream(String repositoryId, Holder objectId, Boolean overwriteFlag, Holder changeToken, ContentStream contentStream, ExtensionsData extension) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void deleteContentStream(String repositoryId, Holder objectId, Holder changeToken, ExtensionsData extension) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void appendContentStream(String repositoryId, Holder objectId, Holder changeToken, ContentStream contentStream, boolean isLastChunk, ExtensionsData extension) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
// ----- private methods -----
private void recursivelyCheckAndDeleteFiles(final App app, final FailedToDeleteDataImpl result, final AbstractFile toDelete, final Boolean continueOnFailure) throws FrameworkException {
if (toDelete != null) {
final Principal owner = toDelete.getOwnerNode();
if (owner == null || owner.isGranted(Permission.delete, securityContext)) {
app.delete(toDelete);
for (final AbstractFile child : toDelete.getProperty(AbstractFile.children)) {
recursivelyCheckAndDeleteFiles(app, result, child, continueOnFailure);
}
} else {
if (continueOnFailure) {
result.getIds().add(toDelete.getUuid());
} else {
throw new CmisPermissionDeniedException("Cannot delete object with ID " + toDelete.getUuid());
}
}
}
}
private T get(final App app, final Class type, final String id) throws FrameworkException {
final T obj = app.get(type, id);
if (obj != null) {
return obj;
}
throw new CmisObjectNotFoundException("Object with ID " + id + " does not exist");
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy