KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > beehive > controls > runtime > bean > ControlBeanContext


1 package org.apache.beehive.controls.runtime.bean;
2 /*
3  * Copyright 2004 The Apache Software Foundation.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  * $Header:$
18  */

19
20 import java.lang.annotation.Annotation JavaDoc;
21 import java.lang.reflect.AnnotatedElement JavaDoc;
22 import java.lang.reflect.Field JavaDoc;
23 import java.lang.reflect.Method JavaDoc;
24 import java.beans.PropertyChangeEvent JavaDoc;
25 import java.beans.PropertyVetoException JavaDoc;
26 import java.beans.beancontext.BeanContext JavaDoc;
27 import java.beans.beancontext.BeanContextServiceRevokedEvent JavaDoc;
28 import java.beans.beancontext.BeanContextServiceRevokedListener JavaDoc;
29 import java.beans.beancontext.BeanContextServiceProvider JavaDoc;
30 import java.beans.beancontext.BeanContextServices JavaDoc;
31 import java.beans.beancontext.BeanContextServicesSupport JavaDoc;
32 import java.util.*;
33 import java.io.InputStream JavaDoc;
34 import java.io.InputStreamReader JavaDoc;
35 import java.io.BufferedReader JavaDoc;
36 import java.io.IOException JavaDoc;
37
38 import org.apache.beehive.controls.api.ControlException;
39 import org.apache.beehive.controls.api.bean.ControlInterface;
40 import org.apache.beehive.controls.api.context.ControlHandle;
41 import org.apache.beehive.controls.api.properties.AnnotatedElementMap;
42 import org.apache.beehive.controls.api.properties.BeanPropertyMap;
43 import org.apache.beehive.controls.api.properties.PropertyMap;
44 import org.apache.beehive.controls.api.properties.PropertySet;
45 import org.apache.beehive.controls.api.properties.PropertySetProxy;
46
47 /**
48  * The ControlBeanContext implements the basic BeanContextServices implementation
49  * for ControlBeans.
50  *
51  * It provides several basic functions:
52  * - it defines the generic services that are available for all control containers
53  * - it acts as the base class for other container service implementations
54  * - it acts as the BeanContextServicesRevokedListener when an associated control
55  * bean has lost access to services.
56  */

