This project has retired. For details please refer to its Attic page.
InMemoryNavigationServiceImpl 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.inmemory.server;
20  
21  import java.math.BigInteger;
22  import java.util.ArrayList;
23  import java.util.Collections;
24  import java.util.List;
25  
26  import org.apache.chemistry.opencmis.commons.PropertyIds;
27  import org.apache.chemistry.opencmis.commons.data.AllowableActions;
28  import org.apache.chemistry.opencmis.commons.data.ExtensionsData;
29  import org.apache.chemistry.opencmis.commons.data.ObjectData;
30  import org.apache.chemistry.opencmis.commons.data.ObjectInFolderContainer;
31  import org.apache.chemistry.opencmis.commons.data.ObjectInFolderData;
32  import org.apache.chemistry.opencmis.commons.data.ObjectInFolderList;
33  import org.apache.chemistry.opencmis.commons.data.ObjectList;
34  import org.apache.chemistry.opencmis.commons.data.ObjectParentData;
35  import org.apache.chemistry.opencmis.commons.data.Properties;
36  import org.apache.chemistry.opencmis.commons.definitions.TypeDefinition;
37  import org.apache.chemistry.opencmis.commons.enums.IncludeRelationships;
38  import org.apache.chemistry.opencmis.commons.exceptions.CmisConstraintException;
39  import org.apache.chemistry.opencmis.commons.exceptions.CmisInvalidArgumentException;
40  import org.apache.chemistry.opencmis.commons.exceptions.CmisObjectNotFoundException;
41  import org.apache.chemistry.opencmis.commons.impl.dataobjects.ObjectDataImpl;
42  import org.apache.chemistry.opencmis.commons.impl.dataobjects.ObjectInFolderContainerImpl;
43  import org.apache.chemistry.opencmis.commons.impl.dataobjects.ObjectInFolderDataImpl;
44  import org.apache.chemistry.opencmis.commons.impl.dataobjects.ObjectInFolderListImpl;
45  import org.apache.chemistry.opencmis.commons.impl.dataobjects.ObjectListImpl;
46  import org.apache.chemistry.opencmis.commons.impl.dataobjects.ObjectParentDataImpl;
47  import org.apache.chemistry.opencmis.commons.impl.server.ObjectInfoImpl;
48  import org.apache.chemistry.opencmis.commons.server.CallContext;
49  import org.apache.chemistry.opencmis.commons.server.ObjectInfoHandler;
50  import org.apache.chemistry.opencmis.inmemory.DataObjectCreator;
51  import org.apache.chemistry.opencmis.inmemory.FilterParser;
52  import org.apache.chemistry.opencmis.inmemory.storedobj.api.DocumentVersion;
53  import org.apache.chemistry.opencmis.inmemory.storedobj.api.Filing;
54  import org.apache.chemistry.opencmis.inmemory.storedobj.api.Folder;
55  import org.apache.chemistry.opencmis.inmemory.storedobj.api.MultiFiling;
56  import org.apache.chemistry.opencmis.inmemory.storedobj.api.ObjectStore;
57  import org.apache.chemistry.opencmis.inmemory.storedobj.api.SingleFiling;
58  import org.apache.chemistry.opencmis.inmemory.storedobj.api.StoreManager;
59  import org.apache.chemistry.opencmis.inmemory.storedobj.api.StoredObject;
60  import org.apache.chemistry.opencmis.inmemory.storedobj.api.VersionedDocument;
61  import org.apache.chemistry.opencmis.inmemory.types.PropertyCreationHelper;
62  import org.apache.commons.logging.Log;
63  import org.apache.commons.logging.LogFactory;
64  
65  public class InMemoryNavigationServiceImpl extends InMemoryAbstractServiceImpl {
66  
67      private static final Log LOG = LogFactory.getLog(InMemoryNavigationServiceImpl.class);
68  
69      final AtomLinkInfoProvider fAtomLinkProvider;
70  
71      public InMemoryNavigationServiceImpl(StoreManager storeManager) {
72          super(storeManager);
73          fAtomLinkProvider = new AtomLinkInfoProvider(fStoreManager);
74      }
75  
76      public ObjectList getCheckedOutDocs(CallContext context, String repositoryId, String folderId, String filter,
77              String orderBy, Boolean includeAllowableActions, IncludeRelationships includeRelationships,
78              String renditionFilter, BigInteger maxItems, BigInteger skipCount, ExtensionsData extension,
79              ObjectInfoHandler objectInfos) {
80  
81          validator.getCheckedOutDocs(context, repositoryId, folderId, extension);
82          ObjectListImpl res = new ObjectListImpl();
83          List<ObjectData> odList = new ArrayList<ObjectData>();
84  
85          LOG.debug("start getCheckedOutDocs()");
86  
87          String user = context.getUsername();
88          if (null == folderId) {
89              List<StoredObject> checkedOuts = fStoreManager.getObjectStore(repositoryId).getCheckedOutDocuments(
90                      orderBy, context.getUsername(), includeRelationships);
91              for (StoredObject checkedOut : checkedOuts) {
92                  TypeDefinition td = fStoreManager.getTypeById(repositoryId, checkedOut.getTypeId()).getTypeDefinition();
93  //                DocumentVersion workingCopy = ((VersionedDocument) checkedOut).getPwc();
94  //                if (null == workingCopy)
95  //                	throw new CmisConstraintException("document " + checkedOut + " is checked out but has no working copy");       
96                  ObjectData od = PropertyCreationHelper.getObjectData(td, checkedOut, filter, user,
97                          includeAllowableActions, includeRelationships, renditionFilter, false, false, extension);
98                  if (context.isObjectInfoRequired()) {
99                      ObjectInfoImpl objectInfo = new ObjectInfoImpl();
100                     fAtomLinkProvider.fillInformationForAtomLinks(repositoryId, /* workingCopy */ checkedOut, objectInfo);
101                     objectInfos.addObjectInfo(objectInfo);
102                 }
103                 odList.add(od);
104             }
105         } else {
106             LOG.debug("getting checked-out documents for folder: " + folderId);
107             ObjectInFolderList children = getChildrenIntern(repositoryId, folderId, filter, orderBy,
108                     includeAllowableActions, includeRelationships, renditionFilter, false, -1, -1, false, context
109                             .isObjectInfoRequired() ? objectInfos : null, user);
110             for (ObjectInFolderData child : children.getObjects()) {
111                 ObjectData obj = child.getObject();
112                 StoredObject so = fStoreManager.getObjectStore(repositoryId).getObjectById(obj.getId());
113                 LOG.debug("Checked out: children:" + obj.getId());
114                 if (so instanceof DocumentVersion && ((DocumentVersion) so).getParentDocument().isCheckedOut()) {
115                     odList.add(obj);
116                     if (context.isObjectInfoRequired()) {
117                         ObjectInfoImpl objectInfo = new ObjectInfoImpl();
118                         fAtomLinkProvider.fillInformationForAtomLinks(repositoryId, so, objectInfo);
119                         objectInfos.addObjectInfo(objectInfo);
120                     }
121                 }
122             }
123         }
124         res.setObjects(odList);
125         res.setNumItems(BigInteger.valueOf(odList.size()));
126 
127         LOG.debug("end getCheckedOutDocs()");
128         return res;
129     }
130 
131     public ObjectInFolderList getChildren(CallContext context, String repositoryId, String folderId, String filter,
132             String orderBy, Boolean includeAllowableActions, IncludeRelationships includeRelationships,
133             String renditionFilter, Boolean includePathSegment, BigInteger maxItems, BigInteger skipCount,
134             ExtensionsData extension, ObjectInfoHandler objectInfos) {
135 
136         LOG.debug("start getChildren()");
137 
138         validator.getChildren(context,repositoryId, folderId, extension);
139 
140         int maxItemsInt = maxItems == null ? -1 : maxItems.intValue();
141         int skipCountInt = skipCount == null ? -1 : skipCount.intValue();
142         String user = context.getUsername();
143         ObjectInFolderList res = getChildrenIntern(repositoryId, folderId, filter, orderBy, includeAllowableActions,
144                 includeRelationships, renditionFilter, includePathSegment, maxItemsInt, skipCountInt, false,
145                 context.isObjectInfoRequired() ? objectInfos : null, user);
146         LOG.debug("stop getChildren()");
147         return res;
148     }
149 
150     public List<ObjectInFolderContainer> getDescendants(CallContext context, String repositoryId, String folderId,
151             BigInteger depth, String filter, Boolean includeAllowableActions,
152             IncludeRelationships includeRelationships, String renditionFilter, Boolean includePathSegment,
153             ExtensionsData extension, ObjectInfoHandler objectInfos) {
154 
155         LOG.debug("start getDescendants()");
156 
157         validator.getDescendants(context, repositoryId, folderId, extension);
158 
159         int levels;
160         if (depth == null) {
161             levels = 2; // one of the recommended defaults (should it be
162         } else if (depth.intValue() == 0) {
163             throw new CmisInvalidArgumentException("A zero depth is not allowed for getDescendants().");
164         } else {
165             levels = depth.intValue();
166         }
167 
168         int level = 0;
169         String user = context.getUsername();
170         List<ObjectInFolderContainer> result = getDescendantsIntern(repositoryId, folderId, filter,
171                 includeAllowableActions, includeRelationships, renditionFilter, includePathSegment, level, levels,
172                 false, objectInfos, user);
173 
174         LOG.debug("stop getDescendants()");
175         return result;
176     }
177 
178     public ObjectData getFolderParent(CallContext context, String repositoryId, String folderId, String filter,
179             ExtensionsData extension, ObjectInfoHandler objectInfos) {
180 
181         LOG.debug("start getFolderParent()");
182 
183         StoredObject so = validator.getFolderParent(context, repositoryId, folderId, extension);
184 
185         Folder folder = null;
186         if (so instanceof Folder) {
187             folder = (Folder) so;
188         } else {
189             throw new CmisInvalidArgumentException("Can't get folder parent, id does not refer to a folder: "
190                     + folderId);
191         }
192 
193         ObjectData res = getFolderParentIntern(repositoryId, folder, filter, false, 
194         		IncludeRelationships.NONE, context.getUsername(), context.isObjectInfoRequired() ? objectInfos : null);
195         if (res == null) {
196             throw new CmisInvalidArgumentException("Cannot get parent of a root folder");
197         }
198 
199         // To be able to provide all Atom links in the response we need
200         // additional information:
201         if (context.isObjectInfoRequired()) {
202             ObjectInfoImpl objectInfo = new ObjectInfoImpl();
203             fAtomLinkProvider.fillInformationForAtomLinks(repositoryId, so, objectInfo);
204             objectInfos.addObjectInfo(objectInfo);
205         }
206 
207         LOG.debug("stop getFolderParent()");
208         return res;
209     }
210 
211     public List<ObjectInFolderContainer> getFolderTree(CallContext context, String repositoryId, String folderId,
212             BigInteger depth, String filter, Boolean includeAllowableActions,
213             IncludeRelationships includeRelationships, String renditionFilter, Boolean includePathSegment,
214             ExtensionsData extension, ObjectInfoHandler objectInfos) {
215 
216         LOG.debug("start getFolderTree()");
217 
218         validator.getFolderTree(context, repositoryId, folderId, extension);
219 
220         if (depth != null && depth.intValue() == 0) {
221             throw new CmisInvalidArgumentException("A zero depth is not allowed for getFolderTree().");
222         }
223 
224         int levels = depth == null ? 2 : depth.intValue();
225         int level = 0;
226         String user = context.getUsername();
227         List<ObjectInFolderContainer> result = getDescendantsIntern(repositoryId, folderId, filter,
228                 includeAllowableActions, includeRelationships, renditionFilter, includePathSegment, level, levels,
229                 true, objectInfos, user);
230 
231         LOG.debug("stop getFolderTree()");
232         return result;
233     }
234 
235     public List<ObjectParentData> getObjectParents(CallContext context, String repositoryId, String objectId,
236             String filter, Boolean includeAllowableActions, IncludeRelationships includeRelationships,
237             String renditionFilter, Boolean includeRelativePathSegment, ExtensionsData extension,
238             ObjectInfoHandler objectInfos) {
239 
240         LOG.debug("start getObjectParents()");
241 
242         StoredObject so = validator.getObjectParents(context, repositoryId, objectId, extension);
243 
244         // for now we have only folders that have a parent and the in-memory
245         // provider only has one
246         // parent for each object (no multi-filing)
247         List<ObjectParentData> result = null;
248 
249         Filing spo = null;
250         if (so instanceof Filing) {
251             spo = (Filing) so;
252         } else {
253             return Collections.emptyList();
254         }
255 
256         result = getObjectParentsIntern(repositoryId, spo, filter, 
257         		context.isObjectInfoRequired() ? objectInfos : null, includeAllowableActions, includeRelationships,
258 				context.getUsername());
259 
260         // To be able to provide all Atom links in the response we need
261         // additional information:
262         if (context.isObjectInfoRequired()) {
263             ObjectInfoImpl objectInfo = new ObjectInfoImpl();
264             fAtomLinkProvider.fillInformationForAtomLinks(repositoryId, so, objectInfo);
265             objectInfos.addObjectInfo(objectInfo);
266         }
267 
268         LOG.debug("stop getObjectParents()");
269         return result;
270     }
271 
272     // private helpers
273 
274     private ObjectInFolderList getChildrenIntern(String repositoryId, String folderId, String filter, String orderBy,
275             Boolean includeAllowableActions, IncludeRelationships includeRelationships, String renditionFilter,
276             Boolean includePathSegments, int maxItems, int skipCount, boolean folderOnly, ObjectInfoHandler objectInfos,
277             String user) {
278 
279         ObjectInFolderListImpl result = new ObjectInFolderListImpl();
280         List<ObjectInFolderData> folderList = new ArrayList<ObjectInFolderData>();
281         ObjectStore fs = fStoreManager.getObjectStore(repositoryId);
282         StoredObject so = fs.getObjectById(folderId);
283         Folder folder = null;
284 
285         if (so == null) {
286             throw new CmisObjectNotFoundException("Unknown object id: " + folderId);
287         }
288 
289         if (so instanceof Folder) {
290             folder = (Folder) so;
291         }
292         else {
293             return null; // it is a document and has no children
294         }
295 
296         List<? extends StoredObject> children = folderOnly ? folder.getFolderChildren(maxItems, skipCount, user) : folder
297                 .getChildren(maxItems, skipCount, user);
298 
299         for (StoredObject spo : children) {
300             ObjectInFolderDataImpl oifd = new ObjectInFolderDataImpl();
301             if (includePathSegments != null && includePathSegments) {
302                 oifd.setPathSegment(spo.getName());
303             }
304 
305             TypeDefinition typeDef = fStoreManager.getTypeById(repositoryId, spo.getTypeId()).getTypeDefinition();
306             ObjectData objectData = PropertyCreationHelper.getObjectData(typeDef, spo, filter, user, includeAllowableActions, 
307                     includeRelationships, renditionFilter, false, false, null);
308 
309             oifd.setObject(objectData);
310             folderList.add(oifd);
311             // add additional information for Atom
312             if (objectInfos != null) {
313                 ObjectInfoImpl objectInfo = new ObjectInfoImpl();
314                 fAtomLinkProvider.fillInformationForAtomLinks(repositoryId, spo, objectInfo);
315                 objectInfos.addObjectInfo(objectInfo);
316             }
317 
318         }
319         result.setObjects(folderList);
320         result.setNumItems(BigInteger.valueOf(folderList.size()));
321         if (objectInfos != null) {
322             ObjectInfoImpl objectInfo = new ObjectInfoImpl();
323             fAtomLinkProvider.fillInformationForAtomLinks(repositoryId, so, objectInfo);
324             objectInfos.addObjectInfo(objectInfo);
325         }
326         return result;
327     }
328 
329     private List<ObjectInFolderContainer> getDescendantsIntern(String repositoryId, String folderId, String filter,
330             Boolean includeAllowableActions, IncludeRelationships includeRelationships, String renditionFilter,
331             Boolean includePathSegments, int level, int maxLevels, boolean folderOnly, ObjectInfoHandler objectInfos,
332             String user) {
333 
334         // log.info("getDescendantsIntern: " + folderId + ", in level " + level
335         // + ", max levels " + maxLevels);
336 
337         List<ObjectInFolderContainer> childrenOfFolderId = null;
338         if (maxLevels == -1 || level < maxLevels) {
339             String orderBy = PropertyIds.NAME;
340             ObjectInFolderList children = getChildrenIntern(repositoryId, folderId, filter, orderBy,
341                     includeAllowableActions, includeRelationships, renditionFilter, includePathSegments, 1000, 0,
342                     folderOnly, objectInfos, user);
343 
344             childrenOfFolderId = new ArrayList<ObjectInFolderContainer>();
345             if (null != children) {
346 
347                 for (ObjectInFolderData child : children.getObjects()) {
348                     ObjectInFolderContainerImpl oifc = new ObjectInFolderContainerImpl();
349                     String childId = child.getObject().getId();
350                     List<ObjectInFolderContainer> subChildren = getDescendantsIntern(repositoryId, childId, filter,
351                             includeAllowableActions, includeRelationships, renditionFilter, includePathSegments,
352                             level + 1, maxLevels, folderOnly, objectInfos, user);
353 
354                     oifc.setObject(child);
355                     if (null != subChildren) {
356                         oifc.setChildren(subChildren);
357                     }
358                     childrenOfFolderId.add(oifc);
359                 }
360             }
361         }
362         return childrenOfFolderId;
363     }
364 
365     private List<ObjectParentData> getObjectParentsIntern(String repositoryId, Filing sop, String filter,
366             ObjectInfoHandler objectInfos, Boolean includeAllowableActions, 
367             IncludeRelationships includeRelationships, String user) {
368 
369         List<ObjectParentData> result = null;
370         if (sop instanceof SingleFiling) {
371             ObjectData parent = getFolderParentIntern(repositoryId, (SingleFiling) sop, filter, 
372             		includeAllowableActions, includeRelationships, user, objectInfos);
373             if (null != parent) {
374                 ObjectParentDataImpl parentData = new ObjectParentDataImpl();
375                 parentData.setObject(parent);
376                 String path = ((SingleFiling) sop).getPath();
377                 int beginIndex = path.lastIndexOf(Filing.PATH_SEPARATOR) + 1; 
378                 //   Note: if not found results in 0
379                 String relPathSeg = path.substring(beginIndex, path.length());
380                 parentData.setRelativePathSegment(relPathSeg);
381                 result = Collections.singletonList((ObjectParentData) parentData);
382             } else {
383                 result = Collections.emptyList();
384             }
385         } else if (sop instanceof MultiFiling) {
386             result = new ArrayList<ObjectParentData>();
387             MultiFiling multiParentObj = (MultiFiling) sop;
388             List<Folder> parents = multiParentObj.getParents(user);
389             if (null != parents) {
390                 for (Folder parent : parents) {
391                     ObjectParentDataImpl parentData = new ObjectParentDataImpl();
392                     TypeDefinition typeDef = fStoreManager.getTypeById(repositoryId, parent.getTypeId()).getTypeDefinition();
393                     ObjectData objData = PropertyCreationHelper.getObjectData(typeDef, parent, filter, user, includeAllowableActions, 
394                             includeRelationships, "", false, true, null);
395 
396                     parentData.setObject(objData);
397                     parentData.setRelativePathSegment(multiParentObj.getPathSegment());
398                     result.add(parentData);
399                     if (objectInfos != null) {
400                         ObjectInfoImpl objectInfo = new ObjectInfoImpl();
401                         fAtomLinkProvider.fillInformationForAtomLinks(repositoryId, parent, objectInfo);
402                         objectInfos.addObjectInfo(objectInfo);
403                     }
404                 }
405             }
406         }
407         return result;
408     }
409 
410     private ObjectData getFolderParentIntern(String repositoryId, SingleFiling sop, String filter,
411     		Boolean includeAllowableActions, IncludeRelationships includeRelationships, 
412     		String user, ObjectInfoHandler objectInfos) {
413 
414         ObjectDataImpl parent = new ObjectDataImpl();
415 
416         Folder parentFolder = sop.getParent();
417 
418         if (null == parentFolder) {
419             return null;
420         }
421 
422         copyFilteredProperties(repositoryId, parentFolder, filter, parent);
423         
424         parent.setRelationships(DataObjectCreator.getRelationships(includeRelationships, parentFolder, user));
425         
426         if (includeAllowableActions != null && includeAllowableActions) {
427             //  AllowableActions allowableActions = DataObjectCreator.fillAllowableActions(spo, user);
428           	AllowableActions allowableActions = parentFolder.getAllowableActions(user);
429           	parent.setAllowableActions(allowableActions);
430           }
431         
432         if (objectInfos != null) {
433             ObjectInfoImpl objectInfo = new ObjectInfoImpl();
434             fAtomLinkProvider.fillInformationForAtomLinks(repositoryId, parentFolder, objectInfo);
435             objectInfos.addObjectInfo(objectInfo);
436         }
437 
438         return parent;
439     }
440 
441     void copyFilteredProperties(String repositoryId, StoredObject so, String filter, ObjectDataImpl objData) {
442         List<String> requestedIds = FilterParser.getRequestedIdsFromFilter(filter);
443         TypeDefinition td = fStoreManager.getTypeById(repositoryId, so.getTypeId()).getTypeDefinition();
444         Properties props = PropertyCreationHelper.getPropertiesFromObject(so, td, requestedIds, true);
445         objData.setProperties(props);
446     }
447 
448 }