Bean Extender Guide to Features


Bean Management

Bean Management functions address problems facing tool developers. Specifically, it helps developers who are writing tools that operate on beans. Developers can perform the following tasks with Bean Management:

Bean Management is designed for use within tool programs. The components of Bean Management are model and view objects. The model objects provide basic selection and command separation. The view objects operate on the model objects using AWT components. The communications between the view and its container or controller are through standard Java events.

Bean Management consists of:

The dialogs and user interfaces of Bean Management allow developers to select beans from a variety of repositories. Bean Management provides collection behavior to aggregate, select, and operate on beans from one or more repositories.

Bean Management provides a ManagedBean object as the basic handle for tools to use when operating on beans. The managed bean is extensible and flexible. The ManagedBean class provides full support for JavaBeans entities. These entities are the support files for the Java bean.

The Bean Management model objects use the functions of the BeanBag class and other classes without requiring view objects. Tool programs can integrate the Bean Management model objects into other models to present separate views for those models.

There are model classes for the BeanBag and for the repository. Each model class has associated event classes and event listener interfaces. The event sets are grouped into selection change events and model change events. Selection events occur when a call to a command method of the model changes the current selection of data within the model. Model change events occur when a call to a command or to a selection method of the model changes the data held within or managed by the model.

For additional information of these classes, see the Bean Extender API Reference.

Using BeanBag Objects

Bean Management provides support for applications to view collections of beans or stay informed of changes to the collections. This support is provided by:

Tool programs that use or manipulate beans generally use one or more BeanBagModel objects. However, it is not necessary to use the BeanBagView or DesktopBeanBagView class. The BeanBagModel class provides management of bean collections without requiring that any view be associated with them. A tool program requiring user interaction in the selection or manipulation of beans typically creates a view that listens to BeanBagModel-generated events and provides appropriate feedback.

Generally, there is not a one-to-one correspondence between files and beans.

Using BeanBag Models and Views

The BeanBagView class is a base class derived from java.awt.Container. It provides the foundation for viewers of a BeanBagModel object. The BeanBagView class defines methods that do the following:

Subclasses of BeanBagView can respond to key, mouse, and drag operations.

BeanBagView subclass implementations can obtain graphical information about the beans that they display through method provided by the ManagedBean class. For example, the BeanBagView.acquireMBIcon() method calls the ManagedBean.getIconInstance() method to obtain an image for a particular bean. The BeanBagView subclass DesktopBeanBagView uses the ManagedBean.getIconInstance() method to show icons for managed beans contained in its BeanBagModel object. The DesktopBeanBagView class also calls the ManagedBean.getBeanName() method to display the name of a particular managed bean with its corresponding icon.

The following code is from the DesktopBeanBagView.addIcon() method. This method uses the LabeledIcon class to graphically represent the passed ManagedBean object in its view. The addIcon() method calls the inherited acquireMBIcon() method to get the icon.

{
  // create LabeledIcon from ManagedBean
  LabeledIcon bi = new LabeledIcon(mb, acquireMBIcon(mb), mb.getBeanName(), iconStyle);
  // listen for action events on icon
  bi.addActionListener(this);
  // add icon to collection
  icons.addElement(bi);
  // add icon to view
  add(bi);
}

The BeanBagModel is selection- or command-based and supports selection by repository, by repository association, and by typical interactive selection. The following commands are supported by the BeanBag model:

When a BeanBagModel object's contents change, it generates a ModelChangeEvent object and dispatches it to listeners registered by the addModelChangeListener() method. When a BeanBagModel object's selection changes, it generates an ItemEvent object and dispatches it to listeners registered by addItemListener() method.

The following code sections show typical usage of BeanBagModel command methods and selections.

A BeanBagModel object can contain ManagedBean instances that have been loaded from multiple repositories, even from multiple repository models. The BeanBagModel object operates on the correct repository by examining the repository name stored in each ManagedBean object it contains. However, all repositories accessed by a given BeanBagModel object must be accessed in the same mode (read-only, write-only, or read-write mode). The BeanBagModel object raises an exception if the repositories are not accessed in the same mode.

