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.helper;
018
019import static org.forgerock.util.Reject.*;
020
021import org.forgerock.json.fluent.JsonValue;
022import org.forgerock.openig.heap.Heap;
023import org.forgerock.openig.heap.HeapException;
024
025/**
026 * Lazily resolve a {@link JsonValue} reference node against a provided {@link Heap} instance.
027 * Once the reference has been acquired, no other resolution is tried (except for optional references resolved
028 * to {@code null}).
029 * @param <T> expected type of the resolved reference object
030 */
031public final class LazyReference<T> {
032
033    /**
034     * Builds a LazyReference dedicated to resolve the given (optional or not) {@code reference} of type {@code type}
035     * from the given {@code heap}.
036     *
037     * @param heap
038     *         Heap instance that will try to resolve the reference
039     * @param reference
040     *         Reference to be resolved (can be an inline declaration)
041     * @param type
042     *         expected resolved type of the reference
043     * @param optional
044     *         is this reference optional (return {@code null} if the given {@code reference} wraps a {@code null}
045     *         value)
046     * @return  a new LazyReference
047     * @param <R> expected resolved type of the reference
048     */
049    public static <R> LazyReference<R> newReference(final Heap heap,
050                                                    final JsonValue reference,
051                                                    final Class<R> type,
052                                                    final boolean optional) {
053        return new LazyReference<R>(checkNotNull(heap), checkNotNull(reference), type, optional);
054    }
055
056    private final Heap heap;
057    private final JsonValue reference;
058    private final Class<T> type;
059    private final boolean optional;
060
061    private T resolved;
062
063    private LazyReference(final Heap heap, final JsonValue reference, final Class<T> type, final boolean optional) {
064        this.heap = heap;
065        this.reference = reference;
066        this.type = type;
067        this.optional = optional;
068    }
069
070    /**
071     * Resolves the encapsulated reference.
072     * Notice that synchronization is done in the Heap, so no need to cover that here.
073     *
074     * @return the resolved instance, or {@code null} if it was optional and not set.
075     * @throws HeapException
076     *         if resolution failed, this error is the one thrown be the heap, untouched.
077     */
078    public T get() throws HeapException {
079        if (resolved == null) {
080            resolved = heap.resolve(reference, type, optional);
081        }
082        return resolved;
083    }
084
085}