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 }