View Javadoc
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.server.impl.atompub;
20  
21  import org.apache.chemistry.opencmis.commons.data.ObjectData;
22  import org.apache.chemistry.opencmis.commons.data.ObjectInFolderContainer;
23  import org.apache.chemistry.opencmis.commons.data.ObjectInFolderData;
24  import org.apache.chemistry.opencmis.commons.data.ObjectInFolderList;
25  import org.apache.chemistry.opencmis.commons.data.ObjectList;
26  import org.apache.chemistry.opencmis.commons.data.ObjectParentData;
27  import org.apache.chemistry.opencmis.commons.enums.IncludeRelationships;
28  import org.apache.chemistry.opencmis.commons.exceptions.CmisRuntimeException;
29  import org.apache.chemistry.opencmis.commons.impl.Constants;
30  import org.apache.chemistry.opencmis.commons.impl.UrlBuilder;
31  import org.apache.chemistry.opencmis.commons.impl.server.ObjectInfoImpl;
32  import org.apache.chemistry.opencmis.commons.server.CallContext;
33  import org.apache.chemistry.opencmis.commons.server.CmisService;
34  import org.apache.chemistry.opencmis.commons.server.ObjectInfo;
35  import org.apache.chemistry.opencmis.commons.server.RenditionInfo;
36  import static org.apache.chemistry.opencmis.server.impl.atompub.AtomPubUtils.RESOURCE_ACL;
37  import static org.apache.chemistry.opencmis.server.impl.atompub.AtomPubUtils.RESOURCE_ALLOWABLEACIONS;
38  import static org.apache.chemistry.opencmis.server.impl.atompub.AtomPubUtils.RESOURCE_CHECKEDOUT;
39  import static org.apache.chemistry.opencmis.server.impl.atompub.AtomPubUtils.RESOURCE_CHILDREN;
40  import static org.apache.chemistry.opencmis.server.impl.atompub.AtomPubUtils.RESOURCE_CONTENT;
41  import static org.apache.chemistry.opencmis.server.impl.atompub.AtomPubUtils.RESOURCE_DESCENDANTS;
42  import static org.apache.chemistry.opencmis.server.impl.atompub.AtomPubUtils.RESOURCE_ENTRY;
43  import static org.apache.chemistry.opencmis.server.impl.atompub.AtomPubUtils.RESOURCE_FOLDERTREE;
44  import static org.apache.chemistry.opencmis.server.impl.atompub.AtomPubUtils.RESOURCE_PARENTS;
45  import static org.apache.chemistry.opencmis.server.impl.atompub.AtomPubUtils.RESOURCE_POLICIES;
46  import static org.apache.chemistry.opencmis.server.impl.atompub.AtomPubUtils.RESOURCE_RELATIONSHIPS;
47  import static org.apache.chemistry.opencmis.server.impl.atompub.AtomPubUtils.RESOURCE_TYPE;
48  import static org.apache.chemistry.opencmis.server.impl.atompub.AtomPubUtils.compileBaseUrl;
49  import static org.apache.chemistry.opencmis.server.impl.atompub.AtomPubUtils.compileUrl;
50  import static org.apache.chemistry.opencmis.server.impl.atompub.AtomPubUtils.compileUrlBuilder;
51  import static org.apache.chemistry.opencmis.server.impl.atompub.AtomPubUtils.writeObjectEntry;
52  import static org.apache.chemistry.opencmis.server.shared.HttpUtils.getBigIntegerParameter;
53  import static org.apache.chemistry.opencmis.server.shared.HttpUtils.getBooleanParameter;
54  import static org.apache.chemistry.opencmis.server.shared.HttpUtils.getEnumParameter;
55  import static org.apache.chemistry.opencmis.server.shared.HttpUtils.getStringParameter;
56  
57  import java.math.BigInteger;
58  
59  import java.util.GregorianCalendar;
60  import java.util.List;
61  
62  import javax.servlet.http.HttpServletRequest;
63  import javax.servlet.http.HttpServletResponse;
64  
65  
66  /**
67   * Navigation Service operations.
68   */
69  public final class NavigationService
70  {
71      private NavigationService(  )
72      {
73      }
74  
75      /**
76       * Children Collection GET.
77       */
78      public static void getChildren( CallContext context, CmisService service, String repositoryId,
79          HttpServletRequest request, HttpServletResponse response )
80          throws Exception
81      {
82          // get parameters
83          String folderId = getStringParameter( request, Constants.PARAM_ID );
84          String filter = getStringParameter( request, Constants.PARAM_FILTER );
85          String orderBy = getStringParameter( request, Constants.PARAM_ORDER_BY );
86          Boolean includeAllowableActions = getBooleanParameter( request, Constants.PARAM_ALLOWABLE_ACTIONS );
87          IncludeRelationships includeRelationships = getEnumParameter( request, Constants.PARAM_RELATIONSHIPS,
88                  IncludeRelationships.class );
89          String renditionFilter = getStringParameter( request, Constants.PARAM_RENDITION_FILTER );
90          Boolean includePathSegment = getBooleanParameter( request, Constants.PARAM_PATH_SEGMENT );
91          BigInteger maxItems = getBigIntegerParameter( request, Constants.PARAM_MAX_ITEMS );
92          BigInteger skipCount = getBigIntegerParameter( request, Constants.PARAM_SKIP_COUNT );
93  
94          // execute
95          ObjectInFolderList children = service.getChildren( repositoryId, folderId, filter, orderBy,
96                  includeAllowableActions, includeRelationships, renditionFilter, includePathSegment, maxItems,
97                  skipCount, null );
98  
99          if ( children == null )
100         {
101             throw new CmisRuntimeException( "Children are null!" );
102         }
103 
104         ObjectInfo folderInfo = service.getObjectInfo( repositoryId, folderId );
105 
106         if ( folderInfo == null )
107         {
108             throw new CmisRuntimeException( "Folder Object Info is missing!" );
109         }
110 
111         // set headers
112         response.setStatus( HttpServletResponse.SC_OK );
113         response.setContentType( Constants.MEDIATYPE_FEED );
114 
115         // write XML
116         AtomFeed feed = new AtomFeed(  );
117         feed.startDocument( response.getOutputStream(  ) );
118         feed.startFeed( true );
119 
120         // write basic Atom feed elements
121         feed.writeFeedElements( folderInfo.getId(  ), folderInfo.getCreatedBy(  ), folderInfo.getName(  ),
122             folderInfo.getLastModificationDate(  ), null, children.getNumItems(  ) );
123 
124         // write links
125         UrlBuilder baseUrl = compileBaseUrl( request, repositoryId );
126 
127         feed.writeServiceLink( baseUrl.toString(  ), repositoryId );
128 
129         feed.writeSelfLink( compileUrl( baseUrl, RESOURCE_CHILDREN, folderInfo.getId(  ) ), null );
130 
131         feed.writeDescribedByLink( compileUrl( baseUrl, RESOURCE_TYPE, folderInfo.getTypeId(  ) ) );
132 
133         feed.writeAllowableActionsLink( compileUrl( baseUrl, RESOURCE_ALLOWABLEACIONS, folderInfo.getId(  ) ) );
134 
135         feed.writeDownLink( compileUrl( baseUrl, RESOURCE_CHILDREN, folderInfo.getId(  ) ), Constants.MEDIATYPE_FEED );
136 
137         if ( folderInfo.supportsDescendants(  ) )
138         {
139             feed.writeDownLink( compileUrl( baseUrl, RESOURCE_DESCENDANTS, folderInfo.getId(  ) ),
140                 Constants.MEDIATYPE_DESCENDANTS );
141         }
142 
143         if ( folderInfo.supportsFolderTree(  ) )
144         {
145             feed.writeFolderTreeLink( compileUrl( baseUrl, RESOURCE_FOLDERTREE, folderInfo.getId(  ) ) );
146         }
147 
148         if ( folderInfo.hasParent(  ) )
149         {
150             feed.writeUpLink( compileUrl( baseUrl, RESOURCE_PARENTS, folderInfo.getId(  ) ), Constants.MEDIATYPE_FEED );
151         }
152 
153         if ( folderInfo.getRenditionInfos(  ) != null )
154         {
155             for ( RenditionInfo ri : folderInfo.getRenditionInfos(  ) )
156             {
157                 feed.writeAlternateLink( compileUrl( baseUrl, RESOURCE_CONTENT, ri.getId(  ) ), ri.getContenType(  ),
158                     ri.getKind(  ), ri.getTitle(  ), ri.getLength(  ) );
159             }
160         }
161 
162         if ( folderInfo.hasAcl(  ) )
163         {
164             feed.writeAclLink( compileUrl( baseUrl, RESOURCE_ACL, folderInfo.getId(  ) ) );
165         }
166 
167         if ( folderInfo.supportsPolicies(  ) )
168         {
169             feed.writeAclLink( compileUrl( baseUrl, RESOURCE_POLICIES, folderInfo.getId(  ) ) );
170         }
171 
172         if ( folderInfo.supportsRelationships(  ) )
173         {
174             feed.writeRelationshipsLink( compileUrl( baseUrl, RESOURCE_RELATIONSHIPS, folderInfo.getId(  ) ) );
175         }
176 
177         UrlBuilder pagingUrl = new UrlBuilder( compileUrlBuilder( baseUrl, RESOURCE_CHILDREN, folderInfo.getId(  ) ) );
178         pagingUrl.addParameter( Constants.PARAM_FILTER, filter );
179         pagingUrl.addParameter( Constants.PARAM_ORDER_BY, orderBy );
180         pagingUrl.addParameter( Constants.PARAM_ALLOWABLE_ACTIONS, includeAllowableActions );
181         pagingUrl.addParameter( Constants.PARAM_RELATIONSHIPS, includeRelationships );
182         pagingUrl.addParameter( Constants.PARAM_RENDITION_FILTER, renditionFilter );
183         pagingUrl.addParameter( Constants.PARAM_PATH_SEGMENT, includePathSegment );
184         feed.writePagingLinks( pagingUrl, maxItems, skipCount, children.getNumItems(  ), children.hasMoreItems(  ),
185             AtomPubUtils.PAGE_SIZE );
186 
187         // write collection
188         feed.writeCollection( compileUrl( baseUrl, RESOURCE_CHILDREN, folderInfo.getId(  ) ), null,
189             "Folder collection", Constants.MEDIATYPE_CMISATOM );
190 
191         // write entries
192         if ( children.getObjects(  ) != null )
193         {
194             AtomEntry entry = new AtomEntry( feed.getWriter(  ) );
195 
196             for ( ObjectInFolderData object : children.getObjects(  ) )
197             {
198                 if ( ( object == null ) || ( object.getObject(  ) == null ) )
199                 {
200                     continue;
201                 }
202 
203                 writeObjectEntry( service, entry, object.getObject(  ), null, repositoryId, object.getPathSegment(  ),
204                     null, baseUrl, false );
205             }
206         }
207 
208         // we are done
209         feed.endFeed(  );
210         feed.endDocument(  );
211     }
212 
213     /**
214      * Descendants feed GET.
215      */
216     public static void getDescendants( CallContext context, CmisService service, String repositoryId,
217         HttpServletRequest request, HttpServletResponse response )
218         throws Exception
219     {
220         // get parameters
221         String folderId = getStringParameter( request, Constants.PARAM_ID );
222         BigInteger depth = getBigIntegerParameter( request, Constants.PARAM_DEPTH );
223         String filter = getStringParameter( request, Constants.PARAM_FILTER );
224         Boolean includeAllowableActions = getBooleanParameter( request, Constants.PARAM_ALLOWABLE_ACTIONS );
225         IncludeRelationships includeRelationships = getEnumParameter( request, Constants.PARAM_RELATIONSHIPS,
226                 IncludeRelationships.class );
227         String renditionFilter = getStringParameter( request, Constants.PARAM_RENDITION_FILTER );
228         Boolean includePathSegment = getBooleanParameter( request, Constants.PARAM_PATH_SEGMENT );
229 
230         // execute
231         List<ObjectInFolderContainer> descendants = service.getDescendants( repositoryId, folderId, depth, filter,
232                 includeAllowableActions, includeRelationships, renditionFilter, includePathSegment, null );
233 
234         if ( descendants == null )
235         {
236             throw new CmisRuntimeException( "Descendants are null!" );
237         }
238 
239         ObjectInfo folderInfo = service.getObjectInfo( repositoryId, folderId );
240 
241         if ( folderInfo == null )
242         {
243             throw new CmisRuntimeException( "Folder Object Info is missing!" );
244         }
245 
246         // set headers
247         response.setStatus( HttpServletResponse.SC_OK );
248         response.setContentType( Constants.MEDIATYPE_FEED );
249 
250         // write XML
251         AtomFeed feed = new AtomFeed(  );
252         feed.startDocument( response.getOutputStream(  ) );
253         feed.startFeed( true );
254 
255         // write basic Atom feed elements
256         feed.writeFeedElements( folderInfo.getId(  ), folderInfo.getCreatedBy(  ), folderInfo.getName(  ),
257             folderInfo.getLastModificationDate(  ), null, null );
258 
259         // write links
260         UrlBuilder baseUrl = compileBaseUrl( request, repositoryId );
261 
262         feed.writeServiceLink( baseUrl.toString(  ), repositoryId );
263 
264         feed.writeSelfLink( compileUrl( baseUrl, RESOURCE_DESCENDANTS, folderInfo.getId(  ) ), null );
265 
266         feed.writeViaLink( compileUrl( baseUrl, RESOURCE_ENTRY, folderInfo.getId(  ) ) );
267 
268         feed.writeDownLink( compileUrl( baseUrl, RESOURCE_CHILDREN, folderInfo.getId(  ) ), Constants.MEDIATYPE_FEED );
269 
270         if ( folderInfo.supportsFolderTree(  ) )
271         {
272             feed.writeFolderTreeLink( compileUrl( baseUrl, RESOURCE_FOLDERTREE, folderInfo.getId(  ) ) );
273         }
274 
275         if ( folderInfo.hasParent(  ) )
276         {
277             feed.writeUpLink( compileUrl( baseUrl, RESOURCE_PARENTS, folderInfo.getId(  ) ), Constants.MEDIATYPE_FEED );
278         }
279 
280         // write entries
281         AtomEntry entry = new AtomEntry( feed.getWriter(  ) );
282 
283         for ( ObjectInFolderContainer container : descendants )
284         {
285             if ( ( container == null ) || ( container.getObject(  ) == null ) ||
286                     ( container.getObject(  ).getObject(  ) == null ) )
287             {
288                 continue;
289             }
290 
291             writeObjectEntry( service, entry, container.getObject(  ).getObject(  ), container.getChildren(  ),
292                 repositoryId, container.getObject(  ).getPathSegment(  ), null, baseUrl, false );
293         }
294 
295         // we are done
296         feed.endFeed(  );
297         feed.endDocument(  );
298     }
299 
300     /**
301      * Folder tree feed GET.
302      */
303     public static void getFolderTree( CallContext context, CmisService service, String repositoryId,
304         HttpServletRequest request, HttpServletResponse response )
305         throws Exception
306     {
307         // get parameters
308         String folderId = getStringParameter( request, Constants.PARAM_ID );
309         BigInteger depth = getBigIntegerParameter( request, Constants.PARAM_DEPTH );
310         String filter = getStringParameter( request, Constants.PARAM_FILTER );
311         Boolean includeAllowableActions = getBooleanParameter( request, Constants.PARAM_ALLOWABLE_ACTIONS );
312         IncludeRelationships includeRelationships = getEnumParameter( request, Constants.PARAM_RELATIONSHIPS,
313                 IncludeRelationships.class );
314         String renditionFilter = getStringParameter( request, Constants.PARAM_RENDITION_FILTER );
315         Boolean includePathSegment = getBooleanParameter( request, Constants.PARAM_PATH_SEGMENT );
316 
317         // execute
318         List<ObjectInFolderContainer> folderTree = service.getFolderTree( repositoryId, folderId, depth, filter,
319                 includeAllowableActions, includeRelationships, renditionFilter, includePathSegment, null );
320 
321         if ( folderTree == null )
322         {
323             throw new CmisRuntimeException( "Folder tree is null!" );
324         }
325 
326         ObjectInfo folderInfo = service.getObjectInfo( repositoryId, folderId );
327 
328         if ( folderInfo == null )
329         {
330             throw new CmisRuntimeException( "Folder Object Info is missing!" );
331         }
332 
333         // set headers
334         response.setStatus( HttpServletResponse.SC_OK );
335         response.setContentType( Constants.MEDIATYPE_FEED );
336 
337         // write XML
338         AtomFeed feed = new AtomFeed(  );
339         feed.startDocument( response.getOutputStream(  ) );
340         feed.startFeed( true );
341 
342         // write basic Atom feed elements
343         feed.writeFeedElements( folderInfo.getId(  ), folderInfo.getCreatedBy(  ), folderInfo.getName(  ),
344             folderInfo.getLastModificationDate(  ), null, null );
345 
346         // write links
347         UrlBuilder baseUrl = compileBaseUrl( request, repositoryId );
348 
349         feed.writeServiceLink( baseUrl.toString(  ), repositoryId );
350 
351         feed.writeSelfLink( compileUrl( baseUrl, RESOURCE_DESCENDANTS, folderInfo.getId(  ) ), null );
352 
353         feed.writeViaLink( compileUrl( baseUrl, RESOURCE_ENTRY, folderInfo.getId(  ) ) );
354 
355         feed.writeDownLink( compileUrl( baseUrl, RESOURCE_CHILDREN, folderInfo.getId(  ) ), Constants.MEDIATYPE_FEED );
356 
357         if ( folderInfo.supportsDescendants(  ) )
358         {
359             feed.writeDownLink( compileUrl( baseUrl, RESOURCE_DESCENDANTS, folderInfo.getId(  ) ),
360                 Constants.MEDIATYPE_DESCENDANTS );
361         }
362 
363         if ( folderInfo.hasParent(  ) )
364         {
365             feed.writeUpLink( compileUrl( baseUrl, RESOURCE_PARENTS, folderInfo.getId(  ) ), Constants.MEDIATYPE_FEED );
366         }
367 
368         // write entries
369         AtomEntry entry = new AtomEntry( feed.getWriter(  ) );
370 
371         for ( ObjectInFolderContainer container : folderTree )
372         {
373             if ( ( container == null ) || ( container.getObject(  ) == null ) ||
374                     ( container.getObject(  ).getObject(  ) == null ) )
375             {
376                 continue;
377             }
378 
379             writeObjectEntry( service, entry, container.getObject(  ).getObject(  ), container.getChildren(  ),
380                 repositoryId, container.getObject(  ).getPathSegment(  ), null, baseUrl, false );
381         }
382 
383         // we are done
384         feed.endFeed(  );
385         feed.endDocument(  );
386     }
387 
388     /**
389      * Object parents feed GET.
390      */
391     public static void getObjectParents( CallContext context, CmisService service, String repositoryId,
392         HttpServletRequest request, HttpServletResponse response )
393         throws Exception
394     {
395         // get parameters
396         String objectId = getStringParameter( request, Constants.PARAM_ID );
397         String filter = getStringParameter( request, Constants.PARAM_FILTER );
398         Boolean includeAllowableActions = getBooleanParameter( request, Constants.PARAM_ALLOWABLE_ACTIONS );
399         IncludeRelationships includeRelationships = getEnumParameter( request, Constants.PARAM_RELATIONSHIPS,
400                 IncludeRelationships.class );
401         String renditionFilter = getStringParameter( request, Constants.PARAM_RENDITION_FILTER );
402         Boolean includeRelativePathSegment = getBooleanParameter( request, Constants.PARAM_RELATIVE_PATH_SEGMENT );
403 
404         // execute
405         List<ObjectParentData> parents = service.getObjectParents( repositoryId, objectId, filter,
406                 includeAllowableActions, includeRelationships, renditionFilter, includeRelativePathSegment, null );
407 
408         if ( parents == null )
409         {
410             throw new CmisRuntimeException( "Parents are null!" );
411         }
412 
413         ObjectInfo objectInfo = service.getObjectInfo( repositoryId, objectId );
414 
415         if ( objectInfo == null )
416         {
417             throw new CmisRuntimeException( "Object Info is missing!" );
418         }
419 
420         // set headers
421         response.setStatus( HttpServletResponse.SC_OK );
422         response.setContentType( Constants.MEDIATYPE_FEED );
423 
424         // write XML
425         AtomFeed feed = new AtomFeed(  );
426         feed.startDocument( response.getOutputStream(  ) );
427         feed.startFeed( true );
428 
429         // write basic Atom feed elements
430         feed.writeFeedElements( objectInfo.getId(  ), objectInfo.getCreatedBy(  ), objectInfo.getName(  ),
431             objectInfo.getLastModificationDate(  ), null, null );
432 
433         // write links
434         UrlBuilder baseUrl = compileBaseUrl( request, repositoryId );
435 
436         feed.writeServiceLink( baseUrl.toString(  ), repositoryId );
437 
438         feed.writeSelfLink( compileUrl( baseUrl, RESOURCE_PARENTS, objectInfo.getId(  ) ), null );
439 
440         // write entries
441         AtomEntry entry = new AtomEntry( feed.getWriter(  ) );
442 
443         for ( ObjectParentData object : parents )
444         {
445             if ( ( object == null ) || ( object.getObject(  ) == null ) )
446             {
447                 continue;
448             }
449 
450             writeObjectEntry( service, entry, object.getObject(  ), null, repositoryId, null,
451                 object.getRelativePathSegment(  ), baseUrl, false );
452         }
453 
454         // we are done
455         feed.endFeed(  );
456         feed.endDocument(  );
457     }
458 
459     /**
460      * Checked Out Collection GET.
461      */
462     public static void getCheckedOutDocs( CallContext context, CmisService service, String repositoryId,
463         HttpServletRequest request, HttpServletResponse response )
464         throws Exception
465     {
466         // get parameters
467         String folderId = getStringParameter( request, Constants.PARAM_FOLDER_ID );
468         String filter = getStringParameter( request, Constants.PARAM_FILTER );
469         String orderBy = getStringParameter( request, Constants.PARAM_ORDER_BY );
470         Boolean includeAllowableActions = getBooleanParameter( request, Constants.PARAM_ALLOWABLE_ACTIONS );
471         IncludeRelationships includeRelationships = getEnumParameter( request, Constants.PARAM_RELATIONSHIPS,
472                 IncludeRelationships.class );
473         String renditionFilter = getStringParameter( request, Constants.PARAM_RENDITION_FILTER );
474         BigInteger maxItems = getBigIntegerParameter( request, Constants.PARAM_MAX_ITEMS );
475         BigInteger skipCount = getBigIntegerParameter( request, Constants.PARAM_SKIP_COUNT );
476 
477         // execute
478         ObjectList checkedOut = service.getCheckedOutDocs( repositoryId, folderId, filter, orderBy,
479                 includeAllowableActions, includeRelationships, renditionFilter, maxItems, skipCount, null );
480 
481         if ( checkedOut == null )
482         {
483             throw new CmisRuntimeException( "Checked Out list is null!" );
484         }
485 
486         ObjectInfo folderInfo = null;
487 
488         if ( folderId != null )
489         {
490             folderInfo = service.getObjectInfo( repositoryId, folderId );
491 
492             if ( folderInfo == null )
493             {
494                 throw new CmisRuntimeException( "Folder Object Info is missing!" );
495             }
496         }
497         else
498         {
499             folderInfo = new ObjectInfoImpl(  );
500 
501             GregorianCalendar now = new GregorianCalendar(  );
502 
503             ( (ObjectInfoImpl) folderInfo ).setId( "uri:x-checkedout" );
504             ( (ObjectInfoImpl) folderInfo ).setName( "Checked Out" );
505             ( (ObjectInfoImpl) folderInfo ).setCreatedBy( "" );
506             ( (ObjectInfoImpl) folderInfo ).setCreationDate( now );
507             ( (ObjectInfoImpl) folderInfo ).setLastModificationDate( now );
508             ( (ObjectInfoImpl) folderInfo ).setHasParent( false );
509             ( (ObjectInfoImpl) folderInfo ).setSupportsDescendants( false );
510             ( (ObjectInfoImpl) folderInfo ).setSupportsFolderTree( false );
511         }
512 
513         // set headers
514         response.setStatus( HttpServletResponse.SC_OK );
515         response.setContentType( Constants.MEDIATYPE_FEED );
516 
517         // write XML
518         AtomFeed feed = new AtomFeed(  );
519         feed.startDocument( response.getOutputStream(  ) );
520         feed.startFeed( true );
521 
522         // write basic Atom feed elements
523         feed.writeFeedElements( folderInfo.getId(  ), folderInfo.getCreatedBy(  ), folderInfo.getName(  ),
524             folderInfo.getLastModificationDate(  ), null, checkedOut.getNumItems(  ) );
525 
526         // write links
527         UrlBuilder baseUrl = compileBaseUrl( request, repositoryId );
528 
529         feed.writeServiceLink( baseUrl.toString(  ), repositoryId );
530 
531         feed.writeSelfLink( compileUrl( baseUrl, RESOURCE_CHECKEDOUT, folderInfo.getId(  ) ), null );
532 
533         UrlBuilder pagingUrl = new UrlBuilder( compileUrlBuilder( baseUrl, RESOURCE_CHECKEDOUT, folderInfo.getId(  ) ) );
534         pagingUrl.addParameter( Constants.PARAM_FILTER, filter );
535         pagingUrl.addParameter( Constants.PARAM_ORDER_BY, orderBy );
536         pagingUrl.addParameter( Constants.PARAM_ALLOWABLE_ACTIONS, includeAllowableActions );
537         pagingUrl.addParameter( Constants.PARAM_RELATIONSHIPS, includeRelationships );
538         pagingUrl.addParameter( Constants.PARAM_RENDITION_FILTER, renditionFilter );
539         feed.writePagingLinks( pagingUrl, maxItems, skipCount, checkedOut.getNumItems(  ), checkedOut.hasMoreItems(  ),
540             AtomPubUtils.PAGE_SIZE );
541 
542         // write entries
543         if ( checkedOut.getObjects(  ) != null )
544         {
545             AtomEntry entry = new AtomEntry( feed.getWriter(  ) );
546 
547             for ( ObjectData object : checkedOut.getObjects(  ) )
548             {
549                 if ( object == null )
550                 {
551                     continue;
552                 }
553 
554                 writeObjectEntry( service, entry, object, null, repositoryId, null, null, baseUrl, false );
555             }
556         }
557 
558         // we are done
559         feed.endFeed(  );
560         feed.endDocument(  );
561     }
562 }