JdbcMapper/beehive-controls/src/main/java/org/apache/beehive/controls/runtime/bean/ControlBeanContext.java

1121 lines
41 KiB
Java

/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* $Header:$
*/
package org.apache.beehive.controls.runtime.bean;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyVetoException;
import java.beans.PropertyChangeListener;
import java.beans.VetoableChangeListener;
import java.beans.beancontext.BeanContext;
import java.beans.beancontext.BeanContextServiceRevokedEvent;
import java.beans.beancontext.BeanContextServiceProvider;
import java.beans.beancontext.BeanContextServices;
import java.beans.beancontext.BeanContextChild;
import java.beans.beancontext.BeanContextServiceRevokedListener;
import java.beans.beancontext.BeanContextServicesListener;
import java.beans.beancontext.BeanContextMembershipListener;
import java.beans.beancontext.BeanContextServiceAvailableEvent;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TooManyListenersException;
import java.util.Vector;
import java.util.Collection;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
import java.net.URL;
import org.apache.beehive.controls.api.ControlException;
import org.apache.beehive.controls.api.context.ControlHandle;
import org.apache.beehive.controls.api.properties.AnnotatedElementMap;
import org.apache.beehive.controls.api.properties.BeanPropertyMap;
import org.apache.beehive.controls.api.properties.PropertyMap;
import org.apache.beehive.controls.api.properties.PropertySet;
import org.apache.beehive.controls.api.properties.PropertySetProxy;
/**
* The ControlBeanContext implements the basic BeanContextServices implementation
* for ControlBeans.
*
* It provides several basic functions:
* - it defines the generic services that are available for all control containers
* - it acts as the base class for other container service implementations
* - it acts as the BeanContextServicesRevokedListener when an associated control
* bean has lost access to services.
*/
public class ControlBeanContext
implements org.apache.beehive.controls.api.context.ControlBeanContext,
java.beans.PropertyChangeListener,
java.beans.VetoableChangeListener,
java.io.Serializable
{
/**
* Creates a new ControlBeanContext instance associated with a specific control bean. If the
* <code>ControlBean</code> is null, this ControlBeanContext object represents a top-level Control
* container. This constructor uses the default implementation of the
* {@link java.beans.beancontext.BeanContextServices} interface from the JDK.
*
* @param bean The control bean that contains/scopes the ControlBeanContext. If null, it means the
* ControlBeanContext is for a top-level container.
*/
protected ControlBeanContext(ControlBean bean)
{
this(bean, DEFAULT_BEAN_CONTEXT_SERVICES_FACTORY);
}
/**
* Creates a new ControlBeanContext instance associated with a specific control bean. If the
* <code>ControlBean</code> is null, this ControlBeanContext object represents a top-level Control
* container. This constructor uses the <code>beanContextServicesDelegate</code> instance as the
* implementation of the {@link java.beans.beancontext.BeanContextServices} interface.
*
* @param bean The control bean
* @param beanContextServicesFactory A factory that can be used to create the BeanContextServicesFactory object
* that implements support for the {@link BeanContextServices} interface.
*/
protected ControlBeanContext(ControlBean bean, BeanContextServicesFactory beanContextServicesFactory) {
super();
_bean = bean;
// ensure that there is a valid factory for creating the BCS delegate
if(beanContextServicesFactory == null)
beanContextServicesFactory = DEFAULT_BEAN_CONTEXT_SERVICES_FACTORY;
_beanContextServicesDelegate = beanContextServicesFactory.instantiate(this);
initialize();
}
/**
* Called by BeanContextSupport superclass during construction and deserialization to
* initialize subclass transient state
*/
public void initialize()
{
//
// Register the ControlBeanContext provider on all new context instances.
//
addService(org.apache.beehive.controls.api.context.ControlBeanContext.class, CONTROL_BEAN_CONTEXT_PROVIDER);
}
/**
* Implements the
* {@link java.beans.beancontext.BeanContextServiceRevokedListener#serviceRevoked(java.beans.beancontext.BeanContextServiceRevokedEvent)}
* method. This is called if the associated {@link ControlBean} has requested a service that is being subsequently
* revoked.
*/
public void serviceRevoked(BeanContextServiceRevokedEvent bcsre)
{
//
// This can happen, if the control is disassociated from a parent context that is
// providing services.
//
}
/**
* Overrides the {@link java.beans.beancontext.BeanContextChild#setBeanContext(java.beans.beancontext.BeanContext)}
* method. This hook is used to perform additional processing that needs to occur when the control is associated
* with a new nesting context.
*/
public synchronized void setBeanContext(BeanContext beanContext)
throws PropertyVetoException
{
ControlBeanContext cbcs = null;
if (beanContext != null)
{
//
// ControlBeans can only be nested in context service instances that derive
// from ControlBeanContext.
//
if (!(beanContext instanceof ControlBeanContext))
{
PropertyChangeEvent pce = new PropertyChangeEvent(_bean, "beanContext", getBeanContext(), beanContext);
throw new PropertyVetoException("Context does not support nesting controls: " +
beanContext.getClass(), pce);
}
cbcs = (ControlBeanContext)beanContext;
}
_beanContextServicesDelegate.setBeanContext(beanContext);
resetControlID();
_hasSingleThreadedParent = cbcs != null ? cbcs.isSingleThreadedContainer() : false;
//
// Notify the bean that its context (container) has been set.
//
if (_bean != null)
_bean.setBeanContext(beanContext);
}
/**
* The NameGenerator class is a simple helper class that creates new unique names based
* upon a base prefix and an incrementing counter
*/
private static class NameGenerator implements java.io.Serializable
{
NameGenerator(String namePrefix)
{
_namePrefix = namePrefix;
}
/**
* Get the next unique name
*/
public synchronized String next()
{
return _namePrefix + _nextIndex++;
}
int _nextIndex = 0;
String _namePrefix;
}
/**
* Returns a new NameGenerator instance based upon a particular naming
* prefix.
*/
private NameGenerator getNameGenerator(String namePrefix)
{
synchronized(this)
{
if (_nameGenerators == null)
_nameGenerators = new HashMap<String,NameGenerator>();
NameGenerator nameGenerator = _nameGenerators.get(namePrefix);
if (nameGenerator == null)
{
nameGenerator = new NameGenerator(namePrefix);
_nameGenerators.put(namePrefix, nameGenerator);
}
return nameGenerator;
}
}
/**
* Generates a new unique control ID for an instance of the target class
*/
public String generateUniqueID(Class clazz)
{
String namePrefix = clazz.getName();
int dotIndex = namePrefix.lastIndexOf('.');
if (dotIndex > 0)
namePrefix = namePrefix.substring(dotIndex+1);
NameGenerator nameGenerator = getNameGenerator(namePrefix);
return nameGenerator.next();
}
/**
* Overrides the BeanContextSupport.add() method to perform additional validation
* that is unique for ControlBeans containers.
*/
public boolean add(Object targetChild)
{
//
// The context can contain ControlBeans and other types of objects, such as a control
// factory.
//
String beanID = null;
if (targetChild instanceof ControlBean)
{
ControlBean bean = (ControlBean)targetChild;
beanID = bean.getLocalID();
//
// The bean is anonymous, so we must generate a new unique name within this context.
//
if (beanID == null)
{
beanID = generateUniqueID(bean.getClass());
bean.setLocalID(beanID);
}
ControlBean existingBean = (ControlBean)_childMap.get(beanID);
if (existingBean != null && existingBean != targetChild)
{
throw new IllegalArgumentException("Attempting to add control with duplicate ID: " +
beanID);
}
}
boolean added = _beanContextServicesDelegate.add(targetChild);
if (added && beanID != null)
_childMap.put(beanID, targetChild);
return added;
}
/**
* Overrides the BeanContextSupport.remove() method to perform additional post-processing
* on child removal.
*/
public boolean remove(Object targetChild)
{
assert targetChild instanceof ControlBean; // should be guaranteed above
boolean removed = _beanContextServicesDelegate.remove(targetChild);
if (removed)
{
//
// Remove from the locally maintained child map
//
String localID = ((ControlBean)targetChild).getLocalID();
Object removedChild = _childMap.remove(localID);
assert removedChild == targetChild; // just being safe
}
return removed;
}
/**
* Returns a ControlBean instance nested the current BeanContext.
* @param id the identifier for the target control, relative to the current
* context.
*/
public ControlBean getBean(String id)
{
// If no control id separator found, the bean is a direct child of this context
int delim = id.indexOf(org.apache.beehive.controls.api.bean.ControlBean.IDSeparator);
if (delim < 0) // child is a direct descendent
return (ControlBean)_childMap.get(id);
// Find the child referenced by the first element in the path
ControlBean bean = (ControlBean)_childMap.get(id.substring(0, delim));
if (bean == null)
return bean;
// Get the BeanContext associated with the found child, and then ask it
// to resolve the rest of the path
return bean.getBeanContextProxy().getBean(id.substring(delim+1));
}
/**
* Returns the ControlBean associated directly with the ControlBeanContext. If the
* context represents a top-level container, will return null.
*/
public ControlBean getControlBean()
{
return _bean;
}
public synchronized boolean hasSingleThreadedParent()
{
return _hasSingleThreadedParent;
}
/**
* Returns true if this container associated with this context service enforces
* single-threaded invocation, false otherwise.
*
* This MUST be overridden by container-specific subclasses in order to change
* the default behavior. If a single-threaded container intends to guarantee
* single-threaded behavior (such as the EJB container), this should return true.
*/
public synchronized boolean isSingleThreadedContainer()
{
return ( hasSingleThreadedParent() || ( _bean != null && _bean.hasSingleThreadedImpl() ));
}
/**
* The initializeControl method is invoked when the implementation instance associated
* with the context has been instantiated and initialized.
*/
public void initializeControl()
{
//
// Deliver the onCreate event to any register lifecycle listeners
//
if (_lifeCycleListeners != null)
{
for (LifeCycle lifeCycleListener : _lifeCycleListeners) {
lifeCycleListener.onCreate();
}
}
}
/**
* Returns the PropertyMap containing default properties for an AnnotatedElement
* in the current context. The initialization of PropertyMap binding is always
* done by delegating to a {@link ControlContainerContext}, enabling containers to implement
* property binding mechanisms (such as external config) that may override the values
* contained within the element annotations.
*/
public PropertyMap getAnnotationMap(AnnotatedElement annotElem)
{
ControlBeanContext beanContext = this;
while (beanContext != null)
{
// REVIEW: should ControlContainerContext-derived classes override getBeanAnnotationMap? Not sure
// that name makes sense, and perhaps it shouldn't take a ControlBean.
if (beanContext instanceof ControlContainerContext)
return beanContext.getBeanAnnotationMap(_bean, annotElem);
beanContext = (ControlBeanContext)beanContext.getBeanContext();
}
// No ControlContainerContext was found, so just use the default implementation
return getBeanAnnotationMap(_bean, annotElem);
}
/**
* The default implementation of getBeanAnnotationMap. This returns a map based purely
* upon annotation reflection
*/
protected PropertyMap getBeanAnnotationMap(ControlBean bean, AnnotatedElement annotElem)
{
PropertyMap map = new AnnotatedElementMap(annotElem);
// REVIEW: is this the right place to handle the general control client case?
if ( bean != null )
setDelegateMap( map, bean, annotElem );
return map;
}
static protected void setDelegateMap( PropertyMap map, ControlBean bean, AnnotatedElement annotElem )
{
//
// If building an annotation map for a method or field, we want to delegate back
// to the base control type.
//
Class annotClass = null;
if (annotElem instanceof Field)
{
annotClass = ((Field)annotElem).getType();
}
else if (annotElem instanceof Method)
{
annotClass = bean.getControlInterface();
}
if (annotClass != null)
{
PropertyMap delegateMap = bean.getAnnotationMap(annotClass);
map.setDelegateMap(delegateMap);
}
}
//
// ControlBeanContext.getControlInterface
//
public Class getControlInterface()
{
return _bean.getControlInterface();
}
//
// ControlBeanContext.getControlPropertySet
//
public <T extends Annotation> T getControlPropertySet(Class<T> propertySet)
{
PropertyMap map = _bean.getPropertyMap();
//
// Optional properties are not exposed to clients using traditional JavaBean
// setters/getters (because there is way to represent an 'unset' value); for
// these properties, the impl can tell if the PropertySet is unset because
// this method will return null.
//
if (!map.containsPropertySet(propertySet))
{
PropertySet psAnnot = propertySet.getAnnotation(PropertySet.class);
if (psAnnot.optional())
return null;
}
//
// Construct a new PropertySet proxy instance that derives its values from
// the bean property map.
//
return PropertySetProxy.getProxy(propertySet, map);
}
//
// ControlBeanContext.getMethodPropertySet
//
public <T extends Annotation> T getMethodPropertySet(Method m, Class<T> propertySet)
{
PropertyMap map = _bean.getAnnotationMap(m);
//
// Optional properties are not exposed to clients using traditional JavaBean
// setters/getters (because there is way to represent an 'unset' value); for
// these properties, the impl can tell if the PropertySet is unset because
// this method will return null.
//
if (!map.containsPropertySet(propertySet))
{
PropertySet psAnnot = propertySet.getAnnotation(PropertySet.class);
if (psAnnot.optional())
return null;
}
//
// Construct a new PropertySet proxy instance that derives its values from
// the method property map.
//
return PropertySetProxy.getProxy(propertySet, _bean.getAnnotationMap(m));
}
//
// ControlBeanContext.getParameterPropertySet
//
public <T extends Annotation> T getParameterPropertySet(Method m, int i, Class<T> propertySet)
throws IllegalArgumentException, IndexOutOfBoundsException
{
if (i >= m.getParameterTypes().length)
throw new IndexOutOfBoundsException("Invalid parameter index for method:" + m);
// todo: Currently, there is no external override mechanism for method parameters
Annotation [] paramAnnots = m.getParameterAnnotations()[i];
for (Annotation paramAnnot : paramAnnots)
if (propertySet.isAssignableFrom(paramAnnot.getClass()))
return (T) paramAnnot;
return null;
}
//
// ControlBeanContext.getParameterNames
//
public String [] getParameterNames(Method m)
throws IllegalArgumentException
{
return _bean.getParameterNames(m);
}
//
// ControlBeanContext.getNamedParameterValue
//
public Object getParameterValue(Method m, String parameterName, Object [] parameters)
throws IllegalArgumentException
{
String [] names = getParameterNames(m);
// Validate the input parameter array
if (parameters.length != names.length)
throw new IllegalArgumentException("Expected " + names.length + " parameters," +
"Found " + parameters.length);
// Finding the index of the matching parameter name
int i = 0;
while (i < names.length)
{
if (names[i].equals(parameterName))
break;
i++;
}
if (i == names.length)
throw new IllegalArgumentException("No method parameter with name: " + parameterName);
// Return the parameter value at the matched index
return parameters[i];
}
//
// ControlBeanContext.getPropertyMap
//
public PropertyMap getControlPropertyMap()
{
//
// Return a wrapped copy of the original bean property map, so any edits
// don't impact the bean properties.
//
return new BeanPropertyMap(_bean.getPropertyMap());
}
//
// ControlBeanContext.getService
//
public <T> T getService(Class<T> serviceClass, Object selector)
{
//
// If the requested service is a ControlBeanContext instance, the current instance
// can be returned.
//
if (serviceClass.equals(org.apache.beehive.controls.api.context.ControlBeanContext.class))
return (T)this;
//
// The parent BeanContext is responsible for providing requested services. If
// no parent context is available or it is does not manage services, then no service.
//
BeanContext bc = getBeanContext();
if (bc == null || !(bc instanceof BeanContextServices))
return null;
//
// Call getService on the parent context, using this bean as the requestor and the
// this context as the child context and ServicesRevoked event listener parameters.
//
try
{
return (T)((BeanContextServices)bc).getService(this, _bean, serviceClass, selector, this);
}
catch (TooManyListenersException tmle)
{
// This would be highly unusual... it implies that the registration for service
// revocation notifications failed for some reason.
throw new ControlException("Unable to register for service events", tmle);
}
}
//
// ControlBeanContext.getControlHandle
//
public ControlHandle getControlHandle()
{
//
// Find the associated ControlContainerContext, which provides a container-specific
// implementation of ControlHandle
//
ControlBeanContext beanContext = this;
while (beanContext != null && !(beanContext instanceof ControlContainerContext))
beanContext = (ControlBeanContext)beanContext.getBeanContext();
if (beanContext == null)
return null;
//
// Ask the container for a ControlHandle instance referencing the target bean
//
return ((ControlContainerContext)beanContext).getControlHandle(_bean);
}
//
// ControlBeanContext.getClassLoader
//
public java.lang.ClassLoader getClassLoader()
{
return getControlInterface().getClassLoader();
}
//
// ControlBeanContext.addLifeCycleListener
//
synchronized public void addLifeCycleListener(LifeCycle listener)
{
if (_lifeCycleListeners == null)
{
_lifeCycleListeners = new Vector<LifeCycle>();
//
// Since bound/constrained property changes are exposed as lifecycle events, we
// need to register ourselves as a listener for these events the first time a
// lifecycle listener is added.
//
_bean.getPropertyChangeSupport().addPropertyChangeListener(this);
_bean.getVetoableChangeSupport().addVetoableChangeListener(this);
}
_lifeCycleListeners.addElement(listener);
}
//
// ControlBeanContext.removeLifeCycleListener
//
synchronized public void removeLifeCycleListener(LifeCycle listener)
{
if (_lifeCycleListeners != null)
_lifeCycleListeners.removeElement(listener);
}
//
// PropertyChangeListener.propertyChange
//
public void propertyChange(PropertyChangeEvent pce)
{
if (_lifeCycleListeners != null)
{
for (LifeCycle lifeCycleListener : _lifeCycleListeners) {
lifeCycleListener.onPropertyChange(pce);
}
}
}
//
// VetoableChangeListener.vetoableChange
//
public void vetoableChange(PropertyChangeEvent pce) throws PropertyVetoException
{
if (_lifeCycleListeners != null)
{
for (LifeCycle lifeCycleListener : _lifeCycleListeners) {
lifeCycleListener.onVetoableChange(pce);
}
}
}
/* package */ String getControlID()
{
if (_controlID != null || _bean == null)
return _controlID;
// Initially set to the local beans relative ID
String id = _bean.getLocalID();
// If there is a parent context, prepend its ID and the ID separator
BeanContext bc = getBeanContext();
if (bc != null && bc instanceof ControlBeanContext)
{
String parentID = ((ControlBeanContext)bc).getControlID();
if (parentID != null)
{
id = parentID +
org.apache.beehive.controls.api.bean.ControlBean.IDSeparator +
id;
}
}
// Cache the computed value
_controlID = id;
return id;
}
/**
* Resets the composite control ID for this context and all children beneath it. This
* can be used to invalidate cached values when necessary (for example, when a context
* is reparented).
*/
private void resetControlID()
{
_controlID = null;
for (Object child : this) {
if (child instanceof ControlBeanContext)
((ControlBeanContext) child).resetControlID();
}
}
//
// BeanContextServices.getCurrentServiceClasses
// Override the default implementation of getCurrentServiceClasses inherited from
// java.beans.beancontext.BeanContextServicesSuppport. The reason for this is a bug/
// flaw in its underlying implementation. It does not include any services exposed
// by any nesting contexts. This is contradictory to the implementation of hasService()
// and getService() which do delegate up to a parent context to find services if not
// available on the local context. This means hasService() could return 'true' for a
// service that isn't returned by getCurrentServiceClasses(), which seems like a bug.
//
synchronized public Iterator getCurrentServiceClasses()
{
Set classSet = new HashSet();
BeanContextServices bcs = _beanContextServicesDelegate;
while (bcs != null)
{
Iterator iter = bcs.getCurrentServiceClasses();
while (iter.hasNext())
classSet.add(iter.next());
// Go up to the parent, if it is a service provider as well
BeanContext bc = getBeanContext();
if (bc instanceof BeanContextServices && bcs != bc)
bcs = (BeanContextServices)bc;
else
bcs = null;
}
return classSet.iterator();
}
//
// BeanContextServices.getCurrentServiceSelectors
// Override getCurrentServiceSelectors for the same reason as above
//
public Iterator getCurrentServiceSelectors(Class serviceClass)
{
if (hasService(serviceClass))
return _beanContextServicesDelegate.getCurrentServiceSelectors(serviceClass);
BeanContext bc = getBeanContext();
if (bc instanceof BeanContextServices)
return ((BeanContextServices)bc).getCurrentServiceSelectors(serviceClass);
return null;
}
private synchronized void writeObject(ObjectOutputStream oos)
throws IOException {
oos.defaultWriteObject();
if(_beanContextServicesDelegate instanceof java.beans.beancontext.BeanContextSupport) {
((java.beans.beancontext.BeanContextSupport)_beanContextServicesDelegate).writeChildren(oos);
} else if(_beanContextServicesDelegate instanceof org.apache.beehive.controls.runtime.webcontext.ControlBeanContextSupport) {
((org.apache.beehive.controls.runtime.webcontext.ControlBeanContextSupport)_beanContextServicesDelegate).writeChildren(oos);
}
else assert false;
}
private synchronized void readObject(ObjectInputStream ois)
throws IOException, ClassNotFoundException {
ois.defaultReadObject();
if(_beanContextServicesDelegate instanceof java.beans.beancontext.BeanContextSupport) {
((java.beans.beancontext.BeanContextSupport)_beanContextServicesDelegate).readChildren(ois);
} else if(_beanContextServicesDelegate instanceof org.apache.beehive.controls.runtime.webcontext.ControlBeanContextSupport) {
((org.apache.beehive.controls.runtime.webcontext.ControlBeanContextSupport)_beanContextServicesDelegate).readChildren(ois);
}
else assert false;
// Re-initialize a deserialized control hierarchy.
initialize();
}
protected BeanContextServicesFactory getBeanContextServicesFactory() {
return DEFAULT_BEAN_CONTEXT_SERVICES_FACTORY;
}
public boolean equals(Object o) {
/* todo: make sure this logic is right / sufficient */
if (this == o)
return true;
if(!(o instanceof org.apache.beehive.controls.api.context.ControlBeanContext))
return false;
return o instanceof ControlBeanContext &&
_beanContextServicesDelegate.equals(((ControlBeanContext)o)._beanContextServicesDelegate);
}
public int hashCode() {
/* todo: make sure this logic is right / sufficient */
int result;
result = (_bean != null ? _bean.hashCode() : 0);
result = 31 * result + (_beanContextServicesDelegate != null ? _beanContextServicesDelegate.hashCode() : 0);
return result;
}
/* --------------------------------------------------------------------------
Implementation of java.beans.beancontext.BeanContextServices
-------------------------------------------------------------------------- */
public boolean addService(Class serviceClass, BeanContextServiceProvider serviceProvider) {
return _beanContextServicesDelegate.addService(serviceClass, serviceProvider);
}
public void revokeService(Class serviceClass, BeanContextServiceProvider serviceProvider, boolean revokeCurrentServicesNow) {
_beanContextServicesDelegate.revokeService(serviceClass, serviceProvider, revokeCurrentServicesNow);
}
public boolean hasService(Class serviceClass) {
return _beanContextServicesDelegate.hasService(serviceClass);
}
public Object getService(BeanContextChild child, Object requestor, Class serviceClass, Object serviceSelector, BeanContextServiceRevokedListener bcsrl) throws TooManyListenersException {
return _beanContextServicesDelegate.getService(child, requestor, serviceClass, serviceSelector, bcsrl);
}
public void releaseService(BeanContextChild child, Object requestor, Object service) {
_beanContextServicesDelegate.releaseService(child, requestor, service);
}
public void addBeanContextServicesListener(BeanContextServicesListener bcsl) {
_beanContextServicesDelegate.addBeanContextServicesListener(bcsl);
}
public void removeBeanContextServicesListener(BeanContextServicesListener bcsl) {
_beanContextServicesDelegate.removeBeanContextServicesListener(bcsl);
}
public Object instantiateChild(String beanName) throws IOException, ClassNotFoundException {
return _beanContextServicesDelegate.instantiateChild(beanName);
}
public InputStream getResourceAsStream(String name, BeanContextChild bcc) throws IllegalArgumentException {
return _beanContextServicesDelegate.getResourceAsStream(name, bcc);
}
public URL getResource(String name, BeanContextChild bcc) throws IllegalArgumentException {
return _beanContextServicesDelegate.getResource(name, bcc);
}
public void addBeanContextMembershipListener(BeanContextMembershipListener bcml) {
_beanContextServicesDelegate.addBeanContextMembershipListener(bcml);
}
public void removeBeanContextMembershipListener(BeanContextMembershipListener bcml) {
_beanContextServicesDelegate.removeBeanContextMembershipListener(bcml);
}
public BeanContext getBeanContext() {
return _beanContextServicesDelegate.getBeanContext();
}
public void addPropertyChangeListener(String name, PropertyChangeListener pcl) {
_beanContextServicesDelegate.addPropertyChangeListener(name, pcl);
}
public void removePropertyChangeListener(String name, PropertyChangeListener pcl) {
_beanContextServicesDelegate.removePropertyChangeListener(name, pcl);
}
public void addVetoableChangeListener(String name, VetoableChangeListener vcl) {
_beanContextServicesDelegate.addVetoableChangeListener(name, vcl);
}
public void removeVetoableChangeListener(String name, VetoableChangeListener vcl) {
_beanContextServicesDelegate.removeVetoableChangeListener(name, vcl);
}
public int size() {
return _beanContextServicesDelegate.size();
}
public boolean isEmpty() {
return _beanContextServicesDelegate.isEmpty();
}
public boolean contains(Object o) {
return _beanContextServicesDelegate.contains(o);
}
public Iterator iterator() {
return _beanContextServicesDelegate.iterator();
}
public Object[] toArray() {
return _beanContextServicesDelegate.toArray();
}
public Object[] toArray(Object[] a) {
return _beanContextServicesDelegate.toArray(a);
}
public boolean containsAll(Collection c) {
return _beanContextServicesDelegate.containsAll(c);
}
public boolean addAll(Collection c) {
return _beanContextServicesDelegate.addAll(c);
}
public boolean removeAll(Collection c) {
return _beanContextServicesDelegate.removeAll(c);
}
public boolean retainAll(Collection c) {
return _beanContextServicesDelegate.retainAll(c);
}
public void clear() {
_beanContextServicesDelegate.clear();
}
public void setDesignTime(boolean designTime) {
_beanContextServicesDelegate.setDesignTime(designTime);
}
public boolean isDesignTime() {
return _beanContextServicesDelegate.isDesignTime();
}
public boolean needsGui() {
return _beanContextServicesDelegate.needsGui();
}
public void dontUseGui() {
_beanContextServicesDelegate.dontUseGui();
}
public void okToUseGui() {
_beanContextServicesDelegate.okToUseGui();
}
public boolean avoidingGui() {
return _beanContextServicesDelegate.avoidingGui();
}
public void serviceAvailable(BeanContextServiceAvailableEvent bcsae) {
_beanContextServicesDelegate.serviceAvailable(bcsae);
}
/* --------------------------------------------------------------------------
Static / deprecated methods.
-------------------------------------------------------------------------- */
/**
* Applies externally defined (via INTERCEPTOR_CONFIG_FILE) ordering priority for
* controls interceptor services.
*
* @param interceptors
* @return String[]
* @deprecated Use {@link InterceptorUtils#prioritizeInterceptors(String[])} instead. This method will
* be removed in the next point release.
*/
public static String[] prioritizeInterceptors( String [] interceptors ) {
return InterceptorUtils.prioritizeInterceptors(interceptors);
}
/**
* Returns the default binding based entirely upon annotations or naming conventions.
* @param controlIntf the control interface class
* @return the class name of the default control implementation binding
* @deprecated Use {@link ControlUtils#getDefaultControlBinding(Class)} insated. This method will be
* removed in the next point release.
*/
public static String getDefaultControlBinding(Class controlIntf)
{
return ControlUtils.getDefaultControlBinding(controlIntf);
}
/**
* Implements the default control implementation binding algorithm ( <InterfaceName> + "Impl" ). See
* documentation for the org.apache.beehive.controls.api.bean.ControlInterface annotation.
*
* @param implBinding the value of the defaultBinding attribute returned from a ControlInterface annotation
* @param controlClass the actual name of the interface decorated by the ControlInterface annotation
* @return the resolved defaultBinding value
* @deprecated Use {@link ControlUtils#resolveDefaultBinding(String, String)} insated. This method
* will be removed in the next point release.
*/
public static String resolveDefaultBinding( String implBinding, String controlClass )
{
return ControlUtils.resolveDefaultBinding(implBinding, controlClass);
}
/**
* The ControlBeanContextProvider inner class acts as a single BeanContext service
* provider for the ControlBeanContext service class. The implementation is simple,
* because the runtime ControlBeanContext implementation class directly implements
* this interface.
*/
private static class ControlBeanContextProvider implements BeanContextServiceProvider
{
//
// BeanContextServiceProvider.getService()
//
public Object getService(BeanContextServices bcs, Object requestor, Class serviceClass,
Object serviceSelector)
{
//
// Contextual services for a ControlBean is provided by the peer context
// instance.
//
if (requestor instanceof ControlBean)
return ((ControlBean)requestor).getControlBeanContext();
return null;
}
//
// BeanContextServiceProvider.releaseService()
//
public void releaseService(BeanContextServices bcs, Object requestor, Object service)
{
// noop, because context exists whether referenced or not
}
//
// BeanContextServiceProvider.getContextServiceSelectors()
//
public Iterator getCurrentServiceSelectors(BeanContextServices bcs, Class serviceClass)
{
return null; // no selectors
}
}
/*package*/ static abstract class BeanContextServicesFactory {
protected abstract BeanContextServices instantiate(ControlBeanContext controlBeanContext);
}
private static final class DefaultBeanContextServicesFactory
extends BeanContextServicesFactory {
protected BeanContextServices instantiate(ControlBeanContext controlBeanContext) {
return new java.beans.beancontext.BeanContextServicesSupport(controlBeanContext);
}
}
/**
* A singleton instance of the ControlBeanContextProvider class is that will be registered
* on all ControlBeanContext instances. The provider can be a singleton because it is
* completely stateless and thread-safe.
*/
private static final ControlBeanContextProvider CONTROL_BEAN_CONTEXT_PROVIDER =
new ControlBeanContextProvider();
/**
* A singleton instance of the BeanContextServicesFactory class that can be implemented by subclasses
* to allow top-level Control containers to provide their own implementations of the
* {@link java.beans.beancontext.BeanContextServices} interface. This field is considered an implementation
* detail and should not be referenced directly.
*/
private static final BeanContextServicesFactory DEFAULT_BEAN_CONTEXT_SERVICES_FACTORY =
new DefaultBeanContextServicesFactory();
/**
* The ControlBean instance that this context is providing services for. This value can
* be null, if the context instance is associated with top-level (non-control) context.
*/
private ControlBean _bean;
/**
* Indicates whether this context's parent guarantees single-threaded behaviour.
*/
private boolean _hasSingleThreadedParent = false;
/**
* Maps children by the local (relative) ID of the child to the actual bean instance.
* This needs to be synchronized, because adds/removes/gets are not necessarily guaranteed
* to happen within the scope of the global hierarchy lock. It would be relatively easy
* to synchronize add/remove, since setBeanContext on the child is inside this lock scope,
* but gets on the map are another story.
*/
private Map<String,Object> _childMap = Collections.synchronizedMap(new HashMap<String,Object>());
/**
* Maintains a set of NameGenerators (for control ID generation) keyed by a
* base prefix. The map itself is lazily constructed, so there is minimal
* overhead of no id generation is needed in this context.
*/
private Map<String,NameGenerator> _nameGenerators;
/**
* Maintains the list of lifecycle event listeners (if any) for this context.
*/
private transient Vector<LifeCycle> _lifeCycleListeners;
/**
* Caches the full composite control ID, that includes the entire path from the root
* ContainerContext to the associated bean. This value can be transient, since it
* can be easily recomputed when needed.
*/
private transient String _controlID;
/**
* Object that implements the java.beans.beancontext APIs from the JDK to provide compliance with the
* JavaBeans BeanContext / BeanContextChild specification. The ControlBeanContext class uses
* this object as a delegate to provide this functionality rather than extending the BeanContext
* support classes directly. This allows for more flexibility in how the BeanContextServices (et al)
* API implementations evolve over time.
*/
private BeanContextServices _beanContextServicesDelegate;
}