Bean Extender Guide to Features


Utilities

Bean Extender contains several utilities. These utilities help JavaBean programmers and assemblers. The utilities are:

The Dipping Interface

Java programmers and assemblers can dip their dippable bean instance using the dip tool. The dip tool interacts with JavaBeans visually in a graphical user interface. This tool can be invoked from either the command line or a builder tool such as the Assembly Surface.

The Dipping Interface relies on a programming interface of the Dipping Framework for dipping a dippable bean with a dip bean. When the Dipping Interface is invoked, it presents a dialog with:

When the dip tool is invoked from the command line, it presents a dialog with the following additional information:

The following graphic is the graphical interface presented by the dip tool.
* Figure dipgui02 not displayed.

Using Command Line Invocation

You can invoke the Dipping interface utility by typing the following command:

java com.ibm.beans.tools.dip.dip

The previous invocation is shortened to:

java dip

The default to a basic invocation reads the current directory and loads all the JAR files. However, you can:

The command line syntax for invoking the Dipping Interface, including input bean and output repository selections and operation mode is as follows:

java dip
     [-?]
     [-dir dir]                    [-withDir dir]                   [-toDir]     [-batch]
     [-jar jarFile]                [-withJar jarFile]               [-toJar]
     [-jarDir dir]                 [-withJarDir dir]                [-toOriginal]
     [-class moniker classFile]    [-withClass classFile]
     [-classInJar moniker jarFile] [-withClassInJar moniker jarFile]
     [-ser moniker serFile]        [-withSer moniker serFile]
     [-serInJar moniker jarFile]   [-withSerInJar moniker jarFile]

For example:

java dip -classInJar sunw/demo/jelly/Jelly \bdk\bars\jelly.jar 
         -withClassInJar com/ibm/beans/samples/dips/print/PrintDip \dip\jars\printdip.jar
         -toOriginal

For additional information on this command line syntax, see the following sections.

Specifying Input Bean Selections

You can pre-specify input bean selections by using one of the following optional arguments:

java dip -dir dir
         -jar jarFile
         -jarDir dir
         -class moniker classFile
         -classInJar moniker jarFile
         -ser moniker serFile
         -serInJar moniker jarFile

Specifying Dip Bean Selection

You can pre-specify dip Bean selections. To pre-specify the dip Bean selections, use one of the following optional arguments:

java dip -withDir dir
         -withJar jarFile
         -withJarDir dir
         -withClass classFile
         -withClassInJar moniker jarFile
         -withSer moniker serFile
         -withSerInJar moniker jarFile

Specifying Output Repository Selections

You can pre-specify output repository selections for the generated .class files. To pre-specify the output repository selections, use one of the following optional arguments:

java dip -toDir         dir
         -toJar         jarFile
         -toOriginal

Specifying Mode of Operation

You can optionally specify the Dipping Interface to perform operations in batch mode. The default is interactive.

java dip -batch

If you specify batch, the interface is displayed, but it does not pause even if it encounters an error.

Using the Dipping Process

Dipping processing occurs when you click on the Add Dip button or the Remove Dip button. Each of these processes is explained in the following sections.

Processing with Add Dip

On the Select Dip panel, click on the beans to dip and then click on the Add Dip button. For each dippable bean selected in the Select Bean(s) panel, the following processing occurs:

  1. An instance of the dippable bean is obtained or instantiated, if necessary.

  2. The customizer for the dip instance is displayed. When the customizer is closed, the dip instance is added to the dippable bean instance.

  3. If a location is specified, the bean is serialized to it.

Processing with Remove Dip

When you have selected the beans to remove from the Dips Applied panel, click on the Remove Dip button. However, not all dips can be removed, for example, the SecurityDip.

Programming to the Dipping Interface

Any Java builder application can invoke the Dipping Interface by constructing a new DipDialog object. The DipDialog class constructor takes a dippable instance as an argument. This same instance is the output of the dipping processes. In this case, the Select Bean(s) panel and the Select Location panel are not necessary.

For additional information on class DipDialog, see the Bean Extender API Reference.

The JarJava Class

The JarJava class define the utility that easily adds repositories to the CLASSPATH environment statement and prevents a ClassNotFound exception from being thrown. In many cases, the packaging and deployment functions of the Bean Extender technology handle beans directly from the JAR, zip, and other repositories. You generally do not have to install these repositories on your CLASSPATH environment statement. However, if the repository has a dependency on another repository, which is unknown to Bean Extender, a ClassNotFound exception can be thrown. Use the JarJava utility to resolve this problem.

