blob: b96e993f567f8988b1b7de1866443d2e3e3df81d [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.client.runtime;
import static org.apache.chemistry.opencmis.commons.impl.CollectionsHelper.isNullOrEmpty;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.chemistry.opencmis.client.api.CmisObject;
import org.apache.chemistry.opencmis.client.api.Document;
import org.apache.chemistry.opencmis.client.api.ObjectFactory;
import org.apache.chemistry.opencmis.client.api.ObjectId;
import org.apache.chemistry.opencmis.client.api.ObjectType;
import org.apache.chemistry.opencmis.client.api.OperationContext;
import org.apache.chemistry.opencmis.client.api.Policy;
import org.apache.chemistry.opencmis.client.api.Property;
import org.apache.chemistry.opencmis.client.bindings.spi.LinkAccess;
import org.apache.chemistry.opencmis.commons.PropertyIds;
import org.apache.chemistry.opencmis.commons.data.Ace;
import org.apache.chemistry.opencmis.commons.data.ContentStream;
import org.apache.chemistry.opencmis.commons.data.ContentStreamHash;
import org.apache.chemistry.opencmis.commons.data.ObjectData;
import org.apache.chemistry.opencmis.commons.data.PartialContentStream;
import org.apache.chemistry.opencmis.commons.enums.CmisVersion;
import org.apache.chemistry.opencmis.commons.enums.IncludeRelationships;
import org.apache.chemistry.opencmis.commons.enums.Updatability;
import org.apache.chemistry.opencmis.commons.enums.VersioningState;
import org.apache.chemistry.opencmis.commons.exceptions.CmisNotSupportedException;
import org.apache.chemistry.opencmis.commons.exceptions.CmisRuntimeException;
import org.apache.chemistry.opencmis.commons.impl.dataobjects.ContentStreamHashImpl;
import org.apache.chemistry.opencmis.commons.spi.Holder;
public class DocumentImpl extends AbstractFilableCmisObject implements Document {
private static final long serialVersionUID = 1L;
/**
* Constructor.
*/
public DocumentImpl(SessionImpl session, ObjectType objectType, ObjectData objectData, OperationContext context) {
initialize(session, objectType, objectData, context);
}
// properties
public String getCheckinComment() {
return getPropertyValue(PropertyIds.CHECKIN_COMMENT);
}
public String getVersionLabel() {
return getPropertyValue(PropertyIds.VERSION_LABEL);
}
public String getVersionSeriesId() {
return getPropertyValue(PropertyIds.VERSION_SERIES_ID);
}
public String getVersionSeriesCheckedOutId() {
return getPropertyValue(PropertyIds.VERSION_SERIES_CHECKED_OUT_ID);
}
public String getVersionSeriesCheckedOutBy() {
return getPropertyValue(PropertyIds.VERSION_SERIES_CHECKED_OUT_BY);
}
public Boolean isImmutable() {
return getPropertyValue(PropertyIds.IS_IMMUTABLE);
}
public Boolean isLatestMajorVersion() {
return getPropertyValue(PropertyIds.IS_LATEST_MAJOR_VERSION);
}
public Boolean isLatestVersion() {
return getPropertyValue(PropertyIds.IS_LATEST_VERSION);
}
public Boolean isMajorVersion() {
return getPropertyValue(PropertyIds.IS_MAJOR_VERSION);
}
public Boolean isPrivateWorkingCopy() {
return getPropertyValue(PropertyIds.IS_PRIVATE_WORKING_COPY);
}
public Boolean isVersionSeriesCheckedOut() {
return getPropertyValue(PropertyIds.IS_VERSION_SERIES_CHECKED_OUT);
}
public long getContentStreamLength() {
BigInteger bigInt = getPropertyValue(PropertyIds.CONTENT_STREAM_LENGTH);
return (bigInt == null) ? (long) -1 : bigInt.longValue();
}
public String getContentStreamMimeType() {
return getPropertyValue(PropertyIds.CONTENT_STREAM_MIME_TYPE);
}
public String getContentStreamFileName() {
return getPropertyValue(PropertyIds.CONTENT_STREAM_FILE_NAME);
}
public String getContentStreamId() {
return getPropertyValue(PropertyIds.CONTENT_STREAM_ID);
}
public List<ContentStreamHash> getContentStreamHashes() {
List<String> hashes = getPropertyValue(PropertyIds.CONTENT_STREAM_HASH);
if (isNullOrEmpty(hashes)) {
return null;
}
List<ContentStreamHash> result = new ArrayList<ContentStreamHash>(hashes.size());
for (String hash : hashes) {
result.add(new ContentStreamHashImpl(hash));
}
return result;
}
// operations
public Document copy(ObjectId targetFolderId, Map<String, ?> properties, VersioningState versioningState,
List<Policy> policies, List<Ace> addAces, List<Ace> removeAces, OperationContext context) {
ObjectId newId = null;
try {
newId = getSession().createDocumentFromSource(this, properties, targetFolderId, versioningState, policies,
addAces, removeAces);
} catch (CmisNotSupportedException nse) {
newId = copyViaClient(targetFolderId, properties, versioningState, policies, addAces, removeAces);
}
// if no context is provided the object will not be fetched
if (context == null || newId == null) {
return null;
}
// get the new object
CmisObject object = getSession().getObject(newId, context);
if (!(object instanceof Document)) {
throw new CmisRuntimeException("Newly created object is not a document! New id: " + newId);
}
return (Document) object;
}
public Document copy(ObjectId targetFolderId) {
return copy(targetFolderId, null, null, null, null, null, getSession().getDefaultContext());
}
/**
* Copies the document manually. The content is streamed from the repository
* and back.
*/
protected ObjectId copyViaClient(ObjectId targetFolderId, Map<String, ?> properties,
VersioningState versioningState, List<Policy> policies, List<Ace> addAces, List<Ace> removeAces) {
Map<String, Object> newProperties = new HashMap<String, Object>();
OperationContext allPropsContext = getSession().createOperationContext();
allPropsContext.setFilterString("*");
allPropsContext.setIncludeAcls(false);
allPropsContext.setIncludeAllowableActions(false);
allPropsContext.setIncludePathSegments(false);
allPropsContext.setIncludePolicies(false);
allPropsContext.setIncludeRelationships(IncludeRelationships.NONE);
allPropsContext.setRenditionFilterString("cmis:none");
Document allPropsDoc = (Document) getSession().getObject(this, allPropsContext);
for (Property<?> prop : allPropsDoc.getProperties()) {
if (prop.getDefinition().getUpdatability() == Updatability.READWRITE
|| prop.getDefinition().getUpdatability() == Updatability.ONCREATE) {
newProperties.put(prop.getId(), prop.getValue());
}
}
if (properties != null) {
newProperties.putAll(properties);
}
ContentStream contentStream = allPropsDoc.getContentStream();
try {
return getSession().createDocument(newProperties, targetFolderId, contentStream, versioningState, policies,
addAces, removeAces);
} finally {
if (contentStream != null) {
InputStream stream = contentStream.getStream();
if (stream != null) {
try {
stream.close();
} catch (IOException ioe) {
throw new CmisRuntimeException("Cannot close source stream!", ioe);
}
}
}
}
}
public void deleteAllVersions() {
delete(true);
}
// versioning
public ObjectId checkOut() {
String newObjectId = null;
readLock();
try {
String objectId = getObjectId();
Holder<String> objectIdHolder = new Holder<String>(objectId);
getBinding().getVersioningService().checkOut(getRepositoryId(), objectIdHolder, null, null);
newObjectId = objectIdHolder.getValue();
} finally {
readUnlock();
}
// remove original version from cache, the path and a few versioning
// properties are not valid anymore
getSession().removeObjectFromCache(this);
if (newObjectId == null) {
return null;
}
return getSession().createObjectId(newObjectId);
}
public void cancelCheckOut() {
String objectId = getObjectId();
getBinding().getVersioningService().cancelCheckOut(getRepositoryId(), objectId, null);
// remove PWC from cache, it doesn't exist anymore
getSession().removeObjectFromCache(this);
}
public ObjectId checkIn(boolean major, Map<String, ?> properties, ContentStream contentStream,
String checkinComment, List<Policy> policies, List<Ace> addAces, List<Ace> removeAces) {
String newObjectId = null;
readLock();
try {
Holder<String> objectIdHolder = new Holder<String>(getObjectId());
ObjectFactory of = getObjectFactory();
Set<Updatability> updatebility = EnumSet.noneOf(Updatability.class);
updatebility.add(Updatability.READWRITE);
updatebility.add(Updatability.WHENCHECKEDOUT);
getBinding().getVersioningService().checkIn(getRepositoryId(), objectIdHolder, major,
of.convertProperties(properties, getType(), getSecondaryTypes(), updatebility),
of.convertContentStream(contentStream), checkinComment, of.convertPolicies(policies),
of.convertAces(addAces), of.convertAces(removeAces), null);
newObjectId = objectIdHolder.getValue();
} finally {
readUnlock();
}
// remove PWC from cache, it doesn't exist anymore
getSession().removeObjectFromCache(this);
if (newObjectId == null) {
return null;
}
return getSession().createObjectId(newObjectId);
}
public List<Document> getAllVersions() {
return getAllVersions(getSession().getDefaultContext());
}
public List<Document> getAllVersions(OperationContext context) {
String objectId;
String versionSeriesId;
readLock();
try {
objectId = getObjectId();
versionSeriesId = getVersionSeriesId();
} finally {
readUnlock();
}
List<ObjectData> versions = getBinding().getVersioningService().getAllVersions(getRepositoryId(), objectId,
versionSeriesId, context.getFilterString(), context.isIncludeAllowableActions(), null);
ObjectFactory objectFactory = getSession().getObjectFactory();
List<Document> result = new ArrayList<Document>();
if (versions != null) {
for (ObjectData objectData : versions) {
CmisObject doc = objectFactory.convertObject(objectData, context);
if (!(doc instanceof Document)) {
// should not happen...
continue;
}
result.add((Document) doc);
}
}
return result;
}
public Document getObjectOfLatestVersion(boolean major) {
return getObjectOfLatestVersion(major, getSession().getDefaultContext());
}
public Document getObjectOfLatestVersion(boolean major, OperationContext context) {
return getSession().getLatestDocumentVersion(this, major, context);
}
// content operations
public ContentStream getContentStream() {
return getContentStream(null, null, null);
}
public ContentStream getContentStream(BigInteger offset, BigInteger length) {
return getContentStream(null, offset, length);
}
public ContentStream getContentStream(String streamId) {
return getContentStream(streamId, null, null);
}
public ContentStream getContentStream(String streamId, BigInteger offset, BigInteger length) {
// get the stream
ContentStream contentStream = getSession().getContentStream(this, streamId, offset, length);
if (contentStream == null) {
return null;
}
// the AtomPub binding doesn't return a file name
// -> get the file name from properties, if present
String filename = contentStream.getFileName();
if (filename == null) {
filename = getContentStreamFileName();
}
long lengthLong = (contentStream.getBigLength() == null ? -1 : contentStream.getBigLength().longValue());
// convert and return stream object
return getSession().getObjectFactory().createContentStream(filename, lengthLong, contentStream.getMimeType(),
contentStream.getStream(), contentStream instanceof PartialContentStream);
}
public String getContentUrl() {
return getContentUrl(null);
}
public String getContentUrl(String streamId) {
if (getBinding().getObjectService() instanceof LinkAccess) {
LinkAccess linkAccess = (LinkAccess) getBinding().getObjectService();
if (streamId == null) {
return linkAccess.loadContentLink(getRepositoryId(), getId());
} else {
return linkAccess.loadRenditionContentLink(getRepositoryId(), getId(), streamId);
}
}
return null;
}
public Document setContentStream(ContentStream contentStream, boolean overwrite) {
ObjectId objectId = setContentStream(contentStream, overwrite, true);
if (objectId == null) {
return null;
}
if (!getObjectId().equals(objectId.getId())) {
return (Document) getSession().getObject(objectId, getCreationContext());
}
return this;
}
public ObjectId setContentStream(ContentStream contentStream, boolean overwrite, boolean refresh) {
String newObjectId = null;
readLock();
try {
Holder<String> objectIdHolder = new Holder<String>(getObjectId());
Holder<String> changeTokenHolder = new Holder<String>((String) getPropertyValue(PropertyIds.CHANGE_TOKEN));
getBinding().getObjectService().setContentStream(getRepositoryId(), objectIdHolder, overwrite,
changeTokenHolder, getObjectFactory().convertContentStream(contentStream), null);
newObjectId = objectIdHolder.getValue();
} finally {
readUnlock();
}
if (refresh) {
refresh();
}
if (newObjectId == null) {
return null;
}
return getSession().createObjectId(newObjectId);
}
public Document appendContentStream(ContentStream contentStream, boolean isLastChunk) {
if (getSession().getRepositoryInfo().getCmisVersion() == CmisVersion.CMIS_1_0) {
throw new CmisNotSupportedException("This method is not supported for CMIS 1.0 repositories.");
}
ObjectId objectId = appendContentStream(contentStream, isLastChunk, true);
if (objectId == null) {
return null;
}
if (!getObjectId().equals(objectId.getId())) {
return (Document) getSession().getObject(objectId, getCreationContext());
}
return this;
}
public ObjectId appendContentStream(ContentStream contentStream, boolean isLastChunk, boolean refresh) {
String newObjectId = null;
readLock();
try {
Holder<String> objectIdHolder = new Holder<String>(getObjectId());
Holder<String> changeTokenHolder = new Holder<String>((String) getPropertyValue(PropertyIds.CHANGE_TOKEN));
getBinding().getObjectService().appendContentStream(getRepositoryId(), objectIdHolder, changeTokenHolder,
getObjectFactory().convertContentStream(contentStream), isLastChunk, null);
newObjectId = objectIdHolder.getValue();
} finally {
readUnlock();
}
if (refresh) {
refresh();
}
if (newObjectId == null) {
return null;
}
return getSession().createObjectId(newObjectId);
}
public Document deleteContentStream() {
ObjectId objectId = deleteContentStream(true);
if (objectId == null) {
return null;
}
if (!getObjectId().equals(objectId.getId())) {
return (Document) getSession().getObject(objectId, getCreationContext());
}
return this;
}
public ObjectId deleteContentStream(boolean refresh) {
String newObjectId = null;
readLock();
try {
Holder<String> objectIdHolder = new Holder<String>(getObjectId());
Holder<String> changeTokenHolder = new Holder<String>((String) getPropertyValue(PropertyIds.CHANGE_TOKEN));
getBinding().getObjectService().deleteContentStream(getRepositoryId(), objectIdHolder, changeTokenHolder,
null);
newObjectId = objectIdHolder.getValue();
} finally {
readUnlock();
}
if (refresh) {
refresh();
}
if (newObjectId == null) {
return null;
}
return getSession().createObjectId(newObjectId);
}
public ObjectId checkIn(boolean major, Map<String, ?> properties, ContentStream contentStream, String checkinComment) {
return this.checkIn(major, properties, contentStream, checkinComment, null, null, null);
}
}