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 ForgeRock AS.
015 */
016
017package org.forgerock.openig.decoration.global;
018
019import java.util.Map;
020
021import org.forgerock.json.fluent.JsonValue;
022import org.forgerock.openig.decoration.Context;
023import org.forgerock.openig.decoration.Decorator;
024import org.forgerock.openig.heap.HeapException;
025
026/**
027 * A GlobalDecorator stores decorators configuration in order to re-apply them when requested
028 * to decorate a given heap object instance.
029 */
030public class GlobalDecorator implements Decorator {
031
032    /**
033     * Heap Key for the global decorator(s). They may be local to each Heap.
034     */
035    public static final String GLOBAL_DECORATOR_HEAP_KEY = "global-decorator";
036
037    private final Decorator parent;
038    private final JsonValue decorators;
039
040    /**
041     * Builds a new GlobalDecorator using given decorators JSON object element.
042     *
043     * @param parent
044     *            the parent global decorator from which additional global
045     *            decorators may be inherited. May be {@code null}
046     * @param config
047     *            a JSON configuration
048     * @param reservedFieldNames
049     *            the names of reserved top level fields in the config which
050     *            should not be parsed as global decorators
051     */
052    public GlobalDecorator(final Decorator parent, final JsonValue config,
053            final String... reservedFieldNames) {
054        this.parent = parent;
055        // create a copy of the config with the reserved names filtered out
056        this.decorators = config.expect(Map.class).clone();
057        for (String reservedFieldName : reservedFieldNames) {
058            decorators.remove(reservedFieldName);
059        }
060    }
061
062    @Override
063    public boolean accepts(final Class<?> type) {
064        // Not used
065        return true;
066    }
067
068    /**
069     * Decorate the given object instance with the previously declared set of decorations instead of the provided one.
070     *
071     * @param delegate
072     *         instance to decorate
073     * @param ignored
074     *         ignored (may probably be {@code null})
075     * @param context
076     *         Context of the heap object to be decorated
077     * @return the decorated instance or the original delegate (if no decorator could apply)
078     * @throws HeapException
079     *         if one of the decorator failed to decorate the instance
080     */
081    @Override
082    public Object decorate(final Object delegate, final JsonValue ignored, final Context context)
083            throws HeapException {
084        Object decorated = parent != null ? parent.decorate(delegate, ignored, context) : delegate;
085        for (JsonValue decoration : decorators) {
086            String decoratorName = decoration.getPointer().leaf();
087            // Process the decoration
088            Decorator decorator = context.getHeap().get(decoratorName, Decorator.class);
089
090            if ((decorator != null) && decorator.accepts(delegate.getClass())) {
091                decorated = decorator.decorate(decorated, decoration, context);
092            }
093        }
094        return decorated;
095    }
096}