Architecture Document for Deployment Descriptor API

Author: Milan Kuchtiak
Version: 1.4
Updated 01/16/2004
Contents

0. Initial Description of DD API

The project is based on the requirement to access the web module deployment descriptor for other Netbeans modules in a simple and servlet spec.-independent way.

1. The Goal of Project

There are multiple cases when web module deployment descriptor need to be modified from the "outside".
These are some examples of probable DD API clients :


The goal of DD API is to provide a simple way how web module deployments descriptor can be found, scanned and modified.

2. Use Cases

Use case 1 : J2EE Application

J2EE Aplications often need to explore the included modules. Web modules are usually used as clients or front-end components of J2EE application.
There is a requirement to be able to identify the sub-elements of web modules that are included to J2EE Application. For example, the J2EE Application need to be able to create a web module (WEB client), with the default web.xml file, then create a display-name and add a servlet element to deployment descriptor.

Use case 2 : Web Services Based on Servlet

JAX-RPC Web Services based on servlet need to include specific elemens to deployment descriptor and map the service to a URL that specifies where the WSDL file can be found.
See the example (JWSDP1.2) :

<listener>
  <listener-class>com.sun.xml.rpc.server.http.JAXRPCContextListener</listener-class>
</listener>
<servlet>
  <servlet-name>Hello</servlet-name>
  <display-name>Hello</display-name>
  <description>JAX-RPC endpoint - Hello</description>
  <servlet-class>com.sun.xml.rpc.server.http.JAXRPCServlet</servlet-class>
  <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
  <servlet-name>Hello</servlet-name>
  <url-pattern>/hello</url-pattern>
</servlet-mapping>

Use case 3 : Web Application Wizards

There are several wizards that need to insert elements to DD regarding the type of the wizard.
Examples :

Use case 4 : DD Editor

DD Editor significantly improves DD editing in the way that user doesn't need to know the syntax of web.xml file. It is desirable for DD Editor module to work with DD API interfaces instead of s2b beans directly (generated for the specific version of DD), as it is was done in previous versions.

Use case 5 : Other modules that need to modify the deployment descriptor

This is the list of other possible clients of DD API :

3. Requirements

Based on the expectations derived from the Use Cases we can specify the list of requirements:

  1. Read/write access

    Clients need to have access to deployment descriptor data, modify the data and be able to save changes back to FileObject or output stream.

  2. All data access

    Clients need to be able to access all the data from deployment descriptor and modify them easily. There need to be some general methods created to simplify the actions like :

    • create a new empty web.xml element
    • add a new element containing the initial data
    • find a specific element by name
    Comment: These methods need to improve the usability comparing to the direct manipulation with schema2beans classes.

  3. Multiple Version Support, support for both DTD and XML schema driven files

    Provide the universal DD API interfaces/methods regardless the version of DD(Servlet2.3/Servlet2.4). Throw the VersionNotSupportedException when the method is not supported in specific version.

  4. Flexibility against the servlet specification changes

    DD API should be prepared for the Servlet spec.changes in order to be backward compatible :

    - if new elements are added, new methods need to throw the VersionNotSupportedException in order to support the old version(s).
    - If elements are removed from new spec.(broken backward compatibility), the related methods need to throw the VersionNotSupportedException.

  5. It is not supposed that DD API interfaces will be implemented by third party - no SPI support.

  6. DD API listener model

    Clients must be able to listen to the changes on DD API objects. The PropertyChangeEvents must be fired when :

    • web.xml elements are changed
    • web.xml elements are added
    • web.xml elements are removed
    The PropertyChangeListener should be available to listen to web.xml nodes (represented by DD API interfaces).

  7. Invalid data handling

    DD API should notify client when web.xml file is unparsable or invalid towards the DTD or XML schema file.

What is the DD API not :

  1. NOT DD Editor

    The DD API provides no UI for deployment descriptor editing. It provides no UI at all.

  2. NOT web.xml constructor

    DD API doesn't enable to create the web.xml file from scratch.

  3. NOT able to change the version of web.xml file

    This feature is not planned to be supported for the first version of DD API (PromotionB), but can be implemented later.
    Thus, the server spec.version is the read-only property for the first version.

  4. NOT related to web-apps functionality

    There is no relationship to web-apps functionality provided by web/core, web/advanced etc. modules. In other words DD API exists as a standalone Netbeans module not dependent on other modules (except OpenIDE/FileSystem,OpenIDE/Util and schema2beans).

  5. NO ANT support

    Meanwhile there is no support for web.xml modification using the ANT build script. There are no DD API ant tasks prepared for the first version.
    It is expected that for the next version one ore more ANT tasks will be created for DD modification.

4. The Overall Architecture

