1 /* 2 * Zemucan: A Syntax Assistant for DB2 3 * Copyright (C) 2009, 2010 Andres Gomez Casanova 4 * 5 * This file is part of Zemucan. 6 * 7 * Zemucan is free software: you can redistribute it and/or modify 8 * it under the terms of the GNU Lesser General Public License as published by 9 * the Free Software Foundation; either version 3 of the License, or 10 * (at your option) any later version. 11 * 12 * Zemucan is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public License 18 * along with this library; if not, see <http://www.gnu.org/licenses/>. 19 * 20 * Contact: 21 * a n g o c a at y a h o o dot c o m 22 * Cra. 45 No 61 - 31, Bogota, Colombia. 23 * 24 * Author: $LastChangedBy: angoca $: 25 * Date: $LastChangedDate: 2011-03-07 00:34:33 -0500 (lun, 07 mar 2011) $: 26 * Revision: $LastChangedRevision: 1924 $: 27 * URL: $HeadURL: https://zemucan.svn.sourceforge.net/svnroot/zemucan/branches/zemucan_v1/source-code/tools/src/main/java/name/angoca/zemucan/tools/configurator/Configurator.java $: 28 */ 29 package name.angoca.zemucan.tools.configurator; 30 31 import java.util.Enumeration; 32 import java.util.Properties; 33 34 import name.angoca.zemucan.tools.Constants; 35 import name.angoca.zemucan.tools.messages.Messages; 36 37 import org.slf4j.Logger; 38 import org.slf4j.LoggerFactory; 39 40 /** 41 * This class loads the configuration of the application. The implementation is 42 * with a singleton. The name of the configuration file is in a Constant 43 * (SA_CONF_XML_FILENAME = sa_conf.xml) This class is not thread safe because the 44 * singleton does not have a synchronized part. 45 * <p> 46 * This class defines all the default values in a set of constants; their names 47 * are in the Constants interface. 48 * <p> 49 * <b>Control Version</b> 50 * <p> 51 * <ul> 52 * <li>0.0.1 Class creation.</li> 53 * <li>0.1.0 Singleton and get method.</li> 54 * <li>0.1.1 Basic configuration and new values.</li> 55 * <li>0.2.0 Destroy instance and set property.</li> 56 * <li>0.2.1 Warn level when file problem.</li> 57 * <li>0.2.2 Use of constants.</li> 58 * <li>0.2.3 getInstance synchronized.</li> 59 * <li>0.3.0 Remove of circular dependencies.</li> 60 * <li>0.3.1 Include file name in log.</li> 61 * <li>0.3.2 Log the filename.</li> 62 * <li>1.0.0 Moved to version 1.</li> 63 * <li>1.0.1 zemucan conf file and property.</li> 64 * <li>1.1.0 Delimiters deleted.</li> 65 * <li>1.2.0 Exception hierarchy changed.</li> 66 * <li>1.3.0 Exit and prompt token, and publics.</li> 67 * <li>1.3.1 Log modified.</li> 68 * <li>1.3.2 Not synchronized, not thread safe.</li> 69 * <li>1.3.3 Strings externalized.</li> 70 * <li>1.3.4 Assert.</li> 71 * <li>1.3.5 Grammar reader.</li> 72 * <li>1.3.6 Extra tokens problem.</li> 73 * <li>1.3.7 Synchronization.</li> 74 * <li>1.4.0 Delete property, for tests.</li> 75 * <li>1.4.1 Override some parameters.</li> 76 * </ul> 77 * 78 * @author Andres Gomez Casanova <a 79 * href="mailto:a n g o c a at y a h o o dot c o m">(AngocA)</a> 80 * @version 1.4.1 2010-08-08 81 */ 82 public final class Configurator { 83 84 /** 85 * Property value: Grammar file name. 86 */ 87 static final String GRAMMAR_FILE_DESCRIPTORS_VALUE = "grammar"; //$NON-NLS-1$ 88 /** 89 * Property value: Grammar reader name. 90 */ 91 public static final String GRAMMAR_READER_NAME_VALUE = "name.angoca.zemucan.grammarReader.impl.xml.ImplementationXMLGrammarReader"; //$NON-NLS-1$ 92 /** 93 * Singleton instance. 94 */ 95 private static Configurator instance; 96 /** 97 * Logger. 98 */ 99 private static final Logger LOGGER = LoggerFactory 100 .getLogger(Configurator.class); 101 102 /** 103 * Destroys the sole instance. Useful for testing purposes. 104 */ 105 public static void destroyInstance() { 106 Configurator.LOGGER.debug("Destroying Configurator instance."); //$NON-NLS-1$ 107 108 if (Configurator.instance != null) { 109 Configurator.instance.properties.clear(); 110 Configurator.instance.properties = null; 111 Configurator.instance = null; 112 } 113 assert Configurator.instance == null; 114 } 115 116 /** 117 * This is the singleton implementation. This method returns the sole 118 * instance of this class. This is not thread safe, because this method does 119 * not have a synchronized part. 120 * <p> 121 * This method has a part where it is synchronized, however it is not thread 122 * safe because of the problem with the Single Pattern in Java 123 * (http://www.ibm.com/developerworks/java/library/j-dcl.html) 124 * 125 * @return The sole instance of the Configurator class. 126 */ 127 public static Configurator/* ! */getInstance() { 128 if (Configurator.instance == null) { 129 Configurator.LOGGER.debug("Creating Configurator instance."); //$NON-NLS-1$ 130 synchronized (Configurator.class) { 131 Configurator.instance = new Configurator(); 132 } 133 } 134 135 assert Configurator.instance != null; 136 return Configurator.instance; 137 } 138 139 /** 140 * Set of properties. 141 */ 142 private Properties properties; 143 144 /** 145 * Default constructor. 146 */ 147 private Configurator() { 148 // Loads the XML properties file in a Properties structure. 149 // Tries to retrieve a filename in the system properties. It's for 150 // unit test. 151 final String fileName = System 152 .getProperty(Constants.ZEMUCAN_CONF_XML_PROPERTY); 153 try { 154 if ((fileName == null) || fileName.equals("")) { //$NON-NLS-1$ 155 if (Configurator.LOGGER.isDebugEnabled()) { 156 Configurator.LOGGER.debug("Properties from: " //$NON-NLS-1$ 157 + Constants.ZEMUCAN_CONF_XML_FILENAME); 158 } 159 160 this.loadXMLFile(Constants.ZEMUCAN_CONF_XML_FILENAME); 161 162 } else { 163 if (Configurator.LOGGER.isDebugEnabled()) { 164 Configurator.LOGGER 165 .debug("Properties from file: " + fileName); //$NON-NLS-1$ 166 } 167 this.loadXMLFile(fileName); 168 } 169 } catch (final AbstractConfiguratorException e) { 170 Configurator.LOGGER.warn(Messages.getString("Configurator."//$NON-NLS-1$ 171 + "CONF3-LoadingDefaultProperties"), //$NON-NLS-1$ 172 fileName); 173 Configurator.LOGGER.debug("File's problem.", e); //$NON-NLS-1$ 174 175 this.loadDefaults(); 176 } 177 178 // Override some properties defined in the System 179 this.modifyLoadedProperties(); 180 181 // If Debug level then show the properties. 182 if (Configurator.LOGGER.isDebugEnabled()) { 183 final Enumeration<Object> enumen = this.properties.keys(); 184 while (enumen.hasMoreElements()) { 185 final String prop = (String) enumen.nextElement(); 186 Configurator.LOGGER.debug("{} : {} ", prop.toString(), //$NON-NLS-1$ 187 this.properties.getProperty(prop)); 188 } 189 } 190 } 191 192 /** 193 * Removes a property from the list. 194 * 195 * @param key 196 * Property to delete. 197 */ 198 public void deleteProperty(final String/* ! */key) { 199 assert key != null; 200 201 this.properties.remove(key); 202 } 203 204 /** 205 * Retrieves a property from the load properties. 206 * 207 * @param key 208 * Name of the property to load. A property cannot be empty nor 209 * null. 210 * @return Value of the property. Null if there is no value with that name. 211 */ 212 public String /* ? */getProperty(final String/* ! */key) { 213 assert key != null; 214 assert !key.equals(""); 215 216 Configurator.LOGGER.debug( 217 "Getting: {} - {}", key, this.properties.getProperty(key)); //$NON-NLS-1$ 218 return this.properties.getProperty(key); 219 } 220 221 /** 222 * Defines a set of defaults properties. 223 */ 224 private void loadDefaults() { 225 this.properties = new Properties(); 226 this.properties.setProperty(Constants.GRAMMAR_READER_NAME_PROPERTY, 227 Configurator.GRAMMAR_READER_NAME_VALUE); 228 this.properties.setProperty( 229 Constants.GRAMMAR_FILE_DESCRIPTORS_PROPERTY, 230 Configurator.GRAMMAR_FILE_DESCRIPTORS_VALUE); 231 this.properties.setProperty(Constants.ABOUT_TOKEN_PROPERTY, 232 Constants.ABOUT_TOKEN_VALUE); 233 this.properties.setProperty(Constants.HELP_TOKEN_PROPERTY, 234 Constants.HELP_TOKEN_VALUE); 235 } 236 237 /** 238 * Loads the properties that are in a XML file. 239 * 240 * @param fileName 241 * Name of configuration file. 242 * @throws AbstractReaderException 243 * If there is a problem with the file (when finding or 244 * reading.) 245 */ 246 private void loadXMLFile(final String/* ! */fileName) 247 throws AbstractConfiguratorException { 248 assert fileName != null; 249 250 this.properties = ConfigurationReader.readFile(fileName); 251 } 252 253 /** 254 * Modifies some already loaded values with specific values received from 255 * the System properties. 256 */ 257 private void modifyLoadedProperties() { 258 final String fileDescriptors = System 259 .getProperty(Constants.GRAMMAR_FILE_DESCRIPTORS_PROPERTY); 260 if (fileDescriptors != null) { 261 this.properties.setProperty( 262 Constants.GRAMMAR_FILE_DESCRIPTORS_PROPERTY, 263 fileDescriptors); 264 } 265 266 } 267 268 /** 269 * Set a property after the properties file has been read. This is for 270 * testing purposes, because the configuration is not the same for all 271 * cases. 272 * 273 * @param key 274 * Name of the property. A key cannot be null nor empty. 275 * @param value 276 * Value of the property. A value cannot be null. 277 */ 278 public void setProperty(final String /* ! */key, final String /* ! */value) { 279 assert key != null; 280 assert !key.equals(""); 281 assert value != null; 282 283 this.properties.setProperty(key, value); 284 } 285 }