0001: /*
0002: * <copyright>
0003: *
0004: * Copyright 2000-2004 BBNT Solutions, LLC
0005: * under sponsorship of the Defense Advanced Research Projects
0006: * Agency (DARPA).
0007: *
0008: * You can redistribute this software and/or modify it under the
0009: * terms of the Cougaar Open Source License as published on the
0010: * Cougaar Open Source Website (www.cougaar.org).
0011: *
0012: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
0013: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
0014: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
0015: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
0016: * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
0017: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
0018: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
0019: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
0020: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0021: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
0022: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0023: *
0024: * </copyright>
0025: */
0026:
0027: package org.cougaar.tools.csmart.core.property;
0028:
0029: import org.cougaar.tools.csmart.core.cdata.ComponentData;
0030: import org.cougaar.tools.csmart.core.db.PopulateDb;
0031: import org.cougaar.tools.csmart.core.property.name.ComponentName;
0032: import org.cougaar.tools.csmart.core.property.name.CompositeName;
0033: import org.cougaar.tools.csmart.core.property.name.SimpleName;
0034: import org.cougaar.tools.csmart.ui.viewer.CSMART;
0035: import org.cougaar.util.FilteredIterator;
0036: import org.cougaar.util.UnaryPredicate;
0037: import org.cougaar.util.log.Logger;
0038:
0039: import javax.swing.event.EventListenerList;
0040: import java.io.IOException;
0041: import java.io.ObjectInputStream;
0042: import java.io.ObjectOutputStream;
0043: import java.io.PrintStream;
0044: import java.io.Serializable;
0045: import java.lang.reflect.Constructor;
0046: import java.net.URL;
0047: import java.util.ArrayList;
0048: import java.util.Collection;
0049: import java.util.Collections;
0050: import java.util.EventListener;
0051: import java.util.HashMap;
0052: import java.util.Iterator;
0053: import java.util.List;
0054: import java.util.Map;
0055: import java.util.NoSuchElementException;
0056:
0057: /**
0058: * This is the default configurable component implementation.
0059: * It implements all methods that define, name, label, etc. Properties.
0060: *
0061: * This class should be overridden by specific components.
0062: */
0063: public abstract class ConfigurableComponent implements BaseComponent,
0064: ConfigurableComponentListener {
0065: private static final long serialVersionUID = -1294225527645517794L;
0066:
0067: private transient Map myProperties = new HashMap();
0068: private transient boolean myPropertiesInvalid = false; // flag to invalidate the local cache
0069: private transient ComposableComponent parent; // Our parent, if any
0070: private transient List children = null; // Our children, if any
0071: private static int nameCount = 0;
0072: private ComponentName myName;
0073: private boolean nameChangeMark = false;
0074:
0075: private transient EventListenerList listeners = null;
0076:
0077: private PropertiesListener myPropertiesListener = new MyPropertiesListener();
0078:
0079: /** Handle to the Logger **/
0080: protected transient Logger log;
0081:
0082: private class MyPropertiesListener implements PropertiesListener,
0083: ConfigurableComponentListener {
0084: public void propertyAdded(PropertyEvent e) {
0085: // Note the assumption that getProperty returns both Visible and inVisible properties
0086: if (e.getProperty().isVisible()) {
0087: firePropertyAdded(e);
0088: }
0089: }
0090:
0091: public void propertyRemoved(PropertyEvent e) {
0092: // Note the assumption that getProperty returns both Visible and inVisible properties
0093: // Bug 1743: Is the following version better?
0094: // if (e.getProperty().isVisible()) {
0095: if (isPropertyVisible(e.getProperty())) {
0096: firePropertyRemoved(e);
0097: }
0098: }
0099: }
0100:
0101: /**
0102: * Gets an <code>EventListenerList</code>.
0103: *
0104: * @return an <code>EventListenerList</code> object
0105: */
0106: protected EventListenerList getEventListenerList() {
0107: if (listeners == null)
0108: listeners = new EventListenerList();
0109: return listeners;
0110: }
0111:
0112: /**
0113: * Add a PropertiesListener. PropertiesListeners are invoked
0114: * whenever properties are added or removed.
0115: *
0116: * @param l <code>PropertiesListener</code> to add
0117: */
0118: public void addPropertiesListener(PropertiesListener l) {
0119: getEventListenerList().add(PropertiesListener.class, l);
0120: }
0121:
0122: /**
0123: * Removes a PropertiesListener.
0124: *
0125: * @param l <code>PropertiesListener</code> to remove
0126: */
0127: public void removePropertiesListener(PropertiesListener l) {
0128: getEventListenerList().remove(PropertiesListener.class, l);
0129: }
0130:
0131: /**
0132: * Fires an <code>PropertyEvent</code> when a new property
0133: * is added to the component.
0134: *
0135: * @param ev <code>PropertyEvent </code>
0136: */
0137: protected void firePropertyAdded(PropertyEvent ev) {
0138: PropertiesListener[] ls = (PropertiesListener[]) getEventListenerList()
0139: .getListeners(PropertiesListener.class);
0140: for (int i = 0; i < ls.length; i++) {
0141: ls[i].propertyAdded(ev);
0142: }
0143: }
0144:
0145: private void firePropertyAdded(Property p) {
0146: if (listeners != null) {
0147: firePropertyAdded(new PropertyEvent(p,
0148: PropertyEvent.PROPERTY_ADDED));
0149: }
0150: }
0151:
0152: private void firePropertyRemoved(Property p) {
0153: firePropertyRemoved(new PropertyEvent(p,
0154: PropertyEvent.PROPERTY_REMOVED));
0155: }
0156:
0157: private void firePropertyRemoved(PropertyEvent ev) {
0158: PropertiesListener[] ls = (PropertiesListener[]) getEventListenerList()
0159: .getListeners(PropertiesListener.class);
0160: for (int i = 0; i < ls.length; i++) {
0161: ls[i].propertyRemoved(ev);
0162: }
0163: }
0164:
0165: /**
0166: * Construct a ConfigurableComponent with a given name. Nota bene:
0167: * the constructors of ConfigurableComponents must _not_ perform any
0168: * initialization of properties because the final name of the
0169: * component is not known until it has been incorporated in a
0170: * component hierarchy. The abstract initProperties() method should
0171: * be used to initialize properties. The initialization of any child
0172: * components should be deferred until the initialization of the
0173: * parent.
0174: **/
0175: protected ConfigurableComponent(String name) {
0176: if (name == null) {
0177: name = getClass().getName();
0178: int ix = name.lastIndexOf('.');
0179: if (ix >= 0)
0180: name = name.substring(ix + 1);
0181: name += "-" + ++nameCount;
0182: }
0183: myName = new ComponentName(null, name);
0184: createLogger();
0185: }
0186:
0187: private void createLogger() {
0188: log = CSMART.createLogger(this .getClass().getName());
0189: }
0190:
0191: public abstract void initProperties();
0192:
0193: /**
0194: * Set a bunch of Properties at once. Used when creating a component
0195: * from the database. Default implementation just iterates through
0196: * the map. Note that the properties <em>must</em> have been previously
0197: * created in <code>initProperties()</code>
0198: *
0199: * @param props a <code>Map</code> of <code>String</code> property names and <code>Object</code> values
0200: */
0201: public void setProperties(Map props) {
0202: // Set the properties in Alphabetical Order.
0203: // This allows any required listeners to fire, setting up
0204: // dynamic properties.
0205: ArrayList names = new ArrayList();
0206: for (Iterator i = props.keySet().iterator(); i.hasNext();) {
0207: names.add(i.next());
0208: }
0209:
0210: // Note therefore that for recipes, Arg Order doesnt matter - just
0211: // the alphabetical order of the argument names
0212: Collections.sort(names);
0213:
0214: Iterator i = names.iterator();
0215:
0216: // For each property to add
0217: while (i.hasNext()) {
0218: try {
0219: String propName = (String) i.next();
0220: String propValue = (String) props.get(propName);
0221: Property prop = getProperty(propName);
0222: if (prop == null) {
0223: if (log.isErrorEnabled()) {
0224: log.error("Unknown property: " + propName + "="
0225: + propValue + " in component "
0226: + this .toString() + ". Will add it.");
0227: }
0228: // FIXME: This wont get the class right potentially
0229: prop = addProperty(propName, propValue);
0230: } else {
0231: Class propClass = prop.getPropertyClass();
0232: if (log.isDebugEnabled() && propClass == null) {
0233: log.debug("null prop class for Prop name: "
0234: + propName + ", value " + propValue
0235: + " property: " + prop.toString());
0236: }
0237: Constructor constructor = propClass
0238: .getConstructor(new Class[] { String.class });
0239: Object value = constructor
0240: .newInstance(new Object[] { propValue });
0241: if (log.isDebugEnabled()) {
0242: log.debug("Setting value for property "
0243: + prop.getName().toString()
0244: + " with label " + prop.getLabel()
0245: + " and old value: " + prop.getValue()
0246: + " to new val " + value);
0247: }
0248: prop.setValue(value);
0249: }
0250: } catch (Exception e) {
0251: if (log.isErrorEnabled()) {
0252: log.error("Exception setting component properties",
0253: e);
0254: }
0255: }
0256: }
0257: } // end of setProperties
0258:
0259: /**
0260: * Get a <code>URL</code> for a description of the component. May return <code>null</code>.
0261: * <br>
0262: * This default implementation returns <code>null</code>.
0263: *
0264: * @return an <code>URL</code> describing this component.
0265: */
0266: public URL getDescription() {
0267: return null;
0268: }
0269:
0270: /**
0271: * Gets the Ancestor of this component.
0272: * The ancestor is a specific class type.
0273: *
0274: * @param cls <code>Class</code> of Ancestor
0275: * @return <code>ComposableComponent</code> for the ancestor.
0276: */
0277: protected ComposableComponent getAncestorOfClass(Class cls) {
0278: ComposableComponent parent = getParent();
0279: if (parent == null)
0280: return null;
0281: if (cls.isInstance(parent))
0282: return parent;
0283: return ((ConfigurableComponent) parent).getAncestorOfClass(cls);
0284: }
0285:
0286: /**
0287: * Gets a <code>Collection</code> of all Descendents of this component
0288: * that are a specific class type.
0289: * Note: The collection (parameter) must be initialized!
0290: *
0291: * @param cls The <code>Class</code> of the Descendents
0292: * @param c An Empty <code>Collection</code> for the result.
0293: * @return a <code>Collection</code> of a descendents requested.
0294: */
0295: public Collection getDescendentsOfClass(Class cls, Collection c) {
0296: for (int i = 0, n = getChildCount(); i < n; i++) {
0297: ComposableComponent child = getChild(i);
0298: child.getDescendentsOfClass(cls, c);
0299: if (cls.isInstance(child))
0300: c.add(child);
0301: }
0302: return c;
0303: }
0304:
0305: /**
0306: * Gets a <code>Collection</code> of all Descendents of this component
0307: * that are a specific class type.
0308: *
0309: * @param cls The <code>Class</code> of the Descendents
0310: * @return a <code>Collection</code> of a descendents requested.
0311: */
0312: public Collection getDescendentsOfClass(Class cls) {
0313: return getDescendentsOfClass(cls, new ArrayList());
0314: }
0315:
0316: /**
0317: * Set the name of this component. The name is relative to the
0318: * parent and must be distinct in that context.
0319: *
0320: * @param newName the new name for this component.
0321: **/
0322: public void setName(String newName) {
0323: startNameChange();
0324: myName.setName(SimpleName.getSimpleName(newName));
0325: finishNameChange();
0326: }
0327:
0328: /**
0329: * Gets the short name of this component. All component names
0330: * are made up of a chain based on the component hierarchy.
0331: * This chain is: grandparent.parent.child
0332: * Short name is just 'child'.
0333: *
0334: * @return a <code>String</code> value of the short name.
0335: */
0336: public String getShortName() {
0337: return getFullName().last().toString();
0338: }
0339:
0340: /**
0341: * Gets the full name of this component. All component names
0342: * are made up of a chain based on the component hierarchy.
0343: * This chain is: grandparent.parent.child
0344: *
0345: * Full name is the complete chain.
0346: *
0347: * @return a <code>CompositeName</code> value of the full component name.
0348: */
0349: public CompositeName getFullName() {
0350: return myName;
0351: }
0352:
0353: /**
0354: * Add a child to this component. Childs are always of type
0355: * <code>ComposableComponent</code>.
0356: *
0357: * @param c the child to add
0358: * @return Count of all Children in this component.
0359: */
0360: public int addChild(ComposableComponent c) {
0361: if (children == null)
0362: children = new ArrayList();
0363: ((ConfigurableComponent) c)
0364: .addPropertiesListener(myPropertiesListener);
0365: if (getChild(((ConfigurableComponent) c).getFullName()) != null) {
0366: // Name is not unqiue, make it so.
0367: ((ConfigurableComponent) c)
0368: .setName(((ConfigurableComponent) c).getFullName()
0369: .toString()
0370: + String.valueOf(getChildCount()));
0371: }
0372: children.add(c);
0373: c.setParent(this );
0374: for (Iterator i = ((ConfigurableComponent) c).getProperties(); i
0375: .hasNext();) {
0376: Property prop = (Property) i.next();
0377: if (prop != null)
0378: firePropertyAdded(prop);
0379: }
0380: return children.size() - 1;
0381: }
0382:
0383: /**
0384: * Removes a child component at a specific index.
0385: *
0386: * @param childIndex Index of child to remove.
0387: */
0388: public void removeChild(int childIndex) {
0389: removeChild(getChild(childIndex));
0390: }
0391:
0392: /**
0393: * Removes a specific child component.
0394: *
0395: * @param c <code>ComposableComponent</code> of child to remove.
0396: */
0397: public void removeChild(ComposableComponent c) {
0398: if (children == null || c.getParent() != this )
0399: return;
0400: ((ConfigurableComponent) c)
0401: .removePropertiesListener(myPropertiesListener);
0402: for (Iterator i = ((ConfigurableComponent) c).getProperties(); i
0403: .hasNext();) {
0404: Property prop = (Property) i.next();
0405: if (prop != null)
0406: firePropertyRemoved(prop);
0407: }
0408: children.remove(c);
0409: c.setParent(null);
0410: }
0411:
0412: /**
0413: * Removes all children of this component.
0414: *
0415: */
0416: public void removeAllChildren() {
0417: while (getChildCount() != 0) {
0418: removeChild(getChildCount() - 1);
0419: }
0420: }
0421:
0422: /**
0423: * Gets a count of all children within this component.
0424: *
0425: * @return Child Count.
0426: */
0427: public int getChildCount() {
0428: if (children == null)
0429: return 0;
0430: return children.size();
0431: }
0432:
0433: /**
0434: * Gets a child component from a specific index.
0435: *
0436: * @param n index of child component to retreive.
0437: * @return a <code>ComposableComponent</code> object for that child.
0438: */
0439: public ComposableComponent getChild(int n) {
0440: return (ComposableComponent) children.get(n);
0441: }
0442:
0443: /**
0444: * Gets a child component based on the childs Full Name.
0445: *
0446: * @param childName <code>CompositeName</code> of the child.
0447: * @return a <code>ComposableComponent</code> object of the child.
0448: */
0449: public ComposableComponent getChild(CompositeName childName) {
0450: ComposableComponent cc = null;
0451:
0452: for (int i = 0; i < getChildCount(); i++) {
0453: cc = getChild(i);
0454: if (((ConfigurableComponent) cc).getShortName().equals(
0455: childName.toString())) {
0456: return cc;
0457: }
0458: }
0459:
0460: return null;
0461: }
0462:
0463: /**
0464: * Changing our parent changes all our property names so we have to
0465: * rehash them and flush their caches.
0466: *
0467: * @param newParent New Parent Component
0468: */
0469: public void setParent(ComposableComponent newParent) {
0470: ComposableComponent oldParent = parent;
0471: startNameChange();
0472: parent = newParent;
0473: myName.setComponent((BaseComponent) parent); // flushes myName's cache as a side-effect
0474: finishNameChange();
0475: if (oldParent != null)
0476: ((ConfigurableComponent) oldParent)
0477: .fireChildConfigurationChanged();
0478: if (newParent != null)
0479: ((ConfigurableComponent) newParent)
0480: .fireChildConfigurationChanged();
0481: }
0482:
0483: /**
0484: * Add a ChildConfigurationListener. ChildConfigurationListener are
0485: * invoked whenever children are added or removed.
0486: *
0487: * @param l <code>ChildConfigurationListener</code> to add to this component.
0488: */
0489: public void addChildConfigurationListener(
0490: ChildConfigurationListener l) {
0491: getEventListenerList().add(ChildConfigurationListener.class, l);
0492: }
0493:
0494: /**
0495: * Removes a <code>ChildConfigurationListener</code> from this component.
0496: *
0497: * @param l <code>ChildCondigurationListener</code> to remove.
0498: */
0499: public void removeChildConfigurationListener(
0500: ChildConfigurationListener l) {
0501: getEventListenerList().remove(ChildConfigurationListener.class,
0502: l);
0503: }
0504:
0505: /**
0506: * Fires an event when a child configuration has changed.
0507: *
0508: */
0509: protected void fireChildConfigurationChanged() {
0510: ChildConfigurationListener[] ls = (ChildConfigurationListener[]) getEventListenerList()
0511: .getListeners(ChildConfigurationListener.class);
0512: for (int i = 0; i < ls.length; i++) {
0513: ls[i].childConfigurationChanged();
0514: }
0515: }
0516:
0517: /**
0518: * Move the contents of the myProperties Map into the
0519: * myPropertyEntries Collection since the keys in the Map are about
0520: * to become invalid. The myProperties Map will be recreated later.
0521: **/
0522: public void startNameChange() {
0523: if (nameChangeMark)
0524: return;
0525: nameChangeMark = true;
0526: for (int i = 0, n = getChildCount(); i < n; i++) {
0527: ((ConfigurableComponent) getChild(i)).startNameChange();
0528: }
0529:
0530: // MIK: WTF why are we trashing the entire CC hierarchy's maps?!?
0531: /*
0532: if (parent != null)
0533: ((ConfigurableComponent)parent).startNameChange();
0534: */
0535:
0536: nameChangeMark = false;
0537:
0538: getFullName().decache(); // decache this component name.
0539:
0540: if (myProperties != null) {
0541: // invalidate the property hashmap
0542: myPropertiesInvalid = true;
0543:
0544: // while we're here, we'll decache the property names
0545: // MIK: we could probably wait till we do getMyProperties
0546: for (Iterator it = myProperties.entrySet().iterator(); it
0547: .hasNext();) {
0548: Map.Entry entry = (Map.Entry) it.next();
0549: CompositeName n = (CompositeName) entry.getKey();
0550: n.decache();
0551: }
0552: }
0553: } // end of startNameChange
0554:
0555: /**
0556: * Called after a change in our name is completed. We do nothing
0557: * with the myProperties Map because it is recreated on demand. If
0558: * there was a former parent, we inform the old parent that one of
0559: * its children has been abducted.
0560: **/
0561: public void finishNameChange() {
0562: if (nameChangeMark)
0563: return;
0564: nameChangeMark = true;
0565: for (int i = 0, n = getChildCount(); i < n; i++) {
0566: ((ConfigurableComponent) getChild(i)).finishNameChange();
0567: }
0568: if (parent != null)
0569: ((ConfigurableComponent) parent).finishNameChange();
0570: nameChangeMark = false;
0571: }
0572:
0573: /**
0574: * The actual Map of our properties is private so we can do a late
0575: * bind of it. The properties are sometimes in the myProperties Map
0576: * and sometimes in myPropertyEntries collection. This is done
0577: * because the names can change as the component is reparented and
0578: * therefore become invalid as keys in the map. After reparenting,
0579: * this procedure recreates the Map the first time it is needed.
0580: * @return the Map of this component's properties.
0581: **/
0582: protected Map getMyProperties() {
0583: if (myProperties != null) {
0584: if (myPropertiesInvalid) {
0585: // copy the contents because we're going to trash the original
0586: ArrayList tmp = new ArrayList(myProperties.values());
0587: // clear the original
0588: myProperties.clear();
0589: for (int i = 0, l = tmp.size(); i < l; i++) {
0590: Property p = (Property) tmp.get(i);
0591: myProperties.put(p.getName(), p);
0592: }
0593: myPropertiesInvalid = false;
0594: }
0595: }
0596: // Note assumption that myProperties is never null. Otherwise, getMyProperties could
0597: // now return null, which is an API change!
0598: return myProperties;
0599: }
0600:
0601: /**
0602: * Gets the parent of this component. If there are no
0603: * parents, NULL is returned.
0604: *
0605: * @return a <code>ComposableComponent</code> object for the parent, or null if no parent.
0606: */
0607: public ComposableComponent getParent() {
0608: return parent;
0609: }
0610:
0611: /**
0612: * Get an invisible property which is not returned by <code>getVisibleProperty</code>.
0613: * Use this method only when absolutely necessary.
0614: * Returns null if no invisible property exists with the specified name.
0615: *
0616: * @param name full name of property to look for
0617: * @return a <code>Property</code> value, null if the named property is Visible
0618: */
0619: public Property getInvisibleProperty(CompositeName name) {
0620: return getPropertyWorker(name, false, false);
0621: }
0622:
0623: /**
0624: * Get an invisible property which is not returned by <code>getVisibleProperty</code>.
0625: * Use this method only when absolutely necessary.
0626: * Returns null if no invisible property exists with the specified name.
0627: *
0628: * @param localName short name of property to look for
0629: * @return a <code>Property</code> value
0630: */
0631: public Property getInvisibleProperty(String localName) {
0632: return getInvisibleProperty(new ComponentName(this , localName));
0633: }
0634:
0635: /**
0636: * Get a visible property which is not returned by <code>getInvisibleProperty</code>.
0637: * Use this method only when absolutely necessary.
0638: * Returns null if no visible property exists with the specified name.
0639: *
0640: * @param name full Name of property to look for
0641: * @return a <code>Property</code> value, null if the named property is Invisible
0642: */
0643: public Property getVisibleProperty(CompositeName name) {
0644: return getPropertyWorker(name, false, true);
0645: }
0646:
0647: /**
0648: * Get a visible property which is not returned by <code>getVisibleProperty</code>.
0649: * Use this method only when absolutely necessary.
0650: * Returns null if no visible property exists with the specified name.
0651: *
0652: * @param localName short name of Property to find
0653: * @return a <code>Property</code> value
0654: */
0655: public Property getVisibleProperty(String localName) {
0656: return getVisibleProperty(new ComponentName(this , localName));
0657: }
0658:
0659: /**
0660: * Get a property by name. Current functionality returns it regardless
0661: * of whether it is in fact invisible.
0662: *
0663: * @param name the name of the property.
0664: * @return the property or null if there is no property with the
0665: * specified name
0666: **/
0667: public Property getProperty(CompositeName name) {
0668: return getPropertyWorker(name, true, true);
0669: }
0670:
0671: // Only print the stacktrace once for this error
0672: private transient boolean hadNullChildNameError = false;
0673:
0674: // Worker method that gets properties from a component or its children.
0675: // If you ask for all, it gets the property whether visible or not.
0676: // Otherwise, it looks at the third argument, and only returns the property
0677: // if its visibility matches your request
0678: // Note that this method is called recursively
0679: protected Property getPropertyWorker(CompositeName name,
0680: boolean all, boolean visible) {
0681: // Note: This now assumes it is _always_ true that a Property is located off a Component
0682: // based on its name: <full name of component>.foo, for example
0683:
0684: // walk from root to see if we're at a reasonable spot
0685: if (name.startsWith(myName)) { // is this component a prefix?
0686: // Invisible Properties are still properties -- they just
0687: // say they are not visible. So we must test them
0688: // and return null if they say they are not visible
0689: Property p = (Property) getMyProperties().get(name);
0690: if (p != null) {
0691: // Are we getting all properties
0692: if (all) {
0693: // If so, just return it
0694: return p;
0695: // Otherwise, we only want to return the actual property
0696: // if its visibility matches that requested
0697: } else if (p.isVisible() == visible) {
0698: return p;
0699: } else {
0700: // User did not want all properties, and this property's visibility
0701: // is not the variant the user wanted
0702: // Don't return it.
0703: // Note however that on recursion into children, this null return
0704: // is indistinguishable from not finding the property
0705: return null;
0706: }
0707: } // end of block on found the property locally
0708:
0709: // Didn't find the property locally. Check the children.
0710: // check the children
0711: int myl = myName.size();
0712: int nl = name.size();
0713: if (nl > myl) { // any chance a child has it?
0714: CompositeName nn = name.get(myl); // get the next name
0715: if (nn == null) {
0716: if (log.isErrorEnabled())
0717: log.error(
0718: "getProperty: null CompositeName. myName: "
0719: + myName + ", name: " + name
0720: + " myName.size(): " + myl
0721: + " name.size() " + nl,
0722: new Throwable());
0723: return null;
0724: }
0725:
0726: // Now loop over the children
0727: for (int i = 0, n = getChildCount(); i < n; i++) {
0728: ConfigurableComponent child = (ConfigurableComponent) getChild(i);
0729:
0730: // First, some error checks
0731: if (child == null) {
0732: if (log.isErrorEnabled())
0733: log.error("getProperty[" + getFullName()
0734: + "]: null child at index " + i
0735: + " when getChildCount reported "
0736: + n, new Throwable());
0737: continue;
0738: }
0739: if (child.getFullName() == null) {
0740: // This seems common at de-serialization, and apparently harmless. Is it somehow expected?
0741: if (hadNullChildNameError) {
0742: // Warning: Can't do stacktrace here cause it happens so often
0743: if (log.isInfoEnabled())
0744: log
0745: .info("getProperty["
0746: + getFullName()
0747: + "]: null child name for child at index "
0748: + i);
0749: } else {
0750: hadNullChildNameError = true;
0751: if (log.isInfoEnabled())
0752: log
0753: .info(
0754: "getProperty["
0755: + getFullName()
0756: + "]: null child name for child at index "
0757: + i,
0758: new Throwable());
0759: }
0760: continue;
0761: }
0762:
0763: // Now see if the childs name would allow it to have the property
0764: if (nn.equals(child.getFullName().get(myl))) {
0765: Property result = child.getPropertyWorker(name,
0766: all, visible);
0767: if (result != null) {
0768: // Found it!
0769: if (nl == myl + 1) {
0770: if (log.isErrorEnabled())
0771: log.error(
0772: "getProperty: Bogon alert: n+l child match!\n"
0773: + getFullName()
0774: + "\n" + name,
0775: new Throwable());
0776: }
0777: return result;
0778: }
0779: // We fall in here also when the matching child had the property
0780: // but it was invisible and we wanted visible or vice versa
0781: if (log.isErrorEnabled())
0782: log
0783: .error(
0784: "getProperty Error: matching child didn't have "
0785: + (all == true ? ""
0786: : (visible == true ? "visible "
0787: : "invisible "))
0788: + "property\n"
0789: + getFullName()
0790: + "\n" + name,
0791: new Throwable());
0792: return null;
0793: }
0794: } // end of loop over children
0795:
0796: // no child has it
0797: if (nl != myl + 1) {
0798: // only warn if the prop is not 1 name longer than component.
0799: if (log.isErrorEnabled())
0800: log.error(
0801: "getProperty Error: didn't have a child who could have match\n"
0802: + getFullName() + "\n" + name,
0803: new Throwable());
0804: }
0805: return null;
0806: } else {
0807: // no child could have it (even if we have children)
0808: // We'll see this whenever someone asks component "foo.bar" for "foo.bar.baz" property
0809: // which doesn't exist.
0810: //if (log.isErrorEnabled())
0811: //log.error("getProperty Error: No child could have match ("+nl+"<="+myl+")\n"+
0812: // getFullName()+"\n"+
0813: // name, new Throwable());
0814: return null;
0815: }
0816: } else {
0817: // inappropriate prefix - bail
0818: if (log.isErrorEnabled())
0819: log.error("getProperty Error: Inappropriate prefix\n"
0820: + getFullName() + "\n" + name, new Throwable());
0821: //Thread.dumpStack();
0822: return null;
0823: }
0824: } // end of getPropertyWorker
0825:
0826: /**
0827: * Gets a local property based on a <code>String</code> name.
0828: *
0829: * @param localName of the property
0830: * @return a <code>Property</code> object.
0831: */
0832: public Property getProperty(String localName) {
0833: return getProperty(new ComponentName(this , localName));
0834: }
0835:
0836: /**
0837: * Add a property with a given value. A new Property is created
0838: * having the given name and value. In addition the other fields of
0839: * the property set to default values consistent with the class of
0840: * the value.
0841: * @param name the name of the property
0842: * @param value must be one of the supported value types
0843: * @return the index of the new property
0844: **/
0845: public Property addProperty(String name, Object value) {
0846: if (value == null)
0847: throw new IllegalArgumentException("null value not allowed");
0848: return addProperty(name, value, value.getClass(), true);
0849: }
0850:
0851: /**
0852: * Add an invisible property to the component. Invisible properties
0853: * are property that act and behave just like a normal property but
0854: * are not visible to the GUI.
0855: *
0856: * @param name of the property
0857: * @param value of the propery
0858: * @return a <code>Property</code> object for the new Property
0859: */
0860: public Property addInvisibleProperty(String name, Object value) {
0861: if (value == null)
0862: throw new IllegalArgumentException("null value not allowed");
0863: return addProperty(name, value, value.getClass(), false);
0864: }
0865:
0866: /**
0867: * Adds a property to the component with a given name, value and class.
0868: *
0869: * @param name Name of the property
0870: * @param value Value of the property
0871: * @param cls Class of the property
0872: * @return a <code>Property</code> object for the new Property.
0873: */
0874: public Property addProperty(String name, Object value, Class cls) {
0875: return addProperty(name, value, cls, true);
0876: }
0877:
0878: /**
0879: * Adds an invisible property to the component with a given name, value and class.
0880: *
0881: * @param name Name of the property
0882: * @param value Value of the property
0883: * @param cls Class of the property
0884: * @return a <code>Property</code> object for the new Property.
0885: */
0886: public Property addInvisibleProperty(String name, Object value,
0887: Class cls) {
0888: return addProperty(name, value, cls, false);
0889: }
0890:
0891: /**
0892: * Adds a new Property to the Component.
0893: *
0894: * @param p <code>Property</code> to add.
0895: * @return a <code>Property</code> value
0896: */
0897: public Property addProperty(Property p) {
0898: return addProperty(p, true);
0899: }
0900:
0901: /**
0902: * Adds a new Invisible Property to the component.
0903: *
0904: * @param p <code/>Property</code> to add.
0905: * @return a <code/>Property</code> value
0906: */
0907: public Property addInvisibleProperty(Property p) {
0908: return addProperty(p, false);
0909: }
0910:
0911: /**
0912: * Adds a new Property with an attached PropertyListener
0913: *
0914: * @param name Name of the new Property
0915: * @param value Value of the new Property
0916: * @param l PropertyListener for this Property
0917: * @return a <code>Property</code> value
0918: */
0919: public Property addProperty(String name, Object value,
0920: PropertyListener l) {
0921: Property p = addProperty(name, value, value.getClass(), false);
0922: p.addPropertyListener(l);
0923: return p;
0924: }
0925:
0926: /**
0927: * Removes a Property from this component. The property must be
0928: * local to the component.
0929: *
0930: * @param prop Property to remove.
0931: */
0932: public void removeProperty(Property prop) {
0933: boolean wasVisible = isPropertyVisible(prop);
0934: // FIXME!!
0935: // Huh? So how do you remove an invisible property? Or is that not possible?
0936: if (!wasVisible)
0937: return; // if it's not visible, then it's not my property
0938: Object oldValue = getMyProperties().remove(prop.getName());
0939: if (oldValue == null) { // was someone else's property, ignore
0940: if (log.isErrorEnabled())
0941: log.error("", new Throwable(
0942: "Attempting to remove non-local property: "
0943: + prop.getName() + " from "
0944: + getFullName().toString()));
0945: return;
0946: }
0947: firePropertyRemoved(prop);
0948: }
0949:
0950: private Property addProperty(Property p, boolean visible) {
0951: if (p == null || p.getName() == null)
0952: return p;
0953:
0954: // Put in some debug stuff to see if this is ever called with a Property whose
0955: // name does not make sense in this component
0956: CompositeName name = p.getName();
0957: if (!name.startsWith(myName)) {
0958: if (log.isWarnEnabled())
0959: log.warn(
0960: "Adding property whose name makes no sense locally: "
0961: + getFullName() + ".addProperty("
0962: + name + ", visible=" + visible,
0963: new Throwable());
0964: }
0965:
0966: // remove old property if it exists
0967: Property oldProperty = (Property) getMyProperties().get(
0968: p.getName());
0969: if (oldProperty != null)
0970: removeProperty(oldProperty);
0971: getMyProperties().put(p.getName(), p);
0972: // if the new property is visible, tell the listeners
0973: if (visible)
0974: firePropertyAdded(p);
0975: return p;
0976: }
0977:
0978: private Property addProperty(String name, Object value, Class cls,
0979: boolean visible) {
0980: Property result = addProperty(
0981: new ConfigurableComponentProperty(this , name, value),
0982: visible);
0983: result.setPropertyClass(cls);
0984: return result;
0985: }
0986:
0987: /**
0988: * Gets an <code/>Iterator</code> of all visible properties Local to this component.
0989: *
0990: * @return an <code/>Iterator</code> of all local properties
0991: */
0992: public Iterator getLocalPropertyNames() {
0993: return new FilteredIterator(getPropertyNames(),
0994: localPropertyNamePredicate);
0995: }
0996:
0997: /**
0998: * Gets an <code/>Iterator</code> of all visible properties Local to this component, sorted.
0999: *
1000: * @return an <code/>Iterator</code> of all sorted local properties
1001: */
1002: public Iterator getSortedLocalPropertyNames() {
1003: ArrayList names = new ArrayList();
1004: Iterator iter = new FilteredIterator(getPropertyNames(),
1005: localPropertyNamePredicate);
1006:
1007: while (iter.hasNext()) {
1008: names.add(iter.next());
1009: }
1010:
1011: Collections.sort(names);
1012:
1013: return names.iterator();
1014:
1015: }
1016:
1017: /**
1018: * Test if a Property is local to this component. Local properties
1019: * have names beginning with the name of this component and have one
1020: * additional component.
1021: **/
1022: private UnaryPredicate localPropertyNamePredicate = new UnaryPredicate() {
1023: public boolean execute(Object o) {
1024: CompositeName pName = (CompositeName) o;
1025: CompositeName cName = getFullName();
1026: return pName.size() == cName.size() + 1
1027: && pName.startsWith(cName);
1028: }
1029: };
1030:
1031: // FIXME: Maybe add a version that does all properties, not just visible?
1032: // Follow the getPropertyWorker model above...
1033: /**
1034: * Gets an <code>Iterator</code> of all visible Property Names in (or under) this component.
1035: *
1036: * @return an <code>Iterator</code> value
1037: */
1038: public Iterator getPropertyNames() {
1039: return new Iterator() {
1040: // Note: getMyProperties _will_ return invisible properties
1041: Iterator currentIterator = getMyProperties().keySet()
1042: .iterator();
1043: int nextChildIndex = 0;
1044: CompositeName pendingName = null;
1045:
1046: // Track which component's properties we are looking at. Always starts with this
1047: ConfigurableComponent child = ConfigurableComponent.this ;
1048:
1049: public boolean hasNext() {
1050: while (pendingName == null) {
1051: // If done searching a given component
1052: while (!currentIterator.hasNext()) {
1053: // If don't have any more children to search
1054: if (nextChildIndex >= getChildCount()) {
1055: currentIterator = null; // drop ref to keyset, even if client keeps iterator around.
1056: return false;
1057: }
1058: // Get next child
1059: child = (ConfigurableComponent) getChild(nextChildIndex++);
1060: currentIterator = child.getPropertyNames();
1061: }
1062:
1063: // Try next property name in list
1064: pendingName = (CompositeName) currentIterator
1065: .next();
1066: try {
1067: if (child != null) {
1068: if (pendingName != null) {
1069: // Find the property in the child, regardless of its visibility
1070: if (child.getProperty(pendingName) == null) {
1071: // Since we're looking at the child from which we just got the name,
1072: // this is bad. Particulary since getProperty returns all properties,
1073: // not just visible ones
1074: if (log.isErrorEnabled())
1075: log
1076: .error(
1077: getFullName()
1078: + ".getPropertyNames: got null property for name "
1079: + pendingName
1080: + " off of child "
1081: + child
1082: .getFullName(),
1083: new Throwable());
1084:
1085: // Don't treat this as a valid property name to return
1086: pendingName = null;
1087: } else if (!((Property) child
1088: .getProperty(pendingName))
1089: .isVisible()) {
1090: // getProperty now returns all properties, so this is legitimate
1091:
1092: // if (log.isInfoEnabled())
1093: // log.info(getFullName() + ".getPropertyNames got invisible but not null property " + pendingName + " off of child " + child.getFullName());
1094:
1095: // Right here we decide: Does this method return both visible and
1096: // invisible property names?
1097: // To ignore invisible properties, we set pendingName to null
1098: // so the hasNext will return false if only invisible properties left
1099: // and next will never give it to you
1100: pendingName = null;
1101: }
1102: }
1103: } else {
1104: if (log.isErrorEnabled())
1105: log
1106: .error(getFullName()
1107: + ".getPropertyNames got null child at nextChildIndex "
1108: + nextChildIndex
1109: + " while looking for prop="
1110: + pendingName);
1111: } // end of block to ensure non-null child
1112: } catch (Exception e) {
1113: if (log.isErrorEnabled())
1114: log.error(
1115: "getPropertyNames: Exception while getting "
1116: + getFullName() + " prop="
1117: + pendingName
1118: + " and nextChildIndex: "
1119: + nextChildIndex, e);
1120: }
1121: } // end of while loop getting a non-null pendingName
1122: return true;
1123: }
1124:
1125: public Object next() {
1126: if (pendingName == null && !hasNext())
1127: throw new NoSuchElementException();
1128: Object result = pendingName;
1129: pendingName = null;
1130: return result;
1131: }
1132:
1133: public void remove() {
1134: throw new UnsupportedOperationException();
1135: }
1136: };
1137: }
1138:
1139: /**
1140: * Get iterator of all local properties (regardless of visibility)
1141: **/
1142: public Iterator getLocalProperties() {
1143: return getMyProperties().values().iterator();
1144: }
1145:
1146: // FIXME: Need a version for all properties? For invisible properties?
1147: /**
1148: * Return the properties in this component tree. Ignore invisible properties
1149: **/
1150: public Iterator getProperties() {
1151: return new Iterator() {
1152: Iterator currentIterator = getMyProperties().values()
1153: .iterator();
1154: int nextChildIndex = 0;
1155: Property pendingProp = null;
1156:
1157: public boolean hasNext() {
1158: while (pendingProp == null) {
1159: while (!currentIterator.hasNext()) {
1160: if (nextChildIndex >= getChildCount()) {
1161: return false;
1162: }
1163: currentIterator = ((ConfigurableComponent) getChild(nextChildIndex++))
1164: .getProperties();
1165: }
1166:
1167: Property nprop = (Property) currentIterator.next();
1168: // Right here is where we decide whether this iterator covers just visible
1169: // -- as in this case -- all, or just invisible properties
1170: if (!nprop.isVisible()) {
1171: pendingProp = null;
1172: } else {
1173: pendingProp = nprop;
1174: }
1175: }
1176: return true;
1177: }
1178:
1179: public Object next() {
1180: if (pendingProp == null && !hasNext())
1181: throw new NoSuchElementException();
1182: Object result = pendingProp;
1183: pendingProp = null;
1184: return result;
1185: }
1186:
1187: public void remove() {
1188: throw new UnsupportedOperationException();
1189: }
1190: };
1191: }
1192:
1193: /**
1194: * Return all properties in this tree, regardless of visibility
1195: **/
1196: public Iterator getAllProperties() {
1197: return new Iterator() {
1198: Iterator currentIterator = getMyProperties().values()
1199: .iterator();
1200: int nextChildIndex = 0;
1201: Property pendingProp = null;
1202:
1203: public boolean hasNext() {
1204: while (pendingProp == null) {
1205: while (!currentIterator.hasNext()) {
1206: if (nextChildIndex >= getChildCount()) {
1207: return false;
1208: }
1209: currentIterator = ((ConfigurableComponent) getChild(nextChildIndex++))
1210: .getProperties();
1211: }
1212:
1213: pendingProp = (Property) currentIterator.next();
1214: }
1215: return true;
1216: }
1217:
1218: public Object next() {
1219: if (pendingProp == null && !hasNext())
1220: throw new NoSuchElementException();
1221: Object result = pendingProp;
1222: pendingProp = null;
1223: return result;
1224: }
1225:
1226: public void remove() {
1227: throw new UnsupportedOperationException();
1228: }
1229: };
1230: }
1231:
1232: /**
1233: * Block the propagation of a child property. Such properties are
1234: * typically set by the parent component and should not be visible
1235: * from above.
1236: **/
1237: public void setPropertyVisible(Property prop, boolean newVisible) {
1238: CompositeName name = prop.getName();
1239: Property p = null;
1240: if (newVisible) {
1241: p = (Property) getMyProperties().get(name);
1242: // Property may not exist in map yet.
1243: if (p != null) {
1244: if (!p.isVisible())
1245: firePropertyAdded(prop);
1246: }
1247: } else {
1248: p = (Property) getMyProperties().get(name);
1249: if (p != null) {
1250: if (p.isVisible())
1251: firePropertyRemoved(prop);
1252: }
1253: }
1254: if (p != null) {
1255: p.setVisible(newVisible);
1256: getMyProperties().put(name, p);
1257: }
1258: }
1259:
1260: /**
1261: * Determines if the specified property is visible as a local property.
1262: * If a property is not visible, it cannot be seen in the GUI.
1263: *
1264: * @param prop Property to check visiblity
1265: * @return a <code>boolean</code> value
1266: */
1267: public boolean isPropertyVisible(Property prop) {
1268: Property p = (Property) getMyProperties().get(prop.getName());
1269: // If the society is fresh from the db, props don't exist in map yet.
1270: if (p == null)
1271: return false;
1272: return p.isVisible();
1273: }
1274:
1275: /**
1276: * Gets a <code/>List</code> of all visible Properties in this component.
1277: *
1278: * @return a <code/>List</code> value
1279: */
1280: public List getPropertyNamesList() {
1281: List props = new ArrayList();
1282: for (Iterator i = getPropertyNames(); i.hasNext();) {
1283: CompositeName name = (CompositeName) i.next();
1284: props.add(name);
1285: }
1286: return props;
1287: }
1288:
1289: /**
1290: * Copies a BaseComponent Object
1291: *
1292: * @param result Object to copy
1293: * @return a <code/>BaseComponent</code> value
1294: */
1295: public BaseComponent copy(BaseComponent result) {
1296: if (result == null) {
1297: log.error("Null target component copying from "
1298: + this .getFullName().toString(), new Throwable());
1299: return null;
1300: }
1301: // Make sure we're copying apples into apples
1302: // The result can be a sub-class, but we want it
1303: // to at least have the same set of properties
1304: if (!(this .getClass().isAssignableFrom(result.getClass())))
1305: return null;
1306: Iterator iter = getSortedLocalPropertyNames();
1307: while (iter.hasNext()) {
1308: CompositeName name = (CompositeName) iter.next();
1309: Property myProp = getProperty(name);
1310: if (myProp == null) {
1311: // Try to get invisible Property. -- but note that
1312: // invisible properties are also returned by getProperty
1313: // so we should never get in here
1314: myProp = getInvisibleProperty(name);
1315: if (myProp == null) {
1316: if (log.isErrorEnabled()) {
1317: log.error("Null property " + name.toString()
1318: + " copying from "
1319: + this .getFullName().toString(),
1320: new Throwable());
1321: }
1322: continue;
1323: }
1324: }
1325: // compose the correct name for the property
1326: // name must be prepended by new society name
1327: String s = name.last().toString();
1328: ComponentName hisPropName = new ComponentName(result, s);
1329: Property hisProp = result.getProperty(hisPropName);
1330:
1331: // Note that this InvisibleProperty call should not help, since getProperty should
1332: // return both visible and invisible properties
1333: if (hisProp == null
1334: && ((hisProp = result
1335: .getInvisibleProperty(hisPropName)) == null)) {
1336: if (log.isErrorEnabled()) {
1337: log.error("Report bug 1377: Using "
1338: + CSMART.writeDebug() + " couldn't find "
1339: + hisPropName.toString() + " in "
1340: + result.getFullName().toString()
1341: + " copying from " + name.toString()
1342: + " in " + this .getFullName().toString(),
1343: new Throwable());
1344: }
1345: } else {
1346: try {
1347: Object o = PropertyHelper.validateValue(myProp,
1348: myProp.getValue());
1349: if (o != null) {
1350: hisProp.setValue(o);
1351: }
1352: } catch (InvalidPropertyValueException e) {
1353: if (log.isErrorEnabled()) {
1354: log.error(
1355: "Caught InvalidPropertyValueException: "
1356: + getClass().getName(), e);
1357: }
1358: }
1359: } // end of else block
1360: } // end of loop over properties
1361:
1362: // Now, clone my children
1363: for (int i = 0; i < getChildCount(); i++) {
1364: ConfigurableComponent cc = (ConfigurableComponent) getChild(i);
1365: BaseComponent co = (BaseComponent) result.getChild(cc
1366: .getFullName().last());
1367: if (co != null) {
1368: cc.copy(co);
1369: }
1370: }
1371:
1372: return result;
1373: }
1374:
1375: private void writeObject(ObjectOutputStream stream)
1376: throws IOException {
1377: stream.defaultWriteObject();
1378: stream.writeObject(parent);
1379: stream.writeObject(children);
1380: Map properties = getMyProperties();
1381:
1382: // write in new format - old format is below in comment
1383: {
1384: int n = (-1) - properties.size(); // signal new format
1385: stream.writeInt(n);
1386: for (Iterator i = properties.values().iterator(); i
1387: .hasNext();) {
1388: stream.writeObject(i.next());
1389: }
1390: }
1391:
1392: /*
1393: // old format
1394: stream.writeInt(properties.size());
1395: for (Iterator i = properties.entrySet().iterator(); i.hasNext(); ) {
1396: PropertyEntry entry = new PropertyEntry((Map.Entry)i.next());
1397: stream.writeObject(entry);
1398: }
1399: */
1400:
1401: stream.writeObject(getSerializableListeners());
1402: }
1403:
1404: private List getSerializableListeners() {
1405: List result = new ArrayList();
1406: Object[] lll = getEventListenerList().getListenerList();
1407: for (int i = 0; i < lll.length; i += 2) {
1408: Class cls = (Class) lll[i];
1409: EventListener l = (EventListener) lll[i + 1];
1410: if (l instanceof ConfigurableComponentListener) {
1411: result.add(cls);
1412: result.add(l);
1413: }
1414: }
1415: return result;
1416: }
1417:
1418: private void readObject(ObjectInputStream stream)
1419: throws IOException, ClassNotFoundException {
1420: myProperties = new HashMap(1);
1421: stream.defaultReadObject();
1422: parent = (ComposableComponent) stream.readObject();
1423: children = (List) stream.readObject();
1424: int n = stream.readInt();
1425: if (n >= 0) {
1426: // old, big format - this should be dumped.
1427: myProperties = new HashMap(1 + n * 4);
1428: for (int i = 0; i < n; i++) {
1429: PropertyEntry entry = (PropertyEntry) stream
1430: .readObject();
1431: Property p = (Property) entry.getValue();
1432: myProperties.put(p.getName(), p);
1433: }
1434: } else {
1435: // new format - we should cut over and simplify
1436: n = (-1) - n;
1437: myProperties = new HashMap(1 + n * 4);
1438: for (int i = 0; i < n; i++) {
1439: Property p = (Property) stream.readObject();
1440: myProperties.put(p.getName(), p);
1441: }
1442: }
1443: setSerializableListeners((List) stream.readObject());
1444: createLogger();
1445: }
1446:
1447: public ComponentData addComponentData(ComponentData data) {
1448: return data;
1449: }
1450:
1451: public ComponentData modifyComponentData(ComponentData data) {
1452: return data;
1453: }
1454:
1455: /**
1456: * Default implementation of new form of modifyComponentData invokes
1457: * the old form without the pdb argument
1458: **/
1459: public ComponentData modifyComponentData(ComponentData data,
1460: PopulateDb pdb) {
1461: return modifyComponentData(data);
1462: }
1463:
1464: public boolean componentWasRemoved() {
1465: return false;
1466: }
1467:
1468: // Note this only checks visible properties
1469: public boolean hasUnboundProperties() {
1470: for (Iterator i = getPropertyNames(); i.hasNext();) {
1471: Property prop = (Property) getProperty((CompositeName) i
1472: .next());
1473: if (prop != null) {
1474: if (!prop.isValueSet())
1475: return true;
1476: }
1477: }
1478: return false;
1479: }
1480:
1481: private void setSerializableListeners(List l) {
1482: EventListenerList ll = getEventListenerList();
1483: for (Iterator i = l.iterator(); i.hasNext();) {
1484: Class cls = (Class) i.next();
1485: EventListener listener = (EventListener) i.next();
1486: ll.add(cls, listener);
1487: }
1488: }
1489:
1490: /**
1491: * Dumps a list of the Local Properties
1492: *
1493: * @param out Stream to dump properties to.
1494: */
1495: public void printLocalProperties(PrintStream out) {
1496: printLocalProperties(out, "");
1497: }
1498:
1499: /**
1500: * Prints a list of local properties.
1501: *
1502: * @param out Stream to print properties to.
1503: * @param indent Indentation before each output string.
1504: */
1505: public void printLocalProperties(PrintStream out, String indent) {
1506: List props = new ArrayList();
1507: for (Iterator iterator = getLocalPropertyNames(); iterator
1508: .hasNext();)
1509: props.add(iterator.next());
1510: printProperties(out, indent, props);
1511: }
1512:
1513: /**
1514: * Prints all visible Properties for this component.
1515: *
1516: * @param out Stream to print to.
1517: */
1518: public void printAllProperties(PrintStream out) {
1519: printAllProperties(out, "");
1520: }
1521:
1522: /**
1523: * Prints all visible Properties for this component.
1524: *
1525: * @param out Stream to print to.
1526: * @param indent Indentation amount before each output line.
1527: */
1528: public void printAllProperties(PrintStream out, String indent) {
1529: printProperties(out, "", getPropertyNamesList());
1530: }
1531:
1532: /**
1533: * Prints a specific list of Properties.
1534: *
1535: * @param out Stream to output to.
1536: * @param indent About to indent output.
1537: * @param props List of Properties to list.
1538: */
1539: private void printProperties(PrintStream out, String indent,
1540: List props) {
1541: int n = props.size();
1542: out.println(indent + "Number of properties: " + n);
1543: out.println(indent + "=======================================");
1544: for (int i = 0; i < n; i++) {
1545: CompositeName name = (CompositeName) props.get(i);
1546: out.println(indent + "Property name: " + name);
1547: getProperty(name).printProperty(out, indent);
1548: out.println(indent
1549: + "=======================================");
1550: }
1551: }
1552:
1553: static class PropertyEntry implements Map.Entry, Serializable {
1554: Object key;
1555: Object value;
1556:
1557: public PropertyEntry(Map.Entry me) {
1558: key = me.getKey();
1559: value = me.getValue();
1560: }
1561:
1562: public Object getKey() {
1563: return key;
1564: }
1565:
1566: public Object getValue() {
1567: return value;
1568: }
1569:
1570: public Object setValue(Object o) {
1571: Object result = value;
1572: value = o;
1573: return result;
1574: }
1575: }
1576:
1577: // Note: ConfigurableComponent has no .equals method. Should it?
1578:
1579: public String toString() {
1580: return getShortName();
1581: }
1582: } // end of ConfigurableComponent
|