1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 package org.apache.chemistry.opencmis.server.impl.atompub;
24
25 import org.apache.chemistry.opencmis.commons.data.ObjectData;
26 import org.apache.chemistry.opencmis.commons.data.ObjectInFolderContainer;
27 import org.apache.chemistry.opencmis.commons.definitions.TypeDefinition;
28 import org.apache.chemistry.opencmis.commons.definitions.TypeDefinitionContainer;
29 import org.apache.chemistry.opencmis.commons.enums.BaseTypeId;
30 import org.apache.chemistry.opencmis.commons.exceptions.CmisRuntimeException;
31 import org.apache.chemistry.opencmis.commons.impl.Constants;
32 import org.apache.chemistry.opencmis.commons.impl.ReturnVersion;
33 import org.apache.chemistry.opencmis.commons.impl.UrlBuilder;
34 import org.apache.chemistry.opencmis.commons.server.CmisService;
35 import org.apache.chemistry.opencmis.commons.server.ObjectInfo;
36 import org.apache.chemistry.opencmis.commons.server.RenditionInfo;
37
38 import java.math.BigInteger;
39
40 import java.util.GregorianCalendar;
41 import java.util.List;
42
43 import javax.servlet.http.HttpServletRequest;
44
45 import javax.xml.bind.JAXBException;
46 import javax.xml.stream.XMLStreamException;
47
48
49
50
51
52 public final class AtomPubUtils
53 {
54 public static final String RESOURCE_CHILDREN = "children";
55 public static final String RESOURCE_DESCENDANTS = "descendants";
56 public static final String RESOURCE_FOLDERTREE = "foldertree";
57 public static final String RESOURCE_TYPE = "type";
58 public static final String RESOURCE_TYPES = "types";
59 public static final String RESOURCE_TYPESDESC = "typedesc";
60 public static final String RESOURCE_ENTRY = "entry";
61 public static final String RESOURCE_PARENTS = "parents";
62 public static final String RESOURCE_VERSIONS = "versions";
63 public static final String RESOURCE_ALLOWABLEACIONS = "allowableactions";
64 public static final String RESOURCE_ACL = "acl";
65 public static final String RESOURCE_POLICIES = "policies";
66 public static final String RESOURCE_RELATIONSHIPS = "relationships";
67 public static final String RESOURCE_OBJECTBYID = "id";
68 public static final String RESOURCE_OBJECTBYPATH = "path";
69 public static final String RESOURCE_QUERY = "query";
70 public static final String RESOURCE_CHECKEDOUT = "checkedout";
71 public static final String RESOURCE_UNFILED = "unfiled";
72 public static final String RESOURCE_CHANGES = "changes";
73 public static final String RESOURCE_CONTENT = "content";
74 public static final BigInteger PAGE_SIZE = BigInteger.valueOf( 100 );
75 public static final String TYPE_AUTHOR = "unknown";
76
77
78
79
80 private AtomPubUtils( )
81 {
82 }
83
84
85
86
87 public static UrlBuilder compileBaseUrl( HttpServletRequest request, String repositoryId )
88 {
89 UrlBuilder url = new UrlBuilder( request.getScheme( ), request.getServerName( ), request.getServerPort( ),
90 null );
91
92 url.addPath( request.getContextPath( ) );
93 url.addPath( request.getServletPath( ) );
94 url.addPath( "/document/cmis/atom/" );
95
96 if ( repositoryId != null )
97 {
98 url.addPathSegment( repositoryId );
99 }
100
101 return url;
102 }
103
104
105
106
107 public static String compileUrl( UrlBuilder baseUrl, String resource, String id )
108 {
109 return compileUrlBuilder( baseUrl, resource, id ).toString( );
110 }
111
112
113
114
115 public static UrlBuilder compileUrlBuilder( UrlBuilder baseUrl, String resource, String id )
116 {
117 UrlBuilder url = new UrlBuilder( baseUrl );
118 url.addPathSegment( resource );
119
120 if ( id != null )
121 {
122 url.addParameter( "id", id );
123 }
124
125 return url;
126 }
127
128
129
130
131
132
133
134
135 public static void writeObjectEntry( CmisService service, AtomEntry entry, ObjectData object,
136 List<ObjectInFolderContainer> children, String repositoryId, String pathSegment, String relativePathSegment,
137 UrlBuilder baseUrl, boolean isRoot ) throws XMLStreamException, JAXBException
138 {
139 if ( object == null )
140 {
141 throw new CmisRuntimeException( "Object not set!" );
142 }
143
144 ObjectInfo info = service.getObjectInfo( repositoryId, object.getId( ) );
145
146 if ( info == null )
147 {
148 throw new CmisRuntimeException( "Object Info not found for: " + object.getId( ) );
149 }
150
151
152 entry.startEntry( isRoot );
153
154
155 String contentSrc = null;
156
157 if ( info.hasContent( ) )
158 {
159 UrlBuilder contentSrcBuilder = compileUrlBuilder( baseUrl, RESOURCE_CONTENT, info.getId( ) );
160
161 if ( info.getFileName( ) != null )
162 {
163 contentSrcBuilder.addPathSegment( info.getFileName( ) );
164 }
165
166 contentSrc = contentSrcBuilder.toString( );
167 }
168
169 entry.writeObject( object, info, contentSrc, info.getContentType( ), pathSegment, relativePathSegment );
170
171
172 entry.writeServiceLink( baseUrl.toString( ), repositoryId );
173
174 entry.writeSelfLink( compileUrl( baseUrl, RESOURCE_ENTRY, info.getId( ) ), info.getId( ) );
175 entry.writeEnclosureLink( compileUrl( baseUrl, RESOURCE_ENTRY, info.getId( ) ) );
176 entry.writeEditLink( compileUrl( baseUrl, RESOURCE_ENTRY, info.getId( ) ) );
177 entry.writeDescribedByLink( compileUrl( baseUrl, RESOURCE_TYPE, info.getTypeId( ) ) );
178 entry.writeAllowableActionsLink( compileUrl( baseUrl, RESOURCE_ALLOWABLEACIONS, info.getId( ) ) );
179
180 if ( info.hasParent( ) )
181 {
182 entry.writeUpLink( compileUrl( baseUrl, RESOURCE_PARENTS, info.getId( ) ), Constants.MEDIATYPE_FEED );
183 }
184
185 if ( info.getBaseType( ) == BaseTypeId.CMIS_FOLDER )
186 {
187 entry.writeDownLink( compileUrl( baseUrl, RESOURCE_CHILDREN, info.getId( ) ), Constants.MEDIATYPE_FEED );
188
189 if ( info.supportsDescendants( ) )
190 {
191 entry.writeDownLink( compileUrl( baseUrl, RESOURCE_DESCENDANTS, info.getId( ) ),
192 Constants.MEDIATYPE_DESCENDANTS );
193 }
194
195 if ( info.supportsFolderTree( ) )
196 {
197 entry.writeFolderTreeLink( compileUrl( baseUrl, RESOURCE_FOLDERTREE, info.getId( ) ) );
198 }
199 }
200
201 if ( info.getVersionSeriesId( ) != null )
202 {
203 UrlBuilder vsUrl = compileUrlBuilder( baseUrl, RESOURCE_VERSIONS, info.getId( ) );
204 vsUrl.addParameter( Constants.PARAM_VERSION_SERIES_ID, info.getVersionSeriesId( ) );
205 entry.writeVersionHistoryLink( vsUrl.toString( ) );
206 }
207
208 if ( !info.isCurrentVersion( ) )
209 {
210 UrlBuilder cvUrl = compileUrlBuilder( baseUrl, RESOURCE_ENTRY, info.getId( ) );
211 cvUrl.addParameter( Constants.PARAM_RETURN_VERSION, ReturnVersion.LATEST );
212 entry.writeEditLink( cvUrl.toString( ) );
213 }
214
215 if ( info.getBaseType( ) == BaseTypeId.CMIS_DOCUMENT )
216 {
217 entry.writeEditMediaLink( compileUrl( baseUrl, RESOURCE_CONTENT, info.getId( ) ), info.getContentType( ) );
218 }
219
220 if ( info.getWorkingCopyId( ) != null )
221 {
222 entry.writeWorkingCopyLink( compileUrl( baseUrl, RESOURCE_ENTRY, info.getWorkingCopyId( ) ) );
223 }
224
225 if ( info.getWorkingCopyOriginalId( ) != null )
226 {
227 entry.writeViaLink( compileUrl( baseUrl, RESOURCE_ENTRY, info.getWorkingCopyOriginalId( ) ) );
228 }
229
230 if ( info.getRenditionInfos( ) != null )
231 {
232 for ( RenditionInfo ri : info.getRenditionInfos( ) )
233 {
234 UrlBuilder rurl = compileUrlBuilder( baseUrl, RESOURCE_CONTENT, info.getId( ) );
235 rurl.addParameter( Constants.PARAM_STREAM_ID, ri.getId( ) );
236 entry.writeAlternateLink( rurl.toString( ), ri.getContenType( ), ri.getKind( ), ri.getTitle( ),
237 ri.getLength( ) );
238 }
239 }
240
241 if ( info.hasAcl( ) )
242 {
243 entry.writeAclLink( compileUrl( baseUrl, RESOURCE_ACL, info.getId( ) ) );
244 }
245
246 if ( info.supportsPolicies( ) )
247 {
248 entry.writePoliciesLink( compileUrl( baseUrl, RESOURCE_POLICIES, info.getId( ) ) );
249 }
250
251 if ( info.supportsRelationships( ) )
252 {
253 entry.writeRelationshipsLink( compileUrl( baseUrl, RESOURCE_RELATIONSHIPS, info.getId( ) ) );
254 }
255
256 if ( info.getRelationshipSourceIds( ) != null )
257 {
258 for ( String id : info.getRelationshipSourceIds( ) )
259 {
260 entry.writeRelationshipSourceLink( compileUrl( baseUrl, RESOURCE_ENTRY, id ) );
261 }
262 }
263
264 if ( info.getRelationshipTargetIds( ) != null )
265 {
266 for ( String id : info.getRelationshipTargetIds( ) )
267 {
268 entry.writeRelationshipTargetLink( compileUrl( baseUrl, RESOURCE_ENTRY, id ) );
269 }
270 }
271
272
273 if ( ( children != null ) && ( children.size( ) > 0 ) )
274 {
275 writeObjectChildren( service, entry, info, children, repositoryId, baseUrl );
276 }
277
278
279 entry.endEntry( );
280 }
281
282
283
284
285
286
287
288 public static void writeContentChangesObjectEntry( CmisService service, AtomEntry entry, ObjectData object,
289 List<ObjectInFolderContainer> children, String repositoryId, String pathSegment, String relativePathSegment,
290 UrlBuilder baseUrl, boolean isRoot ) throws XMLStreamException, JAXBException
291 {
292 if ( object == null )
293 {
294 throw new CmisRuntimeException( "Object not set!" );
295 }
296
297 ObjectInfo info = null;
298
299 try
300 {
301 info = service.getObjectInfo( repositoryId, object.getId( ) );
302 }
303 catch ( Exception e )
304 {
305
306 }
307
308 if ( info != null )
309 {
310 writeObjectEntry( service, entry, object, children, repositoryId, pathSegment, relativePathSegment,
311 baseUrl, isRoot );
312
313 return;
314 }
315
316
317 entry.startEntry( isRoot );
318
319
320 entry.writeDeletedObject( object );
321
322
323 entry.writeServiceLink( baseUrl.toString( ), repositoryId );
324
325
326 entry.endEntry( );
327 }
328
329
330
331
332 public static void writeObjectChildren( CmisService service, AtomEntry entry, ObjectInfo folderInfo,
333 List<ObjectInFolderContainer> children, String repositoryId, UrlBuilder baseUrl )
334 throws XMLStreamException, JAXBException
335 {
336
337 AtomFeed feed = new AtomFeed( entry.getWriter( ) );
338 feed.startChildren( );
339 feed.startFeed( false );
340
341
342 feed.writeFeedElements( folderInfo.getId( ), folderInfo.getCreatedBy( ), folderInfo.getName( ),
343 folderInfo.getLastModificationDate( ), null, null );
344
345
346 feed.writeServiceLink( baseUrl.toString( ), repositoryId );
347
348 feed.writeSelfLink( compileUrl( baseUrl, RESOURCE_DESCENDANTS, folderInfo.getId( ) ), null );
349
350 feed.writeViaLink( compileUrl( baseUrl, RESOURCE_ENTRY, folderInfo.getId( ) ) );
351
352 feed.writeDownLink( compileUrl( baseUrl, RESOURCE_CHILDREN, folderInfo.getId( ) ), Constants.MEDIATYPE_FEED );
353
354 feed.writeDownLink( compileUrl( baseUrl, RESOURCE_FOLDERTREE, folderInfo.getId( ) ),
355 Constants.MEDIATYPE_DESCENDANTS );
356
357 feed.writeUpLink( compileUrl( baseUrl, RESOURCE_PARENTS, folderInfo.getId( ) ), Constants.MEDIATYPE_FEED );
358
359 for ( ObjectInFolderContainer container : children )
360 {
361 if ( ( container != null ) && ( container.getObject( ) != null ) )
362 {
363 writeObjectEntry( service, entry, container.getObject( ).getObject( ), container.getChildren( ),
364 repositoryId, container.getObject( ).getPathSegment( ), null, baseUrl, false );
365 }
366 }
367
368
369 feed.endFeed( );
370 feed.endChildren( );
371 }
372
373
374
375
376 public static void writeTypeEntry( AtomEntry entry, TypeDefinition type, List<TypeDefinitionContainer> children,
377 String repositoryId, UrlBuilder baseUrl, boolean isRoot )
378 throws XMLStreamException, JAXBException
379 {
380
381 entry.startEntry( isRoot );
382
383
384 entry.writeType( type );
385
386
387 entry.writeServiceLink( baseUrl.toString( ), repositoryId );
388
389 entry.writeSelfLink( compileUrl( baseUrl, RESOURCE_TYPE, type.getId( ) ), type.getId( ) );
390 entry.writeEnclosureLink( compileUrl( baseUrl, RESOURCE_TYPE, type.getId( ) ) );
391
392 if ( type.getParentTypeId( ) != null )
393 {
394 entry.writeUpLink( compileUrl( baseUrl, RESOURCE_TYPE, type.getParentTypeId( ) ), Constants.MEDIATYPE_ENTRY );
395 }
396
397 UrlBuilder downLink = compileUrlBuilder( baseUrl, RESOURCE_TYPES, null );
398 downLink.addParameter( Constants.PARAM_TYPE_ID, type.getId( ) );
399 entry.writeDownLink( downLink.toString( ), Constants.MEDIATYPE_CHILDREN );
400
401 UrlBuilder downLink2 = compileUrlBuilder( baseUrl, RESOURCE_TYPESDESC, null );
402 downLink2.addParameter( Constants.PARAM_TYPE_ID, type.getId( ) );
403 entry.writeDownLink( downLink2.toString( ), Constants.MEDIATYPE_DESCENDANTS );
404 entry.writeDescribedByLink( compileUrl( baseUrl, RESOURCE_TYPE, type.getBaseTypeId( ).value( ) ) );
405
406
407 if ( ( children != null ) && ( children.size( ) > 0 ) )
408 {
409 writeTypeChildren( entry, type, children, repositoryId, baseUrl );
410 }
411
412
413 entry.endEntry( );
414 }
415
416
417
418
419 private static void writeTypeChildren( AtomEntry entry, TypeDefinition type,
420 List<TypeDefinitionContainer> children, String repositoryId, UrlBuilder baseUrl )
421 throws XMLStreamException, JAXBException
422 {
423
424 AtomFeed feed = new AtomFeed( entry.getWriter( ) );
425 feed.startChildren( );
426 feed.startFeed( false );
427
428
429 feed.writeFeedElements( type.getId( ), TYPE_AUTHOR, type.getDisplayName( ), new GregorianCalendar( ), null,
430 null );
431
432 feed.writeServiceLink( baseUrl.toString( ), repositoryId );
433
434 UrlBuilder selfLink = compileUrlBuilder( baseUrl, RESOURCE_TYPESDESC, null );
435 selfLink.addParameter( Constants.PARAM_TYPE_ID, type.getId( ) );
436 feed.writeSelfLink( selfLink.toString( ), type.getId( ) );
437
438 feed.writeViaLink( compileUrl( baseUrl, RESOURCE_TYPE, type.getId( ) ) );
439
440 UrlBuilder downLink = compileUrlBuilder( baseUrl, RESOURCE_TYPES, null );
441 downLink.addParameter( Constants.PARAM_TYPE_ID, type.getId( ) );
442 feed.writeDownLink( downLink.toString( ), Constants.MEDIATYPE_FEED );
443
444 if ( type.getParentTypeId( ) != null )
445 {
446 feed.writeUpLink( compileUrl( baseUrl, RESOURCE_TYPE, type.getParentTypeId( ) ), Constants.MEDIATYPE_ENTRY );
447 }
448
449
450 for ( TypeDefinitionContainer container : children )
451 {
452 if ( ( container != null ) && ( container.getTypeDefinition( ) != null ) )
453 {
454 writeTypeEntry( entry, container.getTypeDefinition( ), container.getChildren( ), repositoryId,
455 baseUrl, false );
456 }
457 }
458
459
460 feed.endFeed( );
461 feed.endChildren( );
462 }
463 }