001    /* java.beans.beancontext.BeanContextChildSupport
002       Copyright (C) 1999 Free Software Foundation, Inc.
003    
004    This file is part of GNU Classpath.
005    
006    GNU Classpath is free software; you can redistribute it and/or modify
007    it under the terms of the GNU General Public License as published by
008    the Free Software Foundation; either version 2, or (at your option)
009    any later version.
010    
011    GNU Classpath is distributed in the hope that it will be useful, but
012    WITHOUT ANY WARRANTY; without even the implied warranty of
013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014    General Public License for more details.
015    
016    You should have received a copy of the GNU General Public License
017    along with GNU Classpath; see the file COPYING.  If not, write to the
018    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019    02110-1301 USA.
020    
021    Linking this library statically or dynamically with other modules is
022    making a combined work based on this library.  Thus, the terms and
023    conditions of the GNU General Public License cover the whole
024    combination.
025    
026    As a special exception, the copyright holders of this library give you
027    permission to link this library with independent modules to produce an
028    executable, regardless of the license terms of these independent
029    modules, and to copy and distribute the resulting executable under
030    terms of your choice, provided that you also meet, for each linked
031    independent module, the terms and conditions of the license of that
032    module.  An independent module is a module which is not derived from
033    or based on this library.  If you modify this library, you may extend
034    this exception to your version of the library, but you are not
035    obligated to do so.  If you do not wish to do so, delete this
036    exception statement from your version. */
037    
038    
039    package java.beans.beancontext;
040    
041    import java.beans.PropertyChangeEvent;
042    import java.beans.PropertyChangeListener;
043    import java.beans.PropertyChangeSupport;
044    import java.beans.PropertyVetoException;
045    import java.beans.VetoableChangeListener;
046    import java.beans.VetoableChangeSupport;
047    import java.io.Serializable;
048    
049    /**
050     * Support for creating a <code>BeanContextChild</code>.
051     * This class contains the most common implementations of the methods in
052     * the <code>BeanContextChild</code>
053     *
054     * @specnote This class is not very well specified.  I had to "fill in the
055     *           blanks" in most places with what I thought was reasonable
056     *           behavior.  If there are problems, let me know.
057     *
058     * @author John Keiser
059     * @since 1.2
060     * @see java.beans.beancontext.BeanContextChild
061     */
062    public class BeanContextChildSupport
063      implements BeanContextChild, BeanContextServicesListener, Serializable
064    {
065      static final long serialVersionUID = 6328947014421475877L;
066    
067            /**
068             * The peer on which to perform <code>set</code> actions.
069             * This is here so that this class can be used as a peer.
070             * <P>
071             *
072             * When extending this class, this variable will be set to
073             * <code>this</code>.
074             */
075            public BeanContextChild beanContextChildPeer;
076    
077            /**
078             * The parent <code>BeanContext</code>.
079             */
080            protected transient BeanContext beanContext;
081    
082            /**
083             * If <code>setBeanContext()</code> was vetoed once before, this
084             * is set to <code>true</code> so that the next time, vetoes will
085             * be ignored.
086             */
087            protected transient boolean rejectedSetBCOnce;
088    
089            /**
090             * Listeners are registered here and events are fired through here.
091             */
092            protected PropertyChangeSupport pcSupport;
093    
094            /**
095             * Listeners are registered here and events are fired through here.
096             */
097            protected VetoableChangeSupport vcSupport;
098    
099            /**
100             * Create a new <code>BeanContextChildSupport</code> with itself as the peer.
101             * This is meant to be used when you subclass
102             * <code>BeanContextChildSupport</code> to create your child.
103             */
104            public BeanContextChildSupport()
105      {
106                    this (null);
107            }
108    
109            /**
110             * Create a new <code>BeanContextChildSupport</code> with the specified peer.
111             * @param peer the peer to use, or <code>null</code> to specify
112             *        <code>this</code>.
113             */
114            public BeanContextChildSupport (BeanContextChild peer)
115      {
116                    if (peer == null)
117          {
118            peer = this;
119          }
120    
121                    beanContextChildPeer = peer;
122                    pcSupport = new PropertyChangeSupport (peer);
123                    vcSupport = new VetoableChangeSupport (peer);
124            }
125    
126            /**
127             * Set the parent <code>BeanContext</code>.
128             * <P>
129             *
130             * When this Object is being added to a new BeanContext or moved
131             * from an old one, a non-null value will be passed in.
132             * <P>
133             *
134             * When this Object is being removed from the current
135             * <code>BeanContext</code>, <code>setBeanContext()</code> will
136             * receive the parameter <code>null</code>.
137             * <P>
138             *
139             * Order of events:
140             * <OL>
141             *   <LI>
142             *     If the new <code>BeanContext</code> is the same as the old
143             *     one, nothing happens.
144             *   </LI>
145             *   <LI>
146             *     If the change has not been rejected or vetoed before, call
147             *     <code>validatePendingSetBeanContext()</code>.  If this call
148             *     returns <code>false</code>, the change is rejected and a
149             *     <code>PropertyVetoException</code> is thrown.
150             *   </LI>
151             *   <LI>
152             *     If the change has not been rejected or vetoed before,
153             *     <code>VetoableChangeEvent</code>s are fired with the name
154             *     <code>"beanContext"</code>, using the
155             *     <code>fireVetoableChange()</code> method.  If a veto
156             *     occurs, reversion events are fired using the same method,
157             *     the change is rejected, and the veto is rethrown.
158             *   </LI>
159             *   <LI>
160             *     <code>releaseBeanContextResources()</code> is called.
161             *   </LI>
162             *   <LI>
163             *     The change is made.
164             *   </LI>
165             *   <LI>
166             *     <code>PropertyChangeEvent</code>s are fired using the
167             *     <code>firePropertyChange()</code> method.
168             *   </LI>
169             *   <LI>
170             *     <code>initializeBeanContextResources()</code> is called.
171             *   </LI>
172             * </OL>
173             * <P>
174             *
175             * @param newBeanContext the new parent for the
176             *        <code>BeanContextChild</code>, or <code>null</code> to
177             *        signify removal from a tree.
178             * @exception PropertyVetoException if the
179             *            <code>BeanContextChild</code> implementor does not
180             *            wish to have its parent changed.
181             */
182      public void setBeanContext(BeanContext newBeanContext)
183        throws PropertyVetoException
184      {
185        synchronized (beanContextChildPeer)
186          {
187            if (newBeanContext == beanContext)
188              return;
189    
190            if (!rejectedSetBCOnce)
191              {
192                if (!validatePendingSetBeanContext (newBeanContext))
193                  {
194                    rejectedSetBCOnce = true;
195                    throw new PropertyVetoException ("validatePendingSetBeanContext() rejected change",
196                                                     new PropertyChangeEvent(beanContextChildPeer, "beanContext", beanContext, newBeanContext));
197                  }
198    
199                try
200                  {
201                    fireVetoableChange ("beanContext", beanContext, newBeanContext);
202                  }
203                catch (PropertyVetoException e)
204                  {
205                    rejectedSetBCOnce = true;
206                    throw e;
207                  }
208              }
209    
210                            releaseBeanContextResources ();
211    
212                            beanContext = newBeanContext;
213                            rejectedSetBCOnce = false;
214    
215                            firePropertyChange ("beanContext", beanContext, newBeanContext);
216    
217                            initializeBeanContextResources ();
218                    }
219            }
220    
221            /**
222             * Get the parent <code>BeanContext</code>.
223             * @return the parent <code>BeanContext</code>.
224             */
225            public BeanContext getBeanContext()
226      {
227                    return beanContext;
228            }
229    
230            /**
231             * Get the peer (or <code>this</code> if there is no peer).
232             * @return the peer, or <code>this</code> if there is no peer.
233             */
234            public BeanContextChild getBeanContextChildPeer() {
235                    return beanContextChildPeer;
236            }
237    
238            /**
239             * Determine whether there is a peer.
240             * This is true iff <code>getBeanContextChildPeer() == this</code>.
241             * @return whether there is a peer.
242             */
243            public boolean isDelegated() {
244                    return beanContextChildPeer == this;
245            }
246    
247            /**
248             * Add a listener that will be notified when a specific property changes.
249             * @param propertyName the name of the property to listen on.
250             * @param listener the listener to listen on the property.
251             */
252            public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
253                    pcSupport.addPropertyChangeListener(propertyName, listener);
254            }
255    
256            /**
257             * Remove a listener to a certain property.
258             *
259             * @param propertyName the name of the property being listened on.
260             * @param listener the listener listening on the property.
261             */
262            public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) {
263                    pcSupport.removePropertyChangeListener(propertyName, listener);
264            }
265    
266            /**
267             * Add a listener that will be notified when a specific property
268             * change is requested (a PropertyVetoException may be thrown) as
269             * well as after the change is successfully made.
270             *
271             * @param propertyName the name of the property to listen on.
272             * @param listener the listener to listen on the property.
273             */
274            public void addVetoableChangeListener(String propertyName, VetoableChangeListener listener) {
275                    vcSupport.addVetoableChangeListener(propertyName, listener);
276            }
277    
278            /**
279             * Remove a listener to a certain property.
280             *
281             * @param propertyName the name of the property being listened on
282             * @param listener the listener listening on the property.
283             */
284            public void removeVetoableChangeListener(String propertyName, VetoableChangeListener listener) {
285                    vcSupport.removeVetoableChangeListener(propertyName, listener);
286            }
287    
288            /**
289             * Fire a property change.
290             *
291             * @param propertyName the name of the property that changed
292             * @param oldVal the old value of the property
293             * @param newVal the new value of the property
294             */
295            public void firePropertyChange(String propertyName, Object oldVal, Object newVal) {
296                    pcSupport.firePropertyChange(propertyName, oldVal, newVal);
297            }
298    
299            /**
300             * Fire a vetoable property change.
301             *
302             * @param propertyName the name of the property that changed
303             * @param oldVal the old value of the property
304             * @param newVal the new value of the property
305             * @exception PropertyVetoException if the change is vetoed.
306             */
307            public void fireVetoableChange(String propertyName, Object oldVal, Object newVal)
308                            throws PropertyVetoException {
309                    vcSupport.fireVetoableChange(propertyName, oldVal, newVal);
310            }
311    
312            /**
313             * Called by <code>BeanContextServices.revokeService()</code> to indicate that a service has been revoked.
314             * If you have a reference to such a service, it should be
315             * discarded and may no longer function properly.
316             * <code>getService()</code> will no longer work on the specified
317             * service class after this event has been fired.
318             * <P>
319             *
320             * <EM>This method is meant to be overriden.</EM>
321             * <code>BeanContextChildSupport</code>'s implementation does
322             * nothing.
323             *
324             * @param event the service revoked event.
325             * @see java.beans.beancontext.BeanContextServices#revokeService(java.lang.Class,java.beans.beancontext.BeanContextServiceProvider,boolean)
326             */
327            public void serviceRevoked(BeanContextServiceRevokedEvent event) {
328            }
329    
330            /**
331             * Called by <code>BeanContextServices</code> whenever a service is made available.
332             * <P>
333             *
334             * <EM>This method is meant to be overriden.</EM>
335             * <code>BeanContextChildSupport</code>'s implementation does
336             * nothing.
337             *
338             * @param event the service revoked event, with useful information
339             *        about the new service.
340             */
341            public void serviceAvailable(BeanContextServiceAvailableEvent event) {
342            }
343    
344            /**
345             * Called by <code>setBeanContext()</code> to determine whether the set should be rejected.
346             * <P>
347             *
348             * <EM>This method is meant to be overriden.</EM>
349             * <code>BeanContextChildSupport</code>'s implementation simply
350             * returns <code>true</code>.
351             *
352             * @param newBeanContext the new parent.
353             * @return whether to allow the parent to be changed to the new
354             *         value.
355             */
356            public boolean validatePendingSetBeanContext(BeanContext newBeanContext) {
357                    return true;
358            }
359    
360            /**
361             * Called by <code>setBeanContext()</code> to release resources of a what will soon no longer be the parent.
362             * <P>
363             *
364             * <EM>This method is meant to be overriden.</EM>
365             * <code>BeanContextChildSupport</code>'s implementation does
366             * nothing.
367             */
368            protected void releaseBeanContextResources() {
369            }
370    
371            /**
372             * Called by <code>setBeanContext()</code> to grab resources when the parent has been set.
373             * <P>
374             *
375             * <EM>This method is meant to be overriden.</EM>
376             * <code>BeanContextChildSupport</code>'s implementation does
377             * nothing.
378             */
379            protected void initializeBeanContextResources() {
380            }
381    }