C H A P T E R  2

Developing Components


Develop Your First Component

This chapter provides a description of the fundamental steps involved in creating, distributing, and using a Sun ONE Application Framework component.

Approach this as an exercise, and actually build and test drive the component. After completing this section, you should have a good understanding of the process. Do not worry about trying to understand every detail at this point. The rest of this document delves into details concerning the various types of components, the details of the metadata formats, and the extra optional features available to component authors.

This section assumes basic familiarity with the Sun ONE Application Framework application.

Decide the Type of the Component

An ultra-simple example is contrived to focus on technique. You will create a new DisplayField component called "MyTextField". The objective is to have this component expose a new property called "Foo" that will take a boolean value. Application developers will be able to visually select MyTextField and add it to their Sun ONE Application Framework pages. It is expected that the component will have all of the properties of the standard Sun ONE Application Framework TextField component, plus the new Foo property.

Create the Component Class

A new component class is not always needed in Sun ONE Application Framework. This subtlety is discussed later in this document. This example, however, does require a new component class, so you will begin with that.

1. In any Java editor create the package mycomponents.

2. Create the mycomponents.MyTextField class.

3. Make MyTextField extend com.iplanet.jato.view.BasicDisplayField.

4. Implement the appropriate constructor for the component type.

All DisplayField components must implement a two-arg constructor that takes a View "parent" and a String "name". The IDE toolset assumes that all DisplayField components will implement this constructor.

5. Add a get and set method for the new boolean property named "Foo".

After these steps, mycomponents/MyTextField.java should look as follows:

package mycomponents;

 

import com.iplanet.jato.view.*;

 

/**

*

* @author component author

*/

public class MyTextField extends BasicDisplayField {

 

/** Creates a new instance of MyTextField */

public MyTextField(View parent, String name) {

super(parent, name);

}

 

public boolean getFoo() {

return foo;

}

 

public void setFoo(boolean value) {

foo = value;

}

 

boolean foo;

}


Although you are creating a new property on this component, how this property actually interacts with the component at run-time is not defined. That is up to you as the component author and is beyond the scope of this part of the document.

Create the ComponentInfo Class

The ComponentInfo class defines the design-time metadata that the IDE toolset requires to incorporate the component. In this example, you extend an existing ComponentInfo and, in true OO style, simply augment it. You could, of course, choose to implement the ComponentInfo interface from scratch, but that would be unproductive in this case.

1. Create the class mycomponents.MyTextFieldComponentInfo.

2. Make MyTextFieldComponentInfo extend com.iplanet.jato.view.html2.TextFieldComponentInfo.

3. Implement the no-arg constructor.

4. Implement the getComponentDescriptor() method to provide the basic design-time description of the component.

5. Implement the getConfigPropertyDescriptors() method to identify which properties you want to expose in the IDE.

Utilize inheritance to add the new Foo property to those properties already defined in TextFieldComponentInfo.

After these steps, mycomponents/MyTextFieldComponentInfo.java should look like the code that follows:



Note - In the following sample code, for demonstration purposes, String values have been embedded directly. Utilize resource bundles if you anticipate the need to localize your display strings.



package mycomponents;

 

import java.util.*;

import com.iplanet.jato.view.*;

import com.iplanet.jato.component.*;

import com.iplanet.jato.view.html2.*;

 

 

