1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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
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 @Override
87 public Boolean isVersionSeriesPrivateWorkingCopy() {
88 if (Boolean.FALSE.equals(getDocumentType().isVersionable())) {
89 return false;
90 }
91
92 Boolean isCheckedOut = isVersionSeriesCheckedOut();
93 if (Boolean.FALSE.equals(isCheckedOut)) {
94 return false;
95 }
96
97 Boolean isPWC = isPrivateWorkingCopy();
98 if (isPWC != null) {
99 return isPWC;
100 }
101
102 String vsCoId = getVersionSeriesCheckedOutId();
103 if (vsCoId == null) {
104
105 return null;
106 }
107
108 return vsCoId.equals(getId());
109 }
110
111
112
113 @Override
114 public String getCheckinComment() {
115 return getPropertyValue(PropertyIds.CHECKIN_COMMENT);
116 }
117
118 @Override
119 public String getVersionLabel() {
120 return getPropertyValue(PropertyIds.VERSION_LABEL);
121 }
122
123 @Override
124 public String getVersionSeriesId() {
125 return getPropertyValue(PropertyIds.VERSION_SERIES_ID);
126 }
127
128 @Override
129 public String getVersionSeriesCheckedOutId() {
130 return getPropertyValue(PropertyIds.VERSION_SERIES_CHECKED_OUT_ID);
131 }
132
133 @Override
134 public String getVersionSeriesCheckedOutBy() {
135 return getPropertyValue(PropertyIds.VERSION_SERIES_CHECKED_OUT_BY);
136 }
137
138 @Override
139 public Boolean isImmutable() {
140 return getPropertyValue(PropertyIds.IS_IMMUTABLE);
141 }
142
143 @Override
144 public Boolean isLatestMajorVersion() {
145 return getPropertyValue(PropertyIds.IS_LATEST_MAJOR_VERSION);
146 }
147
148 @Override
149 public Boolean isLatestVersion() {
150 return getPropertyValue(PropertyIds.IS_LATEST_VERSION);
151 }
152
153 @Override
154 public Boolean isMajorVersion() {
155 return getPropertyValue(PropertyIds.IS_MAJOR_VERSION);
156 }
157
158 @Override
159 public Boolean isPrivateWorkingCopy() {
160 return getPropertyValue(PropertyIds.IS_PRIVATE_WORKING_COPY);
161 }
162
163 @Override
164 public Boolean isVersionSeriesCheckedOut() {
165 return getPropertyValue(PropertyIds.IS_VERSION_SERIES_CHECKED_OUT);
166 }
167
168 @Override
169 public long getContentStreamLength() {
170 BigInteger bigInt = getPropertyValue(PropertyIds.CONTENT_STREAM_LENGTH);
171 return bigInt == null ? (long) -1 : bigInt.longValue();
172 }
173
174 @Override
175 public String getContentStreamMimeType() {
176 return getPropertyValue(PropertyIds.CONTENT_STREAM_MIME_TYPE);
177 }
178
179 @Override
180 public String getContentStreamFileName() {
181 return getPropertyValue(PropertyIds.CONTENT_STREAM_FILE_NAME);
182 }
183
184 @Override
185 public String getContentStreamId() {
186 return getPropertyValue(PropertyIds.CONTENT_STREAM_ID);
187 }
188
189 @Override
190 public List<ContentStreamHash> getContentStreamHashes() {
191 List<String> hashes = getPropertyValue(PropertyIds.CONTENT_STREAM_HASH);
192 if (isNullOrEmpty(hashes)) {
193 return null;
194 }
195
196 List<ContentStreamHash> result = new ArrayList<ContentStreamHash>(hashes.size());
197 for (String hash : hashes) {
198 result.add(new ContentStreamHashImpl(hash));
199 }
200
201 return result;
202 }
203
204 @Override
205 public String getLatestAccessibleStateId() {
206 return getPropertyValue(PropertyIds.LATEST_ACCESSIBLE_STATE_ID);
207 }
208
209
210
211 @Override
212 public Document copy(ObjectId targetFolderId, Map<String, ?> properties, VersioningState versioningState,
213 List<Policy> policies, List<Ace> addAces, List<Ace> removeAces, OperationContext context) {
214
215 ObjectId newId = null;
216 try {
217 newId = getSession().createDocumentFromSource(this, properties, targetFolderId, versioningState, policies,
218 addAces, removeAces);
219 } catch (CmisNotSupportedException nse) {
220 newId = copyViaClient(targetFolderId, properties, versioningState, policies, addAces, removeAces);
221 }
222
223
224 if (context == null || newId == null) {
225 return null;
226 }
227
228 CmisObject object = getSession().getObject(newId, context);
229 if (!(object instanceof Document)) {
230 throw new CmisRuntimeException("Newly created object is not a document! New id: " + newId);
231 }
232
233 return (Document) object;
234 }
235
236 @Override
237 public Document copy(ObjectId targetFolderId) {
238 return copy(targetFolderId, null, null, null, null, null, getSession().getDefaultContext());
239 }
240
241
242
243
244
245 protected ObjectId copyViaClient(ObjectId targetFolderId, Map<String, ?> properties,
246 VersioningState versioningState, List<Policy> policies, List<Ace> addAces, List<Ace> removeAces) {
247 Map<String, Object> newProperties = new HashMap<String, Object>();
248
249 OperationContext allPropsContext = getSession().createOperationContext();
250 allPropsContext.setFilterString("*");
251 allPropsContext.setIncludeAcls(false);
252 allPropsContext.setIncludeAllowableActions(false);
253 allPropsContext.setIncludePathSegments(false);
254 allPropsContext.setIncludePolicies(false);
255 allPropsContext.setIncludeRelationships(IncludeRelationships.NONE);
256 allPropsContext.setRenditionFilterString("cmis:none");
257
258 Document allPropsDoc = (Document) getSession().getObject(this, allPropsContext);
259
260 for (Property<?> prop : allPropsDoc.getProperties()) {
261 if (prop.getDefinition().getUpdatability() == Updatability.READWRITE
262 || prop.getDefinition().getUpdatability() == Updatability.ONCREATE) {
263 newProperties.put(prop.getId(), prop.getValue());
264 }
265 }
266
267 if (properties != null) {
268 newProperties.putAll(properties);
269 }
270
271 ContentStream contentStream = allPropsDoc.getContentStream();
272 try {
273 return getSession().createDocument(newProperties, targetFolderId, contentStream, versioningState, policies,
274 addAces, removeAces);
275 } finally {
276 if (contentStream != null) {
277 InputStream stream = contentStream.getStream();
278 if (stream != null) {
279 try {
280 stream.close();
281 } catch (IOException ioe) {
282 throw new CmisRuntimeException("Cannot close source stream!", ioe);
283 }
284 }
285 }
286 }
287 }
288
289 @Override
290 public void deleteAllVersions() {
291 delete(true);
292 }
293
294
295
296 @Override
297 public ObjectId checkOut() {
298 String newObjectId = null;
299
300 readLock();
301 try {
302 String objectId = getObjectId();
303 Holder<String> objectIdHolder = new Holder<String>(objectId);
304
305 getBinding().getVersioningService().checkOut(getRepositoryId(), objectIdHolder, null, null);
306 newObjectId = objectIdHolder.getValue();
307 } finally {
308 readUnlock();
309 }
310
311
312
313 getSession().removeObjectFromCache(this);
314
315 if (newObjectId == null) {
316 return null;
317 }
318
319 return getSession().createObjectId(newObjectId);
320 }
321
322 @Override
323 public void cancelCheckOut() {
324 String objectId = getObjectId();
325
326 getBinding().getVersioningService().cancelCheckOut(getRepositoryId(), objectId, null);
327
328
329 getSession().removeObjectFromCache(this);
330 }
331
332 @Override
333 public ObjectId checkIn(boolean major, Map<String, ?> properties, ContentStream contentStream,
334 String checkinComment, List<Policy> policies, List<Ace> addAces, List<Ace> removeAces) {
335 String newObjectId = null;
336
337 readLock();
338 try {
339 Holder<String> objectIdHolder = new Holder<String>(getObjectId());
340
341 ObjectFactory of = getObjectFactory();
342
343 Set<Updatability> updatebility = EnumSet.noneOf(Updatability.class);
344 updatebility.add(Updatability.READWRITE);
345 updatebility.add(Updatability.WHENCHECKEDOUT);
346
347 getBinding().getVersioningService().checkIn(getRepositoryId(), objectIdHolder, major,
348 of.convertProperties(properties, getType(), getSecondaryTypes(), updatebility),
349 of.convertContentStream(contentStream), checkinComment, of.convertPolicies(policies),
350 of.convertAces(addAces), of.convertAces(removeAces), null);
351
352 newObjectId = objectIdHolder.getValue();
353 } finally {
354 readUnlock();
355 }
356
357
358 getSession().removeObjectFromCache(this);
359
360 if (newObjectId == null) {
361 return null;
362 }
363
364 return getSession().createObjectId(newObjectId);
365 }
366
367 @Override
368 public List<Document> getAllVersions() {
369 return getAllVersions(getSession().getDefaultContext());
370 }
371
372 @Override
373 public List<Document> getAllVersions(OperationContext context) {
374 String objectId;
375 String versionSeriesId;
376
377 readLock();
378 try {
379 objectId = getObjectId();
380 versionSeriesId = getVersionSeriesId();
381 } finally {
382 readUnlock();
383 }
384
385 List<ObjectData> versions = getBinding().getVersioningService().getAllVersions(getRepositoryId(), objectId,
386 versionSeriesId, context.getFilterString(), context.isIncludeAllowableActions(), null);
387
388 ObjectFactory objectFactory = getSession().getObjectFactory();
389
390 List<Document> result = new ArrayList<Document>();
391 if (versions != null) {
392 for (ObjectData objectData : versions) {
393 CmisObject doc = objectFactory.convertObject(objectData, context);
394 if (!(doc instanceof Document)) {
395
396 continue;
397 }
398
399 result.add((Document) doc);
400 }
401 }
402
403 return result;
404
405 }
406
407 @Override
408 public Document getObjectOfLatestVersion(boolean major) {
409 return getObjectOfLatestVersion(major, getSession().getDefaultContext());
410 }
411
412 @Override
413 public Document getObjectOfLatestVersion(boolean major, OperationContext context) {
414 return getSession().getLatestDocumentVersion(this, major, context);
415 }
416
417
418
419 @Override
420 public ContentStream getContentStream() {
421 return getContentStream(null, null, null);
422 }
423
424 @Override
425 public ContentStream getContentStream(BigInteger offset, BigInteger length) {
426 return getContentStream(null, offset, length);
427 }
428
429 @Override
430 public ContentStream getContentStream(String streamId) {
431 return getContentStream(streamId, null, null);
432 }
433
434 @Override
435 public ContentStream getContentStream(String streamId, BigInteger offset, BigInteger length) {
436
437 ContentStream contentStream = getSession().getContentStream(this, streamId, offset, length);
438
439 if (contentStream == null) {
440 return null;
441 }
442
443
444
445 String filename = contentStream.getFileName();
446 if (filename == null) {
447 filename = getContentStreamFileName();
448 }
449
450 long lengthLong = (contentStream.getBigLength() == null ? -1 : contentStream.getBigLength().longValue());
451
452
453 return getSession().getObjectFactory().createContentStream(filename, lengthLong, contentStream.getMimeType(),
454 contentStream.getStream(), contentStream instanceof PartialContentStream);
455 }
456
457 @Override
458 public String getContentUrl() {
459 return getContentUrl(null);
460 }
461
462 @Override
463 public String getContentUrl(String streamId) {
464 if (getBinding().getObjectService() instanceof LinkAccess) {
465 LinkAccess linkAccess = (LinkAccess) getBinding().getObjectService();
466
467 if (streamId == null) {
468 return linkAccess.loadContentLink(getRepositoryId(), getId());
469 } else {
470 return linkAccess.loadRenditionContentLink(getRepositoryId(), getId(), streamId);
471 }
472 }
473
474 return null;
475 }
476
477 @Override
478 public Document setContentStream(ContentStream contentStream, boolean overwrite) {
479 ObjectId objectId = setContentStream(contentStream, overwrite, true);
480 if (objectId == null) {
481 return null;
482 }
483
484 if (!getObjectId().equals(objectId.getId())) {
485 return (Document) getSession().getObject(objectId, getCreationContext());
486 }
487
488 return this;
489 }
490
491 @Override
492 public ObjectId setContentStream(ContentStream contentStream, boolean overwrite, boolean refresh) {
493 String newObjectId = null;
494
495 readLock();
496 try {
497 Holder<String> objectIdHolder = new Holder<String>(getObjectId());
498 Holder<String> changeTokenHolder = new Holder<String>((String) getPropertyValue(PropertyIds.CHANGE_TOKEN));
499
500 getBinding().getObjectService().setContentStream(getRepositoryId(), objectIdHolder, overwrite,
501 changeTokenHolder, getObjectFactory().convertContentStream(contentStream), null);
502
503 newObjectId = objectIdHolder.getValue();
504 } finally {
505 readUnlock();
506 }
507
508 if (refresh) {
509 refresh();
510 }
511
512 if (newObjectId == null) {
513 return null;
514 }
515
516 return getSession().createObjectId(newObjectId);
517 }
518
519 @Override
520 public Document appendContentStream(ContentStream contentStream, boolean isLastChunk) {
521 if (getSession().getRepositoryInfo().getCmisVersion() == CmisVersion.CMIS_1_0) {
522 throw new CmisNotSupportedException("This method is not supported for CMIS 1.0 repositories.");
523 }
524
525 ObjectId objectId = appendContentStream(contentStream, isLastChunk, true);
526 if (objectId == null) {
527 return null;
528 }
529
530 if (!getObjectId().equals(objectId.getId())) {
531 return (Document) getSession().getObject(objectId, getCreationContext());
532 }
533
534 return this;
535 }
536
537 @Override
538 public ObjectId appendContentStream(ContentStream contentStream, boolean isLastChunk, boolean refresh) {
539 if (getSession().getRepositoryInfo().getCmisVersion() == CmisVersion.CMIS_1_0) {
540 throw new CmisNotSupportedException("This method is not supported for CMIS 1.0 repositories.");
541 }
542
543 String newObjectId = null;
544
545 readLock();
546 try {
547 Holder<String> objectIdHolder = new Holder<String>(getObjectId());
548 Holder<String> changeTokenHolder = new Holder<String>((String) getPropertyValue(PropertyIds.CHANGE_TOKEN));
549
550 getBinding().getObjectService().appendContentStream(getRepositoryId(), objectIdHolder, changeTokenHolder,
551 getObjectFactory().convertContentStream(contentStream), isLastChunk, null);
552
553 newObjectId = objectIdHolder.getValue();
554 } finally {
555 readUnlock();
556 }
557
558 if (refresh) {
559 refresh();
560 }
561
562 if (newObjectId == null) {
563 return null;
564 }
565
566 return getSession().createObjectId(newObjectId);
567 }
568
569 @Override
570 public Document deleteContentStream() {
571 ObjectId objectId = deleteContentStream(true);
572 if (objectId == null) {
573 return null;
574 }
575
576 if (!getObjectId().equals(objectId.getId())) {
577 return (Document) getSession().getObject(objectId, getCreationContext());
578 }
579
580 return this;
581 }
582
583 @Override
584 public ObjectId deleteContentStream(boolean refresh) {
585 String newObjectId = null;
586
587 readLock();
588 try {
589 Holder<String> objectIdHolder = new Holder<String>(getObjectId());
590 Holder<String> changeTokenHolder = new Holder<String>((String) getPropertyValue(PropertyIds.CHANGE_TOKEN));
591
592 getBinding().getObjectService().deleteContentStream(getRepositoryId(), objectIdHolder, changeTokenHolder,
593 null);
594
595 newObjectId = objectIdHolder.getValue();
596 } finally {
597 readUnlock();
598 }
599
600 if (refresh) {
601 refresh();
602 }
603
604 if (newObjectId == null) {
605 return null;
606 }
607
608 return getSession().createObjectId(newObjectId);
609 }
610
611 @Override
612 public OutputStream createOverwriteOutputStream(String filename, String mimeType) {
613 if (getSession().getRepositoryInfo().getCmisVersion() == CmisVersion.CMIS_1_0) {
614 throw new CmisNotSupportedException("This method is not supported for CMIS 1.0 repositories.");
615 }
616
617 return new AppendOutputStream(getSession(), this, true, filename, mimeType);
618 }
619
620 @Override
621 public OutputStream createOverwriteOutputStream(String filename, String mimeType, int bufferSize) {
622 if (getSession().getRepositoryInfo().getCmisVersion() == CmisVersion.CMIS_1_0) {
623 throw new CmisNotSupportedException("This method is not supported for CMIS 1.0 repositories.");
624 }
625
626 return new AppendOutputStream(getSession(), this, true, filename, mimeType, bufferSize);
627 }
628
629 @Override
630 public OutputStream createAppendOutputStream() {
631 if (getSession().getRepositoryInfo().getCmisVersion() == CmisVersion.CMIS_1_0) {
632 throw new CmisNotSupportedException("This method is not supported for CMIS 1.0 repositories.");
633 }
634
635 return new AppendOutputStream(getSession(), this, false, null, null);
636 }
637
638 @Override
639 public OutputStream createAppendOutputStream(int bufferSize) {
640 if (getSession().getRepositoryInfo().getCmisVersion() == CmisVersion.CMIS_1_0) {
641 throw new CmisNotSupportedException("This method is not supported for CMIS 1.0 repositories.");
642 }
643
644 return new AppendOutputStream(getSession(), this, false, null, null, bufferSize);
645 }
646
647 @Override
648 public ObjectId checkIn(boolean major, Map<String, ?> properties, ContentStream contentStream,
649 String checkinComment) {
650 return this.checkIn(major, properties, contentStream, checkinComment, null, null, null);
651 }
652 }