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.bindings.spi.atompub;
20
21 import java.io.IOException;
22 import java.io.InputStream;
23 import java.io.OutputStream;
24 import java.math.BigInteger;
25 import java.util.ArrayList;
26 import java.util.Collections;
27 import java.util.List;
28 import java.util.Map;
29
30 import javax.xml.stream.XMLStreamException;
31
32 import org.apache.chemistry.opencmis.client.bindings.spi.BindingSession;
33 import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomAllowableActions;
34 import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomElement;
35 import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomEntry;
36 import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomFeed;
37 import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomLink;
38 import org.apache.chemistry.opencmis.client.bindings.spi.http.Output;
39 import org.apache.chemistry.opencmis.client.bindings.spi.http.Response;
40 import org.apache.chemistry.opencmis.commons.PropertyIds;
41 import org.apache.chemistry.opencmis.commons.SessionParameter;
42 import org.apache.chemistry.opencmis.commons.data.Acl;
43 import org.apache.chemistry.opencmis.commons.data.AllowableActions;
44 import org.apache.chemistry.opencmis.commons.data.BulkUpdateObjectIdAndChangeToken;
45 import org.apache.chemistry.opencmis.commons.data.ContentStream;
46 import org.apache.chemistry.opencmis.commons.data.ExtensionsData;
47 import org.apache.chemistry.opencmis.commons.data.FailedToDeleteData;
48 import org.apache.chemistry.opencmis.commons.data.ObjectData;
49 import org.apache.chemistry.opencmis.commons.data.Properties;
50 import org.apache.chemistry.opencmis.commons.data.PropertyData;
51 import org.apache.chemistry.opencmis.commons.data.PropertyId;
52 import org.apache.chemistry.opencmis.commons.data.PropertyString;
53 import org.apache.chemistry.opencmis.commons.data.RenditionData;
54 import org.apache.chemistry.opencmis.commons.enums.IncludeRelationships;
55 import org.apache.chemistry.opencmis.commons.enums.UnfileObject;
56 import org.apache.chemistry.opencmis.commons.enums.VersioningState;
57 import org.apache.chemistry.opencmis.commons.exceptions.CmisConnectionException;
58 import org.apache.chemistry.opencmis.commons.exceptions.CmisConstraintException;
59 import org.apache.chemistry.opencmis.commons.exceptions.CmisInvalidArgumentException;
60 import org.apache.chemistry.opencmis.commons.exceptions.CmisNotSupportedException;
61 import org.apache.chemistry.opencmis.commons.exceptions.CmisObjectNotFoundException;
62 import org.apache.chemistry.opencmis.commons.impl.Constants;
63 import org.apache.chemistry.opencmis.commons.impl.IOUtils;
64 import org.apache.chemistry.opencmis.commons.impl.MimeHelper;
65 import org.apache.chemistry.opencmis.commons.impl.ReturnVersion;
66 import org.apache.chemistry.opencmis.commons.impl.UrlBuilder;
67 import org.apache.chemistry.opencmis.commons.impl.dataobjects.BulkUpdateImpl;
68 import org.apache.chemistry.opencmis.commons.impl.dataobjects.BulkUpdateObjectIdAndChangeTokenImpl;
69 import org.apache.chemistry.opencmis.commons.impl.dataobjects.ContentStreamImpl;
70 import org.apache.chemistry.opencmis.commons.impl.dataobjects.FailedToDeleteDataImpl;
71 import org.apache.chemistry.opencmis.commons.impl.dataobjects.PartialContentStreamImpl;
72 import org.apache.chemistry.opencmis.commons.spi.Holder;
73 import org.apache.chemistry.opencmis.commons.spi.ObjectService;
74
75
76
77
78 public class ObjectServiceImpl extends AbstractAtomPubService implements ObjectService {
79
80
81
82
83 public ObjectServiceImpl(BindingSession session) {
84 setSession(session);
85 }
86
87 @Override
88 public String createDocument(String repositoryId, Properties properties, String folderId,
89 ContentStream contentStream, VersioningState versioningState, List<String> policies, Acl addAces,
90 Acl removeAces, ExtensionsData extension) {
91 checkCreateProperties(properties);
92
93
94 String link = null;
95
96 if (folderId == null) {
97
98
99
100
101 link = loadCollection(repositoryId, Constants.COLLECTION_UNFILED);
102
103 if (link == null) {
104 throw new CmisObjectNotFoundException("Unknown repository or unfiling not supported!");
105 }
106 } else {
107 link = loadLink(repositoryId, folderId, Constants.REL_DOWN, Constants.MEDIATYPE_CHILDREN);
108
109 if (link == null) {
110 throwLinkException(repositoryId, folderId, Constants.REL_DOWN, Constants.MEDIATYPE_CHILDREN);
111 }
112 }
113
114 UrlBuilder url = new UrlBuilder(link);
115 url.addParameter(Constants.PARAM_VERSIONIG_STATE, versioningState);
116
117
118 final AtomEntryWriter entryWriter = new AtomEntryWriter(createObject(properties, null, policies),
119 getCmisVersion(repositoryId), contentStream);
120
121
122 Response resp = post(url, Constants.MEDIATYPE_ENTRY, new Output() {
123 @Override
124 public void write(OutputStream out) throws XMLStreamException, IOException {
125 entryWriter.write(out);
126 }
127 });
128
129
130 AtomEntry entry = parse(resp.getStream(), AtomEntry.class);
131
132
133 handleAclModifications(repositoryId, entry, addAces, removeAces);
134
135 return entry.getId();
136 }
137
138 @Override
139 public String createDocumentFromSource(String repositoryId, String sourceId, Properties properties,
140 String folderId, VersioningState versioningState, List<String> policies, Acl addACEs, Acl removeACEs,
141 ExtensionsData extension) {
142 throw new CmisNotSupportedException("createDocumentFromSource is not supported by the AtomPub binding!");
143 }
144
145 @Override
146 public String createFolder(String repositoryId, Properties properties, String folderId, List<String> policies,
147 Acl addAces, Acl removeAces, ExtensionsData extension) {
148 checkCreateProperties(properties);
149
150
151 String link = loadLink(repositoryId, folderId, Constants.REL_DOWN, Constants.MEDIATYPE_CHILDREN);
152
153 if (link == null) {
154 throwLinkException(repositoryId, folderId, Constants.REL_DOWN, Constants.MEDIATYPE_CHILDREN);
155 }
156
157 UrlBuilder url = new UrlBuilder(link);
158
159
160 final AtomEntryWriter entryWriter = new AtomEntryWriter(createObject(properties, null, policies),
161 getCmisVersion(repositoryId));
162
163
164 Response resp = post(url, Constants.MEDIATYPE_ENTRY, new Output() {
165 @Override
166 public void write(OutputStream out) throws XMLStreamException, IOException {
167 entryWriter.write(out);
168 }
169 });
170
171
172 AtomEntry entry = parse(resp.getStream(), AtomEntry.class);
173
174
175 handleAclModifications(repositoryId, entry, addAces, removeAces);
176
177 return entry.getId();
178 }
179
180 @Override
181 public String createPolicy(String repositoryId, Properties properties, String folderId, List<String> policies,
182 Acl addAces, Acl removeAces, ExtensionsData extension) {
183 checkCreateProperties(properties);
184
185
186 String link = null;
187
188 if (folderId == null) {
189
190
191
192
193 link = loadCollection(repositoryId, Constants.COLLECTION_UNFILED);
194
195 if (link == null) {
196 throw new CmisObjectNotFoundException("Unknown repository or unfiling not supported!");
197 }
198 } else {
199 link = loadLink(repositoryId, folderId, Constants.REL_DOWN, Constants.MEDIATYPE_CHILDREN);
200
201 if (link == null) {
202 throwLinkException(repositoryId, folderId, Constants.REL_DOWN, Constants.MEDIATYPE_CHILDREN);
203 }
204 }
205
206 UrlBuilder url = new UrlBuilder(link);
207
208
209 final AtomEntryWriter entryWriter = new AtomEntryWriter(createObject(properties, null, policies),
210 getCmisVersion(repositoryId));
211
212
213 Response resp = post(url, Constants.MEDIATYPE_ENTRY, new Output() {
214 @Override
215 public void write(OutputStream out) throws XMLStreamException, IOException {
216 entryWriter.write(out);
217 }
218 });
219
220
221 AtomEntry entry = parse(resp.getStream(), AtomEntry.class);
222
223
224 handleAclModifications(repositoryId, entry, addAces, removeAces);
225
226 return entry.getId();
227 }
228
229 @Override
230 public String createItem(String repositoryId, Properties properties, String folderId, List<String> policies,
231 Acl addAces, Acl removeAces, ExtensionsData extension) {
232 checkCreateProperties(properties);
233
234
235 String link = null;
236
237 if (folderId == null) {
238 link = loadCollection(repositoryId, Constants.COLLECTION_UNFILED);
239
240 if (link == null) {
241 throw new CmisObjectNotFoundException("Unknown repository or unfiling not supported!");
242 }
243 } else {
244 link = loadLink(repositoryId, folderId, Constants.REL_DOWN, Constants.MEDIATYPE_CHILDREN);
245
246 if (link == null) {
247 throwLinkException(repositoryId, folderId, Constants.REL_DOWN, Constants.MEDIATYPE_CHILDREN);
248 }
249 }
250
251 UrlBuilder url = new UrlBuilder(link);
252
253
254 final AtomEntryWriter entryWriter = new AtomEntryWriter(createObject(properties, null, policies),
255 getCmisVersion(repositoryId));
256
257
258 Response resp = post(url, Constants.MEDIATYPE_ENTRY, new Output() {
259 @Override
260 public void write(OutputStream out) throws XMLStreamException, IOException {
261 entryWriter.write(out);
262 }
263 });
264
265
266 AtomEntry entry = parse(resp.getStream(), AtomEntry.class);
267
268
269 handleAclModifications(repositoryId, entry, addAces, removeAces);
270
271 return entry.getId();
272 }
273
274 @Override
275 public String createRelationship(String repositoryId, Properties properties, List<String> policies, Acl addAces,
276 Acl removeAces, ExtensionsData extension) {
277 checkCreateProperties(properties);
278
279
280 PropertyData<?> sourceIdProperty = properties.getProperties().get(PropertyIds.SOURCE_ID);
281 if (!(sourceIdProperty instanceof PropertyId)) {
282 throw new CmisInvalidArgumentException("Source Id is not set!");
283 }
284
285 String sourceId = ((PropertyId) sourceIdProperty).getFirstValue();
286 if (sourceId == null) {
287 throw new CmisInvalidArgumentException("Source Id is not set!");
288 }
289
290
291 String link = loadLink(repositoryId, sourceId, Constants.REL_RELATIONSHIPS, Constants.MEDIATYPE_FEED);
292
293 if (link == null) {
294 throwLinkException(repositoryId, sourceId, Constants.REL_RELATIONSHIPS, Constants.MEDIATYPE_FEED);
295 }
296
297 UrlBuilder url = new UrlBuilder(link);
298
299
300 final AtomEntryWriter entryWriter = new AtomEntryWriter(createObject(properties, null, policies),
301 getCmisVersion(repositoryId));
302
303
304 Response resp = post(url, Constants.MEDIATYPE_ENTRY, new Output() {
305 @Override
306 public void write(OutputStream out) throws XMLStreamException, IOException {
307 entryWriter.write(out);
308 }
309 });
310
311
312 AtomEntry entry = parse(resp.getStream(), AtomEntry.class);
313
314
315 handleAclModifications(repositoryId, entry, addAces, removeAces);
316
317 return entry.getId();
318 }
319
320 @Override
321 public void updateProperties(String repositoryId, Holder<String> objectId, Holder<String> changeToken,
322 Properties properties, ExtensionsData extension) {
323
324 if ((objectId == null) || (objectId.getValue() == null) || (objectId.getValue().length() == 0)) {
325 throw new CmisInvalidArgumentException("Object ID must be set!");
326 }
327
328
329 String link = loadLink(repositoryId, objectId.getValue(), Constants.REL_SELF, Constants.MEDIATYPE_ENTRY);
330
331 if (link == null) {
332 throwLinkException(repositoryId, objectId.getValue(), Constants.REL_SELF, Constants.MEDIATYPE_ENTRY);
333 }
334
335 UrlBuilder url = new UrlBuilder(link);
336 if (changeToken != null) {
337 if (getSession().get(SessionParameter.OMIT_CHANGE_TOKENS, false)) {
338 changeToken.setValue(null);
339 } else {
340
341
342
343 url.addParameter(Constants.PARAM_CHANGE_TOKEN, changeToken.getValue());
344 }
345 }
346
347
348 final AtomEntryWriter entryWriter = new AtomEntryWriter(createObject(properties, changeToken == null ? null
349 : changeToken.getValue(), null), getCmisVersion(repositoryId));
350
351
352 Response resp = put(url, Constants.MEDIATYPE_ENTRY, new Output() {
353 @Override
354 public void write(OutputStream out) throws XMLStreamException, IOException {
355 entryWriter.write(out);
356 }
357 });
358
359
360 AtomEntry entry = parse(resp.getStream(), AtomEntry.class);
361
362
363 if (entry.getId() == null) {
364 throw new CmisConnectionException("Received Atom entry is not a CMIS entry!");
365 }
366
367
368 objectId.setValue(entry.getId());
369
370 if (changeToken != null) {
371 changeToken.setValue(null);
372 }
373
374 lockLinks();
375 try {
376
377 removeLinks(repositoryId, entry.getId());
378
379
380 for (AtomElement element : entry.getElements()) {
381 if (element.getObject() instanceof AtomLink) {
382 addLink(repositoryId, entry.getId(), (AtomLink) element.getObject());
383 } else if (element.getObject() instanceof ObjectData) {
384
385 if (changeToken != null) {
386 ObjectData object = (ObjectData) element.getObject();
387
388 if (object.getProperties() != null) {
389 Object changeTokenStr = object.getProperties().getProperties()
390 .get(PropertyIds.CHANGE_TOKEN);
391 if (changeTokenStr instanceof PropertyString) {
392 changeToken.setValue(((PropertyString) changeTokenStr).getFirstValue());
393 }
394 }
395 }
396 }
397 }
398 } finally {
399 unlockLinks();
400 }
401 }
402
403 @Override
404 public List<BulkUpdateObjectIdAndChangeToken> bulkUpdateProperties(String repositoryId,
405 List<BulkUpdateObjectIdAndChangeToken> objectIdAndChangeToken, Properties properties,
406 List<String> addSecondaryTypeIds, List<String> removeSecondaryTypeIds, ExtensionsData extension) {
407
408 String link = loadCollection(repositoryId, Constants.COLLECTION_BULK_UPDATE);
409
410 if (link == null) {
411 throw new CmisObjectNotFoundException("Unknown repository or bulk update properties is not supported!");
412 }
413
414
415 final BulkUpdateImpl bulkUpdate = new BulkUpdateImpl();
416 bulkUpdate.setObjectIdAndChangeToken(objectIdAndChangeToken);
417 bulkUpdate.setProperties(properties);
418 bulkUpdate.setAddSecondaryTypeIds(addSecondaryTypeIds);
419 bulkUpdate.setRemoveSecondaryTypeIds(removeSecondaryTypeIds);
420
421 final AtomEntryWriter entryWriter = new AtomEntryWriter(bulkUpdate);
422
423
424 Response resp = post(new UrlBuilder(link), Constants.MEDIATYPE_ENTRY, new Output() {
425 @Override
426 public void write(OutputStream out) throws XMLStreamException, IOException {
427 entryWriter.write(out);
428 }
429 });
430
431 AtomFeed feed = parse(resp.getStream(), AtomFeed.class);
432 List<BulkUpdateObjectIdAndChangeToken> result = new ArrayList<BulkUpdateObjectIdAndChangeToken>(feed
433 .getEntries().size());
434
435
436 if (!feed.getEntries().isEmpty()) {
437
438 for (AtomEntry entry : feed.getEntries()) {
439
440
441
442 for (AtomElement element : entry.getElements()) {
443 if (element.getObject() instanceof ObjectData) {
444 ObjectData object = (ObjectData) element.getObject();
445 String id = object.getId();
446 if (id != null) {
447 String changeToken = null;
448 PropertyData<?> changeTokenProp = object.getProperties().getProperties()
449 .get(PropertyIds.CHANGE_TOKEN);
450 if (changeTokenProp instanceof PropertyString) {
451 changeToken = ((PropertyString) changeTokenProp).getFirstValue();
452 }
453
454 result.add(new BulkUpdateObjectIdAndChangeTokenImpl(id, changeToken));
455 }
456 }
457 }
458 }
459 }
460
461 return result;
462 }
463
464 @Override
465 public void deleteObject(String repositoryId, String objectId, Boolean allVersions, ExtensionsData extension) {
466
467
468 String link = loadLink(repositoryId, objectId, Constants.REL_SELF, Constants.MEDIATYPE_ENTRY);
469
470 if (link == null) {
471 throwLinkException(repositoryId, objectId, Constants.REL_SELF, Constants.MEDIATYPE_ENTRY);
472 }
473
474 UrlBuilder url = new UrlBuilder(link);
475 url.addParameter(Constants.PARAM_ALL_VERSIONS, allVersions);
476
477 delete(url);
478 }
479
480 @Override
481 public FailedToDeleteData deleteTree(String repositoryId, String folderId, Boolean allVersions,
482 UnfileObject unfileObjects, Boolean continueOnFailure, ExtensionsData extension) {
483
484
485 String link = loadLink(repositoryId, folderId, Constants.REL_DOWN, null);
486 String childrenLink = null;
487
488 if (link != null) {
489
490
491 childrenLink = link;
492 link = null;
493 } else {
494
495
496 link = loadLink(repositoryId, folderId, Constants.REL_DOWN, Constants.MEDIATYPE_DESCENDANTS);
497 }
498
499 if (link == null) {
500 link = loadLink(repositoryId, folderId, Constants.REL_FOLDERTREE, Constants.MEDIATYPE_DESCENDANTS);
501 }
502
503 if (link == null) {
504 link = loadLink(repositoryId, folderId, Constants.REL_FOLDERTREE, Constants.MEDIATYPE_FEED);
505 }
506
507 if (link == null) {
508 link = childrenLink;
509 }
510
511 if (link == null) {
512 throwLinkException(repositoryId, folderId, Constants.REL_DOWN, Constants.MEDIATYPE_DESCENDANTS);
513 }
514
515 UrlBuilder url = new UrlBuilder(link);
516 url.addParameter(Constants.PARAM_ALL_VERSIONS, allVersions);
517 url.addParameter(Constants.PARAM_UNFILE_OBJECTS, unfileObjects);
518 url.addParameter(Constants.PARAM_CONTINUE_ON_FAILURE, continueOnFailure);
519
520
521 Response resp = getHttpInvoker().invokeDELETE(url, getSession());
522
523
524 if (resp.getResponseCode() == 200 || resp.getResponseCode() == 202 || resp.getResponseCode() == 204) {
525 return new FailedToDeleteDataImpl();
526 }
527
528
529
530
531 if (resp.getResponseCode() == 500) {
532 link = loadLink(repositoryId, folderId, Constants.REL_DOWN, Constants.MEDIATYPE_CHILDREN);
533
534 if (link != null) {
535 url = new UrlBuilder(link);
536
537 url.addParameter(Constants.PARAM_FILTER, "cmis:objectId");
538 url.addParameter(Constants.PARAM_ALLOWABLE_ACTIONS, false);
539 url.addParameter(Constants.PARAM_RELATIONSHIPS, IncludeRelationships.NONE);
540 url.addParameter(Constants.PARAM_RENDITION_FILTER, "cmis:none");
541 url.addParameter(Constants.PARAM_PATH_SEGMENT, false);
542
543 url.addParameter(Constants.PARAM_MAX_ITEMS, 1000);
544 url.addParameter(Constants.PARAM_SKIP_COUNT, 0);
545
546
547 resp = read(url);
548 AtomFeed feed = parse(resp.getStream(), AtomFeed.class);
549
550
551 FailedToDeleteDataImpl result = new FailedToDeleteDataImpl();
552 List<String> ids = new ArrayList<String>();
553 result.setIds(ids);
554
555
556 for (AtomEntry entry : feed.getEntries()) {
557 ids.add(entry.getId());
558 }
559
560 return result;
561 }
562 }
563
564 throw convertStatusCode(resp.getResponseCode(), resp.getResponseMessage(), resp.getErrorContent(), null);
565 }
566
567 @Override
568 public AllowableActions getAllowableActions(String repositoryId, String objectId, ExtensionsData extension) {
569
570 String link = loadLink(repositoryId, objectId, Constants.REL_ALLOWABLEACTIONS,
571 Constants.MEDIATYPE_ALLOWABLEACTION);
572
573 if (link == null) {
574 throwLinkException(repositoryId, objectId, Constants.REL_ALLOWABLEACTIONS,
575 Constants.MEDIATYPE_ALLOWABLEACTION);
576 }
577
578 UrlBuilder url = new UrlBuilder(link);
579
580
581 Response resp = read(url);
582 AtomAllowableActions allowableActions = parse(resp.getStream(), AtomAllowableActions.class);
583
584 return allowableActions.getAllowableActions();
585 }
586
587 @Override
588 public ContentStream getContentStream(String repositoryId, String objectId, String streamId, BigInteger offset,
589 BigInteger length, ExtensionsData extension) {
590
591 String link = null;
592 if (streamId != null) {
593
594 link = loadLink(repositoryId, objectId, Constants.REL_ALTERNATE, streamId);
595 if (link != null) {
596 streamId = null;
597 }
598 }
599 if (link == null) {
600 link = loadLink(repositoryId, objectId, AtomPubParser.LINK_REL_CONTENT, null);
601 }
602
603 if (link == null) {
604 throw new CmisConstraintException("No content stream");
605 }
606
607 UrlBuilder url = new UrlBuilder(link);
608
609
610 url.addParameter(Constants.PARAM_STREAM_ID, streamId);
611
612
613 Response resp = getHttpInvoker().invokeGET(url, getSession(), offset, length);
614
615
616 if ((resp.getResponseCode() != 200) && (resp.getResponseCode() != 206)) {
617 throw convertStatusCode(resp.getResponseCode(), resp.getResponseMessage(), resp.getErrorContent(), null);
618 }
619
620 ContentStreamImpl result;
621 if (resp.getResponseCode() == 206) {
622 result = new PartialContentStreamImpl();
623 } else {
624 result = new ContentStreamImpl();
625 }
626
627 String filename = null;
628 String contentDisposition = resp.getHeader("Content-Disposition");
629 if (contentDisposition != null) {
630 filename = MimeHelper.decodeContentDispositionFilename(contentDisposition);
631 }
632
633 result.setFileName(filename);
634 result.setLength(resp.getContentLength());
635 result.setMimeType(resp.getContentTypeHeader());
636 result.setStream(resp.getStream());
637
638 return result;
639 }
640
641 @Override
642 public ObjectData getObject(String repositoryId, String objectId, String filter, Boolean includeAllowableActions,
643 IncludeRelationships includeRelationships, String renditionFilter, Boolean includePolicyIds,
644 Boolean includeACL, ExtensionsData extension) {
645
646 return getObjectInternal(repositoryId, IdentifierType.ID, objectId, ReturnVersion.THIS, filter,
647 includeAllowableActions, includeRelationships, renditionFilter, includePolicyIds, includeACL, extension);
648 }
649
650 @Override
651 public ObjectData getObjectByPath(String repositoryId, String path, String filter, Boolean includeAllowableActions,
652 IncludeRelationships includeRelationships, String renditionFilter, Boolean includePolicyIds,
653 Boolean includeACL, ExtensionsData extension) {
654
655 return getObjectInternal(repositoryId, IdentifierType.PATH, path, ReturnVersion.THIS, filter,
656 includeAllowableActions, includeRelationships, renditionFilter, includePolicyIds, includeACL, extension);
657 }
658
659 @Override
660 public Properties getProperties(String repositoryId, String objectId, String filter, ExtensionsData extension) {
661 ObjectData object = getObjectInternal(repositoryId, IdentifierType.ID, objectId, ReturnVersion.THIS, filter,
662 Boolean.FALSE, IncludeRelationships.NONE, "cmis:none", Boolean.FALSE, Boolean.FALSE, extension);
663
664 return object.getProperties();
665 }
666
667 @Override
668 public List<RenditionData> getRenditions(String repositoryId, String objectId, String renditionFilter,
669 BigInteger maxItems, BigInteger skipCount, ExtensionsData extension) {
670 ObjectData object = getObjectInternal(repositoryId, IdentifierType.ID, objectId, ReturnVersion.THIS,
671 PropertyIds.OBJECT_ID, Boolean.FALSE, IncludeRelationships.NONE, renditionFilter, Boolean.FALSE,
672 Boolean.FALSE, extension);
673
674 List<RenditionData> result = object.getRenditions();
675 if (result == null) {
676 result = Collections.emptyList();
677 }
678
679 return result;
680 }
681
682 @Override
683 public void moveObject(String repositoryId, Holder<String> objectId, String targetFolderId, String sourceFolderId,
684 ExtensionsData extension) {
685 if (objectId == null || objectId.getValue() == null || objectId.getValue().length() == 0) {
686 throw new CmisInvalidArgumentException("Object ID must be set!");
687 }
688
689 if (targetFolderId == null || targetFolderId.length() == 0 || sourceFolderId == null
690 || sourceFolderId.length() == 0) {
691 throw new CmisInvalidArgumentException("Source and target folder must be set!");
692 }
693
694
695 String link = loadLink(repositoryId, targetFolderId, Constants.REL_DOWN, Constants.MEDIATYPE_CHILDREN);
696
697 if (link == null) {
698 throwLinkException(repositoryId, targetFolderId, Constants.REL_DOWN, Constants.MEDIATYPE_CHILDREN);
699 }
700
701 UrlBuilder url = new UrlBuilder(link);
702 url.addParameter(Constants.PARAM_SOURCE_FOLDER_ID, sourceFolderId);
703
704
705 boolean objectIdOnMove = getSession().get(SessionParameter.INCLUDE_OBJECTID_URL_PARAM_ON_MOVE, false);
706 if (objectIdOnMove) {
707 url.addParameter("objectId", objectId.getValue());
708 url.addParameter("targetFolderId", targetFolderId);
709 }
710
711
712 final AtomEntryWriter entryWriter = new AtomEntryWriter(createIdObject(objectId.getValue()),
713 getCmisVersion(repositoryId));
714
715
716 Response resp = post(url, Constants.MEDIATYPE_ENTRY, new Output() {
717 @Override
718 public void write(OutputStream out) throws XMLStreamException, IOException {
719 entryWriter.write(out);
720 }
721 });
722
723
724 if (objectIdOnMove) {
725
726
727 return;
728 }
729
730
731 AtomEntry entry = parse(resp.getStream(), AtomEntry.class);
732
733 objectId.setValue(entry.getId());
734 }
735
736 @Override
737 public void setContentStream(String repositoryId, Holder<String> objectId, Boolean overwriteFlag,
738 Holder<String> changeToken, ContentStream contentStream, ExtensionsData extension) {
739 setOrAppendContent(repositoryId, objectId, overwriteFlag, changeToken, contentStream, true, false, extension);
740 }
741
742 @Override
743 public void deleteContentStream(String repositoryId, Holder<String> objectId, Holder<String> changeToken,
744 ExtensionsData extension) {
745
746 if ((objectId == null) || (objectId.getValue() == null)) {
747 throw new CmisInvalidArgumentException("Object ID must be set!");
748 }
749
750
751 String link = loadLink(repositoryId, objectId.getValue(), Constants.REL_EDITMEDIA, null);
752
753 if (link == null) {
754 throwLinkException(repositoryId, objectId.getValue(), Constants.REL_EDITMEDIA, null);
755 }
756
757 UrlBuilder url = new UrlBuilder(link);
758 if (changeToken != null && !getSession().get(SessionParameter.OMIT_CHANGE_TOKENS, false)) {
759 url.addParameter(Constants.PARAM_CHANGE_TOKEN, changeToken.getValue());
760 }
761
762 delete(url);
763
764 objectId.setValue(null);
765 if (changeToken != null) {
766 changeToken.setValue(null);
767 }
768 }
769
770 @Override
771 public void appendContentStream(String repositoryId, Holder<String> objectId, Holder<String> changeToken,
772 ContentStream contentStream, boolean isLastChunk, ExtensionsData extension) {
773 setOrAppendContent(repositoryId, objectId, null, changeToken, contentStream, isLastChunk, true, extension);
774 }
775
776
777
778 private static void checkCreateProperties(Properties properties) {
779 if ((properties == null) || (properties.getProperties() == null)) {
780 throw new CmisInvalidArgumentException("Properties must be set!");
781 }
782
783 if (!properties.getProperties().containsKey(PropertyIds.OBJECT_TYPE_ID)) {
784 throw new CmisInvalidArgumentException("Property " + PropertyIds.OBJECT_TYPE_ID + " must be set!");
785 }
786
787 if (properties.getProperties().containsKey(PropertyIds.OBJECT_ID)) {
788 throw new CmisInvalidArgumentException("Property " + PropertyIds.OBJECT_ID + " must not be set!");
789 }
790 }
791
792
793
794
795 private void handleAclModifications(String repositoryId, AtomEntry entry, Acl addAces, Acl removeAces) {
796 if (!isAclMergeRequired(addAces, removeAces)) {
797 return;
798 }
799
800 Acl originalAces = getAclInternal(repositoryId, entry.getId(), Boolean.FALSE, null);
801
802 if (originalAces != null) {
803
804 Acl newACL = mergeAcls(originalAces, addAces, removeAces);
805 if (newACL != null) {
806 updateAcl(repositoryId, entry.getId(), newACL, null);
807 }
808 }
809 }
810
811
812
813
814 private void setOrAppendContent(String repositoryId, Holder<String> objectId, Boolean overwriteFlag,
815 Holder<String> changeToken, ContentStream contentStream, boolean isLastChunk, boolean append,
816 ExtensionsData extension) {
817
818 if ((objectId == null) || (objectId.getValue() == null)) {
819 throw new CmisInvalidArgumentException("Object ID must be set!");
820 }
821
822
823 if ((contentStream == null) || (contentStream.getStream() == null) || (contentStream.getMimeType() == null)) {
824 throw new CmisInvalidArgumentException("Content must be set!");
825 }
826
827
828 String link = loadLink(repositoryId, objectId.getValue(), Constants.REL_EDITMEDIA, null);
829
830 if (link == null) {
831 throwLinkException(repositoryId, objectId.getValue(), Constants.REL_EDITMEDIA, null);
832 }
833
834 UrlBuilder url = new UrlBuilder(link);
835 if (changeToken != null && !getSession().get(SessionParameter.OMIT_CHANGE_TOKENS, false)) {
836 url.addParameter(Constants.PARAM_CHANGE_TOKEN, changeToken.getValue());
837 }
838
839 if (append) {
840 url.addParameter(Constants.PARAM_APPEND, Boolean.TRUE);
841 url.addParameter(Constants.PARAM_IS_LAST_CHUNK, isLastChunk);
842 } else {
843 url.addParameter(Constants.PARAM_OVERWRITE_FLAG, overwriteFlag);
844 }
845
846 final InputStream stream = contentStream.getStream();
847
848
849 Map<String, String> headers = null;
850 if (contentStream.getFileName() != null) {
851 headers = Collections
852 .singletonMap(
853 MimeHelper.CONTENT_DISPOSITION,
854 MimeHelper.encodeContentDisposition(MimeHelper.DISPOSITION_ATTACHMENT,
855 contentStream.getFileName()));
856 }
857
858
859 Response resp = put(url, contentStream.getMimeType(), headers, new Output() {
860 @Override
861 public void write(OutputStream out) throws IOException {
862 IOUtils.copy(stream, out);
863 }
864 });
865
866
867 if ((resp.getResponseCode() != 200) && (resp.getResponseCode() != 201) && (resp.getResponseCode() != 204)) {
868 throw convertStatusCode(resp.getResponseCode(), resp.getResponseMessage(), resp.getErrorContent(), null);
869 }
870
871 if (resp.getResponseCode() == 201) {
872
873
874
875 objectId.setValue(null);
876 }
877
878 if (changeToken != null) {
879 changeToken.setValue(null);
880 }
881 }
882 }