/* $Id: ConfigurationHandler.java 17819 2010-01-12 18:40:41Z linus $ ***************************************************************************** * Copyright (c) 2009 Contributors - see below * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * linus ***************************************************************************** * * Some portions of this file was previously release using the BSD License: */ // Copyright (c) 1996-2007 The Regents of the University of California. All // Rights Reserved. Permission to use, copy, modify, and distribute this // software and its documentation without fee, and without a written // agreement is hereby granted, provided that the above copyright notice // and this paragraph appear in all copies. This software program and // documentation are copyrighted by The Regents of the University of // California. The software program and documentation are supplied "AS // IS", without any accompanying services from The Regents. The Regents // does not warrant that the operation of the program will be // uninterrupted or error-free. The end-user understands that the program // was developed for research purposes and is advised not to rely // exclusively on the program for any reason. IN NO EVENT SHALL THE // UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, // SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, // ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF // THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF // SUCH DAMAGE. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE // PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF // CALIFORNIA HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT, // UPDATES, ENHANCEMENTS, OR MODIFICATIONS. package org.argouml.configuration; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.io.File; import java.net.URL; import org.apache.log4j.Logger; /** * This class provides a user configuration based upon properties. * This provides an implementation-free interface to a configuration * repository. Any classes which need to implement a configuration * datastore must extend this class. * * All of the required behavioral logic for the configuration is * contained within this class, as public final methods. Any * storage-related logic must be handled by the extending class. * These methods are abstract. * * This class is intimately related to * {@link org.argouml.configuration.Configuration}. * * @author Thierry Lach * * @since 0.9.4 */ public abstract class ConfigurationHandler { /** * Internal storage for the <code>File</code> the configuration was * loaded from, otherwise null. */ private File loadedFromFile; /** * Internal storage for the <code>URL</code> the configuration was * loaded from, otherwise null. */ private URL loadedFromURL; /** * Internal flag indicating whether the configuration can be updated. */ private boolean changeable; /** * Internal flag indicating whether the configuration has been loaded. * Configuration rules allow a single load, whether manual or automatic. */ private boolean loaded; /** * Internal worker for property change. */ private static PropertyChangeSupport pcl; /** * Logger. */ private static final Logger LOG = Logger.getLogger(ConfigurationHandler.class); /** * Anonymous constructor allows configuration changes. */ public ConfigurationHandler() { this(true); } /** * Constructor which optionally allows configuration changes. * * @param c indicates if the configuration can be changed */ public ConfigurationHandler(boolean c) { super(); changeable = c; } /** * Returns a default configuration path. This could be a filename * or a URL. It is not guaranteed to be usable across different * implementations of ConfigurationHandler. * * @return the default configuration path or url. */ public abstract String getDefaultPath(); /** * Internal worker which is called prior to any getValue * or setValue to ensure that the default load is done if it was not * loaded previously. */ private void loadIfNecessary() { if (!loaded) { loadDefault(); } } /** * Load the configuration from the default location. * * @return true if this call loaded the configuration, * otherwise false, not distinguishing between a load * error or a previously loaded configuration. * * @see #isLoaded */ public final boolean loadDefault() { // Only allow one load if (loaded) { return false; } boolean status = load(new File(getDefaultPath())); if (!status) { status = loadUnspecified(); } loaded = true; return status; } /** * Save the configuration to the location it was loaded from. * Do not force it if the configuration was not loaded already. * * @return true if the save was successful, false if it was not * attempted or encountered an error. */ public final boolean saveDefault() { return saveDefault(false); } /** * Save the configuration to the location it was loaded from. * * @param force the save even if it would not normally be done. * @return true if the save was successful, false if it was not * attempted or encountered an error. */ public final boolean saveDefault(boolean force) { if (force) { File toFile = new File(getDefaultPath()); boolean saved = saveFile(toFile); if (saved) { loadedFromFile = toFile; } return saved; } if (!loaded) { return false; } if (loadedFromFile != null) { return saveFile(loadedFromFile); } if (loadedFromURL != null) { return saveURL(loadedFromURL); } return false; } /** * Indicates whether the configuration can be saved. * * @return true if the configuration can be saved. */ public final boolean isChangeable() { return changeable; } /** * Indicates whether the configuration has been loaded. * * @return true if the configuration has been loaded. */ public final boolean isLoaded() { return loaded; } /** * Load the configuration from a <code>File</code>. * * @param file to load from. * @return true if this call loaded the configuration, * otherwise false, not distinguishing between a load * error or a previously loaded configuration. */ public final boolean load(File file) { boolean status = loadFile(file); if (status) { if (pcl != null) { pcl.firePropertyChange(Configuration.FILE_LOADED, null, file); } loadedFromFile = file; } return status; } /** * Load the configuration from a <code>URL</code>. * * @param url to load from. * @return true if this call loaded the configuration, * otherwise false, not distinguishing between a load * error or a previously loaded configuration. */ public final boolean load(URL url) { boolean status = loadURL(url); if (status) { if (pcl != null) { pcl.firePropertyChange(Configuration.URL_LOADED, null, url); } loadedFromURL = url; } return status; } /** * Save the configuration to a <code>File</code>. * * @param file to save to. * @return true if this call saved the configuration, * otherwise false. */ public final boolean save(File file) { if (!loaded) { return false; } boolean status = saveFile(file); if (status) { if (pcl != null) { pcl.firePropertyChange(Configuration.FILE_SAVED, null, file); } } return status; } /** * Save the configuration to a <code>URL</code>. * * @param url to save to. * @return true if this call saved the configuration, * otherwise false. */ public final boolean save(URL url) { if (!loaded) { return false; } boolean status = saveURL(url); if (status) { if (pcl != null) { pcl.firePropertyChange(Configuration.URL_SAVED, null, url); } } return status; } /** * Returns the string value of a configuration property. * * @param key the configuration key to return. * @param defaultValue the default value key to return * if the key is not found. * * @return the value of the key or the default value * if the key does not exist. */ public final String getString(ConfigurationKey key, String defaultValue) { loadIfNecessary(); return getValue(key.getKey(), defaultValue); } /** * Returns the numeric value of a configuration property. * * @param key the configuration key to return. * @param defaultValue the default value key to return * if the key is not found. * * @return the value of the key or the default value * if the key does not exist. */ public final int getInteger(ConfigurationKey key, int defaultValue) { loadIfNecessary(); try { String s = getValue(key.getKey(), Integer.toString(defaultValue)); return Integer.parseInt(s); } catch (NumberFormatException nfe) { return defaultValue; } } /** * Returns the numeric value of a configuration property. * * @param key the configuration key to return. * @param defaultValue the default value key to return * if the key is not found. * * @return the value of the key or the default value * if the key does not exist. */ public final double getDouble(ConfigurationKey key, double defaultValue) { loadIfNecessary(); try { String s = getValue(key.getKey(), Double.toString(defaultValue)); return Double.parseDouble(s); } catch (NumberFormatException nfe) { return defaultValue; } } /** * Returns the boolean value of a configuration property. * * @param key the configuration key to return. * @param defaultValue the default value key to return * if the key is not found. * * @return the value of the key or the default value * if the key does not exist. */ public final boolean getBoolean(ConfigurationKey key, boolean defaultValue) { loadIfNecessary(); Boolean dflt = Boolean.valueOf(defaultValue); Boolean b = key != null ? Boolean.valueOf(getValue(key.getKey(), dflt.toString())) : dflt; return b.booleanValue(); } /** * Internal routine which calls the abstract setValue and handles * all necessary functionality including firing property change * notifications and tracing. * * @param key the configuration key to modify. * @param newValue the new value of the key. */ private synchronized void workerSetValue(ConfigurationKey key, String newValue) { loadIfNecessary(); String oldValue = getValue(key.getKey(), ""); setValue(key.getKey(), newValue); if (pcl != null) { pcl.firePropertyChange(key.getKey(), oldValue, newValue); } } /** * Sets the string value of a configuration property. * * @param key the configuration key to modify. * @param newValue the value to set the key to. */ public final void setString(ConfigurationKey key, String newValue) { workerSetValue(key, newValue); } /** * Sets the numeric value of a configuration property. * * @param key the configuration key to modify. * @param value the value to set the key to. */ public final void setInteger(ConfigurationKey key, int value) { workerSetValue(key, Integer.toString(value)); } /** * Sets the numeric value of a configuration property. * * @param key the configuration key to modify. * @param value the value to set the key to. */ public final void setDouble(ConfigurationKey key, double value) { workerSetValue(key, Double.toString(value)); } /** * Sets the boolean value of a configuration property. * * @param key the configuration key to modify. * @param value the value to set the key to. */ public final void setBoolean(ConfigurationKey key, boolean value) { Boolean bool = Boolean.valueOf(value); workerSetValue(key, bool.toString()); } /** * Adds a property change listener. * * @param p The class which will listen for property changes. */ public final void addListener(PropertyChangeListener p) { if (pcl == null) { pcl = new PropertyChangeSupport(this); } LOG.debug("addPropertyChangeListener(" + p + ")"); pcl.addPropertyChangeListener(p); } /** * Removes a property change listener. * * @param p The class to remove as a property change listener. */ public final void removeListener(PropertyChangeListener p) { if (pcl != null) { LOG.debug("removePropertyChangeListener()"); pcl.removePropertyChangeListener(p); } } /** * Adds a property change listener.Static for simplicity of use. * * @param key The specific key to listen for. * @param p The class which will listen for property changes. */ public final void addListener(ConfigurationKey key, PropertyChangeListener p) { if (pcl == null) { pcl = new PropertyChangeSupport(this); } LOG.debug("addPropertyChangeListener(" + key.getKey() + ")"); pcl.addPropertyChangeListener(key.getKey(), p); } /** * Removes a property change listener. * * @param key The specific key being listened for. * @param p The class to remove as a property change listener. */ public final void removeListener(ConfigurationKey key, PropertyChangeListener p) { if (pcl != null) { LOG.debug("removePropertyChangeListener(" + key.getKey() + ")"); pcl.removePropertyChangeListener(key.getKey(), p); } } /** * Internal processing to load from an unspecified source. * * @return true if the load was successful, otherwise false. */ boolean loadUnspecified() { return false; } /** * Internal processing to save to an unspecified source. * * @return true if the save was successful, otherwise false. */ boolean saveUnspecified() { return false; } /** * Internal processing to load a <code>File</code>. * * @param file the file to load. * * @return true if the load was successful, otherwise false. */ public abstract boolean loadFile(File file); /** * Internal processing to load a <code>URL</code>. * * @param url the url to load. * * @return true if the load was successful, otherwise false. */ public abstract boolean loadURL(URL url); /** * Internal processing to save a <code>File</code>. * * @param file the file to save. * * @return true if the save was successful, otherwise false. */ public abstract boolean saveFile(File file); /** * Internal processing to save a <code>URL</code>. * * @param url the url to save. * * @return true if the save was successful, otherwise false. */ public abstract boolean saveURL(URL url); /** * Allows query for the existence of a configuration property. * This may be overridden if the implementation has a * more efficient method. * * @param key the property being checked. * * @return true if the key exists, otherwise false. */ public boolean hasKey(ConfigurationKey key) { return getValue(key.getKey(), "true").equals(getValue(key.getKey(), "false")); } /** * Returns the string value of a configuration property. * * @param key the configuration key to return. * @param defaultValue the configuration key to return. * * @return the value of the key or the default value * if the key does not exist. */ public abstract String getValue(String key, String defaultValue); /** * Sets the string value of a configuration property. * * @param key the configuration key to modify. * @param value the value to set the key to. */ public abstract void setValue(String key, String value); /** * Remove the property and the assotiated value. * * @param key The key to remove. */ public abstract void remove(String key); }