View Javadoc

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 }