public class MyTextFieldComponentInfo extends TextFieldComponentInfo {

 

public MyTextFieldComponentInfo()

{

super();

}

 

public ComponentDescriptor getComponentDescriptor() {

 

// identify the component class

ComponentDescriptor result=new ComponentDescriptor(

"mycomponents.MyTextField");

 

// The name will be used to determine a name for the component instance

result.setName("MyTextField");

 

// The display name will be used to show the component in a chooser

result.setDisplayName("MyTextField Component");

 

// The description will be the tool tip text for the component

result.setShortDescription("A simple demonstration of a new component");

 

return result;

}

 

public ConfigPropertyDescriptor[] getConfigPropertyDescriptors() {

 

if (configPropertyDescriptors!=null)

return configPropertyDescriptors;

 

// Get any properties defined in the super class

configPropertyDescriptors=super.getConfigPropertyDescriptors();

List descriptors=new LinkedList(

Arrays.asList(configPropertyDescriptors));

 

ConfigPropertyDescriptor descriptor = null;

// Add the "foo" property

descriptor=new ConfigPropertyDescriptor("foo",Boolean.TYPE);

descriptor.setDisplayName("Foo Property");

descriptor.setHidden(false);

descriptor.setExpert(false);

descriptor.setDefaultValue(new Boolean(false));

descriptors.add(descriptor);

 

// Create/return the array

configPropertyDescriptors = (ConfigPropertyDescriptor[])

descriptors.toArray(

new ConfigPropertyDescriptor[descriptors.size()]);

return configPropertyDescriptors;

}

private ConfigPropertyDescriptor[] configPropertyDescriptors;

}


Create the Component Library Manifest

Sun ONE Application Framework components are packaged and distributed in ordinary JAR files. Any classes (component, ComponentInfo, and any other ancillary files) should be placed in the JAR in accordance with standard Java convention.

Additionally, the Sun ONE Application Framework requires that a component library JAR contains a special Sun ONE Application Framework library manifest file. This is a simple XML document that describes the collection of components in the library. Library manifests might declare any number of components. In this case, just declare the one component that you have just authored.

The Sun ONE Application Framework library manifest must be named complib.xml. Within the JAR file, the Sun ONE Application Framework library manifest must be placed in the /COMP-INF directory.

1. Create the file called complib.xml.

2. Add the minimum information to satisfy the Sun ONE Application Framework library manifest requirements.

3. Add a component declaration for the MyTextField component.

After these steps, the COMP-INF/complib.xml file should look like the code that follows:



Note - If you use a tool to create the XML file, be sure that it looks like this. Some XML tools automatically insert a root element when you create the file. Make sure the root element is <component-library> as indicated below. An improper XML file will cause the IDE toolset to fail to discover your component library.



 

<?xml version="1.0" encoding="UTF-8"?>

<component-library>

<tool-info>

<tool-version>2.1.0</tool-version>

</tool-info>

<library-name>mycomponents</library-name>

<display-name>My First Component Library</display-name>

<!-- Your icon here

<icon>

<small-icon>/com/iplanet/jato/resources/complib.gif</small-icon>

</icon>

-->

<interface-version>1.0.0</interface-version>

<implementation-version>20030221</implementation-version>

 

<component>

<component-class>mycomponents.MyTextField</component-class>

<component-info-class>mycomponents.MyTextFieldComponentInfo</component- info-class>

</component>

</component-library>


Create the Component Library JAR File

JAR up the component classes so they can be ready for distribution as a library.

The name of the JAR file is arbitrary.

1. In this case, name the JAR file mycomponents.jar.

You can omit the Java source files from the JAR.

2. Include in the JAR any necessary ancillary resources, such as icon images or resource bundles.

In this case there are none.

The mycomponents.jar internal structure should look like the code that follows:

mycomponents/MyTextField.class

mycomponents/MyTextFieldComponentInfo.class

COMP-INF/complib.xml


Test the Component

Your library is now ready for testing and distribution. You should test it in a sample project. This stage requires the use of the Sun ONE Studio with the Sun ONE Application Framework module installed and enabled. If you have never built a Sun ONE Application Framework application in the Sun ONE Studio, before continuing, you should first complete the Sun ONE Application Framework Tutorial that is included with the Sun ONE Application Framework document set.



Caution - You can test your component(s) in any existing Sun ONE Application Framework application. However, you should create a new Sun ONE Application Framework application to serve as the test application for all of the example components that you will build in the course of completing the exercises within this guide. The instructions that follow generally assume that the names for your test objects were generated according to Sun ONE Application Framework defaults (for example, Page1, and so on) and you will have an easier time following the instructions if your test application's object names match those in the instructions.



1. Create a new Sun ONE Application Framework application in the Sun ONE Studio.

The name of the application is up to you.

2. From the filesystem, copy the new mycomponents.jar file into the WEB-INF/lib directory within your test application.

