1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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.ObjectList;
23 import org.apache.chemistry.opencmis.commons.enums.IncludeRelationships;
24 import org.apache.chemistry.opencmis.commons.exceptions.CmisInvalidArgumentException;
25 import org.apache.chemistry.opencmis.commons.exceptions.CmisRuntimeException;
26 import org.apache.chemistry.opencmis.commons.impl.Constants;
27 import static org.apache.chemistry.opencmis.commons.impl.Converter.convert;
28 import org.apache.chemistry.opencmis.commons.impl.JaxBHelper;
29 import org.apache.chemistry.opencmis.commons.impl.UrlBuilder;
30 import org.apache.chemistry.opencmis.commons.impl.jaxb.CmisObjectType;
31 import org.apache.chemistry.opencmis.commons.impl.jaxb.CmisQueryType;
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.spi.Holder;
35 import static org.apache.chemistry.opencmis.server.impl.atompub.AtomPubUtils.RESOURCE_CHANGES;
36 import static org.apache.chemistry.opencmis.server.impl.atompub.AtomPubUtils.RESOURCE_QUERY;
37 import static org.apache.chemistry.opencmis.server.impl.atompub.AtomPubUtils.compileBaseUrl;
38 import static org.apache.chemistry.opencmis.server.impl.atompub.AtomPubUtils.compileUrlBuilder;
39 import static org.apache.chemistry.opencmis.server.impl.atompub.AtomPubUtils.writeContentChangesObjectEntry;
40 import static org.apache.chemistry.opencmis.server.shared.HttpUtils.getBigIntegerParameter;
41 import static org.apache.chemistry.opencmis.server.shared.HttpUtils.getBooleanParameter;
42 import static org.apache.chemistry.opencmis.server.shared.HttpUtils.getEnumParameter;
43 import static org.apache.chemistry.opencmis.server.shared.HttpUtils.getStringParameter;
44
45 import java.math.BigInteger;
46
47 import java.util.GregorianCalendar;
48
49 import javax.servlet.http.HttpServletRequest;
50 import javax.servlet.http.HttpServletResponse;
51
52 import javax.xml.bind.JAXBElement;
53 import javax.xml.bind.Unmarshaller;
54
55
56
57
58
59 public class DiscoveryService
60 {
61 private static final String METHOD_GET = "GET";
62 private static final String METHOD_POST = "POST";
63
64 private DiscoveryService( )
65 {
66 }
67
68
69
70
71 public static void query( CallContext context, CmisService service, String repositoryId,
72 HttpServletRequest request, HttpServletResponse response )
73 throws Exception
74 {
75
76 String statement = null;
77 Boolean searchAllVersions = null;
78 Boolean includeAllowableActions = null;
79 IncludeRelationships includeRelationships = null;
80 String renditionFilter = null;
81 BigInteger maxItems = null;
82 BigInteger skipCount = null;
83
84 int statusCode = 0;
85
86 if ( METHOD_POST.equals( request.getMethod( ) ) )
87 {
88
89 Object queryRequest = null;
90
91 try
92 {
93 Unmarshaller u = JaxBHelper.createUnmarshaller( );
94 queryRequest = u.unmarshal( request.getInputStream( ) );
95 }
96 catch ( Exception e )
97 {
98 throw new CmisInvalidArgumentException( "Invalid query request: " + e, e );
99 }
100
101 if ( !( queryRequest instanceof JAXBElement<?> ) )
102 {
103 throw new CmisInvalidArgumentException( "Not a query document!" );
104 }
105
106 if ( !( ( (JAXBElement<?>) queryRequest ).getValue( ) instanceof CmisQueryType ) )
107 {
108 throw new CmisInvalidArgumentException( "Not a query document!" );
109 }
110
111 CmisQueryType queryType = (CmisQueryType) ( (JAXBElement<?>) queryRequest ).getValue( );
112
113 statement = queryType.getStatement( );
114 searchAllVersions = queryType.isSearchAllVersions( );
115 includeAllowableActions = queryType.isIncludeAllowableActions( );
116 includeRelationships = convert( IncludeRelationships.class, queryType.getIncludeRelationships( ) );
117 renditionFilter = queryType.getRenditionFilter( );
118 maxItems = queryType.getMaxItems( );
119 skipCount = queryType.getSkipCount( );
120
121 statusCode = HttpServletResponse.SC_CREATED;
122 }
123 else if ( METHOD_GET.equals( request.getMethod( ) ) )
124 {
125
126 statement = getStringParameter( request, Constants.PARAM_Q );
127 searchAllVersions = getBooleanParameter( request, Constants.PARAM_SEARCH_ALL_VERSIONS );
128 includeAllowableActions = getBooleanParameter( request, Constants.PARAM_ALLOWABLE_ACTIONS );
129 includeRelationships = getEnumParameter( request, Constants.PARAM_RELATIONSHIPS, IncludeRelationships.class );
130 renditionFilter = null;
131 maxItems = getBigIntegerParameter( request, Constants.PARAM_MAX_ITEMS );
132 skipCount = getBigIntegerParameter( request, Constants.PARAM_SKIP_COUNT );
133
134 statusCode = HttpServletResponse.SC_OK;
135 }
136 else
137 {
138 throw new CmisRuntimeException( "Invalid HTTP method!" );
139 }
140
141
142 ObjectList results = service.query( repositoryId, statement, searchAllVersions, includeAllowableActions,
143 includeRelationships, renditionFilter, maxItems, skipCount, null );
144
145 if ( results == null )
146 {
147 throw new CmisRuntimeException( "Results are null!" );
148 }
149
150
151 UrlBuilder baseUrl = compileBaseUrl( request, repositoryId );
152
153 UrlBuilder pagingUrl = compileUrlBuilder( baseUrl, RESOURCE_QUERY, null );
154 pagingUrl.addParameter( Constants.PARAM_Q, statement );
155 pagingUrl.addParameter( Constants.PARAM_SEARCH_ALL_VERSIONS, searchAllVersions );
156 pagingUrl.addParameter( Constants.PARAM_ALLOWABLE_ACTIONS, includeAllowableActions );
157 pagingUrl.addParameter( Constants.PARAM_RELATIONSHIPS, includeRelationships );
158
159 UrlBuilder location = new UrlBuilder( pagingUrl );
160 location.addParameter( Constants.PARAM_MAX_ITEMS, maxItems );
161 location.addParameter( Constants.PARAM_SKIP_COUNT, skipCount );
162
163 response.setStatus( statusCode );
164 response.setContentType( Constants.MEDIATYPE_FEED );
165
166
167
168
169
170
171
172 response.setHeader( "Location", location.toString( ) );
173
174
175 AtomFeed feed = new AtomFeed( );
176 feed.startDocument( response.getOutputStream( ) );
177 feed.startFeed( true );
178
179
180 GregorianCalendar now = new GregorianCalendar( );
181 feed.writeFeedElements( "query", "", "Query", now, null, results.getNumItems( ) );
182
183
184 feed.writeServiceLink( baseUrl.toString( ), repositoryId );
185
186 feed.writePagingLinks( pagingUrl, maxItems, skipCount, results.getNumItems( ), results.hasMoreItems( ),
187 AtomPubUtils.PAGE_SIZE );
188
189 if ( results.getObjects( ) != null )
190 {
191 AtomEntry entry = new AtomEntry( feed.getWriter( ) );
192 int idCounter = 0;
193
194 for ( ObjectData result : results.getObjects( ) )
195 {
196 if ( result == null )
197 {
198 continue;
199 }
200
201 idCounter++;
202 writeQueryResultEntry( entry, result, "id-" + idCounter, now );
203 }
204 }
205
206
207 feed.endFeed( );
208 feed.endDocument( );
209 }
210
211 private static void writeQueryResultEntry( AtomEntry entry, ObjectData result, String id, GregorianCalendar now )
212 throws Exception
213 {
214 CmisObjectType resultJaxb = convert( result );
215
216 if ( resultJaxb == null )
217 {
218 return;
219 }
220
221
222 entry.startEntry( false );
223
224
225 entry.writeAuthor( "" );
226 entry.writeId( entry.generateAtomId( id ) );
227 entry.writePublished( now );
228 entry.writeTitle( "Query Result " + id );
229 entry.writeUpdated( now );
230
231
232 JaxBHelper.marshal( JaxBHelper.CMIS_EXTRA_OBJECT_FACTORY.createObject( resultJaxb ), entry.getWriter( ), true );
233
234
235 entry.endEntry( );
236 }
237
238
239
240
241 public static void getContentChanges( CallContext context, CmisService service, String repositoryId,
242 HttpServletRequest request, HttpServletResponse response )
243 throws Exception
244 {
245
246 String changeLogToken = getStringParameter( request, Constants.PARAM_CHANGE_LOG_TOKEN );
247 Boolean includeProperties = getBooleanParameter( request, Constants.PARAM_PROPERTIES );
248 String filter = getStringParameter( request, Constants.PARAM_FILTER );
249 Boolean includePolicyIds = getBooleanParameter( request, Constants.PARAM_POLICY_IDS );
250 Boolean includeAcl = getBooleanParameter( request, Constants.PARAM_ACL );
251 BigInteger maxItems = getBigIntegerParameter( request, Constants.PARAM_MAX_ITEMS );
252
253
254 Holder<String> changeLogTokenHolder = new Holder<String>( changeLogToken );
255 ObjectList changes = service.getContentChanges( repositoryId, changeLogTokenHolder, includeProperties, filter,
256 includePolicyIds, includeAcl, maxItems, null );
257
258 if ( changes == null )
259 {
260 throw new CmisRuntimeException( "Changes are null!" );
261 }
262
263
264 response.setStatus( HttpServletResponse.SC_OK );
265 response.setContentType( Constants.MEDIATYPE_FEED );
266
267
268 AtomFeed feed = new AtomFeed( );
269 feed.startDocument( response.getOutputStream( ) );
270 feed.startFeed( true );
271
272
273 GregorianCalendar now = new GregorianCalendar( );
274 feed.writeFeedElements( "contentChanges", "", "Content Change", now, null, changes.getNumItems( ) );
275
276
277 UrlBuilder baseUrl = compileBaseUrl( request, repositoryId );
278
279 feed.writeServiceLink( baseUrl.toString( ), repositoryId );
280
281 if ( changeLogTokenHolder.getValue( ) != null )
282 {
283 UrlBuilder nextLink = compileUrlBuilder( baseUrl, RESOURCE_CHANGES, null );
284 nextLink.addParameter( Constants.PARAM_CHANGE_LOG_TOKEN, changeLogTokenHolder.getValue( ) );
285 nextLink.addParameter( Constants.PARAM_PROPERTIES, includeProperties );
286 nextLink.addParameter( Constants.PARAM_FILTER, filter );
287 nextLink.addParameter( Constants.PARAM_POLICY_IDS, includePolicyIds );
288 nextLink.addParameter( Constants.PARAM_ACL, includeAcl );
289 nextLink.addParameter( Constants.PARAM_MAX_ITEMS, maxItems );
290 feed.writeNextLink( nextLink.toString( ) );
291 }
292
293
294 if ( changes.getObjects( ) != null )
295 {
296 AtomEntry entry = new AtomEntry( feed.getWriter( ) );
297
298 for ( ObjectData object : changes.getObjects( ) )
299 {
300 if ( object == null )
301 {
302 continue;
303 }
304
305 writeContentChangesObjectEntry( service, entry, object, null, repositoryId, null, null, baseUrl, false );
306 }
307 }
308
309
310 feed.endFeed( );
311 feed.endDocument( );
312 }
313 }