The JarJava utility invokes the Java interpreter to execute the specified Java class name. The JarJava invocation takes the same arguments as the java command, but it handles the setting of the CLASSPATH environment statement. To use any JAR file or zip file in the directory, add that directory path to the CLASSPATH statement. The JarJava utility scans all directories in the CLASSPATH statement and automatically adds any JAR or zip file found in those directories to the CLASSPATH statement used by the Java interpreter.

The syntax for the JarJava application is:

java com.ibm.beans.tools.JarJava classname
These are the same arguments accepted on a java command.

For example, if the initial value of the CLASSPATH environment variable is:

u/classes:/u/lib/classes.zip:/u/jars
and the directory /u/jars contains a file named mybeans.jar; when the JarJava application is invoked with the command:
java com.ibm.beans.tools.JarJava MyJavaApp arg1 arg2 ... argN
the JarJava utility starts the child process with the command:
java -classpath /u/classes:/u/lib/classes.zip:/u/jars:/u/jars/mybeans.jar MyJavaApp

The LogStream Class

The functions of the LogStream class prefaces each message with a header that includes the date, the name of the log, and the name of the thread:

date:log name:thread name:log message
When a new LogStream object is created, it defaults to sending messages to System.err. Subsequently, the LogStream can be reset to use any OutputStream. The LogStream can write to System.err, a FileOutputStream, or the OutputStream of the socket.

There are two approaches to writing to logs:

However, there are problems with the java.rmi.server.LogStream class that are solved by using com.ibm.beans.util.LogStream class. These problems are that thejava.rmi.server.LogStream class:

Advantages of com.ibm.beans.util.LogStream

The APIs and logic of com.ibm.beans.util.LogStream mirror those of java.rmi.server.LogStream but with the following changes:

Example Code

import com.ibm.beans.util.LogStream;
import com.ibm.beans.util.MessageFormatter;
...
MessageFormatter mf = new MessageFormatter ("com.ibm.beans.myPkg.myBndl");
LogStream errorLog = LogStream.log ("MyErrorLog");
LogStream debugLog = LogStream.log ("MyDebugLog");
 
// messages in the debug log do not have to be NLS enabled.
debugLog.println ("First debug line");
 
// but here is one that is NLS enabled.
debugLog.println (mf, "bundleMsgHandle1");
 
// all error messages need to be NLS enabled.
errorLog.println (mf, "bundleMsgHandle2", arg1, arg2);
 
try
  {
    ...
  }
catch (Exception ex)
  {
    errorLog.println(mf, "bundleMsgHandle3");
    // you can print the stack to the error log
    ex.printStackTrace(errorLog);
  }
...

Bean Extender Log Initialization

Bean Extender uses three implementations of LogStream: an output log, an error log, and a debug log. The output log is logically System.out. The error log is logically System.err. The debug log is also logically System.out, but is separate from the output log so that it can be turned off. The output log and error log should always be output, but the debug log is only turned on to debug a problem. When you use the Configuration tool, the Logging tab can be used to adjust the settings of the Bean Extender logs.


* Figure log01 not displayed.

Each of the three logs allow the following configuration changes:

Name
Each log is uniquely identified by an ASCII name. Different logs can be combined into the same log by changing them so they have identical names.

For additional information on how the LogStream names are used, see the description of the com.ibm.beans.util.LogStream.log() method in the Bean Extender API Reference.

Level
This value is set to one of the three logging level constants defined in the com.ibm.beans.util.LogStream class:

SILENT
Specifies that nothing is written to the log, and the messages are sent to the bit bucket.
BRIEF
Specifies that the prefix is not added to the message.
VERBOSE
Specifies that prefix and message are printed to the OutputStream.

For additional information on class LogStream constants, see the Bean Extender API Reference.

Stream
Any of the three logs can be set to print to either System.out or System.err.

Also, a button is provided to allow the user to reset to installed settings. When this button is pressed, the three logs configuration values are reset to their initial installed settings. This button only effects the log configuration. It does not effect any thing else configured by the Configure tool.

The Merged Customizer

The MergedCustomizer implements a java.beans.Customizer and provides a way for a bean to nest multiple customizers in a single customizer. This single customizer is a notebook. The customizer is used by the Dipping Framework to merge dip customizers with the customizer of the original bean. The original customizer is placed on the first page of the notebook.

The following graphic is an example of a displayed merged customizer:


* Figure merged1 not displayed.

The MergedCustomizer is a customizer that implements the java.beans.Customizer interface. The Customizer interface is comprised of the following methods:

When the setObject() method is invoked on the MergedCustomizer:

The MergedCustomizer enforces all objects passed to the setObject() method to be MergeCustomizable objects. The MergeCustomizable interface is comprised of the following methods:

