alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

What this is

This file is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Other links

The source code

/*
 *                 Sun Public License Notice
 * 
 * The contents of this file are subject to the Sun Public License
 * Version 1.0 (the "License"). You may not use this file except in
 * compliance with the License. A copy of the License is available at
 * http://www.sun.com/
 * 
 * The Original Code is NetBeans. The Initial Developer of the Original
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2004 Sun
 * Microsystems, Inc. All Rights Reserved.
 */

package org.openide.options;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import org.openide.ErrorManager;
import org.openide.util.HelpCtx;
import org.openide.util.NbBundle;
import org.openide.util.SharedClassObject;

/** Base class for all system options.
* Provides methods for adding
* and working with property change and guarantees
* that all instances of the same class will share these listeners.
* 

* When a new option is created, it should subclass * SystemOption, add static variables to it that will hold * the values of properties, and write non-static setters/getters that will * notify all listeners about property changes via * {@link #firePropertyChange}. *

JavaBeans introspection is used to find the properties, * so it is possible to use {@link BeanInfo}. * * @author Jaroslav Tulach */ public abstract class SystemOption extends SharedClassObject implements HelpCtx.Provider { /** generated Serialized Version UID */ static final long serialVersionUID = 558589201969066966L; /** property to indicate that the option is currently loading its data */ private static final Object PROP_LOADING = new Object (); /** property to indicate that the option is currently loading its data */ private static final Object PROP_STORING = new Object (); /** Default constructor. */ public SystemOption() { // SystemOption must declare this property in order to be correctly deserialized // by SharedClassObject.findObject function putProperty ("netbeans.systemoption.hack", null); // NOI18N } /** Fire a property change event to all listeners. Delays * this loading when readExternal is active till it finishes. * * @param name the name of the property * @param oldValue the old value * @param newValue the new value */ protected void firePropertyChange ( String name, Object oldValue, Object newValue ) { if (getProperty (PROP_LOADING) != null) { // somebody is loading, assign any object different than // this to indicate that firing should occure putProperty (PROP_LOADING, PROP_LOADING); // but do not fire the change now return; } super.firePropertyChange (name, oldValue, newValue); } /** Write all properties of this object (or subclasses) to an object output. * @param out the output stream * @exception IOException on error */ public void writeExternal (ObjectOutput out) throws IOException { try { // gets info about all properties that were added by subclass BeanInfo info = org.openide.util.Utilities.getBeanInfo (getClass (), SystemOption.class); PropertyDescriptor[] desc = info.getPropertyDescriptors (); putProperty (PROP_STORING, this); Object[] param = new Object[0]; synchronized (getLock ()) { // write all properties that have getter to stream for (int i = 0; i < desc.length; i++) { // skip readonly Properties if (desc[i].getWriteMethod () == null) { continue; } String propName = desc[i].getName(); Object value = getProperty(propName); boolean fromRead; // JST: this code handles the case when somebody needs to store // different value then is the value of get/set method. // in such case value (from getProperty) is not of the type // of the getter/setter and is used instead of the value from getXXXX Method read = desc[i].getReadMethod(); if (read == null) { continue; } if (value == null || isInstance(desc[i].getPropertyType(), value)) { fromRead = true; try { value = read.invoke (this, param); } catch (InvocationTargetException ex) { // exception thrown IOException ne = new IOException (NbBundle.getMessage ( SystemOption.class, "EXC_InGetter", getClass (), desc[i].getName () )); ErrorManager.getDefault ().annotate (ne, ex); throw ne; } catch (IllegalAccessException ex) { // exception thrown IOException ne = new IOException (NbBundle.getMessage ( SystemOption.class, "EXC_InGetter", getClass (), desc[i].getName () )); ErrorManager.getDefault ().annotate (ne, ex); throw ne; } } else { fromRead = false; } // writes name of the property out.writeObject (propName); // writes its value out.writeObject (value); // from getter or stored prop? out.writeObject(fromRead ? Boolean.TRUE : Boolean.FALSE); } } } catch (IntrospectionException ex) { // if we cannot found any info about properties } finally { putProperty (PROP_STORING, null); } // write null to signal end of properties out.writeObject (null); } /** Returns true if the object is assignable to the class. * Also if the class is primitive and the object is of the matching wrapper type. */ private static boolean isInstance(Class c, Object o) { return c.isInstance(o) || (c == Byte.TYPE && (o instanceof Byte)) || (c == Short.TYPE && (o instanceof Short)) || (c == Integer.TYPE && (o instanceof Integer)) || (c == Long.TYPE && (o instanceof Long)) || (c == Float.TYPE && (o instanceof Float)) || (c == Double.TYPE && (o instanceof Double)) || (c == Boolean.TYPE && (o instanceof Boolean)) || (c == Character.TYPE && (o instanceof Character)); } /** Read all properties of this object (or subclasses) from an object input. * If there is a problem setting the value of any property, that property will be ignored; * other properties should still be set. * @param in the input stream * @exception IOException on error * @exception ClassNotFound if a class used to restore the system option is not found */ public void readExternal (ObjectInput in) throws IOException, ClassNotFoundException { // hashtable that maps names of properties to setter methods HashMap map = new HashMap (); try { synchronized (getLock ()) { // indicate that we are loading files putProperty (PROP_LOADING, this); try { // gets info about all properties that were added by subclass BeanInfo info = org.openide.util.Utilities.getBeanInfo (getClass (), SystemOption.class); PropertyDescriptor[] desc = info.getPropertyDescriptors (); // write all properties that have getter to stream for (int i = 0; i < desc.length; i++) { Method m = desc[i].getWriteMethod (); /*if (m == null) { System.out.println ("HOW HOW HOW HOWHOWHOWHOWHWO: " + desc[i].getName() + " XXX " + getClass()); throw new IOException (new MessageFormat (NbBundle.getBundle (SystemOption.class).getString ("EXC_InSetter")). format (new Object[] {getClass (), desc[i].getName ()}) ); } */ map.put (desc[i].getName (), m ); } } catch (IntrospectionException ex) { // if we cannot found any info about properties // leave the hashtable empty and only read stream till null is found ErrorManager.getDefault().notify ( ErrorManager.INFORMATIONAL, ex); } String preread = null; do { // read the name of property String name; if (preread != null) { name = preread; preread = null; } else { name = (String)in.readObject(); } // break if the end of property stream is found if (name == null) break; // read the value of property Object value = in.readObject (); // read flag - use the setter method or store as property? Object useMethodObject = in.readObject(); boolean useMethod; boolean nullRead = false; // this should be last processed property? if (useMethodObject == null) { useMethod = true; nullRead = true; } else if (useMethodObject instanceof String) { useMethod = true; preread = (String) useMethodObject; } else { useMethod = ((Boolean) useMethodObject).booleanValue(); } if (useMethod) { // set the value Method write = (Method)map.get (name); if (write != null) { // if you have where to set the value try { write.invoke (this, new Object[] { value }); } catch (Exception ex) { String msg = "Cannot call " + write + " for property " + getClass().getName() + "." + name; // NOI18N ErrorManager.getDefault().annotate(ex, ErrorManager.UNKNOWN, msg, null, null, null); ErrorManager.getDefault ().notify ( ErrorManager.INFORMATIONAL, ex ); } } } else { putProperty(name, value, false); } if (nullRead) { break; } } while (true); } } finally { // get current state if (this != getProperty (PROP_LOADING)) { // some changes should be fired // loading finished putProperty (PROP_LOADING, null); firePropertyChange (null, null, null); } else { // loading finished putProperty (PROP_LOADING, null); } } } protected boolean clearSharedData () { return false; } /** * Get the name of this system option. * The default implementation just uses the {@link #displayName display name}. * @return the name */ public final String getName () { return displayName (); } /** * Get the display name of this system option. * @return the display name */ public abstract String displayName (); /** Get context help for this system option. * @return context help */ public HelpCtx getHelpCtx () { return new HelpCtx (SystemOption.class); } /** Allows subclasses to test whether the change of a property * is invoked from readExternal method or by external change invoked * by any other program. * * @return true if the readExternal method is in progress */ protected final boolean isReadExternal () { return getProperty (PROP_LOADING) != null; } /** Allows subclasses to test whether the getter of a property * is invoked from writeExternal method or by any other part of the program. * * @return true if the writeExternal method is in progress */ protected final boolean isWriteExternal () { return getProperty (PROP_STORING) != null; } }

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.