This project has retired. For details please refer to its Attic page.
AbstractCmisService 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.commons.impl.server;
20  
21  import java.math.BigInteger;
22  import java.util.ArrayList;
23  import java.util.GregorianCalendar;
24  import java.util.HashMap;
25  import java.util.List;
26  import java.util.Map;
27  
28  import org.apache.chemistry.opencmis.commons.PropertyIds;
29  import org.apache.chemistry.opencmis.commons.data.Acl;
30  import org.apache.chemistry.opencmis.commons.data.AllowableActions;
31  import org.apache.chemistry.opencmis.commons.data.ContentStream;
32  import org.apache.chemistry.opencmis.commons.data.ExtensionsData;
33  import org.apache.chemistry.opencmis.commons.data.FailedToDeleteData;
34  import org.apache.chemistry.opencmis.commons.data.ObjectData;
35  import org.apache.chemistry.opencmis.commons.data.ObjectInFolderContainer;
36  import org.apache.chemistry.opencmis.commons.data.ObjectInFolderList;
37  import org.apache.chemistry.opencmis.commons.data.ObjectList;
38  import org.apache.chemistry.opencmis.commons.data.ObjectParentData;
39  import org.apache.chemistry.opencmis.commons.data.Properties;
40  import org.apache.chemistry.opencmis.commons.data.PropertyBoolean;
41  import org.apache.chemistry.opencmis.commons.data.PropertyData;
42  import org.apache.chemistry.opencmis.commons.data.PropertyDateTime;
43  import org.apache.chemistry.opencmis.commons.data.PropertyId;
44  import org.apache.chemistry.opencmis.commons.data.PropertyInteger;
45  import org.apache.chemistry.opencmis.commons.data.PropertyString;
46  import org.apache.chemistry.opencmis.commons.data.RenditionData;
47  import org.apache.chemistry.opencmis.commons.data.RepositoryCapabilities;
48  import org.apache.chemistry.opencmis.commons.data.RepositoryInfo;
49  import org.apache.chemistry.opencmis.commons.definitions.TypeDefinition;
50  import org.apache.chemistry.opencmis.commons.definitions.TypeDefinitionContainer;
51  import org.apache.chemistry.opencmis.commons.definitions.TypeDefinitionList;
52  import org.apache.chemistry.opencmis.commons.enums.AclPropagation;
53  import org.apache.chemistry.opencmis.commons.enums.BaseTypeId;
54  import org.apache.chemistry.opencmis.commons.enums.CapabilityAcl;
55  import org.apache.chemistry.opencmis.commons.enums.IncludeRelationships;
56  import org.apache.chemistry.opencmis.commons.enums.RelationshipDirection;
57  import org.apache.chemistry.opencmis.commons.enums.UnfileObject;
58  import org.apache.chemistry.opencmis.commons.enums.VersioningState;
59  import org.apache.chemistry.opencmis.commons.exceptions.CmisInvalidArgumentException;
60  import org.apache.chemistry.opencmis.commons.exceptions.CmisNotSupportedException;
61  import org.apache.chemistry.opencmis.commons.exceptions.CmisObjectNotFoundException;
62  import org.apache.chemistry.opencmis.commons.exceptions.CmisRuntimeException;
63  import org.apache.chemistry.opencmis.commons.server.CmisService;
64  import org.apache.chemistry.opencmis.commons.server.ObjectInfo;
65  import org.apache.chemistry.opencmis.commons.server.ObjectInfoHandler;
66  import org.apache.chemistry.opencmis.commons.server.RenditionInfo;
67  import org.apache.chemistry.opencmis.commons.spi.Holder;
68  
69  public abstract class AbstractCmisService implements CmisService, ObjectInfoHandler {
70  
71      private Map<String, ObjectInfo> objectInfoMap;
72      private boolean addObjectInfos = true;
73  
74      // --- repository service ---
75  
76      /**
77       * {@inheritDoc}
78       * 
79       * <p>
80       * <b>Implementation Hints:</b>
81       * <ul>
82       * <li>Bindings: AtomPub, Web Services, Local</li>
83       * <li>Implementation is required. Convenience implementation is present.</li>
84       * </ul>
85       */
86      public RepositoryInfo getRepositoryInfo(String repositoryId, ExtensionsData extension) {
87          RepositoryInfo result = null;
88  
89          List<RepositoryInfo> repositories = getRepositoryInfos(extension);
90          if (repositories != null) {
91              for (RepositoryInfo ri : repositories) {
92                  if (ri.getId().equals(repositoryId)) {
93                      result = ri;
94                      break;
95                  }
96              }
97          }
98  
99          if (result == null) {
100             throw new CmisObjectNotFoundException("Repository '" + repositoryId + "' does not exist!");
101         }
102 
103         return result;
104     }
105 
106     /**
107      * {@inheritDoc}
108      * 
109      * <p>
110      * <b>Implementation Hints:</b>
111      * <ul>
112      * <li>Bindings: AtomPub, Web Services, Local</li>
113      * <li>Implementation is required.</li>
114      * </ul>
115      */
116     public abstract List<RepositoryInfo> getRepositoryInfos(ExtensionsData extension);
117 
118     /**
119      * {@inheritDoc}
120      * 
121      * <p>
122      * <b>Implementation Hints:</b>
123      * <ul>
124      * <li>Bindings: AtomPub, Web Services, Local</li>
125      * <li>Implementation is required.</li>
126      * </ul>
127      */
128     public abstract TypeDefinitionList getTypeChildren(String repositoryId, String typeId,
129             Boolean includePropertyDefinitions, BigInteger maxItems, BigInteger skipCount, ExtensionsData extension);
130 
131     /**
132      * {@inheritDoc}
133      * 
134      * <p>
135      * <b>Implementation Hints:</b>
136      * <ul>
137      * <li>Bindings: AtomPub, Web Services, Local</li>
138      * <li>Implementation is optional.</li>
139      * </ul>
140      */
141     public List<TypeDefinitionContainer> getTypeDescendants(String repositoryId, String typeId, BigInteger depth,
142             Boolean includePropertyDefinitions, ExtensionsData extension) {
143         throw new CmisNotSupportedException("Not supported!");
144     }
145 
146     /**
147      * {@inheritDoc}
148      * 
149      * <p>
150      * <b>Implementation Hints:</b>
151      * <ul>
152      * <li>Bindings: AtomPub, Web Services, Local</li>
153      * <li>Implementation is required.</li>
154      * </ul>
155      */
156     public abstract TypeDefinition getTypeDefinition(String repositoryId, String typeId, ExtensionsData extension);
157 
158     // --- navigation service ---
159 
160     /**
161      * {@inheritDoc}
162      * 
163      * <p>
164      * <b>Implementation Hints:</b>
165      * <ul>
166      * <li>Bindings: AtomPub, Web Services, Local</li>
167      * <li>Implementation is required.</li>
168      * <li>Object infos should contain the folder and all returned children.</li>
169      * </ul>
170      */
171     public abstract ObjectInFolderList getChildren(String repositoryId, String folderId, String filter, String orderBy,
172             Boolean includeAllowableActions, IncludeRelationships includeRelationships, String renditionFilter,
173             Boolean includePathSegment, BigInteger maxItems, BigInteger skipCount, ExtensionsData extension);
174 
175     /**
176      * {@inheritDoc}
177      * 
178      * <p>
179      * <b>Implementation Hints:</b>
180      * <ul>
181      * <li>Bindings: AtomPub, Web Services, Local</li>
182      * <li>Implementation is optional.</li>
183      * <li>Object infos should contain the folder and all returned descendants.</li>
184      * </ul>
185      */
186     public List<ObjectInFolderContainer> getDescendants(String repositoryId, String folderId, BigInteger depth,
187             String filter, Boolean includeAllowableActions, IncludeRelationships includeRelationships,
188             String renditionFilter, Boolean includePathSegment, ExtensionsData extension) {
189         throw new CmisNotSupportedException("Not supported!");
190     }
191 
192     /**
193      * {@inheritDoc}
194      * 
195      * <p>
196      * <b>Implementation Hints:</b>
197      * <ul>
198      * <li>Bindings: AtomPub, Web Services, Local</li>
199      * <li>Implementation is optional.</li>
200      * <li>Object infos should contain the folder and all returned descendants.</li>
201      * </ul>
202      */
203     public List<ObjectInFolderContainer> getFolderTree(String repositoryId, String folderId, BigInteger depth,
204             String filter, Boolean includeAllowableActions, IncludeRelationships includeRelationships,
205             String renditionFilter, Boolean includePathSegment, ExtensionsData extension) {
206         throw new CmisNotSupportedException("Not supported!");
207     }
208 
209     /**
210      * {@inheritDoc}
211      * 
212      * <p>
213      * <b>Implementation Hints:</b>
214      * <ul>
215      * <li>Bindings: AtomPub, Web Services, Local</li>
216      * <li>Implementation is required.</li>
217      * <li>Object infos should contain the object and all returned parents.</li>
218      * </ul>
219      */
220     public abstract List<ObjectParentData> getObjectParents(String repositoryId, String objectId, String filter,
221             Boolean includeAllowableActions, IncludeRelationships includeRelationships, String renditionFilter,
222             Boolean includeRelativePathSegment, ExtensionsData extension);
223 
224     /**
225      * {@inheritDoc}
226      * 
227      * <p>
228      * <b>Implementation Hints:</b>
229      * <ul>
230      * <li>Bindings: AtomPub, Web Services, Local</li>
231      * <li>Implementation is optional.</li>
232      * <li>Object infos should contain the returned parent folder.</li>
233      * </ul>
234      */
235     public ObjectData getFolderParent(String repositoryId, String folderId, String filter, ExtensionsData extension) {
236         throw new CmisNotSupportedException("Not supported!");
237     }
238 
239     /**
240      * {@inheritDoc}
241      * 
242      * <p>
243      * <b>Implementation Hints:</b>
244      * <ul>
245      * <li>Bindings: AtomPub, Web Services, Local</li>
246      * <li>Implementation is optional.</li>
247      * <li>Object infos should contain the folder and the returned objects.</li>
248      * </ul>
249      */
250     public ObjectList getCheckedOutDocs(String repositoryId, String folderId, String filter, String orderBy,
251             Boolean includeAllowableActions, IncludeRelationships includeRelationships, String renditionFilter,
252             BigInteger maxItems, BigInteger skipCount, ExtensionsData extension) {
253         throw new CmisNotSupportedException("Not supported!");
254     }
255 
256     // --- object service ---
257 
258     /**
259      * {@inheritDoc}
260      * 
261      * <p>
262      * <b>Implementation Hints:</b>
263      * <ul>
264      * <li>Bindings: AtomPub</li>
265      * <li>Implementation is optional. Convenience implementation is present.</li>
266      * <li>Object infos should contain the newly created object.</li>
267      * </ul>
268      */
269     public String create(String repositoryId, Properties properties, String folderId, ContentStream contentStream,
270             VersioningState versioningState, List<String> policies, ExtensionsData extension) {
271         // check properties
272         if (properties == null || properties.getProperties() == null) {
273             throw new CmisInvalidArgumentException("Properties must be set!");
274         }
275 
276         // check object type id
277         PropertyData<?> obbjectTypeIdProperty = properties.getProperties().get(PropertyIds.OBJECT_TYPE_ID);
278         if (obbjectTypeIdProperty == null || !(obbjectTypeIdProperty.getFirstValue() instanceof String)) {
279             throw new CmisInvalidArgumentException("Property '" + PropertyIds.OBJECT_TYPE_ID + "' must be set!");
280         }
281 
282         // get the type
283         String objectTypeId = obbjectTypeIdProperty.getFirstValue().toString();
284         TypeDefinition type = getTypeDefinition(repositoryId, objectTypeId, null);
285 
286         // create object
287         String newId = null;
288         switch (type.getBaseTypeId()) {
289         case CMIS_DOCUMENT:
290             newId = createDocument(repositoryId, properties, folderId, contentStream, versioningState, policies, null,
291                     null, extension);
292             break;
293         case CMIS_FOLDER:
294             newId = createFolder(repositoryId, properties, folderId, policies, null, null, extension);
295             break;
296         case CMIS_POLICY:
297             newId = createPolicy(repositoryId, properties, folderId, policies, null, null, extension);
298             break;
299         }
300 
301         // check new object id
302         if (newId == null) {
303             throw new CmisRuntimeException("Creation failed!");
304         }
305 
306         // return the new object id
307         return newId;
308     }
309 
310     /**
311      * {@inheritDoc}
312      * 
313      * <p>
314      * <b>Implementation Hints:</b>
315      * <ul>
316      * <li>Bindings: Web Services, Local</li>
317      * <li>Implementation is optional.</li>
318      * </ul>
319      */
320     public String createDocument(String repositoryId, Properties properties, String folderId,
321             ContentStream contentStream, VersioningState versioningState, List<String> policies, Acl addAces,
322             Acl removeAces, ExtensionsData extension) {
323         throw new CmisNotSupportedException("Not supported!");
324     }
325 
326     /**
327      * {@inheritDoc}
328      * 
329      * <p>
330      * <b>Implementation Hints:</b>
331      * <ul>
332      * <li>Bindings: Web Services, Local</li>
333      * <li>Implementation is optional.</li>
334      * </ul>
335      */
336     public String createDocumentFromSource(String repositoryId, String sourceId, Properties properties,
337             String folderId, VersioningState versioningState, List<String> policies, Acl addAces, Acl removeAces,
338             ExtensionsData extension) {
339         throw new CmisNotSupportedException("Not supported!");
340     }
341 
342     /**
343      * {@inheritDoc}
344      * 
345      * <p>
346      * <b>Implementation Hints:</b>
347      * <ul>
348      * <li>Bindings: Web Services, Local</li>
349      * <li>Implementation is optional.</li>
350      * </ul>
351      */
352     public String createFolder(String repositoryId, Properties properties, String folderId, List<String> policies,
353             Acl addAces, Acl removeAces, ExtensionsData extension) {
354         throw new CmisNotSupportedException("Not supported!");
355     }
356 
357     /**
358      * {@inheritDoc}
359      * 
360      * <p>
361      * <b>Implementation Hints:</b>
362      * <ul>
363      * <li>Bindings: AtomPub, Web Services, Local</li>
364      * <li>Implementation is optional.</li>
365      * <li>Object infos should contain the newly created object.</li>
366      * </ul>
367      */
368     public String createRelationship(String repositoryId, Properties properties, List<String> policies, Acl addAces,
369             Acl removeAces, ExtensionsData extension) {
370         throw new CmisNotSupportedException("Not supported!");
371     }
372 
373     /**
374      * {@inheritDoc}
375      * 
376      * <p>
377      * <b>Implementation Hints:</b>
378      * <ul>
379      * <li>Bindings: Web Services, Local</li>
380      * <li>Implementation is optional.</li>
381      * </ul>
382      */
383     public String createPolicy(String repositoryId, Properties properties, String folderId, List<String> policies,
384             Acl addAces, Acl removeAces, ExtensionsData extension) {
385         throw new CmisNotSupportedException("Not supported!");
386     }
387 
388     /**
389      * {@inheritDoc}
390      * 
391      * <p>
392      * <b>Implementation Hints:</b>
393      * <ul>
394      * <li>Bindings: AtomPub, Web Services, Local</li>
395      * <li>Implementation is optional.</li>
396      * </ul>
397      */
398     public AllowableActions getAllowableActions(String repositoryId, String objectId, ExtensionsData extension) {
399         throw new CmisNotSupportedException("Not supported!");
400     }
401 
402     /**
403      * {@inheritDoc}
404      * 
405      * <p>
406      * <b>Implementation Hints:</b>
407      * <ul>
408      * <li>Bindings: AtomPub, Web Services, Local</li>
409      * <li>Implementation is required.</li>
410      * <li>Object infos should contain the returned object.</li>
411      * </ul>
412      */
413     public abstract ObjectData getObject(String repositoryId, String objectId, String filter,
414             Boolean includeAllowableActions, IncludeRelationships includeRelationships, String renditionFilter,
415             Boolean includePolicyIds, Boolean includeAcl, ExtensionsData extension);
416 
417     /**
418      * {@inheritDoc}
419      * 
420      * <p>
421      * <b>Implementation Hints:</b>
422      * <ul>
423      * <li>Bindings: Web Services, Local</li>
424      * <li>Implementation is optional.</li>
425      * </ul>
426      */
427     public Properties getProperties(String repositoryId, String objectId, String filter, ExtensionsData extension) {
428         throw new CmisNotSupportedException("Not supported!");
429     }
430 
431     /**
432      * {@inheritDoc}
433      * 
434      * <p>
435      * <b>Implementation Hints:</b>
436      * <ul>
437      * <li>Bindings: Web Services, Local</li>
438      * <li>Implementation is optional.</li>
439      * </ul>
440      */
441     public List<RenditionData> getRenditions(String repositoryId, String objectId, String renditionFilter,
442             BigInteger maxItems, BigInteger skipCount, ExtensionsData extension) {
443         throw new CmisNotSupportedException("Not supported!");
444     }
445 
446     /**
447      * {@inheritDoc}
448      * 
449      * <p>
450      * <b>Implementation Hints:</b>
451      * <ul>
452      * <li>Bindings: AtomPub, Web Services, Local</li>
453      * <li>Implementation is optional.</li>
454      * <li>Object infos should contain the returned object.</li>
455      * </ul>
456      */
457     public ObjectData getObjectByPath(String repositoryId, String path, String filter, Boolean includeAllowableActions,
458             IncludeRelationships includeRelationships, String renditionFilter, Boolean includePolicyIds,
459             Boolean includeAcl, ExtensionsData extension) {
460         throw new CmisNotSupportedException("Not supported!");
461     }
462 
463     /**
464      * {@inheritDoc}
465      * 
466      * <p>
467      * <b>Implementation Hints:</b>
468      * <ul>
469      * <li>Bindings: AtomPub, Web Services, Local</li>
470      * <li>Implementation is optional.</li>
471      * </ul>
472      */
473     public ContentStream getContentStream(String repositoryId, String objectId, String streamId, BigInteger offset,
474             BigInteger length, ExtensionsData extension) {
475         throw new CmisNotSupportedException("Not supported!");
476     }
477 
478     /**
479      * {@inheritDoc}
480      * 
481      * <p>
482      * <b>Implementation Hints:</b>
483      * <ul>
484      * <li>Bindings: AtomPub, Web Services, Local</li>
485      * <li>Implementation is optional.</li>
486      * <li>Object infos should contain the updated object.</li>
487      * </ul>
488      */
489     public void updateProperties(String repositoryId, Holder<String> objectId, Holder<String> changeToken,
490             Properties properties, ExtensionsData extension) {
491         throw new CmisNotSupportedException("Not supported!");
492     }
493 
494     /**
495      * {@inheritDoc}
496      * 
497      * <p>
498      * <b>Implementation Hints:</b>
499      * <ul>
500      * <li>Bindings: AtomPub, Web Services, Local</li>
501      * <li>Implementation is optional.</li>
502      * <li>Object infos should contain the moved object.</li>
503      * </ul>
504      */
505     public void moveObject(String repositoryId, Holder<String> objectId, String targetFolderId, String sourceFolderId,
506             ExtensionsData extension) {
507         throw new CmisNotSupportedException("Not supported!");
508     }
509 
510     /**
511      * {@inheritDoc}
512      * 
513      * <p>
514      * <b>Implementation Hints:</b>
515      * <ul>
516      * <li>Bindings: Web Services, Local</li>
517      * <li>Implementation is optional. Convenience implementation is present.</li>
518      * </ul>
519      */
520     public void deleteObject(String repositoryId, String objectId, Boolean allVersions, ExtensionsData extension) {
521         deleteObjectOrCancelCheckOut(repositoryId, objectId, allVersions, extension);
522     }
523 
524     /**
525      * {@inheritDoc}
526      * 
527      * <p>
528      * <b>Implementation Hints:</b>
529      * <ul>
530      * <li>Bindings: AtomPub</li>
531      * <li>Implementation is optional.</li>
532      * </ul>
533      */
534     public void deleteObjectOrCancelCheckOut(String repositoryId, String objectId, Boolean allVersions,
535             ExtensionsData extension) {
536         throw new CmisNotSupportedException("Not supported!");
537     }
538 
539     /**
540      * {@inheritDoc}
541      * 
542      * <p>
543      * <b>Implementation Hints:</b>
544      * <ul>
545      * <li>Bindings: AtomPub, Web Services, Local</li>
546      * <li>Implementation is optional.</li>
547      * </ul>
548      */
549     public FailedToDeleteData deleteTree(String repositoryId, String folderId, Boolean allVersions,
550             UnfileObject unfileObjects, Boolean continueOnFailure, ExtensionsData extension) {
551         throw new CmisNotSupportedException("Not supported!");
552     }
553 
554     /**
555      * {@inheritDoc}
556      * 
557      * <p>
558      * <b>Implementation Hints:</b>
559      * <ul>
560      * <li>Bindings: AtomPub, Web Services, Local</li>
561      * <li>Implementation is optional.</li>
562      * </ul>
563      */
564     public void setContentStream(String repositoryId, Holder<String> objectId, Boolean overwriteFlag,
565             Holder<String> changeToken, ContentStream contentStream, ExtensionsData extension) {
566         throw new CmisNotSupportedException("Not supported!");
567     }
568 
569     /**
570      * {@inheritDoc}
571      * 
572      * <p>
573      * <b>Implementation Hints:</b>
574      * <ul>
575      * <li>Bindings: AtomPub, Web Services, Local</li>
576      * <li>Implementation is optional.</li>
577      * </ul>
578      */
579     public void deleteContentStream(String repositoryId, Holder<String> objectId, Holder<String> changeToken,
580             ExtensionsData extension) {
581         throw new CmisNotSupportedException("Not supported!");
582     }
583 
584     // --- versioning service ---
585 
586     /**
587      * {@inheritDoc}
588      * 
589      * <p>
590      * <b>Implementation Hints:</b>
591      * <ul>
592      * <li>Bindings: AtomPub, Web Services, Local</li>
593      * <li>Implementation is optional.</li>
594      * <li>Object infos should contain the checked out object.</li>
595      * </ul>
596      */
597     public void checkOut(String repositoryId, Holder<String> objectId, ExtensionsData extension,
598             Holder<Boolean> contentCopied) {
599         throw new CmisNotSupportedException("Not supported!");
600     }
601 
602     /**
603      * {@inheritDoc}
604      * 
605      * <p>
606      * <b>Implementation Hints:</b>
607      * <ul>
608      * <li>Bindings: AtomPub, Web Services, Local</li>
609      * <li>Implementation is optional.</li>
610      * </ul>
611      */
612     public void cancelCheckOut(String repositoryId, String objectId, ExtensionsData extension) {
613         throw new CmisNotSupportedException("Not supported!");
614     }
615 
616     /**
617      * {@inheritDoc}
618      * 
619      * <p>
620      * <b>Implementation Hints:</b>
621      * <ul>
622      * <li>Bindings: AtomPub, Web Services, Local</li>
623      * <li>Implementation is optional.</li>
624      * <li>Object infos should contain the checked in object.</li>
625      * </ul>
626      */
627     public void checkIn(String repositoryId, Holder<String> objectId, Boolean major, Properties properties,
628             ContentStream contentStream, String checkinComment, List<String> policies, Acl addAces, Acl removeAces,
629             ExtensionsData extension) {
630         throw new CmisNotSupportedException("Not supported!");
631     }
632 
633     /**
634      * {@inheritDoc}
635      * 
636      * <p>
637      * <b>Implementation Hints:</b>
638      * <ul>
639      * <li>Bindings: AtomPub, Web Services, Local</li>
640      * <li>Implementation is optional.</li>
641      * <li>Object infos should contain the returned object.</li>
642      * </ul>
643      */
644     public ObjectData getObjectOfLatestVersion(String repositoryId, String objectId, String versionSeriesId,
645             Boolean major, String filter, Boolean includeAllowableActions, IncludeRelationships includeRelationships,
646             String renditionFilter, Boolean includePolicyIds, Boolean includeAcl, ExtensionsData extension) {
647         throw new CmisNotSupportedException("Not supported!");
648     }
649 
650     /**
651      * {@inheritDoc}
652      * 
653      * <p>
654      * <b>Implementation Hints:</b>
655      * <ul>
656      * <li>Bindings: Web Services, Local</li>
657      * <li>Implementation is optional.</li>
658      * </ul>
659      */
660     public Properties getPropertiesOfLatestVersion(String repositoryId, String objectId, String versionSeriesId,
661             Boolean major, String filter, ExtensionsData extension) {
662         throw new CmisNotSupportedException("Not supported!");
663     }
664 
665     /**
666      * {@inheritDoc}
667      * 
668      * <p>
669      * <b>Implementation Hints:</b>
670      * <ul>
671      * <li>Bindings: AtomPub, Web Services, Local</li>
672      * <li>Implementation is optional.</li>
673      * <li>Object infos should contain the returned objects.</li>
674      * </ul>
675      */
676     public List<ObjectData> getAllVersions(String repositoryId, String objectId, String versionSeriesId, String filter,
677             Boolean includeAllowableActions, ExtensionsData extension) {
678         throw new CmisNotSupportedException("Not supported!");
679     }
680 
681     // --- discovery service ---
682 
683     /**
684      * {@inheritDoc}
685      * 
686      * <p>
687      * <b>Implementation Hints:</b>
688      * <ul>
689      * <li>Bindings: AtomPub, Web Services, Local</li>
690      * <li>Implementation is optional.</li>
691      * <li>Object infos should contain the returned objects.</li>
692      * </ul>
693      */
694     public ObjectList getContentChanges(String repositoryId, Holder<String> changeLogToken, Boolean includeProperties,
695             String filter, Boolean includePolicyIds, Boolean includeAcl, BigInteger maxItems, ExtensionsData extension) {
696         throw new CmisNotSupportedException("Not supported!");
697     }
698 
699     /**
700      * {@inheritDoc}
701      * 
702      * <p>
703      * <b>Implementation Hints:</b>
704      * <ul>
705      * <li>Bindings: AtomPub, Web Services, Local</li>
706      * <li>Implementation is optional.</li>
707      * </ul>
708      */
709     public ObjectList query(String repositoryId, String statement, Boolean searchAllVersions,
710             Boolean includeAllowableActions, IncludeRelationships includeRelationships, String renditionFilter,
711             BigInteger maxItems, BigInteger skipCount, ExtensionsData extension) {
712         throw new CmisNotSupportedException("Not supported!");
713     }
714 
715     // --- multi filing service ---
716 
717     /**
718      * {@inheritDoc}
719      * 
720      * <p>
721      * <b>Implementation Hints:</b>
722      * <ul>
723      * <li>Bindings: AtomPub, Web Services, Local</li>
724      * <li>Implementation is optional.</li>
725      * <li>Object infos should contain the added object.</li>
726      * </ul>
727      */
728     public void addObjectToFolder(String repositoryId, String objectId, String folderId, Boolean allVersions,
729             ExtensionsData extension) {
730         throw new CmisNotSupportedException("Not supported!");
731     }
732 
733     /**
734      * {@inheritDoc}
735      * 
736      * <p>
737      * <b>Implementation Hints:</b>
738      * <ul>
739      * <li>Bindings: AtomPub, Web Services, Local</li>
740      * <li>Implementation is optional.</li>
741      * <li>Object infos should contain the removed object.</li>
742      * </ul>
743      */
744     public void removeObjectFromFolder(String repositoryId, String objectId, String folderId, ExtensionsData extension) {
745         throw new CmisNotSupportedException("Not supported!");
746     }
747 
748     // --- relationship service ---
749 
750     /**
751      * {@inheritDoc}
752      * 
753      * <p>
754      * <b>Implementation Hints:</b>
755      * <ul>
756      * <li>Bindings: AtomPub, Web Services, Local</li>
757      * <li>Implementation is optional.</li>
758      * <li>Object infos should contain the object and the returned relationship
759      * objects.</li>
760      * </ul>
761      */
762     public ObjectList getObjectRelationships(String repositoryId, String objectId, Boolean includeSubRelationshipTypes,
763             RelationshipDirection relationshipDirection, String typeId, String filter, Boolean includeAllowableActions,
764             BigInteger maxItems, BigInteger skipCount, ExtensionsData extension) {
765         throw new CmisNotSupportedException("Not supported!");
766     }
767 
768     // --- ACL service ---
769 
770     /**
771      * {@inheritDoc}
772      * 
773      * <p>
774      * <b>Implementation Hints:</b>
775      * <ul>
776      * <li>Bindings: Web Services, Local</li>
777      * <li>Implementation is optional.</li>
778      * </ul>
779      */
780     public Acl applyAcl(String repositoryId, String objectId, Acl addAces, Acl removeAces,
781             AclPropagation aclPropagation, ExtensionsData extension) {
782         throw new CmisNotSupportedException("Not supported!");
783     }
784 
785     /**
786      * {@inheritDoc}
787      * 
788      * <p>
789      * <b>Implementation Hints:</b>
790      * <ul>
791      * <li>Bindings: AtomPub</li>
792      * <li>Implementation is optional.</li>
793      * </ul>
794      */
795     public Acl applyAcl(String repositoryId, String objectId, Acl aces, AclPropagation aclPropagation) {
796         throw new CmisNotSupportedException("Not supported!");
797     }
798 
799     /**
800      * {@inheritDoc}
801      * 
802      * <p>
803      * <b>Implementation Hints:</b>
804      * <ul>
805      * <li>Bindings: AtomPub, Web Services, Local</li>
806      * <li>Implementation is optional.</li>
807      * </ul>
808      */
809     public Acl getAcl(String repositoryId, String objectId, Boolean onlyBasicPermissions, ExtensionsData extension) {
810         throw new CmisNotSupportedException("Not supported!");
811     }
812 
813     // --- policy service ---
814 
815     /**
816      * {@inheritDoc}
817      * 
818      * <p>
819      * <b>Implementation Hints:</b>
820      * <ul>
821      * <li>Bindings: AtomPub, Web Services, Local</li>
822      * <li>Implementation is optional.</li>
823      * <li>Object infos should contain the applied policy object.</li>
824      * </ul>
825      */
826     public void applyPolicy(String repositoryId, String policyId, String objectId, ExtensionsData extension) {
827         throw new CmisNotSupportedException("Not supported!");
828     }
829 
830     /**
831      * {@inheritDoc}
832      * 
833      * <p>
834      * <b>Implementation Hints:</b>
835      * <ul>
836      * <li>Bindings: AtomPub, Web Services, Local</li>
837      * <li>Implementation is optional.</li>
838      * <li>Object infos should contain the returned policy objects.</li>
839      * </ul>
840      */
841     public List<ObjectData> getAppliedPolicies(String repositoryId, String objectId, String filter,
842             ExtensionsData extension) {
843         throw new CmisNotSupportedException("Not supported!");
844     }
845 
846     /**
847      * {@inheritDoc}
848      * 
849      * <p>
850      * <b>Implementation Hints:</b>
851      * <ul>
852      * <li>Bindings: AtomPub, Web Services, Local</li>
853      * <li>Implementation is optional.</li>
854      * </ul>
855      */
856     public void removePolicy(String repositoryId, String policyId, String objectId, ExtensionsData extension) {
857         throw new CmisNotSupportedException("Not supported!");
858     }
859 
860     // --- server specific ---
861 
862     /**
863      * Returns the object info map.
864      */
865     private Map<String, ObjectInfo> getObjectInfoMap() {
866         if (objectInfoMap == null) {
867             objectInfoMap = new HashMap<String, ObjectInfo>();
868         }
869 
870         return objectInfoMap;
871     }
872 
873     /**
874      * {@inheritDoc}
875      * 
876      * <p>
877      * <b>Implementation Hints:</b>
878      * <ul>
879      * <li>Bindings: AtomPub</li>
880      * <li>If the object info is not found, the object info will be assembled.
881      * To do that the repository info, the object, the object parent, the object
882      * history and the base type definitions will be fetched. If you want to
883      * change this behavior, override this method.</li>
884      * </ul>
885      */
886     public ObjectInfo getObjectInfo(String repositoryId, String objectId) {
887         Map<String, ObjectInfo> oim = getObjectInfoMap();
888         ObjectInfo info = oim.get(objectId);
889         if (info == null) {
890             // object info has not been found -> create one
891             try {
892                 // switch off object info collection to avoid side effects
893                 addObjectInfos = false;
894 
895                 // get the object and its info
896                 ObjectData object = getObject(repositoryId, objectId, null, Boolean.TRUE, IncludeRelationships.BOTH,
897                         "*", Boolean.TRUE, Boolean.FALSE, null);
898                 info = getObjectInfoIntern(repositoryId, object);
899 
900                 // switch on object info collection
901                 addObjectInfos = true;
902 
903                 // add object info
904                 addObjectInfo(info);
905             } catch (Exception e) {
906                 info = null;
907             } finally {
908                 addObjectInfos = true;
909             }
910         }
911         return info;
912     }
913 
914     /**
915      * Collects the {@link ObjectInfo} about an object.
916      * 
917      * @param repositoryId
918      *            the repository id
919      * @param object
920      *            the object
921      * @return the collected object info
922      */
923     protected ObjectInfo getObjectInfoIntern(String repositoryId, ObjectData object) {
924         // if the object has no properties, stop here
925         if (object.getProperties() == null || object.getProperties().getProperties() == null) {
926             throw new CmisRuntimeException("No properties!");
927         }
928 
929         ObjectInfoImpl info = new ObjectInfoImpl();
930 
931         // get the repository info
932         RepositoryInfo repositoryInfo = getRepositoryInfo(repositoryId, null);
933 
934         // general properties
935         info.setObject(object);
936         info.setId(object.getId());
937         info.setName(getStringProperty(object, PropertyIds.NAME));
938         info.setCreatedBy(getStringProperty(object, PropertyIds.CREATED_BY));
939         info.setCreationDate(getDateTimeProperty(object, PropertyIds.CREATED_BY));
940         info.setLastModificationDate(getDateTimeProperty(object, PropertyIds.LAST_MODIFICATION_DATE));
941         info.setTypeId(getIdProperty(object, PropertyIds.OBJECT_TYPE_ID));
942         info.setBaseType(object.getBaseTypeId());
943 
944         // versioning
945         info.setIsCurrentVersion(object.getBaseTypeId() == BaseTypeId.CMIS_DOCUMENT);
946         info.setWorkingCopyId(null);
947         info.setWorkingCopyOriginalId(null);
948 
949         info.setVersionSeriesId(getIdProperty(object, PropertyIds.VERSION_SERIES_ID));
950         if (info.getVersionSeriesId() != null) {
951             Boolean isLatest = getBooleanProperty(object, PropertyIds.IS_LATEST_VERSION);
952             info.setIsCurrentVersion(isLatest == null ? true : isLatest.booleanValue());
953 
954             Boolean isCheckedOut = getBooleanProperty(object, PropertyIds.IS_VERSION_SERIES_CHECKED_OUT);
955             if (isCheckedOut != null && isCheckedOut.booleanValue()) {
956                 info.setWorkingCopyId(getIdProperty(object, PropertyIds.VERSION_SERIES_CHECKED_OUT_ID));
957 
958                 // get latest version
959                 List<ObjectData> versions = getAllVersions(repositoryId, object.getId(), info.getVersionSeriesId(),
960                         null, Boolean.FALSE, null);
961                 if (versions != null && versions.size() > 0) {
962                     info.setWorkingCopyOriginalId(versions.get(0).getId());
963                 }
964             }
965         }
966 
967         // content
968         String fileName = getStringProperty(object, PropertyIds.CONTENT_STREAM_FILE_NAME);
969         String mimeType = getStringProperty(object, PropertyIds.CONTENT_STREAM_MIME_TYPE);
970         String streamId = getIdProperty(object, PropertyIds.CONTENT_STREAM_ID);
971         BigInteger length = getIntegerProperty(object, PropertyIds.CONTENT_STREAM_LENGTH);
972         boolean hasContent = fileName != null || mimeType != null || streamId != null || length != null;
973         if (hasContent) {
974             info.setHasContent(hasContent);
975             info.setContentType(mimeType);
976             info.setFileName(fileName);
977         } else {
978             info.setHasContent(false);
979             info.setContentType(null);
980             info.setFileName(null);
981         }
982 
983         // parent
984         if (object.getBaseTypeId() == BaseTypeId.CMIS_RELATIONSHIP) {
985             info.setHasParent(false);
986         } else if (object.getBaseTypeId() == BaseTypeId.CMIS_FOLDER) {
987             info.setHasParent(!object.getId().equals(repositoryInfo.getRootFolderId()));
988         } else {
989             try {
990                 List<ObjectParentData> parents = getObjectParents(repositoryId, object.getId(), null, Boolean.FALSE,
991                         IncludeRelationships.NONE, "cmis:none", Boolean.FALSE, null);
992                 info.setHasParent(parents.size() > 0);
993             } catch (CmisInvalidArgumentException e) {
994                 info.setHasParent(false);
995             }
996         }
997 
998         // policies and relationships
999         info.setSupportsRelationships(false);
1000         info.setSupportsPolicies(false);
1001 
1002         TypeDefinitionList baseTypesList = getTypeChildren(repositoryId, null, Boolean.FALSE, BigInteger.valueOf(4),
1003                 BigInteger.ZERO, null);
1004         for (TypeDefinition type : baseTypesList.getList()) {
1005             if (BaseTypeId.CMIS_RELATIONSHIP.value().equals(type.getId())) {
1006                 info.setSupportsRelationships(true);
1007             } else if (BaseTypeId.CMIS_POLICY.value().equals(type.getId())) {
1008                 info.setSupportsPolicies(true);
1009             }
1010         }
1011 
1012         // renditions
1013         info.setRenditionInfos(null);
1014         List<RenditionData> renditions = object.getRenditions();
1015         if (renditions != null && renditions.size() > 0) {
1016             List<RenditionInfo> renditionInfos = new ArrayList<RenditionInfo>();
1017             for (RenditionData rendition : renditions) {
1018                 RenditionInfoImpl renditionInfo = new RenditionInfoImpl();
1019                 renditionInfo.setId(rendition.getStreamId());
1020                 renditionInfo.setKind(rendition.getKind());
1021                 renditionInfo.setContentType(rendition.getMimeType());
1022                 renditionInfo.setTitle(rendition.getTitle());
1023                 renditionInfo.setLength(rendition.getBigLength());
1024                 renditionInfos.add(renditionInfo);
1025             }
1026             info.setRenditionInfos(renditionInfos);
1027         }
1028 
1029         // relationships
1030         info.setRelationshipSourceIds(null);
1031         info.setRelationshipTargetIds(null);
1032         List<ObjectData> relationships = object.getRelationships();
1033         if (relationships != null && relationships.size() > 0) {
1034             List<String> sourceIds = new ArrayList<String>();
1035             List<String> targetIds = new ArrayList<String>();
1036             for (ObjectData relationship : relationships) {
1037                 String sourceId = getIdProperty(relationship, PropertyIds.SOURCE_ID);
1038                 String targetId = getIdProperty(relationship, PropertyIds.TARGET_ID);
1039                 if (object.getId().equals(sourceId)) {
1040                     sourceIds.add(relationship.getId());
1041                 }
1042                 if (object.getId().equals(targetId)) {
1043                     targetIds.add(relationship.getId());
1044                 }
1045             }
1046             if (sourceIds.size() > 0) {
1047                 info.setRelationshipSourceIds(sourceIds);
1048             }
1049             if (targetIds.size() > 0) {
1050                 info.setRelationshipTargetIds(targetIds);
1051             }
1052         }
1053 
1054         // global settings
1055         info.setHasAcl(false);
1056         info.setSupportsDescendants(false);
1057         info.setSupportsFolderTree(false);
1058 
1059         RepositoryCapabilities capabilities = repositoryInfo.getCapabilities();
1060         if (capabilities != null) {
1061             info.setHasAcl(capabilities.getAclCapability() == CapabilityAcl.DISCOVER
1062                     || capabilities.getAclCapability() == CapabilityAcl.MANAGE);
1063             if (object.getBaseTypeId() == BaseTypeId.CMIS_FOLDER) {
1064                 info.setSupportsDescendants(Boolean.TRUE.equals(capabilities.isGetDescendantsSupported()));
1065                 info.setSupportsFolderTree(Boolean.TRUE.equals(capabilities.isGetFolderTreeSupported()));
1066             }
1067         }
1068 
1069         return info;
1070     }
1071 
1072     /**
1073      * Adds an object info.
1074      */
1075     public void addObjectInfo(ObjectInfo objectInfo) {
1076         if (!addObjectInfos) {
1077             return;
1078         }
1079 
1080         if (objectInfo != null && objectInfo.getId() != null) {
1081             getObjectInfoMap().put(objectInfo.getId(), objectInfo);
1082         }
1083     }
1084 
1085     /**
1086      * Clears the object info map.
1087      */
1088     public void clearObjectInfos() {
1089         objectInfoMap = null;
1090     }
1091 
1092     public void close() {
1093         clearObjectInfos();
1094     }
1095 
1096     // --- helpers ---
1097 
1098     protected String getStringProperty(ObjectData object, String name) {
1099         PropertyData<?> property = object.getProperties().getProperties().get(name);
1100         if (property instanceof PropertyString) {
1101             return ((PropertyString) property).getFirstValue();
1102         }
1103         return null;
1104     }
1105 
1106     protected String getIdProperty(ObjectData object, String name) {
1107         PropertyData<?> property = object.getProperties().getProperties().get(name);
1108         if (property instanceof PropertyId) {
1109             return ((PropertyId) property).getFirstValue();
1110         }
1111         return null;
1112     }
1113 
1114     protected GregorianCalendar getDateTimeProperty(ObjectData object, String name) {
1115         PropertyData<?> property = object.getProperties().getProperties().get(name);
1116         if (property instanceof PropertyDateTime) {
1117             return ((PropertyDateTime) property).getFirstValue();
1118         }
1119         return null;
1120     }
1121 
1122     protected Boolean getBooleanProperty(ObjectData object, String name) {
1123         PropertyData<?> property = object.getProperties().getProperties().get(name);
1124         if (property instanceof PropertyBoolean) {
1125             return ((PropertyBoolean) property).getFirstValue();
1126         }
1127         return null;
1128     }
1129 
1130     protected BigInteger getIntegerProperty(ObjectData object, String name) {
1131         PropertyData<?> property = object.getProperties().getProperties().get(name);
1132         if (property instanceof PropertyInteger) {
1133             return ((PropertyInteger) property).getFirstValue();
1134         }
1135         return null;
1136     }
1137 }