------------------------------------------------------------------------------------------------------------------------------------------------------------------
JAVA STUDIO CREATOR2 组件开发
搜集整理:封朋成
Copyright 1994-2006 Sun Microsystems, Inc.
目录
1.1.1. Java Studio Creator 2 组件: 简介 5
1.2.2.1. Writing Custom Component Functionality 7
1.2.2.2. Creating Component Artifacts and Component Library 9
2.5.2. Design-Time Artifacts 18
3.1. 组件Design-Time Considerations 24
4. JAVA STUDIO CREATOR2 的 Design-Time API 29
5. 开发JAVA STUDIO CREATOR组件的四条规则 31
5.2.1. 规则1: Use the ResponseWriter class methods startElement, endElement, and writeAttribute. 31
5.2.2. 规则2: Always pass in a component reference to the startElement method on the ResponseWriter. 32
5.2.3. 规则3: Use a style property for every component. 32
5.2.4. 规则4: Do not throw exceptions from your renderer! 33
6. Java Studio Creator Design-Time API 用户手册 34
6.1.1.3. JavaBean 组件和 JavaBeans 组件模型 35
6.1.2.1. Design-Time Context 36
6.1.2.2. Generation of Persistence 37
6.1.2.3. Manipulation of Hierarchy 37
6.2. The Java Studio Creator Design-Time API 38
6.2.1.2.1. MarkupDesignContext (extends DesignContext) 46
6.2.1.2.2. FacesDesignContext (extends MarkupDesignContext) 47
6.2.1.3.1. MarkupDesignBean (extends DesignBean) 50
6.2.1.3.2. FacesDesignBean (extends MarkupDesignBean) 51
6.2.1.4.1. FacesDesignProperty (extends DesignProperty) 52
6.2.2. 进入/挂钩点Access / Hook Points 54
6.2.2.1.1. MarkupDesignInfo (extends DesignInfo) 57
6.2.2.1.2. MarkupRenderContext 58
6.2.2.1.3. MarkupMouseRegion 58
6.2.2.4. DisplayAction and DisplayActionSet 62
6.2.3.1. Additional PropertyDescriptor Attributes 66
6.2.3.2. Additional EventSetDescriptor and EventDescriptor Attributes 67
6.2.3.3. Context Data Attributes 68
6.3.1 示例: 提供扩展的 BeanInfo Metadata
6.3.3 示例: 使用beanCreatedSetup 函数初始化
6.3.4 示例: 创建一个 Customizer2 对话框
The Java Studio Creator 2 IDE comes with a set of bundled standard components that you use to develop the visible interface for your applications. These reusable components, which rely on the JavaServer Faces™ technology, are the basic building blocks for user interfaces. Since JavaServer Faces components cover most common requirements for web page requests and responses, you can construct most of your applications by assembling these standard components.
In addition, you can build your own components and reuse these "custom" components in other applications. Typically, you build a new component by extending the API of a standard component. However, by keeping certain information in mind you can ensure that new custom components you build work well with the Java Studio Creator 2 IDE.
After you complete this introduction, you might be interested in other articles that cover this advanced subject in greater depth, such as:
* Building and Customizing JavaServer Faces Technology Components
* Design Time API for Sun Java Studio Creator 2
* How to Write JavaServer Faces Components
* Creating Custom UI Components
Also look at the Core JavaServer Faces book, some of whose chapters are available here.
The standard components included with the IDE use the JavaServer Faces technology to handle various tasks for your application. For example, a component handles how it is displayed or rendered on a page. The component encodes the internal representation of its properties and attributes into a suitable markup language for page rendering. A component also converts properties associated with incoming requests into its own corresponding properties and attributes. That is, the component decodes an incoming request’s parameters, headers, and cookies into properties and attributes.
In addition to having JSF components convert incoming requests to a form usable by the component, a component uses JavaServer Faces technology to validate the syntax and semantics of the request. Components are also able to save and restore their state across multiple requests. They can queue events to effect state changes in one or more components.
When you drop components onto a Java Studio Creator page, you may, and probably will, change their properties to fit your application. By doing so you are customizing that standard component for your exact needs.
For example, you don’t really need to build an entirely new custom component if you simply want to change a standard component’s visual representation or if you want to change its decoding behavior (such as its handling of incoming requests). Instead, you can simply customize an existing standard component—that is, change its visual representation by changing its property values. You can also customize an existing component to change how it handles requests. Although the component can delegate handling requests to a separate renderer—a renderer determines how the component appears to the user and shields the application from these issues—doing so may be as much work as building a new component. When you write your own renderer you still do many of the same defining and packaging tasks that you do for a custom component.
Building a new component is different from customizing or using an existing component. If you want to change a component’s behavior other than through its properties, you may need to consider building a custom component.
Component vendors or component developers build custom components because that is their business—they build complex components that go beyond what standard components can do. As an application developer, you may want to build a custom component to add to or modify how a standard component works. For example, you may want to consider building a custom component if you need a component to support a new type of event. For type safety reasons, every standard component supports a specific type of event. You cannot extend an event type of one component to a different, new event type.
You might also want to build a custom component to give it behavior not covered by any of the standard components. Also, consider a custom component when you want to override the way a standard component works; that is, you want to override the way the component decodes, converts, validates, and handles state (saves and restores state) across requests. For example, you might not want to persist a component’s state across requests. Or you might want a component to have additional attributes beyond its standard attributes. In this case, your component extends the standard component so that it provides the standard attributes and you implement the additional attributes.
You don’t have to build a custom component from scratch. The easiest way to build a custom component is to extend an existing standard component. By choosing a standard component whose functionality is close to your custom one, your custom component can inherit a good portion of the standard behavior.
To select a standard component to extend, first classify the type of your component by what you want it to do. Component types fall into the categories of output, input, control, or container, and sometimes a combination of these. For example, your custom component might only display some data or it might accept some user input. If display only, you might want to extend the JSF standard output (UIOutput) component. If it handles input data, then you should also consider the type of input it accepts. A component may accept simple text input, in which case you extend the JSF UIInput component. If you intend your component to accept input selected by the user from a list, this might encompass a selection of one or many pieces of data. Consider extending either the UISelectOne component (to select one item from a list) or the UISelectMany component (to select multiple items).
Control-type components, such as buttons, trigger an application-specific command or action when activated by the user. For these components, you extend UICommand. A component may also be a container that contains or nests other components. For these components, you extend UIPanel.
Sometimes you want your custom component to have the behavior of a combination of standard components. In this case, you extend a standard class for one type of behavior and then implement a JSF behavioral interface for the other type of behavior. For example, suppose you want your component to accept input and handle control actions. You might extend the UIInput standard component to add the input behavior and implement the JSF ActionSource interface for the action behavior.
In some cases you might extend the abstract base class for all components, UIComponent Base. Consider this approach if you can’t find a good match with the behavior of the standard components. The UIComponentBase class provides default implementations of just about every component method. You can then concentrate on the unique characteristics of your custom component. (The JavaServer Faces specification, which you can find at http://java.sun.com/j2ee/javaserverfaces/reference/api/index.html, details the available interfaces and component classes.)
To illustrate, let’s look at what is involved to create a custom calendar component—a Date Picker component that lets users select a date. (See Figure 1.) Date Picker is packaged with a second custom component, Date Displayer, which displays a date. These components are available on the sample components page for demonstration and download.

Figure 1: Date Picker Component
First, you extend the appropriate UIComponent class for your component and give the component a single type name string for identification purposes. For example, you might use the string com.example.DatePicker. Then you either implement or call several methods in the component class. You need to implement the getFamily method to return the component name string. Creator uses this component name string and the rendererType to locate the code responsible for rendering the component. (As noted in the next section, you manually write the renderer code.) You must also include a call to the method setRendererType passing it the component name string as a parameter. Finally, you implement the saveState and restoreState methods.
For a user to view a component’s property in the IDE property sheet, that property must be a JavaBeans component property with typed accessor methods. Currently, the IDE requires a component to have the String properties style, which it renders as the style attribute, and a rendered property. Optionally, you may also include other properties, such as a title property, which the IDE renders as the title attribute, or a styleClass property, which it renders as the styleClass attribute. You may also include other custom properties for your component. For example, Date Picker might have an int property called numYears.
When you build a custom component, you also create a set of artifacts, such as renderers, metadata, and icon images in addition to the custom component, and then package everything together in a component library, or single archive file, called a complib file. A complib file is similar to other JAR files such as WAR or EAR files and is the means of distributing the component to other users. You can use zip utilities, such as WinZip, that work with JAR files to view and work with a complib file.
Building a custom JSF component involves writing three types of classes plus some metadata, all of which are deployed to the server as part of the runtime JAR. Let’s look at what this entails for the Date Picker component. You write the UIComponent class itself, DatePicker.java. You also must manually write a renderer for the component, DatePickerRenderer.java, and its tag handler, DatePickerTag.java. The renderer class must extend (either directly or indirectly) javax.faces.render.Renderer. In addition, you write two metadata files, sample-date.tld and faces-config.xml.
The JSF implementation uses the faces-config.xml file to determine the components, validators, and renderers. The sample-date.tld file, which is the JSP tag library descriptor, tells the container’s JSP compiler how to process the tags in a JSP page, and it is closely associated with the tag handler. The sample-date.tld file contains the tag name (datePicker), the tag class name (com.example.DatePickerTag), the Creator attributes (style, rendered, styleClass, and title), and any custom component attributes (numYears). For each attribute you must define a JavaBean-style set method in the tag handler. In addition to these set methods, the tag handler includes two methods that return information in the metadata about the component class: getComponentType looks up the component class and getRendererType looks up the renderer class. You implement two additional methods in the tag handler: setProperties, which transfers JSP attribute values to the component and release, which releases resources.
The Java Studio Creator IDE improves this design experience through additional design-time artifacts you can provide for a component. These artifacts include another metadata file, sunfaces-config.xml. Ideally, you should keep to a minimum the amount of metadata in the faces-config.xml file and place additional information, such as the category of a property sheet in which a property should appear, in the sun-faces-config.xml file. The two metadata files simplify development, since the code generator uses them to produce BeanInfoBase classes for the component. You can extend this base class to produce a design-time class, such as DatePickerBeanInfo.java for the Date Picker component. In addition, you can write property editors like DateEditor.java, create custom icon images, and custom javadoc documentation. All design-time artifacts (except for javadoc files) go into a design-time JAR file.
To complete packaging a component, collect all artifacts along with the manifest file, and place everything into the complib file.
You can use your own custom components, or those supplied by others, in applications you develop using the Java Studio Creator IDE. For instructions on customizing and importing components for use in your application, see Writing JavaServer Faces Custom Components in the Sun Java Studio Creator 2 Environment and Rules for Writing Custom Components in Sun Java Studio Creator 2.
The following simple steps enable you to use custom components within an application. First, download to your system a component library package file (the complib file). Then, in the Palette window within the IDE, right-click any section node to display the context menu and select the Manage Component Libraries... option. The Component Library Manager dialog box appears. Navigate to the location of the downloaded component library file and specify the section (or let the IDE create a new section) within the palette to which you import the component library. When the import process completes, the new component appears on the palette and you can drop it into any application or project.
When the IDE imports the component library file, it expands the package and loads the component’s BeanInfo and runtime classes. The IDE also populates the palette section with the new component. At the same time, the IDE copies the component files to a location, ~/.Creator/2_0/complibs, beneath the user’s directory.
You can do things to enhance the way your custom components work within the IDE. As noted previously, the IDE requires components to have style (style and styleClass) attributes. The Java Studio Creator IDE also requires a binding attribute for each component. To carry through its application model of one Java class per page and all components available for manipulation on a page, the IDE uses component binding to make the component available in the Java class that represents the page. In addition, because the IDE requires the use of JSP tags, you need to develop tag libraries and supporting tag classes for all custom components.
It is helpful to be familiar with the JavaBeans architecture, since the IDE manipulates components as JavaBeans components. In particular, you should understand the BeanInfo interface and how the IDE uses that interface to discover a component’s properties and supported events. The BeanInfo interface also plays a part in the design-time API for components, which enhances the design-time usability of components. Since design-time behavior is controlled by BeanInfo attributes and an optional DesignInfo class, you can enhance your component’s design-time user experience in the IDE by writing your own design-time support for these classes.
Generally, components methods are called within a runtime JavaServer Faces framework. The Java Studio Creator IDE itself also calls some methods that support the component’s role in the JSF life cycle, in particular calling methods that generate its design view of an application page by rendering the component tree. Because of this, you should exercise caution when referencing an application’s external context in your component methods since objects normally found in an application’s servlet context may not exist in the IDE. This may mean that the IDE cannot render the component; if so, the component is also not visible in the IDE design view.
By now you should understand the differences between customizing a standard component and building a new component, along with the concepts involved in these tasks. The role of JavaServer Faces technology in Java Studio Creator 2 components should also be clear.
This article takes a concrete, "by example" approach to describe the process of developing a component library. It demonstrates how to develop a simple complib that contains components and a converter. Along the way, it describes the major steps of the development process and provides links to sources with more details. You may want to concentrate on these major steps when you first read this article, later you can follow the links for more details.
Generally, the IDE tries to maintain backward compatibility for component library interfaces. If you have developed component libraries, or complibs, for previous versions of the IDE, they will most likely work with Java Studio Creator 2. While the intention is to maintain backward compatibility, it is always possible that the interfaces described here may change in the future.
The Java Studio Creator 2 IDE uses the standard JavaBeans component architecture to associate property editors, customizers, and other metadata with a component at design time. A JavaBean component or bean is a reusable software unit that exposes its features (such as properties, methods, and events) to tools. The IDE expects user-manipulatable objects to be beans. This includes JavaServer Faces components, such as text fields and command buttons, as well as JavaServer Faces converters and validators. Non-JavaServer Faces components, such as Data Providers, must also be JavaBean components. The IDE obtains metadata on these beans using BeanInfo classes and the Java Studio Creator Design-Time API.
Design time refers to those parts of an application used only by a tool or an IDE, such as Java Studio Creator 2. Runtime refers to the parts of an application that are always deployed to a servlet container or application server. Some runtime parts can also be used in a tool or an IDE at design time.
The major steps for adding third-party components to Java Studio Creator are as follows:
1. Create the runtime components. When creating the runtime components, developers should consider design-time aspects since some code may be executed at design time. Components should be JavaBeans components and should meet the guidelines that ensure they will work well in Java Studio Creator 2. Adapting existing components for use in the IDE should follow these same guidelines as described in Part 2 of this article.
2. Create the design-time artifacts for the components. The design-time artifacts include JavaBeans BeanInfo classes, property editors, customizers, icons, and other resources as well as classes that are part of the Java Studio Creator Design-Time API.
3. Assemble all the parts—the runtime components, the design-time code, icons, Javadocs, source code, and a complib manifest—into a complib file.
4. Import the complib into the IDE. The user imports the complib into the IDE and uses the components in an application.
Component developers should perform these steps iteratively until they are satisfied with the results.
To illustrate these steps, let's see how to develop a simple complib containing JavaServer Faces components and a converter. (You may be familiar with the sample-date complib from an earlier version of the IDE; this is an updated version of that complib.) The sample-simple-<version>.complib contains a date picker component, a DHTML popup calendar component, and a combined java.sql.Date and java.util.Date converter, along with some design-time classes. Note that the current complib version number is 2.2.1, but this may change if the complib is enhanced.
If you are writing your own JavaServer Faces component or modifying an existing component to work in Java Studio Creator 2, it is best to use the DHTML popup calendar component as a template. The popup calendar component is a good example of a more complex component; it also illustrates how to add resources (such as java-script and Cascading Style Sheet (CSS) files) to a component library.
The DHTML popup calendar included in the complib is a customized and improved version of the basic Calendar component that comes with the IDE. The DHTML popup calendar can handle different locales and can be embedded within certain components, such as within a Table component. Figure 1 and Figure 2 give you an idea of how this custom component extended the functionality of the basic Calendar component.


Figure 1: DHTML Popup Calendar Custom Component With Localization

Figure 2: DHTML Popup Calendar Custom Component Embedded in Table
You can get a copy of these sample component files from the Java Studio Creator 2 IDE Update Center, which you access from the Tools pull-down menu. There are two files available:
* Binary complib file, which can be imported into the IDE
* Source zip file, which contains a source distribution described in this article
Ideally, an IDE should support any component. However, this requirement often conflicts with a user’s ease-of-use. Since the Java Studio Creator IDE originally emphasized ease-of-use, full generic JavaServer Faces support may be delayed. For example, the IDE allows the user to drag and drop components onto a design canvas. To support this and work well, the components themselves must follow a more restrictive set of rules. (See Writing Custom Components for Java Studio Creator Part 2: Design-Time Considerations for more information.) These rules are useful when modifying an existing component to work well in the IDE, as well as for developing new components.
Creating a component library involves creating various parts, then packaging the parts into a single complib file. A complib can contain the following parts:
* Runtime JAR files, which contain classes and metadata that are deployed to a server at runtime as part of the application. Runtime JAR file are also used at design time.
* Design-time JAR files, which contain classes and metadata used by the IDE itself and not deployed at runtime.
* Javadoc zip files, which contain Javadocs for IDE users. These files are not deployed.
* Source files, which contain Java source code for use by IDE users. These files are not deployed.
* Help information, which is for use by IDE users. (Support for these help files in the complib is not yet implemented in the IDE.)
A JAR manifest file, called MANIFEST.MF, that points to a second file, a configuration XML file, which in turn catalogs the contents of the component library. (This second catalog file allows for hierarchical elements and internationalization.) This example has the manifest file, META-INF/MANIFEST.MF, and the XML catalog file, complib-config.xml. The IDE reads both files, but it is the second file, the complib-config.xml file, that contains all the information on the complib, essentially serving as a table of contents to the complib. The XML file allows the IDE to determine the items (and their types) that are in the component library.
Note: Having two files—a MANIFEST.MF and a catalog XML file—reflects the current approach to component libraries. Older complibs may have only a MANIFEST.MF file; the IDE will support these older complibs to maintain backward compatibility.
Before taking a closer look at the parts of a component library, a few words on the components themselves. While they do not have to be JavaServer Faces components, all Java Studio Creator components must be beans. (For example, Data Providers are beans but not JavaServer Faces components.)
A component that is a JavaServer Faces component is a subclass of UIComponent. Such a component is often referred to as a visual component because it typically includes code to render markup for display in a user agent or user's browser. For visual components, the IDE displays the rendered markup in the Visual Designer at design time. In contrast, other types of beans— including non-JavaServer Faces components—are referred to as nonvisual components.
Runtime artifacts are typically packaged in one or more JAR files. The sample has a JavaServer Faces converter, which is a nonvisual component. Nonvisual components usually are implemented by hand. Visual components are generally more complex. Writing a visual JavaServer Faces component involves creating several Java classes plus some metadata:
* Metadata: sample-simple.tld (tag library descriptor) and XML configuration file(s)
* The UIComponent itself: DatePicker.java and PopupCalendar.java
* The component’s renderer: DatePickerRenderer.java and PopupCalendarRenderer.java
* The component’s tag handler: DatePickerTag.java and PopupCalendarTag.java
Although this might seem like a lot of work, much of the information for a visual component is boilerplate and can even be derived from the same set of metadata. Instead of manually keeping the different parts of a component in sync, one approach is to keep a single set of metadata and provide a code generator to derive the boilerplate classes and configuration files. This approach is illustrated in this article. The sample has two configuration files—faces-config.xml and sun-faces-config.xml— containing metadata that are used as input into a code generator to produce both runtime and design-time artifacts.
The code generator is optional. If you experience problems running the code generator for your own components, you can determine how to manually write your own code by examining the output that the generator produced for the sample components.
Design-time artifacts are typically packaged in a design-time JAR file. These artifacts include:
* Design-time classes:
o PopupCalendarBeanInfo.java describes the PopupCalendar bean.
o PopupCalendarDesignInfo.java supports dynamic design-time behavior.
o SqlUtilDateConverterBeanInfo.java describes the SqlUtilDateConverter bean.
* Other code, such as custom property editors: YearAlignPropertyEditor.java
* Other resources: PNG icon (image file) for DatePicker
Other optional files, such as Javadoc and source code files, can also be packaged in zip files. These files allow the IDE to provide Javadoc and source during development.
The complib contains a date picker component and a combined java.sql.Date and java.util.Date converter, along with some design-time classes.
Let’s start by creating a runtime JAR file containing the JavaServer Faces components for the date picker component. The java.util.Date converter can be implemented manually as a bean without any properties.
Visual components require three kinds of runtime classes: the UIComponent class itself, the tag handler class, and the renderer. Much of the UIComponent code is boilerplate and can be generated automatically. Similarly, the tag handler follows a boilerplate pattern and can also be generated automatically. No special component code should be in the tag handler since the Java Studio Creator 2 IDE does not execute tag handlers at design time. Of the three, the renderer is what gives the component its unique character and is thus typically written by hand.
The tag library descriptor, the TLD file, can also be generated automatically.
A JavaServer Faces runtime requires a configuration file, faces-config.xml, to determine the types of components, converters, validators, and renderers for an application. However, the schema for the faces-config.xml file is extensible, and Java Studio Creator 2 extends it to allow additional metadata, which can be used as input to a code generator. Typically, this extended metadata file is called sun-faces-config.xml.
Because it is required by the runtime, only the minimal metadata required for runtime is included in the faces-config.xml file. All extended metadata information is kept in the sun-faces- config.xml configuration file.
Let's look at the sample faces-config.xml file. It has minimal information about the date picker component and its renderer. When creating a new component, first add entries to this file.
Next, examine the sun-faces-config.xml file. This file contains the component's description, tag-name, taglib-uri, base-component-type, and instance-name, as well as all its properties. Each property contains a description and other metadata, such as display name, type, JavaBeans property editor, and category in the property inspector.
The metadata in the sun-faces-config.xml file is used to generate the following:
* Component base classes containing concrete properties and value bindings. For example, DatePickerBase.java.
* Tag library handler classes containing code to collect JavaServer Pages (JSP) attributes and set their values on properties in component classes. For example, DatePickerTag.java.
* A tag library descriptor file that tells the JSP compiler in a container how to process the tags in a JSP page. For example, sample-simple.tld.
* JavaBeans BeanInfo base classes that contain metadata on a component. For example, DatePickerBeanInfoBase.java.
For more information on running the Java Studio Creator code generator with the sun-faces- config.xml file as input, see the gen-all target in the ant build.xml file. (The build.xml file is part of the sample source distribution that you can download. You should open this file to see this target reference.) Keep in mind, however, that the code generator interface may change.
After running the code generator, you need to write the actual renderer and component classes manually . For details, see the code in the following files:
* Renderer class: DatePickerRenderer.java
* Component class: DatePicker.java which extends DatePickerBase
Finally collect all the runtime classes, resources, and the faces-config.xml file and create the runtime JAR. See the jar-rt ant target in the ant build.xml file.
The next major step is to create a design-time JAR file. The design-time JAR file contains BeanInfo classes and other items that are not deployed to a container but are used only by a tool.
The gen-beaninfo target in the ant build.xml file, run by the gen-all target, also generates BeanInfo base classes. You need to extend these base classes to create BeanInfo classes.
If you forget to extend the BeanInfo base class, your component will not work correctly because the JavaBeans Introspector returns a BeanInfo class that is based on inspecting the bean using the Java reflection API.
Java Studio Creator uses BeanInfo classes as the exclusive source of static metadata about components. Refer to the DatePickerBeanInfo.java source code for more information. Note how you can associate an icon with the component by adding an image file and how you can manipulate property descriptors.
Design-time JAR files also contain DesignInfo classes. DesignInfo classes provide dynamic behavior rather than static information about a component. The sample DatePickerDesignInfo.java shows how a property can be changed at design time when you add a new instance of a date picker to a page. The sample also shows how to link a DateUtilConverter to a DatePicker using the Java Studio Creator Design-Time API. This API extends the standard JavaBeans API and adds a rich set of new features to manipulate components and properties at design time and provides the IDE with context menu items, customizers, and extended property editors.
Other items typically placed in a design-time JAR file are property editors, category descriptors, and localization resource bundles. For example, in DatePickerBeanInfo, the DatePicker yearAlign property is associated with com.example.util.YearAlignPropertyEditor, which is also included in the design-time JAR file. For details, see the jar-dt target in the sample build.xml file.
Other optional items useful to the IDE users can be included in a complib. These items are:
* Javadoc files: See the javadoc and complib ant targets.
* Source files: See the complib ant target, which shows how to include a source code zip file.
* Help: Eventually help files will be supported, but currently they are not supported.
Assembling the complib file is the final step. First, create a JAR manifest file containing a pointer to an XML config file. In this example, complib-config.xml contains all metadata about the complib.
In the example, the conf/complib-config.xml file contains a pointer to a Java property ResourceBundle for internationalization. It explicitly declares component classes within the IDE’s Palette categories. It also uses filter expressions that are replaced by the ant copy task.
Finally, create the complib file with the JAR ant task. See the complib target for details.
Test your assembled component library as follows:
1. Open the Component Library Manager dialog. In the IDE, select Tools->Component Library Manager from the menu bar. (Alternatively, you canselect Manage Component Libraries from a Palette category context menu.)
2. Click the Import... button in the Component Library Manager dialog to open the Import Component Library dialog.
3. Browse to your complib file and import it.
4. Add a component from the newly imported component library to test your component.
Java Studio Creator 2 takes the imported component library and expands the package, adding the components in the imported library into the user Palette. (You might need to open the Palette category to see the new components.) It also copies the expanded complib to a location under the current user directory, ~/.Creator/. (Note that this location may change.)
Test the component by adding it to a page. The first time you add the component to a page, the IDE copies the unpacked complib into the project and creates a reference to the component library. You can see the reference in the Projects window beneath the Libraries node for the project. You can see a project’s added libraries by selecting the project node’s Properties context menu item in the Projects window.
Keep in mind these other considerations when working with component libraries.
* When you first import a complib, the IDE unpacks and expands the complib file into a subdirectory of the Java Studio Creator userdir. For example, in Java Studio Creator 2, it is placed under ~/.Creator/2_0/complibs/. However, the location of the actual Java Studio Creator userdir may change. Each project that uses a component library has its own copy kept in a subdirectory of the project that is created the first time a component from a particular component library is added to the project.
* Consider the following plan of attack if you develop a component iteratively. First, change some code, generate a new complib, import the complib into Java Studio Creator, then test the new code within an existing project. You may want to overwrite the previous project complib explicitly. To do so, add a component from the newly imported complib displayed in the Palette to a page in the project, then undo the add. This action causes the IDE to overwrite the older complib with the new complib in the project. Even if both complibs have the same identifier (uri, version pair), the IDE overwrites the older one with the new version because of its use of timestamps.
* Third-party developers should use the IDE’s Java Studio Creator Design-Time API to create a richer design-time experience.
* You can set a command line property to specify the initial component library import browse directory. For example, on a Windows system, you can open a DOS prompt and execute: C:\Sun\Creator\bin\creator.exe -J-Dtoolbox.importStartDir=/cygwin/home/ edwingo/tmp.
* Java Studio Creator 2 allows you to auto-install a component library by placing the complib file in a special directory: $RAVE_INSTALL_HOME/complibs_to_install/. The next time you run the IDE, the complib files in that directory are installed into the Palette automatically.
* Be sure that a visual component’s BeanInfo class extends the generated BeanInfoBase class. If not, you may see a problem when you add the visual component to a project. Even if you developed the visual component following the procedure used for the sample component, if its BeanInfo class does not extend the BeanInfoBase class, the newly added component may appear in the Outline window, not in the Visual Designer and the error log shows no exceptions. You can ignore the following warning message, which may appear in the IDE log file: "You are trying to access file: complib-config.xml from the default package...".
* Existing generic JavaServer Faces components (such as myfaces and ourfaces) require additional modification to work with the IDE. You can get some generic components to work by adding additional design-time code; in other cases you might need to modify the component runtime code. Once modified, you can package these components into a complib file. See Writing Custom Components for Java Studio Creator Part 2: Design-Time Considerations for guidelines. Sometimes, the properties for the Date component do not update properly in the Properties window. To force an update, click the property in the Properties window. Some Date properties are read-only; you can only access them using Java code getter methods.
Now you've had an overview of the process for creating and using a component library for the Java Studio Creator 2 IDE. You've learned the different files that make up a component library, along with the steps for building, assembling, and testing the components in such a library.
The sample component with sources referred to by this article are downloadable from the Java Studio Creator 2 IDE Update Center. They provide a good means for seeing the make-up of a component library first hand.
The Java Studio Creator 2 IDE uses the standard JavaBeans(tm) component architecture to associate property editors, customizers, and other metadata with a component at design time. A JavaBean component or bean is a reusable software unit that exposes its features—its properties, methods, and events—to tools. The IDE expects user-manipulatable objects to be beans. This includes JavaServer Faces components, such as text fields and command buttons, as well as JavaServer Faces converters and validators. It also applies to non-JavaServer Faces components such as Data Providers, which are components that subclass the DataProvider class. The IDE obtains metadata on these beans using BeanInfo classes and the Java Studio Creator Design-Time API.
While Java Studio Creator components do not necessarily have to be JavaServer Faces components, they do all have to be JavaBeans components. For example, Data Providers are beans but they are not JavaServer Faces components. A JavaServer Faces component is a subclass of UIComponent and is often referred to as a visual component because it usually includes code to render markup for display in a user agent. For visual components, the IDE displays the rendered markup in the Visual Designer at design time. Other types of beans that do not have code to render markup are referred to as nonvisual components.
Nonvisual components are relatively straightforward to develop. For example, like all beans, they need to have concrete typed properties with accessor methods. The IDE uses BeanInfo classes at design time to obtain information about the component, such as its base instance name, then uses that information when instantiating and persisting a bean in a project. The Java Studio Creator Design-Time API document provides more information on the BeanInfo constants.
Visual JavaServer Faces components are more complex and this article makes them its focus. Like all beans, visual components have the same fundamental requirements as nonvisual components; they also have some additional guidelines developers need to follow. In particular, when writing the runtime code for a visual component, you should also keep in mind that parts of the component code will be run at design time within the IDE.
Visual components typically consists of three parts: a component class, a renderer, and a tag handler. There is also a tag library descriptor file, which is typically identified with a .tld extension. The IDE currently ignores the tag library descriptor file, although a servlet container or application server may use this file.
The following sections cover the rules and provide development tips for the different parts of a visual component.
Components should have concrete properties and not rely on the generic attributes capability of the UIComponent superclass. The IDE uses the JavaBeans architecture and expects typed properties with accessor methods. When possible, avoid Object typed properties since use of this type can require casting in Java code. Instead, use appropriately typed properties or provide aliased properties. For example, use the following in component code:
public String getText() {
return (String) getValue();
}
public void setText(String text) {
setValue(text);
}
By using appropriately typed or aliased properties, IDE users can use the IDE’s code completion capabilities and can avoid inserting type casts. Rather than users having to write code like this:
String myString = (String) textField1.getValue();
Instead, IDE users can write code like this:
String myString = textField1.getText();
Components should have a style property. Java Studio Creator uses this style property for absolute positioning. Typically, components also have a styleClass property that holds the name of a CSS style class. See “ Renderer Guidelines” for additional information.
The renderer for a component is typically implemented as a separate class. Here we list the guidelines for writing renderers.
Because the IDE calls the rendering methods at design time to generate a visual representation in the Visual Designer, the renderers must be able to execute successfully under conditions that may not be typical at runtime. For example, component properties might be in a partially initialized state since a user can change a property during design and the tool calls the component’s renderer to update its visual representation. Similarly, any cached helper components or facets may also need to be reinitialized.
Avoid using the ResponseWriter.write method except to pass on user markup from a property. Instead, generate markup using the methods ResponseWriter.startElement, ResponseWriter.endElement, and ResponseWriter.writeAttribute.
Always provide a component reference to the ResponseWrite method startElement(String name, UIComponent component). The tool uses this reference to determine the component a user has selected in the Visual Designer.
Propagate the style property to the rendered output to allow positioning and sizing of the component. For a component with a single top-level element or a single visual top-level element, duplicate the style property on that element. For example, if the JavaServer Pages (JSP) page contains:
<foo:bar style="width: 400px; color: blue"/>
The rendered output should be something like:
<div style="width: 400px; color: blue">
<input type="submit" value="Hello"/>
</div>
Components with multiple visual top-level elements should be wrapped in a single top-level element.
Handle the styleClass property in a similar manner to the style property. That is, consider providing a styleClass property that is propagated to the HTML class attribute in a similar way and to the same element as the style property.
Design-time rendering can be special cased by testing for Beans.isDesignTime. It is also possible to overlay a special design-time renderer on top of the normal runtime renderer. For example, you can create a MyDesignTimeRenderer, which delegates to the normal runtime MyRenderer. Next, create an additional design-time META-INF/faces-config file, which you add to the design-time JAR file, then add an entry to MyDesignTimeRenderer to reference the design-time faces-config file. The tool executes only the design-time renderer; it will not be executed at runtime.
Since the JSP tags associated with components are not executed at design time, they should not include logic other than copying in the relevant attributes with type conversions. You will want to follow this guideline to ensure that your components work with non-JSP view handlers, too.
The runtime parts of a component are packaged in one or more runtime JAR files and are deployed to a web container such as an application server. At design time, the tool can use some of the runtime parts in addition to design-time code and metadata. Java Studio Creator uses JavaBeans for static design-time metadata and relies on the Java Studio Creator Design-Time API to enable dynamic design-time behavior. (The Java Studio Creator Design-Time API specification is available at http://developers.sun.com/prodtech/javatools/jscreator/reference/docs/apis/designtime/.)
You can use the Java Studio Creator Design-Time API to do the following:
* Create context menu items
* Add enhanced property editors and bean customizers
* Create specialized behavior on drop operations
* Add the ability to link components together
* Accept or reject parent or child component drop operations
* Create more advanced behavior, such as inline editing, mouse regions, and so forth.
The IDE needs to know the mapping of a component to a tag and it obtains this static metadata from a BeanInfo. For example:
private java.beans.BeanDescriptor beanDescriptor;
...
beanDescriptor.setValue(Constants.BeanDescriptor.TAG_NAME,"commandButton");
beanDescriptor.setValue(Constants.BeanDescriptor.TAGLIB_PREFIX,"h");
beanDescriptor.setValue(Constants.BeanDescriptor.TAGLIB_URI,
"http://java.sun.com/jsf/html");
You can write a BeanInfo class by hand or use a code generator. Input to a code generator is an XML sun-faces-config.xml file that contains the metadata for each component. For more information, see the example sample-simple-<version>.complib (available for download from the IDE Update Center) discussed in the Writing Custom Components for Java Studio Creator Part 1: Developing a Component Library article. In particular, see the section Running the Code Generator in that article.
The following code shows the metadata necessary for a renderer.
<renderer-extension>
...
<instance-name>button</instance-name>
<tag-name>commandButton</tag-name>
<taglib-prefix>h</taglib-prefix>
<taglib-uri>http://java.sun.com/jsf/html</taglib-uri>
</renderer-extension>
You might wonder what qualifies as dynamic design-time behavior. A good example of such dynamic behavior is the following scenario: You drop a table component on the Visual Designer, then create a number of dummy rows and columns. You can associate dynamic behavior with a component by using a DesignInfo class. A simple example can be found in the same sample-simple-<version>.complib mentioned above. This complib is available for download from the IDE Update Center.
You've read a number of guidelines you should keep in mind when writing custom components, particularly visual components, for the Java Studio Creator 2 IDE. You've also seen how to write the component class, as well as the code for the renderer and tag handler files.
Components, which are simply Java classes with properties, methods, and events, can be visual or nonvisual and server- or client-based. Properties affect the look-and-feel of a component and its behavior, and can be manipulated both during design and runtime. At runtime, methods – also called operations – are invoked on components and result in the component doing certain things. Components broadcast events, which are runtime messages, during their lifecycle to indicate some change in their state.
The Sun Java Studio Creator 2 IDE includes a visual design environment for drag-and-drop creation of visual and nonvisual applications. Using this API, component developers gain access to the rich array of design-time interactions available in the IDE's visual design environment. The API enables a component developer to customize the user's design-time experience with mouse interactions. This includes extending such mouse operations as drag, drop, and link. The API also lets developers create custom context menus, perform custom rendering, and customize property editors. In addition, a developer can add customizers to the IDE and have these customizers be context aware.
Component developers, especially if they are familiar with the JavaBeans model, should find it easy to use the Java Studio Creator Design-Time API. The Creator Design-Time API is closely coupled to the JavaBeans API, but it is extended to better handle design-time manipulation of live component objects in a visual design environment. The JavaBeans component model covers most requirements for defining the properties, methods, and events that make up a component, and it even covers many design-time manipulation details, such as property editors and customizers. However, as good as the JavaBeans component model is, it does fall short in some areas.
The Java Studio Creator Design-Time extends the JavaBeans model by adding a set of interfaces that help accomplish some significant design-time tasks. One of the key extensions is a set of interfaces that maintain design-time context information. This context information simplifies working with components that are bound to each other, such as a data-aware text field bound to a column in a table.
Another extension handles persistence generation. An IDE must be able to persist whatever a user does in the tool's visual editor. The Java Studio Creator IDE directly stores user manipulations in a page's backing JSP file and Java source code file – that is, in the Page1.jsp and Page1.java source code. Other IDEs typically use an application's real source code to persist visual design changes. Furthermore, the Java Studio Creator Design-Time API includes a set of interfaces implemented within the IDE, which ensure that the IDE generates the correct source code. To accomplish this, these interfaces marshal all design-time direct manipulations of a live object. Thus, when you want to set a property value using the Java Studio Creator Design-Time API, you first retrieve the DesignProperty you want to set from the DesignBean that you're manipulating. Then you call one of two methods: DesignProperty.setValue(Object) or DesignProperty.setValueSource(String). These methods cause the IDE to set the property to the specified value and also generate the appropriate source code.
In addition, the Java Studio Creator Design-Time API gives component developers full access to live event hooks during design time. These live event hooks cover such tasks as generation and querying, among others. That is, component developers can, if desired, gain access to event hooks generated by a customizer, a property editor, or even by right-clicking a context menu on a component.
Another important feature included in the Java Studio Creator Design-Time API is the ability to completely manipulate the full hierarchy of components, both visual and nonvisual components. This feature allows a component developer to enable a Customizer, Property Editor, or (right-click) context menu item to alter the containership hierarchy of a set of JavaBeans components. The standard JavaBeans model does not allow component developers to enable dynamic creation of a new instance or manipulate containership during design time. With the Java Studio Creator Design-Time API, for example, a component developer can create a Customizer for a data grid component and, based on user input to the Customizer, have it completely change the containership hierarchy beneath the data grid component. A user might use the Customizer to create a set of columns and fields inside the data grid component's existing columns. The component developer can also use the API to create instances of helper components and classes at the same time that the user manipulates the Customizer dialog. The developer can even batch these operations behind an Apply or Cancel operation.
The Java Studio Creator Design-Time API extends the JavaBeans model of mouse interaction at design time. The API includes full contextual mouse interaction with a live JavaBean component at design time. This permits the component developer to define these mouse interactions in a component-specific way. What might this entail? A developer, during design time, might want to click the tabs of a tabbed pane component to select a particular pane. While this seems simple, the standard JavaBeans model does not allow it. Other IDE vendors have added hard-coded, component-specific solutions for these interactions, and some solutions have been added to the Swing library. However, the Java Studio Creator Design-Time API makes mouse interaction at design time available to any component developer.
To get the most from the information presented below, you should be familiar with JavaServer Faces components, their tags, and how to write them. Many documents have been written on this subject and you might want to refer to them before continuing. A good one to start with is Writing Custom Components, Part 1: Developing a Component Library.
Writing a JavaServer Faces component is not difficult. It requires writing three to four classes that define the component: a subclass of a standard UIComponent that comes close to your component's functionality; a renderer subclass, and a tag handler class to drive the render response phase. You also need to write a .tld file (a Tag Library Descriptor file – an XML document that describes a tag library), and metadata files (such as faces-config.xml) that contain information about your component.
There are four rules you need to follow when writing your own JavaServer Faces components. By adhering to these rules, you can ensure that your components will work correctly when sized and positioned using CSS properties. They also ensure that your components work well during the design phase in a tool such as Java Studio Creator. The four rules are presented in order of importance:
First and foremost, you must use the ResponseWriter's startElement, endElement, and writeAttribute methods rather than using the write method. It is important that you do not write out markup by simply streaming out HTML bytes linearly using the write method.
However, there is one minor exception to this rule: Some components need to produce HTML output provided by the user. For example, this exception applies to the HtmlOutputText component when its Escape property is set to false. You may use the write method for this limited scenario.
It is important to always pass in a component reference to the ResponseWriter startElement method. For example, if your UIComponent is a PanelGrid, and you want to produce <table><tr><td>... as output, you would pass in the following to startElement:
writer.startElement("table", gridpanel);
writer.startElement("tr", gridpanel);
writer.startElement("td", gridpanel);
Every component should have a style property that renders to a style attribute on the rendered HTML markup. Having a style property allows tools like Java Studio Creator to use the stylesheet to position and size the component.
Keep in mind that it is vital you remember to replicate this style attribute on your top-level rendered HTML tag. Unfortunately, things aren't always so simple, and you should keep in mind the following three possible complications and how to handle these situations so as to avoid problems:
* Rendering a single top-level HTML element – Normally, you render a single top-level HTML element (even one possibly with children) from the JSP tag. In this case, simply duplicate the value of the JSP tag's style attribute to the top-level HTML tag attribute. For example, if you have
<h:commandButton style="width: 100px"/>
in the JSP, you would rende