The Morphing Interface

Bean Extender provides Java programmers and assemblers the following ways to morph classes:

  1. The BeanMorpher
  2. The Morphing Interface

The BeanMorpher is a command line tool that is described completely in "Creating a Dippable Bean" and the Bean Extender API Reference.

The Morphing Interface is a GUI than can be invoked from the command line or from a builder tool such as the Assembly Surface. The Morphing Interface relies on the BeanMorpher of the Dipping Framework.

Using Command Line Invocation

You can invoke the Morphing Interface by typing the following command:

java com.ibm.beans.tools.dip.morph

The previous invocation is shortened to:

java morph

The defaults to a basic invocation are:

However, you can:

The command line syntax for invoking the Morphing Interface, including input source and output repository selections and operation mode is as follows:

Usage: java com.ibm.beans.tools.dip.morph -options
  -?                    Print this help message.
  -jarDir <dir>	        Load a directory of jar files.
  -jar <jarFile>        Load a jarFile.
  -repos <dir>          Load a repository directory.
                        A repository directory is a directory containing
                        an un-jared jar file including it's manifest file.
  -class <moniker classFile>    Load a specific class file,
                        giving it the specified moniker.
  -classInJar <moniker jarFile> Load a specific class from a jar file,
                        giving it the specified moniker.
  -toOriginal           Save the morphed class with the original class.
  -toJar <jarFile>      Save the morphed class in the specified jar file.
  -toRepos <dir>        Save the morphed class in the specified repository
                        directory.
  -hideOriginal         The original class should not be saved
                        with the newly morphed class.
  -modeless             The view of the morphing UI should not be modal.

For example:

java morph -classInJar sunw/demo/jelly/Jelly \bdk\jars\jelly.jar -toOriginal

For additional information on this command line syntax, see the following sections.

Specifying Input Source Selections

You can pre-specify the input source selections by using one of the following optional arguments. These arguments are mutually exclusive, only one is allowed.

java morph -repos dir
           -jar jarFile
           -jarDir dir
           -class moniker classFile
           -classInJar moniker jarFile

Specifying Output Repository Selections

You can pre-specify output repository selections for the generated .class files. To pre-specify the output repository selections, use one of the following optional arguments. These arguments are mutually exclusive, only one is allowed.

java morph -toRepos dir
           -toJar jarfile
           -toOriginal

Using the Morphing Process

When you invoke the Morphing Interface, it presents a dialog with three tabs:

The Main tab

The Main tab in the Morphing Interface presents the essentials of what is needed to morph a class.

The following graphic depicts the Main tab in the Morphing Interface.
* Figure morph01 not displayed.

Hierarchy of the new dippable class
You must select whether the new dippable class is to be created through inheritance or aggregation. The restrictions on creating a new dippable class through inheritance and aggregation are explained completely in "Creating a Dippable Bean".

If you select inheritance, the new dippable class is created as a child of the original class. The new dippable class is a "kind of" the original class. Anywhere the original class could be used, the new dippable class can be used.

If you select aggregation, the new dippable class is created implementing an interface, so you must also select an interface. You must first choose a class to be used to implement the function of the new dippable class, then you must choose an interface to the dippable class that is to be implemented. The new dippable class is a "kind of" the interface, and the original class is a "part of" the new dippable class that is used to implement the interface.

If the new dippable class is implemented using aggregation, the interface selected does not have to be the only interface of the class selected. If you would like to have the new dippable class implement more than one interface of the class, the additional interfaces can be entered using the Additional API option under the Advanced Customization tab.

Choosing inheritance or aggregation depends on what you want the new dippable bean to be. If you want it to be a dippable version of an existing class, you should use inheritance. If you want it to be a dippable version of an existing interface, you should use aggregation. Of course, restrictions on inheritance may force you to use aggregation. For example, if the original class is a final class then no child can be created, so you would consider aggregation. Similarly, restrictions on aggregation may force you to use inheritance. For example, if the interface you want to implement doesn't introduce the methods necessary to implement the interface, like java.lang.Cloneable or java.io.Serializable, you would consider inheritance.

Hide original bean(s)
You can optionally decide that the original class should not be labelled a "Java-Bean" in the manifest for the location that contains the new dippable class. A manifest is described in the "JAR File Format" documentation provided with the Java Development Kit. The original class will still exist in the same location as the dippable, but since it is not labelled a "Java-Bean" tools that read the manifest will consider the original class a supportive class and not include it in a list of beans.

Location of the new dippable class
You must decide where you want to store the class files for the new dippable class. You can store these class files in the same location as the original class, or you can store them in:

