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 2010-2011 ApexIdentity Inc.
015 * Portions Copyright 2011-2015 ForgeRock AS.
016 */
017
018package org.forgerock.openig.filter;
019
020import static org.forgerock.openig.util.JsonValues.ofRequiredHeapObject;
021
022import java.util.List;
023
024import org.forgerock.http.Filter;
025import org.forgerock.http.Handler;
026import org.forgerock.http.handler.Handlers;
027import org.forgerock.http.protocol.Request;
028import org.forgerock.http.protocol.Response;
029import org.forgerock.json.JsonValue;
030import org.forgerock.openig.heap.GenericHeapObject;
031import org.forgerock.openig.heap.GenericHeaplet;
032import org.forgerock.openig.heap.HeapException;
033import org.forgerock.services.context.Context;
034import org.forgerock.util.promise.NeverThrowsException;
035import org.forgerock.util.promise.Promise;
036
037/**
038 * A chain of zero or more filters and one handler. The chain is responsible for
039 * dispatching the request to each filter in the chain, and finally the handler.
040 * <p>
041 * When a chain dispatches a request to a filter, it creates a "subchain" (a subset of this
042 * chain, which contains the remaining downstream filters and handler), and passes it as a
043 * parameter to the filter. For this reason, a filter should make no assumptions or
044 * correlations using the chain it is supplied with when invoked.
045 * <p>
046 * A filter may elect to terminate dispatching of the request to the rest of the chain by not
047 * calling {@code chain.handle(Context, Request)} and generate its own response or dispatch to a
048 * completely different handler.
049 *
050 * @see Filter
051 */
052public class Chain extends GenericHeapObject implements Handler {
053
054    /** The CHF Chain implementation. */
055    private final Handler delegate;
056
057    /**
058     * Builds a chain of filters that will finally dispatch to the given handler.
059     * List of Filters is empty by default.
060     * @param handler terminus of the chain
061     * @param filters list of {@link Filter}s
062     */
063    public Chain(final Handler handler, final List<Filter> filters) {
064        delegate = Handlers.chainOf(handler, filters);
065    }
066
067    @Override
068    public Promise<Response, NeverThrowsException> handle(final Context context, final Request request) {
069        return delegate.handle(context, request);
070    }
071
072    /** Creates and initializes a filter chain in a heap environment. */
073    public static class Heaplet extends GenericHeaplet {
074        @Override
075        public Object create() throws HeapException {
076            Handler terminus = heap.resolve(config.get("handler"),
077                                            Handler.class);
078            JsonValue list = config.get("filters")
079                                   .required()
080                                   .expect(List.class);
081            List<Filter> filters = list.asList(ofRequiredHeapObject(heap, Filter.class));
082            return new Chain(terminus, filters);
083        }
084    }
085}