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.
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.
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.
BeanBagModel model = new BeanBagModel(); model.loadFromRepository(null, "repositoryX");
ManagedBean mb; ... // initialize mb somehow model.add(mb); model.select(mb);
if (model.isSelected(mb))
for (Enumeration ese = model.doGetSelected().elements(); ese.hasMoreElements(); ) { ManagedBean mbean = (ManagedBean)ese.nextElement(); if (mbean ...) ... }
model.selectNone();
model.selectAll(); model.doRemove();
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.
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); } }
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:
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".
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();
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.
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.
beans.directory:[drive_letter:]/<path>where drive_letter is the letter of the drive assignment (optional) and path is the path for the directory repository. For example: beans.directory:f:/path/to/DirectoryRepository
beans.jar:[drive_letter:]/<path><JAR_filename>where drive_letter is the letter of the drive assignment (optional), path is the path for the directory repository, and JAR_filename is the name of the JAR file. For example: beans.jar:/path/to/JARRepository.jar
beans.zip:[drive_letter:]/<path><zip_filename>where drive_letter is the letter of the drive assignment (optional), path is the path for the ZIP repository, and zip_filename is the name of the ZIP file. For example: beans.zip:/path/to/ZipRepository.zip
beans.net://<hostname[:port]>/<servername>/[<item-key>]
For example:
beans.net://repoman.ibm.com/myServer/myClass.class
to specify a repository by class name, or
beans.net://repoman.ibm.com/myServer/CA2718A8128B3141C1618D0618E0496F
to specify a repository by warehouse item id. The hostname or servername value may be an asterisk "*", in which case a locally configured default value will be used. For additional information, see "Network Deployment".
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. |
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.
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.
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>. |
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.
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();
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.
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).
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_repositorywhere 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.jarmerges 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.
The gel application can be used to convert between different repository formats. For example:
java gel my_zipfile.zip my_jarfile.jarconverts 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.
The gel application can be used to expand repositories. The command:
java gel my_jarfile.jar .is equivalent to:
jar xvf my_jarfile.jarexcept the manifest file contains Bean Extender enhancements.
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.jarcreates 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:
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:
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; } }
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.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; } }
For instance, for our running example the line would be:repository.pkgs=<protocol_package>;<protocol_name>;<factory_class>
If two or more custom RepositoryModels are being added, the triplets are separated by the bar '|' character:repository.pkgs=com.companyname;beans.xxx;com.companyname.XXXRepositoryModelFactory
repository.pkgs=<pac1>;<pro1>;<fac1>|<pac2>;<pro2>;<fac2>...
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 -Of course, this is just a suggestion, and the developer can use whatever kind of URL naming scheme they decide they want to parse.Custom repositories may also be network enabled, in which case the following scheme is recommended:beans.xxx:[drive_letter:]/<path>/<filename>For example:
beans.xxx:f:/this/is/a/path/to/a/XXXRepositoryNetXXXRepositoryModel -
beans.xxx://<hostname>/[<path>]/<filename>For example:
beans.xxx://xxxserver.austin.ibm.com/this/path/BigXXX.suffix