KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > openide > options > SystemOption


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19 package org.openide.options;
20
21 import org.openide.util.HelpCtx;
22 import org.openide.util.NbBundle;
23 import org.openide.util.SharedClassObject;
24
25 import java.beans.BeanInfo JavaDoc;
26 import java.beans.IntrospectionException JavaDoc;
27 import java.beans.PropertyDescriptor JavaDoc;
28
29 import java.io.IOException JavaDoc;
30 import java.io.ObjectInput JavaDoc;
31 import java.io.ObjectOutput JavaDoc;
32
33 import java.lang.reflect.InvocationTargetException JavaDoc;
34 import java.lang.reflect.Method JavaDoc;
35
36 import java.util.HashMap JavaDoc;
37 import java.util.Map JavaDoc;
38 import java.util.logging.Level JavaDoc;
39 import java.util.logging.Logger JavaDoc;
40 import org.openide.util.Exceptions;
41
42
43 /**
44 * Base class for all system options.
45 * Provides methods for adding
46 * and working with property change and guarantees
47 * that all instances of the same class will share these listeners.
48 * <P>
49 * When a new option is created, it should subclass
50 * <CODE>SystemOption</CODE>, add <em>static</em> variables to it that will hold
51 * the values of properties, and write non-static setters/getters that will
52 * notify all listeners about property changes via
53 * {@link #firePropertyChange}.
54 * <p>JavaBeans introspection is used to find the properties,
55 * so it is possible to use {@link BeanInfo}.
56 *
57 * @author Jaroslav Tulach
58  * @deprecated Use {@link org.openide.util.NbPreferences} instead.
59 */

