001: /*
002: * Copyright (c) 2001, Jacob Smullyan.
003: *
004: * This is part of SkunkDAV, a WebDAV client. See http://skunkdav.sourceforge.net/
005: * for the latest version.
006: *
007: * SkunkDAV is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License as published
009: * by the Free Software Foundation; either version 2, or (at your option)
010: * any later version.
011: *
012: * SkunkDAV is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * General Public License for more details.
016: *
017: * You should have received a copy of the GNU General Public License
018: * along with SkunkDAV; see the file COPYING. If not, write to the Free
019: * Software Foundation, 59 Temple Place - Suite 330, Boston, MA
020: * 02111-1307, USA.
021: *
022: * Revision: $Revision: 1.6 $
023: */
024: package org.skunk.config;
025:
026: import java.beans.BeanInfo;
027: import java.beans.IntrospectionException;
028: import java.beans.Introspector;
029: import java.beans.PropertyDescriptor;
030: import java.lang.reflect.InvocationTargetException;
031: import java.lang.reflect.Method;
032: import java.util.HashMap;
033: import java.util.Iterator;
034: import org.skunk.trace.Debug;
035:
036: public class Configurator {
037: private ConfigStore store, defaultStore, reversionStore;
038: private static Configurator configurator = null;
039:
040: public static Configurator getConfigurator() {
041: return configurator;
042: }
043:
044: public static void setConfigurator(Configurator configurator) {
045: Configurator.configurator = configurator;
046: }
047:
048: public Configurator(ConfigStore store) {
049: this .store = store;
050: this .defaultStore = new InMemoryConfigStore();
051: this .reversionStore = new InMemoryConfigStore();
052: }
053:
054: public ConfigStore getStore() {
055: return store;
056: }
057:
058: public ConfigStore getReversionStore() {
059: return reversionStore;
060: }
061:
062: public ConfigStore getDefaultStore() {
063: return defaultStore;
064: }
065:
066: /**
067: * configure the object's properties.
068: * Will take an array, too.
069: *
070: */
071: public void configure(Object configurable) {
072: if (configurable instanceof Class)
073: throw new IllegalArgumentException(
074: "configurable object may not be a Class object");
075: Object[] configurables = (configurable instanceof Object[]) ? (Object[]) configurable
076: : new Object[] { configurable };
077: for (int i = 0; i < configurables.length; i++) {
078: _configure(configurable, store, false);
079: }
080: }
081:
082: /**
083: * starts a try transaction
084: * @param configurable object to be configured -- may not be null
085: */
086: public void tryOn(Object configurable) {
087: if (Debug.DEBUG)
088: Debug.trace(this , Debug.DP4, "object to try on: {0}",
089: configurable);
090: if (configurable instanceof Class)
091: throw new IllegalArgumentException(
092: "configurable object may not be a Class object");
093: Object[] configurables = (configurable instanceof Object[]) ? (Object[]) configurable
094: : new Object[] { configurable };
095: for (int i = 0; i < configurables.length; i++) {
096: //we only want to store the original state of the data, before the
097: //try tranaction started.
098: boolean storeReversionData = !reversionStore
099: .isRegistered(configurable.getClass());
100: _configure(configurable, store, storeReversionData);
101: }
102: }
103:
104: /**
105: * ends a try transaction
106: * @param configurable Object to be configured, or the class of such -- may not be null
107: */
108: public void tryOff(Object configurableOrClass) {
109: if (configurableOrClass instanceof Class) {
110: reversionStore.unregister((Class) configurableOrClass);
111: } else
112: reversionStore.unregister(configurableOrClass.getClass());
113: }
114:
115: public void revert(Object configurable) {
116: if (configurable instanceof Class)
117: throw new IllegalArgumentException(
118: "configurable object may not be a Class object");
119: if (configurable instanceof Object[]) {
120: revertArray((Object[]) configurable);
121: } else {
122: _configure(configurable, reversionStore, false);
123: reversionStore.unregister(configurable.getClass());
124: }
125: }
126:
127: public void revertToDefault(Object configurable) {
128: if (configurable instanceof Class)
129: throw new IllegalArgumentException(
130: "configurable object may not be a Class object");
131: _configure(configurable, defaultStore, false);
132: }
133:
134: private void revertArray(Object[] configurables) {
135: HashMap classSet = new HashMap();
136: //to facilitate use of a HashMap as a set (HashSet simply uses a HashMap instance internally)
137: byte[] nothing = new byte[0];
138: for (int i = 0; i < configurables.length; i++) {
139: Object configurable = configurables[i];
140: if (configurable instanceof Class)
141: throw new IllegalArgumentException(
142: "configurable object may not be a Class object");
143: _configure(configurable, reversionStore, false);
144: classSet.put(configurable.getClass(), nothing);
145: }
146: for (Iterator it = classSet.keySet().iterator(); it.hasNext();)
147: reversionStore.unregister((Class) it.next());
148: }
149:
150: private void _configure(Object configurable,
151: ConfigStore configStore, boolean enableReversion) {
152: Class configClass = configurable.getClass();
153: boolean needDefaultValue = !defaultStore
154: .isRegistered(configClass);
155: try {
156: BeanInfo info = Introspector.getBeanInfo(configClass);
157: PropertyDescriptor[] propDescriptors = info
158: .getPropertyDescriptors();
159: for (int i = 0; i < propDescriptors.length; i++) {
160: PropertyDescriptor pd = propDescriptors[i];
161: String propName = pd.getName();
162: //check store for property
163: Object value = configStore.getConfigValue(configClass,
164: propName);
165: if (value != null) {
166: if (Debug.DEBUG)
167: Debug.trace(this , Debug.DP3,
168: "property found to configure: {0}",
169: propName);
170:
171: //find getter method and store the current values in the reversion store
172: if (enableReversion || needDefaultValue) {
173: Method getter = pd.getReadMethod();
174: if (getter != null) {
175: Object currentValue = getter.invoke(
176: configurable, null);
177: if (Debug.DEBUG)
178: Debug.trace(this , Debug.DP3,
179: "current config value is {0}",
180: currentValue.toString());
181: if (enableReversion) {
182: if (Debug.DEBUG)
183: Debug.trace(this , Debug.DP3,
184: "in reversion mode");
185: reversionStore.setConfigValue(
186: configClass, propName,
187: currentValue);
188: }
189: if (needDefaultValue) {
190: if (Debug.DEBUG)
191: Debug.trace(this , Debug.DP3,
192: "getting default value");
193: defaultStore.setConfigValue(
194: configClass, propName,
195: currentValue);
196: }
197: }
198: }
199: if (Debug.DEBUG)
200: Debug
201: .trace(
202: this ,
203: Debug.DP3,
204: "getting write method: will invoke with argument {0}",
205: new Object[] { value });
206: Method setter = pd.getWriteMethod();
207: if (setter != null)
208: setter.invoke(configurable,
209: new Object[] { value });
210: }
211: }
212: } catch (IntrospectionException intro) {
213: if (Debug.DEBUG)
214: Debug.trace(this , Debug.DP2, intro);
215: } catch (IllegalAccessException illAcc) {
216: if (Debug.DEBUG)
217: Debug.trace(this , Debug.DP2, illAcc);
218: } catch (IllegalArgumentException illArg) {
219: if (Debug.DEBUG)
220: Debug.trace(this , Debug.DP2, illArg);
221: } catch (InvocationTargetException invoTarg) {
222: if (Debug.DEBUG)
223: Debug.trace(this , Debug.DP2, invoTarg);
224: }
225: }
226: }
227:
228: /*
229: $Log: Configurator.java,v $
230: Revision 1.6 2001/02/16 18:15:10 smulloni
231: many fixes to TextEditorCustomizer. FileMode and SyntaxStyle now have a
232: configData property (they will probably be made into sibling classes).
233:
234: Revision 1.5 2001/02/06 00:11:18 smulloni
235: struggle, perhaps futile, with the TextEditorCustomizer and other implicated
236: classes
237:
238: Revision 1.4 2000/11/06 23:35:39 smullyan
239: numerous changes to the configuration system, which is veering dangerously
240: towards correct function. LockRenderer is a table cell renderer that displays
241: a lock icon.
242:
243: Revision 1.3 2000/11/03 22:51:52 smullyan
244: various changes to makefile to get it to work properly -- had to eliminate
245: wildcard imports to get jikes to behave. Continued hacking at configuration
246: system, which now stores default settings. TableViewCustomizer currently
247: quite broken as I integrate into it my new DualListPanel component.
248:
249: Revision 1.2 2000/11/03 00:16:33 smullyan
250: massive work on the configuration system -- still buggy and rough. One
251: customizer sketched (inadequately, but for proof of concept):
252: TableViewCustomizer.
253:
254: Revision 1.1 2000/11/01 15:30:14 smullyan
255: adding config classes (moved from package org.skunk.dav.client.gui.config)
256:
257: Revision 1.2 2000/11/01 04:18:40 smullyan
258: changes to configuration system: support of reversible configuration (in
259: preparation for Preferences)
260:
261: */
|