001/*
002 * The contents of this file are subject to the terms of the Common Development and
003 * Distribution License (the License). You may not use this file except in compliance with the
004 * License.
005 *
006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
007 * specific language governing permission and limitations under the License.
008 *
009 * When distributing Covered Software, include this CDDL Header Notice in each file and include
010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
011 * Header, with the fields enclosed by brackets [] replaced by your own identifying
012 * information: "Portions Copyright [year] [name of copyright owner]".
013 *
014 * Copyright 2012-2015 ForgeRock AS.
015 */
016
017package org.forgerock.json.resource;
018
019import java.util.List;
020import java.util.Map;
021
022import org.forgerock.http.routing.Version;
023import org.forgerock.json.JsonPointer;
024import org.forgerock.json.JsonValue;
025import org.forgerock.util.i18n.PreferredLocales;
026import org.forgerock.util.query.QueryFilter;
027
028/**
029 * A request to search for all JSON resources matching a user specified set of criteria.
030 * <p>
031 * There are four types of query request: <ul> <li>default query: when neither a filter, expression or query ID are
032 * specified all resources will be returned <li>query by filter: returns all resources which match the {@link
033 * QueryFilters} specified using {@link #setQueryFilter(QueryFilter)} <li>query by ID: returns all resources which match
034 * the named prepared query specified using {@link #setQueryId(String)} <li>query by expression: returns all resources
035 * which match a native expression specified using {@link #setQueryExpression(String)}. Note that this type of query
036 * should only be used in very rare cases since it introduces a tight coupling between the application and the
037 * underlying JSON resource. In addition, applications should take care to prevent users from directly accessing this
038 * form of query for security reasons. </ul>
039 * <p>
040 * In addition to the above mentioned query types queries may also be paged when a page size is found via {@link
041 * #getPageSize()}. Paged requests should be used in most cases when an unknown number of query results will be
042 * returned.
043 */
044public interface QueryRequest extends Request {
045    /**
046     * The name of the field which contains the paged results cookie in the JSON representation.
047     */
048    String FIELD_PAGED_RESULTS_COOKIE = "pagedResultsCookie";
049    /**
050     * The name of the field which contains the paged results offset in the JSON representation.
051     */
052    String FIELD_PAGED_RESULTS_OFFSET = "pagedResultsOffset";
053    /**
054     * The name of the field which contains the page size in the JSON representation.
055     */
056    String FIELD_PAGE_SIZE = "pageSize";
057    /**
058     * The name of the field which contains the query expression in the JSON representation.
059     */
060    String FIELD_QUERY_EXPRESSION = "queryExpression";
061    /**
062     * The name of the field which contains the query filter in the JSON representation.
063     */
064    String FIELD_QUERY_FILTER = "queryFilter";
065    /**
066     * The name of the field which contains the query ID in the JSON representation.
067     */
068    String FIELD_QUERY_ID = "queryId";
069    /**
070     * The name of the field which contains the sort keys in the JSON representation.
071     */
072    String FIELD_SORT_KEYS = "sortKeys";
073    /**
074     * The name of the field which contains the policy used for calculating the total number of paged results.
075     */
076    String FIELD_TOTAL_PAGED_RESULTS_POLICY = "totalPagedResultsPolicy";
077
078
079    @Override
080    <R, P> R accept(final RequestVisitor<R, P> v, final P p);
081
082
083    @Override
084    QueryRequest addField(JsonPointer... fields);
085
086
087    @Override
088    QueryRequest addField(String... fields);
089
090    /**
091     * Adds one or more sort keys which will be used for ordering the JSON resources returned by this query request.
092     *
093     * @param keys
094     *         The sort keys which will be used for ordering the JSON resources returned by this query request.
095     * @return This query request.
096     * @throws UnsupportedOperationException
097     *         If this query request does not permit changes to the sort keys.
098     */
099    QueryRequest addSortKey(SortKey... keys);
100
101    /**
102     * Adds one or more sort keys which will be used for ordering the JSON resources returned by this query request.
103     *
104     * @param keys
105     *         The sort keys which will be used for ordering the JSON resources returned by this query request.
106     * @return This query request.
107     * @throws IllegalArgumentException
108     *         If one or more of the provided sort keys could not be parsed.
109     * @throws UnsupportedOperationException
110     *         If this query request does not permit changes to the sort keys.
111     */
112    QueryRequest addSortKey(String... keys);
113
114
115    @Override
116    String getAdditionalParameter(String name);
117
118
119    @Override
120    Map<String, String> getAdditionalParameters();
121
122
123    @Override
124    List<JsonPointer> getFields();
125
126    /**
127     * Returns the requested page results page size or {@code 0} if paged results are not required. For all paged result
128     * requests other than the initial request, a cookie should be provided with the query request. See {@link
129     * #getPagedResultsCookie()} for more information.
130     *
131     * @return The requested page results page size or {@code 0} if paged results are not required.
132     * @see #getPagedResultsCookie()
133     * @see #getPagedResultsOffset()
134     */
135    int getPageSize();
136
137    /**
138     * Returns the opaque cookie which is used by the resource provider to track its position in the set of query
139     * results. Paged results will be enabled if and only if the page size is non-zero.
140     * <p>
141     * The cookie must be {@code null} in the initial query request sent by the client. For subsequent query requests
142     * the client must include the cookie returned with the previous query result, until the resource provider returns a
143     * {@code null} cookie indicating that the final page of results has been returned.
144     * <p>
145     * <em>Note:</em> Cookies and offsets are mutually exclusive.
146     *
147     * @return The opaque cookie which is used by the resource provider to track its position in the set of query
148     * results, or {@code null} if paged results are not requested (when the page size is 0) or if the first page of
149     * results is being requested (when the page size is non-zero).
150     * @see #getPageSize()
151     * @see #getPagedResultsOffset()
152     */
153    String getPagedResultsCookie();
154
155    /**
156     * Returns the zero-based index of the first resource which should be included in the query results. An offset of 0
157     * (default) will return the first resource in the collection. An offset of {@code 1} will return the second, and so
158     * on ...
159     * <p>
160     * <em>Note:</em> Offsets and cookies are mutually exclusive. When a cookie is supplied only the default {@code 0}
161     * offset is supported.
162     * <p>
163     * Offset must be a zero-based integer denoting the number of records to skip. This is very similar to the
164     * <code>LIMIT</code> and <code>SKIP</code> clauses in SQL databases.
165     *
166     * @return The zero-based index within the result set of the first result which should be returned.
167     * @see #getPageSize()
168     * @see #getPagedResultsCookie()
169     */
170    int getPagedResultsOffset();
171
172
173    @Override
174    PreferredLocales getPreferredLocales();
175
176    /**
177     * Returns the native query expression which will be used for processing the query request. An example of a native
178     * query expression is a SQL statement.
179     * <p>
180     * <b>NOTE:</b> the native query expression, query filter, and query ID parameters are mutually exclusive and only
181     * one of them may be specified.
182     *
183     * @return The native query expression which will be used for processing the query request, or {@code null} if
184     * another type of query is to be performed.
185     * @see QueryRequest#getQueryFilter()
186     * @see QueryRequest#getQueryId()
187     */
188    String getQueryExpression();
189
190    /**
191     * Returns the query filter which will be used for selecting which JSON resources will be returned.
192     * <p>
193     * <b>NOTE:</b> the native query expression, query filter, and query ID parameters are mutually exclusive and only
194     * one of them may be specified.
195     *
196     * @return The query filter which will be used for selecting which JSON resources will be returned, or {@code null}
197     * if another type of query is to be performed.
198     * @see QueryRequest#getQueryExpression()
199     * @see QueryRequest#getQueryId()
200     */
201    QueryFilter<JsonPointer> getQueryFilter();
202
203    /**
204     * Returns the query identifier for pre-defined queries.
205     * <p>
206     * <b>NOTE:</b> the native query expression, query filter, and query ID parameters are mutually exclusive and only
207     * one of them may be specified.
208     *
209     * @return The query identifier for pre-defined queries, or {@code null} if a pre-defined query is not to be used,
210     * or {@code null} if another type of query is to be performed.
211     * @see QueryRequest#getQueryExpression()
212     * @see QueryRequest#getQueryFilter()
213     */
214    String getQueryId();
215
216
217    @Override
218    RequestType getRequestType();
219
220    @Override
221    String getResourcePath();
222
223    @Override
224    ResourcePath getResourcePathObject();
225
226    @Override
227    Version getResourceVersion();
228
229    /**
230     * Returns the sort keys which should be used for ordering the JSON resources returned by this query request. The
231     * returned list may be modified if permitted by this query request.
232     *
233     * @return The sort keys which should be used for ordering the JSON resources returned by this query request (never
234     * {@code null}).
235     */
236    List<SortKey> getSortKeys();
237
238    /**
239     * Returns the {@link CountPolicy} used to calculate {@link QueryResponse#getTotalPagedResults()}.
240     *
241     * @return The count policy.
242     * @see QueryResponse#getTotalPagedResults()
243     */
244    CountPolicy getTotalPagedResultsPolicy();
245
246    @Override
247    QueryRequest setAdditionalParameter(String name, String value) throws BadRequestException;
248
249    /**
250     * Sets the requested page results page size or {@code 0} if paged results are not required. For all paged result
251     * requests other than the initial request, a cookie should be provided with the query request. See {@link
252     * #setPagedResultsCookie(String)} for more information.
253     *
254     * @param size
255     *         The requested page results page size or {@code 0} if paged results are not required.
256     * @return This query request.
257     * @throws UnsupportedOperationException
258     *         If this query request does not permit changes to the page size.
259     * @see #getPagedResultsCookie()
260     * @see #setPagedResultsOffset(int)
261     */
262    QueryRequest setPageSize(int size);
263
264    /**
265     * Sets the opaque cookie which is used by the resource provider to track its position in the set of query results.
266     * Paged results will be enabled if and only if the page size is non-zero.
267     * <p>
268     * The cookie must be {@code null} in the initial query request sent by the client. For subsequent query requests
269     * the client must include the cookie returned with the previous query result, until the resource provider returns a
270     * {@code null} cookie indicating that the final page of results has been returned.
271     * <p>
272     * When subsequent paged requests are being made no query parameters may be altered; doing so will result in
273     * undefined behavior. The only parameter that may be changed during paged requests is the page size.
274     *
275     * @param cookie
276     *         The opaque cookie which is used by the resource provider to track its position in the set of query
277     *         results.
278     * @return This query request.
279     * @throws UnsupportedOperationException
280     *         If this query request does not permit changes to the paged results cookie.
281     * @see #setPageSize(int)
282     * @see #addSortKey(SortKey...)
283     * @see #addSortKey(String...)
284     */
285    QueryRequest setPagedResultsCookie(String cookie);
286
287    /**
288     * Sets the zero-based index of the first resource which should be included in the query results. An offset of 0
289     * (default) will return the first resource in the collection. An offset of {@code 1} will return the second, and so
290     * on ...
291     * <p>
292     * <em>Note:</em> Offsets and cookies are mutually exclusive. When a cookie is supplied only the default {@code 0}
293     * offset is supported.
294     * <p>
295     * Offset must be a zero-based integer denoting the number of records to skip. This is very similar to the
296     * <code>LIMIT</code> and <code>SKIP</code> clauses in SQL databases.
297     *
298     * @param offset
299     *         The index within the result set of the first result which should be returned.
300     * @return This query request.
301     * @throws UnsupportedOperationException
302     *         If this query request does not permit changes to the paged results offset.
303     * @see #setPageSize(int)
304     * @see #setPagedResultsCookie(String)
305     */
306    QueryRequest setPagedResultsOffset(int offset);
307
308    @Override
309    QueryRequest setPreferredLocales(PreferredLocales preferredLocales);
310
311    /**
312     * Sets the native query expression which will be used for processing the query request. An example of a native
313     * query expression is a SQL statement.
314     * <p>
315     * <b>NOTE:</b> the native query expression, query filter, and query ID parameters are mutually exclusive and only
316     * one of them may be specified.
317     *
318     * @param expression
319     *         The native query expression which will be used for processing the query request, or {@code null} if
320     *         another type of query is to be performed.
321     * @return This query request.
322     * @throws UnsupportedOperationException
323     *         If this query request does not permit changes to the query identifier.
324     * @see QueryRequest#setQueryFilter(QueryFilter)
325     * @see QueryRequest#setQueryId(String)
326     */
327    QueryRequest setQueryExpression(String expression);
328
329    /**
330     * Sets the query filter which will be used for selecting which JSON resources will be returned.
331     * <p>
332     * <b>NOTE:</b> the native query expression, query filter, and query ID parameters are mutually exclusive and only
333     * one of them may be specified.
334     *
335     * @param filter
336     *         The query filter which will be used for selecting which JSON resources will be returned, or {@code null}
337     *         if another type of query is to be performed.
338     * @return This query request.
339     * @throws UnsupportedOperationException
340     *         If this query request does not permit changes to the query filter.
341     * @see QueryRequest#setQueryExpression(String)
342     * @see QueryRequest#setQueryId(String)
343     */
344    QueryRequest setQueryFilter(QueryFilter<JsonPointer> filter);
345
346    /**
347     * Sets the query identifier for pre-defined queries.
348     * <p>
349     * <b>NOTE:</b> the native query expression, query filter, and query ID parameters are mutually exclusive and only
350     * one of them may be specified.
351     *
352     * @param id
353     *         The query identifier for pre-defined queries, or {@code null} if another type of query is to be
354     *         performed.
355     * @return This query request.
356     * @throws UnsupportedOperationException
357     *         If this query request does not permit changes to the query identifier.
358     * @see QueryRequest#setQueryExpression(String)
359     * @see QueryRequest#setQueryFilter(QueryFilter)
360     */
361    QueryRequest setQueryId(String id);
362
363    @Override
364    QueryRequest setResourcePath(ResourcePath path);
365
366    @Override
367    QueryRequest setResourcePath(String path);
368
369    @Override
370    QueryRequest setResourceVersion(Version resourceVersion);
371
372    /**
373     * Sets the policy for calculating the total number of paged results. If no count policy is supplied or paged
374     * results are not requested a default of {@link CountPolicy#NONE} will be used. This will result in no count being
375     * performed and no overhead incurred.
376     *
377     * @param policy
378     *         The policy used to calculate total paged results
379     * @return This query request.
380     * @see QueryResponse#getTotalPagedResultsPolicy()
381     * @see QueryResponse#getTotalPagedResults()
382     */
383    QueryRequest setTotalPagedResultsPolicy(CountPolicy policy);
384
385    @Override
386    JsonValue toJsonValue();
387}