Sun ™ Studio Creator 2 Design-Time API User Guide (for component authors)

Joe Nuxoll

Version: 2.0 August 15, 2005 Java Studio Creator Design-Time API User Guide

Table of Contents

1 – Introduction 1.1 – Definitions 1.1.1 – Component 1.1.2 – Component Model 1.1.3 – JavaBean Component and JavaBeans Component Model 1.1.4 – Component Library 1.1.5 – Component Author 1.1.6 – IDE (Integrated Development Environment) 1.1.7 – IDE Vendor 1.1.8 – Application Developer 1.2 – JavaBeans 1.0 Extensions Provided by CDT 1.2.1 – Design-Time Context 1.2.2 – Generation of Persistence 1.2.3 – Manipulation of Hierarchy 1.2.4 – Rich Mouse Interaction 2 – The Java Studio Creator Design-Time API 2.1 – General Model and Hierarchy 2.1.1 – DesignProject 2.1.2 – DesignContext 2.1.2.1 – MarkupDesignContext 2.1.2.2 – FacesDesignContext 2.1.3 – DesignBean 2.1.3.1 – MarkupDesignBean 2.1.3.2 – FacesDesignBean 2.1.4 – DesignProperty 2.1.4.1 – FacesDesignProperty 2.1.5 – DesignEvent 2.2 – Access and Hook Points 2.2.1 – DesignInfo 2.2.1.1 – MarkupDesignInfo 2.2.1.1.1 – MarkupRenderContext 2.2.1.1.2 – MarkupMouseRegion 2.2.1.2 – MarkupTableDesignInfo 2.2.2 – PropertyEditor2 2.2.3 – Customizer2 2.2.4 – DisplayAction and DisplayActionSet 2.2.5 – Result 2.2.5.1 – ResultMessage 2.3 – Extended Metadata 2.3.1 – Additional BeanInfo Attributes 2.3.2 – Additional PropertyDescriptor Attributes 2.3.3 – Additional EventDescriptor Attributes 2.3.4 – Context Data Attributes 3 – Examples and Use Cases 3.1 - Example: Providing Extended BeanInfo Metadata 3.2 - Example: Providing Custom Right-Click Context Items 3.3 - Example: Using beanCreatedSetup Method to Setup Initial State 3.4 - Example: Creating a Customizer2 Dialog 3.5 - Example: Using a PropertyEditor2 to Scan Design Context 3.6 - Example: Interaction With the User Via a Result Object Java Studio Creator Design-Time API User Guide

1 – Introduction

This document is for component authors that want to provide a better design-time experience for their users, developers using Sun Java™ Studio Creator Integrated Development Environment (the IDE). This document outlines the concepts, APIs, and use-model of the Java Studio Creator Design-Time API (CDT), which is the rich design- time interaction API hosted by Sun Java Studio Creator.

The CDT provides component authors with access to the rich design-time interactions available in the visual design environment. Via this API, a component author can create a rich design-time experience for users of their components. This includes mouse interactions (drag/drop/link), custom context menus, custom rendering, as well as context-aware customizers and property editors. The CDT is closely coupled with the JavaBeans™ API – and extends this API to better handle design-time manipulation of live component objects in a visual design environment.

1.1 – Definitions

A clear understanding of the following definitions is essential to understanding this guide.

1.1.1 – Component – A Java class that is used as a functional building block in a modern software application. A component has properties, methods, and events (PME). Properties can be manipulated at design-time and runtime, and affect the settings and behavior of the component. Methods can be invoked at runtime to make the component do things, and are also referred to as operations. Events are runtime messages broadcast by a component during its lifecycle, indicating that its state has changed in some way. A component’s events can be hooked by an application – thus invoking application-specific code. A component can be visual (like a TextField or a TreeControl) or non- visual (like a Connection or a Timer). Components can exist on the server or on the client. Sometimes, the term control is used in place of component, but the term control often implies a higher-level client-side component.

Author’s aside: Components simplify learning how to build an application by allowing the application developer to learn the features of a software platform piece by piece – while employing the same development model (setting properties and hooking events). Instead of having to learn a new OO-based API for each new platform technology they might need to leverage, the developer can focus on one component at a time, and just learn how to use each one as they go along.

1.1.2 – Component Model – The rules for defining a component on a particular software platform. A component model includes patterns and/or language syntax for declaring the properties, methods, events (PME), and the interaction lifecycle of a component. A component model also defines the design-time interfaces that an IDE or a developer uses to manipulate a component. A software platform’s “component model” API typically defines the primary development model / methodology that a developer uses to build applications.

1.1.3 – JavaBean Component and JavaBeans Component Model – The Java Platform’s version of component and component model. A JavaBean is a component in the Java Platform. The JavaBeans Component Model (or simply JavaBeans) is the prescribed component model for the Java Platform.

1.1.4 – Component Library – A collection of components usually supplied by the same vendor, and designed to work together seamlessly. For example, Swing is a component library.

1.1.5 – Component Author – A company, group, or individual that is responsible for implementing and making available components or component libraries. Component authors leverage the Java Studio Creator Design-Time API to supply greater value with their components.

1.1.6 – IDE (Integrated Development Environment) – An IDE is a software program that is designed to aide in the creation of other software programs. An IDE typically includes a text-based source code editor, an integrated compiler, and debugging and profiling functionality. Modern IDEs also include a visual design environment for drag and drop creation of visual and non-visual applications, as well as fully context-sensitive code completion and refactoring in the editor. Sun Java Studio Creator software program is an IDE.

1.1.7 – IDE Vendor – This is simply a company, group, or individual that is responsible for implementing and making available one or more IDE products. Sun Microsystems is an IDE Vendor.

1.1.8 – Application Developer – An individual that uses an IDE to build an application. This person uses standard components, and might purchase 3rd party components to help them assemble applications quickly and simply.

1.2 – JavaBeans Extensions Provided by CDT

The JavaBeans Component Model specification covers most of the requirements for defining a component in Java. A component author can declare and document properties, methods, and events, as well as most of the critical design-time metadata that describes a JavaBean component. The specification also covers a lot of design-time manipulation details, such as PropertyEditors, Customizers, and so on.

One place where JavaBeans stands out from other component models is the strict separation of design-time vs. runtime. With JavaBeans and the Java Studio Creator Design-Time API, it is possible to create a rich design-time experience for a developer without sacrificing any runtime performance or incurring additional deployment overhead. CDT keeps true to this strict separation.

CDT makes it possible to perform a number of common design-time tasks that are not possible with the standard JavaBeans 1.0 design-time APIs, as described in the sections that follow.

1.2.1 – Design-Time Context

It is common to see a visual, data-aware control with two data-binding properties: for this example, a data-aware DbTextField with a rowSet property (of type javax.sql.RowSet), and a columnName property (of type java.lang.String).

At design-time an application developer first sets the rowSet property. Typically, this will be done by clicking the DbTextField to select it in the Visual Editor, then choosing the rowSet property in the property sheet, then selecting a RowSet instance name from a drop-down list of RowSet instance names on the page being designed. Once the developer has set the rowSet property, they click the columnName property, and select a column name from the drop-down list of column names in the previously set RowSet instance.

Though it seems simple, none of this can be done with standard JavaBeans APIs. With these APIs, a PropertyEditor is only passed the instance of the property value to edit. For the rowSet property, an instance of a RowSet (or null) would be passed to the PropertyEditor.setValue(Object) method, and there would be no way to obtain a list of RowSet instances on the page to display to the user. When the columnName property is set, a String (or null) is passed to the PropertyEditor.setValue (Object) method, and the PropertyEditor is only passed the characters of the String itself. The PropertyEditor does not know that the property value represents a column name on a component that also has a rowSet property that might or might not be set.

This missing information is called design-time context. With the Java Studio Creator Design-Time API, it is trivial for a component author to access the live component that owns the property being set, and query its rowSet property to see if it is currently set, and then get the correct SQL metadata to provide a list of column names to display to the user. It is equally trivial to query the context of the component being designed to get a list of instances variables that satisfy a particular interface or ancestry constraint, like showing a list of RowSet instances available on the page.

1.2.2 – Generation of Persistence

An IDE has to be able to persist everything that a user does in the Visual Editor. In Java Studio Creator, manipulations are stored in the Page1.jsp and Page1.java source code directly. Most IDEs use the real source code as their persistence mechanism for visual design.

The Java Studio Creator Design-Time API includes a set of interfaces implemented within Java Studio Creator that marshal all direct manipulations of a live object at design-time, thus ensuring the correct source code will be generated. To set a property using the CDT, you get the DesignProperty you want from the DesignBean you wish to manipulate and call DesignProperty.setValue(Object) or DesignProperty.setValueSource(String). The IDE will then set the property as specified and generate the appropriate source code.

Additionally, the Java Studio Creator Design-Time API grants a component author full access to live event hooks (generation, querying, and so on), all at design-time. For example, a Customizer, PropertyEditor, or right-clicking a context menu on a component could generate specific event hook(s) if desired.

1.2.3 – Manipulation of Hierarchy

What of a component designer wants to enable a Customizer or PropertyEditor or right-click context item to alter the containership hierarchy of a set of JavaBeans components? With standard JavaBeans, it is not possible for a component author to enable dynamic creation of a new instance or manipulation of containership in any way at design-time (not with a PropertyEditor or a Customizer or in any other way).

The Java Studio Creator Design-Time API includes the ability to completely manipulate the full hierarchy of components, visual and non-visual. A component author can, for example, create a Customizer for a datagrid component that completely changes the containership hierarchy underneath the datagrid based on the user’s input in the Customizer for example, creating a set of columns and fields inside the columns. The component author can also create instances of helper components and classes as the user is manipulating the Customizer dialog. In addition, the component author can batch these operations behind an Apply/Cancel operation.