Supporting BeanBag Events

A BeanBagModel object does not require that managed beans be added only by reading them from a repository. Tool programs can generate managed beans through their own mechanisms and add them to a BeanBagModel object.

As command methods are called on a BeanBagModel object, causing a content change, the BeanBagModel object sends ModelEvent objects to notify registered ModelChangeListener objects. Likewise, as selection methods are called on a BeanBagModel object, it sends corresponding ItemEvent objects to registered ItemListener objects.

BeanBagModel events contain a reference to the source BeanBagModel object and a Vector that contains the relevant set of ManagedBean objects. For example, if a selection occurs in a BeanBagModel object that causes several managed beans to be selected, then a Vector is constructed containing those managed beans. This Vector is then used to construct the ItemEvent object.

If a change occurs in the contents of a BeanBagModel object as a result of a command method, then the BeanBagModel constructs a ModelEvent containing a Vector of the managed beans that changed. For example, if a command method causes several managed beans to be removed from the BeanBagModel object, then a Vector is constructed containing the removed managed beans. This Vector is then used to construct the ModelEvent object.

The ModelChangeListener interface should be implemented by classes that need to be notified of changes to a BeanBagModel object's contents. Classes that implement this interface are called when managed beans are added to or removed from the BeanBagModel object or when the repository-access mode of the BeanBagModel is changed.

The ItemListener interface should be implemented by classes that need to be notified of changes to the BeanBagModel selection. Classes that implement this interface are notified when managed beans are added to, or removed from, the selection.

The following code shows how a class implementing ItemListener could handle a selection change notification from a BeanBagModel:

public void itemStateChanged(ItemEvent e)
  {
    if (e.getItemSelectable() instanceof BeanBagModel) {
       BeanBagModel bbm = (BeanBagModel) e.getItemSelectable();
       Vector selectedMBs = bbm.doGetSelected();
       // Call setSelectedIcons() method to cause all the
       // icons associated with the managed beans passed
       // in the ItemEvent to indicate selection.
       setSelectedIcons(selectedMBs);
    }
  }

Using Repository Models and Managed Beans

Generally, a programmer performing Bean Management interacts with the BeanBag views and models. However, for finer granularity, a programmer must use and understand the underlying structure of repository model (RepositoryModel) objects, managed bean (MB) objects, and managed bean element (MBE) objects. The basic underlying structure for Bean Management is:
* Figure mgbean01 not displayed.
The repository model contains zero or more managed bean objects. Each managed bean contains one or more managed bean elements.

The architectural concept of Bean Management is that a repository is read into a repository model. The repository model creates a managed bean (ManagedBean) object for each bean in the repository and creates a managed bean element (MBElement) object for each file that makes up each bean. For additional information on these components, see "Using Repository Models", "Using Managed Beans", and "Using Managed Bean Elements".

Using Repository Models

A repository model is one of the variety of models into which a repository is read. The following repository models are currently available:
DirectoryRepositoryModel The class that defines the model that reads and writes file system directory repositories. Basically, a directory repository is the equivalent to an unarchived JAR file. If the directory repository does not contain a manifest, this model performs "best guessing" about the contents of the repository. That is, this models tries to make logical guesses about which items are beans and which items are miscellaneous support files.
JarRepositoryModel The class that defines the model that reads and writes JAR file repositories. The JAR file must contain a manifest.
ZipRepositoryModel The class that defines the model that reads and writes ZIP files. The ZIP repository does not always contain a manifest. If there is a manifest, this model uses it. If the ZIP repository does not contain a manifest, this model performs "best guessing" about the contents of the repository. That is, this model tries to make logical guesses about which items are beans and which items are miscellaneous support files.
NetRepositoryModel The class that defines the model that reads JAR and ZIP file repositories over the network using Network Deployment functions. At this time, the NetRepositoryModel is READ-ONLY. For additional information, see "Network Deployment".

These repository models provide ModelChange and SelectionChange event support by implementing RepositoryModelChangeListener and RepositorySelectionChangeListener:

