blob: 39528441af069f9aa2c44c16f72a1b0555d6d286 [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.util.ArrayList;
import java.util.List;
import org.apache.chemistry.opencmis.commons.PropertyIds;
import org.apache.chemistry.opencmis.commons.data.Acl;
import org.apache.chemistry.opencmis.commons.data.ContentStream;
import org.apache.chemistry.opencmis.commons.data.ExtensionsData;
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.definitions.DocumentTypeDefinition;
import org.apache.chemistry.opencmis.commons.definitions.TypeDefinition;
import org.apache.chemistry.opencmis.commons.enums.BaseTypeId;
import org.apache.chemistry.opencmis.commons.enums.IncludeRelationships;
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.CmisUpdateConflictException;
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.ObjectStore;
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.PropertyCreationHelper;
import org.apache.chemistry.opencmis.server.support.TypeManager;
public class InMemoryVersioningServiceImpl extends InMemoryAbstractServiceImpl {
private InMemoryObjectServiceImpl fObjectService;
private AtomLinkInfoProvider fAtomLinkProvider;
public InMemoryVersioningServiceImpl(StoreManager storeManager, InMemoryObjectServiceImpl objectService) {
super(storeManager);
fObjectService = objectService;
fAtomLinkProvider = new AtomLinkInfoProvider(fStoreManager);
}
public void cancelCheckOut(CallContext context, String repositoryId, String objectId, ExtensionsData extension) {
StoredObject so = validator.cancelCheckOut(context, repositoryId, objectId, extension);
ObjectStore objStore = fStoreManager.getObjectStore(repositoryId);
String user = context.getUsername();
VersionedDocument verDoc = testHasProperCheckedOutStatus(so, user);
DocumentVersion pwc = verDoc.getPwc();
verDoc.cancelCheckOut(user);
objStore.deleteVersion(pwc);
// if this is the last version delete the document itself
if (verDoc.getAllVersions().size() == 0) {
fStoreManager.getObjectStore(repositoryId).deleteObject(verDoc.getId(), true, user);
}
}
public void checkIn(CallContext context, String repositoryId, Holder<String> objectId, Boolean majorParam,
Properties properties, ContentStream contentStreamParam, String checkinComment, List<String> policies,
Acl addAces, Acl removeAces, ExtensionsData extension, ObjectInfoHandler objectInfos) {
Acl aclAdd = org.apache.chemistry.opencmis.inmemory.TypeValidator.expandAclMakros(context.getUsername(),
addAces);
Acl aclRemove = org.apache.chemistry.opencmis.inmemory.TypeValidator.expandAclMakros(context.getUsername(),
removeAces);
StoredObject so = validator.checkIn(context, repositoryId, objectId, aclAdd, aclRemove, policies, extension);
String user = context.getUsername();
VersionedDocument verDoc = testHasProperCheckedOutStatus(so, user);
// check if the contentStream is a usable object or ignore it otherwise
// Note Browser binding sets an empty object
ObjectStore objStore = fStoreManager.getObjectStore(repositoryId);
ContentStream contentStream = contentStreamParam;
if (contentStream != null) {
if (contentStream.getStream() == null) {
contentStream = null;
} else {
objStore.setContent(so, contentStream);
}
}
boolean major = (null == majorParam ? true : majorParam);
verDoc.checkIn(major, properties, ((Content)so).getContent(), checkinComment, policies, user);
if (null != properties && null != properties.getProperties()) {
// rename:
PropertyData<?> pd = properties.getProperties().get(PropertyIds.NAME);
if (pd != null) {
String newName = (String) pd.getFirstValue();
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
objStore.rename(so, (String) pd.getFirstValue(), user);
}
}
so.updateSystemBasePropertiesWhenModified(null, context.getUsername());
// 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);
}
}
public void checkOut(CallContext context, String repositoryId, Holder<String> objectId, ExtensionsData extension,
Holder<Boolean> contentCopied, ObjectInfoHandler objectInfos) {
StoredObject so = validator.checkOut(context, repositoryId, objectId, extension, contentCopied);
TypeDefinition typeDef = getTypeDefinition(repositoryId, so);
if (!typeDef.getBaseTypeId().equals(BaseTypeId.CMIS_DOCUMENT)) {
throw new CmisNotSupportedException("Only documents can be checked-out.");
} else if (!((DocumentTypeDefinition) typeDef).isVersionable()) {
throw new CmisNotSupportedException("Object can't be checked-out, type is not versionable.");
}
checkIsVersionableObject(so);
ObjectStore objectStore = fStoreManager.getObjectStore(repositoryId);
VersionedDocument verDoc = getVersionedDocumentOfObjectId(so);
ContentStream content = null;
ObjectStore objStore = fStoreManager.getObjectStore(repositoryId);
if (so instanceof DocumentVersion) {
content = objStore.getContent(so, 0, -1);
} else {
DocumentVersion latestVer = ((VersionedDocument) so).getLatestVersion(false);
content = objStore.getContent(latestVer, 0, -1);
}
if (verDoc.isCheckedOut()) {
throw new CmisUpdateConflictException("Document " + objectId.getValue() + " is already checked out.");
}
String user = context.getUsername();
checkHasUser(user);
DocumentVersion pwc = verDoc.checkOut(user);
objectStore.setContent(pwc, content);
objectStore.storeVersion(pwc);
objectId.setValue(pwc.getId()); // return the id of the created pwc
if (null != contentCopied) {
contentCopied.setValue(true);
}
// 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, pwc, objectInfo);
objectInfos.addObjectInfo(objectInfo);
}
}
public List<ObjectData> getAllVersions(CallContext context, String repositoryId, String objectId,
String versionSeriesId, String filter, Boolean includeAllowableActions, ExtensionsData extension,
ObjectInfoHandler objectInfos) {
// Note that in AtomPub object id is null and versionSeriesId is set and
// in SOAP bindinf versionSeriesId is set
// and objectId is null
StoredObject so;
List<ObjectData> res = new ArrayList<ObjectData>();
String id = versionSeriesId;
if (null == versionSeriesId) {
if (null == objectId) {
throw new CmisInvalidArgumentException("getAllVersions requires a version series id, but it was null.");
}
id = objectId;
}
so = validator.getAllVersions(context, repositoryId, objectId, id, extension);
if (!(so instanceof VersionedDocument)) {
if (!(so instanceof DocumentVersion)) {
throw new CmisInvalidArgumentException("getAllVersions requires an id of a versioned document.");
}
so = ((DocumentVersion) so).getParentDocument();
}
VersionedDocument verDoc = (VersionedDocument) so;
List<DocumentVersion> versions = verDoc.getAllVersions();
for (DocumentVersion version : versions) {
ObjectData objData = getObject(context, repositoryId, version.getId(), filter, includeAllowableActions,
IncludeRelationships.NONE, false, extension, objectInfos);
res.add(objData);
}
// reverse list of versions because spec expects latest version first
List<ObjectData> temp = new ArrayList<ObjectData>(res.size());
for (ObjectData ver : res) {
temp.add(0, ver);
}
res = temp;
// provide information for Atom links for version series:
if (context.isObjectInfoRequired()) {
ObjectInfoImpl objectInfo = new ObjectInfoImpl();
fAtomLinkProvider.fillInformationForAtomLinks(repositoryId, so, objectInfo);
objectInfos.addObjectInfo(objectInfo);
}
return res;
}
public ObjectData getObjectOfLatestVersion(CallContext context, String repositoryId, String objectId,
String versionSeriesId, Boolean major, String filter, Boolean includeAllowableActions,
IncludeRelationships includeRelationships, String renditionFilter, Boolean includePolicyIds,
Boolean includeAcl, ExtensionsData extension, ObjectInfoHandler objectInfos) {
StoredObject so = validator.getObjectOfLatestVersion(context, repositoryId, objectId, versionSeriesId,
extension);
ObjectData objData = null;
// In AtomPu8b you do not get the version series id, only the object id
if (so instanceof DocumentVersion) {
so = ((DocumentVersion) so).getParentDocument();
}
if (so instanceof VersionedDocument) {
VersionedDocument verDoc = (VersionedDocument) so;
DocumentVersion latestVersion = verDoc.getLatestVersion(major);
objData = getObject(context, repositoryId, latestVersion.getId(), filter, includeAllowableActions,
includeRelationships, includePolicyIds, extension, objectInfos);
} else if (so instanceof Document) {
objData = getObject(context, repositoryId, so.getId(), filter, includeAllowableActions,
includeRelationships, includePolicyIds, extension, objectInfos);
} else {
throw new CmisInvalidArgumentException("Object is not instance of a document (version series)");
}
// provide information for Atom links for version series:
if (context.isObjectInfoRequired()) {
ObjectInfoImpl objectInfo = new ObjectInfoImpl();
fAtomLinkProvider.fillInformationForAtomLinks(repositoryId, so, objectInfo);
objectInfos.addObjectInfo(objectInfo);
}
return objData;
}
public Properties getPropertiesOfLatestVersion(CallContext context, String repositoryId, String objectId,
String versionSeriesId, Boolean major, String filter, ExtensionsData extension) {
StoredObject so = validator.getPropertiesOfLatestVersion(context, repositoryId, objectId, versionSeriesId,
extension);
ObjectStore objectStore = fStoreManager.getObjectStore(repositoryId);
StoredObject latestVersionObject = null;
// In AtomPu8b you do not get the version series id, only the object id
if (so instanceof DocumentVersion) {
so = ((DocumentVersion) so).getParentDocument();
}
if (so instanceof VersionedDocument) {
VersionedDocument verDoc = (VersionedDocument) so;
latestVersionObject = verDoc.getLatestVersion(major);
} else if (so instanceof Document) {
latestVersionObject = so;
} else {
throw new CmisInvalidArgumentException("Object is not instance of a document (version series)");
}
List<String> requestedIds = FilterParser.getRequestedIdsFromFilter(filter);
TypeManager tm = fStoreManager.getTypeManager(repositoryId);
Properties props = PropertyCreationHelper.getPropertiesFromObject(latestVersionObject, objectStore, tm,
requestedIds, true);
return props;
}
private ObjectData getObject(CallContext context, String repositoryId, String objectId, String filter,
Boolean includeAllowableActions, IncludeRelationships includeRelationships, Boolean includePolicies,
ExtensionsData extension, ObjectInfoHandler objectInfos) {
return fObjectService.getObject(context, repositoryId, objectId, filter, includeAllowableActions,
includeRelationships, null, includePolicies, includeAllowableActions, extension, objectInfos);
}
}