Source Code Cross Referenced for ConfigurableComponent.java in  » Science » Cougaar12_4 » org » cougaar » tools » csmart » core » property » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Science » Cougaar12_4 » org.cougaar.tools.csmart.core.property 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


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
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.