diff --git a/api.debugger/apichanges.xml b/api.debugger/apichanges.xml --- a/api.debugger/apichanges.xml +++ b/api.debugger/apichanges.xml @@ -309,6 +309,25 @@ + + + Support for providing initial values of properties. + + + + + +

+ Properties.Initializer interface introduced to provide initial + values of properties. This is necessary when properties are + accessed from more places and it's not practical to copy default + values to every such location. +

+
+ + +
+ diff --git a/api.debugger/manifest.mf b/api.debugger/manifest.mf --- a/api.debugger/manifest.mf +++ b/api.debugger/manifest.mf @@ -1,4 +1,4 @@ Manifest-Version: 1.0 OpenIDE-Module: org.netbeans.api.debugger/1 OpenIDE-Module-Localizing-Bundle: org/netbeans/api/debugger/Bundle.properties -OpenIDE-Module-Specification-Version: 1.16 +OpenIDE-Module-Specification-Version: 1.17 diff --git a/api.debugger/src/org/netbeans/api/debugger/Properties.java b/api.debugger/src/org/netbeans/api/debugger/Properties.java --- a/api.debugger/src/org/netbeans/api/debugger/Properties.java +++ b/api.debugger/src/org/netbeans/api/debugger/Properties.java @@ -66,6 +66,7 @@ import org.openide.filesystems.FileLock; import org.openide.filesystems.FileObject; import org.openide.filesystems.FileUtil; +import org.openide.util.Exceptions; import org.openide.util.RequestProcessor; @@ -355,7 +356,28 @@ */ public void write (Object object, Properties properties); } - + + /** + * Implementing this interface one can define initial values of properties. + */ + public interface Initializer { + + /** + * The list of supported property names. + * @return the property names supported by this initializer + */ + String[] getSupportedPropertyNames(); + + /** + * Get the default value of property. + * @param propertyName The name of the property + * @return The default value + */ + Object getDefaultPropertyValue(String propertyName); + + } + + private final static class PrimitiveRegister { private HashMap properties = new HashMap (); @@ -486,94 +508,160 @@ private static final Map BAD_MAP = new HashMap (); private static final Collection BAD_COLLECTION = new ArrayList (); private static final Object[] BAD_ARRAY = new Object [0]; - - private List readersList; - private HashMap register; - - + + ServicesHolder readers = new ReaderHolder(); + ServicesHolder initializers = new InitializerHolder(); + + private static abstract class ServicesHolder { + + private Class clazz; + // Holds the list to prevent from garbage-collect. Do not remove! + private List servicesList; + protected HashMap register; + + public ServicesHolder(Class clazz) { + this.clazz = clazz; + } + + private final void init() { + register = new HashMap(); + final List list = DebuggerManager.getDebuggerManager().lookup(null, clazz); + servicesList = list; + synchronized (list) { + for (T s : list) { + registerService(s); + } + } + ((Customizer) list).addPropertyChangeListener( + new PropertyChangeListener() { + public void propertyChange(PropertyChangeEvent evt) { + synchronized (ServicesHolder.this) { + Set registeredServices = new HashSet(register.values()); + synchronized (list) { + for (T s : list) { + if (!registeredServices.remove(s)) { + registerService(s); + } + } + } + for (T s : registeredServices) { + unregisterService(s); + } + } + } + }); + ((Customizer) list).setObject(Lookup.NOTIFY_LOAD_FIRST); + ((Customizer) list).setObject(Lookup.NOTIFY_UNLOAD_LAST); + } + + protected abstract void registerService(T s); + + protected abstract void unregisterService(T s); + + public synchronized T find(String name) { + if (register == null) { + init(); + } + return register.get(name); + } + + } + + private static final class ReaderHolder extends ServicesHolder { + + public ReaderHolder() { + super(Reader.class); + } + + @Override + protected void registerService(Reader r) { + //System.err.println("registerReader("+r+")"); + String[] ns = r.getSupportedClassNames (); + int j, jj = ns.length; + for (j = 0; j < jj; j++) { + register.put (ns [j], r); + } + } + + @Override + protected void unregisterService(Reader r) { + //System.err.println("unregisterReader("+r+")"); + String[] ns = r.getSupportedClassNames (); + int j, jj = ns.length; + for (j = 0; j < jj; j++) { + register.remove (ns [j]); + } + } + + @Override + public synchronized Reader find(String typeID) { + + Reader r = super.find(typeID); + if (r != null) return r; + + Class c = null; + try { + c = getClassLoader ().loadClass (typeID); + } catch (ClassNotFoundException e) { + ErrorManager.getDefault().notify(e); + return null; + } + while ((c != null) && (register.get (c.getName ()) == null)) { + c = c.getSuperclass (); + } + if (c != null) + r = (Reader) register.get (c.getName ()); + return r; + } + + } + + private static final class InitializerHolder extends ServicesHolder { + + public InitializerHolder() { + super(Initializer.class); + } + + @Override + protected void registerService(Initializer i) { + //System.err.println("registerInitializer("+i+")"); + String[] ns = i.getSupportedPropertyNames(); + int j, jj = ns.length; + for (j = 0; j < jj; j++) { + register.put (ns [j], i); + } + } + + @Override + protected void unregisterService(Initializer i) { + //System.err.println("unregisterInitializer("+i+")"); + String[] ns = i.getSupportedPropertyNames (); + int j, jj = ns.length; + for (j = 0; j < jj; j++) { + register.remove (ns [j]); + } + } + } + + private PrimitiveRegister impl = new PrimitiveRegister (); - private void initReaders () { - register = new HashMap(); - readersList = DebuggerManager.getDebuggerManager().lookup(null, Reader.class); - synchronized (readersList) { - for (Reader r : readersList) { - registerReader(r); + + private T getInitialValue(String propertyName, Class clazz) { + Initializer initializer = initializers.find(propertyName); + if (initializer != null) { + Object value = initializer.getDefaultPropertyValue(propertyName); + if (value != null && !clazz.isAssignableFrom(value.getClass())) { + Exceptions.printStackTrace(new IllegalStateException( + "Value ("+value+") of a bad type ("+value.getClass()+") returned by "+initializer+ + " for property '"+propertyName+"'. It can not be cast to "+clazz)); + value = null; } - } - ((Customizer) readersList).addPropertyChangeListener( - new PropertyChangeListener() { - public void propertyChange(PropertyChangeEvent evt) { - synchronized (PropertiesImpl.this) { - Set registeredReaders = new HashSet(register.values()); - synchronized (readersList) { - for (Reader r : readersList) { - if (!registeredReaders.remove(r)) { - registerReader(r); - } - } - } - for (Reader r : registeredReaders) { - unregisterReader(r); - } - } - } - }); - ((Customizer) readersList).setObject(Lookup.NOTIFY_LOAD_FIRST); - ((Customizer) readersList).setObject(Lookup.NOTIFY_UNLOAD_LAST); - } - - private void registerReader(Reader r) { - //System.err.println("registerReader("+r+")"); - String[] ns = r.getSupportedClassNames (); - int j, jj = ns.length; - for (j = 0; j < jj; j++) { - register.put (ns [j], r); + return (T) value; + } else { + return null; } } - - private void unregisterReader(Reader r) { - //System.err.println("unregisterReader("+r+")"); - String[] ns = r.getSupportedClassNames (); - int j, jj = ns.length; - for (j = 0; j < jj; j++) { - register.remove (ns [j]); - } - } - - // Used from tests - synchronized void addReader(Reader r) { - if (register == null) { - initReaders (); - } - registerReader(r); - } - - private synchronized Reader findReader (String typeID) { - if (register == null) { - initReaders (); - } - - Reader r = (Reader) register.get (typeID); - if (r != null) return r; - - Class c = null; - try { - c = getClassLoader ().loadClass (typeID); - } catch (ClassNotFoundException e) { - ErrorManager.getDefault().notify(e); - return null; - } - while ((c != null) && (register.get (c.getName ()) == null)) { - c = c.getSuperclass (); - } - if (c != null) - r = (Reader) register.get (c.getName ()); - return r; - } - - - // primitive properties .................................................................................... @@ -710,7 +798,13 @@ public Object getObject (String propertyName, Object defaultValue) { synchronized(impl) { String typeID = impl.getProperty (propertyName, null); - if (typeID == null) return defaultValue; + if (typeID == null) { + Object initialValue = getInitialValue(propertyName, Object.class); + if (initialValue == null) { + initialValue = defaultValue; + } + return initialValue; + } if (typeID.equals ("# null")) return null; if (!typeID.startsWith ("# ")) { @@ -745,7 +839,7 @@ return co; } } - Reader r = findReader (typeID); + Reader r = readers.find(typeID); if (r == null) { ErrorManager.getDefault().log("Can not read object. No reader registered for type " + typeID + "."); return defaultValue; @@ -778,7 +872,7 @@ } // find register - Reader r = findReader (value.getClass ().getName ()); + Reader r = readers.find(value.getClass ().getName ()); if (r == null) { ErrorManager.getDefault().log ("Can not write object " + value); return; @@ -794,8 +888,11 @@ synchronized(impl) { String arrayType = impl.getProperty (propertyName + ".array_type", null); if (arrayType == null) { - ErrorManager.getDefault().log("Unknown array type for "+propertyName); - return defaultValue; + Object[] initialValue = getInitialValue(propertyName, Object[].class); + if (initialValue == null) { + initialValue = defaultValue; + } + return initialValue; } Properties p = getProperties (propertyName); int l = p.getInt ("length", -1); @@ -834,7 +931,13 @@ public Collection getCollection (String propertyName, Collection defaultValue) { synchronized(impl) { String typeID = impl.getProperty (propertyName, null); - if (typeID == null) return defaultValue; + if (typeID == null) { + Collection initialValue = getInitialValue(propertyName, Collection.class); + if (initialValue == null) { + initialValue = defaultValue; + } + return initialValue; + } if (!typeID.startsWith ("# ")) return defaultValue; Collection c = null; try { @@ -886,7 +989,13 @@ public Map getMap (String propertyName, Map defaultValue) { synchronized(impl) { String typeID = impl.getProperty (propertyName, null); - if (typeID == null) return defaultValue; + if (typeID == null) { + Map initialValue = getInitialValue(propertyName, Map.class); + if (initialValue == null) { + initialValue = defaultValue; + } + return initialValue; + } if (!typeID.startsWith ("# ")) return defaultValue; Map m = null; try {