1.2.4 – Rich Mouse Interaction

One major missing feature of the JavaBeans Component Model is the concept of mouse interaction at design-time. For example, a developer might want to be able to click the tabs of a JTabbedPane component at design-time to select them. This seems simple, but there is no way to do this sort of thing with standard JavaBeans. IDE vendors have been forced to add hard-coded, component-specific solutions for these types of interactions. Most of these solutions have been added for the Swing library only, understandably because Swing has become very popular. Mouse interaction at design- time should be available for any component vendor to take advantage of. The Java Studio Creator Design-Time API includes full contextual mouse interaction with a live JavaBean component at design-time, and allows the right party (the component author) to define these interactions in a component-specific way. Java Studio Creator Design-Time API User Guide

2 – The Java Studio Creator Design-Time API

The Java Studio Creator Design-Time API provides component authors with access to the rich design-time interactions available in the visual design environment. This API is essentially divided into two parts:

• Interfaces that are implemented by the Sun Java Studio Creator IDE itself. These interfaces are referenced by the component author in their design-time code to access the live component instances being designed and to retrieve contextual information. These interfaces are discussed in section 2.1 of this document.

• Interfaces to be implemented by the design-time classes supplied by the component author. The Sun Java Studio Creator IDE uses these classes at design-time to perform the specified functions while the end user (the developer using the IDE) manipulates the components in the visual designer. These interfaces are discussed in section 2.2 of this document.

CDT was conceived and implemented as an integral part of the Sun Java Studio Creator IDE (the IDE). The initial version of the IDE focused on JavaServer FacesTM (JSF) components, but the Java Studio Creator Design-Time API was designed to handle JSF components, GUI components (like Swing), and beyond. Due to time and resource constraints during development of the API, JavaServer Faces components received the greatest attention. It is expected that this API will evolve as the Sun Java Studio Creator IDE provides support for client GUI and mobile application development in the future.

2.1 – General Model and Hierarchy

The Java Studio Creator Design-Time API is in the com.sun.rave.designtime.* package (and sub-packages), and is contained in the DesignTime NetBeans module. The following interfaces are implemented by the Sun Java Studio Creator IDE itself. They provide access the live bean instances in the visual designer and to the context of the design session.

DesignProject (one per project) +->> DesignContext (one per IDE design-time session) +-> DesignBean (the root component being designed) +->> DesignBean (one of many beans on design surface) +->> (possible child hierarchy)... Figure 2.1.a The figure above is a tree diagram of the basic hierarchy of the Java Studio Creator Design-Time API interfaces. These particular interfaces are in the com.sun.rave.designtime.* package. Everything lives within a single DesignProject, which contains any number of DesignContext objects, each of which represents a single design-time session within an IDE. There is a different DesignContext for each page being designed in the running IDE. The DesignContext provides access to the entire contextual tree of components at design- time.

There is a single root component per DesignContext, a DesignBean component. The root component is the this component (the Java keyword used in source code) that is being designed. For example, if one were designing a JFrame, the root component would be a JFrame subclass itself, probably named by default JFrame1.

There is a basic hierarchy of components beneath that root component. This hierarchy might imply physical containership (as in AWT or JavaServer Faces components), where the notion of containership is defined by the adding of child components to a parent component. The containership does not have to be UI-based. For example, a DatabaseTable bean could contain DatabaseColumn components, and so on.

Not all DesignBean instances represent AWT-based or JavaServer Faces-based components. A non-visual Timer component would be a child of the root component in this model.

Component authors have access to this whole contextual tree at design-time. They are free to make any changes they like, including creation and deletion of components anywhere in the tree, and the correct persistence will be kept in sync. For example, if a component author's code creates a new DesignBean, the correct code will be inserted into the Page1.java and Page1.jsp file to represent that bean instance.

2.1.1 – DesignProject

The DesignProject interface represents a simple project in an IDE. All of the DesignContext instances (designable files) can be retrieved from the DesignProject. The DesignProject also provides access to resources found in the project directory (source files, images, etc). A component author may wish to store name-value pairs on the DesignProject – as a project-level setting or as a global setting across all projects.

Following are the main methods of the DesignProject interface and a brief explanation of their function.

DesignContext[] getDesignContexts() Returns all the DesignContext instances in this project. There will be one DesignContext for each designable file in the project. Note that for JSF, this means one DesignContext for each combination of "PageX.java" and "PageX.jsp" file, as well as one for each of the non-page beans, like "SessionBeanX.java", "ApplicationBeanX.java", etc.

DesignContext createDesignContext( String className, Class baseClass, Map contextData) Creates a new DesignContext (backing file) in this project. boolean removeDesignContext(DesignContext context) Removes an existing DesignContext (backing file) from this project.

URI[] getResources(URI rootPath, boolean recurseFolders) Returns the set of project root relative resources in this project as an array of local resource identifiers. The returned URIs will always be paths from the project root, including folder hierarchy within the project. The specified rootPath is used as a filter, to allow drilling-in to directories as desired. Use URI.relativize() to make relative URIs when needed. Use getResourceFile(URI) to retrieve a File object for a particular resource in the project.

File getResourceFile(URI resourceUri) Returns a java.io.File object containing the specified resource.

URI addResource(URL sourceUrl, URI targetUri) throws IOException Copies a resource into this project, and converts the external URL into a local URI (resource identifier string). boolean removeResource(URI resourceUri) Removes a resource from the project directory. void setProjectData(String key, Object data) Object getProjectData(String key) Sets/gets a name-value pair of data on this DesignProject. This name-value pair will be stored in the associated project file, so this data is retrievable in a future IDE session.

NOTE: The data object can be a simple String or a complex (non-String) Object. Either way, it will be stored as text in the project file. When the project file is written to disk, any complex (non-String) objects will be converted to String by using the toString() method. A component author who wants to store a complex (non-String) object must be sure to override the toString() method on the object and serialize out enough information to be able to restore the object when a subsequent call to getProjectData returns a String. Even if a complex object was stored via the setProjectData method, a component author might get back a String from getProjectData if the project has been saved and reopened since the previous call to setProjectData. It is the responsibility of the component author to reconstruct the complex object from the String, and if desired, put it back into the project by using the setProjectData method. Doing so ensures that all subsequent calls to getProjectData with that key will return the complex object instance until the project is closed and restored. void setGlobalData(String key, Object data) Object getGlobalData(String key) Sets a global name-value pair of data. This name-value pair will be stored in the associated user settings file (as text), so this data is retrievable in a future IDE session.

NOTE: The data object can be a simple String or a complex (non-String) Object. Either way, it will be stored as text in the user directory. When the IDE is closed, and state is written to disk, any complex (non-String) objects will be converted to String by using the toString() method. A component author who wants to store a complex (non-String) object must be sure to override the toString() method on the object and serialize out enough information to be able to restore the object when a subsequent call to getGlobalData returns a String. Even if a complex object was stored via the setGlobalData method, a component author might get back a String from getGlobalData if the IDE has been closed and restarted since the previous call to setGlobalData. It is the responsibility of the component author to reconstruct the complex object from the String, and if desired, put it back into the IDE state by using the setGlobalData method. Doing so ensures that all subsequent calls to getGlobalData with that key will return the complex object instance until the IDE is closed.

2.1.2 – DesignContext

The DesignContext interface is also used to create new instances of beans as well as locate instances of DesignBean(s) in a given containership tree.

Following are the main methods of the DesignContext interface and a brief explanation of their function.

String getDisplayName() Returns the display name of the DesignContext. For example, the return value might be “Page1” or “SessionBean1”. boolean canCreateBean( String classname, DesignBean parent, Position position) DesignBean createBean( String classname, DesignBean parent, Position position) Creates an instance of a JavaBean component of the specified type (classname), as a child of the specified parent DesignBean at the specified position. If successful, a DesignBean representing the newly created bean is returned. Before this method is called, a test call should be performed to the canCreateBean method. boolean canMoveBean( DesignBean designBean, DesignBean newParent, Position position) boolean moveBean( DesignBean designBean, DesignBean newParent, Position position) Moves a DesignBean to become a child of the specified parent DesignBean at the specified position. Returns true if successful, false if not. Before this method is called, a test call should be performed to the canMoveBean method.

Transferable copyBeans(DesignBean[] beans) Copies a set of DesignBean instances into a clipboard-like format. This returns a Transferable object that stores all the necessary data for the pasteBeans method.

DesignBean[] pasteBeans(Transferable persistData, DesignBean newParent, Position position) Pastes a set of DesignBean instances (acquired via copyBeans) into the specified parent DesignBean at the specified position. This returns an array of DesignBean(s), representing the newly pasted children. boolean deleteBean(DesignBean designBean) Deletes a DesignBean object (and removes all persistence). Returns true if the delete was successful, false if not.

DesignBean getRootContainer() Returns the root container DesignBean for this DesignContext. This is typically the this component being designed. For example, this would be the view root in a JavaServer Faces application. The children of the root container are the items you see on the page. To get all of the DesignBean objects within the scope of this context (ignoring the containership hierarchy), use the getBeans() method.

DesignBean getBeanForInstance(Object beanInstance) Returns a DesignBean (design-time proxy) to represent the specified JavaBean component instance. This must be an instance that lives within the scope of this DesignContext, or the method will return null.

DesignBean getBeanByName(String instanceName) Returns a DesignBean (design-time proxy) to represent the JavaBean component with the specified instance name. This must be an instance that lives within the scope of this DesignContext, or the method will return null.

