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.RepositoryCapabilities;
22  import org.apache.chemistry.opencmis.commons.data.RepositoryInfo;
23  import org.apache.chemistry.opencmis.commons.definitions.TypeDefinition;
24  import org.apache.chemistry.opencmis.commons.definitions.TypeDefinitionContainer;
25  import org.apache.chemistry.opencmis.commons.definitions.TypeDefinitionList;
26  import org.apache.chemistry.opencmis.commons.enums.CapabilityChanges;
27  import org.apache.chemistry.opencmis.commons.enums.CapabilityQuery;
28  import org.apache.chemistry.opencmis.commons.impl.Constants;
29  import org.apache.chemistry.opencmis.commons.impl.UrlBuilder;
30  import org.apache.chemistry.opencmis.commons.server.CallContext;
31  import org.apache.chemistry.opencmis.commons.server.CmisService;
32  import org.apache.chemistry.opencmis.server.impl.CallContextImpl;
33  import static org.apache.chemistry.opencmis.server.impl.atompub.AtomPubUtils.PAGE_SIZE;
34  import static org.apache.chemistry.opencmis.server.impl.atompub.AtomPubUtils.RESOURCE_CHANGES;
35  import static org.apache.chemistry.opencmis.server.impl.atompub.AtomPubUtils.RESOURCE_CHECKEDOUT;
36  import static org.apache.chemistry.opencmis.server.impl.atompub.AtomPubUtils.RESOURCE_CHILDREN;
37  import static org.apache.chemistry.opencmis.server.impl.atompub.AtomPubUtils.RESOURCE_DESCENDANTS;
38  import static org.apache.chemistry.opencmis.server.impl.atompub.AtomPubUtils.RESOURCE_FOLDERTREE;
39  import static org.apache.chemistry.opencmis.server.impl.atompub.AtomPubUtils.RESOURCE_OBJECTBYID;
40  import static org.apache.chemistry.opencmis.server.impl.atompub.AtomPubUtils.RESOURCE_OBJECTBYPATH;
41  import static org.apache.chemistry.opencmis.server.impl.atompub.AtomPubUtils.RESOURCE_QUERY;
42  import static org.apache.chemistry.opencmis.server.impl.atompub.AtomPubUtils.RESOURCE_TYPE;
43  import static org.apache.chemistry.opencmis.server.impl.atompub.AtomPubUtils.RESOURCE_TYPES;
44  import static org.apache.chemistry.opencmis.server.impl.atompub.AtomPubUtils.RESOURCE_TYPESDESC;
45  import static org.apache.chemistry.opencmis.server.impl.atompub.AtomPubUtils.RESOURCE_UNFILED;
46  import static org.apache.chemistry.opencmis.server.impl.atompub.AtomPubUtils.TYPE_AUTHOR;
47  import static org.apache.chemistry.opencmis.server.impl.atompub.AtomPubUtils.compileBaseUrl;
48  import static org.apache.chemistry.opencmis.server.impl.atompub.AtomPubUtils.compileUrl;
49  import static org.apache.chemistry.opencmis.server.impl.atompub.AtomPubUtils.compileUrlBuilder;
50  import static org.apache.chemistry.opencmis.server.impl.atompub.AtomPubUtils.writeTypeEntry;
51  import static org.apache.chemistry.opencmis.server.shared.HttpUtils.getBigIntegerParameter;
52  import static org.apache.chemistry.opencmis.server.shared.HttpUtils.getBooleanParameter;
53  import static org.apache.chemistry.opencmis.server.shared.HttpUtils.getStringParameter;
54  
55  import java.math.BigInteger;
56  
57  import java.util.Collections;
58  import java.util.GregorianCalendar;
59  import java.util.List;
60  
61  import javax.servlet.http.HttpServletRequest;
62  import javax.servlet.http.HttpServletResponse;
63  
64  
65  /**
66   * Repository Service operations.
67   */
68  public final class RepositoryService
69  {
70      /**
71       * Private constructor.
72       */
73      private RepositoryService(  )
74      {
75      }
76  
77      /**
78       * Renders the service document.
79       */
80      public static void getRepositories( CallContext context, CmisService service, HttpServletRequest request,
81          HttpServletResponse response ) throws Exception
82      {
83          // get parameters
84          String repositoryId = getStringParameter( request, Constants.PARAM_REPOSITORY_ID );
85  
86          // execute
87          List<RepositoryInfo> infoDataList = null;
88  
89          if ( repositoryId == null )
90          {
91              infoDataList = service.getRepositoryInfos( null );
92          }
93          else
94          {
95              infoDataList = Collections.singletonList( service.getRepositoryInfo( repositoryId, null ) );
96  
97              if ( context instanceof CallContextImpl )
98              {
99                  ( (CallContextImpl) context ).put( CallContext.REPOSITORY_ID, repositoryId );
100             }
101         }
102 
103         // set headers
104         response.setStatus( HttpServletResponse.SC_OK );
105         response.setContentType( Constants.MEDIATYPE_SERVICE );
106 
107         // write XML
108         ServiceDocument serviceDoc = new ServiceDocument(  );
109 
110         serviceDoc.startDocument( response.getOutputStream(  ) );
111         serviceDoc.startServiceDocument(  );
112 
113         if ( infoDataList != null )
114         {
115             for ( RepositoryInfo infoData : infoDataList )
116             {
117                 if ( infoData == null )
118                 {
119                     continue;
120                 }
121 
122                 String repId = infoData.getId(  );
123                 UrlBuilder baseUrl = compileBaseUrl( request, repId );
124 
125                 boolean supportsQuery = false;
126                 boolean supportsUnFiling = false;
127                 boolean supportsMultifiling = false;
128                 boolean supportsFolderTree = false;
129                 boolean supportsRootDescendants = false;
130                 boolean supportsChanges = false;
131 
132                 if ( infoData.getCapabilities(  ) != null )
133                 {
134                     RepositoryCapabilities cap = infoData.getCapabilities(  );
135 
136                     if ( cap.getQueryCapability(  ) != null )
137                     {
138                         supportsQuery = ( cap.getQueryCapability(  ) != CapabilityQuery.NONE );
139                     }
140 
141                     if ( cap.isUnfilingSupported(  ) != null )
142                     {
143                         supportsUnFiling = cap.isUnfilingSupported(  );
144                     }
145 
146                     if ( cap.isMultifilingSupported(  ) != null )
147                     {
148                         supportsMultifiling = cap.isMultifilingSupported(  );
149                     }
150 
151                     if ( cap.isGetFolderTreeSupported(  ) != null )
152                     {
153                         supportsFolderTree = cap.isGetFolderTreeSupported(  );
154                     }
155 
156                     if ( cap.isGetDescendantsSupported(  ) != null )
157                     {
158                         supportsRootDescendants = cap.isGetDescendantsSupported(  );
159                     }
160 
161                     if ( cap.getChangesCapability(  ) != null )
162                     {
163                         supportsChanges = ( cap.getChangesCapability(  ) != CapabilityChanges.NONE );
164                     }
165                 }
166 
167                 serviceDoc.startWorkspace( infoData.getId(  ) );
168 
169                 // add collections
170 
171                 // - root collection
172                 serviceDoc.writeCollection( compileUrl( baseUrl, RESOURCE_CHILDREN, infoData.getRootFolderId(  ) ),
173                     Constants.COLLECTION_ROOT, "Root Collection", Constants.MEDIATYPE_ENTRY,
174                     Constants.MEDIATYPE_CMISATOM );
175 
176                 // - types collection
177                 serviceDoc.writeCollection( compileUrl( baseUrl, RESOURCE_TYPES, null ), Constants.COLLECTION_TYPES,
178                     "Types Collection", "" );
179 
180                 // - query collection
181                 if ( supportsQuery )
182                 {
183                     serviceDoc.writeCollection( compileUrl( baseUrl, RESOURCE_QUERY, null ),
184                         Constants.COLLECTION_QUERY, "Query Collection", Constants.MEDIATYPE_QUERY );
185                 }
186 
187                 // - checked out collection collection
188                 serviceDoc.writeCollection( compileUrl( baseUrl, RESOURCE_CHECKEDOUT, null ),
189                     Constants.COLLECTION_CHECKEDOUT, "Checked Out Collection", Constants.MEDIATYPE_CMISATOM );
190 
191                 // - unfiled collection collection
192                 if ( supportsUnFiling || supportsMultifiling )
193                 {
194                     serviceDoc.writeCollection( compileUrl( baseUrl, RESOURCE_UNFILED, null ),
195                         Constants.COLLECTION_UNFILED, "Unfiled Collection", Constants.MEDIATYPE_CMISATOM );
196                 }
197 
198                 // add repository info
199                 serviceDoc.writeRepositoryInfo( infoData );
200 
201                 // add links
202 
203                 // - types descendants
204                 serviceDoc.writeLink( Constants.REP_REL_TYPEDESC, compileUrl( baseUrl, RESOURCE_TYPESDESC, null ),
205                     Constants.MEDIATYPE_FEED, null );
206 
207                 // - folder tree
208                 if ( supportsFolderTree )
209                 {
210                     serviceDoc.writeLink( Constants.REP_REL_FOLDERTREE,
211                         compileUrl( baseUrl, RESOURCE_FOLDERTREE, infoData.getRootFolderId(  ) ),
212                         Constants.MEDIATYPE_DESCENDANTS, null );
213                 }
214 
215                 // - root descendants
216                 if ( supportsRootDescendants )
217                 {
218                     serviceDoc.writeLink( Constants.REP_REL_ROOTDESC,
219                         compileUrl( baseUrl, RESOURCE_DESCENDANTS, infoData.getRootFolderId(  ) ),
220                         Constants.MEDIATYPE_DESCENDANTS, infoData.getRootFolderId(  ) );
221                 }
222 
223                 // - changes
224                 if ( supportsChanges )
225                 {
226                     serviceDoc.writeLink( Constants.REP_REL_CHANGES, compileUrl( baseUrl, RESOURCE_CHANGES, null ),
227                         Constants.MEDIATYPE_FEED, null );
228                 }
229 
230                 // add URI templates
231 
232                 // - object by id
233                 String url = compileUrl( baseUrl, RESOURCE_OBJECTBYID, null ) +
234                     "?id={id}&filter={filter}&includeAllowableActions={includeAllowableActions}&includeACL={includeACL}&includePolicyIds={includePolicyIds}&includeRelationships={includeRelationships}&renditionFilter={renditionFilter}";
235                 serviceDoc.writeUriTemplate( url, Constants.TEMPLATE_OBJECT_BY_ID, Constants.MEDIATYPE_ENTRY );
236 
237                 // - object by path
238                 url = compileUrl( baseUrl, RESOURCE_OBJECTBYPATH, null ) +
239                     "?path={path}&filter={filter}&includeAllowableActions={includeAllowableActions}&includeACL={includeACL}&includePolicyIds={includePolicyIds}&includeRelationships={includeRelationships}&renditionFilter={renditionFilter}";
240                 serviceDoc.writeUriTemplate( url, Constants.TEMPLATE_OBJECT_BY_PATH, Constants.MEDIATYPE_ENTRY );
241 
242                 // - type by id
243                 url = compileUrl( baseUrl, RESOURCE_TYPE, null ) + "?id={id}";
244                 serviceDoc.writeUriTemplate( url, Constants.TEMPLATE_TYPE_BY_ID, Constants.MEDIATYPE_ENTRY );
245 
246                 // - query
247                 if ( supportsQuery )
248                 {
249                     url = compileUrl( baseUrl, RESOURCE_QUERY, null ) +
250                         "?q={q}&searchAllVersions={searchAllVersions}&includeAllowableActions={includeAllowableActions}&includeRelationships={includeRelationships}&maxItems={maxItems}&skipCount={skipCount}";
251                     serviceDoc.writeUriTemplate( url, Constants.TEMPLATE_QUERY, Constants.MEDIATYPE_FEED );
252                 }
253 
254                 serviceDoc.endWorkspace(  );
255             }
256         }
257 
258         serviceDoc.endServiceDocument(  );
259         serviceDoc.endDocument(  );
260     }
261 
262     /**
263      * Renders a type children collection.
264      */
265     public static void getTypeChildren( CallContext context, CmisService service, String repositoryId,
266         HttpServletRequest request, HttpServletResponse response )
267         throws Exception
268     {
269         // get parameters
270         String typeId = getStringParameter( request, Constants.PARAM_TYPE_ID );
271         boolean includePropertyDefinitions = getBooleanParameter( request, Constants.PARAM_PROPERTY_DEFINITIONS, false );
272         BigInteger maxItems = getBigIntegerParameter( request, Constants.PARAM_MAX_ITEMS );
273         BigInteger skipCount = getBigIntegerParameter( request, Constants.PARAM_SKIP_COUNT );
274 
275         // execute
276         TypeDefinitionList typeList = service.getTypeChildren( repositoryId, typeId, includePropertyDefinitions,
277                 maxItems, skipCount, null );
278 
279         BigInteger numItems = ( ( typeList == null ) ? null : typeList.getNumItems(  ) );
280         Boolean hasMoreItems = ( ( typeList == null ) ? null : typeList.hasMoreItems(  ) );
281 
282         String parentTypeId = null;
283         String typeName = "Type Children";
284 
285         // in order to get the parent type, we need the type definition of this
286         // type as well
287         if ( typeId != null )
288         {
289             TypeDefinition typeDefinition = service.getTypeDefinition( repositoryId, typeId, null );
290 
291             parentTypeId = ( ( typeDefinition == null ) ? null : typeDefinition.getParentTypeId(  ) );
292             typeName = ( ( typeDefinition == null ) ? typeId : typeDefinition.getDisplayName(  ) );
293         }
294 
295         // write XML
296         response.setStatus( HttpServletResponse.SC_OK );
297         response.setContentType( Constants.MEDIATYPE_FEED );
298 
299         AtomFeed feed = new AtomFeed(  );
300         feed.startDocument( response.getOutputStream(  ) );
301         feed.startFeed( true );
302 
303         // write basic Atom feed elements
304         feed.writeFeedElements( typeId, TYPE_AUTHOR, typeName, new GregorianCalendar(  ), null, numItems );
305 
306         // write links
307         UrlBuilder baseUrl = compileBaseUrl( request, repositoryId );
308 
309         feed.writeServiceLink( baseUrl.toString(  ), repositoryId );
310 
311         UrlBuilder selfLink = compileUrlBuilder( baseUrl, RESOURCE_TYPES, null );
312         selfLink.addParameter( Constants.PARAM_TYPE_ID, typeId );
313         selfLink.addParameter( Constants.PARAM_PROPERTY_DEFINITIONS, includePropertyDefinitions );
314         feed.writeSelfLink( selfLink.toString(  ), typeId );
315 
316         feed.writeViaLink( compileUrl( baseUrl, RESOURCE_TYPE, typeId ) );
317 
318         UrlBuilder downLink = compileUrlBuilder( baseUrl, RESOURCE_TYPESDESC, null );
319         downLink.addParameter( Constants.PARAM_TYPE_ID, typeId );
320         feed.writeDownLink( downLink.toString(  ), Constants.MEDIATYPE_DESCENDANTS );
321 
322         if ( parentTypeId != null )
323         {
324             feed.writeUpLink( compileUrl( baseUrl, RESOURCE_TYPE, parentTypeId ), Constants.MEDIATYPE_ENTRY );
325         }
326 
327         // write paging links
328         UrlBuilder pagingUrl = compileUrlBuilder( baseUrl, RESOURCE_TYPES, null );
329         pagingUrl.addParameter( Constants.PARAM_TYPE_ID, typeId );
330         pagingUrl.addParameter( Constants.PARAM_PROPERTY_DEFINITIONS, includePropertyDefinitions );
331         feed.writePagingLinks( pagingUrl, maxItems, skipCount, numItems, hasMoreItems, PAGE_SIZE );
332 
333         // write collection
334         UrlBuilder collectionUrl = compileUrlBuilder( baseUrl, RESOURCE_TYPES, null );
335         collectionUrl.addParameter( Constants.PARAM_TYPE_ID, typeId );
336         feed.writeCollection( collectionUrl.toString(  ), null, "Types Collection", "" );
337 
338         // write type entries
339         if ( ( typeList != null ) && ( typeList.getList(  ) != null ) )
340         {
341             AtomEntry entry = new AtomEntry( feed.getWriter(  ) );
342 
343             for ( TypeDefinition type : typeList.getList(  ) )
344             {
345                 writeTypeEntry( entry, type, null, repositoryId, baseUrl, false );
346             }
347         }
348 
349         // we are done
350         feed.endFeed(  );
351         feed.endDocument(  );
352     }
353 
354     /**
355      * Renders a type descendants feed.
356      */
357     public static void getTypeDescendants( CallContext context, CmisService service, String repositoryId,
358         HttpServletRequest request, HttpServletResponse response )
359         throws Exception
360     {
361         // get parameters
362         String typeId = getStringParameter( request, Constants.PARAM_TYPE_ID );
363         BigInteger depth = getBigIntegerParameter( request, Constants.PARAM_DEPTH );
364         boolean includePropertyDefinitions = getBooleanParameter( request, Constants.PARAM_PROPERTY_DEFINITIONS, false );
365 
366         // execute
367         List<TypeDefinitionContainer> typeTree = service.getTypeDescendants( repositoryId, typeId, depth,
368                 includePropertyDefinitions, null );
369 
370         String parentTypeId = null;
371         String typeName = "Type Children";
372 
373         // in order to get the parent type, we need the type definition of this
374         // type as well
375         if ( typeId != null )
376         {
377             TypeDefinition typeDefinition = service.getTypeDefinition( repositoryId, typeId, null );
378 
379             parentTypeId = ( ( typeDefinition == null ) ? null : typeDefinition.getParentTypeId(  ) );
380             typeName = ( ( typeDefinition == null ) ? typeId : typeDefinition.getDisplayName(  ) );
381         }
382 
383         // write XML
384         response.setStatus( HttpServletResponse.SC_OK );
385         response.setContentType( Constants.MEDIATYPE_FEED );
386 
387         AtomFeed feed = new AtomFeed(  );
388         feed.startDocument( response.getOutputStream(  ) );
389         feed.startFeed( true );
390 
391         // write basic Atom feed elements
392         feed.writeFeedElements( typeId, TYPE_AUTHOR, typeName, new GregorianCalendar(  ), null, null );
393 
394         // write links
395         UrlBuilder baseUrl = compileBaseUrl( request, repositoryId );
396 
397         feed.writeServiceLink( baseUrl.toString(  ), repositoryId );
398 
399         UrlBuilder selfLink = compileUrlBuilder( baseUrl, RESOURCE_TYPESDESC, null );
400         selfLink.addParameter( Constants.PARAM_TYPE_ID, typeId );
401         selfLink.addParameter( Constants.PARAM_DEPTH, depth );
402         selfLink.addParameter( Constants.PARAM_PROPERTY_DEFINITIONS, includePropertyDefinitions );
403         feed.writeSelfLink( selfLink.toString(  ), typeId );
404 
405         feed.writeViaLink( compileUrl( baseUrl, RESOURCE_TYPE, typeId ) );
406 
407         UrlBuilder downLink = compileUrlBuilder( baseUrl, RESOURCE_TYPES, null );
408         downLink.addParameter( Constants.PARAM_TYPE_ID, typeId );
409         feed.writeDownLink( downLink.toString(  ), Constants.MEDIATYPE_FEED );
410 
411         if ( parentTypeId != null )
412         {
413             feed.writeUpLink( compileUrl( baseUrl, RESOURCE_TYPE, parentTypeId ), Constants.MEDIATYPE_ENTRY );
414         }
415 
416         // write tree
417         if ( typeTree != null )
418         {
419             AtomEntry entry = new AtomEntry( feed.getWriter(  ) );
420 
421             for ( TypeDefinitionContainer container : typeTree )
422             {
423                 if ( ( container != null ) && ( container.getTypeDefinition(  ) != null ) )
424                 {
425                     writeTypeEntry( entry, container.getTypeDefinition(  ), container.getChildren(  ), repositoryId,
426                         baseUrl, false );
427                 }
428             }
429         }
430 
431         // we are done
432         feed.endFeed(  );
433         feed.endDocument(  );
434     }
435 
436     /**
437      * Renders a type definition.
438      */
439     public static void getTypeDefinition( CallContext context, CmisService service, String repositoryId,
440         HttpServletRequest request, HttpServletResponse response )
441         throws Exception
442     {
443         // get parameters
444         String typeId = getStringParameter( request, Constants.PARAM_ID );
445 
446         // execute
447         TypeDefinition type = service.getTypeDefinition( repositoryId, typeId, null );
448 
449         // write XML
450         response.setStatus( HttpServletResponse.SC_OK );
451         response.setContentType( Constants.MEDIATYPE_ENTRY );
452 
453         AtomEntry entry = new AtomEntry(  );
454         entry.startDocument( response.getOutputStream(  ) );
455         writeTypeEntry( entry, type, null, repositoryId, compileBaseUrl( request, repositoryId ), true );
456         entry.endDocument(  );
457     }
458 }