This project has retired. For details please refer to its Attic page.
FolderImpl 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.Collections;
24  import java.util.List;
25  import java.util.Map;
26  
27  import org.apache.chemistry.opencmis.client.api.CmisObject;
28  import org.apache.chemistry.opencmis.client.api.Document;
29  import org.apache.chemistry.opencmis.client.api.FileableCmisObject;
30  import org.apache.chemistry.opencmis.client.api.Folder;
31  import org.apache.chemistry.opencmis.client.api.ItemIterable;
32  import org.apache.chemistry.opencmis.client.api.ObjectFactory;
33  import org.apache.chemistry.opencmis.client.api.ObjectId;
34  import org.apache.chemistry.opencmis.client.api.ObjectType;
35  import org.apache.chemistry.opencmis.client.api.OperationContext;
36  import org.apache.chemistry.opencmis.client.api.Policy;
37  import org.apache.chemistry.opencmis.client.api.TransientCmisObject;
38  import org.apache.chemistry.opencmis.client.api.TransientFolder;
39  import org.apache.chemistry.opencmis.client.api.Tree;
40  import org.apache.chemistry.opencmis.client.runtime.util.AbstractPageFetcher;
41  import org.apache.chemistry.opencmis.client.runtime.util.CollectionIterable;
42  import org.apache.chemistry.opencmis.client.runtime.util.TreeImpl;
43  import org.apache.chemistry.opencmis.commons.PropertyIds;
44  import org.apache.chemistry.opencmis.commons.data.Ace;
45  import org.apache.chemistry.opencmis.commons.data.ContentStream;
46  import org.apache.chemistry.opencmis.commons.data.FailedToDeleteData;
47  import org.apache.chemistry.opencmis.commons.data.ObjectData;
48  import org.apache.chemistry.opencmis.commons.data.ObjectInFolderContainer;
49  import org.apache.chemistry.opencmis.commons.data.ObjectInFolderData;
50  import org.apache.chemistry.opencmis.commons.data.ObjectInFolderList;
51  import org.apache.chemistry.opencmis.commons.data.ObjectList;
52  import org.apache.chemistry.opencmis.commons.data.PropertyData;
53  import org.apache.chemistry.opencmis.commons.data.PropertyId;
54  import org.apache.chemistry.opencmis.commons.data.PropertyString;
55  import org.apache.chemistry.opencmis.commons.enums.IncludeRelationships;
56  import org.apache.chemistry.opencmis.commons.enums.UnfileObject;
57  import org.apache.chemistry.opencmis.commons.enums.VersioningState;
58  import org.apache.chemistry.opencmis.commons.exceptions.CmisRuntimeException;
59  import org.apache.chemistry.opencmis.commons.spi.NavigationService;
60  
61  public class FolderImpl extends AbstractFilableCmisObject implements Folder {
62  
63      private static final long serialVersionUID = 1L;
64  
65      /**
66       * Constructor.
67       */
68      public FolderImpl(SessionImpl session, ObjectType objectType, ObjectData objectData, OperationContext context) {
69          initialize(session, objectType, objectData, context);
70      }
71  
72      @Override
73      protected TransientCmisObject createTransientCmisObject() {
74          TransientFolderImpl tf = new TransientFolderImpl();
75          tf.initialize(getSession(), this);
76  
77          return tf;
78      }
79  
80      public TransientFolder getTransientFolder() {
81          return (TransientFolder) getTransientObject();
82      }
83  
84      public Document createDocument(Map<String, ?> properties, ContentStream contentStream,
85              VersioningState versioningState, List<Policy> policies, List<Ace> addAces, List<Ace> removeAces,
86              OperationContext context) {
87  
88          ObjectId newId = getSession().createDocument(properties, this, contentStream, versioningState, policies,
89                  addAces, removeAces);
90  
91          // if no context is provided the object will not be fetched
92          if ((context == null) || (newId == null)) {
93              return null;
94          }
95  
96          // get the new object
97          CmisObject object = getSession().getObject(newId, context);
98          if (!(object instanceof Document)) {
99              throw new CmisRuntimeException("Newly created object is not a document! New id: " + newId);
100         }
101 
102         return (Document) object;
103     }
104 
105     public Document createDocumentFromSource(ObjectId source, Map<String, ?> properties,
106             VersioningState versioningState, List<Policy> policies, List<Ace> addAces, List<Ace> removeAces,
107             OperationContext context) {
108 
109         ObjectId newId = getSession().createDocumentFromSource(source, properties, this, versioningState, policies,
110                 addAces, removeAces);
111 
112         // if no context is provided the object will not be fetched
113         if ((context == null) || (newId == null)) {
114             return null;
115         }
116 
117         // get the new object
118         CmisObject object = getSession().getObject(newId, context);
119         if (!(object instanceof Document)) {
120             throw new CmisRuntimeException("Newly created object is not a document! New id: " + newId);
121         }
122 
123         return (Document) object;
124     }
125 
126     public Folder createFolder(Map<String, ?> properties, List<Policy> policies, List<Ace> addAces,
127             List<Ace> removeAces, OperationContext context) {
128 
129         ObjectId newId = getSession().createFolder(properties, this, policies, addAces, removeAces);
130 
131         // if no context is provided the object will not be fetched
132         if ((context == null) || (newId == null)) {
133             return null;
134         }
135 
136         // get the new object
137         CmisObject object = getSession().getObject(newId, context);
138         if (!(object instanceof Folder)) {
139             throw new CmisRuntimeException("Newly created object is not a folder! New id: " + newId);
140         }
141 
142         return (Folder) object;
143     }
144 
145     public Policy createPolicy(Map<String, ?> properties, List<Policy> policies, List<Ace> addAces,
146             List<Ace> removeAces, OperationContext context) {
147 
148         ObjectId newId = getSession().createPolicy(properties, this, policies, addAces, removeAces);
149 
150         // if no context is provided the object will not be fetched
151         if ((context == null) || (newId == null)) {
152             return null;
153         }
154 
155         // get the new object
156         CmisObject object = getSession().getObject(newId, context);
157         if (!(object instanceof Policy)) {
158             throw new CmisRuntimeException("Newly created object is not a policy! New id: " + newId);
159         }
160 
161         return (Policy) object;
162     }
163 
164     public List<String> deleteTree(boolean allVersions, UnfileObject unfile, boolean continueOnFailure) {
165         String repositoryId = getRepositoryId();
166         String objectId = getObjectId();
167 
168         FailedToDeleteData failed = getBinding().getObjectService().deleteTree(repositoryId, objectId, allVersions,
169                 unfile, continueOnFailure, null);
170 
171         if ((failed == null) || (failed.getIds() == null) || (failed.getIds().isEmpty())) {
172             getSession().removeObjectFromCache(this);
173         }
174 
175         return (failed != null ? failed.getIds() : null);
176     }
177 
178     public String getParentId() {
179         return getPropertyValue(PropertyIds.PARENT_ID);
180     }
181 
182     public List<ObjectType> getAllowedChildObjectTypes() {
183         List<ObjectType> result = new ArrayList<ObjectType>();
184 
185         readLock();
186         try {
187             List<String> otids = getPropertyValue(PropertyIds.ALLOWED_CHILD_OBJECT_TYPE_IDS);
188             if (otids == null) {
189                 return result;
190             }
191 
192             for (String otid : otids) {
193                 result.add(getSession().getTypeDefinition(otid));
194             }
195         } finally {
196             readUnlock();
197         }
198 
199         return result;
200     }
201 
202     public ItemIterable<Document> getCheckedOutDocs() {
203         return getCheckedOutDocs(getSession().getDefaultContext());
204     }
205 
206     public ItemIterable<Document> getCheckedOutDocs(OperationContext context) {
207         final String objectId = getObjectId();
208         final NavigationService navigationService = getBinding().getNavigationService();
209         final ObjectFactory objectFactory = getSession().getObjectFactory();
210         final OperationContext ctxt = new OperationContextImpl(context);
211 
212         return new CollectionIterable<Document>(new AbstractPageFetcher<Document>(ctxt.getMaxItemsPerPage()) {
213 
214             @Override
215             protected AbstractPageFetcher.Page<Document> fetchPage(long skipCount) {
216 
217                 // get checked out documents for this folder
218                 ObjectList checkedOutDocs = navigationService.getCheckedOutDocs(getRepositoryId(), objectId,
219                         ctxt.getFilterString(), ctxt.getOrderBy(), ctxt.isIncludeAllowableActions(),
220                         ctxt.getIncludeRelationships(), ctxt.getRenditionFilterString(),
221                         BigInteger.valueOf(this.maxNumItems), BigInteger.valueOf(skipCount), null);
222 
223                 // convert objects
224                 List<Document> page = new ArrayList<Document>();
225                 if (checkedOutDocs.getObjects() != null) {
226                     for (ObjectData objectData : checkedOutDocs.getObjects()) {
227                         CmisObject doc = objectFactory.convertObject(objectData, ctxt);
228                         if (!(doc instanceof Document)) {
229                             // should not happen...
230                             continue;
231                         }
232 
233                         page.add((Document) doc);
234                     }
235                 }
236 
237                 return new AbstractPageFetcher.Page<Document>(page, checkedOutDocs.getNumItems(),
238                         checkedOutDocs.hasMoreItems());
239             }
240         });
241     }
242 
243     public ItemIterable<CmisObject> getChildren() {
244         return getChildren(getSession().getDefaultContext());
245     }
246 
247     public ItemIterable<CmisObject> getChildren(OperationContext context) {
248         final String objectId = getObjectId();
249         final NavigationService navigationService = getBinding().getNavigationService();
250         final ObjectFactory objectFactory = getSession().getObjectFactory();
251         final OperationContext ctxt = new OperationContextImpl(context);
252 
253         return new CollectionIterable<CmisObject>(new AbstractPageFetcher<CmisObject>(ctxt.getMaxItemsPerPage()) {
254 
255             @Override
256             protected AbstractPageFetcher.Page<CmisObject> fetchPage(long skipCount) {
257 
258                 // get the children
259                 ObjectInFolderList children = navigationService.getChildren(getRepositoryId(), objectId,
260                         ctxt.getFilterString(), ctxt.getOrderBy(), ctxt.isIncludeAllowableActions(),
261                         ctxt.getIncludeRelationships(), ctxt.getRenditionFilterString(), ctxt.isIncludePathSegments(),
262                         BigInteger.valueOf(this.maxNumItems), BigInteger.valueOf(skipCount), null);
263 
264                 // convert objects
265                 List<CmisObject> page = new ArrayList<CmisObject>();
266                 List<ObjectInFolderData> childObjects = children.getObjects();
267                 if (childObjects != null) {
268                     for (ObjectInFolderData objectData : childObjects) {
269                         if (objectData.getObject() != null) {
270                             page.add(objectFactory.convertObject(objectData.getObject(), ctxt));
271                         }
272                     }
273                 }
274 
275                 return new AbstractPageFetcher.Page<CmisObject>(page, children.getNumItems(), children.hasMoreItems());
276             }
277         });
278     }
279 
280     public List<Tree<FileableCmisObject>> getDescendants(int depth) {
281         return getDescendants(depth, getSession().getDefaultContext());
282     }
283 
284     public List<Tree<FileableCmisObject>> getDescendants(int depth, OperationContext context) {
285         String objectId = getObjectId();
286 
287         // get the descendants
288         List<ObjectInFolderContainer> providerContainerList = getBinding().getNavigationService().getDescendants(
289                 getRepositoryId(), objectId, BigInteger.valueOf(depth), context.getFilterString(),
290                 context.isIncludeAllowableActions(), context.getIncludeRelationships(),
291                 context.getRenditionFilterString(), context.isIncludePathSegments(), null);
292 
293         return convertBindingContainer(providerContainerList, context);
294     }
295 
296     public List<Tree<FileableCmisObject>> getFolderTree(int depth) {
297         return getFolderTree(depth, getSession().getDefaultContext());
298     }
299 
300     public List<Tree<FileableCmisObject>> getFolderTree(int depth, OperationContext context) {
301         String objectId = getObjectId();
302 
303         // get the folder tree
304         List<ObjectInFolderContainer> providerContainerList = getBinding().getNavigationService().getFolderTree(
305                 getRepositoryId(), objectId, BigInteger.valueOf(depth), context.getFilterString(),
306                 context.isIncludeAllowableActions(), context.getIncludeRelationships(),
307                 context.getRenditionFilterString(), context.isIncludePathSegments(), null);
308 
309         return convertBindingContainer(providerContainerList, context);
310     }
311 
312     /**
313      * Converts a binding container into an API container.
314      */
315     private List<Tree<FileableCmisObject>> convertBindingContainer(List<ObjectInFolderContainer> bindingContainerList,
316             OperationContext context) {
317         if (bindingContainerList == null) {
318             return null;
319         }
320 
321         ObjectFactory of = getSession().getObjectFactory();
322 
323         List<Tree<FileableCmisObject>> result = new ArrayList<Tree<FileableCmisObject>>();
324         for (ObjectInFolderContainer oifc : bindingContainerList) {
325             if ((oifc.getObject() == null) || (oifc.getObject().getObject() == null)) {
326                 // shouldn't happen ...
327                 continue;
328             }
329 
330             // convert the object
331             CmisObject object = of.convertObject(oifc.getObject().getObject(), context);
332             if (!(object instanceof FileableCmisObject)) {
333                 // the repository must not return objects that are not fileable,
334                 // but you never know...
335                 continue;
336             }
337 
338             // convert the children
339             List<Tree<FileableCmisObject>> children = convertBindingContainer(oifc.getChildren(), context);
340 
341             // add both to current container
342             result.add(new TreeImpl<FileableCmisObject>((FileableCmisObject) object, children));
343         }
344 
345         return result;
346     }
347 
348     public boolean isRootFolder() {
349         String objectId = getObjectId();
350         String rootFolderId = getSession().getRepositoryInfo().getRootFolderId();
351 
352         return objectId.equals(rootFolderId);
353     }
354 
355     public Folder getFolderParent() {
356         if (isRootFolder()) {
357             return null;
358         }
359 
360         List<Folder> parents = getParents();
361         if ((parents == null) || (parents.isEmpty())) {
362             return null;
363         }
364 
365         return parents.get(0);
366     }
367 
368     public String getPath() {
369         String path;
370 
371         readLock();
372         try {
373             // get the path property
374             path = getPropertyValue(PropertyIds.PATH);
375 
376             // if the path property isn't set, get it
377             if (path == null) {
378                 String objectId = getObjectId();
379                 ObjectData objectData = getBinding().getObjectService().getObject(getRepositoryId(), objectId,
380                         getPropertyQueryName(PropertyIds.PATH), false, IncludeRelationships.NONE, "cmis:none", false,
381                         false, null);
382 
383                 if ((objectData.getProperties() != null) && (objectData.getProperties().getProperties() != null)) {
384                     PropertyData<?> pathProperty = objectData.getProperties().getProperties().get(PropertyIds.PATH);
385 
386                     if (pathProperty instanceof PropertyString) {
387                         path = ((PropertyString) pathProperty).getFirstValue();
388                     }
389                 }
390             }
391         } finally {
392             readUnlock();
393         }
394 
395         // we still don't know the path ... it's not a CMIS compliant repository
396         if (path == null) {
397             throw new CmisRuntimeException("Repository didn't return " + PropertyIds.PATH + "!");
398         }
399 
400         return path;
401     }
402 
403     @Override
404     public List<Folder> getParents(OperationContext context) {
405         if (isRootFolder()) {
406             return Collections.emptyList();
407         }
408 
409         String objectId = getObjectId();
410 
411         ObjectData bindingParent = getBinding().getNavigationService().getFolderParent(getRepositoryId(), objectId,
412                 getPropertyQueryName(PropertyIds.OBJECT_ID), null);
413 
414         if (bindingParent.getProperties() == null) {
415             // should not happen...
416             throw new CmisRuntimeException("Repository sent invalid data!");
417         }
418 
419         // get id property
420         PropertyData<?> idProperty = bindingParent.getProperties().getProperties().get(PropertyIds.OBJECT_ID);
421         if (!(idProperty instanceof PropertyId)) {
422             // the repository sent an object without a valid object id...
423             throw new CmisRuntimeException("Repository sent invalid data! No object id!");
424         }
425 
426         // fetch the object and make sure it is a folder
427         CmisObject parentFolder = getSession().getObject((String) idProperty.getFirstValue(), context);
428         if (!(parentFolder instanceof Folder)) {
429             // the repository sent an object that is not a folder...
430             throw new CmisRuntimeException("Repository sent invalid data! Object is not a folder!");
431         }
432 
433         return Collections.singletonList((Folder) parentFolder);
434     }
435 
436     @Override
437     public List<String> getPaths() {
438         return Collections.singletonList(getPath());
439     }
440 
441     public Document createDocument(Map<String, ?> properties, ContentStream contentStream,
442             VersioningState versioningState) {
443         return this.createDocument(properties, contentStream, versioningState, null, null, null, getSession()
444                 .getDefaultContext());
445     }
446 
447     public Document createDocumentFromSource(ObjectId source, Map<String, ?> properties, VersioningState versioningState) {
448         return this.createDocumentFromSource(source, properties, versioningState, null, null, null, getSession()
449                 .getDefaultContext());
450     }
451 
452     public Folder createFolder(Map<String, ?> properties) {
453         return this.createFolder(properties, null, null, null, getSession().getDefaultContext());
454     }
455 
456     public Policy createPolicy(Map<String, ?> properties) {
457         return this.createPolicy(properties, null, null, null, getSession().getDefaultContext());
458     }
459 }