DesignBean[] getBeansOfType(Class beanClass) Returns a DesignBean array (design-time proxies) representing the JavaBean components within the scope of this DesignContext that are assignable from the specified class type. This uses Class.isAssignableFrom(Class) to determine if a JavaBean component satisfies the specified criteria, so subtypes of the specified type will be included. DesignBean[] getBeans() Returns an array of all the DesignBeans within the scope of this DesignContext. This is a flat list of instances, ignoring the containership hierarchy. To navigate the containership hierarchy, use the getRootContainer () method. void setContextData(String key, Object data) Object getContextData(String key) Sets or gets a name-value pair of data on this DesignContext. This name-value pair will be stored as text in the associated project file that contains this DesignContext, enabling this data to be retrieved in a future IDE session.

NOTE: The data object can be a simple String or a complex (non-String) Object. Either way, it will be stored as text in the project file and will be associated with this DesignContext. When the project file is written to disk, any complex (non-String) objects will be converted to String by using the toString() method. A component author who wants to store a complex (non- String) object must be sure to override the toString() method on the object and serialize out enough information to be able to restore the object when a subsequent call to getContextData returns a String. Even if a complex object was stored via the setContextData method, a component author might get back a String from getContextData if the project has been saved and reopened since the previous call to setContextData. It is the responsibility of the component author to reconstruct the complex object from the String, and if desired, put it back into the context by using the setContextData method. Doing so ensures that all subsequent calls to getContextData with that key will return the complex object instance until the project is closed and restored.

String addResource(URL resource, boolean copy) throws IOException Adds a resource reference to this DesignContext and converts the external URL into a local resource identifier String. This method also copies an external resource into the project if the copy parameter is set to true.

URL resolveResource(String localResource) Resolves a local resource identifyer String into a fully-qualified URL.

DesignProject getProject() Returns the DesignProject, which is the top-level container for all DesignContext(s).

ContextMethod[] getContextMethods() Returns an array of ContextMethod objects representing the methods declared on this DesignContext (Java source file).

The ContextMethod is a struct-style JavaBean with the following simple properties: • DesignContext designContext • String name • Class[] parameterTypes • String[] parameterNames • Class returnType • Class[] exceptionTypes • int modifiers • String methodBodyText • String commentText

ContextMethod getContextMethod( String methodName, Class[] parameterTypes) Returns a ContextMethod object representing the method with the specified name and parameter types. Returns null if no method exists on this DesignContext with the specified name and parameter types. boolean createContextMethod(ContextMethod method) throws IllegalArgumentException Creates a new method in the source code for this DesignContext. The passed ContextMethod must specify at least the designContext and name, and must not describe a method that already exists in the DesignContext source. To update an existing method, use the updateContextMethod() method. These methods are separated to help prevent accidental method overwriting.

ContextMethod updateContextMethod(ContextMethod method) throws IllegalArgumentException Updates an existing method in the source code for this DesignContext. The passed ContextMethod will be used to locate the desired method to update using the designContext, name, and parameterTypes. This method may only be used to update the modifiers, returnType, parameterNames, exceptionTypes, methodBodyText, or commentText. Any other changes actually constitute the creation of a new method, as they alter the method signature. To create a new method, the createContextMethod() method should be used. These operations are separated to help prevent accidental method overwriting. boolean removeContextMethod(ContextMethod method) Removes an existing method from the source code for this DesignContext. The passed ContextMethod will be used to locate the desired method to remove using the designContext, name, and parameterTypes. No other portions of the ContextMethod are used.

2.1.2.1 – MarkupDesignContext (extends DesignContext)

There is also a DesignContext sub-interface for markup components. The MarkupDesignContext interface extends the DesignContext interface to add additional design-time functionality for markup components. Use the instanceof keyword to check if a DesignContext is actually a MarkupDesignContext.

Following are the main methods of the MarkupDesignContext interface and a brief explanation of their function.

Image getCssPreviewImage( String cssStyle, String[] cssStyleClasses, MarkupDesignBean designBean, int width, int height) Generates and returns a preview image (sized width by height) of the specified MarkupDesignBean after applying the specified CSS styles and style classes to the rendered markup.

Map convertCssStyleToMap(String cssStyle) Converts a CSS inline style string into a Map of style elements

String convertMapToCssStyle(Map cssStyleMap) Converts a Map of CSS styles into an inline CSS style string

2.1.2.2 – FacesDesignContext (extends MarkupDesignContext)

There is also a DesignContext sub-interface for JavaServer Faces components. The FacesDesignContext interface extends the MarkupDesignContext interface to add additional design-time functionality for JavaServer Faces components. Use the instanceof keyword to check if a DesignContext is actually a FacesDesignContext.

Following are the main methods of the FacesDesignContext interface and a brief explanation of their function.

String getReferenceName() Returns the reference name to use in EL expressions to refer to this FacesDesignContext. boolean canCreateFacet( String facetName, String type, DesignBean parent) DesignBean createFacet( String facetName, String type, DesignBean parent) Creates a facet child with the name facetName using a component of type on the faces bean parent. Before this method is called, a test call should be made to canCreateFacet. boolean isValidBindingTarget(DesignBean toBean) Returns a boolean value indicating if a binding expression can be created to point to toBean.

String getBindingExpr(DesignBean toBean) Returns a valid reference expression value with format "#{...}" to point to toBean.

String getBindingExpr(DesignBean toBean, String subExpr) Returns a valid binding expression value with format "#{...}" to point to toBean plus the sub-expression inside of toBean. For example, toBean might be button2 on Page1, and the desired expression might be to get the value of button2. The call would then be getReferenceExpr(button2, "value") which would result in the expression "#{Page1.button2.value}"

Object resolveBindingExpr(String expr) Returns the live instance Object (not DesignBean) to which the reference expression resolves at the moment it is called.

ResolveResult resolveBindingExprToBean(String expr) Returns a ResolveResult that is resolved to the deepest DesignBean that can be found, plus the remaining un-resolvable string (the remaining string that does not resolve to a DesignBean).

ResolveResult is a simple struct-like JavaBean with the following properties:

• DesignBean designBean • String remainder

FacesContext getFacesContext() Returns the FacesContext that can be used by component designers to retrieve design-time JavaServer Faces information.

2.1.3 – DesignBean

DesignBean (one per bean instance at design-time) +--->> DesignProperty (one per bean property) +--->> DesignEvent (one per bean event) figure 2.1.3.a

The figure above shows the relationship between a DesignBean instance and its properties and events. Once a component author has a DesignBean, they have free reign to manipulate these as they desire. Everything they do will be correctly persisted. For example, if a component author's code sets a bean's instance name via the DesignBean interface, the instance name will be changed in the Page1.java and the Page1.jsp source files.

Following are the main methods of the DesignBean interface and a brief explanation of their function.

Object getInstance() Returns the live bean instance that this DesignBean is marshalling. Any manipulations to this live instance will be reflected at design-time, but will not be persisted. Thus, it is important to do all manipulations via the proxy interfaces (DesignProperty, and so on).

String getInstanceName() Returns the instance name of this bean - as declared in source code. boolean canSetInstanceName() boolean setInstanceName(String name) boolean setInstanceName(String name, boolean autoNumber) Renames the instance variable for this bean instance in the source code. If successful, this method returns true, if there is a problem, including the existence of a duplicate instance variable name, this method returns false.

DesignContext getDesignContext() Returns the DesignContext that owns this bean instance.

DesignBean getBeanParent() Returns the DesignBean parent of this bean instance, or null if this is a top- level bean.

DesignProperty[] getProperties() DesignProperty getProperty(String propertyName) DesignProperty getProperty(PropertyDescriptor property) Methods for accessing DesignProperty objects, which represent the properties of this DesignBean.

DesignEvent[] getEvents() DesignEvent[] getEvents(EventSetDescriptor eventSet) DesignEvent getEvent(EventDescriptor event) Methods for accessing DesignEvent objects which represent the events of this DesignBean. boolean isContainer() Returns true if this DesignBean can be a logical container for other DesignBeans, or false if not. For example, if a DesignBean is representing a HtmlCommandButton instance, it will return false from this method, whereas a DesignBean representing an HtmlDataTable will return true. You can only add children to a DesignBean that returns true from this method. int getChildBeanCount() DesignBean getChildBean(int index) DesignBean[] getChildBeans() Methods for accessing child DesignBean objects contained in this DesignBean. Children are logical children, meaning that they represent the subcomponents contained inside another component in the markup (JSP) or containership hierarchy. 2.1.3.1 – MarkupDesignBean (extends DesignBean)

There is also a DesignBean sub-interface for markup components. The MarkupDesignBean interface extends the DesignBean interface to add additional design-time functionality for markup components. Use the instanceof keyword to check if a DesignBean is actually a MarkupDesignBean.

Element getElement() Returns the DOM Element representing the source markup for this markup component.

2.1.3.2 – FacesDesignBean (extends MarkupDesignBean)

The FacesDesignBean interface extends the MarkupDesignBean interface to add additional design-time functionality for JavaServer Faces components. Use the instanceof keyword to check if a DesignBean is actually a FacesDesignBean.

DesignBean getFacet(String facet) Returns the DesignBean component that is currently connected to the specified facet of this FacesDesignBean component.

2.1.4 – DesignProperty

The DesignProperty interface effectively marshals access to a given bean instance's properties. Any reading or writing of the property is done with the DesignProperty interface, and all the “right stuff” is done in the source code as required to persist the manipulations at design time. For example, if a user sets the value property on a button to “Hello”, the value attribute will be correctly set in the JSP markup: value=”Hello”. If a user sets the command property of a RowSet, the command property will be correctly set in Java code: personRowSet.setCommand(“SELECT * FROM PERSON”); Manipulations to a property via the DesignProperty interface will always be persisted correctly, so the component author does not need to worry about it.

Following are the main methods of the DesignProperty interface and a brief explanation of their function.

PropertyDescriptor getPropertyDescriptor() Returns the PropertyDescriptor associated with this DesignProperty

DesignBean getDesignBean() Returns the DesignBean that this DesignProperty is associated with

