This project has retired. For details please refer to its Attic page.
DocumentImpl xref
View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   * http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.chemistry.opencmis.client.runtime;
20  
21  import static org.apache.chemistry.opencmis.commons.impl.CollectionsHelper.isNullOrEmpty;
22  
23  import java.io.IOException;
24  import java.io.InputStream;
25  import java.io.OutputStream;
26  import java.math.BigInteger;
27  import java.util.ArrayList;
28  import java.util.EnumSet;
29  import java.util.HashMap;
30  import java.util.List;
31  import java.util.Map;
32  import java.util.Set;
33  
34  import org.apache.chemistry.opencmis.client.api.CmisObject;
35  import org.apache.chemistry.opencmis.client.api.Document;
36  import org.apache.chemistry.opencmis.client.api.DocumentType;
37  import org.apache.chemistry.opencmis.client.api.ObjectFactory;
38  import org.apache.chemistry.opencmis.client.api.ObjectId;
39  import org.apache.chemistry.opencmis.client.api.ObjectType;
40  import org.apache.chemistry.opencmis.client.api.OperationContext;
41  import org.apache.chemistry.opencmis.client.api.Policy;
42  import org.apache.chemistry.opencmis.client.api.Property;
43  import org.apache.chemistry.opencmis.client.bindings.spi.LinkAccess;
44  import org.apache.chemistry.opencmis.client.runtime.util.AppendOutputStream;
45  import org.apache.chemistry.opencmis.commons.PropertyIds;
46  import org.apache.chemistry.opencmis.commons.data.Ace;
47  import org.apache.chemistry.opencmis.commons.data.ContentStream;
48  import org.apache.chemistry.opencmis.commons.data.ContentStreamHash;
49  import org.apache.chemistry.opencmis.commons.data.ObjectData;
50  import org.apache.chemistry.opencmis.commons.data.PartialContentStream;
51  import org.apache.chemistry.opencmis.commons.enums.CmisVersion;
52  import org.apache.chemistry.opencmis.commons.enums.IncludeRelationships;
53  import org.apache.chemistry.opencmis.commons.enums.Updatability;
54  import org.apache.chemistry.opencmis.commons.enums.VersioningState;
55  import org.apache.chemistry.opencmis.commons.exceptions.CmisNotSupportedException;
56  import org.apache.chemistry.opencmis.commons.exceptions.CmisRuntimeException;
57  import org.apache.chemistry.opencmis.commons.impl.dataobjects.ContentStreamHashImpl;
58  import org.apache.chemistry.opencmis.commons.spi.Holder;
59  
60  public class DocumentImpl extends AbstractFilableCmisObject implements Document {
61  
62      private static final long serialVersionUID = 1L;
63  
64      /**
65       * Constructor.
66       */
67      public DocumentImpl(SessionImpl session, ObjectType objectType, ObjectData objectData, OperationContext context) {
68          initialize(session, objectType, objectData, context);
69      }
70  
71      @Override
72      public DocumentType getDocumentType() {
73          ObjectType objectType = super.getType();
74          if (objectType instanceof DocumentType) {
75              return (DocumentType) objectType;
76          } else {
77              throw new ClassCastException("Object type is not a document type.");
78          }
79      }
80  
81      @Override
82      public boolean isVersionable() {
83          return Boolean.TRUE.equals(getDocumentType().isVersionable());
84      }
85  
86      // properties
87  
88      @Override
89      public String getCheckinComment() {
90          return getPropertyValue(PropertyIds.CHECKIN_COMMENT);
91      }
92  
93      @Override
94      public String getVersionLabel() {
95          return getPropertyValue(PropertyIds.VERSION_LABEL);
96      }
97  
98      @Override
99      public String getVersionSeriesId() {
100         return getPropertyValue(PropertyIds.VERSION_SERIES_ID);
101     }
102 
103     @Override
104     public String getVersionSeriesCheckedOutId() {
105         return getPropertyValue(PropertyIds.VERSION_SERIES_CHECKED_OUT_ID);
106     }
107 
108     @Override
109     public String getVersionSeriesCheckedOutBy() {
110         return getPropertyValue(PropertyIds.VERSION_SERIES_CHECKED_OUT_BY);
111     }
112 
113     @Override
114     public Boolean isImmutable() {
115         return getPropertyValue(PropertyIds.IS_IMMUTABLE);
116     }
117 
118     @Override
119     public Boolean isLatestMajorVersion() {
120         return getPropertyValue(PropertyIds.IS_LATEST_MAJOR_VERSION);
121     }
122 
123     @Override
124     public Boolean isLatestVersion() {
125         return getPropertyValue(PropertyIds.IS_LATEST_VERSION);
126     }
127 
128     @Override
129     public Boolean isMajorVersion() {
130         return getPropertyValue(PropertyIds.IS_MAJOR_VERSION);
131     }
132 
133     @Override
134     public Boolean isPrivateWorkingCopy() {
135         return getPropertyValue(PropertyIds.IS_PRIVATE_WORKING_COPY);
136     }
137 
138     @Override
139     public Boolean isVersionSeriesCheckedOut() {
140         return getPropertyValue(PropertyIds.IS_VERSION_SERIES_CHECKED_OUT);
141     }
142 
143     @Override
144     public long getContentStreamLength() {
145         BigInteger bigInt = getPropertyValue(PropertyIds.CONTENT_STREAM_LENGTH);
146         return bigInt == null ? (long) -1 : bigInt.longValue();
147     }
148 
149     @Override
150     public String getContentStreamMimeType() {
151         return getPropertyValue(PropertyIds.CONTENT_STREAM_MIME_TYPE);
152     }
153 
154     @Override
155     public String getContentStreamFileName() {
156         return getPropertyValue(PropertyIds.CONTENT_STREAM_FILE_NAME);
157     }
158 
159     @Override
160     public String getContentStreamId() {
161         return getPropertyValue(PropertyIds.CONTENT_STREAM_ID);
162     }
163 
164     @Override
165     public List<ContentStreamHash> getContentStreamHashes() {
166         List<String> hashes = getPropertyValue(PropertyIds.CONTENT_STREAM_HASH);
167         if (isNullOrEmpty(hashes)) {
168             return null;
169         }
170 
171         List<ContentStreamHash> result = new ArrayList<ContentStreamHash>(hashes.size());
172         for (String hash : hashes) {
173             result.add(new ContentStreamHashImpl(hash));
174         }
175 
176         return result;
177     }
178 
179     @Override
180     public String getLatestAccessibleStateId() {
181         return getPropertyValue(PropertyIds.LATEST_ACCESSIBLE_STATE_ID);
182     }
183 
184     // operations
185 
186     @Override
187     public Document copy(ObjectId targetFolderId, Map<String, ?> properties, VersioningState versioningState,
188             List<Policy> policies, List<Ace> addAces, List<Ace> removeAces, OperationContext context) {
189 
190         ObjectId newId = null;
191         try {
192             newId = getSession().createDocumentFromSource(this, properties, targetFolderId, versioningState, policies,
193                     addAces, removeAces);
194         } catch (CmisNotSupportedException nse) {
195             newId = copyViaClient(targetFolderId, properties, versioningState, policies, addAces, removeAces);
196         }
197 
198         // if no context is provided the object will not be fetched
199         if (context == null || newId == null) {
200             return null;
201         }
202         // get the new object
203         CmisObject object = getSession().getObject(newId, context);
204         if (!(object instanceof Document)) {
205             throw new CmisRuntimeException("Newly created object is not a document! New id: " + newId);
206         }
207 
208         return (Document) object;
209     }
210 
211     @Override
212     public Document copy(ObjectId targetFolderId) {
213         return copy(targetFolderId, null, null, null, null, null, getSession().getDefaultContext());
214     }
215 
216     /**
217      * Copies the document manually. The content is streamed from the repository
218      * and back.
219      */
220     protected ObjectId copyViaClient(ObjectId targetFolderId, Map<String, ?> properties,
221             VersioningState versioningState, List<Policy> policies, List<Ace> addAces, List<Ace> removeAces) {
222         Map<String, Object> newProperties = new HashMap<String, Object>();
223 
224         OperationContext allPropsContext = getSession().createOperationContext();
225         allPropsContext.setFilterString("*");
226         allPropsContext.setIncludeAcls(false);
227         allPropsContext.setIncludeAllowableActions(false);
228         allPropsContext.setIncludePathSegments(false);
229         allPropsContext.setIncludePolicies(false);
230         allPropsContext.setIncludeRelationships(IncludeRelationships.NONE);
231         allPropsContext.setRenditionFilterString("cmis:none");
232 
233         Document allPropsDoc = (Document) getSession().getObject(this, allPropsContext);
234 
235         for (Property<?> prop : allPropsDoc.getProperties()) {
236             if (prop.getDefinition().getUpdatability() == Updatability.READWRITE
237                     || prop.getDefinition().getUpdatability() == Updatability.ONCREATE) {
238                 newProperties.put(prop.getId(), prop.getValue());
239             }
240         }
241 
242         if (properties != null) {
243             newProperties.putAll(properties);
244         }
245 
246         ContentStream contentStream = allPropsDoc.getContentStream();
247         try {
248             return getSession().createDocument(newProperties, targetFolderId, contentStream, versioningState, policies,
249                     addAces, removeAces);
250         } finally {
251             if (contentStream != null) {
252                 InputStream stream = contentStream.getStream();
253                 if (stream != null) {
254                     try {
255                         stream.close();
256                     } catch (IOException ioe) {
257                         throw new CmisRuntimeException("Cannot close source stream!", ioe);
258                     }
259                 }
260             }
261         }
262     }
263 
264     @Override
265     public void deleteAllVersions() {
266         delete(true);
267     }
268 
269     // versioning
270 
271     @Override
272     public ObjectId checkOut() {
273         String newObjectId = null;
274 
275         readLock();
276         try {
277             String objectId = getObjectId();
278             Holder<String> objectIdHolder = new Holder<String>(objectId);
279 
280             getBinding().getVersioningService().checkOut(getRepositoryId(), objectIdHolder, null, null);
281             newObjectId = objectIdHolder.getValue();
282         } finally {
283             readUnlock();
284         }
285 
286         // remove original version from cache, the path and a few versioning
287         // properties are not valid anymore
288         getSession().removeObjectFromCache(this);
289 
290         if (newObjectId == null) {
291             return null;
292         }
293 
294         return getSession().createObjectId(newObjectId);
295     }
296 
297     @Override
298     public void cancelCheckOut() {
299         String objectId = getObjectId();
300 
301         getBinding().getVersioningService().cancelCheckOut(getRepositoryId(), objectId, null);
302 
303         // remove PWC from cache, it doesn't exist anymore
304         getSession().removeObjectFromCache(this);
305     }
306 
307     @Override
308     public ObjectId checkIn(boolean major, Map<String, ?> properties, ContentStream contentStream,
309             String checkinComment, List<Policy> policies, List<Ace> addAces, List<Ace> removeAces) {
310         String newObjectId = null;
311 
312         readLock();
313         try {
314             Holder<String> objectIdHolder = new Holder<String>(getObjectId());
315 
316             ObjectFactory of = getObjectFactory();
317 
318             Set<Updatability> updatebility = EnumSet.noneOf(Updatability.class);
319             updatebility.add(Updatability.READWRITE);
320             updatebility.add(Updatability.WHENCHECKEDOUT);
321 
322             getBinding().getVersioningService().checkIn(getRepositoryId(), objectIdHolder, major,
323                     of.convertProperties(properties, getType(), getSecondaryTypes(), updatebility),
324                     of.convertContentStream(contentStream), checkinComment, of.convertPolicies(policies),
325                     of.convertAces(addAces), of.convertAces(removeAces), null);
326 
327             newObjectId = objectIdHolder.getValue();
328         } finally {
329             readUnlock();
330         }
331 
332         // remove PWC from cache, it doesn't exist anymore
333         getSession().removeObjectFromCache(this);
334 
335         if (newObjectId == null) {
336             return null;
337         }
338 
339         return getSession().createObjectId(newObjectId);
340     }
341 
342     @Override
343     public List<Document> getAllVersions() {
344         return getAllVersions(getSession().getDefaultContext());
345     }
346 
347     @Override
348     public List<Document> getAllVersions(OperationContext context) {
349         String objectId;
350         String versionSeriesId;
351 
352         readLock();
353         try {
354             objectId = getObjectId();
355             versionSeriesId = getVersionSeriesId();
356         } finally {
357             readUnlock();
358         }
359 
360         List<ObjectData> versions = getBinding().getVersioningService().getAllVersions(getRepositoryId(), objectId,
361                 versionSeriesId, context.getFilterString(), context.isIncludeAllowableActions(), null);
362 
363         ObjectFactory objectFactory = getSession().getObjectFactory();
364 
365         List<Document> result = new ArrayList<Document>();
366         if (versions != null) {
367             for (ObjectData objectData : versions) {
368                 CmisObject doc = objectFactory.convertObject(objectData, context);
369                 if (!(doc instanceof Document)) {
370                     // should not happen...
371                     continue;
372                 }
373 
374                 result.add((Document) doc);
375             }
376         }
377 
378         return result;
379 
380     }
381 
382     @Override
383     public Document getObjectOfLatestVersion(boolean major) {
384         return getObjectOfLatestVersion(major, getSession().getDefaultContext());
385     }
386 
387     @Override
388     public Document getObjectOfLatestVersion(boolean major, OperationContext context) {
389         return getSession().getLatestDocumentVersion(this, major, context);
390     }
391 
392     // content operations
393 
394     @Override
395     public ContentStream getContentStream() {
396         return getContentStream(null, null, null);
397     }
398 
399     @Override
400     public ContentStream getContentStream(BigInteger offset, BigInteger length) {
401         return getContentStream(null, offset, length);
402     }
403 
404     @Override
405     public ContentStream getContentStream(String streamId) {
406         return getContentStream(streamId, null, null);
407     }
408 
409     @Override
410     public ContentStream getContentStream(String streamId, BigInteger offset, BigInteger length) {
411         // get the stream
412         ContentStream contentStream = getSession().getContentStream(this, streamId, offset, length);
413 
414         if (contentStream == null) {
415             return null;
416         }
417 
418         // the AtomPub binding doesn't return a file name
419         // -> get the file name from properties, if present
420         String filename = contentStream.getFileName();
421         if (filename == null) {
422             filename = getContentStreamFileName();
423         }
424 
425         long lengthLong = (contentStream.getBigLength() == null ? -1 : contentStream.getBigLength().longValue());
426 
427         // convert and return stream object
428         return getSession().getObjectFactory().createContentStream(filename, lengthLong, contentStream.getMimeType(),
429                 contentStream.getStream(), contentStream instanceof PartialContentStream);
430     }
431 
432     @Override
433     public String getContentUrl() {
434         return getContentUrl(null);
435     }
436 
437     @Override
438     public String getContentUrl(String streamId) {
439         if (getBinding().getObjectService() instanceof LinkAccess) {
440             LinkAccess linkAccess = (LinkAccess) getBinding().getObjectService();
441 
442             if (streamId == null) {
443                 return linkAccess.loadContentLink(getRepositoryId(), getId());
444             } else {
445                 return linkAccess.loadRenditionContentLink(getRepositoryId(), getId(), streamId);
446             }
447         }
448 
449         return null;
450     }
451 
452     @Override
453     public Document setContentStream(ContentStream contentStream, boolean overwrite) {
454         ObjectId objectId = setContentStream(contentStream, overwrite, true);
455         if (objectId == null) {
456             return null;
457         }
458 
459         if (!getObjectId().equals(objectId.getId())) {
460             return (Document) getSession().getObject(objectId, getCreationContext());
461         }
462 
463         return this;
464     }
465 
466     @Override
467     public ObjectId setContentStream(ContentStream contentStream, boolean overwrite, boolean refresh) {
468         String newObjectId = null;
469 
470         readLock();
471         try {
472             Holder<String> objectIdHolder = new Holder<String>(getObjectId());
473             Holder<String> changeTokenHolder = new Holder<String>((String) getPropertyValue(PropertyIds.CHANGE_TOKEN));
474 
475             getBinding().getObjectService().setContentStream(getRepositoryId(), objectIdHolder, overwrite,
476                     changeTokenHolder, getObjectFactory().convertContentStream(contentStream), null);
477 
478             newObjectId = objectIdHolder.getValue();
479         } finally {
480             readUnlock();
481         }
482 
483         if (refresh) {
484             refresh();
485         }
486 
487         if (newObjectId == null) {
488             return null;
489         }
490 
491         return getSession().createObjectId(newObjectId);
492     }
493 
494     @Override
495     public Document appendContentStream(ContentStream contentStream, boolean isLastChunk) {
496         if (getSession().getRepositoryInfo().getCmisVersion() == CmisVersion.CMIS_1_0) {
497             throw new CmisNotSupportedException("This method is not supported for CMIS 1.0 repositories.");
498         }
499 
500         ObjectId objectId = appendContentStream(contentStream, isLastChunk, true);
501         if (objectId == null) {
502             return null;
503         }
504 
505         if (!getObjectId().equals(objectId.getId())) {
506             return (Document) getSession().getObject(objectId, getCreationContext());
507         }
508 
509         return this;
510     }
511 
512     @Override
513     public ObjectId appendContentStream(ContentStream contentStream, boolean isLastChunk, boolean refresh) {
514         if (getSession().getRepositoryInfo().getCmisVersion() == CmisVersion.CMIS_1_0) {
515             throw new CmisNotSupportedException("This method is not supported for CMIS 1.0 repositories.");
516         }
517 
518         String newObjectId = null;
519 
520         readLock();
521         try {
522             Holder<String> objectIdHolder = new Holder<String>(getObjectId());
523             Holder<String> changeTokenHolder = new Holder<String>((String) getPropertyValue(PropertyIds.CHANGE_TOKEN));
524 
525             getBinding().getObjectService().appendContentStream(getRepositoryId(), objectIdHolder, changeTokenHolder,
526                     getObjectFactory().convertContentStream(contentStream), isLastChunk, null);
527 
528             newObjectId = objectIdHolder.getValue();
529         } finally {
530             readUnlock();
531         }
532 
533         if (refresh) {
534             refresh();
535         }
536 
537         if (newObjectId == null) {
538             return null;
539         }
540 
541         return getSession().createObjectId(newObjectId);
542     }
543 
544     @Override
545     public Document deleteContentStream() {
546         ObjectId objectId = deleteContentStream(true);
547         if (objectId == null) {
548             return null;
549         }
550 
551         if (!getObjectId().equals(objectId.getId())) {
552             return (Document) getSession().getObject(objectId, getCreationContext());
553         }
554 
555         return this;
556     }
557 
558     @Override
559     public ObjectId deleteContentStream(boolean refresh) {
560         String newObjectId = null;
561 
562         readLock();
563         try {
564             Holder<String> objectIdHolder = new Holder<String>(getObjectId());
565             Holder<String> changeTokenHolder = new Holder<String>((String) getPropertyValue(PropertyIds.CHANGE_TOKEN));
566 
567             getBinding().getObjectService().deleteContentStream(getRepositoryId(), objectIdHolder, changeTokenHolder,
568                     null);
569 
570             newObjectId = objectIdHolder.getValue();
571         } finally {
572             readUnlock();
573         }
574 
575         if (refresh) {
576             refresh();
577         }
578 
579         if (newObjectId == null) {
580             return null;
581         }
582 
583         return getSession().createObjectId(newObjectId);
584     }
585 
586     @Override
587     public OutputStream createOverwriteOutputStream(String filename, String mimeType) {
588         if (getSession().getRepositoryInfo().getCmisVersion() == CmisVersion.CMIS_1_0) {
589             throw new CmisNotSupportedException("This method is not supported for CMIS 1.0 repositories.");
590         }
591 
592         return new AppendOutputStream(getSession(), this, true, filename, mimeType);
593     }
594 
595     @Override
596     public OutputStream createOverwriteOutputStream(String filename, String mimeType, int bufferSize) {
597         if (getSession().getRepositoryInfo().getCmisVersion() == CmisVersion.CMIS_1_0) {
598             throw new CmisNotSupportedException("This method is not supported for CMIS 1.0 repositories.");
599         }
600 
601         return new AppendOutputStream(getSession(), this, true, filename, mimeType, bufferSize);
602     }
603 
604     @Override
605     public OutputStream createAppendOutputStream() {
606         if (getSession().getRepositoryInfo().getCmisVersion() == CmisVersion.CMIS_1_0) {
607             throw new CmisNotSupportedException("This method is not supported for CMIS 1.0 repositories.");
608         }
609 
610         return new AppendOutputStream(getSession(), this, false, null, null);
611     }
612 
613     @Override
614     public OutputStream createAppendOutputStream(int bufferSize) {
615         if (getSession().getRepositoryInfo().getCmisVersion() == CmisVersion.CMIS_1_0) {
616             throw new CmisNotSupportedException("This method is not supported for CMIS 1.0 repositories.");
617         }
618 
619         return new AppendOutputStream(getSession(), this, false, null, null, bufferSize);
620     }
621 
622     @Override
623     public ObjectId checkIn(boolean major, Map<String, ?> properties, ContentStream contentStream, String checkinComment) {
624         return this.checkIn(major, properties, contentStream, checkinComment, null, null, null);
625     }
626 }