001: /*
002: * WbProperties.java
003: *
004: * This file is part of SQL Workbench/J, http://www.sql-workbench.net
005: *
006: * Copyright 2002-2008, Thomas Kellerer
007: * No part of this code maybe reused without the permission of the author
008: *
009: * To contact the author please send an email to: support@sql-workbench.net
010: *
011: */
012: package workbench.util;
013:
014: import java.beans.PropertyChangeEvent;
015: import java.beans.PropertyChangeListener;
016: import java.io.BufferedReader;
017: import java.io.BufferedWriter;
018: import java.io.File;
019: import java.io.FileOutputStream;
020: import java.io.IOException;
021: import java.io.OutputStream;
022: import java.io.OutputStreamWriter;
023: import java.util.ArrayList;
024: import java.util.Arrays;
025: import java.util.HashMap;
026: import java.util.List;
027: import java.util.Map;
028: import java.util.Properties;
029: import workbench.interfaces.PropertyStorage;
030:
031: /**
032: * An enhanced Properties class
033: *
034: * @author support@sql-workbench.net
035: */
036: public class WbProperties extends Properties implements PropertyStorage {
037: private int distinctSections;
038:
039: private Map<String, List<PropertyChangeListener>> changeListeners = new HashMap<String, List<PropertyChangeListener>>();
040: private Object changeNotificationSource = null;
041:
042: protected WbProperties() {
043: this (null, 2);
044: }
045:
046: public WbProperties(Object notificationSource) {
047: this (notificationSource, 2);
048: }
049:
050: public WbProperties(Object notificationSource, int num) {
051: this .changeNotificationSource = (notificationSource == null ? this
052: : notificationSource);
053: this .distinctSections = num;
054: }
055:
056: public synchronized void saveToFile(File filename)
057: throws IOException {
058: FileOutputStream out = null;
059: try {
060: out = new FileOutputStream(filename);
061: this .save(out);
062: } finally {
063: out.close();
064: }
065: }
066:
067: public synchronized void save(OutputStream out) throws IOException {
068: Object[] keys = this .keySet().toArray();
069: Arrays.sort(keys);
070: BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
071: out));
072: String value = null;
073: String lastKey = null;
074: String key = null;
075: for (int i = 0; i < keys.length; i++) {
076: key = (String) keys[i];
077:
078: if (lastKey != null) {
079: String k1 = null;
080: String k2 = null;
081: k1 = getSections(lastKey, this .distinctSections);
082: k2 = getSections(key, this .distinctSections);
083: if (!k1.equals(k2)) {
084: bw.newLine();
085: }
086: }
087:
088: Object v = this .get(key);
089: if (v != null) {
090: value = v.toString();
091: value = StringUtil.escapeUnicode(value,
092: CharacterRange.RANGE_7BIT);
093: if (value.length() > 0) {
094: bw.write(key + "=" + value);
095: bw.newLine();
096: } else {
097: bw.write(key + "=");
098: bw.newLine();
099: }
100: } else {
101: bw.write(key + "=");
102: bw.newLine();
103: }
104: lastKey = key;
105: }
106: bw.flush();
107: }
108:
109: public int getIntProperty(String property, int defaultValue) {
110: String value = this .getProperty(property, null);
111: if (value == null)
112: return defaultValue;
113: return StringUtil.getIntValue(value, defaultValue);
114: }
115:
116: public boolean getBoolProperty(String property, boolean defaultValue) {
117: String value = this .getProperty(property, null);
118: if (value == null)
119: return defaultValue;
120: return StringUtil.stringToBool(value);
121: }
122:
123: public void setProperty(String property, int value) {
124: this .setProperty(property, Integer.toString(value));
125: }
126:
127: public void setProperty(String property, boolean value) {
128: this .setProperty(property, Boolean.toString(value));
129: }
130:
131: private String getSections(String aString, int aNum) {
132: int pos = aString.indexOf(".");
133: String result = null;
134: for (int i = 1; i < aNum; i++) {
135: int pos2 = aString.indexOf('.', pos + 1);
136: if (pos2 > -1) {
137: pos = pos2;
138: } else {
139: if (i == (aNum - 1)) {
140: pos = aString.length();
141: }
142: }
143: }
144: result = aString.substring(0, pos);
145: return result;
146: }
147:
148: public void addPropertyChangeListener(
149: PropertyChangeListener aListener, String... properties) {
150: synchronized (this .changeListeners) {
151: for (String prop : properties) {
152: List<PropertyChangeListener> listeners = this .changeListeners
153: .get(prop);
154: if (listeners == null) {
155: listeners = new ArrayList<PropertyChangeListener>();
156: this .changeListeners.put(prop, listeners);
157: }
158: listeners.add(aListener);
159: }
160: }
161: }
162:
163: public void removePropertyChangeListener(
164: PropertyChangeListener aListener) {
165: synchronized (this .changeListeners) {
166: for (List<PropertyChangeListener> listeners : changeListeners
167: .values()) {
168: if (listeners != null) {
169: listeners.remove(aListener);
170: }
171: }
172: }
173: }
174:
175: private void firePropertyChanged(String name, String oldValue,
176: String newValue) {
177: List<PropertyChangeListener> listeners = this .changeListeners
178: .get(name);
179: if (listeners == null || listeners.size() == 0)
180: return;
181:
182: // Making a shallow copy of the list prevents a ConcurrentModificationException
183: List<PropertyChangeListener> l2 = new ArrayList<PropertyChangeListener>(
184: listeners);
185: PropertyChangeEvent evt = new PropertyChangeEvent(this , name,
186: oldValue, newValue);
187:
188: for (PropertyChangeListener l : l2) {
189: if (l != null) {
190: l.propertyChange(evt);
191: }
192: }
193: }
194:
195: public Object setProperty(String name, String value) {
196: return setProperty(name, value, true);
197: }
198:
199: public Object setProperty(String name, String value,
200: boolean firePropChange) {
201: if (name == null)
202: return null;
203:
204: String oldValue = null;
205:
206: synchronized (this ) {
207: if (value == null) {
208: super .remove(name);
209: return null;
210: }
211: oldValue = (String) super .setProperty(name, value);
212: }
213:
214: if (firePropChange && !StringUtil.equalString(oldValue, value)) {
215: this .firePropertyChanged(name, oldValue, value);
216: }
217: return oldValue;
218: }
219:
220: /**
221: * Adds a property definition in the form key=value
222: * Lines starting with # are ignored
223: * Lines that do not contain a = character are ignored
224: * Any text after a # sign in the value is ignored
225: */
226: public void addPropertyDefinition(String line) {
227: if (line == null)
228: return;
229: if (line.trim().length() == 0)
230: return;
231: if (line.startsWith("#"))
232: return;
233: int pos = line.indexOf("=");
234: if (pos == -1)
235: return;
236: String key = line.substring(0, pos);
237: String value = line.substring(pos + 1);
238: pos = value.indexOf('#');
239: if (pos > -1) {
240: value = value.substring(0, pos);
241: }
242: this .setProperty(key, value.trim());
243: }
244:
245: public void loadTextFile(String filename) throws IOException {
246: loadTextFile(filename, null);
247: }
248:
249: /**
250: * Read the content of the file into this properties object.
251: * This method does not support line continuation, but supports
252: * an encoding (as opposed to the original properties class)
253: *
254: */
255: public void loadTextFile(String filename, String encoding)
256: throws IOException {
257: BufferedReader in = null;
258: File f = new File(filename);
259: if (encoding == null) {
260: encoding = EncodingUtil.getDefaultEncoding();
261: }
262: try {
263: in = EncodingUtil.createBufferedReader(f, encoding);
264: String line = in.readLine();
265: while (line != null) {
266: this .addPropertyDefinition(StringUtil
267: .decodeUnicode(line));
268: line = in.readLine();
269: }
270: } finally {
271: try {
272: in.close();
273: } catch (Throwable th) {
274: }
275: }
276: }
277:
278: }
|