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 static org.apache.chemistry.opencmis.commons.impl.CollectionsHelper.isNotEmpty;
22
23 import java.io.InputStream;
24 import java.io.OutputStream;
25 import java.math.BigInteger;
26 import java.util.ArrayList;
27 import java.util.HashMap;
28 import java.util.HashSet;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.Set;
32
33 import javax.xml.stream.XMLStreamWriter;
34
35 import org.apache.chemistry.opencmis.client.bindings.impl.CmisBindingsHelper;
36 import org.apache.chemistry.opencmis.client.bindings.impl.RepositoryInfoCache;
37 import org.apache.chemistry.opencmis.client.bindings.spi.BindingSession;
38 import org.apache.chemistry.opencmis.client.bindings.spi.LinkAccess;
39 import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomAcl;
40 import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomBase;
41 import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomElement;
42 import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomEntry;
43 import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomLink;
44 import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.RepositoryWorkspace;
45 import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.ServiceDoc;
46 import org.apache.chemistry.opencmis.client.bindings.spi.http.HttpInvoker;
47 import org.apache.chemistry.opencmis.client.bindings.spi.http.Output;
48 import org.apache.chemistry.opencmis.client.bindings.spi.http.Response;
49 import org.apache.chemistry.opencmis.commons.PropertyIds;
50 import org.apache.chemistry.opencmis.commons.SessionParameter;
51 import org.apache.chemistry.opencmis.commons.data.Ace;
52 import org.apache.chemistry.opencmis.commons.data.Acl;
53 import org.apache.chemistry.opencmis.commons.data.ExtensionsData;
54 import org.apache.chemistry.opencmis.commons.data.ObjectData;
55 import org.apache.chemistry.opencmis.commons.data.Properties;
56 import org.apache.chemistry.opencmis.commons.data.RepositoryInfo;
57 import org.apache.chemistry.opencmis.commons.definitions.TypeDefinition;
58 import org.apache.chemistry.opencmis.commons.enums.AclPropagation;
59 import org.apache.chemistry.opencmis.commons.enums.CmisVersion;
60 import org.apache.chemistry.opencmis.commons.enums.IncludeRelationships;
61 import org.apache.chemistry.opencmis.commons.exceptions.CmisBaseException;
62 import org.apache.chemistry.opencmis.commons.exceptions.CmisConnectionException;
63 import org.apache.chemistry.opencmis.commons.exceptions.CmisConstraintException;
64 import org.apache.chemistry.opencmis.commons.exceptions.CmisContentAlreadyExistsException;
65 import org.apache.chemistry.opencmis.commons.exceptions.CmisFilterNotValidException;
66 import org.apache.chemistry.opencmis.commons.exceptions.CmisInvalidArgumentException;
67 import org.apache.chemistry.opencmis.commons.exceptions.CmisNameConstraintViolationException;
68 import org.apache.chemistry.opencmis.commons.exceptions.CmisNotSupportedException;
69 import org.apache.chemistry.opencmis.commons.exceptions.CmisObjectNotFoundException;
70 import org.apache.chemistry.opencmis.commons.exceptions.CmisPermissionDeniedException;
71 import org.apache.chemistry.opencmis.commons.exceptions.CmisProxyAuthenticationException;
72 import org.apache.chemistry.opencmis.commons.exceptions.CmisRuntimeException;
73 import org.apache.chemistry.opencmis.commons.exceptions.CmisServiceUnavailableException;
74 import org.apache.chemistry.opencmis.commons.exceptions.CmisStorageException;
75 import org.apache.chemistry.opencmis.commons.exceptions.CmisStreamNotSupportedException;
76 import org.apache.chemistry.opencmis.commons.exceptions.CmisTooManyRequestsException;
77 import org.apache.chemistry.opencmis.commons.exceptions.CmisUnauthorizedException;
78 import org.apache.chemistry.opencmis.commons.exceptions.CmisUpdateConflictException;
79 import org.apache.chemistry.opencmis.commons.exceptions.CmisVersioningException;
80 import org.apache.chemistry.opencmis.commons.impl.Constants;
81 import org.apache.chemistry.opencmis.commons.impl.IOUtils;
82 import org.apache.chemistry.opencmis.commons.impl.ReturnVersion;
83 import org.apache.chemistry.opencmis.commons.impl.UrlBuilder;
84 import org.apache.chemistry.opencmis.commons.impl.XMLConverter;
85 import org.apache.chemistry.opencmis.commons.impl.XMLUtils;
86 import org.apache.chemistry.opencmis.commons.impl.dataobjects.AccessControlEntryImpl;
87 import org.apache.chemistry.opencmis.commons.impl.dataobjects.AccessControlListImpl;
88 import org.apache.chemistry.opencmis.commons.impl.dataobjects.AccessControlPrincipalDataImpl;
89 import org.apache.chemistry.opencmis.commons.impl.dataobjects.ObjectDataImpl;
90 import org.apache.chemistry.opencmis.commons.impl.dataobjects.PolicyIdListImpl;
91 import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertiesImpl;
92 import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyIdImpl;
93 import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyStringImpl;
94
95
96
97
98 public abstract class AbstractAtomPubService implements LinkAccess {
99
100 protected enum IdentifierType {
101 ID, PATH
102 }
103
104 protected static final String NAME_COLLECTION = "collection";
105 protected static final String NAME_URI_TEMPLATE = "uritemplate";
106 protected static final String NAME_PATH_SEGMENT = "pathSegment";
107 protected static final String NAME_RELATIVE_PATH_SEGMENT = "relativePathSegment";
108 protected static final String NAME_NUM_ITEMS = "numItems";
109
110 private static final String EXCEPTION_EXCEPTION_BEGIN = "<!--exception-->";
111 private static final String EXCEPTION_EXCEPTION_END = "<!--/exception-->";
112 private static final String EXCEPTION_MESSAGE_BEGIN = "<!--message-->";
113 private static final String EXCEPTION_MESSAGE_END = "<!--/message-->";
114 private static final String EXCEPTION_KEY_BEGIN = "<!--key-->";
115 private static final String EXCEPTION_KEY_END = "<!--/key-->";
116 private static final String EXCEPTION_VALUE_BEGIN = "<!--value-->";
117 private static final String EXCEPTION_VALUE_END = "<!--/value-->";
118
119 private BindingSession session;
120
121
122
123
124 protected void setSession(BindingSession session) {
125 this.session = session;
126 }
127
128
129
130
131 protected BindingSession getSession() {
132 return session;
133 }
134
135
136
137
138 protected HttpInvoker getHttpInvoker() {
139 return CmisBindingsHelper.getHttpInvoker(session);
140 }
141
142
143
144
145 protected String getServiceDocURL() {
146 Object url = session.get(SessionParameter.ATOMPUB_URL);
147 if (url instanceof String) {
148 return (String) url;
149 }
150
151 return null;
152 }
153
154
155
156
157 protected CmisVersion getCmisVersion(String repositoryId) {
158 if (CmisBindingsHelper.getForcedCmisVersion(session) != null) {
159 return CmisBindingsHelper.getForcedCmisVersion(session);
160 }
161
162 RepositoryInfoCache cache = CmisBindingsHelper.getRepositoryInfoCache(session);
163 RepositoryInfo info = cache.get(repositoryId);
164
165 if (info == null) {
166 List<RepositoryInfo> infoList = getRepositoriesInternal(repositoryId);
167 if (isNotEmpty(infoList)) {
168 info = infoList.get(0);
169 cache.put(info);
170 }
171 }
172
173 return info == null ? CmisVersion.CMIS_1_0 : info.getCmisVersion();
174 }
175
176
177
178
179
180
181 protected LinkCache getLinkCache() {
182 LinkCache linkCache = (LinkCache) getSession().get(SpiSessionParameter.LINK_CACHE);
183 if (linkCache == null) {
184 linkCache = new LinkCache(getSession());
185 getSession().put(SpiSessionParameter.LINK_CACHE, linkCache);
186 }
187
188 return linkCache;
189 }
190
191
192
193
194 protected String getLink(String repositoryId, String id, String rel, String type) {
195 if (repositoryId == null) {
196 throw new CmisInvalidArgumentException("Repository ID must be set!");
197 }
198
199 if (id == null) {
200 throw new CmisInvalidArgumentException("Object ID must be set!");
201 }
202
203 return getLinkCache().getLink(repositoryId, id, rel, type);
204 }
205
206
207
208
209 protected String getLink(String repositoryId, String id, String rel) {
210 return getLink(repositoryId, id, rel, null);
211 }
212
213
214
215
216
217 @Override
218 public String loadLink(String repositoryId, String id, String rel, String type) {
219 String link = getLink(repositoryId, id, rel, type);
220 if (link == null) {
221 getObjectInternal(repositoryId, IdentifierType.ID, id, ReturnVersion.THIS, "cmis:objectId", Boolean.FALSE,
222 IncludeRelationships.NONE, "cmis:none", Boolean.FALSE, Boolean.FALSE, null);
223 link = getLink(repositoryId, id, rel, type);
224 }
225
226 return link;
227 }
228
229
230
231
232
233 @Override
234 public String loadContentLink(String repositoryId, String id) {
235 return loadLink(repositoryId, id, AtomPubParser.LINK_REL_CONTENT, null);
236 }
237
238
239
240
241
242 @Override
243 public String loadRenditionContentLink(String repositoryId, String id, String streamId) {
244 return loadLink(repositoryId, id, Constants.REL_ALTERNATE, streamId);
245 }
246
247
248
249
250 protected void addLink(String repositoryId, String id, String rel, String type, String link) {
251 getLinkCache().addLink(repositoryId, id, rel, type, link);
252 }
253
254
255
256
257 protected void addLink(String repositoryId, String id, AtomLink link) {
258 getLinkCache().addLink(repositoryId, id, link.getRel(), link.getType(), link.getHref());
259 }
260
261
262
263
264 protected void removeLinks(String repositoryId, String id) {
265 getLinkCache().removeLinks(repositoryId, id);
266 }
267
268
269
270
271 protected void lockLinks() {
272 getLinkCache().lockLinks();
273 }
274
275
276
277
278 protected void unlockLinks() {
279 getLinkCache().unlockLinks();
280 }
281
282
283
284
285 protected void throwLinkException(String repositoryId, String id, String rel, String type) {
286 int index = getLinkCache().checkLink(repositoryId, id, rel, type);
287
288 switch (index) {
289 case 0:
290 throw new CmisObjectNotFoundException("Unknown repository!");
291 case 1:
292 throw new CmisObjectNotFoundException("Unknown object!");
293 case 2:
294 throw new CmisNotSupportedException("Operation not supported by the repository for this object!");
295 case 3:
296 throw new CmisNotSupportedException("No link with matching media type!");
297 case 4:
298 throw new CmisRuntimeException("Nothing wrong! Either this is a bug or a threading issue.");
299 default:
300 throw new CmisRuntimeException("Unknown error!");
301 }
302 }
303
304
305
306
307 protected String getTypeLink(String repositoryId, String typeId, String rel, String type) {
308 if (repositoryId == null) {
309 throw new CmisInvalidArgumentException("Repository ID must be set!");
310 }
311
312 if (typeId == null) {
313 throw new CmisInvalidArgumentException("Type ID must be set!");
314 }
315
316 return getLinkCache().getTypeLink(repositoryId, typeId, rel, type);
317 }
318
319
320
321
322 protected String getTypeLink(String repositoryId, String typeId, String rel) {
323 return getTypeLink(repositoryId, typeId, rel, null);
324 }
325
326
327
328
329
330 protected String loadTypeLink(String repositoryId, String typeId, String rel, String type) {
331 String link = getTypeLink(repositoryId, typeId, rel, type);
332 if (link == null) {
333 getTypeDefinitionInternal(repositoryId, typeId);
334 link = getTypeLink(repositoryId, typeId, rel, type);
335 }
336
337 return link;
338 }
339
340
341
342
343 protected void addTypeLink(String repositoryId, String typeId, String rel, String type, String link) {
344 getLinkCache().addTypeLink(repositoryId, typeId, rel, type, link);
345 }
346
347
348
349
350 protected void addTypeLink(String repositoryId, String typeId, AtomLink link) {
351 getLinkCache().addTypeLink(repositoryId, typeId, link.getRel(), link.getType(), link.getHref());
352 }
353
354
355
356
357 protected void removeTypeLinks(String repositoryId, String id) {
358 getLinkCache().removeTypeLinks(repositoryId, id);
359 }
360
361
362
363
364 protected void lockTypeLinks() {
365 getLinkCache().lockTypeLinks();
366 }
367
368
369
370
371 protected void unlockTypeLinks() {
372 getLinkCache().unlockTypeLinks();
373 }
374
375
376
377
378 protected String getCollection(String repositoryId, String collection) {
379 return getLinkCache().getCollection(repositoryId, collection);
380 }
381
382
383
384
385
386 protected String loadCollection(String repositoryId, String collection) {
387 String link = getCollection(repositoryId, collection);
388 if (link == null) {
389
390 getRepositoriesInternal(repositoryId);
391 link = getCollection(repositoryId, collection);
392 }
393
394 return link;
395 }
396
397
398
399
400 protected void addCollection(String repositoryId, String collection, String link) {
401 getLinkCache().addCollection(repositoryId, collection, link);
402 }
403
404
405
406
407 protected String getRepositoryLink(String repositoryId, String rel) {
408 return getLinkCache().getRepositoryLink(repositoryId, rel);
409 }
410
411
412
413
414
415 protected String loadRepositoryLink(String repositoryId, String rel) {
416 String link = getRepositoryLink(repositoryId, rel);
417 if (link == null) {
418
419 getRepositoriesInternal(repositoryId);
420 link = getRepositoryLink(repositoryId, rel);
421 }
422
423 return link;
424 }
425
426
427
428
429 protected void addRepositoryLink(String repositoryId, String rel, String link) {
430 getLinkCache().addRepositoryLink(repositoryId, rel, link);
431 }
432
433
434
435
436 protected void addRepositoryLink(String repositoryId, AtomLink link) {
437 addRepositoryLink(repositoryId, link.getRel(), link.getHref());
438 }
439
440
441
442
443 protected String getTemplateLink(String repositoryId, String type, Map<String, Object> parameters) {
444 return getLinkCache().getTemplateLink(repositoryId, type, parameters);
445 }
446
447
448
449
450
451 protected String loadTemplateLink(String repositoryId, String type, Map<String, Object> parameters) {
452 String link = getTemplateLink(repositoryId, type, parameters);
453 if (link == null) {
454
455 getRepositoriesInternal(repositoryId);
456 link = getTemplateLink(repositoryId, type, parameters);
457 }
458
459 return link;
460 }
461
462
463
464
465 protected void addTemplate(String repositoryId, String type, String link) {
466 getLinkCache().addTemplate(repositoryId, type, link);
467 }
468
469
470
471
472
473
474 protected CmisBaseException convertStatusCode(int code, String message, String errorContent, Throwable t) {
475 String exception = extractException(errorContent);
476 message = extractErrorMessage(message, errorContent);
477 Map<String, String> additionalData = extractAddtionalData(errorContent);
478
479 switch (code) {
480 case 301:
481 case 302:
482 case 303:
483 case 307:
484 return new CmisConnectionException("Redirects are not supported (HTTP status code " + code + "): "
485 + message, errorContent, t);
486 case 400:
487 if (CmisFilterNotValidException.EXCEPTION_NAME.equals(exception)) {
488 return new CmisFilterNotValidException(message, errorContent, additionalData, t);
489 }
490 return new CmisInvalidArgumentException(message, errorContent, additionalData, t);
491 case 401:
492 return new CmisUnauthorizedException(message, errorContent, additionalData, t);
493 case 403:
494 if (CmisStreamNotSupportedException.EXCEPTION_NAME.equals(exception)) {
495 return new CmisStreamNotSupportedException(message, errorContent, additionalData, t);
496 }
497 return new CmisPermissionDeniedException(message, errorContent, additionalData, t);
498 case 404:
499 return new CmisObjectNotFoundException(message, errorContent, additionalData, t);
500 case 405:
501 return new CmisNotSupportedException(message, errorContent, additionalData, t);
502 case 407:
503 return new CmisProxyAuthenticationException(message, errorContent, additionalData, t);
504 case 409:
505 if (CmisContentAlreadyExistsException.EXCEPTION_NAME.equals(exception)) {
506 return new CmisContentAlreadyExistsException(message, errorContent, additionalData, t);
507 } else if (CmisVersioningException.EXCEPTION_NAME.equals(exception)) {
508 return new CmisVersioningException(message, errorContent, additionalData, t);
509 } else if (CmisUpdateConflictException.EXCEPTION_NAME.equals(exception)) {
510 return new CmisUpdateConflictException(message, errorContent, additionalData, t);
511 } else if (CmisNameConstraintViolationException.EXCEPTION_NAME.equals(exception)) {
512 return new CmisNameConstraintViolationException(message, errorContent, additionalData, t);
513 }
514 return new CmisConstraintException(message, errorContent, additionalData, t);
515 case 429:
516 return new CmisTooManyRequestsException(message, errorContent, additionalData, t);
517 case 503:
518 return new CmisServiceUnavailableException(message, errorContent, additionalData, t);
519 default:
520 if (CmisStorageException.EXCEPTION_NAME.equals(exception)) {
521 return new CmisStorageException(message, errorContent, additionalData, t);
522 }
523 return new CmisRuntimeException(message, errorContent, additionalData, t);
524 }
525 }
526
527 protected String extractException(String errorContent) {
528 if (errorContent == null) {
529 return null;
530 }
531
532 int begin = errorContent.indexOf(EXCEPTION_EXCEPTION_BEGIN);
533 int end = errorContent.indexOf(EXCEPTION_EXCEPTION_END);
534
535 if (begin == -1 || end == -1 || begin > end) {
536 return null;
537 }
538
539 return errorContent.substring(begin + EXCEPTION_EXCEPTION_BEGIN.length(), end);
540 }
541
542 protected String extractErrorMessage(String message, String errorContent) {
543 if (errorContent == null) {
544 return message;
545 }
546
547 int begin = errorContent.indexOf(EXCEPTION_MESSAGE_BEGIN);
548 int end = errorContent.indexOf(EXCEPTION_MESSAGE_END);
549
550 if (begin == -1 || end == -1 || begin > end) {
551 return message;
552 }
553
554 return errorContent.substring(begin + EXCEPTION_MESSAGE_BEGIN.length(), end);
555 }
556
557 protected Map<String, String> extractAddtionalData(String errorContent) {
558 if (errorContent == null) {
559 return null;
560 }
561
562 Map<String, String> result = null;
563
564 int pos = 0;
565
566 while (true) {
567 int keyBegin = errorContent.indexOf(EXCEPTION_KEY_BEGIN, pos);
568 int keyEnd = errorContent.indexOf(EXCEPTION_KEY_END, pos);
569
570 if (keyBegin == -1 || keyEnd == -1 || keyBegin > keyEnd) {
571 break;
572 }
573
574 pos = keyEnd + EXCEPTION_KEY_END.length();
575
576 int valueBegin = errorContent.indexOf(EXCEPTION_VALUE_BEGIN, pos);
577 int valueEnd = errorContent.indexOf(EXCEPTION_VALUE_END, pos);
578
579 if (valueBegin == -1 || valueEnd == -1 || valueBegin > valueEnd) {
580 break;
581 }
582
583 pos = valueEnd + EXCEPTION_VALUE_END.length();
584
585 if (result == null) {
586 result = new HashMap<String, String>();
587 }
588
589 result.put(errorContent.substring(keyBegin + EXCEPTION_KEY_BEGIN.length(), keyEnd),
590 errorContent.substring(valueBegin + EXCEPTION_VALUE_BEGIN.length(), valueEnd));
591 }
592
593 return result;
594 }
595
596
597
598 protected boolean is(String name, AtomElement element) {
599 return name.equals(element.getName().getLocalPart());
600 }
601
602 protected boolean isStr(String name, AtomElement element) {
603 return is(name, element) && (element.getObject() instanceof String);
604 }
605
606 protected boolean isInt(String name, AtomElement element) {
607 return is(name, element) && (element.getObject() instanceof BigInteger);
608 }
609
610 protected boolean isNextLink(AtomElement element) {
611 return Constants.REL_NEXT.equals(((AtomLink) element.getObject()).getRel());
612 }
613
614
615
616
617 protected ObjectDataImpl createObject(Properties properties, String changeToken, List<String> policies) {
618 ObjectDataImpl object = new ObjectDataImpl();
619
620 boolean omitChangeToken = getSession().get(SessionParameter.OMIT_CHANGE_TOKENS, false);
621
622 if (properties == null) {
623 properties = new PropertiesImpl();
624 if (changeToken != null && !omitChangeToken) {
625 ((PropertiesImpl) properties)
626 .addProperty(new PropertyStringImpl(PropertyIds.CHANGE_TOKEN, changeToken));
627 }
628 } else {
629 if (omitChangeToken) {
630 if (properties.getProperties().containsKey(PropertyIds.CHANGE_TOKEN)) {
631 properties = new PropertiesImpl(properties);
632 ((PropertiesImpl) properties).removeProperty(PropertyIds.CHANGE_TOKEN);
633 }
634 } else {
635 if (changeToken != null && !properties.getProperties().containsKey(PropertyIds.CHANGE_TOKEN)) {
636 properties = new PropertiesImpl(properties);
637 ((PropertiesImpl) properties).addProperty(new PropertyStringImpl(PropertyIds.CHANGE_TOKEN,
638 changeToken));
639 }
640 }
641 }
642
643 object.setProperties(properties);
644
645 if (isNotEmpty(policies)) {
646 PolicyIdListImpl policyIdList = new PolicyIdListImpl();
647 policyIdList.setPolicyIds(policies);
648 object.setPolicyIds(policyIdList);
649 }
650
651 return object;
652 }
653
654
655
656
657 protected ObjectData createIdObject(String objectId) {
658 ObjectDataImpl object = new ObjectDataImpl();
659
660 PropertiesImpl properties = new PropertiesImpl();
661 object.setProperties(properties);
662
663 properties.addProperty(new PropertyIdImpl(PropertyIds.OBJECT_ID, objectId));
664
665 return object;
666 }
667
668
669
670
671 @SuppressWarnings("unchecked")
672 protected <T extends AtomBase> T parse(InputStream stream, Class<T> clazz) {
673 AtomPubParser parser = new AtomPubParser(stream);
674
675 try {
676 parser.parse();
677 } catch (Exception e) {
678 throw new CmisConnectionException("Parsing exception!", e);
679 }
680
681 AtomBase parseResult = parser.getResults();
682
683 if (!clazz.isInstance(parseResult)) {
684 throw new CmisConnectionException("Unexpected document! Received: "
685 + (parseResult == null ? "something unknown" : parseResult.getType()));
686 }
687
688 return (T) parseResult;
689 }
690
691
692
693
694
695 protected Response read(UrlBuilder url) {
696
697 Response resp = getHttpInvoker().invokeGET(url, session);
698
699
700 if (resp.getResponseCode() != 200) {
701 throw convertStatusCode(resp.getResponseCode(), resp.getResponseMessage(), resp.getErrorContent(), null);
702 }
703
704 return resp;
705 }
706
707
708
709
710
711 protected Response post(UrlBuilder url, String contentType, Output writer) {
712
713 Response resp = getHttpInvoker().invokePOST(url, contentType, writer, session);
714
715
716 if (resp.getResponseCode() != 201) {
717 throw convertStatusCode(resp.getResponseCode(), resp.getResponseMessage(), resp.getErrorContent(), null);
718 }
719
720 return resp;
721 }
722
723
724
725
726
727 protected void postAndConsume(UrlBuilder url, String contentType, Output writer) {
728 Response resp = post(url, contentType, writer);
729 IOUtils.consumeAndClose(resp.getStream());
730 }
731
732
733
734
735
736 protected Response put(UrlBuilder url, String contentType, Output writer) {
737 return put(url, contentType, null, writer);
738 }
739
740
741
742
743
744 protected Response put(UrlBuilder url, String contentType, Map<String, String> headers, Output writer) {
745
746 Response resp = getHttpInvoker().invokePUT(url, contentType, headers, writer, session);
747
748
749 if ((resp.getResponseCode() < 200) || (resp.getResponseCode() > 299)) {
750 throw convertStatusCode(resp.getResponseCode(), resp.getResponseMessage(), resp.getErrorContent(), null);
751 }
752
753 return resp;
754 }
755
756
757
758
759
760 protected void delete(UrlBuilder url) {
761
762 Response resp = getHttpInvoker().invokeDELETE(url, session);
763
764
765 if (resp.getResponseCode() != 204) {
766 throw convertStatusCode(resp.getResponseCode(), resp.getResponseMessage(), resp.getErrorContent(), null);
767 }
768 }
769
770
771
772
773
774
775 protected boolean isAclMergeRequired(Acl addAces, Acl removeAces) {
776 return (addAces != null && isNotEmpty(addAces.getAces()))
777 || (removeAces != null && isNotEmpty(removeAces.getAces()));
778 }
779
780
781
782
783 protected Acl mergeAcls(Acl originalAces, Acl addAces, Acl removeAces) {
784 Map<String, Set<String>> originals = convertAclToMap(originalAces);
785 Map<String, Set<String>> adds = convertAclToMap(addAces);
786 Map<String, Set<String>> removes = convertAclToMap(removeAces);
787 List<Ace> newAces = new ArrayList<Ace>();
788
789
790 for (Map.Entry<String, Set<String>> ace : originals.entrySet()) {
791
792
793 Set<String> addPermissions = adds.get(ace.getKey());
794 if (addPermissions != null) {
795 ace.getValue().addAll(addPermissions);
796 }
797
798
799 Set<String> removePermissions = removes.get(ace.getKey());
800 if (removePermissions != null) {
801 ace.getValue().removeAll(removePermissions);
802 }
803
804
805 if (!ace.getValue().isEmpty()) {
806 newAces.add(new AccessControlEntryImpl(new AccessControlPrincipalDataImpl(ace.getKey()),
807 new ArrayList<String>(ace.getValue())));
808 }
809 }
810
811
812
813 for (Map.Entry<String, Set<String>> ace : adds.entrySet()) {
814 if (!originals.containsKey(ace.getKey()) && !ace.getValue().isEmpty()) {
815 newAces.add(new AccessControlEntryImpl(new AccessControlPrincipalDataImpl(ace.getKey()),
816 new ArrayList<String>(ace.getValue())));
817 }
818 }
819
820 return new AccessControlListImpl(newAces);
821 }
822
823
824
825
826 private static Map<String, Set<String>> convertAclToMap(Acl acl) {
827 Map<String, Set<String>> result = new HashMap<String, Set<String>>();
828
829 if (acl == null || acl.getAces() == null) {
830 return result;
831 }
832
833 for (Ace ace : acl.getAces()) {
834
835 if (!ace.isDirect()) {
836
837 continue;
838 }
839
840
841 if (ace.getPrincipal() == null || ace.getPrincipal().getId() == null) {
842
843 continue;
844 }
845
846 Set<String> permissions = result.get(ace.getPrincipal().getId());
847 if (permissions == null) {
848 permissions = new HashSet<String>();
849 result.put(ace.getPrincipal().getId(), permissions);
850 }
851
852 if (ace.getPermissions() != null) {
853 permissions.addAll(ace.getPermissions());
854 }
855 }
856
857 return result;
858 }
859
860
861
862
863
864 @SuppressWarnings("unchecked")
865 protected List<RepositoryInfo> getRepositoriesInternal(String repositoryId) {
866 List<RepositoryInfo> repInfos = new ArrayList<RepositoryInfo>();
867
868
869 UrlBuilder url = new UrlBuilder(getServiceDocURL());
870 url.addParameter(Constants.PARAM_REPOSITORY_ID, repositoryId);
871
872
873 Response resp = read(url);
874 ServiceDoc serviceDoc = parse(resp.getStream(), ServiceDoc.class);
875
876
877 for (RepositoryWorkspace ws : serviceDoc.getWorkspaces()) {
878 if (ws.getId() == null) {
879
880 continue;
881 }
882
883 for (AtomElement element : ws.getElements()) {
884 if (is(NAME_COLLECTION, element)) {
885 Map<String, String> colMap = (Map<String, String>) element.getObject();
886 addCollection(ws.getId(), colMap.get("collectionType"), colMap.get("href"));
887 } else if (element.getObject() instanceof AtomLink) {
888 addRepositoryLink(ws.getId(), (AtomLink) element.getObject());
889 } else if (is(NAME_URI_TEMPLATE, element)) {
890 Map<String, String> tempMap = (Map<String, String>) element.getObject();
891 addTemplate(ws.getId(), tempMap.get("type"), tempMap.get("template"));
892 } else if (element.getObject() instanceof RepositoryInfo) {
893 repInfos.add((RepositoryInfo) element.getObject());
894 }
895 }
896 }
897
898 return repInfos;
899 }
900
901
902
903
904 protected ObjectData getObjectInternal(String repositoryId, IdentifierType idOrPath, String objectIdOrPath,
905 ReturnVersion returnVersion, String filter, Boolean includeAllowableActions,
906 IncludeRelationships includeRelationships, String renditionFilter, Boolean includePolicyIds,
907 Boolean includeAcl, ExtensionsData extension) {
908
909 Map<String, Object> parameters = new HashMap<String, Object>();
910 parameters.put(Constants.PARAM_ID, objectIdOrPath);
911 parameters.put(Constants.PARAM_PATH, objectIdOrPath);
912 parameters.put(Constants.PARAM_RETURN_VERSION, returnVersion);
913 parameters.put(Constants.PARAM_FILTER, filter);
914 parameters.put(Constants.PARAM_ALLOWABLE_ACTIONS, includeAllowableActions);
915 parameters.put(Constants.PARAM_ACL, includeAcl);
916 parameters.put(Constants.PARAM_POLICY_IDS, includePolicyIds);
917 parameters.put(Constants.PARAM_RELATIONSHIPS, includeRelationships);
918 parameters.put(Constants.PARAM_RENDITION_FILTER, renditionFilter);
919
920 String link = loadTemplateLink(repositoryId, (idOrPath == IdentifierType.ID ? Constants.TEMPLATE_OBJECT_BY_ID
921 : Constants.TEMPLATE_OBJECT_BY_PATH), parameters);
922 if (link == null) {
923 throw new CmisObjectNotFoundException("Unknown repository!");
924 }
925
926 UrlBuilder url = new UrlBuilder(link);
927
928 if (returnVersion != null && returnVersion != ReturnVersion.THIS) {
929 url.addParameter(Constants.PARAM_RETURN_VERSION, returnVersion);
930 }
931
932
933 Response resp = read(url);
934 AtomEntry entry = parse(resp.getStream(), AtomEntry.class);
935
936
937 if (entry.getId() == null) {
938 throw new CmisConnectionException("Received Atom entry is not a CMIS entry!");
939 }
940
941 lockLinks();
942 ObjectData result = null;
943 try {
944
945 removeLinks(repositoryId, entry.getId());
946
947
948 for (AtomElement element : entry.getElements()) {
949 if (element.getObject() instanceof AtomLink) {
950 addLink(repositoryId, entry.getId(), (AtomLink) element.getObject());
951 } else if (element.getObject() instanceof ObjectData) {
952 result = (ObjectData) element.getObject();
953 }
954 }
955 } finally {
956 unlockLinks();
957 }
958
959 return result;
960 }
961
962
963
964
965 protected TypeDefinition getTypeDefinitionInternal(String repositoryId, String typeId) {
966
967 Map<String, Object> parameters = new HashMap<String, Object>();
968 parameters.put(Constants.PARAM_ID, typeId);
969
970 String link = loadTemplateLink(repositoryId, Constants.TEMPLATE_TYPE_BY_ID, parameters);
971 if (link == null) {
972 throw new CmisObjectNotFoundException("Unknown repository!");
973 }
974
975
976 Response resp = read(new UrlBuilder(link));
977 AtomEntry entry = parse(resp.getStream(), AtomEntry.class);
978
979
980 if (entry.getId() == null) {
981 throw new CmisConnectionException("Received Atom entry is not a CMIS entry!");
982 }
983
984 lockTypeLinks();
985 TypeDefinition result = null;
986 try {
987
988 removeTypeLinks(repositoryId, entry.getId());
989
990
991 for (AtomElement element : entry.getElements()) {
992 if (element.getObject() instanceof AtomLink) {
993 addTypeLink(repositoryId, entry.getId(), (AtomLink) element.getObject());
994 } else if (element.getObject() instanceof TypeDefinition) {
995 result = (TypeDefinition) element.getObject();
996 }
997 }
998 } finally {
999 unlockTypeLinks();
1000 }
1001
1002 return result;
1003 }
1004
1005
1006
1007
1008 public Acl getAclInternal(String repositoryId, String objectId, Boolean onlyBasicPermissions,
1009 ExtensionsData extension) {
1010
1011
1012 String link = loadLink(repositoryId, objectId, Constants.REL_ACL, Constants.MEDIATYPE_ACL);
1013
1014 if (link == null) {
1015 throwLinkException(repositoryId, objectId, Constants.REL_ACL, Constants.MEDIATYPE_ACL);
1016 }
1017
1018 UrlBuilder url = new UrlBuilder(link);
1019 url.addParameter(Constants.PARAM_ONLY_BASIC_PERMISSIONS, onlyBasicPermissions);
1020
1021
1022 Response resp = read(url);
1023 AtomAcl acl = parse(resp.getStream(), AtomAcl.class);
1024
1025 return acl.getACL();
1026 }
1027
1028
1029
1030
1031 protected AtomAcl updateAcl(String repositoryId, String objectId, final Acl acl, AclPropagation aclPropagation) {
1032
1033
1034 String link = loadLink(repositoryId, objectId, Constants.REL_ACL, Constants.MEDIATYPE_ACL);
1035
1036 if (link == null) {
1037 throwLinkException(repositoryId, objectId, Constants.REL_ACL, Constants.MEDIATYPE_ACL);
1038 }
1039
1040 UrlBuilder aclUrl = new UrlBuilder(link);
1041 aclUrl.addParameter(Constants.PARAM_ACL_PROPAGATION, aclPropagation);
1042
1043 final CmisVersion cmisVersion = getCmisVersion(repositoryId);
1044
1045
1046 Response resp = put(aclUrl, Constants.MEDIATYPE_ACL, new Output() {
1047 @Override
1048 public void write(OutputStream out) throws Exception {
1049 XMLStreamWriter writer = XMLUtils.createWriter(out);
1050 XMLUtils.startXmlDocument(writer);
1051 XMLConverter.writeAcl(writer, cmisVersion, true, acl);
1052 XMLUtils.endXmlDocument(writer);
1053 }
1054 });
1055
1056
1057 return parse(resp.getStream(), AtomAcl.class);
1058 }
1059
1060 }