001    package data;
002    
003    import java.beans.PropertyChangeListener;
004    import java.beans.PropertyChangeSupport;
005    
006    /**
007     * Convenience class implementing the Nameable interface.
008     *
009     * <p>You should derive all your Nameable classes from this class, as it provides a
010     * complete implementation of the {@link Nameable} interface. However, there is no
011     * obligation to derive from this class, as long as your class implements Nameable and
012     * sticks to the contract defined in that interface.</p>
013     *
014     * @author Steffen Zschaler
015     * @version 2.0 25/05/1999
016     * @since v2.0
017     */
018    public abstract class AbstractNameable extends Object implements Nameable {
019    
020        /**
021         * Used to fire {@link java.beans.PropertyChangeEvent PropertyChangeEvents}.
022         *
023         * @serial
024         */
025        protected PropertyChangeSupport m_pcsPropertyListeners = new PropertyChangeSupport(this);
026    
027        /**
028         * The name of this object.
029         *
030         * @serial
031         */
032        private String m_sName;
033    
034        /**
035         * The current name context.
036         *
037         * @serial
038         */
039        protected NameContext m_ncContext;
040    
041        /**
042         * The monitor synchronizing access to the NameContext.
043         */
044        private transient Object m_oNCLock;
045    
046        /**
047         * Return the monitor synchronizing access to the NameContext.
048         *
049         * @override Never
050         */
051        private final Object getNCLock() {
052            if (m_oNCLock == null) {
053                m_oNCLock = new Object();
054            }
055    
056            return m_oNCLock;
057        }
058    
059        /**
060         * Initialize a new AbstractNameable object with a <code>null</code> name.
061         */
062        public AbstractNameable() {
063            this(null);
064        }
065    
066        /**
067         * Initialize a new AbstractNameable object with the given name. The name context will initially be
068         * <code>null</code>.
069         *
070         * @param sName the AbstractNameable's name.
071         */
072        public AbstractNameable(String sName) {
073            super();
074    
075            m_sName = sName;
076            m_ncContext = null;
077        }
078    
079        /**
080         * Attach a NameContext to this Nameable.
081         *
082         * <p>No naming conventions are checked neither in the old nor in the new NameContext.</p>
083         *
084         * <p>All access to the NameContext is synchronized for thread-safety.</p>
085         *
086         * @param nc the new NameContext of this Nameable object.
087         *
088         * @return the previous NameContext, if any.
089         *
090         * @override Never
091         */
092        public NameContext attach(NameContext nc) {
093            synchronized (getNCLock()) {
094                NameContext ncOld = m_ncContext;
095    
096                m_ncContext = nc;
097    
098                return ncOld;
099            }
100        }
101    
102        /**
103         * Detach the current NameContext from this Nameable.
104         *
105         * <p>All access to the NameContext is synchronized for thread-safety.</p>
106         *
107         * @return the previously attached NameContext, if any.
108         *
109         * @override Never
110         */
111        public NameContext detachNC() {
112            return attach((NameContext)null);
113        }
114    
115        /**
116         * Set the Nameable's name, using help by the NameContext.
117         *
118         * <p>All access to the NameContext is synchronized for thread-safety.</p>
119         *
120         * @param sName the new name of the object
121         * @param db the DataBasket relative to which the name change is to take place.
122         *
123         * @exception NameContextException if the name change was not approved of by the
124         * NameContext.
125         *
126         * @override Never
127         */
128        public void setName(String sName, DataBasket db) throws NameContextException {
129            synchronized (getNCLock()) {
130                String sOld = m_sName;
131    
132                if (m_ncContext != null) {
133                    synchronized (m_ncContext.getNCMonitor()) {
134    
135                        m_ncContext.checkNameChange(db, sOld, sName);
136    
137                        m_sName = sName;
138    
139                        m_ncContext.nameHasChanged(db, sOld, sName);
140                    }
141                } else {
142                    m_sName = sName;
143                }
144    
145                m_pcsPropertyListeners.firePropertyChange(NAME_PROPERTY, sOld, sName);
146            }
147        }
148    
149        /**
150         * Get the name of the object.
151         *
152         * override Never
153         */
154        public String getName() {
155            return m_sName;
156        }
157    
158        /**
159         * Add a PropertyChangeListener that will receive events whenever a bound property changes.
160         *
161         * @override Never
162         */
163        public void addPropertyChangeListener(PropertyChangeListener pcl) {
164            m_pcsPropertyListeners.addPropertyChangeListener(pcl);
165        }
166    
167        /**
168         * Remove a PropertyChangeListener.
169         *
170         * @override Never
171         */
172        public void removePropertyChangeListener(PropertyChangeListener pcl) {
173            m_pcsPropertyListeners.addPropertyChangeListener(pcl);
174        }
175    
176        /**
177         * Add a PropertyChangeListener that will receive events whenever the "name" property changes.
178         *
179         * @override Never
180         */
181        public void addNameListener(PropertyChangeListener pcl) {
182            m_pcsPropertyListeners.addPropertyChangeListener(NAME_PROPERTY, pcl);
183        }
184    
185        /**
186         * Remove a PropertyChangeListener for the "name" property.
187         *
188         * @override Never
189         */
190        public void removeNameListener(PropertyChangeListener pcl) {
191            m_pcsPropertyListeners.removePropertyChangeListener(NAME_PROPERTY, pcl);
192        }
193    }