3. Wait for the Sun ONE Studio background thread to discover that a new JAR has been deployed in the application's WEB-INF/lib directory.

This takes several seconds, depending upon the value Sun ONE Studio background thread Refresh Interval.

The library is fully recognized and functional when a new library node appears under the Sun ONE Application Framework application's Settings and Configuration -> Component Libraries node, as shown below:

This figure shows the newly created library node. 

4. Create a new Page (ViewBean) object.

Take the wizard defaults, and the IDE names it "Page1".

5. Select and expand the newly created Page1 node.

This figure shows the expanded Page1 node. 

6. Add an instance of "MyTextField Component" to Page1.

This can be accomplished in either of two equally valid user interface actions.

This adds an instance to whatever page node has focus at that moment.

Right-click, and select the Add Visual Component action from the pop-up menu.

Note the generic icons for both the library "My First Component Library" and the component "MyTextField Component". This occurs because, in this example, you did not specify any specific icons. That is just one of the features that you will learn about in the rest of this document.

This figure shows the Component Palette. 

The Component Browser (shown below) is an alternative to the Component Palette (shown above). In the rest of this document, any instruction that involves adding a visual component can be fulfilled by using either the Component Palette or the Component Browser. They are functionally interchangeable, and users can use either, or both, at all times.

This figure shows the Component Browser. 

After selecting the MyTextField Component from either the Component Palette or the Component Browser, observe how a child View named "myTextField1" is added to the page.

7. Select the child node myTextField1.

Observe how the IDE's property sheet has added Foo Property, the new custom property, in addition to the inherited TextField component properties.

This figure shows the child node, myTextField1. 

Test the behavior of the Foo Property to make sure it behaves the way you, as component author, expect it should.

You should be able to assign the Foo Property the value True or False.

8. In this example, set the Foo Property to True.

9. Observe the code generation inside the Page1 java file.

You should see a block of code inside the createChildReserved method that looks like the following code (the indenting in your code might differ from what you see below):

...

else if (name.equals(CHILD_MY_TEXT_FIELD1)) {

mycomponents.MyTextField child =

new mycomponents.MyTextField(this, CHILD_MY_TEXT_FIELD1);

child.setFoo(true);

return child;

}

...


Ship It!

When you are finished testing and refining your component, you can distribute the component library JAR file to your developer community. It is up to application developers to add the component JAR file to each application in which they want to utilize the components.


Sun ONE Application Framework Components in More Detail

Sun ONE Application Framework components are designed to enable application developers to more rapidly define Sun ONE Application Framework run-time types (Views, Commands, and Models). However, the manner in which Sun ONE Application Framework components are integrated into the application developer's design-time experience varies in accordance with the range of Java's object oriented opportunities (for example, class sub-typing vs. object instantiation).

As an experienced Java programmer, a Sun ONE Application Framework component author should easily anticipate the manner in which Sun ONE Application Framework application developers will integrate a new component into their development processes. The component author will know that the application developer expects to subclass one type of component, and instantiate another type of component. Component authors understand that in some circumstances they can distribute a component as a fully enabled, fully configured black box, while in other cases, they require the application developer to configure each usage of the component.

The Sun ONE Application Framework component model and the IDE toolset combine to empower component authors and application developers to exploit the full range of Java object orientation. This section details the specific terminology that the Sun ONE Application Framework component model uses to differentiate each component's role as an object oriented building block.

The discussion of components is often filled with highly overloaded terms. To provide the grounds for a more precise discussion of Sun ONE Application Framework components, some terminology has been developed to avoid reliance on confusingly overloaded terms.

Distributable vs. Application-Specific (Non-Distributable) Components

Technically speaking, every Sun ONE Application Framework object (Model, View or Command) is a component. However, not all Sun ONE Application Framework components are destined for distribution in a component library. Some components are simply built as part of the standard process of building the application within the Sun ONE Studio, in which every Model, View, and Command is, technically speaking, a component. This distinction is acknowledged by referring to components which are included in libraries as distributable components, and components which are simply built within applications, as application-specific components, or non-distributable components. This is purely a distinction of terminology, not a hard formal distinction. Distributable components and application-specific components do not differ by type. The distinction is merely a soft categorization, meant to help distinguish the component author's role from the application developer's role. Application developers develop application-specific components. Component authors develop distributable components.

