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 2014-2015 ForgeRock AS.
015 */
016
017package org.forgerock.services.context;
018
019import org.forgerock.json.JsonValue;
020
021/**
022 * Type-safe contextual information associated with the processing of a request in an application.
023 * Contexts are linked together in a stack with a {@link RootContext} at the bottom of the stack. Each context
024 * maintains a reference to its parent context which can be accessed using the {@link #getParent()}} method.
025 * Context implementations may provide information about the client, the end-user, auditing information, routing
026 * decisions, etc. While contexts are arranged in a stack, application code will usually access contexts using the
027 * {@link #asContext(Class)} method:
028 *
029 * <pre>
030 *     Context context = ...; // Opaque reference to the context stack
031 *
032 *     String remoteHost = context.asContext(ClientContext.class).getRemoteHost();
033 *     context.asContext(AttributesContext.class).getAttributes().put("key", "value");
034 * </pre>
035 *
036 * Alternatively, scripted applications will usually access contexts by name:
037 *
038 * <pre>
039 *     var remoteHost = context.client.remoteHost;
040 *     context.attributes.key = "value";
041 * </pre>
042 *
043 * Context implementations should inherit from {@link AbstractContext} and ensure that they can be serialized to and
044 * from JSON.
045 */
046public interface Context {
047
048    /**
049     * Get this Context's name.
050     *
051     * @return this object's name
052     */
053    String getContextName();
054
055    /**
056     * Returns the first context in the chain whose type is a sub-type of the
057     * provided {@code Context} class. The method first checks this context to
058     * see if it has the required type, before proceeding to the parent context,
059     * and then continuing up the chain of parents until the root context is
060     * reached.
061     *
062     * @param <T>
063     *            The context type.
064     * @param clazz
065     *            The class of context to be returned.
066     * @return The first context in the chain whose type is a sub-type of the
067     *         provided {@code Context} class.
068     * @throws IllegalArgumentException
069     *             If no matching context was found in this context's parent
070     *             chain.
071     */
072    <T extends Context> T asContext(Class<T> clazz);
073
074    /**
075     * Returns the first context in the chain whose context name matches the
076     * provided name.
077     *
078     * @param contextName
079     *            The name of the context to be returned.
080     * @return The first context in the chain whose name matches the
081     *         provided context name.
082     * @throws IllegalArgumentException
083     *             If no matching context was found in this context's parent
084     *             chain.
085     */
086    Context getContext(String contextName);
087
088    /**
089     * Returns {@code true} if there is a context in the chain whose type is a
090     * sub-type of the provided {@code Context} class. The method first checks
091     * this context to see if it has the required type, before proceeding to the
092     * parent context, and then continuing up the chain of parents until the
093     * root context is reached.
094     *
095     * @param clazz
096     *            The class of context to be checked.
097     * @return {@code true} if there is a context in the chain whose type is a
098     *         sub-type of the provided {@code Context} class.
099     */
100    boolean containsContext(Class<? extends Context> clazz);
101
102    /**
103     * Returns {@code true} if there is a context in the chain whose name
104     * matches the provided context name.
105     *
106     * @param contextName
107     *            The name of the context to locate.
108     * @return {@code true} if there is a context in the chain whose context name
109     *            matches {@code contextName}.
110     */
111    boolean containsContext(String contextName);
112
113    /**
114     * Returns the unique ID identifying this context, usually a UUID.
115     *
116     * @return The unique ID identifying this context.
117     */
118    String getId();
119
120    /**
121     * Returns the parent of this context.
122     *
123     * @return The parent of this context, or {@code null} if this context is a
124     *         root context.
125     */
126    Context getParent();
127
128    /**
129     * Returns {@code true} if this context is a root context.
130     *
131     * @return {@code true} if this context is a root context.
132     */
133    boolean isRootContext();
134
135    /**
136     * Return this Context as a JsonValue (for persistence).
137     *
138     * @return the Context data as a JsonValue.
139     */
140    JsonValue toJsonValue();
141}