Home Page
>
JavaBeans(TM)
>
Using the BeanContext API
Bean Context #2: Containment and Services
As mentioned in the introduction, the BeanContext API also provides a
standard mechanism through which JavaBeans can discover and utilize the
services offered by their enclosing BeanContext.
Service capability is defined by the
BeanContextServices
interface. Because this interface is a BeanContext extension, it inherits all
BeanContext membership capabilities.
The discovery and
requesting of services can be summarized in the following steps:
- A JavaBean that implements the
java.beans.beancontext.BeanContextServicesListener interface joins the bean context (the context itself
is a BeanContextServices implementation),
and registers its intent to be notified of new services via the context's
addBeanContextServicesListener(BeanContextServicesListener bcsl) method.
- A
java.beans.beancontext.BeanContextServiceProvider registers
a new service with the context via the
context's addService() method. The context notifies
all currently registered listeners that this new service has been added.
- After being notified of the newly available service,
the listening JavaBean requests an instance of the service
from the context.
- The context tells the service provider to deliver the service to the requesting JavaBean.
BeanContextServices: Service Related Methods
Using a
java.beans.beancontext.BeanContextServicesSupport object as the bean context, it is possible to:
- Add a service to this
BeanContext:
boolean addService(java.lang.Class serviceClass, BeanContextServiceProvider serviceProvider)
- Add a service to this
BeanContext:
boolean addService(Class serviceClass, BeanContextServiceProvider bcsp, boolean fireEvent)
- Revoke a service:
void revokeService(java.lang.Class serviceClass, BeanContextServiceProvider serviceProvider, boolean revokeCurrentServicesNow) - Release a
BeanContextChild's (or any arbitrary object associated with a BeanContextChild) reference to the specified service:
void releaseService(BeanContextChild child, java.lang.Object requestor, java.lang.Object service) - Add a
BeanContextServicesListener
void addBeanContextServicesListener(BeanContextServicesListener bcsl) - Remove a
BeanContextServicesListener:
void removeBeanContextServicesListener(BeanContextServicesListener bcsl)
- Get the currently available services for this context:
Iterator getCurrentServiceClasses()
- Determine whether or not a given service is currently available from this context:
boolean hasService(java.lang.Class serviceClass)
- Get a service from the context:
Object getService(BeanContextChild child, java.lang.Object requestor, java.lang.Class serviceClass, java.lang.Object serviceSelector, BeanContextServiceRevokedListener bcsrl)
- Get the list of service dependent service parameters (Service Selectors) for the specified service:
Iterator getCurrentServiceSelectors(java.lang.Class serviceClass)
Service Event Notification
JavaBeans nested into a BeanContextServices implement BeanContextServicesListener
to listen for new services
being added, and/or BeanContextServiceRevokedListener to listen for services being revoked.
There are two event types that may be intercepted by such listeners:
The Service Provider
JavaBeans can query their enclosing bean context for a list of available services, or ask for a specific service
by name. The service itself, however, is actually delivered by a BeanContextServiceProvider.
The provider can be any object that implements the
java.beans.beancontext.BeanContextServiceProvider interface. Services
become available in a context via the bean context's addService() registration method.
BeanContextServiceProvider offers the following three methods, which will be automatically called when a bean requests (or releases) a service from its context:
The Service
The service itself is best described by this paragraph from the specification:
A service, represented by a Class object,
is typically a reference to either an interface,
or to an implementation
that is not publicly instantiable.
This Class defines an interface protocol or contract
between a BeanContextServiceProvider,
the factory of the service,
and an arbitrary object associated with a BeanContextChild
that is currently
nested within the BeanContext the service is registered with.
The following section presents a sample application that uses a word
counting service to count the number of words in a given text file.
A Word Counting Service Example
The classes defined in this sample application are:
-
DocumentBean.java: A JavaBean that encapsulates a File object. Create an instance of this bean by passing it
a String indicating the name of the text file to represent. This bean extends BeanContextChildSupport, which allows
it to listen for addition/revocation of services in its context. When the bean detects that a
WordCount service
has been added to the context, it requests the service to count the number of words it contains.
-
WordCountServiceProvider.java: A class that acts as the
factory for delivering the WordCount service. This
class implements the BeanContextServiceProvider interface.
-
WordCount.java: This interface defines the service itself.
-
DocumentTester.java: The main test program.
File:
DocumentBean.java
import java.beans.beancontext.*;
import java.io.*;
import java.util.*;
/**
* A JavaBean that encapsulates a text file. When added to a bean context,
* this bean listens for a WordCount service to become available. When
* the service does become available, the DocumentBean requests an
* instance of the service. The service then counts the number of words in the file,
* and prints a report to standard output.
*/
public final class DocumentBean extends BeanContextChildSupport {
private File document;
private BeanContextServices context;
/**
* Creates a new DocumentBean given the name of the file to read from.
* @param fileName the name of the file to read from
*/
public DocumentBean(String fileName) {
document = new File(fileName);
}
/**
* Called when this bean detects that a new service
* has been registered with its context.
*
* @param bcsae the BeanContextServiceAvailableEvent
*/
public void serviceAvailable(BeanContextServiceAvailableEvent bcsae) {
System.out.println("[Detected a service being added to the context]");
// Get a reference to the context
BeanContextServices context = bcsae.getSourceAsBeanContextServices();
System.out.println("Is the context offering a WordCount service? "
+ context.hasService(WordCount.class));
// Use the service, if it's available
if (context.hasService(WordCount.class)) {
System.out.println("Attempting to use the service...");
try {
WordCount service = (WordCount)context.getService(this, this,
WordCount.class, document, this);
System.out.println("Got the service!");
service.countWords();
} catch(Exception e) { }
}
}
/**
* Called when this bean detects that a service
* has been revoked from the context.
*
* @param bcsre the BeanContextServiceRevokedEvent
*/
public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) {
System.out.println("[Detected a service being revoked from the context]");
}
}
File:
WordCountServiceProvider.java
import java.beans.beancontext.*;
import java.util.*;
import java.io.*;
/**
* This class is the factory that delivers a word counting service.
* The 3 methods defined in this class are the concrete implementations
* of the BeanContextServiceProvider interface. For this demonstration, the primary
* method of interest is getService(). The getService() methods returns a new
* WordCount instance. It is called by the bean context when a nested
* JavaBean requests the service.
*/
public final class WordCountServiceProvider implements BeanContextServiceProvider {
public Object getService(BeanContextServices bcs,
Object requestor,
Class serviceClass,
Object serviceSelector) {
// For this demo, we know that the cast from serviceSelector
// to File will always work.
final File document = (File)serviceSelector;
/* Return an instance of the service. The service itself is
* the WordCount interface, which is implemented here using
* an anonymous inner class.
*/
return new WordCount() {
public void countWords() {
try {
// Create a Reader to the DocumentBean's File
BufferedReader br = new BufferedReader(new FileReader(document));
String line = null;
int wordCount = 0;
while ((line = br.readLine()) != null) {
StringTokenizer st = new StringTokenizer(line);
while (st.hasMoreTokens()) {
System.out.println("Word " + (++wordCount)
+ " is: " + st.nextToken());
}
}
System.out.println("Total number of words in the document: "
+ wordCount);
System.out.println("[WordCount service brought to you by WordCountServiceProvider]");
br.close();
} catch(Exception e) { }
}
};
}
public void releaseService(BeanContextServices bcs,
Object requestor,
Object service) {
// do nothing
}
public Iterator getCurrentServiceSelectors(BeanContextServices bcs, Class serviceClass) {
return null; // do nothing
}
}
File:
WordCount.java
/**
* The WordCount service. Implementations of the
* countWords() method are provided by the
* WordCountServiceProvider class.
*/
public interface WordCount {
/**
* Counts the number of words in the file.
*/
public abstract void countWords();
}
File:
DocumentTester.java
import java.beans.beancontext.*;
import java.util.*;
/**
* A test program that creates all of the objects,
* a tests the service capabilities. Run this program
* from the command line using java DocumentTester
*/
public class DocumentTester {
public static void main(String[] args) {
BeanContextServicesSupport context = new BeanContextServicesSupport(); // a bean context
DocumentBean doc1 = new DocumentBean("Test.txt");
context.add(doc1);
context.addBeanContextServicesListener(doc1); // listen for new services
WordCountServiceProvider provider = new WordCountServiceProvider();
context.addService(WordCount.class, provider); // add the service to the context
}
}
File:
Test.txt
This text will be analyzed
by the WordCount
service.
Output:
[Detected a service being added to the context]
Is the context offering a WordCount service? true
Attempting to use the service...
Got the service!
Word 1 is: This
Word 2 is: text
Word 3 is: will
Word 4 is: be
Word 5 is: analyzed
Word 6 is: by
Word 7 is: the
Word 8 is: WordCount
Word 9 is: service.
Total number of words in the document: 9
[WordCount service brought to you by WordCountServiceProvider]