/*
* Copyright (c) 2006, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* 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.
*/
package org.wso2.carbon.registry.cmis;
import org.apache.chemistry.opencmis.commons.PropertyIds;
import org.apache.chemistry.opencmis.commons.data.*;
import org.apache.chemistry.opencmis.commons.data.Properties;
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.*;
import org.apache.chemistry.opencmis.commons.exceptions.*;
import org.apache.chemistry.opencmis.commons.impl.dataobjects.*;
import org.apache.chemistry.opencmis.commons.server.ObjectInfoHandler;
import org.apache.chemistry.opencmis.commons.spi.Holder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.wso2.carbon.registry.cmis.util.CMISConstants;
import org.wso2.carbon.registry.cmis.util.CommonUtil;
import org.wso2.carbon.registry.cmis.util.PropertyHelper;
import org.wso2.carbon.registry.core.Collection;
import org.wso2.carbon.registry.core.Registry;
import org.wso2.carbon.registry.core.Resource;
import org.wso2.carbon.registry.core.exceptions.RegistryException;
import org.wso2.carbon.registry.cmis.impl.DocumentTypeHandler;
import org.wso2.carbon.registry.cmis.impl.FolderTypeHandler;
import org.wso2.carbon.registry.cmis.impl.UnversionedDocumentTypeHandler;
import java.math.BigInteger;
import java.util.*;
/**
* This class represents the WSO2 Governance Registry back-end for the CMIS server.
*/
public class CMISRepository {
private static final Logger log = LoggerFactory.getLogger(CMISRepository.class);
private final Registry repository;
private final RegistryTypeManager typeManager;
private final PathManager pathManager;
private final String REPOSITORY_ID = "WSO2 CMIS Repository";
/**
* Create a new <code>org.wso2.registry.chemistry.greg.CMISRepository</code> instance backed by a Governance Registry repository.
*
* @param repository the CMIS repository
* @param pathManager
* @param typeManager
*
*/
public CMISRepository(Registry repository, PathManager pathManager, RegistryTypeManager typeManager) {
this.repository = repository;
this.typeManager = typeManager;
this.pathManager = pathManager;
}
public Registry getRegistry(){
return repository;
}
private String getRepositoryId(){
return REPOSITORY_ID;
}
/**
* See CMIS 1.0 section 2.2.2.2 getRepositoryInfo
*/
public RepositoryInfo getRepositoryInfo() {
if(log.isTraceEnabled()) {
log.trace("<<<<<<<< getRepositoryInfo");
}
return compileRepositoryInfo(getRepositoryId());
}
/**
* See CMIS 1.0 section 2.2.2.2 getRepositoryInfo
*/
public List<RepositoryInfo> getRepositoryInfos() {
ArrayList<RepositoryInfo> infos = new ArrayList<RepositoryInfo>();
infos.add(compileRepositoryInfo(getRepositoryId()));
return infos;
}
/**
* See CMIS 1.0 section 2.2.2.3 getTypeChildren
*/
public TypeDefinitionList getTypeChildren(String typeId, boolean includePropertyDefinitions,
BigInteger maxItems, BigInteger skipCount) {
if(log.isTraceEnabled()) {
log.trace("<<<<<<< getTypesChildren for type id " + typeId);
}
return typeManager.getTypeChildren(typeId, includePropertyDefinitions, maxItems, skipCount);
}
/**
* See CMIS 1.0 section 2.2.2.5 getTypeDefinition
*/
public TypeDefinition getTypeDefinition(String typeId) {
if(log.isTraceEnabled()){
log.trace("<<<<<<< getTypeDefinition for type id " + typeId);
}
TypeDefinition type = typeManager.getType(typeId);
if (type == null) {
throw new CmisObjectNotFoundException("Type '" + typeId + "' is unknown!");
}
return RegistryTypeManager.copyTypeDefinition(type);
}
/**
* See CMIS 1.0 section 2.2.2.4 getTypeDescendants
*/
public List<TypeDefinitionContainer> getTypesDescendants(String typeId, BigInteger depth,
Boolean includePropertyDefinitions) {
return typeManager.getTypesDescendants(typeId, depth, includePropertyDefinitions);
}
/**
* See CMIS 1.0 section 2.2.4.1 createDocument
*/
public String createDocument(Properties properties, String folderId, ContentStream contentStream,
VersioningState versioningState) {
if(log.isTraceEnabled()) {
log.trace("<<<<<<< Creating the document for folder Id:" + folderId
+ "versioning state:" + versioningState.toString() );
}
// check properties
if (!CommonUtil.isNonEmptyProperties(properties)) {
throw new CmisInvalidArgumentException("Properties must be set!");
}
// check type
String typeId = PropertyHelper.getTypeId(properties);
TypeDefinition type = typeManager.getType(typeId);
if (type == null) {
throw new CmisObjectNotFoundException("Type '" + typeId + "' is unknown!");
}
boolean isVersionable = RegistryTypeManager.isVersionable(type);
if (!isVersionable && versioningState != VersioningState.NONE) {
throw new CmisConstraintException("Versioning not supported for " + typeId);
}
String name = PropertyHelper.getStringProperty(properties, PropertyIds.NAME);
// get parent Node
RegistryFolder parent = getGregNode(folderId).asFolder();
if (isVersionable && versioningState == VersioningState.NONE) {
throw new CmisConstraintException("Versioning required for " + typeId);
}
if(versioningState == VersioningState.NONE){
UnversionedDocumentTypeHandler handler = new UnversionedDocumentTypeHandler(getRegistry(), pathManager, typeManager);
RegistryObject gregNode = handler.createDocument(parent, name, properties, contentStream, versioningState);
return gregNode.getId();
} else{
DocumentTypeHandler typeHandler = new DocumentTypeHandler(getRegistry(), pathManager, typeManager);
RegistryObject gregNode = typeHandler.createDocument(parent, name, properties, contentStream, versioningState);
return gregNode.getId();
}
}
/**
* See CMIS 1.0 section 2.2.4.2 createDocumentFromSource
*/
public String createDocumentFromSource(String sourceId, Properties properties, String folderId,
VersioningState versioningState) {
if(log.isTraceEnabled()) {
log.trace("<<<<<<<< Creating document from source with source Id:" + sourceId +
", folder Id:" + folderId + " and versioning state:" + versioningState.toString());
}
// get parent folder Node
RegistryFolder parent = getGregNode(folderId).asFolder();
// get source document Node
RegistryDocument source = getGregNode(sourceId).asDocument();
boolean isVersionable = source.isVersionable();
// Below throws same exception with different message based on spec
if (!isVersionable && versioningState != VersioningState.NONE) {
throw new CmisConstraintException("Versioning not supported for " + sourceId);
}
if (isVersionable && versioningState == VersioningState.NONE) {
throw new CmisConstraintException("Versioning required for " + sourceId);
}
// create child from source
RegistryObject gregNode = parent.addNodeFromSource(source, properties);
return gregNode.getId();
}
/**
* See CMIS 1.0 section 2.2.4.3 createFolder
*/
public String createFolder(Properties properties, String folderId) {
if(log.isTraceEnabled()) {
log.trace("<<<<<<<<< Create folder with folder Id:" + folderId);
}
// check properties
if (!CommonUtil.isNonEmptyProperties(properties)) {
throw new CmisInvalidArgumentException("Properties must be set!");
}
// check type
String typeId = PropertyHelper.getTypeId(properties);
TypeDefinition type = typeManager.getType(typeId);
if (type == null) {
throw new CmisObjectNotFoundException("Type '" + typeId + "' is unknown!");
}
//TODO check the name
String name = PropertyHelper.getStringProperty(properties, PropertyIds.NAME);
// get parent Node
RegistryFolder parent = getGregNode(folderId).asFolder();
FolderTypeHandler typeHandler = new FolderTypeHandler(getRegistry(), pathManager, typeManager);
RegistryObject gregNode = typeHandler.createFolder(parent, name, properties);
return gregNode.getId();
}
/**
* See CMIS 1.0 section 2.2.4.13 moveObject
*/
public ObjectData moveObject(Holder<String> objectId, String targetFolderId,
ObjectInfoHandler objectInfos, boolean requiresObjectInfo) {
if(log.isTraceEnabled()) {
log.trace("<<<<<<<< Moving object from " + objectId.getValue() + " to "
+ targetFolderId);
}
if (!CommonUtil.hasObjectId(objectId)) {
throw new CmisInvalidArgumentException("Id is not valid!");
}
// get the node and parent
RegistryObject gregNode = getGregNode(objectId.getValue());
RegistryFolder parent = getGregNode(targetFolderId).asFolder();
gregNode = gregNode.move(parent);
objectId.setValue(gregNode.getId());
return gregNode.compileObjectType(null, false, objectInfos, requiresObjectInfo);
}
/**
* See CMIS 1.0 section 2.2.4.16 setContentStream
*/
public void setContentStream(Holder<String> objectId, Boolean overwriteFlag,
ContentStream contentStream) {
if(log.isTraceEnabled()) {
log.trace("<<<<<<< Set the content stream for object " + objectId.getValue() +
" with overwrite set to " + overwriteFlag);
}
if (!CommonUtil.hasObjectId(objectId)) {
throw new CmisInvalidArgumentException("Id is not valid!");
}
String pathOfObject = objectId.getValue();
/*If it's a version (We cannot set or delete content from versions.
If this is a version, it should mean the base version is passed.
If not, then an exception)
*/
String pathToGet = objectId.getValue();
if(pathOfObject.contains(";")){
pathToGet = pathOfObject.substring(0, pathOfObject.indexOf(";"));
//get path of latest version
try {
String pathOfLatestVersion = repository.getVersions(pathToGet)[0];
if( pathOfLatestVersion.equals(pathOfObject )){
//It's okay
} else{
throw new CmisInvalidArgumentException("Cannot set or delete content in a Version");
}
} catch (RegistryException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
}
RegistryDocument gregDocument = getGregNode(pathToGet).asDocument();
String id = gregDocument.setContentStream(contentStream, Boolean.TRUE.equals(overwriteFlag)).getId();
objectId.setValue(id);
}
/**
* See CMIS 1.0 section 2.2.4.14 deleteObject
*/
public void deleteObject(String objectId, Boolean allVersions) {
if(log.isTraceEnabled()) {
log.trace("<<<<<< Delete Object with Id" + objectId
+ " with all versions set to " + allVersions);
}
// get the node
RegistryObject gregNode = getGregNode(objectId);
//If PWC cancelCheckOut
//String property = gregNode.getNode().getProperty(GregProperty.GREG_IS_CHECKED_OUT);
//boolean isCheckedOut = property !=null && property.equals("true");
if(objectId.endsWith(CMISConstants.PWC_SUFFIX)){
cancelCheckout(objectId);
} else{
gregNode.delete(Boolean.TRUE.equals(allVersions), RegistryPrivateWorkingCopy.isPwc(repository, objectId));
}
}
/**
* See CMIS 1.0 section 2.2.4.15 deleteTree
*/
public FailedToDeleteData deleteTree(String folderId) {
if(log.isTraceEnabled()) {
log.trace("<<<<<<< deleteTree with folder id " + folderId);
}
//check for root
if(folderId.equals("/")){
throw new CmisInvalidArgumentException("Cannot delete root folder");
}
// get the folder
RegistryFolder gregFolder = getGregNode(folderId).asFolder();
return gregFolder.deleteTree();
}
/**
* See CMIS 1.0 section 2.2.4.12 updateProperties
*/
public ObjectData updateProperties(Holder<String> objectId, Properties properties,
ObjectInfoHandler objectInfos, boolean objectInfoRequired) {
if(log.isTraceEnabled()){
log.trace("<<<<<<< updateProperties for object id: " + objectId.getValue());
}
if (objectId == null) {
throw new CmisInvalidArgumentException("Id is not valid!");
}
// get the node
RegistryObject gregNode = getGregNode(objectId.getValue());
String id = gregNode.updateProperties(properties).getId();
objectId.setValue(id);
return gregNode.compileObjectType(null, false, objectInfos, objectInfoRequired);
}
/**
* See CMIS 1.0 section 2.2.4.7 getObject
*/
public ObjectData getObject(String objectId, String filter, Boolean includeAllowableActions,
ObjectInfoHandler objectInfos, boolean requiresObjectInfo) {
if(log.isTraceEnabled()){
log.trace("<<<<<<<< getObject for id: " + objectId);
}
// check id
if (objectId == null) {
throw new CmisInvalidArgumentException("Object Id must be set.");
}
// get the node
RegistryObject gregNode = getGregNode(objectId);
// gather properties
return gregNode.compileObjectType(splitFilter(filter), includeAllowableActions, objectInfos, requiresObjectInfo);
}
/**
* See CMIS 1.0 section 2.2.4.8 getProperties
*/
public Properties getProperties(String objectId, String filter, Boolean includeAllowableActions,
ObjectInfoHandler objectInfos, boolean requiresObjectInfo) {
ObjectData object = getObject(objectId, filter, includeAllowableActions, objectInfos, requiresObjectInfo);
return object.getProperties();
}
/**
* See CMIS 1.0 section 2.2.4.6 getAllowableActions
*/
public AllowableActions getAllowableActions(String objectId) {
if(log.isTraceEnabled()) {
log.trace("<<<<<<< getAllowableActions for object id " + objectId);
}
RegistryObject gregNode = getGregNode(objectId);
return gregNode.getAllowableActions();
}
/**
* See CMIS 1.0 section 2.2.4.10 getContentStream
*/
public ContentStream getContentStream(String objectId, BigInteger offset, BigInteger length) {
if(log.isTraceEnabled()) {
log.trace("<<<<<<< getContentStream for object id " + objectId);
}
if (offset != null || length != null) {
throw new CmisInvalidArgumentException("Offset and Length are not supported!");
}
// get the node
RegistryDocument gregDocument = getGregNode(objectId).asDocument();
ContentStream contentStream = gregDocument.getContentStream();
if(contentStream.getStream() != null){
return contentStream;
} else{
throw new CmisConstraintException("Resource content is empty");
}
}
/**
* See CMIS 1.0 section 2.2.3.1 getChildren
*/
public ObjectInFolderList getChildren(String folderId, String filter,
Boolean includeAllowableActions, Boolean includePathSegment, BigInteger maxItems, BigInteger skipCount,
ObjectInfoHandler objectInfos, boolean requiresObjectInfo) {
if(log.isTraceEnabled()){
log.trace("<<<<<< getChildren for folder id " + folderId);
}
// skip and max
int skip = skipCount == null ? 0 : skipCount.intValue();
if (skip < 0) {
skip = 0;
}
int max = maxItems == null ? Integer.MAX_VALUE : maxItems.intValue();
if (max < 0) {
max = Integer.MAX_VALUE;
}
// get the folder
RegistryFolder gregFolder = getGregNode(folderId).asFolder();
// set object info of the the folder
if (requiresObjectInfo) {
gregFolder.compileObjectType(null, false, objectInfos, requiresObjectInfo);
}
// prepare result
ObjectInFolderListImpl result = new ObjectInFolderListImpl();
result.setObjects(new ArrayList<ObjectInFolderData>());
result.setHasMoreItems(false);
int count = 0;
// iterate through children
Set<String> splitFilter = splitFilter(filter);
Iterator<RegistryObject> childNodes = gregFolder.getNodes();
while (childNodes.hasNext()) {
RegistryObject child = childNodes.next();
count++;
if (skip > 0) {
skip--;
continue;
}
if (result.getObjects().size() >= max) {
result.setHasMoreItems(true);
continue;
}
// build and add child object
ObjectInFolderDataImpl objectInFolder = new ObjectInFolderDataImpl();
objectInFolder.setObject(child.compileObjectType(splitFilter, includeAllowableActions, objectInfos,
requiresObjectInfo));
if (Boolean.TRUE.equals(includePathSegment)) {
objectInFolder.setPathSegment(child.getName());
}
result.getObjects().add(objectInFolder);
}
result.setNumItems(BigInteger.valueOf(count));
return result;
}
/**
* See CMIS 1.0 section 2.2.3.2 getDescendants
*/
public List<ObjectInFolderContainer> getDescendants(String folderId, BigInteger depth,
String filter, Boolean includeAllowableActions, Boolean includePathSegment, ObjectInfoHandler objectInfos,
boolean requiresObjectInfo, boolean foldersOnly) {
if(log.isTraceEnabled()) {
log.trace("<<<<<< getDescendants or getFolderTree for folder id " + folderId);
}
// check depth
int d = depth == null ? 2 : depth.intValue();
if (d == 0) {
throw new CmisInvalidArgumentException("Depth must not be 0!");
}
if (d < -1) {
d = -1;
}
// get the folder
RegistryFolder gregFolder = getGregNode(folderId).asFolder();
// set object info of the the folder
if (requiresObjectInfo) {
gregFolder.compileObjectType(null, false, objectInfos, requiresObjectInfo);
}
// get the tree
List<ObjectInFolderContainer> result = new ArrayList<ObjectInFolderContainer>();
gatherDescendants(gregFolder, result, foldersOnly, d, splitFilter(filter), includeAllowableActions,
includePathSegment, objectInfos, requiresObjectInfo);
return result;
}
/**
* See CMIS 1.0 section 2.2.3.4 getFolderParent
*/
public ObjectData getFolderParent(String folderId, String filter, ObjectInfoHandler objectInfos,
boolean requiresObjectInfo) {
List<ObjectParentData> parents = getObjectParents(folderId, filter, false, false, objectInfos,
requiresObjectInfo);
if (parents.isEmpty()) {
throw new CmisInvalidArgumentException("The root folder has no parent!");
}
return parents.get(0).getObject();
}
/**
* See CMIS 1.0 section 2.2.3.5 getObjectParents
*/
public List<ObjectParentData> getObjectParents(String objectId, String filter,
Boolean includeAllowableActions, Boolean includeRelativePathSegment, ObjectInfoHandler objectInfos,
boolean requiresObjectInfo) {
if(log.isTraceEnabled()) {
log.trace("<<<<<<< getObjectParents for object id " + objectId);
}
// get the file or folder
RegistryObject gregNode = getGregNode(objectId);
// don't climb above the root folder
if (gregNode.isRoot()) {
return Collections.emptyList();
}
// set object info of the the object
if (requiresObjectInfo) {
gregNode.compileObjectType(null, false, objectInfos, requiresObjectInfo);
}
// get parent
RegistryObject parent = gregNode.getParent();
ObjectData object = parent.compileObjectType(splitFilter(filter), includeAllowableActions, objectInfos,
requiresObjectInfo);
ObjectParentDataImpl result = new ObjectParentDataImpl();
result.setObject(object);
if (Boolean.TRUE.equals(includeRelativePathSegment)) {
result.setRelativePathSegment(gregNode.getName());
}
return Collections.singletonList((ObjectParentData) result);
}
/**
* See CMIS 1.0 section 2.2.4.9 getObjectByPath
*/
public ObjectData getObjectByPath(String folderPath, String filter, boolean includeAllowableActions,
boolean includeACL, ObjectInfoHandler objectInfos, boolean requiresObjectInfo) {
if(log.isTraceEnabled()) {
log.trace("<<<<<<< getObjectByPath for folder path " + folderPath);
}
// check path
if (folderPath == null || !PathManager.isAbsolute(folderPath)) {
throw new CmisInvalidArgumentException("Invalid folder path!");
}
RegistryObject root = getGregNode(PathManager.CMIS_ROOT_ID);
RegistryObject gregNode;
if (PathManager.isRoot(folderPath)) {
gregNode = root;
} else {
String path = PathManager.relativize(PathManager.CMIS_ROOT_PATH, folderPath);
try{
gregNode = root.getNode(path);
}
catch (RegistryException e) {
throw new CmisObjectNotFoundException(e.getMessage(), e);
}
}
return gregNode.compileObjectType(splitFilter(filter), includeAllowableActions, objectInfos, requiresObjectInfo);
}
/**
* See CMIS 1.0 section 2.2.3.6 getCheckedOutDocs
*/
public ObjectList getCheckedOutDocs(String folderId, String filter, String orderBy,
Boolean includeAllowableActions, BigInteger maxItems, BigInteger skipCount){
if(log.isTraceEnabled()) {
log.trace("<<<<<<<< getCheckedOutDocs for folder id " + folderId);
}
// skip and max
int skip = skipCount == null ? 0 : skipCount.intValue();
if (skip < 0) {
skip = 0;
}
int max = maxItems == null ? Integer.MAX_VALUE : maxItems.intValue();
if (max < 0) {
max = Integer.MAX_VALUE;
}
try {
String[] children = null;
if (folderId == null) {
//Get the list of tracked out documents
Resource tracker = repository.get(CMISConstants.GREG_CHECKED_OUT_TRACKER);
children = tracker.getProperties().keySet().toArray(new String[0]);
} else{
RegistryFolder folder = getGregNode(folderId).asFolder();
children = folder.getNode().getChildren();
}
// prepare results
ObjectListImpl result = new ObjectListImpl();
result.setObjects(new ArrayList<ObjectData>());
result.setHasMoreItems(false);
// iterate through children
Set<String> splitFilter = splitFilter(filter);
int count = 0;
for(String child: children) {
if(getRegistry().resourceExists(child)){
RegistryObject node = getGregNode(child);
if (!node.isVersionable()) {
continue;
}
if(!isPrivateWorkingCopy(node)){
continue;
}
count++;
if (skip > 0) {
skip--;
continue;
}
if (result.getObjects().size() >= max) {
result.setHasMoreItems(true);
continue;
}
// build and add child object
RegistryPrivateWorkingCopy gregVersion = node.asVersion().getPwc();
ObjectData objectData = gregVersion.compileObjectType(splitFilter, includeAllowableActions, null, false);
result.getObjects().add(objectData);
} else {
Resource resource = getRegistry().get(CMISConstants.GREG_CHECKED_OUT_TRACKER);
resource.removeProperty(child);
getRegistry().put(CMISConstants.GREG_CHECKED_OUT_TRACKER, resource);
}
}
result.setNumItems(BigInteger.valueOf(count));
return result;
}
catch(RegistryException e){
throw new CmisRuntimeException(e.getMessage(), e);
}
}
private boolean isPrivateWorkingCopy(RegistryObject node) {
String checkedOutProperty = node.getNode().getProperty(CMISConstants.GREG_IS_CHECKED_OUT);
String createdAsPwcProperty = node.getNode().getProperty(CMISConstants.GREG_CREATED_AS_PWC);
boolean checkedOut = checkedOutProperty != null && checkedOutProperty.equals("true");
boolean createdAsPwc = createdAsPwcProperty != null && createdAsPwcProperty.equals("true");
boolean endsWithPwc = node.getNode().getPath().endsWith(CMISConstants.PWC_SUFFIX);
return (checkedOut || createdAsPwc || endsWithPwc);
}
/**
* See CMIS 1.0 section 2.2.7.1 checkOut
*/
public void checkOut(Holder<String> objectId, Holder<Boolean> contentCopied) {
if(log.isTraceEnabled()) {
log.trace("<<<<<<<<< checkout for object id " + objectId.getValue());
}
// check id
if (objectId == null || objectId.getValue() == null) {
throw new CmisInvalidArgumentException("Object Id must be set.");
}
// get the node
RegistryObject gregNode = getGregNode(objectId.getValue());
if (!gregNode.isVersionable()) {
throw new CmisUpdateConflictException("Not a version: " + gregNode);
}
// checkout
RegistryPrivateWorkingCopy pwc = gregNode.asVersion().checkout();
objectId.setValue(pwc.getId());
if (contentCopied != null) {
contentCopied.setValue(true);
}
}
/**
* See CMIS 1.0 section 2.2.7.2 cancelCheckout
*/
public void cancelCheckout(String objectId) {
if(log.isTraceEnabled()) {
log.trace("<<<<<<<< cancelCheckout for object id " + objectId);
}
//TODO check what is the object id. Whether it is the id of orig copy or pwc.
// check id
if (objectId == null) {
throw new CmisInvalidArgumentException("Object Id must be set.");
}
// get the node
RegistryObject gregNode = getGregNode(objectId);
if (!gregNode.isVersionable()) {
throw new CmisUpdateConflictException("Not a version: " + gregNode);
}
// cancelCheckout
gregNode.asVersion().cancelCheckout();
}
/**
* See CMIS 1.0 section 2.2.7.3 checkedIn
*/
public void checkIn(Holder<String> objectId, Boolean major, Properties properties,
ContentStream contentStream, String checkinComment) {
if(log.isTraceEnabled()) {
log.trace("<<<<<<< checkin for object id " + objectId.getValue());
}
// check id
if (objectId == null || objectId.getValue() == null) {
throw new CmisInvalidArgumentException("Object Id must be set.");
}
// get the node
RegistryObject gregNode;
try {
gregNode = getGregNode(objectId.getValue());
}
catch (CmisObjectNotFoundException e) {
throw new CmisUpdateConflictException(e.getCause().getMessage(), e.getCause());
}
if (!gregNode.isVersionable()) {
throw new CmisUpdateConflictException("Not a version: " + gregNode);
}
// checkin
RegistryVersion checkedIn = gregNode.asVersion().checkin(properties, contentStream, checkinComment);
objectId.setValue(checkedIn.getId());
}
/**
* See CMIS 1.0 section 2.2.7.6 getAllVersions
*/
public List<ObjectData> getAllVersions(String objectId, String filter,
Boolean includeAllowableActions, ObjectInfoHandler objectInfos, boolean requiresObjectInfo) {
if(log.isTraceEnabled()) {
log.trace("<<<<<<<<<< getAllVersions for object id " + objectId);
}
// check id
if (objectId == null) {
throw new CmisInvalidArgumentException("Object Id must be set.");
}
Set<String> splitFilter = splitFilter(filter);
// get the node
RegistryObject gregNode = getGregNode(objectId);
// Collect versions
if (gregNode.isVersionable()) {
RegistryVersionBase gregVersion = gregNode.asVersion();
Iterator<RegistryVersion> versions = gregVersion.getVersions();
//if (versions.hasNext()) {
// versions.next(); // skip root version
//}
List<ObjectData> allVersions = new ArrayList<ObjectData>();
while (versions.hasNext()) {
RegistryVersion version = versions.next();
ObjectData objectData = version.compileObjectType(splitFilter, includeAllowableActions, objectInfos,
requiresObjectInfo);
allVersions.add(objectData);
}
// Add pwc if checked out
//Skip if document was created as PWC
String property = gregVersion.getNode().getProperty(CMISConstants.GREG_CREATED_AS_PWC);
//TODO: property is checked for null. Might have to change this in the future.
if (gregVersion.isDocumentCheckedOut() && (property == null) ) {
RegistryPrivateWorkingCopy pwc = gregVersion.getPwc();
ObjectData objectData = pwc.compileObjectType(splitFilter, includeAllowableActions, objectInfos,
requiresObjectInfo);
allVersions.add(objectData);
}
// CMIS mandates descending order
//Collections.reverse(allVersions);
return allVersions;
} else {
// Single version
ObjectData objectData = gregNode.compileObjectType(splitFilter, includeAllowableActions, objectInfos,
requiresObjectInfo);
return Collections.singletonList(objectData);
}
}
/**
* See CMIS 1.0 section 2.2.6.1 query
*/
public ObjectList query(String statement, Boolean searchAllVersions,
Boolean includeAllowableActions, BigInteger maxItems, BigInteger skipCount){
//TODO: Not supported
if(log.isTraceEnabled()) {
log.trace("<<<<<<<<<<< query for the statement " + statement);
}
return new ObjectListImpl();
}
protected RepositoryInfo compileRepositoryInfo(String repositoryId) {
RepositoryInfoImpl fRepositoryInfo = new RepositoryInfoImpl();
fRepositoryInfo.setId(repositoryId);
fRepositoryInfo.setName(getRepositoryName());
fRepositoryInfo.setDescription(getRepositoryDescription());
fRepositoryInfo.setCmisVersionSupported(CMISConstants.CMIS_VERSION);
fRepositoryInfo.setProductName(CMISConstants.PRODUCT_NAME);
fRepositoryInfo.setProductVersion("0.1");
fRepositoryInfo.setVendorName(CMISConstants.VENDOR_NAME);
fRepositoryInfo.setRootFolder("/");
fRepositoryInfo.setThinClientUri("");
RepositoryCapabilitiesImpl capabilities = new RepositoryCapabilitiesImpl();
capabilities.setCapabilityAcl(CapabilityAcl.NONE);
capabilities.setAllVersionsSearchable(false);
capabilities.setCapabilityJoin(CapabilityJoin.NONE);
capabilities.setSupportsMultifiling(false);
capabilities.setSupportsUnfiling(false);
capabilities.setSupportsVersionSpecificFiling(false);
capabilities.setIsPwcSearchable(false);
capabilities.setIsPwcUpdatable(true);
capabilities.setCapabilityQuery(CapabilityQuery.NONE);
capabilities.setCapabilityChanges(CapabilityChanges.NONE);
capabilities.setCapabilityContentStreamUpdates(CapabilityContentStreamUpdates.ANYTIME);
capabilities.setSupportsGetDescendants(true);
capabilities.setSupportsGetFolderTree(true);
capabilities.setCapabilityRendition(CapabilityRenditions.NONE);
fRepositoryInfo.setCapabilities(capabilities);
return fRepositoryInfo;
}
protected String getRepositoryName() {
return getRepositoryId();
}
protected String getRepositoryDescription() {
return "CMIS Repository for Governance Registry";
}
protected RegistryObject getGregNode(String id) {
try {
if (id == null || id.length() == 0) {
throw new CmisInvalidArgumentException("Null or empty id");
}
if (id.equals(PathManager.CMIS_ROOT_ID)) {
return new FolderTypeHandler(repository, pathManager, typeManager).getGregNode(repository.get(id));
}
int k = id.indexOf(';');
if (k >= 0) {
//Version exists, however we must check whether the original resource is present.
//If it doesn't, the version should be deleted and an exception will be thrown.
//This is because in a CMIS repo, if the original resource is deleted then all
// the versions should be deleted as well. When deleteTree is called although the original
//resource is deleted, the versions exist. Hence for the following code.
String originalResourceName = id.substring(0, id.indexOf(";"));
if(!repository.resourceExists(originalResourceName)){
int beginIndex = id.indexOf(":")+1;
int endIndex = id.length();
String versionNumber = id.substring(beginIndex,endIndex);
long snapshotId = Long.parseLong(versionNumber);
repository.removeVersionHistory(originalResourceName, snapshotId);
throw new CmisObjectNotFoundException("Original resource of version does not exist");
}
//Node node = session.getNodeByIdentifier(nodeId);
Resource node = null;
node = repository.get(id);
RegistryObject gregNode = null;
if(node != null){
if(node instanceof Collection){
gregNode = new FolderTypeHandler(getRegistry(), pathManager, typeManager).getGregNode(node);
} else {
gregNode = new DocumentTypeHandler(getRegistry(), pathManager, typeManager).getGregNode(node);
}
}
//if (GregPrivateWorkingCopy.denotesPwc(versionName)) {
// return gregNode.asVersion().getPwc();
//}
//else {
return gregNode.asVersion().getVersion(id);
//}
} else {
Resource node = null;
node = repository.get(id);
RegistryObject gregNode = null;
if(node!=null){
if(node instanceof Collection){
gregNode = new FolderTypeHandler(getRegistry(), pathManager, typeManager).getGregNode(repository.get(id));
} else {
//check if Unversioned type
String property = node.getProperty(CMISConstants.GREG_UNVERSIONED_TYPE);
if(property!=null && property.equals("true")){
gregNode = new UnversionedDocumentTypeHandler(getRegistry(), pathManager, typeManager).getGregNode(repository.get(id));
return gregNode;
}
gregNode = new DocumentTypeHandler(getRegistry(), pathManager, typeManager).getGregNode(repository.get(id));
if (RegistryPrivateWorkingCopy.denotesPwc(repository, id)) {
return gregNode.asVersion().getPwc();
}
}
}
return gregNode;
}
} catch (RegistryException e) {
String msg = "Failed to retrieve the node with id " + id;
log.error(msg, e);
throw new CmisObjectNotFoundException(msg, e);
}
}
/**
* Transitively gather the children of a node down to a specific depth
*/
private static void gatherDescendants(RegistryFolder gregFolder, List<ObjectInFolderContainer> list,
boolean foldersOnly, int depth, Set<String> filter, Boolean includeAllowableActions,
Boolean includePathSegments, ObjectInfoHandler objectInfos, boolean requiresObjectInfo) {
// iterate through children
Iterator<RegistryObject> childNodes = gregFolder.getNodes();
while (childNodes.hasNext()) {
RegistryObject child = childNodes.next();
// folders only?
if (foldersOnly && !child.isFolder()) {
continue;
}
// add to list
ObjectInFolderDataImpl objectInFolder = new ObjectInFolderDataImpl();
objectInFolder.setObject(child.compileObjectType(filter, includeAllowableActions, objectInfos,
requiresObjectInfo));
if (Boolean.TRUE.equals(includePathSegments)) {
objectInFolder.setPathSegment(child.getName());
}
ObjectInFolderContainerImpl container = new ObjectInFolderContainerImpl();
container.setObject(objectInFolder);
list.add(container);
// move to next level
if (depth != 1 && child.isFolder()) {
container.setChildren(new ArrayList<ObjectInFolderContainer>());
gatherDescendants(child.asFolder(), container.getChildren(), foldersOnly, depth - 1, filter,
includeAllowableActions, includePathSegments, objectInfos, requiresObjectInfo);
}
}
}
/**
* Splits a filter statement into a collection of properties.
*/
private static Set<String> splitFilter(String filter) {
if (filter == null || filter.trim().length() == 0)
return null;
Set<String> result = new HashSet<String>();
for (String s : filter.split(",")) {
s = s.trim();
if (s.equals("*")) {
return null;
} else if (s.length() > 0) {
result.add(s);
}
}
// set a few base properties
// query name == id (for base type properties)
result.add(PropertyIds.OBJECT_ID);
result.add(PropertyIds.OBJECT_TYPE_ID);
result.add(PropertyIds.BASE_TYPE_ID);
return result;
}
}