The first term, application-specific components, or non-distributable components, refers to components which are only reusable within the application in which they are defined. They are not packaged into a component library. They generally do not have an explicit ComponentInfo associated with them. As an example, when application developers build a ContainerView or Model in their applications, they are implicitly building application-specific components. This is akin to a javax.swing application developer building an application specific panel or frame. Because the IDE toolset knows how to manipulate these application-specific components directly, they are usable within the same application without any additional work by the developer. For instance, after creating a new application specific Model, the application developer can visually connect that new Model to Views within the current application. Development of an application-specific component is transparent and implicit, and requires no component authoring knowledge per se.

Application-specific (non-distributable) components are:

By contrast, distributable components refers to components which are reusable across many applications. Component authors package distributable components into component libraries. Component authors typically develop an explicit ComponentInfo class for each distributable component. Usually, the creation of a distributable component requires more foresight in design due to its greater ambition for reuse. To use the javax.swing analogy again, a distributable component would be a new sub-type of javax.swing.JPanel which is distributed for use in many new applications. In the Sun ONE Application Framework application, a distributable component might be a new type of DisplayField, or a specialized, but highly reusable type of ContainerView.

Distributable components are:

Of course, in accordance with common bottom-up design practices, it is not uncommon for an application-specific component to be explicitly "promoted" to distributable status. This happens when a development team identifies it as a valid candidate for reuse across applications. This is normal, expected, and encouraged. The promotion of an application-specific component to distributed status merely entails fulfilling the tasks that will be identified as standard for distributable components.

Therefore, in deference to the simplicity/transparency of creating application-specific components versus the relative complexity of authoring distributable components, the bulk of this document is dedicated to describing the process of authoring distributable components.

Extensible vs. Non-Extensible Components

In Sun ONE Application Framework component libraries, there is a formal distinction between extensible and non-extensible components. Component authors are responsible for designating a component as either extensible or non-extensible. This distinction allows component authors to control the manner in which the component-aware IDE toolset will expose a given component for usage by application developers. The IDE toolset will expose both extensible and non-extensible components in well-defined, but distinct fashions.

It is worth noting that while the distinction between extensible and non-extensible is important to a component author, practically speaking, component consumers are totally unaware of the distinction. That it to say, the IDE toolset will never present the application developer with either of these terms. Rather, the IDE toolset will automatically manage these subtleties so that application developers can just concentrate on building their applications. Application developers will generally never need to worry about whether a component is extensible or not, or even whether it has a ComponentInfo class.

Extensible Components

Extensible components are appropriate in those cases where the application assembly calls for the declaration of a new Sun ONE Application Framework sub-type (for example, a new type of Model, a new type of ContainerView, a new type of Command, and so on).

The IDE toolset presents extensible components for direct sub-classing by application developers. When an application developer selects an extensible component from the list of available components, the net result is that the IDE toolset creates a new Java class that extends the selected component's class. A component author should designate a component as an extensible component if it is envisioned that the proper usage of a given component is through application specific sub-typing. Effectively, the Sun ONE Application Framework dictates where extensible components fit in. Wherever the Sun ONE Application Framework framework designates that an application entity must be a sub-type of a framework entity, that is where extensible components come into play.

Extensible components are designated by an <extensible-component> element within the component library manifest, as shown in the following example:

<extensible-component>

<component-class>com.iplanet.jato.view.BasicViewBean</component-class>

<component-info-class>com.iplanet.jato.view.BasicBeanComponentInfo</component-info-class>

</extensible-component>


Extensible components:

Examples are: Extensible ViewBean, ContainerViews, Model, or Command components.

Non-Extensible Components

Non-extensible components are appropriate in cases where the application assembly calls for the simple declaration and configuration of instances.

The net result of an application developer selecting a non-extensible component is that a new instance of the non-extensible component is declared in the application-specific class. For example, whenever a developer adds a text field or a button to a ContainerView, the IDE toolset turns that design decision into a declaration of an instance of the text field or button in ContainerView class. In this manner, application developers populate the application-specific classes with instances of non-extensible components. This is the classic "assembly" model of component based development.

