All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ratpack.handling.Chain Maven / Gradle / Ivy

There is a newer version: 2.0.0-rc-1
Show newest version
/*
 * Copyright 2013 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package ratpack.handling;

import ratpack.func.Action;
import ratpack.launch.LaunchConfig;
import ratpack.registry.Registry;
import ratpack.registry.RegistrySpec;

/**
 * A chain can be used to build a linked series of handlers.
 * 

* A handler chain can be constructed using the {@link Handlers#chain(LaunchConfig, ratpack.func.Action)} like methods. * For example, from a {@link ratpack.launch.HandlerFactory} implementation… *

 * import ratpack.launch.HandlerFactory;
 * import ratpack.launch.LaunchConfig;
 * import ratpack.handling.Chain;
 * import ratpack.handling.Handler;
 * import ratpack.handling.Handlers;
 * import ratpack.handling.Context;
 * import ratpack.func.Action;
 *
 * public class MyHandlerBootstrap implements HandlerFactory {
 *   public Handler create(LaunchConfig launchConfig) {
 *
 *     return Handlers.chain(launchConfig, new Action<Chain>() {
 *       public void execute(Chain chain) {
 *         chain
 *           .assets("public")
 *           .prefix("api", new Action<Chain>() {
 *             public void execute(Chain api) {
 *               api
 *                 .get("people", new PeopleHandler())
 *                 .post( "person/:id", new Handler() {
 *                   public void handle(Context context) {
 *                     // handle
 *                   }
 *                 });
 *             }
 *           });
 *       }
 *     });
 *   }
 * }
 *
 * public class PeopleHandler implements Handler {
 *   public void handle(Context context) {
 *     // handle
 *   }
 * }
 * 
*

* Chains may be backed by a {@link Registry registry}, depending on how the chain was constructed. * For example, the Ratpack Guice module makes it possible to create a Guice backed registry that can be used to * construct dependency injected handlers. See the {@code ratpack-guice} library for details. *

*

* A Groovy specific subclass of this interface is provided by the Groovy module that overloads methods here with {@code Closure} based variants. * See the {@code ratpack-groovy} library for details. *

*/ public interface Chain { /** * Adds a handler that serves static assets at the given file system path, relative to the contextual file system binding. *

* See {@link Handlers#assets(LaunchConfig, String, java.util.List)} for more details on the handler created *

   *    prefix("foo") {
   *      assets("d1", "index.html", "index.xhtml")
   *    }
   * 
* In the above configuration a request like "/foo/app.js" will return the static file "app.js" that is * located in the directory "d1". *

* If the request matches a directory e.g. "/foo", an index file may be served. The {@code indexFiles} * array specifies the names of files to look for in order to serve. * * @param path the relative path to the location of the assets to serve * @param indexFiles the index files to try if the request is for a directory * @return this */ Chain assets(String path, String... indexFiles); /** * Constructs a handler using the given action to define a chain. * * @param action The action that defines the handler chain * @return A handler representing the chain * @throws Exception any thrown by {@code action} */ Handler chain(Action action) throws Exception; default Handler chain(Class> action) throws Exception { return chain(getRegistry().get(action)); } /** * Adds a handler that delegates to the given handler if * the relative {@code path} matches the given {@code path} and the {@code request} {@code HTTPMethod} * is {@code DELETE}. * * @param path the relative path to match on * @param handler the handler to delegate to * @return this * @see Chain#get(String, Handler) * @see Chain#post(String, Handler) * @see Chain#put(String, Handler) * @see Chain#patch(String, Handler) * @see Chain#handler(String, Handler) */ Chain delete(String path, Handler handler); default Chain delete(String path, Class handler) { return delete(path, getRegistry().get(handler)); } /** * Adds a handler that delegates to the given handler if * the {@code request} {@code HTTPMethod} is {@code DELETE} and the {@code path} is at the current root. * * @param handler the handler to delegate to * @return this * @see Chain#get(Handler) * @see Chain#post(Handler) * @see Chain#put(Handler) * @see Chain#patch(Handler) */ Chain delete(Handler handler); default Chain delete(Class handler) { return delete(getRegistry().get(handler)); } /** * Adds a handler to this chain that changes the {@link ratpack.file.FileSystemBinding} for the given handler chain. * * @param path the relative path to the new file system binding point * @param action the definition of the handler chain * @return this * @throws Exception any thrown by {@code action} */ Chain fileSystem(String path, Action action) throws Exception; default Chain fileSystem(String path, Class> action) throws Exception { return fileSystem(path, getRegistry().get(action)); } /** * Adds a handler that delegates to the given handler * if the relative {@code path} matches the given {@code path} and the {@code request} * {@code HTTPMethod} is {@code GET}. *

* * @param path the relative path to match on * @param handler the handler to delegate to * @return this * @see Chain#post(String, Handler) * @see Chain#put(String, Handler) * @see Chain#patch(String, Handler) * @see Chain#delete(String, Handler) * @see Chain#handler(String, Handler) */ Chain get(String path, Handler handler); default Chain get(String path, Class handler) { return get(path, getRegistry().get(handler)); } /** * Adds a handler that delegates to the given handler * if the {@code request} {@code HTTPMethod} is {@code GET} and the {@code path} is at the * current root. * * @param handler the handler to delegate to * @return this * @see Chain#post(Handler) * @see Chain#put(Handler) * @see Chain#patch(Handler) * @see Chain#delete(Handler) */ Chain get(Handler handler); default Chain get(Class handler) { return get(getRegistry().get(handler)); } /** * The launch config of the application that this chain is being created for. * * @return The launch config of the application that this chain is being created for. */ LaunchConfig getLaunchConfig(); /** * The registry that backs this chain. *

* What the registry is depends on how the chain was created. * The {@link Handlers#chain(LaunchConfig, Registry, Action)} allows the registry to be specified. * For a Guice based application, the registry is backed by Guice. * * @see Handlers#chain(LaunchConfig, Registry, Action) * @return The registry that backs this * @throws IllegalStateException if there is no backing registry for this chain */ Registry getRegistry() throws IllegalStateException; /** * Adds the given handler to this. * * @param handler the handler to add * @return this */ Chain handler(Handler handler); default Chain handler(Class handler) { return handler(getRegistry().get(handler)); } /** * Adds a handler that delegates to the given handler if the relative {@code path} * matches the given {@code path} exactly. *

* Nesting {@code path} handlers will not work due to the exact matching, use a combination of {@code path} * and {@code prefix} instead. See {@link Chain#prefix(String, ratpack.func.Action)} for details. *

   *   // this will not work
   *   path("person/:id") {
   *     path("child/:childId") {
   *       // a request of /person/2/child/1 will not get passed the first handler as it will try
   *       // to match "person/2/child/1" with "person/2" which does not match
   *     }
   *
   *   // this will work
   *   prefix("person/:id") {
   *     path("child/:childId") {
   *       // a request of /person/2/child/1 will work this time
   *     }
   *   }
   * 
*

* See {@link Handlers#path(String, Handler)} for the details on how {@code path} is interpreted. * * @param path the relative path to match exactly on * @param handler the handler to delegate to * @return this * @see Chain#post(String, Handler) * @see Chain#get(String, Handler) * @see Chain#put(String, Handler) * @see Chain#patch(String, Handler) * @see Chain#delete(String, Handler) */ Chain handler(String path, Handler handler); default Chain handler(String path, Class handler) { return handler(path, getRegistry().get(handler)); } /** * Adds a handler to the chain that delegates to the given handler if the request has a header with the given name and a its value matches the given value exactly. * *

   *  chain.
   *    header("foo", "bar", new Handler() {
   *      public void handle(Context context) {
   *        context.getResponse().send("Header Handler");
   *      }
   *    });
   * 
* * @param headerName the name of the HTTP Header to match on * @param headerValue the value of the HTTP Header to match on * @param handler the handler to delegate to * @return this */ Chain header(String headerName, String headerValue, Handler handler); default Chain header(String headerName, String headerValue, Class handler) { return header(headerName, headerValue, getRegistry().get(handler)); } /** * Adds a handler to the chain that delegates to the given handler chain if the request has a {@code Host} header that matches the given value exactly. * *
   *  chain.
   *    host("foo.com", new Action<Chain>() {
   *      public void execute(Chain hostChain) {
   *        hostChain.handler(new Handler() {
   *          public void handle(Context context) {
   *            context.getResponse().send("Host Handler");
   *          }
   *        });
   *      }
   *    });
   * 
* * @param hostName the name of the HTTP Header to match on * @param action the handler chain to delegate to if the host matches * @return this * @throws Exception any thrown by {@code action} */ Chain host(String hostName, Action action) throws Exception; default Chain host(String hostName, Class> action) throws Exception { return host(hostName, getRegistry().get(action)); } /** * Inserts the given nested handler chain. *

* Shorter form of {@link #handler(Handler)} handler}({@link #chain(ratpack.func.Action) chain}({@code action}). * * @param action the handler chain to insert * @return this * @throws Exception any thrown by {@code action} */ Chain insert(Action action) throws Exception; default Chain insert(Class> action) throws Exception { return insert(getRegistry().get(action)); } /** * Adds a handler that delegates to the given handler if * the relative {@code path} matches the given {@code path} and the {@code request} {@code HTTPMethod} * is {@code PATCH}. * * @param path the relative path to match on * @param handler the handler to delegate to * @return this * @see Chain#get(String, Handler) * @see Chain#post(String, Handler) * @see Chain#put(String, Handler) * @see Chain#delete(String, Handler) * @see Chain#handler(String, Handler) */ Chain patch(String path, Handler handler); default Chain patch(String path, Class handler) { return patch(path, getRegistry().get(handler)); } /** * Adds a handler that delegates to the given handler if * the {@code request} {@code HTTPMethod} is {@code PATCH} and the {@code path} is at the current root. * * @param handler the handler to delegate to * @return this * @see Chain#get(Handler) * @see Chain#post(Handler) * @see Chain#put(Handler) * @see Chain#delete(Handler) */ Chain patch(Handler handler); default Chain patch(Class handler) { return patch(getRegistry().get(handler)); } /** * Adds a handler that delegates to the given handler if * the relative {@code path} matches the given {@code path} and the {@code request} {@code HTTPMethod} * is {@code POST}. *

* * @param path the relative path to match on * @param handler the handler to delegate to * @return this * @see Chain#get(String, Handler) * @see Chain#put(String, Handler) * @see Chain#patch(String, Handler) * @see Chain#delete(String, Handler) * @see Chain#handler(String, Handler) */ Chain post(String path, Handler handler); default Chain post(String path, Class handler) { return post(path, getRegistry().get(handler)); } /** * Adds a handler that delegates to the given handler if * the {@code request} {@code HTTPMethod} is {@code POST} and the {@code path} is at the current root. *

* * @param handler the handler to delegate to * @return this * @see Chain#get(Handler) * @see Chain#put(Handler) * @see Chain#patch(Handler) * @see Chain#delete(Handler) */ Chain post(Handler handler); default Chain post(Class handler) { return post(getRegistry().get(handler)); } /** * Adds a handler that delegates to the given handlers if the * relative path starts with the given {@code prefix}. *

* All path based handlers become relative to the given {@code prefix}. *

   *   chain
   *     .prefix("person/:id", new Action<Chain>() {
   *       public void execute(Chain personChain) {
   *         personChain
   *           .get("info", new Handler() {
   *             public void handle(Context context) {
   *               // e.g. /person/2/info
   *             }
   *           })
   *           .post("save", new Handler() {
   *             public void handle(Context context) {
   *               // e.g. /person/2/save
   *             }
   *           })
   *           .prefix("child/:childId", new Action<Chain>() {
   *             public void execute(Chain childChain) {
   *               childChain
   *                 .get("info", new Handler() {
   *                   public void handle(Context context) {
   *                     // e.g. /person/2/child/1/info
   *                   }
   *                 });
   *             }
   *           });
   *       }
   *     });
   * 
*

* See {@link ratpack.handling.Handlers#prefix(String, Handler)} * for format details on the {@code prefix} string. * * @param prefix the relative path to match on * @param action the handler chain to delegate to if the prefix matches * @throws Exception any thrown by {@code action} * @return this */ Chain prefix(String prefix, Action action) throws Exception; default Chain prefix(String prefix, Class> action) throws Exception { return prefix(prefix, getRegistry().get(action)); } /** * Adds a handler that delegates to the given handler if * the relative {@code path} matches the given {@code path} and the {@code request} {@code HTTPMethod} * is {@code PUT}. * * @param path the relative path to match on * @param handler the handler to delegate to * @return this * @see Chain#get(String, Handler) * @see Chain#post(String, Handler) * @see Chain#patch(String, Handler) * @see Chain#delete(String, Handler) * @see Chain#handler(String, Handler) */ Chain put(String path, Handler handler); default Chain put(String path, Class handler) { return put(path, getRegistry().get(handler)); } /** * Adds a handler that delegates to the given handler if * the {@code request} {@code HTTPMethod} is {@code PUT} and the {@code path} is at the current root. * * @param handler the handler to delegate to * @return this * @see Chain#get(Handler) * @see Chain#post(Handler) * @see Chain#patch(Handler) * @see Chain#delete(Handler) */ Chain put(Handler handler); default Chain put(Class handler) { return put(getRegistry().get(handler)); } /** * Sends an HTTP redirect to the specified location. *

* The handler to add is created via {@link Handlers#redirect(int, String)}. * * @param code the 3XX HTTP status code. * @param location the URL to set in the Location response header * @return this * @see Handlers#redirect(int, String) */ Chain redirect(int code, String location); /** * Makes the contents of the given registry available for downstream handlers of the same nesting level. *

* The registry is inserted via the {@link ratpack.handling.Context#next(Registry)} method. * * @param registry the registry whose contents should be made available to downstream handlers * @return this */ Chain register(Registry registry); /** * Builds a new registry via the given action, then registers it via {@link #register(Registry)}. * * @param action the definition of a registry * @return this * @throws Exception any thrown by {@code action} */ Chain register(Action action) throws Exception; /** * Adds a handler that inserts the given handler chain with the given registry via {@link Context#insert(ratpack.registry.Registry, Handler...)}. * * @param registry the registry to insert * @param action the definition of the handler chain * @return this * @throws Exception any thrown by {@code action} */ Chain register(Registry registry, Action action) throws Exception; default Chain register(Registry registry, Class> action) throws Exception { return register(registry, getRegistry().get(action)); } /** * Adds a handler that inserts the given handler chain with a registry built by the given action via {@link Context#insert(ratpack.registry.Registry, Handler...)}. * * @param registryAction the definition of the registry to insert] * @param action the definition of the handler chain * @return this * @throws Exception any thrown by {@code action} */ Chain register(Action registryAction, Action action) throws Exception; default Chain register(Action registryAction, Class> action) throws Exception { return register(registryAction, getRegistry().get(action)); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy