The WTP 1.0 Web services wizards are configurable so that new Web services runtimes can be plugged into their framework.† Most runtimes are themselves configurable with many options that can be selected by a user.† This document describes how new Web services runtimes plugging into this runtime framework can also contribute UI pages.† Refer to the Contributing a Web service runtime document for more detail description of the Web service creation framework and how to contribute a Web service runtime.† This document will focus more on how a Web service runtime can contribute UI pages.
In order to demonstrate how UI pages can be added to the Web services framework an example plug-in was created.† This document will describe how this example plug-in code contributes UI to the framework.†† Here is a link to the sample plug-in.† Before getting into a detailed discussion of this sample code, letís have a look at how this sample code affects the Web services wizard.†† In the bottom up Java bean scenario the user usually selects a Java bean and then brings up the Web services wizard as seen below.†
In the screen shot above the runtime is set to Apache Axis.† The sample plug-in code, however, has added a new Web services runtime called, ďWeb services example runtimeĒ.† We will select this runtime to show the example UI pages that have been added.
When the user clicks next in the Web services wizard the page below is displayed.
This page was contributed by the sample code.† The sample code contributed thee main items for this page, the title shaded in green, a description shaded in yellow, and a SWT composite shaded in blue.† Web services runtime extenders can contribute any kind of composite that is required to gather the necessary options from the user.† Any number of pages can be used to collect information from the user.† In the screen shot above an example is shown of how an optional page can be added.† If the user selects the ďDo you want to see the next page?Ē check box and then clicks on the next button an optional second page will be displayed.
A contributed composite can indicate if it is valid or not. †If it indicates that it is not valid the wizard framework will grey out the next and finish buttons so that the user can not proceed forward in the wizard until the page is made valid again.† In this example selecting the check box will cause the page to become invalid.†† The validation code can include a message to indicate why the page is invalid.† The screen shot below shows what is displayed if the check box is selected.
The sample also contains code to show how UI pages can be added for the skeleton scenario.† In this example the first skeleton page looks like this:
This scenario shows a slightly more complex flow of pages.† In this case the first skeleton wizard page can be followed by either just page 2, or just page 3, or both page 2 and page 3.
Detailed code discussion:
Now that you have seen how this example runtime is rendered in the Web services wizard, letís have a look at the code that made this happen.† First we will take a look at the plug-in extensions using the Example Runtime as an example:
The extension above defines the new Web services runtime and its label.
The extension above establishes that this runtime uses a Java implementation, that both top down and bottom up scenarios are supported, and that the runtime class† is:
This class is used to get the IWebService class and the IWebServiceClient classes for this new runtime.† In this example null is returned for the client, since we are focusing on the Web services creation scenarios in this example.
The ExampleWebservice class shows how an extender can inject a sequence of commands at different points in the Web services wizard flow( i.e. develop, assembly, deploy, install, and run )† For this example commands are only added into the develop method.†† This develop method is shown below.
In the code above a DataModel object is created to store the state data that is needed between commands and between commands and UI objects.† This class is only used by the extender so it can be anything that the extender wants it to be.† After the DataModel is declared two sets of commands are created, one for the bottom up scenario and one for the top down scenario.†† In this example the model is passed into all of the commands, but it doesnít need to be if the command does not need the model.† The key commands for the UI code above are Page1ComesUpBeforeThisBUCommand and Page1ComesUpBeforeThisTDCommand.† As we will see later, plug-in extensions will be added that will associate UI objects with these commands.† The ExampleDefaultingCommand command is also used by the UI objects.† This command is used to pass the DataModel object to UI objects.
Now that you have seen how to add commands into the Web services wizard flow, letís look at how the UI objects are added.† In the example code the extensions for adding the UI objects into the Web services framework is the following:
These extensions define the UI page objects that will be added to the Web services wizard flow.† In these extensions an association is made between a command class and a WidgetContributorFactory class.†† When the Web services framework attempts to execute a command it first checks to see if there is a WidgetContributorFactory associated with it.† If one is associated the UI objects contributed by this WidgetContributorFactory are displayed before this command is executed.† For example a command may have several parameters to be gathered before it is executed.† One or more UI pages can be displayed to gather these parameters from the user before the command is executed.† Note: extenders can not rely on the UI pages that they contribute to always being displayed, since the user could click the finish button on the first page of the wizard.† This means that extenders need to have default values for all parameters that they expose via the UI.†
Letís have a closer look at the WidgetContributorFactory for the bottom up scenario in this example.† The BeanConfigWidgetFactory class contains two methods called getFirstNamedWidget and getNextNamedWidget.† These two methods determine the order your UI page objects will be displayed.† The getFirstNamedWidget method returns the first UI page and the getNextNamedWidget object returns subsequent pages.† These methods are called dynamically by the framework which allows them to return different results depending on its model data.† This is how UI pages can be optionally added as was shown above.† If either of these methods returns null it indicates that no UI page is available.
Now letís look at how the DataModel object gets passed into the BeanConfigWidgetFactory class.† This is accomplished via two methods, the registerDataMappings method and the SetWebServiceDataModel method.† The first method is part of the WidgetContributorFactory interface.† This method specifies property mappings between objects in the Web services framework.† In this case we want the framework to associate the WebServiceDataModel property with the ExampleDefaultingCommand and the BeanConfigWidgetFactory object.† When the framework first loads the BeanConfigWidgetFactory class it will see that there is an association with the ExampleDefaultingCommand.† It will then use Java introspection to call the getWebServiceDataModel method on the ExampleDefaultingCommand object to retrieve the DataModel object.† It will then pass this DataModel object to the BeanConfigWidgetFactory object by calling the setWebServiceDataModel method.† Extenders can chose any property name that they want as long as they ensure that the getter and setter method names match the property name and that the type of the property object passed between the getter and setter is the same.
Now letís have a look at the init method in the BeanConfigWidgetFactory class.† This method creates two SimpleWidgetContributor objects, one for each page in the bean configuration scenario.† Each WidgetContributor specifies a title, a description, and a Widget object for the page.† Have a look at the screen shots above to see where this title and description text is displayed on the page.
The last item that we will talk about is the class that contributes the main composite for each page.†
The addControls method is where all the code for the creation of the pageís controls should go.† The parent parameter should be used as the composite parent for the controls that your code creates.† The statusListener parameter is used to control when validation should be performed on this page.† This listener object should be associated with any UI controls that could affect the validity of the page.† If your page is always valid this statusListener parameter can be ignored.
Note:† if a control affects whether subsequent pages appear after this page the statusListener must be associated with this control so that changes in the controls state will result in the handleEvent method being called.† Alternatively, the handleEvent method on the statusListener object can be called directly with a parameter of null to force the page to be validated.
As discussed above the statusListener object is used to determine when validation should occur.† The getStatus method is used to determine if the page is valid or not.† If the getStatus method returns null or a status with a severity of OK, WARNING, or INFO it indicates that the page is valid.†† If the status severity is WARNING or INFO the message text specified in the status object will be displayed in the description area of the page.† If the page is valid the next button will be enabled if there is a subsequent page in the wizard.† The finish button will also be enabled.† If the status severity is ERROR this indicates that the page is not valid.† The message text from the status object will be displayed in the description area of the page.† In addition the next button and finish button will be disabled until the page is made valid again.
Have a look at the BeanConfigWidget and the OptionalBeanConfigWidget classes for concrete implementations of this SimpleWidgetDataContributor class.