Again, the Sun ONE Application Framework dictates where this is appropriate. For instance, in developing an application-level Page (ViewBean) or Pagelet (ContainerView) component, the application developer expects to be able to add child view objects (such as DisplayFields) to that component. Consequently, the IDE toolset presents the application developer with a list of non-extensible components for direct addition to the page or pagelet.

Non-extensible components are designated by a <component> element within the component library manifest, as shown in the following example:

<component>

<component-class>com.iplanet.jato.view.BasicChoiceDisplayField</component-class>

<component-info-class>com.iplanet.jato.view.html2.ListBoxComponentInfo</component-info-class>

</component>


Non-extensible components:

Extensible and Non-Extensible Components in the IDE

If you still find it confusing to distinguish extensible and non-extensible components, it might help at this point to refer to the Sun ONE Studio to see how the IDE toolset transparently exposes extensible and non-extensible components.

1. Open a Sun ONE Application Framework project and select a "module" folder.

2. Right-click, and choose Add->Model or Add->Page (ViewBean) or Add->Pagelet (ContainerView).

These actions invoke wizards which contain an embedded extensible component browser, as shown below:

This figure shows the Extensible Component Browser (New View Wizard). 

3. Complete either of the wizards, and the IDE toolset creates a new class that extends the extensible component's class.

This figure shows the Extensible Component Browser (New Model Wizard). 

4. Select an existing page or pagelet node.

Expand the top node so you can see its inner Visual Components node.

5. Select the Visual Components sub-node, right-click, and select the Add Visual Component action.

This invokes the non-extensible component browser (shown below).

6. Complete the selection of a child view.

This does not result in the creation of a new class, but rather adds a child element to the currently selected class.

This figure shows the Non-Extensible Component Browser. 

The figure above shows the Non-Extensible component browser employed in the context of "Add Visual Component" action. This figure shows the browser fully expanded to show two libraries and the current application's non-extensible components.

In other areas of the IDE, the non-extensible component browser is used to select Page/Pagelets, or Models, or Commands for assignment to certain property values. For instance, wherever a Sun ONE Application Framework use relationship is expressed in a property (for example, a View uses a Model), the property editor can leverage the non-extensible component browser to enable the application developer to select a valid target object.

For instance, properties of type Model Class Name are edited using a non-extensible Component Browser which shows non-extensible Model components in the mounted component libraries (if any), and also any Models which have been added to the current application. Similar behavior applies to editing the "Command Class Name" property. However, in that case, Command components are selected instead of Models.

This figure shows the Model Class Name Browser. 

The figure above shows the Non-Extensible component browser employed in context of a Model Class Name property editor. This figure shows the browser fully expanded to show two libraries and the current application's non-extensible Model components.


ComponentInfo in More Detail

The ComponentInfo class is the heart and soul of the Sun ONE Application Framework 2.1 component model. Logically speaking, a Sun ONE Application Framework component can be defined as a tuple comprised of a component class and a ComponentInfo class. The ComponentInfo class provides the metadata that is introspected by the IDE toolset to provide the component's design-time presence. When you author a ComponentInfo class, you can focus exclusively on design-time considerations. The ComponentInfo class plays no run-time role in the Sun ONE Application Framework.

Specific ComponentInfo classes must implement the com.iplanet.jato.component.ComponentInfo interface, or one of its sub-interfaces. ComponentInfo class names must end with the "ComponentInfo" suffix. Whenever practical, the ComponentInfo class should share the same base name as the component class (for example, Foo and FooComponentInfo).

