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