Object getValue() Returns the current value of this DesignProperty. The returned value is the actual value that the design-time instance of the DesignBean has set for this property. boolean setValue(Object value) Sets the current value of this DesignProperty. This will set the actual value of this property on the design-time instance of this DesignBean. The associated PropertyEditor will be used to produce the appropriate Java or markup code to set the property. Calling this method results in the persistence being written, and will cause the backing file buffer to become "dirty".

String getValueSource() Returns the source-persistence String value of this property. This is the value that the associated PropertyEditor would use to persist the property's current value in source code. boolean setValueSource(String source) Sets the source-persistence String value for this property. This is the value that will actually appear in Java source code (or markup), depending on how the property setting is persisted.

Object getUnsetValue() Returns the value that this property would have if it were unset. This is the property's original (default) state, which is determined by reading the property value on a fresh instance of the associated class (that owns this property). boolean unset() Removes the property setting (if it exists) from the source code, and reverts the property setting back to its original (default) state. The original state is determined by reading the property value on a fresh instance of the associated class (that owns this property), and reading the default value of the property. boolean isModified() Returns true if this DesignProperty has been modified from the default value. A modified property is one that differs in value (== and .equals()) from a newly constructed instance of the DesignBean.

2.1.4.1 – FacesDesignProperty (extends DesignProperty)

FacesDesignProperty is a DesignProperty sub-interface for JavaServer Faces components. This interface extends the DesignProperty interface to add additional design-time functionality for JavaServer Faces components. Use the instanceof keyword to check if a DesignProperty is actually a FacesDesignProperty.

Following are the main methods of the FacesDesignProperty interface and a brief explanation of their function. boolean isBound() Returns true if this property is currently bound with a value expression, false if not

ValueBinding getValueBinding() Returns the ValueBinding object that this property is bound to, IF this property is currently bound via a value expression, or null if it is not bound. void setValueBinding(ValueBinding binding) Sets the ValueBinding on this property, resulting in the property value being set to the appropriate value binding expression

2.1.5 – DesignEvent

The DesignEvent interface marshals access to a given bean instance's events. The component author can query, edit, and create event hooks on any bean in the hierarchy at design-time. An event is hooked when the developer has double-clicked on it to add an event handler method.

Following are the main methods of the DesignEvent interface and a brief explanation of their function.

EventDescriptor getEventDescriptor() Returns the EventDescriptor that defines the meta-data for this DesignEvent

DesignBean getDesignBean() Returns the DesignBean that owns this DesignEvent

String getDefaultHandlerName() Returns the default event handler method name. For example on a Button component's click() event, the default handler name might be button1_click().

String getHandlerName() boolean setHandlerName(String handlerMethodName) Sets the method name for this DesignEvent. If the event is not currently hooked, this will hook it and add the required wiring to direct the event handler code to this method name. If null is passed as the handlerName, then the default event handler method name will be used. boolean isHandled() Returns true if this DesignEvent is currently hooked, or false if it is not boolean removeHandler() Removes and unwires an event handler method from this DesignEvent, if one exists. Returns true if successful, false if not.

String getHandlerMethodSource() void setHandlerMethodSource(String methodBody) throws IllegalArgumentException Gets or sets the Java source for the method body of the handler method. The source is expected to be valid Java source to be injected into the body of this event handler method. If it is not, an IllegalArgumentException is thrown. Java Studio Creator Design-Time API User Guide

2.2 – Access / Hook Points

The previous section outlined the interfaces that are implemented by the Sun Java Studio Creator IDE. This section outlines the interfaces that are intended to be implemented by the component author. The interfaces in this section, when implemented by a component author, will be called by the IDE during the visual design process to provide opportunities to enhance the design-time experience for the developer.

The Java Studio Creator Design-Time API was designed to maintain the boundaries between runtime and design-time code, so a component author need not make any changes to their component implementation to enhance the design-time experience for the developer. All hook points into the CDT are done with design-time only classes that do not get deployed with the application (just like BeanInfo and PropertyEditor, classes provided by the JavaBeans API).

2.2.1 – DesignInfo

This is the primary hook point for component authors. The DesignInfo interface is analogous to the BeanInfo interface and must be implemented by the component author for each component. The BeanInfo interface provides static metadata for the JavaBean component type, whereas the DesignInfo interface provides dynamic behavior for the JavaBean component instance at design-time.

• BeanInfo - static metadata for a JavaBean component type • DesignInfo - dynamic behavior for a JavaBean component instance

A DesignInfo class is located for a given JavaBeans component by using the same technique that is used to locate a BeanInfo class, by the naming convention XxxDesignInfo, where Xxx is replaced by the JavaBeans component's class name. For example, the Donkey class could have a corresponding DonkeyBeanInfo to provide the static metadata, and a DonkeyDesignInfo class to provide the dynamic design-time behavior for the Donkey class.

Following are the main methods of the DesignInfo interface and a brief explanation of their function.

Class getBeanClass() Returns the class type of the JavaBean component that this DesignInfo was designed to work with. This is the handshake between the IDE and the component author to make sure this DesignInfo class should be used for the JavaBean component in question. boolean acceptParent( DesignBean parentBean, DesignBean childBean, Class childClass) Returns true if this child component (passed as 'childBean' and/or 'childClass') can be added as a child to the specified parent component (passed as 'parentBean'). This allows a component author to dynamically inspect the component hierarchy to determine if a particular component may be inserted. This method is called on the DesignInfo representing the childBean component any time a new component is being created, or dragged around in the visual designer. Note that the 'childBean' argument may be null if this operation is happening as a result of a fresh component drop from the palette. In that case, the child component instance will not be created until the actual drop happens, thus these checks must be done with only the child component's Class. boolean acceptChild( DesignBean parentBean, DesignBean childBean, Class childClass) Returns true if this child component (passed as 'childBean' and/or 'childClass') can be added as a child to the specified parent component (passed as 'parentBean'). This allows a component author to dynamically inspect the component hierarchy to determine if a particular component may be inserted. This method is called on the DesignInfo representing the parentBean component any time a new component is being created or dragged around in the visual designer. Note that the 'childBean' argument may be null if this operation is happening as a result of a fresh component drop from the palette. In that case, the child component instance will not be created until the actual drop happens, thus these checks must be done with only the child component's Class.

Result beanCreatedSetup(DesignBean designBean) Provides an opportunity for a DesignInfo object to set up the initial state of a newly created bean. Anything can be done here, including property settings, event hooks, and even the creation of other ancillary beans within the DesignContext. Note that this method is only called once after the component has been first created from the palette.

Result beanPastedSetup(DesignBean designBean) Provides an opportunity for a DesignInfo object to fix up the state of a pasted bean. Anything can be done here, including property settings, event hooks, and even the creation of other ancillary beans within the DesignContext.

Result beanDeletedCleanup(DesignBean designBean) Provides an opportunity for a DesignInfo object to clean up just before a bean gets deleted. Anything can be done here, including property settings, event hooks, and even the creation and deletion of other ancillary beans within the context. Note, however, that this DesignBean object will be deleted immediately upon the return of this method. This method is intended for cleanup of ancillary items created in beanCreatedSetup.

DisplayAction[] getContextItems(DesignBean designBean) Returns the list (or hierarchy) of items to be included in a right-click context menu for this bean at design-time. boolean acceptLink(DesignBean targetBean, DesignBean sourceBean, Class sourceClass) This method is called when an object from a design surface or palette is being dragged over a JavaBeans object type handled by this DesignInfo. If the sourceBean or sourceClass is of interest to the targetBean instance (they can be linked), this method should return true. The user will then be presented with visual cues that this is an appropriate place to drop the item and establish a link. If the user decides to drop the item on this targetBean, the linkBeans method will be called. Note that the sourceBean argument can be null if this drag operation is originating from the palette, because an instance of the bean will not have been created yet.

Result linkBeans(DesignBean targetBean, DesignBean sourceBean) This method is called when an object from a design surface or palette has been dropped on a JavaBean object type handled by this DesignInfo (to establish a link). This method will not be called unless the corresponding acceptLink method call returned true. Typically, calling this method results in property settings on both the DesignBean objects. void beanContextActivated(DesignBean designBean) void beanContextDeactivated(DesignBean designBean) The specified DesignBean object's DesignContext has been activated or deactivated in the project. void beanChanged(DesignBean designBean) The specified DesignBean has changed. Use this method to represent a larger- scale change than a single property, such as a change to the instance name or a change to some other aspect of the DesignBean that is more than just a property. void instanceNameChanged(DesignBean designBean, String oldName) The specified DesignBean's instance name has changed. void propertyChanged(DesignProperty prop, Object oldValue) The specified DesignProperty has changed. This could mean that a new value was set, or the property was unset, or anything that results in the DesignProperty being different. The oldValue will be passed in if applicable and possible. void eventChanged(DesignEvent event) The specified DesignEvent has changed. This could mean that the event was hooked or unhooked, or the handler method name was changed, or anything that results in the DesignEvent being different.

2.2.1.1 – MarkupDesignInfo (extends DesignInfo) The MarkupDesignInfo interface extends the DesignInfo interface to add additional design-time functionality for markup components. Implement the MarkupDesignInfo interface to gain access to this additional functionality. void customizeRender( MarkupDesignBean designBean, MarkupRenderContext renderContext) This method is called after a JavaServer Faces component has been invoked to render itself at design-time, and just before the rendered markup is displayed on the visual design surface. The component author may use this hook to modify the design-time rendered content for the given component. The component author may also hook the markup elements to instances of MarkupMouseRegion via the associateMouseRegion method on the passed MarkupRenderContext parameter.

2.2.1.1.1 – MarkupRenderContext