57 public class ControlBeanContext
58              extends BeanContextServicesSupport JavaDoc
59              implements BeanContextServiceRevokedListener JavaDoc,
60                         org.apache.beehive.controls.api.context.ControlBeanContext,
61                         java.beans.PropertyChangeListener JavaDoc,
62                         java.beans.VetoableChangeListener JavaDoc
63 {
64     /**
65      * Creates a new ControlBeanContext instance associated with a specific
66      * control bean.
67      *
68      * @param bean The control bean that contains/scopes the ControlBeanContext. If null,
69                    it means the ControlBeanContext is for a top-level container.
70      */

71     protected ControlBeanContext(ControlBean bean)
72     {
73         _bean = bean;
74     }
75
76     /**
77      * The ControlBeanContextProvider inner class acts as a single BeanContext service
78      * provider for the ControlBeanContext service class. The implementation is simple,
79      * because the runtime ControlBeanContext implementation class directly implements
80      * this interface.
81      */

82     private static class ControlBeanContextProvider implements BeanContextServiceProvider JavaDoc
83     {
84         //
85
// BeanContextServiceProvider.getService()
86
//
87
public Object JavaDoc getService(BeanContextServices JavaDoc bcs, Object JavaDoc requestor, Class JavaDoc serviceClass,
88                                  Object JavaDoc serviceSelector)
89         {
90             //
91
// Contextual services for a ControlBean is provided by the peer context
92
// instance.
93
//
94
if (requestor instanceof ControlBean)
95                 return ((ControlBean)requestor).getControlBeanContext();
96
97             return null;
98         }
99
100         //
101
// BeanContextServiceProvider.releaseService()
102
//
103
public void releaseService(BeanContextServices JavaDoc bcs, Object JavaDoc requestor, Object JavaDoc service)
104         {
105             // noop, because context exists whether referenced or not
106
}
107
108         //
109
// BeanContextServiceProvider.getContextServiceSelectors()
110
//
111
public Iterator getCurrentServiceSelectors(BeanContextServices JavaDoc bcs, Class JavaDoc serviceClass)
112         {
113             return null; // no selectors
114
}
115     }
116
117     /**
118      * A singleton instance of the ControlBeanContextProvider class is that will be registered
119      * on all ControlBeanContext instances. The provider can be a singleton because it is
120      * completely stateless and thread-safe.
121      */

122     static private ControlBeanContextProvider theProvider = new ControlBeanContextProvider();
123
124     /**
125      * Called by BeanContextSupport superclass during construction and deserialization to
126      * initialize subclass transient state
127      */

128     public void initialize()
129     {
130         super.initialize();
131
132         //
133
// Register the ControlBeanContext provider on all new context instances.
134
//
135
addService(org.apache.beehive.controls.api.context.ControlBeanContext.class, theProvider);
136     }
137
138     /**
139      * Implements the BeanContextServicesRevokedListener.servicesRevoked method. This is
140      * called if the associated ControlBean has requested a service that is being subsequently
141      * revoked.
142      */

143     public void serviceRevoked(BeanContextServiceRevokedEvent JavaDoc bcsre)
144     {
145         //
146
// This can happen, if the control is disassociated from a parent context that is
147
// providing services.
148
//
149
}
150
151     /**
152      * Overrides the BeanContextChild.setBeanContext() method. This hook is used to perform
153      * additional processing that needs to occur when the control is associated with a new
154      * nesting context.
155      */

156     public synchronized void setBeanContext(BeanContext JavaDoc beanContext) throws PropertyVetoException JavaDoc
157     {
158         ControlBeanContext cbcs = null;
159
160         if (beanContext != null)
161         {
162             //
163
// ControlBeans can only be nested in context service instances that derive
164
// from ControlBeanContext.
165
//
166
if (!(beanContext instanceof ControlBeanContext))
167             {
168                 PropertyChangeEvent JavaDoc pce = new PropertyChangeEvent JavaDoc(_bean, "beanContext",
169                                                                   getBeanContext(), beanContext);
170                 throw new PropertyVetoException JavaDoc("Context does not support nesting controls: " +
171                                                 beanContext.getClass(), pce);
172             }
173
174             cbcs = (ControlBeanContext)beanContext;
175         }
176
177
178         super.setBeanContext(beanContext);
179
180         resetControlID();
181
182         _hasSingleThreadedParent = cbcs != null ? cbcs.isSingleThreadedContainer() : false;
183
184         //
185
// Notify the bean that its context (container) has been set.
186
//
187
if (_bean != null)
188             _bean.setBeanContext(beanContext);
189     }
190
191     /**
192      * The NameGenerator class is a simple helper class that creates new unique names based
193      * upon a base prefix and an incrementing counter
194      */

195     private static class NameGenerator implements java.io.Serializable JavaDoc
196     {
197         NameGenerator(String JavaDoc namePrefix)
198         {
199             _namePrefix = namePrefix;
200         }
201
202         /**
203          * Get the next unique name
204          */

205         public synchronized String JavaDoc next()
206         {
207             return _namePrefix + _nextIndex++;
208         }
209
210         int _nextIndex = 0;
211         String JavaDoc _namePrefix;
212     }
213
214     /**
215      * Returns a new NameGenerator instance based upon a particular naming
216      * prefix.
217      */

218     private NameGenerator getNameGenerator(String JavaDoc namePrefix)
219     {
220         synchronized(this)
221         {
222             if (_nameGenerators == null)
223                 _nameGenerators = new HashMap<String JavaDoc,NameGenerator>();
224
225             NameGenerator nameGenerator = (NameGenerator)_nameGenerators.get(namePrefix);
226             if (nameGenerator == null)
227             {
228                 nameGenerator = new NameGenerator(namePrefix);
229                 _nameGenerators.put(namePrefix, nameGenerator);
230             }
231             return nameGenerator;
232         }
233     }
234
235     /**
236      * Generates a new unique control ID for an instance of the target class
237      */

238     public String JavaDoc generateUniqueID(Class JavaDoc clazz)
239     {
240         String JavaDoc namePrefix = clazz.getName();
241         int dotIndex = namePrefix.lastIndexOf('.');
242         if (dotIndex > 0)
243             namePrefix = namePrefix.substring(dotIndex+1);
244         NameGenerator nameGenerator = getNameGenerator(namePrefix);
245         return nameGenerator.next();
246     }
247
248     /**
249      * Overrides the BeanContextSupport.add() method to perform additional validation
250      * that is unique for ControlBeans containers.
251      */

252     public boolean add(Object JavaDoc targetChild)
253     {
254         //
255
// The context can contain ControlBeans and other types of objects, such as a control
256
// factory.
257
//
258
String JavaDoc beanID = null;
259         if (targetChild instanceof ControlBean)
260         {
261             //
262
//
263
//
264
ControlBean bean = (ControlBean)targetChild;
265             beanID = bean.getLocalID();
266
267             //
268
// The bean is anonymous, so we must generate a new unique name within this context.
269
//
270
if (beanID == null)
271             {
272                 beanID = generateUniqueID(bean.getClass());
273                 bean.setLocalID(beanID);
274             }
275
276             ControlBean existingBean = (ControlBean)_childMap.get(beanID);
277             if (existingBean != null && existingBean != targetChild)
278             {
279                 throw new IllegalArgumentException JavaDoc("Attempting to add control with duplicate ID: " +
280                                                    beanID);
281             }
282         }
283         boolean added = super.add(targetChild);
284         if (added && beanID != null)
285             _childMap.put(beanID, targetChild);
286
287         return added;
288     }
289
290     /**
291      * Overrides the BeanContextSupport.remove() method to perform additional post-processing
292      * on child removal.
293      */

294     public boolean remove(Object JavaDoc targetChild)
295     {
296         assert targetChild instanceof ControlBean; // should be guaranteed above
297
boolean removed = super.remove(targetChild);
298         if (removed)
299         {
300             //
301
// Remove from the locally maintained child map
302
//
303
String JavaDoc localID = ((ControlBean)targetChild).getLocalID();
304             Object JavaDoc removedChild = _childMap.remove(localID);
305             assert removedChild == targetChild; // just being safe
306
}
307         return removed;
308     }
309
310     /**
311      * Returns a ControlBean instance nested the current BeanContext.
312      * @param id the identifier for the target control, relative to the current
313      * context.
314      */

315     public ControlBean getBean(String JavaDoc id)
316     {
317         // If no control id separator found, the bean is a direct child of this context
318
int delim = id.indexOf(org.apache.beehive.controls.api.bean.ControlBean.IDSeparator);
319         if (delim < 0) // child is a direct descendent
320
return (ControlBean)_childMap.get(id);
321
322         // Find the child referenced by the first element in the path
323
ControlBean bean = (ControlBean)_childMap.get(id.substring(0, delim));
324         if (bean == null)
325             return bean;
326
327         // Get the BeanContext associated with the found child, and then ask it
328
// to resolve the rest of the path
329
return ((ControlBeanContext)bean.getBeanContextProxy()).getBean(id.substring(delim+1));
330     }
331
332     /**
333      * Returns the ControlBean associated directly with the ControlBeanContext. If the
334      * context represents a top-level container, will return null.
335      */

336     public ControlBean getControlBean()
337     {
338         return _bean;
339     }
340
341     public synchronized boolean hasSingleThreadedParent()
342     {
343         return _hasSingleThreadedParent;
344     }
345
346     /**
347      * Returns true if this container associated with this context service enforces
348      * single-threaded invocation, false otherwise.
349      *
350      * This MUST be overridden by container-specific subclasses. If they guarantee
351      * single-threaded behavior (such as the EJB container), they should return true.
352      */

353     public synchronized boolean isSingleThreadedContainer()
354     {
355         return ( hasSingleThreadedParent() || ( _bean != null && _bean.hasSingleThreadedImpl() ));
356     }
357
358     /**
359      * The initializeControl method is invoked when the implementation instance associated
360      * with the context has been instantiated and initialized.
361      */

362     public void initializeControl()
363     {
364         //
365
// Deliver the onCreate event to any register lifecycle listeners
366
//
367
if (_lifeCycleListeners != null)
368         {
369             Iterator iter = _lifeCycleListeners.iterator();
370             while (iter.hasNext())
371             {
372                 LifeCycle listener = (LifeCycle)iter.next();
373                 listener.onCreate();
374             }
375         }
376     }
377
378     /**
379      * Returns the PropertyMap containing default properties for an AnnotatedElement
380      * in the current context. The initialization of PropertyMap binding is always
381      * done by delegating to a ControlContainerContext, enabling containers to implement
382      * property binding mechanisms (such as external config) that may override the values
383      * contained within the element annotations.
384      */

385     public PropertyMap getAnnotationMap(AnnotatedElement JavaDoc annotElem)
386     {
387         ControlBeanContext beanContext = this;
388         while (beanContext != null)
389         {
390             // REVIEW: should ControlContainerContext-derived classes override getBeanAnnotationMap? Not sure
391
// that name makes sense, and perhaps it shouldn't take a ControlBean.
392
if (beanContext instanceof ControlContainerContext)
393                 return beanContext.getBeanAnnotationMap(_bean, annotElem);
394             beanContext = (ControlBeanContext)beanContext.getBeanContext();
395         }
396             
397         // No ControlContainerContext was found, so just use the default implementation
398
return getBeanAnnotationMap(_bean, annotElem);
399     }
400
401     /**
402      * The default implementation of getBeanAnnotationMap. This returns a map based purely
403      * upon annotation reflection
404      */

405     protected PropertyMap getBeanAnnotationMap(ControlBean bean, AnnotatedElement JavaDoc annotElem)
406     {
407         PropertyMap map = new AnnotatedElementMap(annotElem);
408
409         // REVIEW: is this the right place to handle the general control client case?
410
if ( bean != null )
411             setDelegateMap( map, bean, annotElem );
412         
413         return map;
414     }
415
416     static protected void setDelegateMap( PropertyMap map, ControlBean bean, AnnotatedElement JavaDoc annotElem )
417     {
418         //
419
// If building an annotation map for a method or field, we want to delegate back
420
// to the base control type.
421
//
422
Class JavaDoc annotClass = null;
423         if (annotElem instanceof Field JavaDoc)
424         {
425            annotClass = ((Field JavaDoc)annotElem).getType();
426         }
427         else if (annotElem instanceof Method JavaDoc)
428         {
429            annotClass = bean.getControlInterface();
430         }
431         if (annotClass != null)
432         {
433             PropertyMap delegateMap = bean.getAnnotationMap(annotClass);
434             map.setDelegateMap(delegateMap);
435         }
436     }
437
438     /**
439      * Returns the default binding based entirely upon annotations or naming conventions.
440      */

441     static public String JavaDoc getDefaultControlBinding(Class JavaDoc controlIntf)
442     {
443         controlIntf = ControlBean.getMostDerivedInterface(controlIntf);
444
445         ControlInterface intfAnnot =
446                     (ControlInterface)controlIntf.getAnnotation(ControlInterface.class);
447         String JavaDoc implBinding = intfAnnot.defaultBinding();
448         implBinding = resolveDefaultBinding( implBinding, controlIntf.getName() );
449
450         return implBinding;
451     }
452
453     /**
454      * Implements the default control implementation binding algorithm ( <InterfaceName> + "Impl" ). See
455      * documentation for the org.apache.beehive.controls.api.bean.ControlInterface annotation.
456      *
457      * @param implBinding the value of the defaultBinding attribute returned from a ControlInterface annotation
458      * @param controlClass the actual name of the interface decorated by the ControlInterface annotation
459      * @return the resolved defaultBinding value
460      */

461     public static String JavaDoc resolveDefaultBinding( String JavaDoc implBinding, String JavaDoc controlClass )
462     {
463         int intfIndex = implBinding.indexOf(ControlInterface.INTERFACE_NAME);
464         if (intfIndex >= 0)
465         {
466             implBinding = implBinding.substring(0,intfIndex) + controlClass +
467                           implBinding.substring(intfIndex +
468                                                 ControlInterface.INTERFACE_NAME.length());
469         }
470         return implBinding;
471     }
472
473     //
474
// ControlBeanContext.getControlInterface
475
//
476
public Class JavaDoc getControlInterface()
477     {
478         return _bean.getControlInterface();
479     }
480
481     //
482
// ControlBeanContext.getControlPropertySet
483
//
484
public <T extends Annotation JavaDoc> T getControlPropertySet(Class JavaDoc<T> propertySet)
485     {
486         PropertyMap map = _bean.getPropertyMap();
487
488         //
489
// Optional properties are not exposed to clients using traditional JavaBean
490
// setters/getters (because there is way to represent an 'unset' value); for
491
// these properties, the impl can tell if the PropertySet is unset because
492
// this method will return null.
493
//
494
if (!map.containsPropertySet(propertySet))
495         {
496             PropertySet psAnnot = propertySet.getAnnotation(PropertySet.class);
497             if (psAnnot.optional())
498                 return null;
499         }
500
501         //
502
// Construct a new PropertySet proxy instance that derives its values from
503
// the bean property map.
504
//
505
return PropertySetProxy.getProxy(propertySet, map);
506     }
507
508     //
509
// ControlBeanContext.getMethodPropertySet
510
//
511
public <T extends Annotation JavaDoc> T getMethodPropertySet(Method JavaDoc m, Class JavaDoc<T> propertySet)
512     {
513         PropertyMap map = _bean.getAnnotationMap(m);
514
515         //
516
// Optional properties are not exposed to clients using traditional JavaBean
517
// setters/getters (because there is way to represent an 'unset' value); for
518
// these properties, the impl can tell if the PropertySet is unset because
519
// this method will return null.
520
//
521
if (!map.containsPropertySet(propertySet))
522         {
523             PropertySet psAnnot = propertySet.getAnnotation(PropertySet.class);
524             if (psAnnot.optional())
525                 return null;
526         }
527
528         //
529
// Construct a new PropertySet proxy instance that derives its values from
530
// the method property map.
531
//
532
return PropertySetProxy.getProxy(propertySet, _bean.getAnnotationMap(m));
533     }
534
535     //
536
// ControlBeanContext.getParameterPropertySet
537
//
538
public <T extends Annotation JavaDoc> T getParameterPropertySet(Method JavaDoc m, int i, Class JavaDoc<T> propertySet)
539                                     throws IllegalArgumentException JavaDoc, IndexOutOfBoundsException JavaDoc
540     {
541         if (i >= m.getParameterTypes().length)
542             throw new IndexOutOfBoundsException JavaDoc("Invalid parameter index for method:" + m);
543
544         //
545
// BUGBUG: Currently, there is no external override mechanism for method parameters
546
//
547
Annotation JavaDoc [] paramAnnots = m.getParameterAnnotations()[i];
548         for (int j = 0; j < paramAnnots.length; j++)
549             if (propertySet.isAssignableFrom(paramAnnots[j].getClass()))
550                 return (T)paramAnnots[j];
551
552         return null;
553     }
554
555     //
556
// ControlBeanContext.getParameterNames
557
//
558
public String JavaDoc [] getParameterNames(Method JavaDoc m) throws IllegalArgumentException JavaDoc
559     {
560         return _bean.getParameterNames(m);
561     }
562
563     //
564
// ControlBeanContext.getNamedParameterValue
565
//
566
public Object JavaDoc getParameterValue(Method JavaDoc m, String JavaDoc parameterName, Object JavaDoc [] parameters)
567                   throws IllegalArgumentException JavaDoc
568     {
569         String JavaDoc [] names = getParameterNames(m);
570
571         // Validate the input parameter array
572
if (parameters.length != names.length)
573             throw new IllegalArgumentException JavaDoc("Expected " + names.length + " parameters," +
574                                                "Found " + parameters.length);
575
576         // Finding the index of the matching parameter name
577
int i = 0;
578         while (i < names.length)
579         {
580             if (names[i].equals(parameterName))
581                 break;
582             i++;
583         }
584         if (i == names.length)
585             throw new IllegalArgumentException JavaDoc("No method parameter with name: " + parameterName);
586
587         // Return the parameter value at the matched index
588
return parameters[i];
589     }
590
591     //
592
// ControlBeanContext.getPropertyMap
593
//
594
public PropertyMap getControlPropertyMap()
595     {
596         //
597
// Return a wrapped copy of the original bean property map, so any edits
598
// don't impact the bean properties.
599
//
600
return new BeanPropertyMap(_bean.getPropertyMap());
601     }
602
603     //
604
// ControlBeanContext.getService
605
//
606
public <T> T getService(Class JavaDoc<T> serviceClass, Object JavaDoc selector)
607     {
608         //
609
// If the requested service is a ControlBeanContext instance, the current instance
610
// can be returned.
611
//
612
if (serviceClass.equals(org.apache.beehive.controls.api.context.ControlBeanContext.class))
613             return (T)this;
614
615         //
616
// The parent BeanContext is responsible for providing requested services. If
617
// no parent context is available or it is does not manage services, then no service.
618
//
619
BeanContext JavaDoc bc = getBeanContext();
620         if (bc == null || !(bc instanceof BeanContextServices JavaDoc))
621             return null;
622
623         //
624
// Call getService on the parent context, using this bean as the requestor and the
625
// this context as the child context and ServicesRevoked event listener parameters.
626
//
627
try
628         {
629             return (T)((BeanContextServices JavaDoc)bc).getService(this, _bean, serviceClass, selector,
630                                                             this);
631         }
632         catch (TooManyListenersException tmle)
633         {
634             // This would be highly unusual... it implies that the registration for service
635
// revocation notifications failed for some reason.
636
throw new ControlException("Unable to register for service events", tmle);
637         }
638     }
639
640     //
641
// ControlBeanContext.getControlHandle
642
//
643
public ControlHandle getControlHandle()
644     {
645         //
646
// Find the associated ControlContainerContext, which provides a container-specific
647
// implementation of ControlHandle
648
//
649
ControlBeanContext beanContext = this;
650         while (beanContext != null && !(beanContext instanceof ControlContainerContext))
651             beanContext = (ControlBeanContext)beanContext.getBeanContext();
652
653         if (beanContext == null)
654             return null;
655
656         //
657
// Ask the container for a ControlHandle instance referencing the target bean
658
//
659
return ((ControlContainerContext)beanContext).getControlHandle(_bean);
660     }
661
662     //
663
// ControlBeanContext.getClassLoader
664
//
665
public java.lang.ClassLoader JavaDoc getClassLoader()
666     {
667         return getControlInterface().getClassLoader();
668     }
669
670     /**
671      * Filename that contains ordering priority for controls interceptor services.
672      * Each line in the file is a fully qualified interface name. 1st line in the file
673      * is highest priority.
674      */

675     public static final String JavaDoc INTERCEPTOR_CONFIG_FILE = "controls-interceptors.config";
676
677     /**
678      * Applies externally defined (via INTERCEPTOR_CONFIG_FILE) ordering priority for
679      * controls interceptor services.
680      *
681      * @param interceptors
682      * @return String[]
683      */

684     public static String JavaDoc[] prioritizeInterceptors( String JavaDoc [] interceptors )
685     {
686         if ( interceptors == null )
687             return null;
688
689         // Read external configuration to obtain desired prioritization.
690
if ( _interceptorPriorities == null )
691         {
692             // Only ever attempt to read the external configuration once; bounce the VM if you want to try again.
693
_interceptorPriorities = new ArrayList<String JavaDoc>();
694             BufferedReader JavaDoc in = null;
695             try
696             {
697                 InputStream JavaDoc configFileStream =
698                     ControlBeanContext.class.getClassLoader().getResourceAsStream( INTERCEPTOR_CONFIG_FILE );
699
700                 if ( configFileStream != null )
701                 {
702                     in = new BufferedReader JavaDoc(new InputStreamReader JavaDoc(configFileStream));
703                     String JavaDoc str;
704                     while ((str = in.readLine()) != null)
705                         _interceptorPriorities.add(str);
706                 }
707             }
708             catch (IOException JavaDoc e)
709             {
710             }
711             finally
712             {
713                 try
714                 {
715                     if (in != null)
716                         in.close();
717                 }
718                 catch ( IOException JavaDoc ie ) { }
719             }
720         }
721
722         // Put input list of interceptors into a Set for easy lookup
723
Set<String JavaDoc> input = new HashSet<String JavaDoc>();
724         for ( String JavaDoc ii : interceptors )
725             input.add( ii );
726
727         // Scan through priorities list, building a prioritized list
728
ArrayList<String JavaDoc> prioritized = new ArrayList<String JavaDoc>(interceptors.length);
729         for ( String JavaDoc p : _interceptorPriorities )
730         {
731             if ( input.contains(p) )
732             {
733                 input.remove(p);
734                 prioritized.add(p);
735             }
736         }
737
738         // Anything still left in the input set did not have a priority associated with it,
739
// so they just go at the end in arbitrary order.
740
for ( String JavaDoc p : input )
741             prioritized.add(p);
742
743         return prioritized.toArray(new String JavaDoc[prioritized.size()]);
744     }
745
746     //
747
// ControlBeanContext.addLifeCycleListener
748
//
749
synchronized public void addLifeCycleListener(LifeCycle listener)
750     {
751         if (_lifeCycleListeners == null)
752         {
753             _lifeCycleListeners = new Vector<LifeCycle>();
754
755             //
756
// Since bound/constrained property changes are exposed as lifecycle events, we
757
// need to register ourselves as a listener for these events the first time a
758
// lifecycle listener is added.
759
//
760
_bean.getPropertyChangeSupport().addPropertyChangeListener(this);
761             _bean.getVetoableChangeSupport().addVetoableChangeListener(this);
762         }
763         _lifeCycleListeners.addElement(listener);
764     }
765
766     //
767
// ControlBeanContext.removeLifeCycleListener
768
//
769
synchronized public void removeLifeCycleListener(LifeCycle listener)
770     {
771         if (_lifeCycleListeners != null)
772             _lifeCycleListeners.removeElement(listener);
773     }
774
775     //
776
// PropertyChangeListener.propertyChange
777
//
778
public void propertyChange(PropertyChangeEvent JavaDoc pce)
779     {
780         if (_lifeCycleListeners != null)
781         {
782             Iterator iter = _lifeCycleListeners.iterator();
783             while (iter.hasNext())
784             {
785                 LifeCycle listener = (LifeCycle)iter.next();
786                 listener.onPropertyChange(pce);
787             }
788         }
789     }
790
791     //
792
// VetoableChangeListener.vetoableChange
793
//
794
public void vetoableChange(PropertyChangeEvent JavaDoc pce) throws PropertyVetoException JavaDoc
795     {
796         if (_lifeCycleListeners != null)
797         {
798             Iterator iter = _lifeCycleListeners.iterator();
799             while (iter.hasNext())
800             {
801                 LifeCycle listener = (LifeCycle)iter.next();
802                 listener.onVetoableChange(pce);
803             }
804         }
805     }
806
807     /* package */ String JavaDoc getControlID()
808     {
809         if (_controlID != null || _bean == null)
810             return _controlID;
811
812         // Initially set to the local beans relative ID
813
String JavaDoc id = _bean.getLocalID();
814
815         // If there is a parent context, prepend its ID and the ID separator
816
BeanContext JavaDoc bc = getBeanContext();
817         if (bc != null && bc instanceof ControlBeanContext)
818         {
819             String JavaDoc parentID = ((ControlBeanContext)bc).getControlID();
820             if (parentID != null)
821             {
822                 id = parentID +
823                      org.apache.beehive.controls.api.bean.ControlBean.IDSeparator +
824                      id;
825             }
826         }
827
828         // Cache the computed value
829
_controlID = id;
830
831         return id;
832     }
833
834     /**
835      * Resets the composite control ID for this context and all children beneath it. This
836      * can be used to invalidate cached values when necessary (for example, when a context
837      * is reparented).
838      */

839     private void resetControlID()
840     {
841         _controlID = null;
842         Iterator childIter = this.iterator();
843         while (childIter.hasNext())
844         {
845             Object JavaDoc child = childIter.next();
846             if (child instanceof ControlBeanContext)
847                 ((ControlBeanContext)child).resetControlID();
848         }
849     }
850
851     //
852
// BeanContextServices.getCurrentServiceClasses
853
// Override the default implementatino of getCurrentServiceClasses inherited from
854
// java.beans.beancontext.BeanContextServicesSuppport. The reason for this is a bug/
855
// flaw in its underlying implementation. It does not include any services exposed
856
// by any nesting contexts. This is contradictory to the implementation of hasService()
857
// and getService() which do delegate up to a parent context to find services if not
858
// available on the local context. This means hasService() could return 'true' for a
859
// service that isn't returned by getCurrentServiceClasses(), which seems like a bug.
860
//
861
synchronized public Iterator getCurrentServiceClasses()
862     {
863         Set classSet = new HashSet();
864         BeanContextServices JavaDoc bcs = this;
865
866         while (bcs != null)
867         {
868             // Optimize the case where we can do a direct copy based upon impl knowledge.
869
if (bcs instanceof ControlBeanContext)
870             {
871                 classSet.addAll(((ControlBeanContext)bcs).services.keySet());
872             }
873             else
874             {
875                 Iterator iter = bcs.getCurrentServiceClasses();
876                 while (iter.hasNext())
877                     classSet.add(iter.next());
878             }
879             
880             // Go up to the parent, if it is a service provider as well
881
BeanContext JavaDoc bc = getBeanContext();
882             if (bc instanceof BeanContextServices JavaDoc && bcs != bc)
883                 bcs = (BeanContextServices JavaDoc)bc;
884             else
885                 bcs = null;
886         }
887         return classSet.iterator();
888     }
889
890     //
891
// BeanContextServices.getCurrentServiceSelectors
892
// Override getCurrentServiceSelectors for the same reason as above
893
//
894
public Iterator getCurrentServiceSelectors(Class JavaDoc serviceClass)
895     {
896         if (hasService(serviceClass))
897             return super.getCurrentServiceSelectors(serviceClass);
898         
899         BeanContext JavaDoc bc = getBeanContext();
900         if (bc instanceof BeanContextServices JavaDoc)
901             return ((BeanContextServices JavaDoc)bc).getCurrentServiceSelectors(serviceClass);
902
903         return null;
904     }
905
906     /**
907      * The ControlBean instance that this context is providing services for. This value can
908      * be null, if the context instance is associated with top-level (non-control) context.
909      */

910     private ControlBean _bean;
911
912     /**
913      * Indicates whether this context's parent guarantees single-threaded behaviour.
914      */

915     private boolean _hasSingleThreadedParent = false;
916
917     /**
918      * Maps children by the local (relative) ID of the child to the actual bean instance.
919      * This needs to be synchronized, because adds/removes/gets are not necessarily guaranteed
920      * to happen within the scope of the global hierarchy lock. It would be relatively easy
921      * to synchronize add/remove, since setBeanContext on the child is inside this lock scope,
922      * but gets on the map are another story.
923      */

924     private Map<String JavaDoc,Object JavaDoc> _childMap =
925                 Collections.synchronizedMap(new HashMap<String JavaDoc,Object JavaDoc>());
926
927     /**
928      * Maintains a set of NameGenerators (for control ID generation) keyed by a
929      * base prefix. The map itself is lazily constructed, so there is minimal
930      * overhead of no id generation is needed in this context.
931      */

932     private Map<String JavaDoc,NameGenerator> _nameGenerators;
933
934     /**
935      * Maintains the list of lifecycle event listeners (if any) for this context.
936      */

937     transient private Vector<LifeCycle> _lifeCycleListeners;
938
939     /**
940      * Caches the full composite control ID, that includes the entire path from the root
941      * ContainerContext to the associated bean. This value can be transient, since it
942      * can be easily recomputed when needed.
943      */

944     transient private String JavaDoc _controlID;
945
946     private static ArrayList<String JavaDoc> _interceptorPriorities;
947 }
948
Popular Tags