flexible project concepts
The following document provides an overview of the direction that the J2EE Tools team is going with the design and implementation of the Flexible Project Structure support and API. The document will discuss the following:
The design of the flexible project structure as enumerated by this document does not meet some of the initial suggestions due to constraints within the base Eclipse platform. For instance, only one server target is supported at a time (but users may switch the server target easily and recompile). Also, the resources which compose a module must be wholly contained under a single project, but of course modules may reference modules in other projects.
|Project Structural Model|
The EMF structural model allows the tooling to understand various layouts for projects. Each logical module contained in the project is represented by a WorkbenchModule element. The WorkbenchModule defines information about the type of module, the resources consumed by the module from the project, and the dependent modules. The WorkbenchModule is abstract, and as modeled, does not necessarily correspond to only J2EE artifacts.
The WorkbenchModule defines its deployedName, which is the name that will be used when the deployable form of the module is constructed. For a web application, the deployedName might be “MyWebApplication.war”. The WorkbenchModule may be uniquely referenced by a URI (stored on the WorkbenchModule as the “handle”). The fully qualified URI to any module must begin with the module protocol (“module:”), specify a subprotocol (“resource|classpath”) and then a path to the referenced module. A WorkbenchModule with the deplyedName “MyWebApplication.war” defined in a project named “MyWebModulesProject” would be referenced by the following URI: “module:/resource/MyWebModulesProject/MyWebApplication.war”.
Each WorkbenchModule defines a ModuleType. The ModuleType defines a moduleTypeId, which indicates the specific kind of module. The Web Tools Platform uses the moduleTypeId to determine how to handle the WorkbenchModule. The ModuleType may also define the runtime-paths of special metadata resources which are important to the WorkbenchModule. “Metadata” refers to resources which explain the details of the specific modules. An example of such a file would be the “WEB-INF/web.xml” deployment descriptor for Web Applications.
Each WorkbenchModule defines a list of WorkbenchModuleResources. Each WorkbenchModuleResource provides “sourcePath” and the corresponding “deployedPath”. The “sourcePath” can reference either a file or folder, but must reference a resource in the same project. The “deployedPath” will specify a location relative to the deployed structure of the WorbenchModule.
Each WorkbenchModule defines a list of DependentModules. Each DependentModule provides a handle which must resolve to another WorkbenchModule, a deployedPath that defines where the constructed module will be placed within the context of the deployed WorkbenchModule, and a dependencyType that can be either “consume” or “use” to indicate how the contents of that DependentModule should be absorbed by the WorkbenchModule.
|XML Format for WorkbenchModules|
The EMF model is stored as an XML model on disk. A full schema of this format will follow. The example below defines two modules in a single project. The first module (named: “MyWebModule.war”) defines two resources – each containers – that should be included in the deployed module. Three dependent modules are referenced, demonstrating the various ways that module URIs may be used. The first reference points to a local module, defined in the same project. The second reference (“module:/resource/AnotherProject/MyWebModuleLib2.jar”) uses a fully qualified URI that points to a module in another project. The last reference points to a module which is already in a deployable form and available on the classpath (“module:/classpath/AnotherTeamsUtilities.jar”). The second module defined by the XML sample (“MyWebModuleLib.jar”) defines a WorkbenchModule of the type “jst.utility”, which would be a simple Java library that could be used as a Utility Jar in a *.ear module or a Web Library in a *.war module.
|Constraints enforced by the current solution|
|Interaction Diagram for Important Components|
The follow diagram highlights the important relationships between the components in the Flexible Project API. Each project that supports a flexible project structure has a ModuleCoreNature associated with it. The ModuleCoreNature is used to manage the WTP Modules Structural Model and used to access the Artifact Edit Models. A project has exactly one Structural Model that defines all of the modules contained by the project. A project may have multiple Artifact Edit Models. Each Artifact Edit Model represents the pieces of a module that an operation or editor would want to modify, and are loaded and saved as a single unit.
The complexity of accessing the models is hidden from clients by the use of an Adapter pattern. When a client needs to read or modify a deployment descriptor model, the client may adapt the ArtifactEditModel to return an instance of the ArtifactEdit adapter or even request a specific subclass of ArtifactEdit with API which is targeted to the specific type of Deployment Descriptor. Clients that need to edit or understand the structural model of the modules in the project may use a similar pattern by adapting the ModuleStructuralModel to a ModuleCore adapter, which will then have the necessary API to focus on the module structural model.
The ArtifactEditModel and ModuleStructuralModel are each a subclass of the EditModel object. Edit models have a life cycle that requires them to be notified when clients are using them and notified when clients have completed their tasks. The ModuleCore and ArtifactEdit adapters will wrap the specific instances of the edit models they originally adapted. At the end of the client’s usage, the edit model must still be released. Releasing the edit model allows the framework to maintain an accurate reference count so that when the edit model is no longer in use by any client, the resources that it references may be unloaded.
|ArtifactEdit: Working with the Module Content Metamodel|
The ArtifactEdit adapter pattern is used to facilitate access to the modules resources, and provide API for specific module types. Clients must adapt the ArtifactEditModel to an ArtifactEdit adapter, which will operate in the context of the ArtifactEditModel that created it. An ArtifactEditModel may be acquired from the ModuleCoreNature using the specific WorkbenchModule the client is interested in.
public ArtifactEditModel getModuleEditModelForRead(WorkbenchModule wbModule, Object anAccessorKey)
Each module type will register an ArtifactEditAdapterFactory that creates a corresponding ArtifactEdit instance or subclass. For instance, a module of type “jst.web” would register the WebAppEditAdapterFactory.
IAdapterManager manager = Platform.getAdapterManager(); manager.registerAdapters(new WebAppEditAdapterFactory(), ArtifactEditModel.class);
Web Tools Platform contributors may use SPI as above to expand the types of ArtifactEdit adapters available to clients.
The following line would return the specific ArtifactEdit instance:
WebAppEdit util = (WebAppEdit)moduleEditModel.getAdapter(WebAppEdit.class);
The WebAppEdit class would have some of the specific module API previously found on the WebNature and WebEditModel. Type specific API would be found here:
public WebApp getWebApp(); public int getServletVersion();
Additionally, API is inherited from a common superclass:
public int getJ2EEVersion(); public createDeploymentDescriptorWithRoot(); public EObject getRootObject();
The API that will be provided to consumers is still under development, and suggestions for the kinds of API that are required are always welcome.
|Deployable Module Builder|
The Deployable Module Builder extends the Eclipse Incremental Builder framework in order to create and maintain a deployable module output structure for flexible module projects, which are now supported by the Web Tools Platform. The builder is added to any project which contains the Module Core Nature indicating that a given project is flexible. The can construct appropriate deploy structures for multiple modules of possibly varying types within the same project. The deploy structure for each J2EE module will be the corresponding J2EE-compliant runtime structure, but the builder may be extended to handle other types of modules that are not J2EE-specific. The deploy structures created by the builder may then be used to run on a server.
The Deployable Module Builder is scoped to the project level, as all Eclipse builders are, however this specific builder is more concerned about the individual modules within a given project. The design of the builder focuses on these individual modules, rather than a project-level artifact. The builder uses the WorkbenchModule definitions from the Modules Structural Model to understand what structures need to be created. Each operation arranges the deployable structure according to J2EE specifications by processing each of the WorkbenchModuleResources contained in its WorkbenchModule. The deployable structure is created in the project using the format “RootProject/.deployables/module_name”. The builder also manages all module dependencies making sure dependent modules are handled appropriately. Once all WorkbenchModules for the given project have been constructed, the Java builder will then compile all source code and the *.class files will be pushed into the predefined output locations within their corresponding WorkbenchModule deployed structure. The API defined by the Server Tools component will then be used to correctly adapt a WorkbenchModule to an IModule in order to run the modules on the server.
Each module type (EJB, Web App, App Client, Connector) must register its own type of deployable module builder. The registration mechanism is not yet complete, but will allow for total extensibility within the framework in how deployable modules are constructed. (Note: Currently in the M3 initial implementation, the only module which contributes a deployable module builder is Web Application, which means only a Web Application project can support flexible project structures.)
The following screen shots show a flexible Web Module project before and after the Deployable Module Builder has run.
The contents of the “.deployables” folder are represented as IModules to the Server Tooling, which is a model format that the server can deploy. The Server API contains a ServerUtil object that listens for project changes. A project change occurs after the deploy builder creates a “.deployables” folder. After the project change, ServerUtil will query for a DeployableFactory via an extension point. Currently, Server Tools assigns a single DeployableFactory per project, which must be expanded to allow multiple modules and modules types per project. The DeployableFactory will create multiple J2EE ModuleDelegates depending on the WorkbenchModules defined for the project (see ModuleCore API). Each J2EE ModuleDelegate will set its context and metadata location based on the location of the deployable structure created for the WorkbenchModule. Next, the DeployableFactory creates an IModule (as defined by the Server Tools API) caches the IModule by the project. As already stated, single module per project approach must change to support multiple modules per project.
Once the Run on server action is invoked by the user, the WorkbenchModule will be adapted to an IModule, which the Server Tools understand and can deploy.
Last updated Feb 16 2004