This interface supplies the component author with access to the rendered DOM output of their markup component to customize for design-time rendering. Any manipulations made to the output markup DOM will be displayed on the visual design surface. The MarkupRenderContext interface also surfaces the ability to associate “hot” regions in the markup with dynamic behavior as defined by a MarkupMouseRegion.

Following are the main methods of the MarkupRenderContext interface and a brief explanation of their function.

DocumentFragment getDocumentFragment() MarkupPosition getBeginPosition() MarkupPosition getEndPosition() These methods provide access to the rendered DOM from the markup component. The begin and end positions are within the renderFragment from where nodes were rendered for this component. Note that the end position is not inclusive, it points to the next node in the node list. Also note also that the parent node for begin and end will always be the same. void associateMouseRegion( Element element, MarkupMouseRegion region) Associates a dynamic mouse region with a particular element of rendered markup

2.2.1.1.2 – MarkupMouseRegion

A component author can associate custom behavior with sub-regions of the component by supplying MarkupMouseRegion objects. These objects associate a segment of markup or a rectangle of screen real-estate with custom functionality as specified by the component author. This custom behavior can include contextual menu items (right- click), sub-region mouse behavior for clicking and dragging, and so on. A common example is responding at design time to a user's clicking on a tab in a tab control by selecting that tab and moving it to the front.

Following are the main methods of the MarkupMouseRegion interface and a brief explanation of their function.

DisplayAction[] getContextItems() Returns an array of DisplayAction objects. Used to render a right-click context menu when the user right-clicks this mouse region. boolean isClickable() Result regionClicked(int clickCount) This method is called when a user clicks the mouse within the bounds of this mouse region. The regionClicked method is only called if the isClickable method returns true. boolean acceptLink(DesignBean targetBean, DesignBean sourceBean, Class sourceClass) This method is called when an object from a design surface or palette is being dragged over a region represented by this MarkupMouseRegion. If the sourceBean or sourceClass is of interest to the targetBean instance (they can be linked), this method should return true. The user will then be presented with visual cues that this is an appropriate place to drop the item and establish a link. If the user decides to drop the item on this targetBean, the linkBeans method will be called. Note that the sourceBean argument can be null if this drag operation is originating from the palette because an instance of the bean will not have been created yet.

Result linkBeans(DesignBean targetBean, DesignBean sourceBean) This method is called when an object from a design surface or palette has been dropped on a region represented by this MarkupMouseRegion (to establish a link). This method will not be called unless the corresponding acceptLink method call returned true. Typically, calling this method results in property settings on both the DesignBean objects.

To hook these access points in the CDT, simply provide an XxxDesignInfo class that implements the DesignInfo interface in the same package as your component. The IDE will automatically find the class and call the appropriate methods as the user manipulates your component at design time. A convenient BasicDesignInfo class is supplied for you to use for easy subclassing.

2.2.2 – PropertyEditor2

The PropertyEditor2 interface extends the java.beans.PropertyEditor interface by adding a single method, setDesignProperty(DesignProperty). If a PropertyEditor implements PropertyEditor2, the setDesignProperty() method is called just before the PropertyEditor.setValue(Object) method, giving the component author full access to the entire design-time context and making it possible to implement the rest of the PropertyEditor interface with significantly more information.

Keep in mind, however, when implementing PropertyEditor2 that the passed in DesignProperty is for context purposes only. Direct manipulation of the DesignProperty can easily lead to circular code because the PropertyEditor is used to edit a DesignProperty. The Object PropertyEditor.getValue() method is still the only way a PropertyEditor can provide a changed value for a property. The PropertyEditor must not directly call the setValue(Object) method on the DesignProperty.

2.2.3 – Customizer2

The JavaBeans specification requires that a Customizer or JavaBean component (or both) fire propertyChange events for any property that has been manipulated via the Customizer. In practical experience, it is all too common for a Customizer class (and associated JavaBean component class) to not fire propertyChange events while a user is manipulating them with a Customizer. These manipulations, though visible at design-time in that session (because the user is directly “touching” the live instance), are not persisted, and thus do not manifest themselves either at runtime or when the user returns to the Visual Editor in a later session.

The Customizer2 interface supplies a customizer with an instance of the DesignBean being manipulated, giving the component author full access to the design-time context of the bean being customized. The Customizer2 interface also has semantics for making a stateful customizer dialog. The author of the customizer can supply the user with an Apply button to enable the user to make a series of changes to the component and see it applied in real-time.

There are two ways to display a Customizer2 in Java Studio Creator. The first is to specify the customizer Class in the BeanDesriptor of the BeanInfo for the component in question. The Class returned from BeanDescriptor.getCustomizerClass() will be used when the user right-clicks on the component and selects “Customize”. The other more flexible technique is to return a CustomizerResult (subtype of Result) from any of the methods in the CDT that return a Result object. Any time CustomizerResult is returned from any method, the IDE will display a customizer dialog containing the Customizer2. This includes the DisplayAction.invoke() method used to execute right-click context menu items, which allows the component author to control the display text for the customizer context menu item, as well as providing the ability to have multiple separate customizers available via the context menu. This also includes the beanCreatedSetup and linkBeans methods, allowing the component author to display custom UI when a component is first dropped from the palette or when a drag-drop link is completed, respectively. Following are the main methods of the Customizer2 interface and a brief explanation of their function.

Component getCustomizerPanel(DesignBean designBean) Returns a UI panel (should be lightweight) to be displayed to the user. The passed in DesignBean is the design-time proxy representing the JavaBean component being customized. This method will be called every time the Customizer2 is invoked. boolean isApplyCapable() If a Customizer2 is apply capable (isApplyCapable() returns true), the host dialog will have three buttons: OK, Apply, and Cancel (and possibly Help if there is a helpKey). The isModified() method will be called each time a PropertyChangeEvent is fired to check if the Apply button should be enabled. When the user clicks OK or Apply, the applyChanges method is called. This implies that manipulations in the dialog are not directly affecting the DesignBean. The DesignBean should not be touched until the applyChanges method has been called.

If a Customizer2 is not apply capable (isApplyCapable() returns false), the host dialog will only have one button: Done (and possibly Help if there is a helpKey). The DesignBean may be manipulated at will in this dialog, as it is considered to be non-stateful. When the user clicks Done, the applyChanges method will be called. boolean isModified() Returns true if the customizer is in an edited state - to notify the customizer dialog that the Apply button should be activated.

Result applyChanges() Notifies the customizer that the user has clicked OK or Apply and the customizer should commit it's changes to the DesignBean. void addPropertyChangeListener(PropertyChangeListener) void removePropertyChangeListener(PropertyChangeListener) PropertyChangeListener[] getPropertyChangeListeners() Standard propertyChange events - null property name indicates that the bean changed in some other way than just a property. An applyCapable Customizer2 can use this as a hook to notify the host dialog that the modified state has changed.

2.2.4 – DisplayAction and DisplayActionSet

The DisplayAction interface is very similar to the Swing Action object in that it represents a display name or description or icon, etc. for a snippet of code that is displayed as a menu or a button or something similar to the user. When a button or menu item that was created for a DisplayAction object is clicked or selected, the component author's design-time code is then executed. DisplayAction objects define contextual menu items and option buttons (in result dialogs).

Result invoke() This method is called when a DisplayAction is selected (in the form of a menu item) or clicked (in the form of a dialog button). The component author can implement this method to do whatever is desired. For example, an “Add column” DisplayAction in a context menu for a data table would add a new column to the data table when the user selects it from the menu.

A DisplayActionSet is a DisplayAction that defines a group (tree) of DisplayAction(s). Use DisplayActionSet to created nested menus with popups or to define separated sections of items in a menu.

See also: CheckedDisplayAction, which is a DisplayAction that shows as a checkmark or a checkbox when displayed by the IDE.

2.2.5 – Result

Many of the operations performed with CDT return a Result object, which indicates success or failure (boolean isSuccess()) and can contain any number of messages (ResultMessage objects) for the user. A Result can also contain any number of options (DisplayAction objects), which show a dialog so the user can make a choice. Result objects can be used as the method return type only in interfaces implemented by the component author.

For example, the linkBeans method returns a Result object. A component author who wants the user to be asked a question after dropping something on the component can use this method to return a Result object with a ResultMessage and a few result options in it that present the choices to the user. The code will be notified of the choice the user made, and the component author can branch the code accordingly.

Following are the main methods of the Result class and a brief explanation of their function.

Result.SUCCESS A public static final instance of Result that can be used as a convenience for common return cases. void addMessage(ResultMessage message) void addMessages(ResultMessage[] messages) Use these methods to add messages for the user. void addResultOption(DisplayAction resultOption) void addResultOption(DisplayAction resultOption) Use these methods to add option buttons to the result display dialog. When the user clicks on the button representing a DisplayAction, the invoke() method will be called on the DisplayAction the user clicked. void setDialogTitle(String dialogTitle) Sets the dialog title if the Result causes a dialog to be displayed.

2.2.5.1 – ResultMessage

Following are the main methods of the ResultMessage class and a brief explanation of their function. void setDisplayName(String displayName) This will be used as the message title void setDescription(String description) This will be used as the message text void setMessageType(int messageType) ResultMessage.TYPE_INFORMATION ResultMessage.TYPE_WARNING ResultMessage.TYPE_CRITICAL These constants are used to set the type property of the ResultMessage. A TYPE_INFORMATION message is informational, and may be displayed on the status bar to the user. A TYPE_WARNING message is a warning, and will be displayed in the output window to the user. A TYPE_CRITICAL message is critical, and will be displayed in a dialog to the user.

See also: CustomizerResult, which is a Result that opens a Customizer2 dialog box when it is returned by the DesignInfo method. This class enables the component author to pop up a customizer dialog as a result of any operation on a component. Java Studio Creator Design-Time API User Guide

2.3 – Extended Metadata

