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.
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 :
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>
There are several wizards that need to insert elements to DD regarding the type of the wizard.
Examples :
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.
This is the list of other possible clients of DD API :
Based on the expectations derived from the Use Cases we can specify the list of requirements:
Clients need to have access to deployment descriptor data, modify the data and be able to save changes back to FileObject or output stream.
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 :
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.
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.
It is not supposed that DD API interfaces will be implemented by third party - no SPI support.
Clients must be able to listen to the changes on DD API objects. The PropertyChangeEvents must be fired when :
DD API should notify client when web.xml file is unparsable or invalid towards the DTD or XML schema file.
The DD API provides no UI for deployment descriptor editing. It provides no UI at all.
DD API doesn't enable to create the web.xml file from scratch.
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.
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).
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.
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.
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 :
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 :
VersionNotSupportedException
The exception is thrown when specific DD version doesn't support a specific DD API method.
Methods :
NameAlreadyUsedException
Thrown when an element with the same name is being pushed to deployment descriptor.
Methods :
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 :
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()); } } }
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()); } } }
JRE 1.4 or JRE1.3 with JAXP
IDE/1 > 3.17
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.
Servlet 2.3, Servlet2.4, JAXP
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.
Not.
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.
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.
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.
There is no SPI support in DD API.
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 :
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.
Let's supose these subjects, that may come into a conflict, dealing with DD API :
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.
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.
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 :
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.