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-2014 ForgeRock AS.
016 */
017
018package org.forgerock.openig.heap;
019
020import static org.forgerock.openig.io.TemporaryStorage.*;
021import static org.forgerock.openig.log.LogSink.*;
022
023import java.util.Arrays;
024import java.util.HashSet;
025import java.util.Map;
026import java.util.Set;
027
028import org.forgerock.json.fluent.JsonValue;
029import org.forgerock.openig.io.TemporaryStorage;
030import org.forgerock.openig.log.LogSink;
031import org.forgerock.openig.log.Logger;
032
033/**
034 * A generic base class for heaplets with automatically injected fields.
035 * <p>
036 * If the object created is an instance of {@link GenericHeapObject}, it is then
037 * automatically injected with {@code logger} and {@code storage} objects.
038 */
039public abstract class GenericHeaplet implements Heaplet {
040
041    /** Heap objects to avoid dependency injection (prevents circular dependencies). */
042    private static final Set<String> SPECIAL_OBJECTS =
043            new HashSet<String>(Arrays.asList(LOGSINK_HEAP_KEY, TEMPORARY_STORAGE_HEAP_KEY));
044
045    /** The name of the object to be created and stored in the heap by this heaplet. */
046    protected String name;
047
048    /** The fully qualified name of the object to be created. */
049    protected Name qualified;
050
051    /** The heaplet's object configuration object. */
052    protected JsonValue config;
053
054    /** Where objects should be put and where object dependencies should be retrieved. */
055    protected Heap heap;
056
057    /** Provides methods for logging activities. */
058    protected Logger logger;
059
060    /** Allocates temporary buffers for caching streamed content during processing. */
061    protected TemporaryStorage storage;
062
063    /** The object created by the heaplet's {@link #create()} method. */
064    protected Object object;
065
066    @Override
067    public Object create(Name name, JsonValue config, Heap heap) throws HeapException {
068        this.name = name.getLeaf();
069        this.qualified = name;
070        this.config = config.required().expect(Map.class);
071        this.heap = heap;
072        if (!SPECIAL_OBJECTS.contains(this.name)) {
073            this.logger = new Logger(
074                    heap.resolve(
075                            config.get("logSink").defaultTo(LOGSINK_HEAP_KEY),
076                            LogSink.class, true),
077                    name);
078            this.storage = heap.resolve(
079                    config.get("temporaryStorage").defaultTo(TEMPORARY_STORAGE_HEAP_KEY),
080                    TemporaryStorage.class);
081        }
082        this.object = create();
083        if (this.object instanceof GenericHeapObject) {
084            // instrument object if possible
085            GenericHeapObject ghObject = (GenericHeapObject) this.object;
086            ghObject.logger = this.logger;
087            ghObject.storage = this.storage;
088        }
089        start();
090        return object;
091    }
092
093    @Override
094    public void destroy() {
095        // default does nothing
096    }
097
098    /**
099     * Called to request the heaplet create an object. Called by
100     * {@link Heaplet#create(Name, JsonValue, Heap)} after initializing
101     * the protected field members. Implementations should parse configuration
102     * but not acquire resources, start threads, or log any initialization
103     * messages. These tasks should be performed by the {@link #start()} method.
104     *
105     * @return The created object.
106     * @throws HeapException
107     *             if an exception occurred during creation of the heap object
108     *             or any of its dependencies.
109     * @throws org.forgerock.json.fluent.JsonValueException
110     *             if the heaplet (or one of its dependencies) has a malformed
111     *             configuration.
112     */
113    public abstract Object create() throws HeapException;
114
115    /**
116     * Called to request the heaplet start an object. Called by
117     * {@link Heaplet#create(Name, JsonValue, Heap)} after creating and
118     * configuring the object and once the object's logger and storage have been
119     * configured. Implementations should override this method if they need to
120     * acquire resources, start threads, or log any initialization messages.
121     *
122     * @throws HeapException
123     *             if an exception occurred while starting the heap object or
124     *             any of its dependencies.
125     */
126    public void start() throws HeapException {
127        // default does nothing
128    }
129}