The Java Studio Creator Design-Time API defines a set of common name-value attribute pairs that are typically stuffed into the standard JavaBeans metadata classes. These attribute keys include such things as property categories and instance names to use for generated instances of a bean. Much of these name-value pairs are defined in XML and result in a BeanInfo file being generated. These common attribute keys and their semantics can be defined in the following central location in CDT:

com.sun.rave.designtime.Constants.BeanDescriptor

TAG_NAME (String) – This attribute key is used to define which JSP tag name represents a given component. This key dictates how the JSP-based persistence data will be generated to represent the JavaBean component.

TAGLIB_URI (String) – This attribute key is used to define which JSP tag library contains a given component. This key setting tells the IDE which tag library to import into the JSP page and which prefix to place on the specific new instance of the component in the JSP file.

TAGLIB_PREFIX (String) – This attribute key is used to define the suggested JSP taglib prefix (if not already added to the JSP file).

INSTANCE_NAME (String) – This attribute key is used to define the base instance name that will be used for new instances of the given bean class. These instance names will be auto-numbered for subsequent instances of the given bean class within a scope. If no instanceName key is defined, the bean's class name is used (with a lower-cased initial character). For example, an HtmlCommandButtonBeanInfo class might set the instanceName name/value attribute to button. Doing so would result in new instances of the HtmlCommandButton class being called button1, button2, button3, and so on, as opposed to htmlCommandButton1, htmlCommandButton2, htmlCommandButton3, and so on.

TEXT_NODE_PROPERTY (String) – This attribute key is used to specify a particular property name on a component that controls the contents of a Faces component's rendered text node. This allows in-place editing of flow text on a component displayed in the designer.

IS_CONTAINER (Boolean) – This attribute key is used to specify if a component should be treated as a container on the design surface. This key applies to AWT and Swing components that subclass java.awt.Container, as well as JavaServer Faces components that subclass javax.faces.component.UIComponent. By default, with no setting, these components are treated as containers―users can put things inside them. If the isContainer attribute is set to Boolean.FALSE (or “false”), the components will not be treated as containers. This feature was added with Swing components, which all are subclasses of java.awt.Container, because some of these components, such as JButton. should not be treated as containers.

PREFERRED_CHILD_TYPES (String[]) – This attribute key is used to define the set of preferred childrens' class names. This tells Creator which children types to place in a right-click "Add >" context item for this bean. If this is not set, no "Add >" context item will be present.

PROPERTY_CATEGORIES (CategoryDescriptor[]) – This attribute key is used to define the set of property categories that a given bean surfaces. The property category objects are also supplied in each of the PropertyDescriptor objects (see below), but this static array defines the order that they will be shown in the IDE. Any additional CategoryDescriptor objects that are defined by subsequent PropertyDescriptor objects will be added to the end of this defined list.

HELP_KEY (String) – This attribute key is used to specify a help context key for displaying appropriate help about a JavaBean component when a user clicks on the bean and presses F1 or if a dynamic help window is showing while a bean is selected on the palette.

MARKUP_SECTION (String) – This attribute key is used to define an affinity for a particular markup section for a component. If none is defined, the JSP tag representing this component will be placed into the of the JSP document. For example, a StyleSheet JavaServer Faces component would set the markupSection attribute to head so that the appropriate JSP tag would be generated into the section of the JSP document.

FACET_DESCRIPTORS (FacetDescriptor[]) – This attribute key is used to define the facets that a given JavaServer Faces component supports. Ideally, this would be a separate FacetDescriptor[] getFacetDescriptors() method in the BeanInfo class or a FacesBeanInfo subclass of BeanInfo, but that would require a significant API change to JavaBeans.

CLEANUP_METHOD (String) – This attribute key defines a method name with no arguments and void return type that should be called to clean up an instance of this component. For example, a RowSet might specify close as a cleanup method, so that the IDE will automatically generate a call to rowSet1.close() when a page is being disposed of.

RESIZE_CONSTRAINTS (Integer) – This attribute key defines a single Integer, which represents a bitwise OR of a set of resize flags also defined in the Constants.ResizeConstraints interface. These flags consist of TOP, LEFT, BOTTOM, RIGHT, and combinations of these such as VERTICAL, HORIZONTAL, ANY, and NONE. These bits define which sides of a component are to be resizable at design time. There is also a MAINTAIN_ASPECT_RATIO constant to allow corner resizing to maintain the relative width and height of the shape.

2.3.2 – Additional PropertyDescriptor Attributes

The method declared as PropertyDescriptor[] BeanInfo.getPropertyDescriptors() returns a set of PropertyDescriptor objects that define the set of properties that a JavaBean component class exposes. The PropertyDescriptor(s) can be enhanced by a component author to provide additional metadata for the user. These common attribute keys (and semantics) can be defined in the following central location in CDT:

com.sun.rave.designtime.Constants.PropertyDescriptor

ATTRIBUTE_DESCRIPTOR (AttributeDescriptor) – This attribute key defines the markup attribute that this property corresponds to. Any property settings in the designer that have a corresponding AttributeDescriptor here will generate the property setting code in the JSP file as a markup attribute. This is required to make a property persist its setting in the JSP file instead of the Java file.

CATEGORY (CategoryDescriptor) – This attribute key is used to define the CategoryDescriptor that a particular property belongs to. The categories are displayed in a property inspector as separate groups to simplify the sometimes daunting list of properties that a given JavaBean component may have.

HELP_KEY (String) – This attribute key is used to specify a help context key for displaying appropriate help about a specific property when a user selects the property in the property inspector and presses F1 or if a dynamic help window is showing while a property is selected on the property inspector.

2.3.3 – Additional EventSetDescriptor and EventDescriptor Attributes

The method declared as EventSetDescriptor[] BeanInfo.getEventSetDescriptors() returns a set of EventSetDescriptor objects that define the set of events that a JavaBean component class exposes. The EventSetDescriptor(s) can be enhanced by a component author to provide additional metadata for the user. One of these customizations is the inclusion of an array of EventDescriptor objects, which allow for additional metadata for individual event methods. These common attribute keys (and semantics) can be defined in the following central location in CDT:

com.sun.rave.designtime.Constants.EventSetDescriptor EVENT_DESCRIPTORS (EventDescriptor[]) – This attribute key defines the set the event methods that this event set corresponds to. Additional metadata might be stored in the EventDescriptor associated with a particular event method.

BINDING_PROPERTY (PropertyDescriptor) – This attribute key is used to define the PropertyDescriptor that is capable of receiving a method binding expression to represent the listener for this event set. For example, a JSF action listener can be bound by providing a method binding expression in the 'action' property. NOTE: This will be deprecated and replaced with EventDescriptor.BINDING_PROPERTY (below), because using this attribute restricts the component to having only a single event method per event set.

com.sun.rave.designtime.Constants.EventDescriptor

BINDING_PROPERTY (PropertyDescriptor) – This attribute key is used to define the PropertyDescriptor that is capable of receiving a method binding expression to represent the listener for this event method. For example, a JSF action listener can be bound by providing a method binding expression in the 'action' property.

DEFAULT_EVENT_BODY (String) – This attribute key defines a default method body (expressed as formatted Java Source) for the event handler when it is first created. The body starts immediately after the opening brace, so normally it would need to start with a newline, then 8 spaces for indentation to cover the four spaces to the method inset and another 4 for the code itself.

REQUIRED_IMPORTS (String[]) – This attribute key defines a list of fully qualified class names that must be imported when an event handler is created for this event. The sample code (see DEFAULT_EVENT_BODY) may require it, or common usage in the code may require it (for example, a validate event may typically want a ValidatorException to be pre-imported.)

PARAMETER_NAMES (String[]) – This attribute key defines an array of parameter names to be used when constructing an event handler in the Java source code for this event. The array should have at least as many items as there are parameters.

2.3.4 – Context Data Attributes

The method declared as Object DesignContext.getContextData(String key) returns a piece of data (a key) stored in the DesignContext. A few of these keys return dynamically calculated data from the IDE. These common attribute keys and semantics can be defined in a central location in CDT:

com.sun.rave.designtime.Constants.ContextData SCOPE (String) – This attribute key is used to retrieve the scope that a particular context is stored in for managed beans. This key can return “request”, “session”, or “application”, or null if no scope is specified for this context.

CLASS_NAME (String) – This attribute key is used to retrieve the full class name of the design context. For example, this might be “webapplication1.Page1” for a DesignContext representing a page.

BASE_CLASS (Class) – This attribute key is used to retrieve the Class object of the design context's base class (superclass). For example, this might be the Class object for com.sun.web.ui.appbase.AbstractPageBean for a DesignContext representing a page.

PAGE_RESOURCE_URI (URI) – This attribute key is used to retrieve a URI object representing the project resource for the JSP page (if any) represented by this DesignContext. If there is no page associated with this DesignContext, this constant returns null. For example, this might return “web/Page1.jsp” for a DesignContext representing Page1.

JAVA_RESOURCE_URI (URI) – This attribute key is used to retrieve a URI object representing the project resource for the Java source file represented by this context. For example, this might return “src/webapplication1/Page1.java” for a DesignContext representing Page1.

INIT_METHOD (ContextMethod) – This attribute key is used to retrieve a ContextMethod object representing the init() method from the Java source file represented by this context, or null if there is no init() method defined by this context.

PREPROCESS_METHOD (ContextMethod) – This attribute key is used to retrieve a ContextMethod object representing the preprocess() method from the Java source file represented by this context, or null if there is no preprocess() method defined by this context.

PRERENDER_METHOD (ContextMethod) – This attribute key is used to retrieve a ContextMethod object representing the prerender() method from the Java source file represented by this context, or null if there is no prerender() method defined by this context.