Managed beans within a repository model are operated on using a selection-doAction method paradigm. For example, the following code segment:

repo.selectManagedBean(MyMB);
ManagedBean mba[] = doGetManagedBeans();
repo.doDelete();

Obtaining a Repository Model

Repository models should be obtained from the RepositoryModelFactory class using the createRepositoryModel() method. When the repository model is no longer in use, it should be disposed of using the destroyRepositoryModel() method.

When you want to read a repository, you must use the doOpen() method. The doOpen() method opens the repository model and reads in the data from a specific repository. However, the doOpen() method works only for repositories that have read-only or read-write access.

When you want to write a repository model, you must use the doClose() method. The doClose() method writes the repository model to a specific repository. However, the doClose() method works only for repositories that have write-only or read-write access.

The standard flow of control for a repository model is:

RepositoryModelFactory.initialize();
RepositoryModel repo = RepositoryModelFactory.createRepositoryModel();
repo.doOpen();      // reads the repository, if necessary
// code that manipulates the ManagedBean and MBElement objects
repo.doClose();     // writes the repository, if necessary
RepositoryModelFactory.destroyRepositoryModel(repo);

Note that the BeanBagModel constructors all call RepositoryModelFactory.initialize(), so if you are working with BeanBagModels, you won't need to explicitly call the initialize() method.

Naming a Repository

When you create a repository, there are two ways to name it. You can use an interface to open local JAR file and directory repositories by providing a String containing the name of the repository path. You can use a URL to specify the full range of supported repositories, both local and remote. The following is a list of repository models; including the syntax for specifying its URL and a naming example.

There are versions of the createRepositoryModel() method that accept the URL either as an object or as a String.

A repository can be opened and accessed by multiple repository models in read-only mode, but only a single repository model should open and access a repository in read-write or write-only mode.
Note:Because Java does not provide any file locking mechanism, there is no way to prevent a repository model in another application from opening and accessing a repository currently being used in read-write or write-only mode.

Using Managed Beans

Like managed beans in a repository model, the selection-doAction method paradigm is used to operated on managed bean elements within a managed bean. Similarly, these managed beans provide ModelChange and SelectionChange event support by implementing change Listener support.

The MBModelChangeListener interface is provided for classes that must be notified of changes to the managed bean. Classes that implement this interface are sent ModelChange events when elements are added to or removed from the managed bean.

The MBSelectionChangeListener interface is provided for classes that must be notified of changes to the selection of the managed bean. Classes that implement this interface are sent SelectionChange events when:

You can use the ManagedBean class methods getIconInstance(), getBeanInstance(), getBeanInfoInstance(), and getBeanCustomizerInstance() to instantiate beans and selected parts of beans.

Using Managed Bean Elements

The elements of a managed bean are the structure and support files associated with a bean before it was read from the repository into the repository model. Elements can also be added to a constructed bean programmatically. The MBElementFactory class contains methods that are helpful for creating and copying managed bean elements.

Each element associated with a managed bean is identified by a moniker. A moniker is the name and path of the file element that the managed bean element represents. This moniker is contained in an object of class MBMoniker.

The following code copies a specific managed bean from one repository model to another. It also prints the moniker for each element of each managed bean:

RepositoryModel r; // repository to read
RepositoryModel w; // repository to write
// select and get a managed bean
 
r.selectManagedBean(new MBMoniker("sunw/demo/buttons/OrangeButton.class"));
ManagedBean mba[] = r.doGetManagedBeans();
 
// select all managed bean elements and print their monikers
 
mba[0].selectAll();
MBElement mbea[] = mba[0].doGetElements();
for (int i = 0; i < mbea.length; i++)
    System.out.println("MBElement moniker: " +
                         mbea[i].getMBMoniker().toString());
 
w.doAdd(mba);

There are various subclasses of the MBElement class. These subclasses provide type-dependent access to the managed bean elements. The MBElement class is the parent class for the following MBElement subclasses:

