|
Since the introduction of the JavaBeans component architecture in the Java Development Kit v 1.1 (JDK) release in February 1997, additional specifications have been added to this component architecture such as the Extensible Runtime Containment and Services Protocol and the InfoBus standard extension. Both of these additions provide APIs that enable Beans to interconnect during run-time. Read on to learn more about the Extensible Runtime Containment and Services Protocol API (BeanContext, for short) and see how this API is implemented in the BeanBox in the Beans Development Kit (BDK) 1.1 and how you can develop dynamically connecting Beans. Extensible Runtime Containment and Services Protocol
The JavaBeans architecture sets rules for what makes a Java class a reusable software component (Bean, for short). It defines how, via reflection and introspection, the capabilities of a Bean are discovered. Such capabilities can be a Bean's properties, the events a Bean fires or the public methods of a Bean. This information is used by a development tool to provide a visual programming environment wherein the developer interconnects Beans, wiring one Bean's events to another Bean's public methods. The resulting set of connected components can be compiled into an applet or application and delivered to the end user. Thus the connections between the Beans and the customization of their properties occur during what is called design-time. The result of this process is experienced by the end user during run-time. The BeanContext API adds much more flexibility to this scenario. It enables a Bean to interrogate its environment for certain capabilities and available services. This allows the Bean to dynamically adjust its behavior to the container or context in which it finds itself. The BeanContext API is a core API in the Java 2 Standard Edition SDK (J2SDK). The API consists of two parts: 1) logical containment hierarchy for JavaBeans components and publishing and 2) discovery of services provided by Beans within such a hierarchy. Logical Containment
The containment hierarchy for JavaBeans components enables grouping of
Beans in a logical and traversable manner. This grouping is established
through the use of a
BeanContext in which it is contained,
it must implement the BeanContextChild interface. If
BeanContext containers are to be nested, the
BeanContextChild should implement the
BeanContext interface as well.
Services
The Services API of the Extensible Runtime Containment and Services Protocol
gives JavaBeans components a standard mechanism to discover which services other
Beans may provide and to connect to these Beans to make use of those services.
Services are typically interface or abstract-class based. A particular service
provider can implement the service in a variety of ways while maintaining the
same interface signature. Examples of services are spell checking or debugging.
Another example would be a service provided by a BeanContext API that
controls the locale setting for the Beans within the Beans Development Kit 1.1
BDK 1.1 contains an updated version of the BeanBox and some new
sample Beans. The BeanBox is both a
The BeanBox also provides two services:
The BeanBox publishes the method tracing service. The Juggler Bean looks
for this service and uses it to report on certain methods. The Juggler
connects during instantiation to the method tracing service. Then methods
such as
The BeanBox publishes the run-time/design-time toggle as a
![]() Fig 2. The Method Tracing Service in the BeanBox. (Click on the above image for a full-sized version of the image.) The BeanBox as a
|
transient
java.beans.beancontext.BeanContextServicesSupport
bcss = new
java.beans.beancontext.BeanContextServicesSupport();
private final sunw.demo.methodtracer.MethodTracer mt =
new sunw.demo.methodtracer.MethodTracer();
|
BeanContext proxy:
public BeanContextChild getBeanContextProxy() {
return bcss;
}
When a Bean gets placed in the BeanBox it is added to the
BeanContextcontainer:
bcss.add(bean);
Apart from the services it provides, the BeanBox also localizes the notion of
design-time or run-time to the BeanContext container. Although at the
moment the BeanBox has only one BeanContext, one could use
this in the case of multiple BeanContexts to allow some to be in
design-time and others to be in run-time. So if the Bean knows about design time and run
time, the setting of the BeanContext is forced on the Bean:
if (bean instanceof java.beans.DesignMode) {
java.beans.DesignMode bdm =
(java.beans.DesignMode)bean;
boolean bcdmode =
(boolean)(
(DesignMode)getBeanContextProxy().isDesignTime();
bdm.setDesignTime(bcdmode);
}
|
It gets more interesting when we look at the implementation of the BeanBox
as a BeanContextServiceProvider. In the BeanBox constructor an
anonymous inner class is used to implement the basics:
public BeanBox() {
....
bcss.addService(
sunw.demo.methodtracer.MethodTracer.class,
new BeanContextServiceProvider() {
public Object getService(
BeanContextServices bcs,
Object requestor,
Class serviceClass,
Object serviceSelector) {
mt.logText("Method Tracing service
requested by:\n " +
requestor.getClass().toString());
return mt;
}
public void releaseService(
BeanContextServices bcs,
Object requestor,
Object service) {
mt.logText("Method Tracing service
released by\n " +
requestor.getClass().toString());
}
public Iterator getCurrentServiceSelectors(
BeanContextServices bcs,
Class serviceClass) {
return null;
}
});
}
|
The service itself is implemented in MethodTracer.java:
public final class |
The method tracing service is only active and visible while the
BeanContext is in design time. This is controlled
by adding it as a PropertyChangeListener to the
BeanContextServiceProvider in BeanBox's constructor.
public void propertyChange(
PropertyChangeEvent evt) {
if (evt.propertyName().equals("designMode")) {
boolean dmode =
((Boolean)evt.getNewValue().booleanValue();
setDesignTime(dmode);
}
}
public void setDesignTime(boolean dmode) {
if (this.isVisible() != dmode) setVisible(dmode);
}
public boolean isDesignTime() {
return isVisible();
} |
The Juggler Bean uses the BeanContext provided by the BeanBox
to request the method tracing service. To do this, the Juggler is created as a
BeanContextChild, which will attach itself as a listener for
BeanContextServices events so that it stays abreast of when the
service is available and when it is being revoked. The Juggler uses the
BeanContextChildSupport helper class to do most of the work.
It also monitors the designTime toggle to suspend
usage of the service during run time.
public class Juggler extends Applet implements
Runnable,
BeanContextProxy,
BeanContextServicesListener,
PropertyChangeListener,
DesignMode {
private BeanContextChildSupport bccs =
new BeanContextChildSupport() {
protected void initializeBeanContextResources() {
try {
BeanContextServices bcs =
(BeanContextServices)bccs.getBeanContext();
if (bcs.hasService(MethodTracer.class) {
mtService =
(MethodTracer)bcs.getService(
getBeanContextProxy(),
Juggler.this,
MethodTracer.class,
null,
Juggler.this);
}else{
bcs.addBeanContextServicesListener(
Juggler.this);
}
bcs.addPropertyChangeListener(
"designMode", Juggler.this);
} catch (ClassCastException ex) {
// Nesting BeanContext is not a
// BeanContextServices so do nothing
} catch (Exception e) {
System.err.println("Error
initializing BeanContext resources.");
System.err.println(e);
}
}
protected void releaseBeanContextServices() {
if (mtService != null) {
mtService = mt = null;
}
try {
BeanContextServices bcs =
(BeanContextServices)getBeanContext();
bcs.removePropertyChangeListener("designMode",
Juggler.this);
bcs.removeBeanContextServicesListener(
Juggler.this);
} catch (Exception e) {
}
}
};
|
java.beans.Beans.instantiate() method was amended in
Java 2 to provide support for BeanContext API. Using this
method and passing in a reference to the BeanContext as
a third parameter leads to the instantiate() method invoking
BeanContextSupport.add() as a side effect. That method will
then invoke Juggler.getBeanContextProxy().setBeanContext()
which finally leads to initializeBeanContextResources() on
Juggler's BeanContextChildSupport field. Note that because
initialization of BeanContext resources is invoked from the
nesting BeanContext container, the Juggler applet will still run
outside of the BeanBox, where these services or the BeanContext
itself may not exist.
The Juggler's startJuggling() method is one of the methods that
uses the method tracing service:
public void startJuggling() {
if (mt != null) {
mt.traceMethod();
}
....
} |
Finally, the Juggler implements the BeanContextServices listener
interface as follows:
public void serviceRevoked(
BeanContextServiceRevokedEvent event) {
System.err.println(
"Method Tracing service revoked");
setDebug(false);
mtService =null;
}
public void serviceAvailable(
BeanContextServiceAvailableEvent event) {
if (event.getServiceClass() == MethodTracer.class) {
try {
mtService = (MethodTracer)
event.getSourceAsBeanContextServices().
getService(getBeanContextProxy(),
this,
MethodTracer.class,
null, this);
} catch (Exception e) {
System.err.println(e);
}
}
} |
In BDK 1.1, the use of the BeanContext API is illustrated.
The BeanBox itself is a BeanContext container and provides
a BeanContextService which is used by the Juggler Bean. The
source code for the BeanBox and the sample Beans is included in the BDK.
To fully understand this protocol you may want to read up on the BDK specification.
Note:
BDK 1.1 requires Java 2 Standard Edition SDK (formerly JDK 1.2), which can be downloaded from java.sun.com
http://java.sun.com/products/jdk/1.2/.
Please email any feedback or questions to java-beans@java.sun.com.
Onno Kluyt began his career writing software for PCs and Macintoshes. Nowadays he fills his time as product manager for JavaBeans Technology and JFC.
|
| ||||||||||||