The DD API is based on a bunch of interfaces corresponding to the deployment descriptor xml structure. The names of interfaces are derived from the names of deployment descriptor elements in web.xml file. The DD API interfaces are organized in a hierarchic tree structure. The object of particular interface type is available through the root (WebApp object) od deployment descriptor. The implementation of DD API interfaces is hidden for clients. It is based on schema2beans infrastructure and is DD version - specific. (there is always requirement to support at least two successive versions of DD specification). The root of the deployment descriptor is available using the DDProvider class.

4.1. DD API Interfaces

Package: org.netbeans.api.web.dd

All DD API interfaces are included to this package.
Here is the hierarchic structure of the DD API interfaces :

WebApp
  - Icon [*]
  - InitParam [*]
  - Filter [*]
    - Icon [*]
    - InitParam [*]
  - FilterMapping [*]
  - Listener [*]
    - Icon [*]
  - Servlet [*]
    - Icon [*]
    - InitParam [*]
    - RunAs [*]
    - SecurityRoleRef [*]
  - ServletMapping [*]
  - SessionConfig [?]	
  - MimeMapping [*]
  - WelcomeFileList [?]
  - ErrorPage [*]
  - Taglib [*]
  - JspConfig [?]
    - Taglib [*]
    - JspPropertyGroup [*]
  - SecurityConstraint [*]
    - WebResourceCollection [+]
    - AuthConstraint [?]
    - UserDataConstraint [?]
  - LoginConfig [?]
    - FormLoginConfig [?]
  - SecurityRole [*]
  - EnvEntry [*]
  - EjbRef [*]
  - EjbLocalRef [*]
  - ServiceRef [*]
    - Icon [*]
    - PortComponentRef [*]
    - ServiceRefHandler [*]
      - InitParam [*]
  - ResourceRef [*]
  - ResourceEnvRef [*]
  - MessageDestinationRef [*]
  - MessageDestination [*]
    - Icon [*]
  - LocaleEncodingMappingList [?]
    - LocaleEncoding [+]

Comments : 
[*] - objects occur multiple times in the parent object (0-n)
[+] - objects occur multiple times in the parent object (1-n)
[?] - object can occur only once in the parent object (0-1)

The syntax and usage of interface methods is very simple and straightforward.
If certain object [XYZ interface] occurs multiple times in the parent object these methods are present in the parent interface :


If certain object [XYZ interface] cat occur only once in the parent object these methods are present in the parent interface :
Example : The WebApp interface contains these methods for getting/setting Servlets and WelcomeFileList :
Interfaces contain additional methods corresponding to the simple (String) sub-elements following the deployment descriptor xml syntax.
Example : The Taglib interface contains these additional getters/setters :
Interfaces usually extend some interfaces from
org.netbeans.api.web.dd.common package. For example if a DD Element has the description property, it extends the DescriptionInterface containing the methods for handling the description property .
Example : The WebApp, Servlet, Filter, Listener, ServiceRef , WebResourceCollection extend the DescriptionInterface.

4.2. DDProvider class

Package: org.netbeans.api.web.dd

Provides the access to deployment descriptor root - WebApp object. The DDProvider class is a singleton and caches the WebApp objects in IDE. There are following methods for getting the WebApp object :

4.3. DD API Exceptions

Package: org.netbeans.api.web.dd.common

VersionNotSupportedException

The exception is thrown when specific DD version doesn't support a specific DD API method.
Methods :

Examples :

NameAlreadyUsedException

Thrown when an element with the same name is being pushed to deployment descriptor.
Methods :

Examples :

4.4. DD API Super-Interfaces

Package: org.netbeans.api.web.dd.common

CommonDDBean

Interface providing the basic functionality for all DD API interfaces :


CreateCapability

Interface providing a create capability - for creating a not bound or bound deployment descriptor elements :


FindCapability

Interface providing a general lookup capability :


DescriptionInterface

Interface providing methods for description manipulation. Extended by DD Interfaces containing the Description property.
Methods :


DisplayNameInterface

Interface providing methods for display name manipulation. Extended by DD Interfaces containing the DisplayName property.
Methods :


IconInterface

Interface providing methods for icon manipulation. Extended by DD Interfaces containing the Icon property.
Methods :


ComponentInterface

It is a compound interface created by CommonDDBean, CreateCapability, FindCapability, DescriptionInterface, DisplayNameInterface and IconInterface.

RootInterface

Interface providing an additional functionality for the WebApp interface like method for writing the deployment descriptor to file or merging two DDs into one bean graph.
It extends the ComponentInterface.
Methods :


4.5. Examples of Usage

Example 1

