This project has retired. For details please refer to its
Attic page.
SessionImpl xref
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.math.BigInteger;
24 import java.util.ArrayList;
25 import java.util.Collection;
26 import java.util.Collections;
27 import java.util.EnumSet;
28 import java.util.HashMap;
29 import java.util.LinkedHashMap;
30 import java.util.List;
31 import java.util.Locale;
32 import java.util.Map;
33 import java.util.Set;
34 import java.util.concurrent.locks.ReentrantReadWriteLock;
35
36 import org.apache.chemistry.opencmis.client.api.ChangeEvent;
37 import org.apache.chemistry.opencmis.client.api.ChangeEvents;
38 import org.apache.chemistry.opencmis.client.api.CmisObject;
39 import org.apache.chemistry.opencmis.client.api.Document;
40 import org.apache.chemistry.opencmis.client.api.DocumentType;
41 import org.apache.chemistry.opencmis.client.api.Folder;
42 import org.apache.chemistry.opencmis.client.api.ItemIterable;
43 import org.apache.chemistry.opencmis.client.api.ObjectFactory;
44 import org.apache.chemistry.opencmis.client.api.ObjectId;
45 import org.apache.chemistry.opencmis.client.api.ObjectType;
46 import org.apache.chemistry.opencmis.client.api.OperationContext;
47 import org.apache.chemistry.opencmis.client.api.Policy;
48 import org.apache.chemistry.opencmis.client.api.QueryResult;
49 import org.apache.chemistry.opencmis.client.api.QueryStatement;
50 import org.apache.chemistry.opencmis.client.api.Relationship;
51 import org.apache.chemistry.opencmis.client.api.SecondaryType;
52 import org.apache.chemistry.opencmis.client.api.Session;
53 import org.apache.chemistry.opencmis.client.api.Tree;
54 import org.apache.chemistry.opencmis.client.bindings.cache.TypeDefinitionCache;
55 import org.apache.chemistry.opencmis.client.runtime.cache.Cache;
56 import org.apache.chemistry.opencmis.client.runtime.cache.CacheImpl;
57 import org.apache.chemistry.opencmis.client.runtime.repository.ObjectFactoryImpl;
58 import org.apache.chemistry.opencmis.client.runtime.util.AbstractPageFetcher;
59 import org.apache.chemistry.opencmis.client.runtime.util.CollectionIterable;
60 import org.apache.chemistry.opencmis.client.runtime.util.TreeImpl;
61 import org.apache.chemistry.opencmis.client.util.OperationContextUtils;
62 import org.apache.chemistry.opencmis.commons.PropertyIds;
63 import org.apache.chemistry.opencmis.commons.SessionParameter;
64 import org.apache.chemistry.opencmis.commons.SessionParameterDefaults;
65 import org.apache.chemistry.opencmis.commons.data.Ace;
66 import org.apache.chemistry.opencmis.commons.data.Acl;
67 import org.apache.chemistry.opencmis.commons.data.BulkUpdateObjectIdAndChangeToken;
68 import org.apache.chemistry.opencmis.commons.data.ContentStream;
69 import org.apache.chemistry.opencmis.commons.data.FailedToDeleteData;
70 import org.apache.chemistry.opencmis.commons.data.ObjectData;
71 import org.apache.chemistry.opencmis.commons.data.ObjectList;
72 import org.apache.chemistry.opencmis.commons.data.PropertyData;
73 import org.apache.chemistry.opencmis.commons.data.RepositoryInfo;
74 import org.apache.chemistry.opencmis.commons.definitions.TypeDefinition;
75 import org.apache.chemistry.opencmis.commons.definitions.TypeDefinitionContainer;
76 import org.apache.chemistry.opencmis.commons.definitions.TypeDefinitionList;
77 import org.apache.chemistry.opencmis.commons.enums.AclPropagation;
78 import org.apache.chemistry.opencmis.commons.enums.BaseTypeId;
79 import org.apache.chemistry.opencmis.commons.enums.BindingType;
80 import org.apache.chemistry.opencmis.commons.enums.CmisVersion;
81 import org.apache.chemistry.opencmis.commons.enums.IncludeRelationships;
82 import org.apache.chemistry.opencmis.commons.enums.RelationshipDirection;
83 import org.apache.chemistry.opencmis.commons.enums.UnfileObject;
84 import org.apache.chemistry.opencmis.commons.enums.Updatability;
85 import org.apache.chemistry.opencmis.commons.enums.VersioningState;
86 import org.apache.chemistry.opencmis.commons.exceptions.CmisConstraintException;
87 import org.apache.chemistry.opencmis.commons.exceptions.CmisNotSupportedException;
88 import org.apache.chemistry.opencmis.commons.exceptions.CmisObjectNotFoundException;
89 import org.apache.chemistry.opencmis.commons.exceptions.CmisRuntimeException;
90 import org.apache.chemistry.opencmis.commons.impl.ClassLoaderUtil;
91 import org.apache.chemistry.opencmis.commons.impl.Constants;
92 import org.apache.chemistry.opencmis.commons.impl.dataobjects.BulkUpdateObjectIdAndChangeTokenImpl;
93 import org.apache.chemistry.opencmis.commons.spi.AclService;
94 import org.apache.chemistry.opencmis.commons.spi.AuthenticationProvider;
95 import org.apache.chemistry.opencmis.commons.spi.CmisBinding;
96 import org.apache.chemistry.opencmis.commons.spi.DiscoveryService;
97 import org.apache.chemistry.opencmis.commons.spi.ExtendedAclService;
98 import org.apache.chemistry.opencmis.commons.spi.ExtendedHolder;
99 import org.apache.chemistry.opencmis.commons.spi.ExtendedRepositoryService;
100 import org.apache.chemistry.opencmis.commons.spi.Holder;
101 import org.apache.chemistry.opencmis.commons.spi.NavigationService;
102 import org.apache.chemistry.opencmis.commons.spi.RelationshipService;
103 import org.apache.chemistry.opencmis.commons.spi.RepositoryService;
104
105
106
107
108 public class SessionImpl implements Session {
109
110 private static final OperationContext DEFAULT_CONTEXT = new OperationContextImpl(null, false, true, false,
111 IncludeRelationships.NONE, null, true, null, true, 100);
112
113 private static final Set<Updatability> CREATE_UPDATABILITY = EnumSet.noneOf(Updatability.class);
114 private static final Set<Updatability> CREATE_AND_CHECKOUT_UPDATABILITY = EnumSet.noneOf(Updatability.class);
115
116 static {
117 CREATE_UPDATABILITY.add(Updatability.ONCREATE);
118 CREATE_UPDATABILITY.add(Updatability.READWRITE);
119 CREATE_AND_CHECKOUT_UPDATABILITY.add(Updatability.ONCREATE);
120 CREATE_AND_CHECKOUT_UPDATABILITY.add(Updatability.READWRITE);
121 CREATE_AND_CHECKOUT_UPDATABILITY.add(Updatability.WHENCHECKEDOUT);
122 }
123
124
125
126 private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
127 private transient LinkedHashMap<String, ObjectType> objectTypeCache;
128
129
130
131
132 private OperationContext defaultContext = DEFAULT_CONTEXT;
133
134
135
136
137 private Map<String, String> parameters;
138
139
140
141
142 private CmisBinding binding;
143
144
145
146
147 private Locale locale;
148
149
150
151
152 private final ObjectFactory objectFactory;
153
154
155
156
157 private final AuthenticationProvider authenticationProvider;
158
159
160
161
162 private Cache cache;
163 private final boolean cachePathOmit;
164
165
166
167
168 private TypeDefinitionCache typeDefCache;
169
170
171
172
173 private RepositoryInfo repositoryInfo;
174
175
176
177
178 private static final long serialVersionUID = 1L;
179
180
181
182
183 public SessionImpl(Map<String, String> parameters, ObjectFactory objectFactory,
184 AuthenticationProvider authenticationProvider, Cache cache, TypeDefinitionCache typeDefCache) {
185 if (parameters == null) {
186 throw new IllegalArgumentException("No parameters provided!");
187 }
188
189 this.parameters = parameters;
190 this.locale = determineLocale(parameters);
191
192 this.objectFactory = objectFactory == null ? createObjectFactory() : objectFactory;
193 this.authenticationProvider = authenticationProvider;
194 this.cache = cache == null ? createCache() : cache;
195 this.typeDefCache = typeDefCache;
196
197 cachePathOmit = Boolean.parseBoolean(parameters.get(SessionParameter.CACHE_PATH_OMIT));
198 }
199
200 private Locale determineLocale(Map<String, String> parameters) {
201 Locale result = null;
202
203 String language = parameters.get(SessionParameter.LOCALE_ISO639_LANGUAGE);
204 String country = parameters.get(SessionParameter.LOCALE_ISO3166_COUNTRY);
205 String variant = parameters.get(SessionParameter.LOCALE_VARIANT);
206
207 if (variant != null) {
208
209 result = new Locale(language, country, variant);
210 } else {
211 if (country != null) {
212
213 result = new Locale(language, country);
214 } else {
215 if (language != null) {
216
217 result = new Locale(language);
218 } else {
219 result = Locale.getDefault();
220 }
221 }
222 }
223
224 return result;
225 }
226
227 private ObjectFactory createObjectFactory() {
228 try {
229 String classname = parameters.get(SessionParameter.OBJECT_FACTORY_CLASS);
230
231 Class<?> objectFactoryClass;
232 if (classname == null) {
233 objectFactoryClass = ObjectFactoryImpl.class;
234 } else {
235 objectFactoryClass = ClassLoaderUtil.loadClass(classname);
236 }
237
238 Object of = objectFactoryClass.newInstance();
239 if (!(of instanceof ObjectFactory)) {
240 throw new InstantiationException("Class does not implement ObjectFactory!");
241 }
242
243 ((ObjectFactory) of).initialize(this, parameters);
244
245 return (ObjectFactory) of;
246 } catch (Exception e) {
247 throw new IllegalArgumentException("Unable to create object factory: " + e, e);
248 }
249 }
250
251 private Cache createCache() {
252 try {
253 String classname = parameters.get(SessionParameter.CACHE_CLASS);
254
255 Class<?> cacheClass;
256 if (classname == null) {
257 cacheClass = CacheImpl.class;
258 } else {
259 cacheClass = ClassLoaderUtil.loadClass(classname);
260 }
261
262 Object of = cacheClass.newInstance();
263 if (!(of instanceof Cache)) {
264 throw new InstantiationException("Class does not implement Cache!");
265 }
266
267 ((Cache) of).initialize(this, parameters);
268
269 return (Cache) of;
270 } catch (Exception e) {
271 throw new IllegalArgumentException("Unable to create cache: " + e, e);
272 }
273 }
274
275 @Override
276 public Map<String, String> getSessionParameters() {
277 return Collections.unmodifiableMap(parameters);
278 }
279
280 @Override
281 public void clear() {
282 lock.writeLock().lock();
283 try {
284
285 cache = createCache();
286
287
288 objectTypeCache = null;
289
290
291 getBinding().clearAllCaches();
292 } finally {
293 lock.writeLock().unlock();
294 }
295 }
296
297 @Override
298 public ObjectFactory getObjectFactory() {
299 assert objectFactory != null;
300 return objectFactory;
301 }
302
303 @Override
304 public ItemIterable<Document> getCheckedOutDocs() {
305 return getCheckedOutDocs(getDefaultContext());
306 }
307
308 @Override
309 public ItemIterable<Document> getCheckedOutDocs(OperationContext context) {
310 checkContext(context);
311
312 final NavigationService navigationService = getBinding().getNavigationService();
313 final ObjectFactory of = getObjectFactory();
314 final OperationContext ctxt = new OperationContextImpl(context);
315
316 return new CollectionIterable<Document>(new AbstractPageFetcher<Document>(ctxt.getMaxItemsPerPage()) {
317
318 @Override
319 protected AbstractPageFetcher.Page<Document> fetchPage(long skipCount) {
320
321
322 ObjectList checkedOutDocs = navigationService.getCheckedOutDocs(getRepositoryId(), null,
323 ctxt.getFilterString(), ctxt.getOrderBy(), ctxt.isIncludeAllowableActions(),
324 ctxt.getIncludeRelationships(), ctxt.getRenditionFilterString(),
325 BigInteger.valueOf(this.maxNumItems), BigInteger.valueOf(skipCount), null);
326
327
328 List<Document> page = new ArrayList<Document>();
329 if (checkedOutDocs.getObjects() != null) {
330 for (ObjectData objectData : checkedOutDocs.getObjects()) {
331 CmisObject doc = of.convertObject(objectData, ctxt);
332 if (!(doc instanceof Document)) {
333
334 continue;
335 }
336
337 page.add((Document) doc);
338 }
339 }
340
341 return new AbstractPageFetcher.Page<Document>(page, checkedOutDocs.getNumItems(),
342 checkedOutDocs.hasMoreItems());
343 }
344 });
345 }
346
347 @Override
348 public ChangeEvents getContentChanges(String changeLogToken, boolean includeProperties, long maxNumItems) {
349 return getContentChanges(changeLogToken, includeProperties, maxNumItems, getDefaultContext());
350 }
351
352 @Override
353 public ChangeEvents getContentChanges(String changeLogToken, boolean includeProperties, long maxNumItems,
354 OperationContext context) {
355 checkContext(context);
356
357 Holder<String> changeLogTokenHolder = new Holder<String>(changeLogToken);
358 ObjectList objectList = null;
359
360 lock.readLock().lock();
361 try {
362 objectList = getBinding().getDiscoveryService().getContentChanges(getRepositoryInfo().getId(),
363 changeLogTokenHolder, includeProperties, context.getFilterString(), context.isIncludePolicies(),
364 context.isIncludeAcls(), BigInteger.valueOf(maxNumItems), null);
365 } finally {
366 lock.readLock().unlock();
367 }
368
369 return objectFactory.convertChangeEvents(changeLogTokenHolder.getValue(), objectList);
370 }
371
372 @Override
373 public ItemIterable<ChangeEvent> getContentChanges(String changeLogToken, final boolean includeProperties) {
374 return getContentChanges(changeLogToken, includeProperties, getDefaultContext());
375 }
376
377 @Override
378 public ItemIterable<ChangeEvent> getContentChanges(final String changeLogToken, final boolean includeProperties,
379 OperationContext context) {
380 checkContext(context);
381
382 final DiscoveryService discoveryService = getBinding().getDiscoveryService();
383 final ObjectFactory of = getObjectFactory();
384 final OperationContext ctxt = new OperationContextImpl(context);
385
386 return new CollectionIterable<ChangeEvent>(new AbstractPageFetcher<ChangeEvent>(Integer.MAX_VALUE) {
387
388 private String token = changeLogToken;
389 private String nextLink = null;
390 private boolean firstPage = true;
391
392 @Override
393 protected AbstractPageFetcher.Page<ChangeEvent> fetchPage(long skipCount) {
394 assert firstPage || token != null ? (nextLink == null) : true;
395
396
397 ExtendedHolder<String> changeLogTokenHolder = new ExtendedHolder<String>(token);
398 if (nextLink != null) {
399 changeLogTokenHolder.setExtraValue(Constants.REP_REL_CHANGES, nextLink);
400 }
401
402 ObjectList objectList = discoveryService.getContentChanges(getRepositoryInfo().getId(),
403 changeLogTokenHolder, includeProperties, ctxt.getFilterString(), ctxt.isIncludePolicies(),
404 ctxt.isIncludeAcls(), BigInteger.valueOf(this.maxNumItems), null);
405
406
407 List<ChangeEvent> page = new ArrayList<ChangeEvent>();
408 for (ObjectData objectData : objectList.getObjects()) {
409 page.add(of.convertChangeEvent(objectData));
410 }
411
412 if (!firstPage) {
413
414
415 page.remove(0);
416 }
417 firstPage = false;
418
419 if (changeLogTokenHolder.getValue() != null) {
420
421
422 token = changeLogTokenHolder.getValue();
423 } else {
424
425
426 token = null;
427 nextLink = (String) changeLogTokenHolder.getExtraValue(Constants.REP_REL_CHANGES);
428 }
429
430 return new AbstractPageFetcher.Page<ChangeEvent>(page, objectList.getNumItems(),
431 objectList.hasMoreItems()) {
432 };
433 }
434 }) {
435 @Override
436 public ItemIterable<ChangeEvent> skipTo(long position) {
437 throw new CmisNotSupportedException("Skipping not supported!");
438 }
439
440 @Override
441 public ItemIterable<ChangeEvent> getPage() {
442 throw new CmisNotSupportedException("Paging not supported!");
443 }
444
445 @Override
446 public ItemIterable<ChangeEvent> getPage(int maxNumItems) {
447 throw new CmisNotSupportedException("Paging not supported!");
448 }
449 };
450 }
451
452 @Override
453 public String getLatestChangeLogToken() {
454 return getBinding().getRepositoryService().getRepositoryInfo(getRepositoryId(), null).getLatestChangeLogToken();
455 }
456
457 @Override
458 public OperationContext getDefaultContext() {
459 lock.readLock().lock();
460 try {
461 return defaultContext;
462 } finally {
463 lock.readLock().unlock();
464 }
465 }
466
467 @Override
468 public void setDefaultContext(OperationContext context) {
469 lock.writeLock().lock();
470 try {
471 this.defaultContext = context == null ? DEFAULT_CONTEXT : context;
472 } finally {
473 lock.writeLock().unlock();
474 }
475 }
476
477 @Override
478 public OperationContext createOperationContext(Set<String> filter, boolean includeAcls,
479 boolean includeAllowableActions, boolean includePolicies, IncludeRelationships includeRelationships,
480 Set<String> renditionFilter, boolean includePathSegments, String orderBy, boolean cacheEnabled,
481 int maxItemsPerPage) {
482 return OperationContextUtils.createOperationContext(filter, includeAcls, includeAllowableActions,
483 includePolicies, includeRelationships, renditionFilter, includePathSegments, orderBy, cacheEnabled,
484 maxItemsPerPage);
485 }
486
487 @Override
488 public OperationContext createOperationContext() {
489 return OperationContextUtils.createOperationContext();
490 }
491
492 @Override
493 public ObjectId createObjectId(String id) {
494 return new ObjectIdImpl(id);
495 }
496
497 @Override
498 public Locale getLocale() {
499 return locale;
500 }
501
502 @Override
503 public CmisObject getObject(ObjectId objectId) {
504 return getObject(objectId, getDefaultContext());
505 }
506
507 @Override
508 public CmisObject getObject(ObjectId objectId, OperationContext context) {
509 checkObjectId(objectId);
510 return getObject(objectId.getId(), context);
511 }
512
513 @Override
514 public CmisObject getObject(String objectId) {
515 return getObject(objectId, getDefaultContext());
516 }
517
518 @Override
519 public CmisObject getObject(String objectId, OperationContext context) {
520 checkObjectId(objectId);
521 checkContext(context);
522
523 CmisObject result = null;
524
525
526 if (context.isCacheEnabled()) {
527 result = cache.getById(objectId, context.getCacheKey());
528 if (result != null) {
529 return result;
530 }
531 }
532
533
534 ObjectData objectData = binding.getObjectService().getObject(getRepositoryId(), objectId,
535 context.getFilterString(), context.isIncludeAllowableActions(), context.getIncludeRelationships(),
536 context.getRenditionFilterString(), context.isIncludePolicies(), context.isIncludeAcls(), null);
537
538 result = getObjectFactory().convertObject(objectData, context);
539
540
541 if (context.isCacheEnabled()) {
542 cache.put(result, context.getCacheKey());
543 }
544
545 return result;
546 }
547
548 @Override
549 public CmisObject getObjectByPath(String path) {
550 return getObjectByPath(path, getDefaultContext());
551 }
552
553 @Override
554 public CmisObject getObjectByPath(String path, OperationContext context) {
555 checkPath(path);
556 checkContext(context);
557
558 CmisObject result = null;
559
560
561 if (context.isCacheEnabled() && !cachePathOmit) {
562 result = cache.getByPath(path, context.getCacheKey());
563 if (result != null) {
564 return result;
565 }
566 }
567
568
569 ObjectData objectData = binding.getObjectService().getObjectByPath(getRepositoryId(), path,
570 context.getFilterString(), context.isIncludeAllowableActions(), context.getIncludeRelationships(),
571 context.getRenditionFilterString(), context.isIncludePolicies(), context.isIncludeAcls(), null);
572
573 result = getObjectFactory().convertObject(objectData, context);
574
575
576 if (context.isCacheEnabled()) {
577 cache.putPath(path, result, context.getCacheKey());
578 }
579
580 return result;
581 }
582
583 @Override
584 public CmisObject getObjectByPath(String parentPath, String name) {
585 return getObjectByPath(parentPath, name, getDefaultContext());
586 }
587
588 @Override
589 public CmisObject getObjectByPath(String parentPath, String name, OperationContext context) {
590 if (parentPath == null || parentPath.length() < 1) {
591 throw new IllegalArgumentException("Parent path must be set!");
592 }
593 if (parentPath.charAt(0) != '/') {
594 throw new IllegalArgumentException("Parent path must start with a '/'!");
595 }
596 if (name == null || name.length() < 1) {
597 throw new IllegalArgumentException("Name must be set!");
598 }
599
600 StringBuilder path = new StringBuilder(parentPath.length() + name.length() + 2);
601 path.append(parentPath);
602 if (!parentPath.endsWith("/")) {
603 path.append('/');
604 }
605 path.append(name);
606
607 return getObjectByPath(path.toString(), context);
608 }
609
610 @Override
611 public Document getLatestDocumentVersion(ObjectId objectId) {
612 return getLatestDocumentVersion(objectId, false, getDefaultContext());
613 }
614
615 @Override
616 public Document getLatestDocumentVersion(String objectId, OperationContext context) {
617 checkDocumentId(objectId);
618 return getLatestDocumentVersion(createObjectId(objectId), false, context);
619 }
620
621 @Override
622 public Document getLatestDocumentVersion(String objectId, boolean major, OperationContext context) {
623 checkDocumentId(objectId);
624 return getLatestDocumentVersion(createObjectId(objectId), major, context);
625 }
626
627 @Override
628 public Document getLatestDocumentVersion(String objectId) {
629 checkDocumentId(objectId);
630 return getLatestDocumentVersion(createObjectId(objectId), false, getDefaultContext());
631 }
632
633 @Override
634 public Document getLatestDocumentVersion(ObjectId objectId, OperationContext context) {
635 return getLatestDocumentVersion(objectId, false, context);
636 }
637
638 @Override
639 public Document getLatestDocumentVersion(ObjectId objectId, boolean major, OperationContext context) {
640 checkDocumentId(objectId);
641 checkContext(context);
642
643 CmisObject result = null;
644
645 String versionSeriesId = null;
646
647
648
649 if (objectId instanceof Document) {
650 Document sourceDoc = (Document) objectId;
651
652 if (!sourceDoc.isVersionable()) {
653
654 return (Document) getObject(sourceDoc, context);
655 }
656
657 versionSeriesId = sourceDoc.getVersionSeriesId();
658 }
659
660
661
662 if (versionSeriesId == null) {
663 if (context.isCacheEnabled()) {
664 CmisObject sourceObj = cache.getById(objectId.getId(), context.getCacheKey());
665 if (sourceObj instanceof Document) {
666 Document sourceDoc = (Document) sourceObj;
667
668 if (!sourceDoc.isVersionable()) {
669
670 return (Document) getObject(sourceDoc, context);
671 }
672
673 versionSeriesId = sourceDoc.getVersionSeriesId();
674 }
675 }
676 }
677
678
679
680
681
682 if (versionSeriesId == null) {
683 BindingType bindingType = getBinding().getBindingType();
684 if (bindingType == BindingType.WEBSERVICES || bindingType == BindingType.CUSTOM) {
685
686
687 ObjectData sourceObjectData = binding.getObjectService().getObject(getRepositoryId(), objectId.getId(),
688 PropertyIds.OBJECT_ID + "," + PropertyIds.OBJECT_TYPE_ID + "," + PropertyIds.VERSION_SERIES_ID,
689 false, IncludeRelationships.NONE, "cmis:none", false, false, null);
690
691 String objectTypeId = null;
692
693 if (sourceObjectData.getProperties() != null
694 && sourceObjectData.getProperties().getProperties() != null) {
695
696 PropertyData<?> objectTypeIdProp = sourceObjectData.getProperties().getProperties()
697 .get(PropertyIds.OBJECT_TYPE_ID);
698 if (objectTypeIdProp != null && objectTypeIdProp.getFirstValue() instanceof String) {
699 objectTypeId = (String) objectTypeIdProp.getFirstValue();
700 }
701
702 PropertyData<?> verionsSeriesIdProp = sourceObjectData.getProperties().getProperties()
703 .get(PropertyIds.VERSION_SERIES_ID);
704 if (verionsSeriesIdProp != null && verionsSeriesIdProp.getFirstValue() instanceof String) {
705 versionSeriesId = (String) verionsSeriesIdProp.getFirstValue();
706 }
707 }
708
709
710 if (versionSeriesId == null) {
711
712 ObjectType type = getTypeDefinition(objectTypeId);
713 if (type instanceof DocumentType && Boolean.FALSE.equals(((DocumentType) type).isVersionable())) {
714
715
716 return (Document) getObject(objectId, context);
717 }
718
719 throw new IllegalArgumentException("Object is not a document or not versionable!");
720 }
721 }
722 }
723
724
725 ObjectData objectData = binding.getVersioningService().getObjectOfLatestVersion(getRepositoryId(),
726 objectId.getId(), versionSeriesId, major, context.getFilterString(),
727 context.isIncludeAllowableActions(), context.getIncludeRelationships(),
728 context.getRenditionFilterString(), context.isIncludePolicies(), context.isIncludeAcls(), null);
729
730 result = getObjectFactory().convertObject(objectData, context);
731
732
733 if (context.isCacheEnabled()) {
734 cache.put(result, context.getCacheKey());
735 }
736
737
738 if (!(result instanceof Document)) {
739 throw new IllegalArgumentException("Latest version is not a document!");
740 }
741
742 return (Document) result;
743 }
744
745 @Override
746 public boolean exists(ObjectId objectId) {
747 checkObjectId(objectId);
748 return exists(objectId.getId());
749 }
750
751 @Override
752 public boolean exists(String objectId) {
753 checkObjectId(objectId);
754
755 try {
756 binding.getObjectService().getObject(getRepositoryId(), objectId, "cmis:objectId", Boolean.FALSE,
757 IncludeRelationships.NONE, "cmis:none", Boolean.FALSE, Boolean.FALSE, null);
758 return true;
759 } catch (CmisObjectNotFoundException onf) {
760 removeObjectFromCache(objectId);
761 return false;
762 }
763 }
764
765 @Override
766 public boolean existsPath(String path) {
767 checkPath(path);
768
769 try {
770 ObjectData object = binding.getObjectService().getObjectByPath(getRepositoryId(), path, "cmis:objectId",
771 Boolean.FALSE, IncludeRelationships.NONE, "cmis:none", Boolean.FALSE, Boolean.FALSE, null);
772
773 String cacheObjectId = cache.getObjectIdByPath(path);
774 if (cacheObjectId != null && !cacheObjectId.equals(object.getId())) {
775 cache.removePath(path);
776 }
777
778 return true;
779 } catch (CmisObjectNotFoundException onf) {
780 cache.removePath(path);
781 return false;
782 }
783 }
784
785 @Override
786 public boolean existsPath(String parentPath, String name) {
787 if (parentPath == null || parentPath.length() < 1) {
788 throw new IllegalArgumentException("Parent path must be set!");
789 }
790 if (parentPath.charAt(0) != '/') {
791 throw new IllegalArgumentException("Parent path must start with a '/'!");
792 }
793 if (name == null || name.length() < 1) {
794 throw new IllegalArgumentException("Name must be set!");
795 }
796
797 StringBuilder path = new StringBuilder(parentPath.length() + name.length() + 2);
798 path.append(parentPath);
799 if (!parentPath.endsWith("/")) {
800 path.append('/');
801 }
802 path.append(name);
803
804 return existsPath(path.toString());
805 }
806
807 @Override
808 public void removeObjectFromCache(ObjectId objectId) {
809 checkObjectId(objectId);
810 removeObjectFromCache(objectId.getId());
811 }
812
813 @Override
814 public void removeObjectFromCache(String objectId) {
815 cache.remove(objectId);
816 }
817
818 @Override
819 public RepositoryInfo getRepositoryInfo() {
820 lock.readLock().lock();
821 try {
822 return repositoryInfo;
823 } finally {
824 lock.readLock().unlock();
825 }
826 }
827
828 @Override
829 public Folder getRootFolder() {
830 return getRootFolder(getDefaultContext());
831 }
832
833 @Override
834 public Folder getRootFolder(OperationContext context) {
835 String rootFolderId = getRepositoryInfo().getRootFolderId();
836
837 CmisObject rootFolder = getObject(rootFolderId, context);
838 if (!(rootFolder instanceof Folder)) {
839 throw new CmisRuntimeException("Root folder object is not a folder!");
840 }
841
842 return (Folder) rootFolder;
843 }
844
845 @Override
846 public ItemIterable<ObjectType> getTypeChildren(final String typeId, final boolean includePropertyDefinitions) {
847 final RepositoryService repositoryService = getBinding().getRepositoryService();
848
849 return new CollectionIterable<ObjectType>(new AbstractPageFetcher<ObjectType>(getDefaultContext()
850 .getMaxItemsPerPage()) {
851
852 @Override
853 protected AbstractPageFetcher.Page<ObjectType> fetchPage(long skipCount) {
854
855
856 TypeDefinitionList tdl = repositoryService.getTypeChildren(SessionImpl.this.getRepositoryId(), typeId,
857 includePropertyDefinitions, BigInteger.valueOf(this.maxNumItems),
858 BigInteger.valueOf(skipCount), null);
859
860
861 List<ObjectType> page = new ArrayList<ObjectType>(tdl.getList().size());
862 for (TypeDefinition typeDefinition : tdl.getList()) {
863 page.add(convertTypeDefinition(typeDefinition));
864 }
865
866 return new AbstractPageFetcher.Page<ObjectType>(page, tdl.getNumItems(), tdl.hasMoreItems()) {
867 };
868 }
869 });
870 }
871
872 @Override
873 public ObjectType getTypeDefinition(String typeId) {
874 TypeDefinition typeDefinition = getBinding().getRepositoryService().getTypeDefinition(getRepositoryId(),
875 typeId, null);
876
877 return convertAndCacheTypeDefinition(typeDefinition, true);
878 }
879
880 @Override
881 public ObjectType getTypeDefinition(String typeId, boolean useCache) {
882 RepositoryService service = getBinding().getRepositoryService();
883 if (!(service instanceof ExtendedRepositoryService)) {
884 throw new CmisRuntimeException(
885 "Internal error: Repository Service does not implement ExtendedRepositoryService!");
886 }
887
888 ExtendedRepositoryService extRepSrv = (ExtendedRepositoryService) service;
889 TypeDefinition typeDefinition = extRepSrv.getTypeDefinition(getRepositoryId(), typeId, null, useCache);
890
891 return convertAndCacheTypeDefinition(typeDefinition, useCache);
892 }
893
894 @Override
895 public List<Tree<ObjectType>> getTypeDescendants(String typeId, int depth, boolean includePropertyDefinitions) {
896 List<TypeDefinitionContainer> descendants = getBinding().getRepositoryService().getTypeDescendants(
897 getRepositoryId(), typeId, BigInteger.valueOf(depth), includePropertyDefinitions, null);
898
899 return convertTypeDescendants(descendants);
900 }
901
902
903
904
905
906 private List<Tree<ObjectType>> convertTypeDescendants(List<TypeDefinitionContainer> descendantsList) {
907 List<Tree<ObjectType>> result = new ArrayList<Tree<ObjectType>>();
908
909 for (TypeDefinitionContainer container : descendantsList) {
910 ObjectType objectType = convertTypeDefinition(container.getTypeDefinition());
911 List<Tree<ObjectType>> children = convertTypeDescendants(container.getChildren());
912
913 result.add(new TreeImpl<ObjectType>(objectType, children));
914 }
915
916 return result;
917 }
918
919 private ObjectType convertTypeDefinition(TypeDefinition typeDefinition) {
920 return objectFactory.convertTypeDefinition(typeDefinition);
921 }
922
923
924
925
926
927
928
929
930
931
932 private ObjectType convertAndCacheTypeDefinition(TypeDefinition typeDefinition, boolean useCache) {
933 ObjectType result = null;
934
935 lock.writeLock().lock();
936 try {
937 if (objectTypeCache == null) {
938 int cacheSize;
939 try {
940 cacheSize = Integer.valueOf(parameters.get(SessionParameter.CACHE_SIZE_TYPES));
941 if (cacheSize < 0) {
942 cacheSize = SessionParameterDefaults.CACHE_SIZE_TYPES;
943 }
944 } catch (NumberFormatException nfe) {
945 cacheSize = SessionParameterDefaults.CACHE_SIZE_TYPES;
946 }
947
948 final int maxEntries = cacheSize;
949
950 objectTypeCache = new LinkedHashMap<String, ObjectType>(maxEntries + 1, 0.70f, true) {
951 private static final long serialVersionUID = 1L;
952
953 @Override
954 public boolean removeEldestEntry(Map.Entry<String, ObjectType> eldest) {
955 return size() > maxEntries;
956 }
957 };
958 }
959
960 if (!useCache) {
961 result = objectFactory.convertTypeDefinition(typeDefinition);
962 objectTypeCache.put(result.getId(), result);
963 } else {
964 result = objectTypeCache.get(typeDefinition.getId());
965 if (result == null) {
966 result = objectFactory.convertTypeDefinition(typeDefinition);
967 objectTypeCache.put(result.getId(), result);
968 }
969 }
970
971 return result;
972 } finally {
973 lock.writeLock().unlock();
974 }
975 }
976
977
978
979
980 private void removeFromObjectTypeCache(String typeId) {
981 lock.writeLock().lock();
982 try {
983 if (objectTypeCache != null) {
984 objectTypeCache.remove(typeId);
985 }
986 } finally {
987 lock.writeLock().unlock();
988 }
989 }
990
991 @Override
992 public ObjectType createType(TypeDefinition type) {
993 checkCmisVersion();
994
995 TypeDefinition newType = getBinding().getRepositoryService().createType(getRepositoryId(), type, null);
996 return convertTypeDefinition(newType);
997 }
998
999 @Override
1000 public ObjectType updateType(TypeDefinition type) {
1001 checkCmisVersion();
1002
1003 TypeDefinition updatedType = getBinding().getRepositoryService().updateType(getRepositoryId(), type, null);
1004
1005 removeFromObjectTypeCache(updatedType.getId());
1006
1007 return convertTypeDefinition(updatedType);
1008 }
1009
1010 @Override
1011 public void deleteType(String typeId) {
1012 checkCmisVersion();
1013
1014 getBinding().getRepositoryService().deleteType(getRepositoryId(), typeId, null);
1015 removeFromObjectTypeCache(typeId);
1016 }
1017
1018 @Override
1019 public ItemIterable<QueryResult> query(final String statement, final boolean searchAllVersions) {
1020 return query(statement, searchAllVersions, getDefaultContext());
1021 }
1022
1023 @Override
1024 public ItemIterable<QueryResult> query(final String statement, final boolean searchAllVersions,
1025 OperationContext context) {
1026 checkContext(context);
1027
1028 final DiscoveryService discoveryService = getBinding().getDiscoveryService();
1029 final ObjectFactory of = getObjectFactory();
1030 final OperationContext ctxt = new OperationContextImpl(context);
1031
1032 return new CollectionIterable<QueryResult>(new AbstractPageFetcher<QueryResult>(ctxt.getMaxItemsPerPage()) {
1033
1034 @Override
1035 protected AbstractPageFetcher.Page<QueryResult> fetchPage(long skipCount) {
1036
1037
1038 ObjectList resultList = discoveryService.query(getRepositoryId(), statement, searchAllVersions,
1039 ctxt.isIncludeAllowableActions(), ctxt.getIncludeRelationships(),
1040 ctxt.getRenditionFilterString(), BigInteger.valueOf(this.maxNumItems),
1041 BigInteger.valueOf(skipCount), null);
1042
1043
1044 List<QueryResult> page = new ArrayList<QueryResult>();
1045 if (resultList.getObjects() != null) {
1046 for (ObjectData objectData : resultList.getObjects()) {
1047 if (objectData == null) {
1048 continue;
1049 }
1050
1051 page.add(of.convertQueryResult(objectData));
1052 }
1053 }
1054
1055 return new AbstractPageFetcher.Page<QueryResult>(page, resultList.getNumItems(),
1056 resultList.hasMoreItems());
1057 }
1058 });
1059 }
1060
1061 @Override
1062 public ItemIterable<CmisObject> queryObjects(String typeId, String where, final boolean searchAllVersions,
1063 OperationContext context) {
1064 if (typeId == null || typeId.trim().length() == 0) {
1065 throw new IllegalArgumentException("Type ID must be set!");
1066 }
1067
1068 checkContext(context);
1069
1070 final DiscoveryService discoveryService = getBinding().getDiscoveryService();
1071 final ObjectFactory of = getObjectFactory();
1072 final OperationContext ctxt = new OperationContextImpl(context);
1073 final StringBuilder statement = new StringBuilder(1024);
1074
1075 statement.append("SELECT ");
1076
1077 String select = ctxt.getFilterString();
1078 if (select == null) {
1079 statement.append('*');
1080 } else {
1081 statement.append(select);
1082 }
1083
1084 final ObjectType type = getTypeDefinition(typeId);
1085 statement.append(" FROM ");
1086 statement.append(type.getQueryName());
1087
1088 if (where != null && where.trim().length() > 0) {
1089 statement.append(" WHERE ");
1090 statement.append(where);
1091 }
1092
1093 String orderBy = ctxt.getOrderBy();
1094 if (orderBy != null && orderBy.trim().length() > 0) {
1095 statement.append(" ORDER BY ");
1096 statement.append(orderBy);
1097 }
1098
1099 return new CollectionIterable<CmisObject>(new AbstractPageFetcher<CmisObject>(ctxt.getMaxItemsPerPage()) {
1100
1101 @Override
1102 protected AbstractPageFetcher.Page<CmisObject> fetchPage(long skipCount) {
1103
1104
1105 ObjectList resultList = discoveryService.query(getRepositoryId(), statement.toString(),
1106 searchAllVersions, ctxt.isIncludeAllowableActions(), ctxt.getIncludeRelationships(),
1107 ctxt.getRenditionFilterString(), BigInteger.valueOf(this.maxNumItems),
1108 BigInteger.valueOf(skipCount), null);
1109
1110
1111 List<CmisObject> page = new ArrayList<CmisObject>();
1112 if (resultList.getObjects() != null) {
1113 for (ObjectData objectData : resultList.getObjects()) {
1114 if (objectData == null) {
1115 continue;
1116 }
1117
1118 page.add(of.convertObject(objectData, ctxt));
1119 }
1120 }
1121
1122 return new AbstractPageFetcher.Page<CmisObject>(page, resultList.getNumItems(),
1123 resultList.hasMoreItems());
1124 }
1125 });
1126 }
1127
1128 @Override
1129 public QueryStatement createQueryStatement(final String statement) {
1130 return new QueryStatementImpl(this, statement);
1131 }
1132
1133 @Override
1134 public QueryStatement createQueryStatement(final Collection<String> selectPropertyIds,
1135 final Map<String, String> fromTypes, final String whereClause, final List<String> orderByPropertyIds) {
1136 return new QueryStatementImpl(this, selectPropertyIds, fromTypes, whereClause, orderByPropertyIds);
1137 }
1138
1139
1140
1141
1142
1143
1144
1145
1146 public void connect() {
1147 lock.writeLock().lock();
1148 try {
1149 binding = CmisBindingHelper.createBinding(parameters, authenticationProvider, typeDefCache);
1150
1151
1152 String repositoryId = parameters.get(SessionParameter.REPOSITORY_ID);
1153 if (repositoryId == null) {
1154 throw new IllegalStateException("Repository ID is not set!");
1155 }
1156
1157 repositoryInfo = objectFactory.convertRepositoryInfo(getBinding().getRepositoryService().getRepositoryInfo(
1158 repositoryId, null));
1159 } finally {
1160 lock.writeLock().unlock();
1161 }
1162 }
1163
1164 @Override
1165 public CmisBinding getBinding() {
1166 lock.readLock().lock();
1167 try {
1168 return binding;
1169 } finally {
1170 lock.readLock().unlock();
1171 }
1172 }
1173
1174 public Cache getCache() {
1175 lock.readLock().lock();
1176 try {
1177 return cache;
1178 } finally {
1179 lock.readLock().unlock();
1180 }
1181 }
1182
1183
1184
1185
1186 public String getRepositoryId() {
1187 return getRepositoryInfo().getId();
1188 }
1189
1190
1191
1192 @Override
1193 public ObjectId createDocument(Map<String, ?> properties, ObjectId folderId, ContentStream contentStream,
1194 VersioningState versioningState, List<Policy> policies, List<Ace> addAces, List<Ace> removeAces) {
1195 checkProperties(properties);
1196
1197 String newId = getBinding().getObjectService().createDocument(getRepositoryId(),
1198 objectFactory.convertProperties(properties, null, null, CREATE_AND_CHECKOUT_UPDATABILITY),
1199 (folderId == null ? null : folderId.getId()), objectFactory.convertContentStream(contentStream),
1200 versioningState, objectFactory.convertPolicies(policies), objectFactory.convertAces(addAces),
1201 objectFactory.convertAces(removeAces), null);
1202
1203 if (newId == null) {
1204 return null;
1205 }
1206
1207 return createObjectId(newId);
1208 }
1209
1210 @Override
1211 public ObjectId createDocumentFromSource(ObjectId source, Map<String, ?> properties, ObjectId folderId,
1212 VersioningState versioningState, List<Policy> policies, List<Ace> addAces, List<Ace> removeAces) {
1213 if (source == null || source.getId() == null) {
1214 throw new IllegalArgumentException("Source must be set!");
1215 }
1216
1217
1218 ObjectType type = null;
1219 List<SecondaryType> secondaryTypes = null;
1220 if (source instanceof CmisObject) {
1221 type = ((CmisObject) source).getType();
1222 secondaryTypes = ((CmisObject) source).getSecondaryTypes();
1223 } else {
1224 CmisObject sourceObj = getObject(source);
1225 type = sourceObj.getType();
1226 secondaryTypes = sourceObj.getSecondaryTypes();
1227 }
1228
1229 if (type.getBaseTypeId() != BaseTypeId.CMIS_DOCUMENT) {
1230 throw new IllegalArgumentException("Source object must be a document!");
1231 }
1232
1233 String newId = getBinding().getObjectService().createDocumentFromSource(getRepositoryId(), source.getId(),
1234 objectFactory.convertProperties(properties, type, secondaryTypes, CREATE_AND_CHECKOUT_UPDATABILITY),
1235 (folderId == null ? null : folderId.getId()), versioningState, objectFactory.convertPolicies(policies),
1236 objectFactory.convertAces(addAces), objectFactory.convertAces(removeAces), null);
1237
1238 if (newId == null) {
1239 return null;
1240 }
1241
1242 return createObjectId(newId);
1243 }
1244
1245 @Override
1246 public ObjectId createFolder(Map<String, ?> properties, ObjectId folderId, List<Policy> policies,
1247 List<Ace> addAces, List<Ace> removeAces) {
1248 checkFolderId(folderId);
1249 checkProperties(properties);
1250
1251 String newId = getBinding().getObjectService().createFolder(getRepositoryId(),
1252 objectFactory.convertProperties(properties, null, null, CREATE_UPDATABILITY), folderId.getId(),
1253 objectFactory.convertPolicies(policies), objectFactory.convertAces(addAces),
1254 objectFactory.convertAces(removeAces), null);
1255
1256 if (newId == null) {
1257 return null;
1258 }
1259
1260 return createObjectId(newId);
1261 }
1262
1263 @Override
1264 public ObjectId createPolicy(Map<String, ?> properties, ObjectId folderId, List<Policy> policies,
1265 List<Ace> addAces, List<Ace> removeAces) {
1266 checkProperties(properties);
1267
1268 String newId = getBinding().getObjectService().createPolicy(getRepositoryId(),
1269 objectFactory.convertProperties(properties, null, null, CREATE_UPDATABILITY),
1270 (folderId == null ? null : folderId.getId()), objectFactory.convertPolicies(policies),
1271 objectFactory.convertAces(addAces), objectFactory.convertAces(removeAces), null);
1272
1273 if (newId == null) {
1274 return null;
1275 }
1276
1277 return createObjectId(newId);
1278 }
1279
1280 @Override
1281 public ObjectId createItem(Map<String, ?> properties, ObjectId folderId, List<Policy> policies, List<Ace> addAces,
1282 List<Ace> removeAces) {
1283 checkProperties(properties);
1284
1285 String newId = getBinding().getObjectService().createItem(getRepositoryId(),
1286 objectFactory.convertProperties(properties, null, null, CREATE_UPDATABILITY),
1287 (folderId == null ? null : folderId.getId()), objectFactory.convertPolicies(policies),
1288 objectFactory.convertAces(addAces), objectFactory.convertAces(removeAces), null);
1289
1290 if (newId == null) {
1291 return null;
1292 }
1293
1294 return createObjectId(newId);
1295 }
1296
1297 @Override
1298 public ObjectId createRelationship(Map<String, ?> properties, List<Policy> policies, List<Ace> addAces,
1299 List<Ace> removeAces) {
1300 checkProperties(properties);
1301
1302 String newId = getBinding().getObjectService().createRelationship(getRepositoryId(),
1303 objectFactory.convertProperties(properties, null, null, CREATE_UPDATABILITY),
1304 objectFactory.convertPolicies(policies), objectFactory.convertAces(addAces),
1305 objectFactory.convertAces(removeAces), null);
1306
1307 if (newId == null) {
1308 return null;
1309 }
1310
1311 return createObjectId(newId);
1312 }
1313
1314 @Override
1315 public ObjectId createDocument(Map<String, ?> properties, ObjectId folderId, ContentStream contentStream,
1316 VersioningState versioningState) {
1317 return createDocument(properties, folderId, contentStream, versioningState, null, null, null);
1318 }
1319
1320 @Override
1321 public ObjectId createDocumentFromSource(ObjectId source, Map<String, ?> properties, ObjectId folderId,
1322 VersioningState versioningState) {
1323 return createDocumentFromSource(source, properties, folderId, versioningState, null, null, null);
1324 }
1325
1326 @Override
1327 public ObjectId createFolder(Map<String, ?> properties, ObjectId folderId) {
1328 return createFolder(properties, folderId, null, null, null);
1329 }
1330
1331 @Override
1332 public ObjectId createPolicy(Map<String, ?> properties, ObjectId folderId) {
1333 return createPolicy(properties, folderId, null, null, null);
1334 }
1335
1336 @Override
1337 public ObjectId createItem(Map<String, ?> properties, ObjectId folderId) {
1338 return createItem(properties, folderId, null, null, null);
1339 }
1340
1341
1342
1343 @Override
1344 public ObjectId createRelationship(Map<String, ?> properties) {
1345 return createRelationship(properties, null, null, null);
1346 }
1347
1348 @Override
1349 public ItemIterable<Relationship> getRelationships(ObjectId objectId, final boolean includeSubRelationshipTypes,
1350 final RelationshipDirection relationshipDirection, ObjectType type, OperationContext context) {
1351 checkObjectId(objectId);
1352 checkContext(context);
1353
1354 final String id = objectId.getId();
1355 final String typeId = type == null ? null : type.getId();
1356 final RelationshipService relationshipService = getBinding().getRelationshipService();
1357 final OperationContext ctxt = new OperationContextImpl(context);
1358
1359 return new CollectionIterable<Relationship>(new AbstractPageFetcher<Relationship>(ctxt.getMaxItemsPerPage()) {
1360
1361 @Override
1362 protected AbstractPageFetcher.Page<Relationship> fetchPage(long skipCount) {
1363
1364
1365 ObjectList relList = relationshipService.getObjectRelationships(getRepositoryId(), id,
1366 includeSubRelationshipTypes, relationshipDirection, typeId, ctxt.getFilterString(),
1367 ctxt.isIncludeAllowableActions(), BigInteger.valueOf(this.maxNumItems),
1368 BigInteger.valueOf(skipCount), null);
1369
1370
1371 List<Relationship> page = new ArrayList<Relationship>();
1372 if (relList.getObjects() != null) {
1373 for (ObjectData rod : relList.getObjects()) {
1374 CmisObject relationship = getObject(rod.getId(), ctxt);
1375 if (!(relationship instanceof Relationship)) {
1376 throw new CmisRuntimeException("Repository returned an object that is not a relationship!");
1377 }
1378
1379 page.add((Relationship) relationship);
1380 }
1381 }
1382
1383 return new AbstractPageFetcher.Page<Relationship>(page, relList.getNumItems(), relList.hasMoreItems());
1384 }
1385 });
1386 }
1387
1388
1389
1390 @Override
1391 public List<BulkUpdateObjectIdAndChangeToken> bulkUpdateProperties(List<CmisObject> objects,
1392 Map<String, ?> properties, List<String> addSecondaryTypeIds, List<String> removeSecondaryTypeIds) {
1393 checkCmisVersion();
1394 checkProperties(properties);
1395
1396 ObjectType objectType = null;
1397 Map<String, SecondaryType> secondaryTypes = new HashMap<String, SecondaryType>();
1398
1399
1400 if (addSecondaryTypeIds != null) {
1401 for (String stid : addSecondaryTypeIds) {
1402 ObjectType secondaryType = getTypeDefinition(stid);
1403
1404 if (!(secondaryType instanceof SecondaryType)) {
1405 throw new IllegalArgumentException("Secondary types contains a type that is not a secondary type: "
1406 + secondaryType.getId());
1407 }
1408
1409 secondaryTypes.put(secondaryType.getId(), (SecondaryType) secondaryType);
1410 }
1411 }
1412
1413
1414 List<BulkUpdateObjectIdAndChangeToken> objectIdsAndChangeTokens = new ArrayList<BulkUpdateObjectIdAndChangeToken>();
1415 for (CmisObject object : objects) {
1416 if (object == null) {
1417 continue;
1418 }
1419
1420 objectIdsAndChangeTokens.add(new BulkUpdateObjectIdAndChangeTokenImpl(object.getId(), object
1421 .getChangeToken()));
1422
1423 if (objectType == null) {
1424 objectType = object.getType();
1425 }
1426
1427 if (object.getSecondaryTypes() != null) {
1428 for (SecondaryType secondaryType : object.getSecondaryTypes()) {
1429 secondaryTypes.put(secondaryType.getId(), secondaryType);
1430 }
1431 }
1432 }
1433
1434 Set<Updatability> updatebility = EnumSet.noneOf(Updatability.class);
1435 updatebility.add(Updatability.READWRITE);
1436
1437 return getBinding().getObjectService().bulkUpdateProperties(getRepositoryId(), objectIdsAndChangeTokens,
1438 objectFactory.convertProperties(properties, objectType, secondaryTypes.values(), updatebility),
1439 addSecondaryTypeIds, removeSecondaryTypeIds, null);
1440 }
1441
1442
1443
1444 @Override
1445 public void delete(ObjectId objectId) {
1446 delete(objectId, true);
1447 }
1448
1449 @Override
1450 public void delete(ObjectId objectId, boolean allVersions) {
1451 checkObjectId(objectId);
1452
1453 getBinding().getObjectService().deleteObject(getRepositoryId(), objectId.getId(), allVersions, null);
1454 removeObjectFromCache(objectId);
1455 }
1456
1457 @Override
1458 public List<String> deleteTree(ObjectId folderId, boolean allVersions, UnfileObject unfile,
1459 boolean continueOnFailure) {
1460 checkFolderId(folderId);
1461
1462 FailedToDeleteData failed = getBinding().getObjectService().deleteTree(getRepositoryId(), folderId.getId(),
1463 allVersions, unfile, continueOnFailure, null);
1464
1465 if (failed == null || isNullOrEmpty(failed.getIds())) {
1466 removeObjectFromCache(folderId);
1467 }
1468
1469 return (failed != null ? failed.getIds() : null);
1470 }
1471
1472
1473
1474 @Override
1475 public ContentStream getContentStream(ObjectId docId) {
1476 return getContentStream(docId, null, null, null);
1477 }
1478
1479 @Override
1480 public ContentStream getContentStream(ObjectId docId, String streamId, BigInteger offset, BigInteger length) {
1481 checkDocumentId(docId);
1482
1483
1484 ContentStream contentStream = null;
1485 try {
1486 contentStream = getBinding().getObjectService().getContentStream(getRepositoryId(), docId.getId(),
1487 streamId, offset, length, null);
1488 } catch (CmisConstraintException e) {
1489
1490 return null;
1491 }
1492
1493 return contentStream;
1494 }
1495
1496
1497
1498 @Override
1499 public Acl getAcl(ObjectId objectId, boolean onlyBasicPermissions) {
1500 checkObjectId(objectId);
1501 return getBinding().getAclService().getAcl(getRepositoryId(), objectId.getId(), onlyBasicPermissions, null);
1502 }
1503
1504 @Override
1505 public Acl applyAcl(ObjectId objectId, List<Ace> addAces, List<Ace> removeAces, AclPropagation aclPropagation) {
1506 checkObjectId(objectId);
1507
1508 ObjectFactory of = getObjectFactory();
1509
1510 return getBinding().getAclService().applyAcl(getRepositoryId(), objectId.getId(), of.convertAces(addAces),
1511 of.convertAces(removeAces), aclPropagation, null);
1512 }
1513
1514 @Override
1515 public Acl setAcl(ObjectId objectId, List<Ace> aces) {
1516 checkObjectId(objectId);
1517
1518 if (aces == null) {
1519 aces = Collections.emptyList();
1520 }
1521
1522 AclService aclService = getBinding().getAclService();
1523 if (!(aclService instanceof ExtendedAclService)) {
1524 throw new CmisNotSupportedException("setAcl() is not supported by the binding implementation.");
1525 }
1526
1527 ObjectFactory of = getObjectFactory();
1528
1529 return ((ExtendedAclService) aclService).setAcl(getRepositoryId(), objectId.getId(), of.convertAces(aces));
1530 }
1531
1532
1533
1534 @Override
1535 public void applyPolicy(ObjectId objectId, ObjectId... policyIds) {
1536 checkObjectId(objectId);
1537
1538 if (policyIds == null || policyIds.length == 0) {
1539 throw new IllegalArgumentException("No Policies provided!");
1540 }
1541
1542 String[] ids = new String[policyIds.length];
1543 for (int i = 0; i < policyIds.length; i++) {
1544 if (policyIds[i] == null || policyIds[i].getId() == null) {
1545 throw new IllegalArgumentException("A Policy ID is not set!");
1546 }
1547
1548 ids[i] = policyIds[i].getId();
1549 }
1550
1551 for (String id : ids) {
1552 getBinding().getPolicyService().applyPolicy(getRepositoryId(), id, objectId.getId(), null);
1553 }
1554 }
1555
1556 @Override
1557 public void removePolicy(ObjectId objectId, ObjectId... policyIds) {
1558 checkObjectId(objectId);
1559
1560 if (policyIds == null || policyIds.length == 0) {
1561 throw new IllegalArgumentException("No Policies provided!");
1562 }
1563
1564 String[] ids = new String[policyIds.length];
1565 for (int i = 0; i < policyIds.length; i++) {
1566 if (policyIds[i] == null || policyIds[i].getId() == null) {
1567 throw new IllegalArgumentException("A Policy ID is not set!");
1568 }
1569
1570 ids[i] = policyIds[i].getId();
1571 }
1572
1573 for (String id : ids) {
1574 getBinding().getPolicyService().removePolicy(getRepositoryId(), id, objectId.getId(), null);
1575 }
1576 }
1577
1578
1579
1580 protected final void checkObjectId(ObjectId objectId) {
1581 if (objectId == null || objectId.getId() == null) {
1582 throw new IllegalArgumentException("Invalid object ID!");
1583 }
1584 }
1585
1586 protected final void checkObjectId(String objectId) {
1587 if (objectId == null) {
1588 throw new IllegalArgumentException("Invalid object ID!");
1589 }
1590 }
1591
1592 protected final void checkDocumentId(ObjectId docId) {
1593 if (docId == null || docId.getId() == null) {
1594 throw new IllegalArgumentException("Invalid document ID!");
1595 }
1596 }
1597
1598 protected final void checkDocumentId(String docId) {
1599 if (docId == null) {
1600 throw new IllegalArgumentException("Invalid document ID!");
1601 }
1602 }
1603
1604 protected final void checkFolderId(ObjectId folderId) {
1605 if (folderId == null || folderId.getId() == null) {
1606 throw new IllegalArgumentException("Invalid folder ID!");
1607 }
1608 }
1609
1610 protected final void checkPath(String path) {
1611 if (path == null || path.length() < 1) {
1612 throw new IllegalArgumentException("Invalid path!");
1613 }
1614 if (path.charAt(0) != '/') {
1615 throw new IllegalArgumentException("Path must start with a '/'!");
1616 }
1617 }
1618
1619 protected final void checkContext(OperationContext context) {
1620 if (context == null) {
1621 throw new IllegalArgumentException("Invalid Operation Context!");
1622 }
1623 }
1624
1625 protected final void checkProperties(Map<String, ?> properties) {
1626 if (isNullOrEmpty(properties)) {
1627 throw new IllegalArgumentException("Properties must not be empty!");
1628 }
1629 }
1630
1631 protected final void checkCmisVersion() {
1632 if (repositoryInfo.getCmisVersion() == CmisVersion.CMIS_1_0) {
1633 throw new CmisNotSupportedException("This method is not supported for CMIS 1.0 repositories.");
1634 }
1635 }
1636
1637
1638
1639 @Override
1640 public String toString() {
1641 return "Session " + getBinding().getSessionId();
1642 }
1643 }