Here is an early glimpse into the Sun ONE Application Framework Component Library manifest. In the following snippet, you can see the simple declaration of a component as a component class and ComponentInfo tuple. Note in this example the extra designation of the <extensible-component> tag (for complete details of the Sun ONE Application Framework component manifest, see The Component Manifest, found in Chapter A, Component Library Structure.

<extensible-component>

<component-class>com.iplanet.jato.view.BasicViewBean</component-class>

<component-info-class>com.iplanet.jato.view.BasicViewBeanComponentInfo</component-info-class>

</extensible-component>


However, the Sun ONE Application Framework allows ComponentInfo classes to differ in base name from their associated component class. In fact, the Sun ONE Application Framework allows more than one ComponentInfo class to be associated with the same component class. As stated earlier, logically speaking, a component is a tuple comprised of a component class and a ComponentInfo. The surprise is that the same component class might participate in more than one of these tuples.

This might not be immediately intuitive to most component authors, but it is a very effective and powerful feature of the Sun ONE Application Framework component model. For instance, in the com.iplanet.jato.view.html2 package, there are several ComponentInfo classes which are actually associated with the same component class. For example, the ListBoxComponentInfo, RadioButtonsComponentInfo and ComboBoxComponentInfo classes all specify com.iplanet.jato.view.BasicChoiceDisplayField as their component class.

Following is another actual snippet from the Sun ONE Application Framework Component Library manifest where you can see the component tuples described above:

<component>

<component-class>com.iplanet.jato.view.BasicChoiceDisplayField</component-class>

<component-info-class>com.iplanet.jato.view.html2.ListBoxComponentInfo</component-info-class>

</component>

<component>

<component-class>com.iplanet.jato.view.BasicChoiceDisplayField</component-class>

<component-info-class>com.iplanet.jato.view.html2.RadioButtonsComponentInfo</component-info-class>

</component>

<component>

<component-class>com.iplanet.jato.view.BasicChoiceDisplayField</component-class>

<component-info-class>com.iplanet.jato.view.html2.ComboBoxComponentInfo</component-info-class>

</component>


These pairs form three distinct tuples, and therefore, three distinct logical components. The value presented by this freedom is that new component variations can be created by simply defining new ComponentInfo classes.



Note - To be anything more than just equivalent to other components that use the same component class, the new components must either expose existing component properties not exposed by other components (for example, only ListBoxComponentInfo exposes the "Allow Multiple Choices" property), or change other meaningful component metadata. In the examples provided above, the components primarily differ in the JSP tags that they declare, thereby drastically changing the way these components look and feel when added to an HTML page. However, the component functionality itself is essentially the same among all of them. The ability to declare different tags, and thus different rendering mechanisms for a component, is the most compelling reason to define components that use the same component underlying component class.



Unlike declarative metadata, a ComponentInfo is specified as a Java class. Therefore, new ComponentInfo classes can derive from existing ComponentInfo classes and benefit from standard inheritance of superclass functionality. The com.iplanet.jato.component.SimpleComponentInfo class can serve as a reliable starting point for any new ComponentInfo class, if there is not a more specific and more appropriate subtype already available.


Specialized ComponentInfo Interfaces

The Sun ONE Application Framework provides several specialized sub-types of the ComponentInfo which allow component authors to specify additional metadata that is appropriate for certain components. The IDE toolset leverages the additional metadata to provide special visual development support congruent with the additional metadata.

ExtensibleComponentInfo

The com.iplanet.jato.component.ExtensibleComponentInfo interface allows developers to provide additional metadata that is specifically appropriate for extensible components. In the IDE toolset, extensible components serve as the base classes when developers create new Sun ONE Application Framework types (Models, Pages/Pagelets, and Commands). To this end, the extra metadata defined in the ExtensibleComponentInfo interface allows the component author to influence the construction of the new type. Specifically, component authors might specify a Java class template to serve as the starting point for every new type derived from the extensible component.

Other Types of Specialized ComponentInfo

There are several other specialized types of ComponentInfo:

Details of these interfaces are discussed later in sections describing the steps required to create components of the various types to which these specialized ComponentInfo interfaces pertain.

Standard Implementations of ComponentInfo

Since the Sun ONE Application Framework component model is based on well-defined interfaces, component authors can implement these interfaces from scratch for any new component. However, the Sun ONE Application Framework generally provides ready-made implementations of all of the various specialized ComponentInfo interfaces, and component authors are encouraged to extend one of the existing implementations when writing their own components. This saves you labor and speeds your authoring process.