The JavaTM Tutorial

| Start of Tutorial > Start of Trail > Start of Lesson | Search Feedback Form

Trail: JavaBeans(TM)
Lesson: 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:

> 1. 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.
> 2. 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.
> 3. After being notified of the newly available service, the listening JavaBean requests an instance of the service from the context.
> 4. 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`:
> - 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:

> - `BeanContextServiceAvailableEvent`: received by the `BeanContextServicesListener` in order to identify the service being registered.
> - `BeanContextServiceRevokedEvent`: received by the `BeanContextServiceRevokedListener` in order to identify the service being revoked.

> 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:

> - `Object getService(BeanContextServices bcs, java.lang.Object requestor, java.lang.Class serviceClass, java.lang.Object serviceSelector)`
> - `Iterator getCurrentServiceSelectors(BeanContextServices bcs, java.lang.Class serviceClass)`
> - `public void releaseService(BeanContextServices bcs, java.lang.Object requestor, java.lang.Object service)` Release a service from any object that currently has a reference to it

> 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]

| Start of Tutorial > Start of Trail > Start of Lesson | Search Feedback Form