DESTROY_METHOD (ContextMethod) – This attribute key is used to retrieve a ContextMethod object representing the destroy() method from the Java source file represented by this context, or null if there is no destroy() method defined by this context.

DATASOURCE_NAMES (String) – This attribute key is used to retrieve a comma- separated list of datasource names available to the DesignContext as a String. CSS_STYLE_CLASS_DESCRIPTORS (StyleClassDescriptor[]) – This attribute key is used to retrieve information about the CSS styles that are currently in scope for a context. The IDE will scan the associated CSS style sheets for this page and return a list of known style classes. Java Studio Creator Design-Time API User Guide

3 – Examples / Use Cases

Following are a set of common use cases and examples of using the Java Studio Creator Design-Time API from the perspective of a component author.

3.1 – Example: Providing Extended BeanInfo Metadata

This example shows a few uses of extended metadata in the BeanInfo class. Java Studio Creator looks for this extended metadata for clues on how to best handle the components during design-time. See com.sun.rave.designtime.Constants.BeanDescriptor and com.sun.rave.designtime.Constants.PropertyDescriptor for an exhaustive list of extended metadata that Java Studio Creator will be looking for.

/********************************************************************* * Donkey.java * This is a simple JavaBean component that extends the HtmlOutputText, * which makes it a JavaServer Faces component. A 'furColor' property * of type Color has been added to make things a bit more interesting. *********************************************************************/ import java.awt.*; import javax.faces.component.html.*; public class Donkey extends HtmlOutputText {

// declare a simple JavaBean property called 'furColor' with // type Color - NOTE: this property doesn't really do anything // to the HtmlOutputText. It just here for illustrative purposes. protected Color furColor; public void setFurColor(Color furColor) { this.furColor = furColor; } public Color getFurColor() { return furColor; } }

/********************************************************************* * DonkeyBeanInfo.java * This is a very simple (incomplete) example of a BeanInfo class to * illustrate a few extended meta-data items *********************************************************************/ import java.beans.*; import com.sun.rave.designtime.*; public class DonkeyBeanInfo implements BeanInfo { .... // The BeanDescriptor provides information about the bean class public BeanDescriptor getBeanDescriptor() { BeanDescriptor bd = new BeanDescriptor(Donkey.class, null); // instances of this class should be named donkey1, donkey2... bd.setValue(Constants.BeanDescriptor.INSTANCE_NAME, "donkey"); // a Donkey cannot contain children... bd.setValue(Constants.BeanDescriptor.IS_CONTAINER, Boolean.FALSE); // Donkey components should show up in the tray bd.setValue(Constants.BeanDescriptor.TRAY_COMPONENT, Boolean.TRUE); return bd; }

// The PropertyDescriptor array provides information about each // of the properties on the JavaBean component public PropertyDescriptor[] getPropertyDescriptors() { .... PropertyDescriptor pd = new PropertyDescriptor(...);

// a specific category on the property sheet pd.setValue(Constants.PropertyDescriptor.CATEGORY, new CategoryDescriptor("Appearance"));

// an AttributeDescriptor is required to tell // Java Studio Creator to // persist the property value in the JSP source as an // attribute setting - rather than in the Java code as a // regular JavaBean property pd.setValue(Constants.PropertyDescriptor.ATTRIBUTE_DESCRIPTOR, new AttributeDescriptor("furColor")); .... } } Java Studio Creator Design-Time API User Guide

3.2 – Example: Providing Custom Right-Click Context Items

This example shows how to expose custom right-click context items from a DesignInfo class. In this example, we add two right-click context menu items for the Donkey component.

/********************************************************************* * DonkeyDesignInfo.java * This is portion of a simple DesignInfo class for the Donkey * JavaBean component. This version suppies a couple of context menu * items when the user right-clicks on the component in the visual * designer. *********************************************************************/ import java.awt.*; import com.sun.rave.designtime.*;

// The name 'DonkeyDesignInfo' associates this DesignInfo class with // the 'Donkey' JavaBean component public class DonkeyDesignInfo implements DesignInfo {

// This method is called when a user right-clicks on the Donkey // bean in the Visual Editor public DisplayAction[] getContextItems(DesignBean designBean) {

// declaring a final instance variable for the DesignBean so // we can use it in the inner classes below final DesignBean donkeyBean = designBean;

// Displays "Set value to Hello World!" and sets the value // property to "Hello World!" when it is invoked BasicDisplayAction helloAction = new BasicDisplayAction("Set value to Hello World!") { public Result invoke() { DesignProperty valueProp = donkeyBean.getProperty("value"); valueProp.setValue("Hello World!"); return Result.SUCCESS; } };

// Displays "Color donkey1 Green" and sets the furColor // property to Color.green when it is invoked BasicDisplayAction greenAction = new BasicDisplayAction( "Color " + donkeyBean.getInstanceName() + " Green") { public Result invoke() { // get the 'furColor' property and set it to green DesignProperty colorProp = donkeyBean.getProperty("furColor"); colorProp.setValue(Color.GREEN); return Result.SUCCESS; } }; // The returned DisplayActions will be inserted into the // right-click menu for the Donkey component return new DisplayAction[] { helloAction, greenAction }; } .... } Java Studio Creator Design-Time API User Guide

3.3 – Example: Using beanCreatedSetup Method to Setup Initial State

When a component is first dropped from the palette, the component author has the opportunity to customize the initial setup by manipulating properties, creating ancillary components, and wiring things together. Following are a few examples of beanCreatedSetup methods.

/********************************************************************* * DonkeyDesignInfo.java * This is another portion of a simple DesignInfo class for the Donkey * JavaBean component. This clip shows an example of the * beanCreatedSetup method which sets up the initial state of a Donkey * component after it is dropped from the palette. *********************************************************************/

// Called after a Donkey is first dropped from the palette public Result beanCreatedSetup(DesignBean designBean) {

// initially set the furColor to blue DesignProperty colorProp = designBean.getProperty("furColor"); colorProp.setValue(Color.blue);

// initially set the value to “I am a donkey.” DesignProperty valueProp = designBean.getProperty("value"); valueProp.setValue("I am a donkey.");

return Result.SUCCESS; }

This example is extracted from the HtmlDataTableDesignInfo class supplied with Java Studio Creator. The code clip has been simplified for clarity, but this is the code that executes when a new HtmlDataTable (“Data Table”) componenent is dropped from the palette. To see this code in action, just drop an HtmlDataTable component from the palette onto your page and see what happens. Follow along with the code to see how easy it is to achieve complex initial setup of your components.

/********************************************************************* * HtmlDataTableDesignInfo.java * This is a portion of a the DesignInfo class for the HtmlDataTable * standard JavaServer Faces component. This clip shows a more * complicated example of the beanCreatedSetup method which sets up the * initial state of a HtmlDataTable component after it is dropped from * the palette. NOTE: This example clip has been simplified for * clarity. Typically, more defensive code should be used (null * checks, etc) *********************************************************************/

// in this case, the passed in DesignBean will be an HtmlDataTable, // because this method is the HtmlDataTableDesignInfo class public Result beanCreatedSetup(DesignBean bean) {

// fetch the context from the passed in bean DesignContext context = bean.getDesignContext();

// the passed design context is a faces design context FacesDesignContext fcontext = null; if (context instanceof FacesDesignContext) { fcontext = (FacesDesignContext)context; }

// create and setup a default datamodel DesignBean dm = context.createBean( DefaultTableDataModel.class.getName(), null, null);

// set the instance name of the dm to match the datatable dm.setInstanceName(bean.getInstanceName() + "Model", true);

// get an EL expression for binding to the datamodel // NOTE: the FacesDesignContext must be used to get an EL expr String ref = fcontext.getBindingExpr(dm);

// set the value property on the datatable to point to the model bean.getProperty("value").setValueSource(ref);

// set the var property to "currentRow" bean.getProperty("var").setValue("currentRow");

// create the three initial default columns for (int i = 1; i <= 3; i++) {

// create the UIColumn bean (parented by the table) DesignBean col = context.createBean( UIColumn.class.getName(), bean, null);

// create the HtmlOutputText bean (in the column) DesignBean output = context.createBean( HtmlOutputText.class.getName(), col, null);

// set an EL expression for the output to point at // a column in the datamodel output.getProperty("value").setValueSource( "#{currentRow['COLUMN" + i + "']}");

// create a header facet using another HtmlOutputText // NOTE: the FacesDesignContext must be used to create // a facet DesignBean header = fcontext.createFacet( "header", HtmlOutputText.class.getName(), col);

// set the text for the header header.getProperty("value").setValue("Column " + i); }

return Result.SUCCESS; } Java Studio Creator Design-Time API User Guide

3.4 – Example: Creating a Customizer2 Dialog

The Customizer2 interface allows the component author to supply custom UI to manipulate an entire component at design-time. This example shows a simple customizer dialog that allows the user to set the text and pick a color for our sample Donkey component. The Customizer2 is surfaced in this example via a custom right- click context menu item.

/********************************************************************* * DonkeyDesignInfo.java (inside getContextItems(...) clip) * This is a portion of the DonkeyDesignInfo class. This clip defines * a DisplayAction that will launch the Donkey customizer dialog when * it is invoked. *********************************************************************/

// Displays "Donkey Settings..." and displays a Customizer2 // dialog to user when it is invoked BasicDisplayAction customizeAction = new BasicDisplayAction("Donkey Settings...") { public Result invoke() { Customizer2 donkeyCustomizer = new DonkeyCustomizer(); return new CustomizerResult(donkeyBean, donkeyCustomizer); } };

/********************************************************************* * DonkeyCustomizer.java * This is a Customizer2 class for the Donkey bean. It provides a UI * panel for the user to manipulate the Donkey instance in the Visual * Editor. *********************************************************************/ import java.awt.*; import com.sun.rave.designtime.*;