60 public abstract class SystemOption extends SharedClassObject implements HelpCtx.Provider {
61     /** generated Serialized Version UID */
62     static final long serialVersionUID = 558589201969066966L;
63
64     /** property to indicate that the option is currently loading its data */
65     private static final Object JavaDoc PROP_LOADING = new Object JavaDoc();
66
67     /** property to indicate that the option is currently loading its data */
68     private static final Object JavaDoc PROP_STORING = new Object JavaDoc();
69
70     /** property that holds a Map<String,Object> that stores old values */
71     private static final Object JavaDoc PROP_ORIGINAL_VALUES = new Object JavaDoc();
72
73     /** this represent null in the map in PROP_ORIGINAL_VALUES */
74     private static final Object JavaDoc NULL = new Object JavaDoc();
75
76     /** Default constructor. */
77     public SystemOption() {
78     }
79
80     /** Fire a property change event to all listeners. Delays
81     * this loading when readExternal is active till it finishes.
82     *
83     * @param name the name of the property
84     * @param oldValue the old value
85     * @param newValue the new value
86     */

87     protected void firePropertyChange(String JavaDoc name, Object JavaDoc oldValue, Object JavaDoc newValue) {
88         if ((name != null) && (getProperty("org.openide.util.SharedClassObject.initialize") == null)) { // NOI18N
89

90             Map JavaDoc originalValues = (Map JavaDoc) getProperty(PROP_ORIGINAL_VALUES);
91
92             if (originalValues == null) {
93                 originalValues = new HashMap JavaDoc();
94                 putProperty(PROP_ORIGINAL_VALUES, originalValues);
95             }
96
97             if (originalValues.get(name) == null) {
98                 if (getProperty(name) == null) {
99                     // this is supposed to be setter
100
originalValues.put(name, new Box(oldValue));
101                 } else {
102                     // regular usage of putProperty (....);
103
originalValues.put(name, (oldValue == null) ? NULL : oldValue);
104                 }
105             }
106         }
107
108         if (getProperty(PROP_LOADING) != null) {
109             // somebody is loading, assign any object different than
110
// this to indicate that firing should occure
111
putProperty(PROP_LOADING, PROP_LOADING);
112
113             // but do not fire the change now
114
return;
115         }
116
117         super.firePropertyChange(name, oldValue, newValue);
118     }
119
120     /** Implements the reset by setting back all properties that were
121      * modified. A <em>modified property</em> has fired a
122      * <code>PropertyChangeEvent</code> with
123      * non-null name and non-null old value. The name and value are
124      * remembered and this method sets them back to original value.
125      * <p>
126      * Subclasses are free to override this method and reimplement the
127      * reset by themselves.
128      *
129      * @since 4.46
130      */

131     protected void reset() {
132         synchronized (getLock()) {
133             Map JavaDoc m = (Map JavaDoc) getProperty(PROP_ORIGINAL_VALUES);
134
135             if ((m == null) || m.isEmpty()) {
136                 return;
137             }
138
139             java.util.Iterator JavaDoc it = m.entrySet().iterator();
140 WHILE:
141             while (it.hasNext()) {
142                 Map.Entry JavaDoc e = (Map.Entry JavaDoc) it.next();
143
144                 if (e.getValue() instanceof Box) {
145                     Object JavaDoc value = ((Box) e.getValue()).value;
146
147                     try {
148                         // gets info about all properties that were added by subclass
149
BeanInfo JavaDoc info = org.openide.util.Utilities.getBeanInfo(getClass(), SystemOption.class);
150                         PropertyDescriptor JavaDoc[] desc = info.getPropertyDescriptors();
151
152                         for (int i = 0; i < desc.length; i++) {
153                             if (e.getKey().equals(desc[i].getName())) {
154                                 // our property
155
Method JavaDoc write = desc[i].getWriteMethod();
156
157                                 if (write != null) {
158                                     write.invoke(this, new Object JavaDoc[] { value });
159                                 }
160
161                                 continue WHILE;
162                             }
163                         }
164                     } catch (InvocationTargetException JavaDoc ex) {
165                         // exception thrown
166
Logger.getLogger(SystemOption.class.getName()).log(Level.WARNING, null, ex);
167                     } catch (IllegalAccessException JavaDoc ex) {
168                         Logger.getLogger(SystemOption.class.getName()).log(Level.WARNING, null, ex);
169                     } catch (IntrospectionException JavaDoc ex) {
170                         Logger.getLogger(SystemOption.class.getName()).log(Level.WARNING, null, ex);
171                     }
172                 } else {
173                     putProperty(e.getKey(), (e.getValue() == NULL) ? null : e.getValue());
174                 }
175             }
176
177             // reset all remembered values
178
putProperty(PROP_ORIGINAL_VALUES, null);
179         }
180
181         super.firePropertyChange(null, null, null);
182     }
183
184     /** Write all properties of this object (or subclasses) to an object output.
185     * @param out the output stream
186     * @exception IOException on error
187     */

188     public void writeExternal(ObjectOutput JavaDoc out) throws IOException JavaDoc {
189         try {
190             // gets info about all properties that were added by subclass
191
BeanInfo JavaDoc info = org.openide.util.Utilities.getBeanInfo(getClass(), SystemOption.class);
192             PropertyDescriptor JavaDoc[] desc = info.getPropertyDescriptors();
193
194             putProperty(PROP_STORING, this);
195
196             Object JavaDoc[] param = new Object JavaDoc[0];
197
198             synchronized (getLock()) {
199                 // write all properties that have getter to stream
200
for (int i = 0; i < desc.length; i++) {
201                     // skip readonly Properties
202
if (desc[i].getWriteMethod() == null) {
203                         continue;
204                     }
205                     String JavaDoc propName = desc[i].getName();
206                     Object JavaDoc value = getProperty(propName);
207                     boolean fromRead;
208                     // JST: this code handles the case when somebody needs to store
209
// different value then is the value of get/set method.
210
// in such case value (from getProperty) is not of the type
211
// of the getter/setter and is used instead of the value from getXXXX
212
Method JavaDoc read = desc[i].getReadMethod();
213
214                     if (read == null) {
215                         continue;
216                     }
217                     if ((value == null) || isInstance(desc[i].getPropertyType(),
218                                                       value)) {
219                         fromRead = true;
220                         try {
221                             value = read.invoke(this, param);
222                         }
223                         catch (InvocationTargetException JavaDoc ex) {
224                             throw (IOException JavaDoc) new IOException JavaDoc(NbBundle.getMessage(SystemOption.class,
225                                                                                     "EXC_InGetter",
226                                                                                     getClass(),
227                                                                                     desc[i].getName())).initCause(ex);
228                         }
229                         catch (IllegalAccessException JavaDoc ex) {
230                             throw (IOException JavaDoc) new IOException JavaDoc(NbBundle.getMessage(SystemOption.class,
231                                                                                     "EXC_InGetter",
232                                                                                     getClass(),
233                                                                                     desc[i].getName())).initCause(ex);
234                         }
235                     } else {
236                         fromRead = false;
237                     }
238                     // writes name of the property
239
out.writeObject(propName);
240                     // writes its value
241
out.writeObject(value);
242                     // from getter or stored prop?
243
out.writeObject(fromRead ? Boolean.TRUE
244                                              : Boolean.FALSE);
245                 }
246             }
247         } catch (IntrospectionException JavaDoc ex) {
248             // if we cannot found any info about properties
249
} finally {
250             putProperty(PROP_STORING, null);
251         }
252
253         // write null to signal end of properties
254
out.writeObject(null);
255     }
256
257     /** Returns true if the object is assignable to the class.
258      * Also if the class is primitive and the object is of the matching wrapper type.
259      */

260     private static boolean isInstance(Class JavaDoc c, Object JavaDoc o) {
261         return c.isInstance(o) || ((c == Byte.TYPE) && (o instanceof Byte JavaDoc)) ||
262         ((c == Short.TYPE) && (o instanceof Short JavaDoc)) || ((c == Integer.TYPE) && (o instanceof Integer JavaDoc)) ||
263         ((c == Long.TYPE) && (o instanceof Long JavaDoc)) || ((c == Float.TYPE) && (o instanceof Float JavaDoc)) ||
264         ((c == Double.TYPE) && (o instanceof Double JavaDoc)) || ((c == Boolean.TYPE) && (o instanceof Boolean JavaDoc)) ||
265         ((c == Character.TYPE) && (o instanceof Character JavaDoc));
266     }
267
268     /** Read all properties of this object (or subclasses) from an object input.
269     * If there is a problem setting the value of any property, that property will be ignored;
270     * other properties should still be set.
271     * @param in the input stream
272     * @exception IOException on error
273     * @exception ClassNotFound if a class used to restore the system option is not found
274     */

275     public void readExternal(ObjectInput JavaDoc in) throws IOException JavaDoc, ClassNotFoundException JavaDoc {
276         // hashtable that maps names of properties to setter methods
277
HashMap JavaDoc map = new HashMap JavaDoc();
278
279         try {
280             synchronized (getLock()) {
281                 // indicate that we are loading files
282
putProperty(PROP_LOADING, this);
283
284                 try {
285                     // gets info about all properties that were added by subclass
286
BeanInfo JavaDoc info = org.openide.util.Utilities.getBeanInfo(getClass(), SystemOption.class);
287                     PropertyDescriptor JavaDoc[] desc = info.getPropertyDescriptors();
288
289                     // write all properties that have getter to stream
290
for (int i = 0; i < desc.length; i++) {
291                         Method JavaDoc m = desc[i].getWriteMethod();
292
293                         /*if (m == null) {
294                           System.out.println ("HOW HOW HOW HOWHOWHOWHOWHWO: " + desc[i].getName() + " XXX " + getClass());
295                           throw new IOException (new MessageFormat (NbBundle.getBundle (SystemOption.class).getString ("EXC_InSetter")).
296                             format (new Object[] {getClass (), desc[i].getName ()})
297                                                 );
298                         } */

299                         map.put(desc[i].getName(), m);
300                     }
301                 } catch (IntrospectionException JavaDoc ex) {
302                     // if we cannot found any info about properties
303
// leave the hashtable empty and only read stream till null is found
304
Logger.getLogger(SystemOption.class.getName()).log(Level.WARNING, null, ex);
305                 }
306
307                 String JavaDoc preread = null;
308
309                 do {
310                     // read the name of property
311
String JavaDoc name;
312
313                     if (preread != null) {
314                         name = preread;
315                         preread = null;
316                     } else {
317                         name = (String JavaDoc) in.readObject();
318                     }
319
320                     // break if the end of property stream is found
321
if (name == null) {
322                         break;
323                     }
324
325                     // read the value of property
326
Object JavaDoc value = in.readObject();
327
328                     // read flag - use the setter method or store as property?
329
Object JavaDoc useMethodObject = in.readObject();
330                     boolean useMethod;
331                     boolean nullRead = false; // this should be last processed property?
332

333                     if (useMethodObject == null) {
334                         useMethod = true;
335                         nullRead = true;
336                     } else if (useMethodObject instanceof String JavaDoc) {
337                         useMethod = true;
338                         preread = (String JavaDoc) useMethodObject;
339                     } else {
340                         useMethod = ((Boolean JavaDoc) useMethodObject).booleanValue();
341                     }
342
343                     if (useMethod) {
344                         // set the value
345
Method JavaDoc write = (Method JavaDoc) map.get(name);
346
347                         if (write != null) {
348                             // if you have where to set the value
349
try {
350                                 write.invoke(this, new Object JavaDoc[] { value });
351                             } catch (Exception JavaDoc ex) {
352                                 String JavaDoc msg = "Cannot call " + write + " for property " + getClass().getName() + "." +
353                                     name; // NOI18N
354
Exceptions.attachMessage(ex, msg);
355                                 Logger.getLogger(SystemOption.class.getName()).log(Level.WARNING, null, ex);
356                             }
357                         }
358                     } else {
359                         putProperty(name, value, false);
360                     }
361
362                     if (nullRead) {
363                         break;
364                     }
365                 } while (true);
366             }
367         } finally {
368             // get current state
369
if (this != getProperty(PROP_LOADING)) {
370                 // some changes should be fired
371
// loading finished
372
putProperty(PROP_LOADING, null);
373                 firePropertyChange(null, null, null);
374             } else {
375                 // loading finished
376
putProperty(PROP_LOADING, null);
377             }
378         }
379     }
380
381     protected boolean clearSharedData() {
382         return false;
383     }
384
385     /**
386     * Get the name of this system option.
387     * The default implementation just uses the {@link #displayName display name}.
388     * @return the name
389     */

390     public final String JavaDoc getName() {
391         return displayName();
392     }
393
394     /**
395     * Get the display name of this system option.
396     * @return the display name
397     */

398     public abstract String JavaDoc displayName();
399
400     /** Get context help for this system option.
401     * @return context help
402     */

403     public HelpCtx getHelpCtx() {
404         return new HelpCtx(SystemOption.class);
405     }
406
407     /** Allows subclasses to test whether the change of a property
408     * is invoked from readExternal method or by external change invoked
409     * by any other program.
410     *
411     * @return true if the readExternal method is in progress
412     */

413     protected final boolean isReadExternal() {
414         return getProperty(PROP_LOADING) != null;
415     }
416
417     /** Allows subclasses to test whether the getter of a property
418     * is invoked from writeExternal method or by any other part of the program.
419     *
420     * @return true if the writeExternal method is in progress
421     */

422     protected final boolean isWriteExternal() {
423         return getProperty(PROP_STORING) != null;
424     }
425
426     /** A wrapper object to indicate that a setter should be called
427      * when reseting to default.
428      */

429     private static final class Box extends Object JavaDoc {
430         public Object JavaDoc value;
431
432         public Box(Object JavaDoc v) {
433             this.value = v;
434         }
435     }
436      // end of Box
437
}
438
Popular Tags