This project has retired. For details please refer to its Attic page.
SessionImpl xref

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   * http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.chemistry.opencmis.client.runtime;
20  
21  import java.math.BigInteger;
22  import java.util.ArrayList;
23  import java.util.HashSet;
24  import java.util.List;
25  import java.util.Locale;
26  import java.util.Map;
27  import java.util.Set;
28  import java.util.concurrent.locks.ReentrantReadWriteLock;
29  
30  import org.apache.chemistry.opencmis.client.api.ChangeEvents;
31  import org.apache.chemistry.opencmis.client.api.CmisObject;
32  import org.apache.chemistry.opencmis.client.api.Document;
33  import org.apache.chemistry.opencmis.client.api.ExtensionHandler;
34  import org.apache.chemistry.opencmis.client.api.Folder;
35  import org.apache.chemistry.opencmis.client.api.ItemIterable;
36  import org.apache.chemistry.opencmis.client.api.ObjectFactory;
37  import org.apache.chemistry.opencmis.client.api.ObjectId;
38  import org.apache.chemistry.opencmis.client.api.ObjectType;
39  import org.apache.chemistry.opencmis.client.api.OperationContext;
40  import org.apache.chemistry.opencmis.client.api.Policy;
41  import org.apache.chemistry.opencmis.client.api.QueryResult;
42  import org.apache.chemistry.opencmis.client.api.QueryStatement;
43  import org.apache.chemistry.opencmis.client.api.Relationship;
44  import org.apache.chemistry.opencmis.client.api.Session;
45  import org.apache.chemistry.opencmis.client.api.Tree;
46  import org.apache.chemistry.opencmis.client.runtime.cache.Cache;
47  import org.apache.chemistry.opencmis.client.runtime.cache.CacheImpl;
48  import org.apache.chemistry.opencmis.client.runtime.repository.ObjectFactoryImpl;
49  import org.apache.chemistry.opencmis.client.runtime.util.AbstractPageFetcher;
50  import org.apache.chemistry.opencmis.client.runtime.util.CollectionIterable;
51  import org.apache.chemistry.opencmis.client.runtime.util.TreeImpl;
52  import org.apache.chemistry.opencmis.commons.SessionParameter;
53  import org.apache.chemistry.opencmis.commons.data.Ace;
54  import org.apache.chemistry.opencmis.commons.data.Acl;
55  import org.apache.chemistry.opencmis.commons.data.ContentStream;
56  import org.apache.chemistry.opencmis.commons.data.ObjectData;
57  import org.apache.chemistry.opencmis.commons.data.ObjectList;
58  import org.apache.chemistry.opencmis.commons.data.RepositoryInfo;
59  import org.apache.chemistry.opencmis.commons.definitions.TypeDefinition;
60  import org.apache.chemistry.opencmis.commons.definitions.TypeDefinitionContainer;
61  import org.apache.chemistry.opencmis.commons.definitions.TypeDefinitionList;
62  import org.apache.chemistry.opencmis.commons.enums.AclPropagation;
63  import org.apache.chemistry.opencmis.commons.enums.BaseTypeId;
64  import org.apache.chemistry.opencmis.commons.enums.IncludeRelationships;
65  import org.apache.chemistry.opencmis.commons.enums.RelationshipDirection;
66  import org.apache.chemistry.opencmis.commons.enums.Updatability;
67  import org.apache.chemistry.opencmis.commons.enums.VersioningState;
68  import org.apache.chemistry.opencmis.commons.exceptions.CmisRuntimeException;
69  import org.apache.chemistry.opencmis.commons.spi.AuthenticationProvider;
70  import org.apache.chemistry.opencmis.commons.spi.CmisBinding;
71  import org.apache.chemistry.opencmis.commons.spi.DiscoveryService;
72  import org.apache.chemistry.opencmis.commons.spi.Holder;
73  import org.apache.chemistry.opencmis.commons.spi.NavigationService;
74  import org.apache.chemistry.opencmis.commons.spi.RelationshipService;
75  import org.apache.chemistry.opencmis.commons.spi.RepositoryService;
76  
77  /**
78   * Persistent model session.
79   */
80  public class SessionImpl implements Session {
81  
82      private static final OperationContext DEFAULT_CONTEXT = new OperationContextImpl(null, false, true, false,
83              IncludeRelationships.NONE, null, true, null, true, 100);
84  
85      private static final Set<Updatability> CREATE_UPDATABILITY = new HashSet<Updatability>();
86      static {
87          CREATE_UPDATABILITY.add(Updatability.ONCREATE);
88          CREATE_UPDATABILITY.add(Updatability.READWRITE);
89      }
90  
91      // private static Log log = LogFactory.getLog(SessionImpl.class);
92  
93      private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
94  
95      /*
96       * default session context (serializable)
97       */
98      private OperationContext context = DEFAULT_CONTEXT;
99  
100     /*
101      * session parameter (serializable)
102      */
103     private Map<String, String> parameters;
104 
105     /*
106      * CMIS binding (serializable)
107      */
108     private CmisBinding binding;
109 
110     /*
111      * Session Locale, determined from session parameter (serializable)
112      */
113     private Locale locale;
114 
115     /*
116      * Object factory (serializable)
117      */
118     private final ObjectFactory objectFactory;
119 
120     /*
121      * Authentication provider (serializable)
122      */
123     private final AuthenticationProvider authenticationProvider;
124 
125     /*
126      * Object cache (serializable)
127      */
128     private Cache cache;
129     private final boolean cachePathOmit;
130 
131     /*
132      * Repository info (serializable)
133      */
134     private RepositoryInfo repositoryInfo;
135 
136     /**
137      * required for serialization
138      */
139     private static final long serialVersionUID = 1L;
140 
141     /**
142      * Constructor.
143      */
144     public SessionImpl(Map<String, String> parameters, ObjectFactory objectFactory,
145             AuthenticationProvider authenticationProvider, Cache cache) {
146         if (parameters == null) {
147             throw new IllegalArgumentException("No parameters provided!");
148         }
149 
150         this.parameters = parameters;
151         this.locale = determineLocale(parameters);
152 
153         this.objectFactory = (objectFactory == null ? createObjectFactory() : objectFactory);
154         this.authenticationProvider = authenticationProvider;
155         this.cache = (cache == null ? createCache() : cache);
156 
157         cachePathOmit = Boolean.parseBoolean(parameters.get(SessionParameter.CACHE_PATH_OMIT));
158     }
159 
160     private static Locale determineLocale(Map<String, String> parameters) {
161         Locale locale = null;
162 
163         String language = parameters.get(SessionParameter.LOCALE_ISO639_LANGUAGE);
164         String country = parameters.get(SessionParameter.LOCALE_ISO3166_COUNTRY);
165         String variant = parameters.get(SessionParameter.LOCALE_VARIANT);
166 
167         if (variant != null) {
168             // all 3 parameter must not be null and valid
169             locale = new Locale(language, country, variant);
170         } else {
171             if (country != null) {
172                 // 2 parameter must not be null and valid
173                 locale = new Locale(language, country);
174             } else {
175                 if (language != null) {
176                     // 1 parameter must not be null and valid
177                     locale = new Locale(language);
178                 } else {
179                     locale = Locale.getDefault();
180                 }
181             }
182         }
183 
184         return locale;
185     }
186 
187     private ObjectFactory createObjectFactory() {
188         try {
189             String classname = parameters.get(SessionParameter.OBJECT_FACTORY_CLASS);
190 
191             Class<?> objectFactoryClass;
192             if (classname == null) {
193                 objectFactoryClass = ObjectFactoryImpl.class;
194             } else {
195                 objectFactoryClass = Class.forName(classname);
196             }
197 
198             Object of = objectFactoryClass.newInstance();
199             if (!(of instanceof ObjectFactory)) {
200                 throw new Exception("Class does not implement ObjectFactory!");
201             }
202 
203             ((ObjectFactory) of).initialize(this, parameters);
204 
205             return (ObjectFactory) of;
206         } catch (Exception e) {
207             throw new IllegalArgumentException("Unable to create object factory: " + e, e);
208         }
209     }
210 
211     private Cache createCache() {
212         try {
213             String classname = parameters.get(SessionParameter.CACHE_CLASS);
214 
215             Class<?> cacheClass;
216             if (classname == null) {
217                 cacheClass = CacheImpl.class;
218             } else {
219                 cacheClass = Class.forName(classname);
220             }
221 
222             Object of = cacheClass.newInstance();
223             if (!(of instanceof Cache)) {
224                 throw new Exception("Class does not implement Cache!");
225             }
226 
227             ((Cache) of).initialize(this, parameters);
228 
229             return (Cache) of;
230         } catch (Exception e) {
231             throw new IllegalArgumentException("Unable to create cache: " + e, e);
232         }
233     }
234 
235     public void clear() {
236         lock.writeLock().lock();
237         try {
238             // create new object cache
239             this.cache = createCache();
240 
241             // clear provider cache
242             getBinding().clearAllCaches();
243         } finally {
244             lock.writeLock().unlock();
245         }
246     }
247 
248     public ObjectFactory getObjectFactory() {
249         return this.objectFactory;
250     }
251 
252     public ItemIterable<Document> getCheckedOutDocs() {
253         return getCheckedOutDocs(getDefaultContext());
254     }
255 
256     public ItemIterable<Document> getCheckedOutDocs(OperationContext context) {
257         if (context == null) {
258             throw new IllegalArgumentException("Operation context must be set!");
259         }
260 
261         final NavigationService navigationService = getBinding().getNavigationService();
262         final ObjectFactory objectFactory = getObjectFactory();
263         final OperationContext ctxt = new OperationContextImpl(context);
264 
265         return new CollectionIterable<Document>(new AbstractPageFetcher<Document>(ctxt.getMaxItemsPerPage()) {
266 
267             @Override
268             protected AbstractPageFetcher.Page<Document> fetchPage(long skipCount) {
269 
270                 // get all checked out documents
271                 ObjectList checkedOutDocs = navigationService.getCheckedOutDocs(getRepositoryId(), null,
272                         ctxt.getFilterString(), ctxt.getOrderBy(), ctxt.isIncludeAllowableActions(),
273                         ctxt.getIncludeRelationships(), ctxt.getRenditionFilterString(),
274                         BigInteger.valueOf(this.maxNumItems), BigInteger.valueOf(skipCount), null);
275 
276                 // convert objects
277                 List<Document> page = new ArrayList<Document>();
278                 if (checkedOutDocs.getObjects() != null) {
279                     for (ObjectData objectData : checkedOutDocs.getObjects()) {
280                         CmisObject doc = objectFactory.convertObject(objectData, ctxt);
281                         if (!(doc instanceof Document)) {
282                             // should not happen...
283                             continue;
284                         }
285 
286                         page.add((Document) doc);
287                     }
288                 }
289 
290                 return new AbstractPageFetcher.Page<Document>(page, checkedOutDocs.getNumItems(),
291                         checkedOutDocs.hasMoreItems());
292             }
293         });
294     }
295 
296     public ChangeEvents getContentChanges(String changeLogToken, boolean includeProperties, long maxNumItems) {
297         return getContentChanges(changeLogToken, includeProperties, maxNumItems, getDefaultContext());
298     }
299 
300     public ChangeEvents getContentChanges(String changeLogToken, boolean includeProperties, long maxNumItems,
301             OperationContext context) {
302         if (context == null) {
303             throw new IllegalArgumentException("Operation context must be set!");
304         }
305 
306         lock.readLock().lock();
307         try {
308             Holder<String> changeLogTokenHolder = new Holder<String>(changeLogToken);
309 
310             ObjectList objectList = getBinding().getDiscoveryService().getContentChanges(getRepositoryInfo().getId(),
311                     changeLogTokenHolder, includeProperties, context.getFilterString(), context.isIncludePolicies(),
312                     context.isIncludeAcls(), BigInteger.valueOf(maxNumItems), null);
313 
314             return objectFactory.convertChangeEvents(changeLogTokenHolder.getValue(), objectList);
315         } finally {
316             lock.readLock().unlock();
317         }
318     }
319 
320     public OperationContext getDefaultContext() {
321         lock.readLock().lock();
322         try {
323             return this.context;
324         } finally {
325             lock.readLock().unlock();
326         }
327     }
328 
329     public void setDefaultContext(OperationContext context) {
330         lock.writeLock().lock();
331         try {
332             this.context = (context == null ? DEFAULT_CONTEXT : context);
333         } finally {
334             lock.writeLock().unlock();
335         }
336     }
337 
338     public OperationContext createOperationContext(Set<String> filter, boolean includeAcls,
339             boolean includeAllowableActions, boolean includePolicies, IncludeRelationships includeRelationships,
340             Set<String> renditionFilter, boolean includePathSegments, String orderBy, boolean cacheEnabled,
341             int maxItemsPerPage) {
342         return new OperationContextImpl(filter, includeAcls, includeAllowableActions, includePolicies,
343                 includeRelationships, renditionFilter, includePathSegments, orderBy, cacheEnabled, maxItemsPerPage);
344     }
345 
346     public OperationContext createOperationContext() {
347         return new OperationContextImpl();
348     }
349 
350     public ObjectId createObjectId(String id) {
351         return new ObjectIdImpl(id);
352     }
353 
354     public Locale getLocale() {
355         return this.locale;
356     }
357 
358     public CmisObject getObject(ObjectId objectId) {
359         return getObject(objectId, getDefaultContext());
360     }
361 
362     public CmisObject getObject(ObjectId objectId, OperationContext context) {
363         if ((objectId == null) || (objectId.getId() == null)) {
364             throw new IllegalArgumentException("Object Id must be set!");
365         }
366 
367         return getObject(objectId.getId(), context);
368     }
369 
370     public CmisObject getObject(String objectId) {
371         return getObject(objectId, getDefaultContext());
372     }
373 
374     public CmisObject getObject(String objectId, OperationContext context) {
375         if (objectId == null) {
376             throw new IllegalArgumentException("Object Id must be set!");
377         }
378         if (context == null) {
379             throw new IllegalArgumentException("Operation context must be set!");
380         }
381 
382         CmisObject result = null;
383 
384         // ask the cache first
385         if (context.isCacheEnabled()) {
386             result = this.cache.getById(objectId, context.getCacheKey());
387             if (result != null) {
388                 return result;
389             }
390         }
391 
392         // get the object
393         ObjectData objectData = this.binding.getObjectService().getObject(getRepositoryId(), objectId,
394                 context.getFilterString(), context.isIncludeAllowableActions(), context.getIncludeRelationships(),
395                 context.getRenditionFilterString(), context.isIncludePolicies(), context.isIncludeAcls(), null);
396 
397         result = getObjectFactory().convertObject(objectData, context);
398 
399         // put into cache
400         if (context.isCacheEnabled()) {
401             this.cache.put(result, context.getCacheKey());
402         }
403 
404         return result;
405     }
406 
407     public CmisObject getObjectByPath(String path) {
408         return getObjectByPath(path, getDefaultContext());
409     }
410 
411     public CmisObject getObjectByPath(String path, OperationContext context) {
412         if (path == null) {
413             throw new IllegalArgumentException("Path must be set!");
414         }
415         if (context == null) {
416             throw new IllegalArgumentException("Operation context must be set!");
417         }
418 
419         CmisObject result = null;
420 
421         // ask the cache first
422         if (context.isCacheEnabled() && !cachePathOmit) {
423             result = this.cache.getByPath(path, context.getCacheKey());
424             if (result != null) {
425                 return result;
426             }
427         }
428 
429         // get the object
430         ObjectData objectData = this.binding.getObjectService().getObjectByPath(getRepositoryId(), path,
431                 context.getFilterString(), context.isIncludeAllowableActions(), context.getIncludeRelationships(),
432                 context.getRenditionFilterString(), context.isIncludePolicies(), context.isIncludeAcls(), null);
433 
434         result = getObjectFactory().convertObject(objectData, context);
435 
436         // put into cache
437         if (context.isCacheEnabled()) {
438             this.cache.putPath(path, result, context.getCacheKey());
439         }
440 
441         return result;
442     }
443 
444     public void removeObjectFromCache(ObjectId objectId) {
445         if ((objectId == null) || (objectId.getId() == null)) {
446             return;
447         }
448 
449         removeObjectFromCache(objectId.getId());
450     }
451 
452     public void removeObjectFromCache(String objectId) {
453         cache.remove(objectId);
454     }
455 
456     public RepositoryInfo getRepositoryInfo() {
457         lock.readLock().lock();
458         try {
459             return this.repositoryInfo;
460         } finally {
461             lock.readLock().unlock();
462         }
463     }
464 
465     public Folder getRootFolder() {
466         return getRootFolder(getDefaultContext());
467     }
468 
469     public Folder getRootFolder(OperationContext context) {
470         String rootFolderId = getRepositoryInfo().getRootFolderId();
471 
472         CmisObject rootFolder = getObject(createObjectId(rootFolderId), context);
473         if (!(rootFolder instanceof Folder)) {
474             throw new CmisRuntimeException("Root folder object is not a folder!");
475         }
476 
477         return (Folder) rootFolder;
478     }
479 
480     public ItemIterable<ObjectType> getTypeChildren(final String typeId, final boolean includePropertyDefinitions) {
481         final RepositoryService repositoryService = getBinding().getRepositoryService();
482         final ObjectFactory objectFactory = this.getObjectFactory();
483 
484         return new CollectionIterable<ObjectType>(new AbstractPageFetcher<ObjectType>(this.getDefaultContext()
485                 .getMaxItemsPerPage()) {
486 
487             @Override
488             protected AbstractPageFetcher.Page<ObjectType> fetchPage(long skipCount) {
489 
490                 // fetch the data
491                 TypeDefinitionList tdl = repositoryService.getTypeChildren(SessionImpl.this.getRepositoryId(), typeId,
492                         includePropertyDefinitions, BigInteger.valueOf(this.maxNumItems),
493                         BigInteger.valueOf(skipCount), null);
494 
495                 // convert type definitions
496                 List<ObjectType> page = new ArrayList<ObjectType>(tdl.getList().size());
497                 for (TypeDefinition typeDefinition : tdl.getList()) {
498                     page.add(objectFactory.convertTypeDefinition(typeDefinition));
499                 }
500 
501                 return new AbstractPageFetcher.Page<ObjectType>(page, tdl.getNumItems(), tdl.hasMoreItems()) {
502                 };
503             }
504         });
505     }
506 
507     public ObjectType getTypeDefinition(String typeId) {
508         TypeDefinition typeDefinition = getBinding().getRepositoryService().getTypeDefinition(getRepositoryId(),
509                 typeId, null);
510         return objectFactory.convertTypeDefinition(typeDefinition);
511     }
512 
513     public List<Tree<ObjectType>> getTypeDescendants(String typeId, int depth, boolean includePropertyDefinitions) {
514         List<TypeDefinitionContainer> descendants = getBinding().getRepositoryService().getTypeDescendants(
515                 getRepositoryId(), typeId, BigInteger.valueOf(depth), includePropertyDefinitions, null);
516 
517         return convertTypeDescendants(descendants);
518     }
519 
520     /**
521      * Converts binding <code>TypeDefinitionContainer</code> to API
522      * <code>Container</code>.
523      */
524     private List<Tree<ObjectType>> convertTypeDescendants(List<TypeDefinitionContainer> descendantsList) {
525         List<Tree<ObjectType>> result = new ArrayList<Tree<ObjectType>>();
526 
527         for (TypeDefinitionContainer container : descendantsList) {
528             ObjectType objectType = objectFactory.convertTypeDefinition(container.getTypeDefinition());
529             List<Tree<ObjectType>> children = convertTypeDescendants(container.getChildren());
530 
531             result.add(new TreeImpl<ObjectType>(objectType, children));
532         }
533 
534         return result;
535     }
536 
537     public ItemIterable<QueryResult> query(final String statement, final boolean searchAllVersions) {
538         return query(statement, searchAllVersions, getDefaultContext());
539     }
540 
541     public ItemIterable<QueryResult> query(final String statement, final boolean searchAllVersions,
542             OperationContext context) {
543         if (context == null) {
544             throw new IllegalArgumentException("Operation context must be set!");
545         }
546 
547         final DiscoveryService discoveryService = getBinding().getDiscoveryService();
548         final ObjectFactory objectFactory = this.getObjectFactory();
549         final OperationContext ctxt = new OperationContextImpl(context);
550 
551         return new CollectionIterable<QueryResult>(new AbstractPageFetcher<QueryResult>(ctxt.getMaxItemsPerPage()) {
552 
553             @Override
554             protected AbstractPageFetcher.Page<QueryResult> fetchPage(long skipCount) {
555 
556                 // fetch the data
557                 ObjectList resultList = discoveryService.query(getRepositoryId(), statement, searchAllVersions,
558                         ctxt.isIncludeAllowableActions(), ctxt.getIncludeRelationships(),
559                         ctxt.getRenditionFilterString(), BigInteger.valueOf(this.maxNumItems),
560                         BigInteger.valueOf(skipCount), null);
561 
562                 // convert query results
563                 List<QueryResult> page = new ArrayList<QueryResult>();
564                 if (resultList.getObjects() != null) {
565                     for (ObjectData objectData : resultList.getObjects()) {
566                         if (objectData == null) {
567                             continue;
568                         }
569 
570                         page.add(objectFactory.convertQueryResult(objectData));
571                     }
572                 }
573 
574                 return new AbstractPageFetcher.Page<QueryResult>(page, resultList.getNumItems(),
575                         resultList.hasMoreItems());
576             }
577         });
578     }
579 
580     public ItemIterable<CmisObject> queryObjects(String typeId, String where, final boolean searchAllVersions,
581             OperationContext context) {
582         if (typeId == null || typeId.trim().length() == 0) {
583             throw new IllegalArgumentException("Type id must be set!");
584         }
585 
586         if (context == null) {
587             throw new IllegalArgumentException("Operation context must be set!");
588         }
589 
590         final DiscoveryService discoveryService = getBinding().getDiscoveryService();
591         final ObjectFactory objectFactory = this.getObjectFactory();
592         final OperationContext ctxt = new OperationContextImpl(context);
593         final StringBuilder statement = new StringBuilder("SELECT ");
594 
595         String select = ctxt.getFilterString();
596         if (select == null) {
597             statement.append("*");
598         } else {
599             statement.append(select);
600         }
601 
602         final ObjectType type = getTypeDefinition(typeId);
603         statement.append(" FROM ");
604         statement.append(type.getQueryName());
605 
606         if (where != null && where.trim().length() > 0) {
607             statement.append(" WHERE ");
608             statement.append(where);
609         }
610 
611         String orderBy = ctxt.getOrderBy();
612         if (orderBy != null && orderBy.trim().length() > 0) {
613             statement.append(" ORDER BY ");
614             statement.append(orderBy);
615         }
616 
617         return new CollectionIterable<CmisObject>(new AbstractPageFetcher<CmisObject>(ctxt.getMaxItemsPerPage()) {
618 
619             @Override
620             protected AbstractPageFetcher.Page<CmisObject> fetchPage(long skipCount) {
621 
622                 // fetch the data
623                 ObjectList resultList = discoveryService.query(getRepositoryId(), statement.toString(),
624                         searchAllVersions, ctxt.isIncludeAllowableActions(), ctxt.getIncludeRelationships(),
625                         ctxt.getRenditionFilterString(), BigInteger.valueOf(this.maxNumItems),
626                         BigInteger.valueOf(skipCount), null);
627 
628                 // convert query results
629                 List<CmisObject> page = new ArrayList<CmisObject>();
630                 if (resultList.getObjects() != null) {
631                     for (ObjectData objectData : resultList.getObjects()) {
632                         if (objectData == null) {
633                             continue;
634                         }
635 
636                         page.add(objectFactory.convertObject(objectData, ctxt));
637                     }
638                 }
639 
640                 return new AbstractPageFetcher.Page<CmisObject>(page, resultList.getNumItems(),
641                         resultList.hasMoreItems());
642             }
643         });
644     }
645 
646     public QueryStatement createQueryStatement(final String statement) {
647         return new QueryStatementImpl(this, statement);
648     }
649 
650     public String setExtensionContext(String context) {
651         throw new CmisRuntimeException("not implemented");
652     }
653 
654     public ExtensionHandler setExtensionHandler(String context, ExtensionHandler extensionHandler) {
655         throw new CmisRuntimeException("not implemented");
656     }
657 
658     /**
659      * Connect session object to the provider. This is the very first call after
660      * a session is created.
661      * <p>
662      * In dependency of the parameter set an {@code AtomPub}, a
663      * {@code WebService} or an {@code InMemory} provider is selected.
664      */
665     public void connect() {
666         lock.writeLock().lock();
667         try {
668             this.binding = CmisBindingHelper.createBinding(parameters, authenticationProvider);
669 
670             /* get initial repository id from session parameter */
671             String repositoryId = parameters.get(SessionParameter.REPOSITORY_ID);
672             if (repositoryId == null) {
673                 throw new IllegalStateException("Repository Id is not set!");
674             }
675 
676             repositoryInfo = objectFactory.convertRepositoryInfo(getBinding().getRepositoryService().getRepositoryInfo(
677                     repositoryId, null));
678         } finally {
679             lock.writeLock().unlock();
680         }
681     }
682 
683     public CmisBinding getBinding() {
684         lock.readLock().lock();
685         try {
686             return this.binding;
687         } finally {
688             lock.readLock().unlock();
689         }
690     }
691 
692     public Cache getCache() {
693         lock.readLock().lock();
694         try {
695             return this.cache;
696         } finally {
697             lock.readLock().unlock();
698         }
699     }
700 
701     /**
702      * Returns the repository id.
703      */
704     public String getRepositoryId() {
705         return getRepositoryInfo().getId();
706     }
707 
708     // creates
709 
710     public ObjectId createDocument(Map<String, ?> properties, ObjectId folderId, ContentStream contentStream,
711             VersioningState versioningState, List<Policy> policies, List<Ace> addAces, List<Ace> removeAces) {
712         if ((properties == null) || (properties.isEmpty())) {
713             throw new IllegalArgumentException("Properties must not be empty!");
714         }
715 
716         String newId = getBinding().getObjectService().createDocument(getRepositoryId(),
717                 objectFactory.convertProperties(properties, null, CREATE_UPDATABILITY),
718                 (folderId == null ? null : folderId.getId()), objectFactory.convertContentStream(contentStream),
719                 versioningState, objectFactory.convertPolicies(policies), objectFactory.convertAces(addAces),
720                 objectFactory.convertAces(removeAces), null);
721 
722         if (newId == null) {
723             return null;
724         }
725 
726         return createObjectId(newId);
727     }
728 
729     public ObjectId createDocumentFromSource(ObjectId source, Map<String, ?> properties, ObjectId folderId,
730             VersioningState versioningState, List<Policy> policies, List<Ace> addAces, List<Ace> removeAces) {
731         if ((source == null) || (source.getId() == null)) {
732             throw new IllegalArgumentException("Source must be set!");
733         }
734 
735         // get the type of the source document
736         ObjectType type = null;
737         if (source instanceof CmisObject) {
738             type = ((CmisObject) source).getType();
739         } else {
740             CmisObject sourceObj = getObject(source);
741             type = sourceObj.getType();
742         }
743 
744         if (type.getBaseTypeId() != BaseTypeId.CMIS_DOCUMENT) {
745             throw new IllegalArgumentException("Source object must be a document!");
746         }
747 
748         String newId = getBinding().getObjectService().createDocumentFromSource(getRepositoryId(), source.getId(),
749                 objectFactory.convertProperties(properties, type, CREATE_UPDATABILITY),
750                 (folderId == null ? null : folderId.getId()), versioningState, objectFactory.convertPolicies(policies),
751                 objectFactory.convertAces(addAces), objectFactory.convertAces(removeAces), null);
752 
753         if (newId == null) {
754             return null;
755         }
756 
757         return createObjectId(newId);
758     }
759 
760     public ObjectId createFolder(Map<String, ?> properties, ObjectId folderId, List<Policy> policies,
761             List<Ace> addAces, List<Ace> removeAces) {
762         if ((folderId == null) || (folderId.getId() == null)) {
763             throw new IllegalArgumentException("Folder Id must be set!");
764         }
765         if ((properties == null) || (properties.isEmpty())) {
766             throw new IllegalArgumentException("Properties must not be empty!");
767         }
768 
769         String newId = getBinding().getObjectService().createFolder(getRepositoryId(),
770                 objectFactory.convertProperties(properties, null, CREATE_UPDATABILITY), folderId.getId(),
771                 objectFactory.convertPolicies(policies), objectFactory.convertAces(addAces),
772                 objectFactory.convertAces(removeAces), null);
773 
774         if (newId == null) {
775             return null;
776         }
777 
778         return createObjectId(newId);
779     }
780 
781     public ObjectId createPolicy(Map<String, ?> properties, ObjectId folderId, List<Policy> policies,
782             List<Ace> addAces, List<Ace> removeAces) {
783         if ((properties == null) || (properties.isEmpty())) {
784             throw new IllegalArgumentException("Properties must not be empty!");
785         }
786 
787         String newId = getBinding().getObjectService().createPolicy(getRepositoryId(),
788                 objectFactory.convertProperties(properties, null, CREATE_UPDATABILITY),
789                 (folderId == null ? null : folderId.getId()), objectFactory.convertPolicies(policies),
790                 objectFactory.convertAces(addAces), objectFactory.convertAces(removeAces), null);
791 
792         if (newId == null) {
793             return null;
794         }
795 
796         return createObjectId(newId);
797     }
798 
799     public ObjectId createRelationship(Map<String, ?> properties, List<Policy> policies, List<Ace> addAces,
800             List<Ace> removeAces) {
801         if ((properties == null) || (properties.isEmpty())) {
802             throw new IllegalArgumentException("Properties must not be empty!");
803         }
804 
805         String newId = getBinding().getObjectService().createRelationship(getRepositoryId(),
806                 objectFactory.convertProperties(properties, null, CREATE_UPDATABILITY),
807                 objectFactory.convertPolicies(policies), objectFactory.convertAces(addAces),
808                 objectFactory.convertAces(removeAces), null);
809 
810         if (newId == null) {
811             return null;
812         }
813 
814         return createObjectId(newId);
815     }
816 
817     public ObjectId createDocument(Map<String, ?> properties, ObjectId folderId, ContentStream contentStream,
818             VersioningState versioningState) {
819         return this.createDocument(properties, folderId, contentStream, versioningState, null, null, null);
820     }
821 
822     public ObjectId createDocumentFromSource(ObjectId source, Map<String, ?> properties, ObjectId folderId,
823             VersioningState versioningState) {
824         return this.createDocumentFromSource(source, properties, folderId, versioningState, null, null, null);
825     }
826 
827     public ObjectId createFolder(Map<String, ?> properties, ObjectId folderId) {
828         return this.createFolder(properties, folderId, null, null, null);
829     }
830 
831     public ObjectId createPolicy(Map<String, ?> properties, ObjectId folderId) {
832         return this.createPolicy(properties, folderId, null, null, null);
833     }
834 
835     public ObjectId createRelationship(Map<String, ?> properties) {
836         return this.createRelationship(properties, null, null, null);
837     }
838 
839     public ItemIterable<Relationship> getRelationships(ObjectId objectId, final boolean includeSubRelationshipTypes,
840             final RelationshipDirection relationshipDirection, ObjectType type, OperationContext context) {
841         if ((objectId == null) || (objectId.getId() == null)) {
842             throw new IllegalArgumentException("Invalid object id!");
843         }
844         if (context == null) {
845             throw new IllegalArgumentException("Operation context must be set!");
846         }
847 
848         final String id = objectId.getId();
849         final String typeId = (type == null ? null : type.getId());
850         final RelationshipService relationshipService = getBinding().getRelationshipService();
851         final OperationContext ctxt = new OperationContextImpl(context);
852 
853         return new CollectionIterable<Relationship>(new AbstractPageFetcher<Relationship>(ctxt.getMaxItemsPerPage()) {
854 
855             @Override
856             protected AbstractPageFetcher.Page<Relationship> fetchPage(long skipCount) {
857 
858                 // fetch the relationships
859                 ObjectList relList = relationshipService.getObjectRelationships(getRepositoryId(), id,
860                         includeSubRelationshipTypes, relationshipDirection, typeId, ctxt.getFilterString(),
861                         ctxt.isIncludeAllowableActions(), BigInteger.valueOf(this.maxNumItems),
862                         BigInteger.valueOf(skipCount), null);
863 
864                 // convert relationship objects
865                 List<Relationship> page = new ArrayList<Relationship>();
866                 if (relList.getObjects() != null) {
867                     for (ObjectData rod : relList.getObjects()) {
868                         CmisObject relationship = getObject(createObjectId(rod.getId()), ctxt);
869                         if (!(relationship instanceof Relationship)) {
870                             throw new CmisRuntimeException("Repository returned an object that is not a relationship!");
871                         }
872 
873                         page.add((Relationship) relationship);
874                     }
875                 }
876 
877                 return new AbstractPageFetcher.Page<Relationship>(page, relList.getNumItems(), relList.hasMoreItems());
878             }
879         });
880     }
881 
882     public Acl getAcl(ObjectId objectId, boolean onlyBasicPermissions) {
883         if ((objectId == null) || (objectId.getId() == null)) {
884             throw new IllegalArgumentException("Invalid object id!");
885         }
886 
887         String id = objectId.getId();
888 
889         return getBinding().getAclService().getAcl(getRepositoryId(), id, onlyBasicPermissions, null);
890     }
891 
892     public Acl applyAcl(ObjectId objectId, List<Ace> addAces, List<Ace> removeAces, AclPropagation aclPropagation) {
893         if ((objectId == null) || (objectId.getId() == null)) {
894             throw new IllegalArgumentException("Invalid object id!");
895         }
896 
897         ObjectFactory of = getObjectFactory();
898 
899         return getBinding().getAclService().applyAcl(getRepositoryId(), objectId.getId(), of.convertAces(addAces),
900                 of.convertAces(removeAces), aclPropagation, null);
901     }
902 
903     public void applyPolicy(ObjectId objectId, ObjectId... policyIds) {
904         if ((objectId == null) || (objectId.getId() == null)) {
905             throw new IllegalArgumentException("Invalid object id!");
906         }
907 
908         if ((policyIds == null) || (policyIds.length == 0)) {
909             throw new IllegalArgumentException("No Policies provided!");
910         }
911 
912         String[] ids = new String[policyIds.length];
913         for (int i = 0; i < policyIds.length; i++) {
914             if ((policyIds[i] == null) || (policyIds[i].getId() == null)) {
915                 throw new IllegalArgumentException("A Policy Id is not set!");
916             }
917 
918             ids[i] = policyIds[i].getId();
919         }
920 
921         for (String id : ids) {
922             getBinding().getPolicyService().applyPolicy(getRepositoryId(), id, objectId.getId(), null);
923         }
924     }
925 
926     public void removePolicy(ObjectId objectId, ObjectId... policyIds) {
927         if ((objectId == null) || (objectId.getId() == null)) {
928             throw new IllegalArgumentException("Invalid object id!");
929         }
930 
931         if ((policyIds == null) || (policyIds.length == 0)) {
932             throw new IllegalArgumentException("No Policies provided!");
933         }
934 
935         String[] ids = new String[policyIds.length];
936         for (int i = 0; i < policyIds.length; i++) {
937             if ((policyIds[i] == null) || (policyIds[i].getId() == null)) {
938                 throw new IllegalArgumentException("A Policy Id is not set!");
939             }
940 
941             ids[i] = policyIds[i].getId();
942         }
943 
944         for (String id : ids) {
945             getBinding().getPolicyService().removePolicy(getRepositoryId(), id, objectId.getId(), null);
946         }
947     }
948 }