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 2013-2015 ForgeRock AS.
015 */
016
017package org.forgerock.json.resource;
018
019import org.forgerock.services.context.Context;
020import org.forgerock.util.promise.Promise;
021
022/**
023 * An interface for implementing request handler filters. Filters are linked
024 * together using a {@link FilterChain}.
025 * <p>
026 * On receipt of a request a filter implementation may either:
027 * <ul>
028 * <li><i>stop processing</i> the request and return a result or error
029 * immediately. This is achieved by returning a completed {@code Promise} with
030 * a {@link QueryResponse} or a {@link ResourceException} methods and returning
031 * <li><i>continue processing</i> the request using the next filter in the
032 * filter chain. This is achieved by invoking the appropriate {@code handlerXXX}
033 * method on the passed in request handler. Implementations are permitted to
034 * modify the context or request before forwarding. They may also chain the
035 * promise, returned from the downstream handler, in order to be notified when
036 * a response is returned, allowing a filter to interact with responses before
037 * they are sent to the client.
038 * </ul>
039 * <p>
040 * Implementations are allowed to invoke arbitrary {@code handleXXX} methods on
041 * the request handler if needed before deciding to stop or continue processing.
042 * However, implementations should take care to ensure that the passed in result
043 * handler is invoked at most once per request. This is useful in the case where
044 * a filter implements some functionality as a composite of other operations
045 * (e.g. theoretically, a password modify action could be intercepted within a
046 * filter and converted into a read + update).
047 * <p>
048 * Filter chains are fully asynchronous: filters and request handlers may
049 * delegate work to separate threads either directly (i.e. new Thread() ...) or
050 * indirectly (e.g. via NIO completion handlers).
051 * <p>
052 * The following example illustrates how an authorization filter could be
053 * implemented:
054 *
055 * <pre>
056 * public class AuthzFilter implements Filter {
057 *
058 *     public Promise&lt;Resource, ResourceException&gt; filterRead(final Context context,
059 *             final ReadRequest request, final RequestHandler next) {
060 *         /*
061 *          * Only forward the request if the request is allowed.
062 *          &#42;/
063 *         if (isAuthorized(context, request)) {
064 *             /*
065 *              * Continue processing the request since it is allowed. Chain the
066 *              * promise so that we can filter the returned resource.
067 *              &#42;/
068 *             return next.handleRead(context, request)
069 *                     .thenAsync(new AsyncFunction&lt;Resource, Resource, ResourceException&gt;() {
070 *                         &#064;Override
071 *                         public Promise&lt;Resource, ResourceException&gt; apply(Resource result) {
072 *                             /*
073 *                              * Filter the resource and its attributes.
074 *                              &#42;/
075 *                             if (isAuthorized(context, result)) {
076 *                                 return Promises.newResultPromise(filterResource(context, result));
077 *                             } else {
078 *                                 return newExceptionPromise(ResourceException.newNotFoundException());
079 *                             }
080 *                         }
081 *                     }, new AsyncFunction&lt;ResourceException, Resource, ResourceException&gt;() {
082 *                         &#064;Override
083 *                         public Promise&lt;Resource, ResourceException&gt; apply(ResourceException error) {
084 *                             // Forward - assumes no authorization is required.
085 *                             return newExceptionPromise(error);
086 *                         }
087 *                     });
088 *         } else {
089 *             /*
090 *              * Stop processing the request since it is not allowed.
091 *              &#42;/
092 *             ResourceException exception = new ForbiddenException();
093 *             return newExceptionPromise(exception);
094 *         }
095 *     }
096 *
097 *     // Remaining filterXXX methods...
098 * }
099 * </pre>
100 *
101 * @see Filters
102 */
103public interface Filter {
104
105    /**
106     * Filters an action request.
107     *
108     * @param context
109     *            The filter chain context.
110     * @param request
111     *            The action request.
112     * @param next
113     *            A request handler representing the remainder of the filter
114     *            chain.
115     * @return A {@code Promise} containing the result of the operation.
116     */
117    Promise<ActionResponse, ResourceException> filterAction(Context context, ActionRequest request,
118            RequestHandler next);
119
120    /**
121     * Filters a create request.
122     *
123     * @param context
124     *            The filter chain context.
125     * @param request
126     *            The create request.
127     * @param next
128     *            A request handler representing the remainder of the filter
129     *            chain.
130     * @return A {@code Promise} containing the result of the operation.
131     */
132    Promise<ResourceResponse, ResourceException> filterCreate(Context context, CreateRequest request,
133            RequestHandler next);
134
135    /**
136     * Filters a delete request.
137     *
138     * @param context
139     *            The filter chain context.
140     * @param request
141     *            The delete request.
142     * @param next
143     *            A request handler representing the remainder of the filter
144     *            chain.
145     * @return A {@code Promise} containing the result of the operation.
146     */
147    Promise<ResourceResponse, ResourceException> filterDelete(Context context, DeleteRequest request,
148            RequestHandler next);
149
150    /**
151     * Filters a patch request.
152     *
153     * @param context
154     *            The filter chain context.
155     * @param request
156     *            The patch request.
157     * @param next
158     *            A request handler representing the remainder of the filter
159     *            chain.
160     * @return A {@code Promise} containing the result of the operation.
161     */
162    Promise<ResourceResponse, ResourceException> filterPatch(Context context, PatchRequest request,
163            RequestHandler next);
164
165    /**
166     * Filters a query request.
167     * <p>
168     * Implementations which return results directly rather than forwarding the
169     * request should invoke {@link QueryResourceHandler#handleResource(ResourceResponse)}
170     * for each resource which matches the query criteria. Once all matching
171     * resources have been returned implementations are required to return
172     * either a {@link QueryResponse} if the query has completed successfully, or
173     * {@link ResourceException} if the query did not complete successfully
174     * (even if some matching resources were returned).
175     *
176     * @param context
177     *            The filter chain context.
178     * @param request
179     *            The query request.
180     * @param handler
181     *            The resource handler.
182     * @param next
183     *            A request handler representing the remainder of the filter
184     *            chain.
185     * @return A {@code Promise} containing the result of the operation.
186     */
187    Promise<QueryResponse, ResourceException> filterQuery(Context context, QueryRequest request,
188            QueryResourceHandler handler, RequestHandler next);
189
190    /**
191     * Filters a read request.
192     *
193     * @param context
194     *            The filter chain context.
195     * @param request
196     *            The read request.
197     * @param next
198     *            A request handler representing the remainder of the filter
199     *            chain.
200     * @return A {@code Promise} containing the result of the operation.
201     */
202    Promise<ResourceResponse, ResourceException> filterRead(Context context, ReadRequest request,
203            RequestHandler next);
204
205    /**
206     * Filters an update request.
207     *
208     * @param context
209     *            The filter chain context.
210     * @param request
211     *            The update request.
212     * @param next
213     *            A request handler representing the remainder of the filter
214     *            chain.
215     * @return A {@code Promise} containing the result of the operation.
216     */
217    Promise<ResourceResponse, ResourceException> filterUpdate(Context context, UpdateRequest request,
218            RequestHandler next);
219}