Trail: JavaBeans(TM)
Lesson: Using the BeanContext API
Bean Context #2: Containment and Services
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:

  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:

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:

File: DocumentBean.java


import java.beans.beancontext.*;
import java.io.*;
import java.util.*;

public final class DocumentBean extends BeanContextChildSupport {

    private File document; 
    private BeanContextServices context;

    public DocumentBean(String fileName) {
        document = new File(fileName);
    }

    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) { }
        }        
    }

    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.*;

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


public interface WordCount {

     public abstract void countWords();

}

File: DocumentTester.java


import java.beans.beancontext.*;
import java.util.*;

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]
Previous page: Bean Context #1: Containment Only
Next page: AWT Containers and the BeanContextProxy Interface