When a repository is opened, the repository model assigns the files that make up each bean to a subclass of MBElement. This process is facilitated by using the Bean Extender enhanced manifest file extensions that provide structure and type information for the beans and bean elements listed in the manifest (MANIFEST.MF). This manifest information is generated when Bean Management writes the repository models. For additional information, see "Using Bean Extender Enhanced Manifest File Extensions".

The MBElement methods setProperty(), getProperty(), and removeProperty() allow the user to manipulate a list of <key, value> pairs associated with each MBElement. These properties are written out to the manifest file when the RepositoryModel is written.

Policy and Heuristics

The setPolicy() method allows the user to specify that the Bean Management subsystem should strictly adhere to the JavaBeans spec, or that the Bean Management subsystem should use heuristics to determine ManagedBean structure.

STRICT_SPEC policy means:

ENHANCED_SPEC policy means if there is no Manifest file, the RepositoryModel will be populated using heuristics to determine which MBElements are Beans, BeanInfos, Customizers, etc. This is the default policy.

The default policy is ENHANCED_SPEC.

When a RepositoryModel contains no beans, it will contain a single ManagedBean whose bean name is <NoBean>.

If the policy is ENHANCED_SPEC and there is no manifest, or if the manifest does not provide structure and type information, the repository model performs "best guessing" about the contents of the repository. That is, the model tries to make logical guesses about which items are beans and which items are miscellaneous support files.
Note:If there is no manifest, each directory within a repository is assumed to contain only one bean. In the even that the heuristics are unable to determine the identity of a bean, the bean name will be set to <UnknownBean>.

Using Common Elements

If a manifest file does not contain sufficient information for the repository model to determine the files associated with each bean, common elements are created. When common elements are created, each common element is associated with every bean in the repository model. Generally, common elements are created when the manifest file does not use Bean Extender enhanced manifest file extensions or the JavaSoft Depends-On tag. If you do not use Bean Extender enhanced manifest file extensions or Depends-On, the software cannot determine the elements associated with each bean.

The following diagram depicts the programmatic hierarchy including the common elements.
* Figure mgbean02 not displayed.

You can use common elements when you want each bean within a repository model to contain specific common files. For example, you can use common elements if several beans within the repository model use the same code to display an image. Each file that comprises the common code becomes a managed bean element (MBElement) common to all beans in that repository model.

Common elements are treated separately from "uncommon" elements. For example, to return all elements, common and uncommon, from a managed bean, you can use the following code:

mb.selectAll();
MBElement mbe[] = mb.doGetElements();
mb.selectCommonAll();
MBElement cmbe[] = mb.doGetCommonElements();

Using Bean Extender Enhanced Manifest File Extensions

The Bean Extender enhanced manifest file extensions allow you to unambiguously specify structural information for each element. Basically, this structural information assigns a specific element to a specific bean. Using the Bean Extender enhanced manifest file extensions, you can assign a type to each element. You assign a type to an element by extending the file specification for the manifest to include a key-value pair.

The syntax for a file extension assignment is:

MBInstN: <element_type_description>
where N is an arbitrary unique integer corresponding to a bean in the repository, and element_type_description is a tag that indicates the type of the element file.

To illustrate the differences between a Sun-style manifest and a Bean Extender enhanced manifest, examine how each of the following beans and its file elements are entered into its respective manifest.

The following table provides a side-by-side view of the Sun-style and the Bean Extender enhanced manifests:

Sun-Style Manifest

Bean Extender Enhanced Manifest

Java-Bean: true
Name: MyBean.class
 
 
Name: MyBeanBeanInfo.class
 
 
Name: MyBeanIcon16.gif
 
 
Java-Bean: true
Name: YourBean.class
 
 
Name: YBCustomizer.class
 
 
Name: MyBeanIcon32.gif
 
 
Java-Bean: true
Name: OurBean.ser
 
 
Name: MyBeanCustomizer.class	
 
 
Name: Coffee.data

Java-Bean: true
Name: MyBean.class
MBInst0: BeanClass
 
Name: MyBeanBeanInfo.class
MBInst0: BeanInfoClass
 
Name: MyBeanIcon16.gif
MBInst0: BeanIcon
 
