| /* |
| * 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); |
| } |
| } |