In this example, DD API client prints all listener classes from deployment descriptor to the console:
 package mypackage;

 import org.netbeans.api.web.DDProvider;
 import org.netbeans.api.web.dd.WebApp;
 import org.netbeans.api.web.dd.Listener;
 import org.openide.filesystems.*;

 public class ListenerExample {
     
    /**
     * @param args the command line arguments
     */

    public static void main(String[] args) throws Exception {

	// get the file object of web.xml file
        DDProvider ddProvider = DDProvider.getDefault();
        FileObject fo = Repository.getDefault().findResource("WEB-INF/web.xml");

	// get the deployment descriptor root object
        WebApp webApp = ddProvider.getDDRoot(fo);

	// print the version of deployment dscriptor
        System.out.println("DD version = "+webApp.getVersion());

	// get the array of listeners and print the listener classes
        Listener[] listeners = webApp.getListener();
        for (int i=0; i<listeners.length; i++) {
            System.out.println("Listener ["+i+"] = "+listeners[i].getListenerClass());
        }
    }
 }

Example 2

In this example, DD API client searches a servlet "CarServlet" and, if found, adds 2 init parameters there "car_type" and "car_color" :
 package mypackage;

 import org.netbeans.api.web.DDProvider;
 import org.netbeans.api.web.dd.WebApp;
 import org.netbeans.api.web.dd.Servlet;
 import org.netbeans.api.web.dd.InitParam;
 import org.openide.filesystems.*;

 public class InitParamExample {
     
    /**
     * @param args the command line arguments
     */

    public static void main(String[] args) throws Exception {

	// get the file object of web.xml file
        DDProvider ddProvider = DDProvider.getDefault();
        FileObject fo = Repository.getDefault().findResource("WEB-INF/web.xml");

	// get the deployment descriptor root object
        WebApp webApp = ddProvider.getDDRoot(fo);

	// print the version of deployment dscriptor
        System.out.println("DD version = "+webApp.getVersion());

	// looks for the "CarServlet" servlet at WebApp object by ServletName property
        Servlet servlet = (Servlet) webApp.findBeanByName("Servlet", "ServletName", "CarServlet");

        if (servlet!=null) {

            // create a new - not bound - InitParam object and set it 2 properties ("ParamName" and "ParamValue")
            InitParam param = (InitParam)servlet.createBean("InitParam");
            param.setParamName("car_type");
            param.setParamValue("FORD");
	    // add InitParam object to Servlet object
            servlet.addInitParam(param);

            // create another InitParam object and set it 2 properties
            param = (InitParam)servlet.createBean("InitParam");
            param.setParamName("car_color");
            param.setParamValue("green");
	    // add InitParam object to Servlet object
            servlet.addInitParam(param);

	    // write changes to file object
            webApp.write(fo);

	    // print all init params to console
            InitParam[] newParams = servlet.getInitParam();
            for (int i=0;i<newParams.length;i++)
                System.out.println("init-param ["+i+"] = "+newParams[i].getParamName()+" -> "+newParams[i].getParamValue()); 
        }
    }
 }

5. Time Estimates of the Work

6. Dependencies

6.1. NetBeans Modules

6.2. External Projects

No dependences.

7. Platform Requirements

JRE 1.4 or JRE1.3 with JAXP
IDE/1 > 3.17

8. Public Packages

org.netbeans.api.web.dd - DD API interfaces and DDProvider class.

org.netbeans.api.web.dd.common - DD API Super-Interfaces and DD API Exceptions.

9. Compatibility

9. 1. With Standards

Servlet 2.3, Servlet2.4, JAXP

9. 2. Compatibility Impact

The impact on other modules currently exploring and manipulating web.xml files is minimal. Instead of working with schema2bean classes directly, they need to switch to DD API and work with interfaces.
In most cases the method names used in s2b generated classes are equal to method names in DD API interfaces.

10. Using Lookup

Not.

11. Performance

The reading/parsing and writing the web.xml is the bottleneck of the DD API performance. Than the schema2beans root object is weakly cached in memmory. However, those operations have no visible impact while working with web modules with standard-sized deployment descriptors.
The measurements were not provided for DD API specifically, but there may have been some measurements made in
schema2beans infrastructure that is used for DD API implementation. There should be no additional deficites added by DD API.

11.1. Scalability

Getting rid of the direct dependency on schema2beans generated bean graph enables DD API clients to work with deployment descriptor without care about version-specific details.

11.2. Limitations

Some methods from DD API interfaces throw the VersionNotSupportedException which may be changed in the future (when all versions of DD will suport that element) or vice versa there can be methods which may not be supported in higher versions, so the exception should be thrown. It is supposed that in the future only the limited number of DD versions will always be supported (2 successive versions) . See also the What is DD API Not For part.

11.3. Impact of SPI on Performance

