Source code: org/argouml/configuration/ConfigurationHandler.java
1 // Copyright (c) 1996-2001 The Regents of the University of California. All
2 // Rights Reserved. Permission to use, copy, modify, and distribute this
3 // software and its documentation without fee, and without a written
4 // agreement is hereby granted, provided that the above copyright notice
5 // and this paragraph appear in all copies. This software program and
6 // documentation are copyrighted by The Regents of the University of
7 // California. The software program and documentation are supplied "AS
8 // IS", without any accompanying services from The Regents. The Regents
9 // does not warrant that the operation of the program will be
10 // uninterrupted or error-free. The end-user understands that the program
11 // was developed for research purposes and is advised not to rely
12 // exclusively on the program for any reason. IN NO EVENT SHALL THE
13 // UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
14 // SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
15 // ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
16 // THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
17 // SUCH DAMAGE. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY
18 // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
20 // PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
21 // CALIFORNIA HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT,
22 // UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
23
24 //
25 // This code is originally from the open source UML editor argouml.
26 // Information on argouml can be found at: http://argouml.tigris.org/
27 //
28 // The original author is Thierry Lach
29 //
30 // Adopted by Matthieu Cormier on Fri June 27 2003.
31
32 package org.argouml.configuration;
33
34 import java.beans.*;
35 import java.io.*;
36 import java.util.*;
37 import java.net.*;
38
39 import simple.logging.*;
40
41 /**
42 * This class provides a user configuration based upon properties.
43 * This provides an implementation-free interface to a configuration
44 * repository. Any classes which need to implement a configuration
45 * datastore must extend this class.
46 *
47 * All of the required behavioral logic for the configuration is
48 * contained within this class, as public final methods. Any
49 * storage-related logic must be handled by the extending class.
50 * These methods are abstract.
51 *
52 * This class is intimately related to
53 * {@link org.argouml.configuration.Configuration}.
54 *
55 */
56 public abstract class ConfigurationHandler {
57
58 /** Internal storage for the <code>File</code> the configuration was
59 * loaded from, otherwise null.
60 */
61 private File _loadedFromFile = null;
62
63 /** Internal storage for the <code>URL</code> the configuration was
64 * loaded from, otherwise null.
65 */
66 private URL _loadedFromURL = null;
67
68 /** Internal flag indicating whether the configuration can be updated.
69 */
70 private boolean _changeable = false;
71
72 /** Internal flag indicating whether the configuration has been loaded.
73 * Configuration rules allow a single load, whether manual or automatic.
74 */
75 private boolean _loaded = false;
76
77 /** Internal flag indicating whether the configuration has been modified
78 * after it was loaded.
79 */
80 private boolean _changed = false;
81
82 /** Internal worker for property change.
83 */
84 private static PropertyChangeSupport _pcl = null;
85
86 /** Anonymous constructor allows configuration changes.
87 */
88 public ConfigurationHandler() {
89 this(true);
90 }
91
92 /** Constructor which optionally allows configuration changes.
93 */
94 public ConfigurationHandler(boolean changeable) {
95 super();
96 _changeable = changeable;
97 }
98
99 /** Returns a default configuration path. This could be a filename
100 * or a URL. It is not guaranteed to be usable across different
101 * implementations of ConfigurationHandler.
102 *
103 * @return the default configuration path or url.
104 */
105 public abstract String getDefaultPath();
106
107 /** Internal worker which is called prior to any getValue
108 * or setValue to ensure that the default load is done if it was not
109 * loaded previously.
110 */
111 private void loadIfNecessary() {
112 if (!_loaded) loadDefault();
113 }
114
115 /** Load the configuration from the default location.
116 *
117 * @return true if this call loaded the configuration,
118 * otherwise false, not distinguishing between a load
119 * error or a previously loaded configuration.
120 *
121 * @see #isLoaded
122 */
123 public final boolean loadDefault()
124 {
125 // Only allow one load
126 if (_loaded) return false;
127
128 Log.out("Loading " + getDefaultPath() );
129
130 boolean status = load(new File(getDefaultPath()));
131 if (!status) status = loadUnspecified();
132 _loaded = true;
133 return status;
134 }
135
136 /** Save the configuration to the location it was loaded from.
137 * Do not force it if the configuration was not loaded already.
138 *
139 * @return true if the save was successful, false if it was not
140 * attempted or encountered an error.
141 */
142 public final boolean saveDefault() {
143 return saveDefault(false);
144 }
145
146 /** Save the configuration to the location it was loaded from.
147 *
148 * @return true if the save was successful, false if it was not
149 * attempted or encountered an error.
150 */
151 public final boolean saveDefault(boolean force) {
152 if (force) {
153 File toFile = new File(getDefaultPath());
154 boolean saved = saveFile(toFile);
155 if (saved) {
156 _loadedFromFile = toFile;
157 }
158 return saved;
159 }
160 if (! _loaded) return false;
161
162 if (_loadedFromFile != null) {
163 return saveFile(_loadedFromFile);
164 }
165 if (_loadedFromURL != null) {
166 return saveURL(_loadedFromURL);
167 }
168 return false;
169 }
170
171 /** Indicates whether the configuration can be saved.
172 *
173 * @return true if the configuration can be saved.
174 */
175 public final boolean isChangeable() { return _changeable; }
176
177 /** Indicates whether the configuration can be saved.
178 *
179 * @return true if the configuration has been changed after load.
180 */
181 public final boolean isChanged() { return _changed; }
182
183 /** Indicates whether the configuration has been loaded.
184 *
185 * @return true if the configuration has been loaded.
186 */
187 public final boolean isLoaded() { return _loaded; }
188
189 /** Load the configuration from a <code>File</code>.
190 *
191 * @return true if this call loaded the configuration,
192 * otherwise false, not distinguishing between a load
193 * error or a previously loaded configuration.
194 */
195
196 public final boolean load(File file) {
197 boolean status = loadFile(file);
198 if (status) {
199 if (_pcl != null) {
200 _pcl.firePropertyChange(Configuration.FILE_LOADED, null, file);
201 }
202 _loadedFromFile = file;
203 }
204 return status;
205 }
206
207 /** Load the configuration from a <code>URL</code>.
208 *
209 * @return true if this call loaded the configuration,
210 * otherwise false, not distinguishing between a load
211 * error or a previously loaded configuration.
212 */
213 public final boolean load(URL url) {
214 boolean status = loadURL(url);
215 if (status) {
216 if (_pcl != null) {
217 _pcl.firePropertyChange(Configuration.URL_LOADED, null, url);
218 }
219 _loadedFromURL = url;
220 }
221 return status;
222 }
223
224 /** Save the configuration to a <code>File</code>.
225 *
226 * @return true if this call saved the configuration,
227 * otherwise false.
228 */
229 public final boolean save(File file) {
230 if (! _loaded) {
231 return false;
232 }
233 boolean status = saveFile(file);
234 if (status) {
235 if (_pcl != null) {
236 _pcl.firePropertyChange(Configuration.FILE_SAVED, null, file);
237 }
238 }
239 return status;
240 }
241
242 /** Save the configuration to a <code>URL</code>.
243 *
244 * @return true if this call saved the configuration,
245 * otherwise false.
246 */
247 public final boolean save(URL url) {
248 if (! _loaded) {
249 return false;
250 }
251 boolean status = saveURL(url);
252 if (status) {
253 if (_pcl != null) {
254 _pcl.firePropertyChange(Configuration.URL_SAVED, null, url);
255 }
256 }
257 return status;
258 }
259
260 /** Returns the string value of a configuration property.
261 *
262 * @param key the configuration key to return.
263 * @param defaultValue the default value key to return
264 * if the key is not found.
265 *
266 * @return the value of the key or the default value
267 * if the key does not exist.
268 */
269 public final String getString(ConfigurationKey key, String defaultValue) {
270 loadIfNecessary();
271 return getValue(key.getKey(), defaultValue);
272 }
273
274 /** Returns the numeric value of a configuration property.
275 *
276 * @param key the configuration key to return.
277 * @param defaultValue the default value key to return
278 * if the key is not found.
279 *
280 * @return the value of the key or the default value
281 * if the key does not exist.
282 */
283 public final int getInteger(ConfigurationKey key, int defaultValue) {
284 loadIfNecessary();
285 try {
286 String s = getValue(key.getKey(), Integer.toString(defaultValue));
287 return Integer.parseInt(s);
288 }
289 catch (NumberFormatException nfe) {
290 return defaultValue;
291 }
292 }
293
294 /** Returns the numeric value of a configuration property.
295 *
296 * @param key the configuration key to return.
297 * @param defaultValue the default value key to return
298 * if the key is not found.
299 *
300 * @return the value of the key or the default value
301 * if the key does not exist.
302 */
303 public final double getDouble(ConfigurationKey key, double defaultValue) {
304 loadIfNecessary();
305 try {
306 String s = getValue(key.getKey(), Double.toString(defaultValue));
307 return Double.parseDouble(s);
308 }
309 catch (NumberFormatException nfe) {
310 return defaultValue;
311 }
312 }
313
314 /** Returns the boolean value of a configuration property.
315 *
316 * @param key the configuration key to return.
317 * @param defaultValue the default value key to return
318 * if the key is not found.
319 *
320 * @return the value of the key or the default value
321 * if the key does not exist.
322 */
323 public final boolean getBoolean(ConfigurationKey key, boolean defaultValue) {
324 loadIfNecessary();
325 Boolean dflt = new Boolean(defaultValue);
326 Boolean b = new Boolean(getValue(key.getKey(), dflt.toString()));
327 return b.booleanValue();
328 }
329
330 /** Internal routine which calls the abstract setValue and handles
331 * all necessary functionality including firing property change
332 * notifications and tracing.
333 *
334 * @param key the configuration key to modify.
335 * @param newValue the new value of the key.
336 */
337 private synchronized final void workerSetValue(ConfigurationKey key, String newValue) {
338 loadIfNecessary();
339
340 String oldValue = getValue(key.getKey(), "");
341 setValue(key.getKey(), newValue);
342 if (_pcl != null) {
343 _pcl.firePropertyChange(key.getKey(), oldValue, newValue);
344 }
345 }
346
347 /** Sets the string value of a configuration property.
348 *
349 * @param key the configuration key to modify.
350 * @param newValue the value to set the key to.
351 */
352 public final void setString(ConfigurationKey key, String newValue) {
353 workerSetValue(key, newValue);
354 }
355
356 /** Sets the numeric value of a configuration property.
357 *
358 * @param key the configuration key to modify.
359 * @param value the value to set the key to.
360 */
361 public final void setInteger(ConfigurationKey key, int value) {
362 workerSetValue(key, Integer.toString(value));
363 }
364
365 /** Sets the numeric value of a configuration property.
366 *
367 * @param key the configuration key to modify.
368 * @param value the value to set the key to.
369 */
370 public final void setDouble(ConfigurationKey key, double value) {
371 workerSetValue(key, Double.toString(value));
372 }
373
374 /** Sets the boolean value of a configuration property.
375 *
376 * @param key the configuration key to modify.
377 * @param value the value to set the key to.
378 */
379 public final void setBoolean(ConfigurationKey key, boolean value) {
380 Boolean bool = new Boolean(value);
381 workerSetValue(key, bool.toString());
382 }
383
384 /** Adds a property change listener.
385 *
386 * @param pcl The class which will listen for property changes.
387 */
388 public final void addListener(PropertyChangeListener pcl) {
389 if (_pcl == null) {
390 _pcl = new PropertyChangeSupport(this);
391 }
392
393 _pcl.addPropertyChangeListener(pcl);
394 }
395
396 /** Removes a property change listener.
397 *
398 * @param pcl The class to remove as a property change listener.
399 */
400 public final void removeListener(PropertyChangeListener pcl) {
401 if (_pcl != null) {
402
403 _pcl.removePropertyChangeListener(pcl);
404 }
405 }
406
407 /** Adds a property change listener.Static for simplicity of use.
408 *
409 * @param key The specific key to listen for.
410 * @param pcl The class which will listen for property changes.
411 */
412 public final void addListener(ConfigurationKey key, PropertyChangeListener pcl) {
413 if (_pcl == null) {
414 _pcl = new PropertyChangeSupport(this);
415 }
416
417 _pcl.addPropertyChangeListener(key.getKey(), pcl);
418 }
419
420 /** Removes a property change listener.
421 *
422 * @param key The specific key being listened for.
423 * @param pcl The class to remove as a property change listener.
424 */
425 public final void removeListener(ConfigurationKey key, PropertyChangeListener pcl) {
426 if (_pcl != null) {
427
428 _pcl.removePropertyChangeListener(key.getKey(), pcl);
429 }
430 }
431
432 /** Internal processing to load from an unspecified source.
433 *
434 * @return true if the load was successful, otherwise false.
435 */
436 boolean loadUnspecified() {
437 return false;
438 }
439
440 /** Internal processing to save to an unspecified source.
441 *
442 * @return true if the save was successful, otherwise false.
443 */
444 boolean saveUnspecified() {
445 return false;
446 }
447
448 /** Internal processing to load a <code>File</code>.
449 *
450 * @param file the file to load.
451 *
452 * @return true if the load was successful, otherwise false.
453 */
454 abstract boolean loadFile(File file);
455
456 /** Internal processing to load a <code>URL</code>.
457 *
458 * @param url the url to load.
459 *
460 * @return true if the load was successful, otherwise false.
461 */
462 abstract boolean loadURL(URL url);
463
464 /** Internal processing to save a <code>File</code>.
465 *
466 * @param file the file to save.
467 *
468 * @return true if the save was successful, otherwise false.
469 */
470 abstract boolean saveFile(File file);
471
472 /** Internal processing to save a <code>URL</code>.
473 *
474 * @param url the url to save.
475 *
476 * @return true if the save was successful, otherwise false.
477 */
478 abstract boolean saveURL(URL url);
479
480 /** Allows query for the existence of a configuration property.
481 * This may be overridden if the implementation has a
482 * more efficient method.
483 *
484 * @param key the property being checked.
485 *
486 * @return true if the key exists, otherwise false.
487 */
488 public boolean hasKey(ConfigurationKey key) {
489 return getValue(key.getKey(), "true").equals(getValue(key.getKey(), "false"));
490 }
491
492 /** Returns the string value of a configuration property.
493 *
494 * @param key the configuration key to return.
495 * @param defaultValue the configuration key to return.
496 *
497 * @return the value of the key or the default value
498 * if the key does not exist.
499 */
500 public abstract String getValue(String key, String defaultValue);
501
502 /** Sets the string value of a configuration property.
503 *
504 * @param key the configuration key to modify.
505 * @param value the value to set the key to.
506 */
507 public abstract void setValue(String key, String value);
508 }
509
510