/* * $Id$ * * Copyright 2006, The jCoderZ.org Project. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * Neither the name of the jCoderZ.org Project nor the names of * its contributors may be used to endorse or promote products * derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.jcoderz.commons.config; import java.util.Enumeration; import java.util.HashSet; import java.util.Iterator; import java.util.MissingResourceException; import java.util.ResourceBundle; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; /** * This ConfigurationCache implementation is based on a property file. * */ public final class ConfigurationCacheByPropertiesImpl implements ConfigurationCacheInterface { // the property file's bundle name for the configuration private static final String BUNDLE_NAME = "org.jcoderz.commons.config.configuration"; /** * Name of this class */ private static final String CLASSNAME = ConfigurationCacheByPropertiesImpl.class.getName(); /** * Logger for this class */ private static final Logger logger = Logger.getLogger(CLASSNAME); /** * The resource bundle where the config data is cached. * It contains the cached Configuration values. * The key is a ConfigurationKey object and the value * a String representing the value. */ private ResourceBundle mResourceBundle = null; /** * cache the configuration keys also, to prevent set creation for every * getKeys() call */ private Set mConfigurationKeys = null; /** * This Set contains the Services that have been registered to receive * notifications when the cache has been changed. * The Set contains objects that implement the ConfigurationListener * interface. */ private final Set mRegisteredServices = new HashSet(); private boolean mIsInitialized; private Exception mInitException; /** * Singleton has no public constructor * * @see ConfigurationCacheByPropertiesImpl#current */ private ConfigurationCacheByPropertiesImpl () { try { init(); mIsInitialized = true; mInitException = null; } catch (Exception x) { mIsInitialized = false; mInitException = x; final ConfigurationInitializationFailedException sysEvt = new ConfigurationInitializationFailedException(x); sysEvt.log(); } } /** * Returns a reference to the one and only object instance of this * class. Use this method to access the object's methods. * * @return a reference to the one and only object instance of this class. */ public static ConfigurationCacheByPropertiesImpl current () { final ConfigurationCacheByPropertiesImpl result = ConfigurationCacheHolder.INSTANCE; if (! result.mIsInitialized) { throw new ConfigurationInitializationFailedException( result.mInitException); } return result; } /** * Setup configuration cache as MBean and initialize cache. */ private void init () { final String method = "init"; if (logger.isLoggable(Level.FINER)) { logger.entering(CLASSNAME, method); } reloadCache(); if (logger.isLoggable(Level.FINER)) { logger.exiting(CLASSNAME, method); } } /** * @see ConfigurationCacheInterface#getString * Returns the String value set for the given configuration key. * @param key the key to look up. * @return the value as string. * @throws ConfigurationValueNotFoundException if the key is not set or * the resource was not found. */ public String getString (String key) throws ConfigurationValueNotFoundException { final String result; try { result = mResourceBundle.getString(key); CfgLogMessage.ConfigurationValueRead.log(key, result); } catch (MissingResourceException e) { throw new ConfigurationValueNotFoundException(key, e); } return result; } /** {@inheritDoc} */ public Set getKeys () { return mConfigurationKeys; } /** {@inheritDoc} */ public void addConfigurationListener (ConfigurationListener newListener) { mRegisteredServices.add(newListener); } /** * Reloads the internal configuration cache from resource bundle. * If an exception occurs during, the old cached properties are * returned. */ public void reloadCache () { final String method = "reloadCache"; if (logger.isLoggable(Level.FINER)) { logger.entering(CLASSNAME, method); } try { mResourceBundle = ResourceBundle.getBundle(BUNDLE_NAME); final Enumeration keys = mResourceBundle.getKeys(); mConfigurationKeys = new HashSet(java.util.Collections.list(keys)); } catch (Exception e) { final ConfigurationInitializationFailedException cife = new ConfigurationInitializationFailedException(e); // CHECKME: create special config cache reload exception? cife.addParameter("DETAIL", "Exception while updating ConfigurationCache."); throw cife; } if (logger.isLoggable(Level.FINER)) { logger.exiting(CLASSNAME, method); } notifyServices(); } /** * Notifies all registered services about the cache update. */ private void notifyServices () { final Iterator it = mRegisteredServices.iterator(); final ConfigUpdateEvent event = new ConfigUpdateEvent(this, ConfigUpdateEvent.CACHE_UPDATED); while (it.hasNext()) { ((ConfigurationListener) it.next()).updateConfiguration(event); } } /** * Local helper class holding a member initialized by calling * the private constructor of the singleton. */ private static final class ConfigurationCacheHolder { private static final ConfigurationCacheByPropertiesImpl INSTANCE = new ConfigurationCacheByPropertiesImpl(); } }