There is no SPI support in DD API.

12. Resolving Concurrency

Several clients can concurrently use the DD API and work with the same instance of deployment descriptor at the same time.
In another words, several clients can work with the same DD API data model. See the picture :

DD API Schema

Problems arise when one client stars to modify a web.xml and another client tries to make some changes to the same file while being modificated by the first client.
Also the synchronization between the data model (in memory) and web.xml file (on disk) need to be solved. It is important to devide the responsibility for rosolving the concurent issues and synchronization between DD API module and client modules.

12.1. Use Cases

Let's supose these subjects, that may come into a conflict, dealing with DD API :

Use Case 1 [Client 1 vs. Client 2]

Client 1 (DD Text Editor) : the web.xml file is open in text editor and user makes some changes leading towards a valid web.xml document, then saves the changes.
Client 2 (Servlet Wizard) : gets the deployment descriptor (using DD API) and adds the servlet and servlet-mapping. Then it tries to write the changes.
Expected Behaviour : changes from Client 2 are propagated to text editor and afterwards saved to web.xml file.

Use Case 2 [Client 1 vs. Client 2]

Client 1 (DD Text Editor) : the web.xml file is open in text editor and user makes some changes leading towards a valid web.xml document, but doesn't save the changes.
Client 2 (Servlet Wizard) : tries to update and write deployment descriptor using DD API.
Expected Behaviour : changes from Client 2 are propagated to text editor and user is asked to save the changes in order to be accepted by web server.

Use Case 3 [Client 1 vs. Client 2]

Client 1 (DD Text Editor) : the web.xml file is open in text editor and user makes some changes leading towards an invalid web.xml document, doesn't save the changes.
Client 2 (Servlet Wizard) : tries to update and write deployment descriptor using DD API.
Expected Behaviour : The text editor asks user to complete the changes to make the document valid and to save the document. Then Changes made by Client 2 are merged.

Use Case 4 [Client 1 vs. Client 2]

Client 1 (DD Text Editor) : the web.xml file is open in text editor and user makes some changes leading towards an invalid web.xml document, then saves the changes even for invalid data.
Client 2 (Servlet Wizard) : tries to update and write deployment descriptor using DD API.
Expected Behaviour : The same as for Use Case 3 - user is asked to modify (and save) the document in text editor in order to be valid, then changes made by Client 2 are merged.

Use Case 5 [Client 1 vs. Client 3]

Client 1 (DD Text Editor) : the web.xml file is open in text editor and user makes some changes leading towards the invalid web.xml document.
Client 3 (DD Visual Editor) : user switches to Visual DD Editor and continues in editing using a visual editor component panel.
Expected Behaviour : When trying to provide the changes(the focus on text field is lost), Text Editor client should be notified that document in text editor isn't valid and following changes can cause some data lost. After accomlishing the changes in text editor, changes from visual editor are merged to web.xml data model.

The Client 2[Wizard] and Client 3[Visual DD Editor] don't differ much in behaviour except that Visual DD Editor doesn't require the changes to be saved to disk after any change in component panel. In fact the Text Editor and Visual Editor should share the same save cookie object and let user to decide when to save the data to disk.

12.2. Solution and Impact on DD API users

The concurrent problems should be hidden for the users and need to be resolved in implementation part of DD API and in DD Text Editor and DD Visual Editor respectively.
The solution is based on call back pattern when DD Editor provides the DD API with OutputProvider object.
DD API delegates then the save action to OutputProvider.save() method that resolves the writing as well as the concurent problem for DD API. It is realizable, because OutputProvider object knows whether the web.xml document is valid or not in DD Editor.

It is important for DD API cliets to minimize the time between the event when web.xml file is open (obtained using the DDProvider.getDDRoot() method) and saved. There is not reasonable do create delays between those actions.
Example : When implementing the Servlet Wizard the wrong technique is to obtain the WebApp (DD root) object when the wizard is open and then provide the (modification and) writing after the wizard is finished. The good implementation takes the root object just before the deployment descriptor is modified and saved.

13. Extensibility

The DD API need do be flexible enough towards the future changes in Servlet specification. Nowadays DD API accepts both the DTD and XML schema files. It is expected that in future the XML schema for deployment descriptor will be changed. The DD API is prepared for changes that either break or not break the backward compatibility. It is expected that :

Though the DD API consists of a set of interfaces, the implementation part is supposed to be writen only by DD API owners.
There is also no support for plug-in the new implementation.
This will be specified clearly in the API documentation.

14. Testing

The DD API is being developed in the Extreme Programming style and the NbUnit tests were already developped. Though, the unit tests are running in "ide" mode currently, newertheless, they are ready to run in "code" mode as well.