Java-Bean: true
Name: YourBean.class
MBInst1: BeanClass
 
Name: YBCustomizer.class
NBInst1: BeanCustomizerClass	
 
Name: MyBeanIcon32.gif
MBInst0: BeanIcon
 
Java-Bean: true
Name: OurBean.ser
MBInst2: BeanSer
 
Name: MyBeanCustomizer.class	
MBInst0: BeanCustomizerClass	
 
Name: Coffee.data
MBInst0: OtherFile
MBInst2: OtherFile

Using the Bean Extender enhanced manifest file extensions allows you to easily determine the file elements associated with each bean. With each file element entry is its associated explicit type information. Each file element containing MBInst0 in its paragraph is part of the same bean (MyBean). Because MyBean.class, MyBeanBeanInfo.class, MyBeanIcon16.gif, MyBeanIcon32.gif, MyBeanCustomizer.class, and Coffee.data all contain MBInst0, all these file elements comprise the MyBean object. Therefore, you can use this manifest to accurately and reliably assign elements to the correct managed bean.

The user may select the output manifest style with the RepositoryModel method setManifestStyle(). The default is both IBM enhanced and JavaSoft style combined, with MBInstN tags as illustrated above combined with the JavaSoft Depends-On tag for structural information.

Reading Repositories
Bean Management will read and attempt to make sense of virtually any kind of JAR, ZIP, or Directory repository with any kind of MANIFEST.MF file. Specifically:

Managing Distribution and Deployment

When working with repositories, you can manage the distribution and deployment of various repositories using the Bean Extender gel application. You can use the gel application to perform the following tasks:

The manifests produced with the gel application contain both Bean Extender enhanced tags (MBInst) and regular JavaSoft tags (Depends-On).

Merging Repositories

When you create a new bean that is stored in a repository other than the storage locations of the original beans, it may be necessary to merge several repositories into a single repository. By using a single repository, you do not need to be concerned about the dependencies among the beans in the various repositories.

The gel application can merge several repositories into a single repository. The syntax is:

java gel repository1 ... repositoryN output_repository
where repository1 to repositoryN are the names of the various repositories to be merged and output_repository is the name of the resulting merged repository.
Note:The output_repository can have the same name as one of the source repositories.

For example, the command:

java gel my_repository.jar helper_repository.jar my_repository.jar
merges my_repository.jar and helper_repository.jar into my_repository.jar.

The file extension of the repository name determines the type of repository; however, you can merge repositories of different types. The gel application manages all the required type conversions.

Converting Repositories

The gel application can be used to convert between different repository formats. For example:

java gel my_zipfile.zip my_jarfile.jar
converts a zip file repository to a JAR file repository. If the zip repository file did not contain a manifest file, the gel application will produce an IBM Bean Extender enhanced manifest file.

Expanding Repositories

The gel application can be used to expand repositories. The command:

java gel my_jarfile.jar .
is equivalent to:
jar xvf my_jarfile.jar
except the manifest file contains Bean Extender enhancements.

Creating Repositories

If you have a directory tree that contains one or more beans and an optional manifest file, you can use the gel application to create a JAR file repository. For example:

java gel my_directory my_new_jar_repository.jar
creates a JAR repository file using the contents from the directory tree named my_directory.

If the manifest file exists, it must reside be located in my_directory/META-INF/MANIFEST.MF. If the manifest does not exist, the gel application will create a Bean Extender enhanced manifest file using "best guess" assumptions. That is, the gel application will create a manifest using the assumptions that there is one bean only in each subdirectory and that the bean element files are named rationally.

For example, the gel application uses the file name elements for:

MyBean.class
MyBeanBeanInfo.class
MyBeanIcon16.gif
MyBeanIcon32.gif
MyBeanCustomizer.class

to make the assumptions that:

Registering User-Written RepositoryModels

