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 2008 Sun Microsystems, Inc.
015 * Portions copyright 2014-2015 ForgeRock AS.
016 */
017
018package org.forgerock.opendj.config;
019
020import static org.forgerock.util.Utils.closeSilently;
021
022import java.io.BufferedInputStream;
023import java.io.IOException;
024import java.io.InputStream;
025import java.util.HashMap;
026import java.util.Map;
027import java.util.MissingResourceException;
028import java.util.Properties;
029
030/**
031 * A class for retrieving non-internationalized resource properties associated
032 * with a managed object definition.
033 * <p>
034 * Resource properties are not available for the {@link TopCfgDefn}.
035 */
036public final class ManagedObjectDefinitionResource {
037
038    /** Mapping from definition to property tables. */
039    private final Map<AbstractManagedObjectDefinition<?, ?>, Properties> properties = new HashMap<>();
040
041    /** The resource name prefix. */
042    private final String prefix;
043
044    /**
045     * Creates a new resource instance for the named profile.
046     *
047     * @param profile
048     *            The name of the profile.
049     * @return Returns the resource instance for the named profile.
050     */
051    public static ManagedObjectDefinitionResource createForProfile(String profile) {
052        return new ManagedObjectDefinitionResource("config.profiles." + profile);
053    }
054
055    /** Private constructor. */
056    private ManagedObjectDefinitionResource(String prefix) {
057        this.prefix = prefix;
058    }
059
060    /**
061     * Get the resource value associated with the specified key.
062     *
063     * @param d
064     *            The managed object definition.
065     * @param key
066     *            The resource key.
067     * @return Returns the resource value associated with the specified key.
068     * @throws MissingResourceException
069     *             If the key was not found.
070     * @throws UnsupportedOperationException
071     *             If the provided managed object definition was the
072     *             {@link TopCfgDefn}.
073     */
074    public String getString(AbstractManagedObjectDefinition<?, ?> d, String key) {
075        if (d.isTop()) {
076            throw new UnsupportedOperationException("Profile resources are not available for the "
077                + "Top configuration definition");
078        }
079
080        Properties p = getProperties(d);
081        String result = p.getProperty(key);
082
083        if (result == null) {
084            String baseName = prefix + "." + d.getClass().getName();
085            String path = baseName.replace('.', '/') + ".properties";
086
087            throw new MissingResourceException("Can't find resource " + path + ", key " + key, baseName, key);
088        }
089
090        return result;
091    }
092
093    /**
094     * Retrieve the properties table associated with a managed object,
095     * lazily loading it if necessary.
096     */
097    private synchronized Properties getProperties(AbstractManagedObjectDefinition<?, ?> d) {
098        Properties p = properties.get(d);
099
100        if (p == null) {
101            // Load the resource file.
102            String baseName = prefix + "." + d.getClass().getName();
103            String path = baseName.replace('.', '/') + ".properties";
104            InputStream stream = ConfigurationFramework.getInstance().getClassLoader().getResourceAsStream(path);
105
106            if (stream == null) {
107                throw new MissingResourceException("Can't find resource " + path, baseName, "");
108            }
109
110            final InputStream is = new BufferedInputStream(stream);
111            p = new Properties();
112            try {
113                p.load(is);
114            } catch (IOException e) {
115                throw new MissingResourceException("Can't load resource " + path
116                        + " due to IO exception: " + e.getMessage(), baseName, "");
117            } finally {
118                closeSilently(is);
119            }
120
121            // Cache the resource.
122            properties.put(d, p);
123        }
124
125        return p;
126    }
127}