// This class extends a basic helper class provided in the CDT public class DonkeyCustomizer extends BasicCustomizer2 {

// constructs a new DonkeyCustomizer instance public DonkeyCustomizer() { super(null, "Donkey Customizer"); setApplyCapable(true); }

// storage for the actual UI panel to display to the user protected DonkeyCustomizerPanel panel;

// creates the DonkeyCustomizerPanel to display to the user protected Component createCustomizerPanel() { // the 'designBean' instance variable is in the superclass panel = new DonkeyCustomizerPanel(this, designBean); return panel; } // this is called when the user clicks Apply or OK in the dialog // it is typical to keep the apply logic in the panel class public Result applyChanges() { return panel.applyChanges(); } }

/********************************************************************* * DonkeyCustomizerPanel.java * This is the panel UI class for the Donkey bean customizer. This * panel is displayed to the user when the Donkey bean customizer is * invoked. This panel allows the user to manipulate the 'value' and * 'furColor' properties on the Donkey component at the same time. *********************************************************************/ public class DonkeyCustomizerPanel extends JPanel {

protected DonkeyCustomizer donkeyCustomizer; protected DesignBean donkeyBean;

protected JLabel valueLabel = new JLabel(); protected JTextField valueTextField = new JTextField();

protected JLabel colorLabel = new JLabel(); protected JColorChooser colorChooser = new JColorChooser();

// constructs a new DonkeyCustomizerPanel for the passed in // DonkeyCustomizer and DesignBean public DonkeyCustomizerPanel( DonkeyCustomizer customizer, DesignBean bean) {

this.donkeyCustomizer = customizer; this.donkeyBean = bean;

// using GridBagLayout for a simple panel this.setLayout(new GridBagLayout()); this.add(valueLabel, new GridBagConstraints( 0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(8, 8, 0, 8), 0, 0)); this.add(valueTextField, new GridBagConstraints( 0, 1, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(4, 8, 8, 8), 0, 0)); this.add(colorLabel, new GridBagConstraints( 0, 2, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(8, 8, 0, 8), 0, 0)); this.add(colorChooser, new GridBagConstraints( 0, 3, 1, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(4, 8, 8, 8), 0, 0));

// IMPORTANT: this is where the panel UI fetches the current // state of the DesignBean. Alterations are made in the panel // while the customizer dialog is displayed - but not "pushed" // back to the DesignBean until the user clicks OK or Apply.

// grab the current state of the 'value' property and show it // in the valueTextField DesignProperty valueProp = donkeyBean.getProperty("value"); valueTextField.setText(String.valueOf(valueProp.getValue()));

// grab the current state of the 'furColor' property and show // it in the colorChooser DesignProperty colorProp = donkeyBean.getProperty("furColor"); colorChooser.setColor((Color)colorProp.getValue());

// IMPORTANT: this is where the UI components are wired to // listen for any changes. When one of the UI components is // altered in the dialog, we want to notify the customizer so // the "Apply" button will become enabled

// hook the valueTextField for changes to the 'text' property valueTextField.addPropertyChangeListener( new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent e) { if ("text".equals(e.getPropertyName())) { donkeyCustomizer.setModified(true); } } });

// hook the colorChooser for changes to the 'color' property colorChooser.addPropertyChangeListener( new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent e) { if ("color".equals(e.getPropertyName())) { donkeyCustomizer.setModified(true); } } }); }

// This method is called when the user clicks OK or Apply. At // this point, we want to "push" the changes into the DesignBean public Result applyChanges() {

// push the valueTextField's 'text' property into the Donkey's // 'value' property DesignProperty valueProp = donkeyBean.getProperty("value"); valueProp.setValue(valueTextField.getText());

// push the colorChooser's 'color' property into the Donkey's // 'furColor' property DesignProperty colorProp = donkeyBean.getProperty("furColor"); colorProp.setValue(colorChooser.getColor());

// reset the modified state on the customizer (so the Apply // button goes disabled again) donkeyCustomizer.setModified(false);

return Result.SUCCESS; } } Java Studio Creator Design-Time API User Guide

3.5 – Example: Using a PropertyEditor2 to Scan Design Context

/********************************************************************* * InputIdListPropertyEditor.java (partial clip) * This is the interesting portion of a PropertyEditor2 that lists the * IDs of all the UIInput components on a page as a drop-down list in * the property sheet. This might be used as the PropertyEditor for a * 'for' property on a label component. *********************************************************************/ public class InputIdListPropertyEditor implements PropertyEditor2 {

// storage for the DesignProperty that the user is editing protected DesignProperty editingProp;

// this is called when the PropertyEditor is about to be used public void setDesignProperty(DesignProperty prop) { this.editingProp = prop; }

// IDEs use this method to fetch a list of strings to display in // the property sheet as a drop-down list public String[] getTags() {

// walk up the tree to fetch the DesignContext that contains // this DesignProperty DesignBean editingBean = editingProp.getDesignBean(); DesignContext designContext = editingBean.getDesignContext();

// request a list of DesignBeans in the DesignContext that // are of type (or a subtype of) UIInput DesignBean[] inputBeans = designContext.getBeansOfType(UIInput.class);

// scan the list and build a String[] of IDs String[] inputIDs = new String[inputBeans.length]; for (int i = 0; i < inputBeans.length; i++) { inputIDs[i] = inputBeans[i].getInstanceName(); }

// return the IDs - which will be displayed in the IDE as // a drop-down list on the property sheet return inputIDs; } .... }

Another common example is the columnName property on a data-aware component. This typically lists a set of column names in the database if the corresponding table property of type ResultSet is also set. The following clip illustrates how this would be achieved using a PropertyEditor2.

/********************************************************************* * ColumnListPropertyEditor.java (partial clip) * This is the interesting portion of a PropertyEditor2 that lists the * database column names if an associated 'table' property (of type * ResultSet) is set on the component being edited. *********************************************************************/ public class ColumnListPropertyEditor implements PropertyEditor2 {

// storage for the DesignProperty that the user is editing protected DesignProperty editingProp;

// this is called when the PropertyEditor is about to be used public void setDesignProperty(DesignProperty prop) { this.editingProp = prop; }

// IDEs use this method to fetch a list of strings to display in // the property sheet as a drop-down list public String[] getTags() {

// walk up the tree to fetch the DesignBean that contains // this DesignProperty DesignBean editingBean = editingProp.getDesignBean();

// check for a property called "table" of type ResultSet DesignProperty tableProp = editingBean.getProperty("table"); if (tableProp != null && ResultSet.class.isAssignableFrom( tableProp.getPropertyDescriptor().getPropertyType())) {

// get the current setting of the table property ResultSet table = (ResultSet)tableProp.getValue(); if (table != null) { try { // fetch the metadata for the table ResultSetMetaData rsmd = table.getMetaData();

// create an array of column names by scanning // the list of columns in the result set String[] columnList = new String[rsmd.getColumnCount()]; for (int i = 0; i < columnList.length; i++) { // NOTE: ResultSet classes use a 1-based index columnList[i] = rsmd.getColumnName(i + 1); }

// this list of column names will show up as a // drop-down list in the property sheet return columnList;

} catch (Exception x) {} } }

// returning null means there is no drop-down list of columns return null; } .... } Java Studio Creator Design-Time API User Guide

3.6 – Example: Interaction With the User Via a Result Object

Many of the CDT methods return a Result object. These can be used to display messages to the user, or to interact with the user via option dialogs. The following example displays a message when a ResultSet is dragged and dropped on a Donkey component.

/********************************************************************* * DonkeyDesignInfo.java (partial clip) * This is a portion of the DonkeyDesignInfo that includes the * acceptLink and linkBeans methods to illustrate the usage of the * Result object to interact with the user. *********************************************************************/

// we can link to ResultSet objects. To play with this, drag things // from the server navigator public boolean acceptLink( DesignBean targetBean, DesignBean sourceBean, Class sourceClass) {

return ResultSet.class.isAssignableFrom(sourceClass); }

// called when the user does the actual drop of the rowset onto a // Donkey component. In this case, the targetBean is the Donkey, and // the sourceBean is the ResultSet. public Result linkBeans(DesignBean targetBean, DesignBean sourceBean) {

// construct a ResultMessage object to display in the dialog ResultMessage message = new ResultMessage(ResultMessage.TYPE_INFORMATION, "You dropped " + sourceBean.getInstanceName() + " onto " + targetBean.getInstanceName() + ". What do you want to do?", "You can either set the Donkey's value to the name of this\n" + "ResultSet (exciting!), or you can bind the Donkey's value\n" + "to the 'NAME' column in the ResultSet.");

// final instances of the target and source bean (for inner classes) final DesignBean tb = targetBean; final DesignBean sb = sourceBean;

// the first result option - setting the Donkey value DisplayAction action1 = new BasicDisplayAction("Set Donkey Name") { public Result invoke() {

// set the 'value' property to the instance name DesignProperty valueProp = tb.getProperty("value"); valueProp.setValue(sb.getInstanceName());

// all is well return Result.SUCCESS; } }; // the second result option - binding the Donkey value DisplayAction action2 = new BasicDisplayAction("Bind Donkey to NAME Column") { public Result invoke() {

// get the value property DesignProperty valueProp = tb.getProperty("value");

// get a FacesDesignContext to make a reference expr DesignContext dc = tb.getDesignContext(); FacesDesignContext fdc = (FacesDesignContext)dc; String refExpr = fdc.getBindingExpr(sb, ".currentRow['NAME']");

// set the value source to the reference expr valueProp.setValueSource(refExpr);

// all is well return Result.SUCCESS; } };

// construct a successful result Result result = new Result(true, message);

// stuff it with result options result.addResultOption(action1); result.addResultOption(action2);

// this will be displayed to the user in the result dialog return result; }