If you choose to store these files in a new JAR file or in a new repository directory, you must supply the name or locations in the corresponding text field.

A repository directory is a directory that contains an unjared JAR file, complete with a manifest.

The General Customization tab

The General Customization tab in the Morphing Interface present the general options for customization of the new dippable class.

The following graphic depicts the General Customization tab in the Morphing Interface.
* Figure morph02 not displayed.

Dippable class implements DippableExtended
All dippable classes implement the Dippable interface. You have the choice of optionally implementing the DippableExtended interface, which is a child of the Dippable interface. Besides supporting all the Dippable methods, the DippableExtended interface exposes all Dip instances applied to the dippable class to any user of the dippable class.

BeanInfo created for dippable class
If you are morphing a bean, you will want a corresponding BeanInfo class created to go with the new dippable bean. The new BeanInfo class will be based off of the BeanInfo for the original class (and all additional API's added), and will use a MergedCustomizer as it's customizer.

If your are morphing an ordinary class, not a bean, you will not want a corresponding BeanInfo class created.

Dippable class's new name
You can optionally decide to name the new dippable class. You can name the new dippable class using either just a class name or a fully qualified name including the package name. If you just provide a class name, the new dippable class will be in the same package as the original class.

If you do not provide a new name, then the new dippable class will be in the same package as the original class. The name for the new dippable class will be a combination of the original interface name (if you chose aggregation), the original class name, and the string "Dippable".

Dip(s) applied
You can optionally decide to have a dip applied to the new dippable class in every constructor. Dips appled this way are applied to the class definition of the new dippable class, not just to a specific instance of the new dippable class.

Having dips applied to the class definition of a dippable bean does not prevent additional dips from being applied to a single instance of the dippable class. Additional dips can still be applied to an instance of the new dippable class, but the class based dips listed in this option during morphing will be applied to all instantiations of the new dippable class.

The Advanced Customization tab

The Advanced Customization tab in the Morphing Interface presents the advanced options for customization of the dippable class. These options assume a higher level of experience with the morphing process, and should not be used by beginner morphers.

The following graphic depicts the Advanced Customization tab in the Morphing Interface.
* Figure morph03 not displayed.

Dippable class overrides parents method(s)
Normally, the new dippable class includes all of the public and protected methods in the original class and all parent classes. You have the option of only allowing the dippable class to include all of the public and protected methods from the original class, but not from any parent class.

This option is only valid if the new dippable class was created using inheritance. It is ignored if the new dippable class is created through aggregation.

Using this option could mean dips applied subsequently to an instance of the dippable class will reject being applied because a method needed by the dip is not available in the dippable class.

Dip(s) applied specify what methods are overridden
Normally, the new dippable class overrides all the methods in the original class and it's parent classes. If you chose to have dips applied to the dippable class using the Dip(s) applied option in the General Customization tab, then this additional option is available where the dips specified determine what methods are overridden in the new dippable class.

This option remains disabled until one or more dips have been chosen in the Dip(s) applied option under the General Customization tab.

Using this option could mean dips applied subsequently to an instance of the dippable class will reject being applied because a method needed by the dip is not available in the dippable class.

Dippable class is final class
Normally, the new dippable class is a final class. You have the option of deciding if the new dippable class should not be final. If the new dippable class is not final, you have the additional option of indicating which (if any) methods in the new dippable class should be marked as final. All overloaded method names will be treated the same, so if method "A" is given in this parameter, all overloaded methods with the name "A" will be made final.

Choose this option with care. If the new dippable class is not a final class, then a child could be created of a dippable class which could subvert the behavior of a dip applied to the dippable class.

Additional API
Some additional API's may be included as part of the dippable class. For each additional API, you must first choose a bean to be used to implement the additional API, then you must choose an interface to the dippable class that is to be implemented. The new dippable class will implement the interface, and delegate the actual work to the corresponding bean.

Choose this option with care. Adding additional API could subvert the desired behavior of the original class. If the original class implemented an interface like Cloneable, it's possible the dippable class with the additional APIs no longer correctly implements Cloneable. After all, the dippable class just uses the original implementation for the clone() method.

Also, it is possible the adding of additional APIs to the dippable class may mean the new dippable class isn't thread-safe or isn't immutable, when the original class was thread-safe or immutable.

Morphing the Selected Class

Once you have made all your choices, click on the Morph Class button. This causes the following process to occur:

  1. Code is generated for the new dippable class
  2. Code is generated for a corresponding BeanInfo
  3. The generated dippable class is compiled.
  4. The generated BeanInfo is compiled.
  5. The compiled .class files are stored at the user-specified location.

Programming to the Morphing Interface

The morphing UI is designed using the model-view-controller approach:


* Figure morph04 not displayed.

As seen in the diagram, the MorphController interfaces with the model and the view through the interface methods defined in the Model, MorphModelManipulator, and MorphView interfaces. The Model sends information to the MorphController class by firing a ModelEvent. The view sends information to the MorphController class by firing a MorphViewEvent. The model and the view have no direct connection. All the logic of what needs to be done is handled by the MorphController.

The MorphController is instantiated using one or two Model+MorphModelManipulator pairings and a single view. One Model+MorphModelManipulator pair represents the collection of classes the MorphController considers for morphing. The second (optional) Model+MorphModelManipulator pair represents the collection of dips the MorphController considers for pre-dipping. If the second Model+MorphModelManipulator pair is not provided, an empty model is created for the dips, and optionally filled with the contents of the first Model+MorphModelManipulator pair. Only one graphical user interface is given to the user to make the decisions necessary for the class to morph.

Anyone wishing to put a different view on the morphing UI only needs to come up with a new implementation of the MorphView interface. Anyone wishing to use a different Model of the classes or dips only needs to come up with a new implementation of the Model interface and it's corresponding MorphModelManipulator interface.

Any Java builder application can invoke the Morphing Interface by constructing a new MorphController instance by providing Model and MorphModelManipulator instances for the list of classes and the list of dips, and by also providing a MorphView instance to display to the user.

   Frame myFrame = new Frame("command line tag");

   // Create the empty model
   BeanBagModel myClassesBeanBagModel = new BeanBagModel();

   // Create the view
   MorphView myView = new MorphDialog(myFrame, true);

   // Create the controller
   MorphController myController = new MorphController(myView,
                 new MorphBeanBagModelManipulator( myClassesBeanBagModel ) );

   // Set any options in the Controller or the View different from the defaults

   // have the MorphController run a System.exit() when it's through;
   myController.setDoRunExit(true);

   // Add some data the model
   myClassesBeanBagModel.loadFromRepository(null,jelly.jar);

   // Show the view
   myView.setDoDisplay(true);

For additional information on MorphDialog objects, see the Bean Extender API Reference.

Serialization Compatibility Checking Tool

The Serialization Compatibility Checking Tool is a utility for Java programmers to help them check the serialization compatibility between two versions of a Java class.

For any commercial software application it is often necessary that the data files and state information saved using the old version of the product are readable by the new version. Java provides the Object Serialization model for persisting the state and instance information of application classes and instances. However, the Java Serialization model is such that changes made to a class betwwen successive releases of a product may result in a situation where a serialized (saved) instance of an old version of a class can not be deserialized and reconstructed into an instance of a new version of the same class. This happens when certain kinds of changes are made to a class that break Serialization compatibility from an old version to a new one.

The Serialization Compatibility Checking Tool helps a Java programmer check if any changes made in a Java class can result in a serialization incompatibility. It uses the set of rules for Type Changes Affecting Serialization defined in the Object Serialization Specification published by JavaSoft.

Typically this tool is intended to be used by Java developers as a preventive measure in their test cycle. In such cases, this tool can be used to compare old and new versions of all the classes in the application and find out the changes that can potentially break the serialization compatibility. Alternatively it can also be built into a builder tool so that the tool can warn the programmer as soon as she makes a change to a class that might result in stream-incompatibility. This tool can be used as a stand-alone Java utility or it can be invoked programmatically.

Command line usage

To use this tool as a command line utility, type:

java com.ibm.beans.tools.CheckCompat oldClassFile newClassFile className

where
oldClassFile: The file name for the old version of the class.
newClassFile: The file name for the new version of the class.
className: The name of the class to be loaded.
For example, consider two versions of a class com.test.foo stored in files D:\test\foo.old and D:\test\foo.new. Then a command such as

java com.ibm.beans.tools.CheckCompat D:\test\foo.old D:\test\foo.new com.test.foo

may result in an output like:

The field public java.lang.String foo.abababab does not exist in the new version.
The field public int foo.xxxx has been changed from nonstatic to static.
The classes missing from the class hierarchy of the new version are: java.awt.Frame java.awt.Window java.awt.Container java.awt.Component.
---- Classes are NOT compatible. ----

Programmatic usage

To invoke this utility from another program use the static method checkCompatibility defined in the class com.ibm.beans.tools.CheckCompat. The signature of the method is as follows:

public static boolean checkCompatibility 
                         (String oldClassFile, 
                          String newClassFile, 
                          String className)


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