/* $Id: ConfigurationProperties.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.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.net.URL; import java.util.Properties; import org.apache.log4j.Logger; /** * This class provides a user configuration based upon * the properties file "argo.user.properties" in the user's home directory. * * @author Thierry Lach */ class ConfigurationProperties extends ConfigurationHandler { /** * Logger. */ private static final Logger LOG = Logger.getLogger(ConfigurationProperties.class); /** * The location of Argo's default properties resource. */ private static String propertyLocation = "/org/argouml/resource/default.properties"; /** * The primary property bundle. */ private Properties propertyBundle; /** * Flag to ensure that only the first load failure is reported * even though we keep trying because the file or URL may only * be temporarily unavailable. */ private boolean canComplain = true; /** * Anonymous constructor. */ ConfigurationProperties() { super(true); Properties defaults = new Properties(); try { defaults.load(getClass().getResourceAsStream(propertyLocation)); LOG.debug("Configuration loaded from " + propertyLocation); } catch (Exception ioe) { // TODO: What should we do here? LOG.warn("Configuration not loaded from " + propertyLocation, ioe); } propertyBundle = new Properties(defaults); } /** * Returns the default path for user properties. * * @return a generic path string. */ public String getDefaultPath() { return System.getProperty("user.home") + "/.argouml/argo.user.properties"; } /** * Returns the default path for user properties (before 0.25.4) * @return a generic path string */ private String getOldDefaultPath() { return System.getProperty("user.home") + "/argo.user.properties"; } /** * Copy a file from source to destination. * * TODO: Perhaps belongs in a utilities class of some sort. * * @param source the source file to be copied * @param dest the destination file * @return success status flag */ private static boolean copyFile(final File source, final File dest) { try { final FileInputStream fis = new FileInputStream(source); final FileOutputStream fos = new FileOutputStream(dest); byte[] buf = new byte[1024]; int i = 0; while ((i = fis.read(buf)) != -1) { fos.write(buf, 0, i); } fis.close(); fos.close(); return true; } catch (final FileNotFoundException e) { LOG.error("File not found while copying", e); return false; } catch (final IOException e) { LOG.error("IO error copying file", e); return false; } catch (final SecurityException e) { LOG.error("You are not allowed to copy these files", e); return false; } } /** * Load the configuration from a specified location. <p> * * Before version 0.25.4, ArgoUML used to store the * properties file in a different location. A user who * upgrades his ArgoUML to a newer version, * would not like to loose his settings. * Hence, in case a properties file does not exist * (in the new location), * this code attempts to copy the file * from the old location to the new location. <p> * * In this upgrade case, the properties file * is copied, not moved. * Rationale: see issue 5364. <p> * * The meaning of the return value is not simply success * in loading the properties file, * but it indicates if we may save the properties * on top of this file later. * Hence, in case a properties file did not exist * (not in the new location, nor in the old location), * then a new empty file is created, * and in this case the return value is true. <p> * * Returning false here would mean that no properties * will be saved at all. * * @param file the path to load the configuration from. * * @return true if the given file-location may be used * for writing the properties later. */ public boolean loadFile(File file) { try { if (!file.exists()) { // check for the older properties file and // copy it over if possible // This is done for compatibility with previous version: // Move the argo.user.properties // written before 0.25.4 to the new location, if it exists. final File oldFile = new File(getOldDefaultPath()); if (oldFile.exists() && oldFile.isFile() && oldFile.canRead() && file.getParentFile().canWrite()) { // copy to new file and let the regular load code // do the actual load final boolean result = copyFile(oldFile, file); if (result) { LOG.info("Configuration copied from " + oldFile + " to " + file); } else { LOG.error("Error copying old configuration to new, " + "see previous log messages"); } } else { try { file.createNewFile(); } catch (IOException e) { LOG.error("Could not create the properties file at: " + file.getAbsolutePath(), e); } } } if (file.exists() && file.isFile() && file.canRead()) { try { propertyBundle.load(new FileInputStream(file)); LOG.info("Configuration loaded from " + file); return true; } catch (final IOException e) { if (canComplain) { LOG.warn("Unable to load configuration " + file); } canComplain = false; } } } catch (final SecurityException e) { LOG.error("A security exception occurred trying to load" + " the configuration, check your security settings", e); } return false; } /** * Save the configuration to a specified location. * * @param file the path to save the configuration at. * * @return true if the save was successful, false if not. */ public boolean saveFile(File file) { try { propertyBundle.store(new FileOutputStream(file), "ArgoUML properties"); LOG.info("Configuration saved to " + file); return true; } catch (Exception e) { if (canComplain) { LOG.warn("Unable to save configuration " + file + "\n"); } canComplain = false; } return false; } /** * Load the configuration from a specified location. * * @param url the path to load the configuration from. * * @return true if the load was successful, false if not. */ public boolean loadURL(URL url) { try { propertyBundle.load(url.openStream()); LOG.info("Configuration loaded from " + url + "\n"); return true; } catch (Exception e) { if (canComplain) { LOG.warn("Unable to load configuration " + url + "\n"); } canComplain = false; return false; } } /** * Save the configuration to a specified location. * * @param url the path to save the configuration at. * * @return true if the save was successful, false if not. */ public boolean saveURL(URL url) { // LOG.info("Configuration saved to " + url + "\n"); return false; } /** * Returns the string value of a configuration property. * * @param key the key to return the value of. * @param defaultValue the value to return if the key was not found. * * @return the string value of the key if found, otherwise null; */ public String getValue(String key, String defaultValue) { String result = ""; try { result = propertyBundle.getProperty(key, defaultValue); } catch (Exception e) { result = defaultValue; } return result; } /** * Sets the string value of a configuration property. * * @param key the key to set. * @param value the value to set the key to. */ public void setValue(String key, String value) { LOG.debug("key '" + key + "' set to '" + value + "'"); propertyBundle.setProperty(key, value); } /** * Remove a property. * * @param key The property to remove. */ public void remove(String key) { propertyBundle.remove(key); } }