In addition to the supplied local and network JAR, ZIP, and Directory RepositoryModels, a user may wish to write their own custom RepositoryModel and have it be employed by the Bean Management system. This section details the steps involved:

  1. Write the RepositoryModel. For purposes of this discussion, this will be referred to as the XXXRepositoryModel. The XXXRepositoryModel must be a subclass of the RepositoryModel class. The developer might wish to write two versions of XXXRepositoryModel, a local version and a network-enabled version (called NetXXXRepositoryModel).

  2. Write a RepositoryModelFactory. This will be called XXXRepositoryModelFactory. This factory must implement RepositoryModelFactoryInterface. Here is a sample XXXRepositoryModelFactory:
    package com.companyname;    // for the sake of this discussion
    
    import java.lang.InstantiationException;
    import java.lang.ClassNotFoundException;
    import java.net.MalformedURLException;
    import java.net.URL;
    <other imports go here>
    
    public class XXXRepositoryModelFactory 
                 implements RepositoryModelFactoryInterface {
    
        public RepositoryModel createRepositoryModel(URL url,
                                                     int mode) 
                               throws NoSuchMethodException,
                                      InstantiationException,
                                      IllegalAccessException,
                                      MalformedURLException {
    
            RepositoryModel r = null;
            String protocol = url.getProtocol();
            String host = url.getHost();
            int port = url.getPort();
            String file = url.getFile();
            String ref = url.getRef();
            String urlString = url.toExternalForm();
    
            if (protocol.equals("beans.xxx")) {
                if (host.equals("")) 
                    r = new XXXRepositoryModel(url, mode);
                else // if host is present, it's a network RepositoryModel
                    r = new NetXXXRepositoryModel(url, mode);
            }
            else {
                System.err.println("Error! Invalid protocol: "+urlString);
            }
    
            return r;
        }
    }
    

  3. The developer must appease the protocol checking code in the URL class by creating a protocol handler. For our purposes, this Handler can be a function-free stub such as:
    package com.companyname.beans.xxx;
    
    import java.net.URLConnection;
    import java.net.URL;
    import java.io.IOException;
    
    public class Handler extends URLStreamHandler {
    
        public URLConnection openConnection(URL u) throws IOException {
    	return (URLConnection)null;
        }
    }
    
    This stub must be compiled and present in the appropriate location. For this example, the directory com/companyname contains the RepositoryModelFactory, and the directory com/companyname/beans/xxx must contain the compiled Handler stub.

  4. Finally, the Bean Management system must be made aware of the new RepositoryModel(s). This is done by adding the repository.pkgs property to the BeanSystem.properties file located in your HOME directory. The syntax is:
    repository.pkgs=<protocol_package>;<protocol_name>;<factory_class>
    
    For instance, for our running example the line would be:
    repository.pkgs=com.companyname;beans.xxx;com.companyname.XXXRepositoryModelFactory
    
    If two or more custom RepositoryModels are being added, the triplets are separated by the bar '|' character:
    repository.pkgs=<pac1>;<pro1>;<fac1>|<pac2>;<pro2>;<fac2>...
    

    URL Conventions

    The custom RepositoryModel will be referenced via URL syntax. The selection mechanism within RepositoryModelFactory that determines which factory to use keys on the URL protocol, that is, beans.jar in beans.jar://www.repocity.com/pub/repos/myRepo.jar. The developer is free to use the rest of the URL fields (host, port, file, ref) in any way they deem appropriate. The protocol name be anything except a protocol name that is already taken, such as http, file, beans.jar, etc. We suggest using something close to the following scheme:

    XXXRepositoryModel -
    beans.xxx:[drive_letter:]/<path>/<filename>
    

    For example:

    beans.xxx:f:/this/is/a/path/to/a/XXXRepository
    
    Custom repositories may also be network enabled, in which case the following scheme is recommended:

    NetXXXRepositoryModel -

    beans.xxx://<hostname>/[<path>]/<filename>
    

    For example:

    beans.xxx://xxxserver.austin.ibm.com/this/path/BigXXX.suffix
    
    Of course, this is just a suggestion, and the developer can use whatever kind of URL naming scheme they decide they want to parse.


    [ Top of Page | Previous Page | Next Page | Table of Contents | Documentation Homepage ]