| <!-- saved from url=(0022)http://internet.e-mail --> |
| <html> |
| |
| <head> |
| <meta http-equiv="Content-Language" content="en-us"> |
| <meta http-equiv="Content-Type" content="text/html; charset=windows-1252"> |
| <meta name="GENERATOR" content="Microsoft FrontPage 4.0"> |
| <meta name="ProgId" content="FrontPage.Editor.Document"> |
| <title>Modules and Servers</title> |
| </head> |
| |
| <body> |
| |
| <h1>WTP Server Tools API<br> |
| Modules and Servers</h1> |
| <p>Last modified Nov. 3, 2004</p> |
| <p>These design notes grew out of discussions between Jim des Rivieres and Tim |
| Deboer the week of Oct. 25-27. The question is how to think of the |
| "modules" as they appear in the Server Core API, and how best to allow |
| for flexible modules layouts in the workspace.</p> |
| <h2>Who owns the notion of module?</h2> |
| <p>A module consists of some content - typically some files in the workspace. |
| Each different module type will have its own rules for the structure and meaning |
| of its content. For example, a simple web module might consist of a simple tree |
| of HTML files. When the module is published to a server, these files will be |
| copied to the real server.</p> |
| <p>However, it's funny to think of the module as something that exists solely |
| for the purpose of being published. A module in the workspace should be viewed |
| as something rich and multi-faceted. Most of the interesting aspects of a module |
| will be left up to the parties that actually defines real modules. It's like the |
| difference between the notions of employee and person. An employee is a limited |
| notion suitable for the limited purposes of describing an organization or a |
| payroll; a person is a more general notion.</p> |
| <p>As discussed in the JST content, there needs to flexibility on how J2EE |
| modules get laid out in the workspace. The complexities include:</p> |
| <ol> |
| <li>Single or multiple modules per workspace project.</li> |
| <li>Files, like Java source code, that are ordinarily considered part of that |
| module's content, but not for the purposes of publishing to the server.</li> |
| <li>Modules with files residing in JAR archives rather than directly in the |
| file system.</li> |
| <li>J2EE parent-child relationships between modules that may or may not be |
| represented with directory containment.</li> |
| </ol> |
| <p>Given the high degree of variability (and current uncertainty) on the module |
| side, one effective strategy is to separate module-related concerns as much as |
| possible from the server-related concerns, and to place only minimal |
| requirements what the module side needs to be like.</p> |
| <p>In other words, the Server Core API should only attempt to capture a limited |
| notion of module-as-something-to-publish. (IPublishableModule would be a more |
| suggestive name than the current IModule.)</p> |
| <h2>What does a server need to know about a module?</h2> |
| <p>Here are the high-level API operations that involve both modules and servers:</p> |
| <ul> |
| <li>Associating a module with a server |
| <ul> |
| <li>Add a module to a server.</li> |
| <li>Remove a module from a server.</li> |
| <li>Obtain a list of modules associated with a server.</li> |
| </ul> |
| </li> |
| <li>Publishing a module to a server |
| <ul> |
| <li>A server publishes the content of one of its modules to the real |
| server.</li> |
| </ul> |
| </li> |
| <li>Monitoring sync of module contents |
| <ul> |
| <li>A server determines whether the content of one of its modules is in |
| sync.</li> |
| <li>A server registers interest in being notified of future changes to the |
| contents of one of its modules.</li> |
| </ul> |
| </li> |
| </ul> |
| <p>The first group of operations for managing associations between modules and |
| servers could, in principle, be done using module ids alone; the actual modules |
| content (or even the module's existence) need not enter into it; the |
| implementation of these operations can be entirely generic. In practice, there |
| are additional validation checks that would be server-type-specific. The add |
| operations is necessarily initiated by a client in possession of both a module |
| and a server.</p> |
| <p>The second group of operations for actual publishing a module's content |
| requires discovering and accessing that content. Several things to observe:</p> |
| <ul> |
| <li>The code that publishes a module is server-type-specific and can be |
| specialized for each particular module type that the server supports. E.g., |
| Tomcat-specific code for publishing an EJB module; JBoss-specific code for |
| publishing an EJB module.</li> |
| <li>The module's content can be presented to servers in a module-type-specific |
| way. E.g., a a simple static web module can look like a "virtual" |
| tree of HTML files; a database module could present its content as something |
| suitable for databases. (The current approach uses a tree of files for |
| everything.)</li> |
| <li>The module-type-specific scheme could also include inter-module |
| relationships where appropriate. E.g., parent-child relationships for J2EE |
| module types.</li> |
| <li>The module-type-specific scheme for presenting module content to servers |
| can build in support for various alternatives. For example, EJB module |
| content could be presented variously as a deployment descriptor plus |
| "virtual" files with standard names; or as a "virtual" |
| EAR file; or as a java.io.File path to an EAR file; or as a java.io.File |
| directory containing an unzipped EAR.</li> |
| <li>The modules contents are revealed to the server only for a limited-time |
| interaction. This means that the objects are short-lived. There is no |
| requirement for events to report changes to content <i>during</i> a publish |
| operation.</li> |
| <li>For modules that really are based on files in the workspace, the module |
| contents that get presented for publication need not betray that fact.</li> |
| </ul> |
| <p>The third group of operations, for monitoring sync of module contents, are |
| very much like the second.</p> |
| <ul> |
| <li>The module-type-specific scheme for presenting module content to servers |
| could include a timestamp. If the server maintains an internal record of |
| what is on the real server along with the timestamp, the server can |
| determine whether the module contents need to be republished.</li> |
| <li>For module-type-specific schemes involving files, each file could carry |
| timestamp information. For some server types, this would allow just the |
| subset of changed files to be recopied to the server in some cases.</li> |
| <li>When the files of a module are stored in the workspace (or somewhere else |
| that can be tightly monitored), it is also practical to report change events |
| affecting a module to interested servers, instead of having the servers poll |
| for such changes.</li> |
| </ul> |
| <p>Here's an API sketch (it differs in a number of way from what is currently |
| released):</p> |
| <ul> |
| <li>Extension point for defining a new module type. |
| <ul> |
| <li>Define module type id, module type name.</li> |
| <li>Provide interface for accessing publishable content.</li> |
| </ul> |
| </li> |
| <li>Extension point for defining a new server type. |
| <ul> |
| <li>Define server type id, server type name.</li> |
| <li>Give list of supported module types.</li> |
| <li>Provide mechanism for publishing supported module types to real |
| server. (Server-type-specific and module-type-specific, but ignorant of |
| how and where module's content is actually stored.) </li> |
| <li>Provide mechanism for launching and talking to real server.</li> |
| </ul> |
| </li> |
| <li>Extension point for defining a new module factory. |
| <ul> |
| <li>Supply module factory id, module factory name.</li> |
| <li>Give list of module types that this factory is capable of creating.</li> |
| <li>Provide mechanism for creating/discovering module instances, and for |
| tracking its module instances.</li> |
| <li>Provide mechanism for providing publishable module content for its |
| module instances. (Server-type-independent, module-type-specific, and |
| cognizant of how and where a module's publishable content is actually |
| stored.)</li> |
| <li>Provide mechanism, where feasible, for notifying a server of changes |
| affecting publishable module content for its module instances.</li> |
| </ul> |
| </li> |
| <li>Module handle represent a unique module instance. |
| <ul> |
| <li>Module has a unique module id.</li> |
| <li>Module has a module type (represented by a module type id - module |
| types might not exist)</li> |
| <li>Module has a module factory (represented by a module factory id |
| - module factory might not exist). This is the module factory |
| responsible for module instance.</li> |
| <li>Module is just a handle (passive key). Module might not exist.</li> |
| <li>Used in server API for adding/removing a module to/from a server; for |
| obtaining a list of modules associated with a server; for obtaining a |
| list of modules associated with a module factory.</li> |
| <li>Interface is client API; clients do not implement.</li> |
| <li>Implementation is internal.</li> |
| <li> |
| <pre>public interface IModuleHandle { |
| public String getId(); |
| public String getModuleTypeId(); |
| public String getModuleFactoryId(); |
| } |
| [somewhere on SPI where it is available to servers and module factories] |
| public IModuleHandle createModuleHandle(String moduleId, String moduleTypeId, String moduleFactoryId);</pre> |
| </li> |
| </ul> |
| </li> |
| <li>Publishable module used by server for limited-purpose of publishing a |
| module's contents. |
| <ul> |
| <li>"Marker" interface - no methods.</li> |
| <li>Each module type defines its own specialized public subinterface for |
| obtaining the module's content.</li> |
| <li>Subinterface is API for parties supplying module factories and server |
| delegates (both SPI side)</li> |
| <li>Subinterface can spec whatever contract works for making the module's |
| publishable content available to any type of server that wishes to |
| support that module type.</li> |
| <li>Module-type-specific subinterface is used by server delegate for |
| publishing purposes.</li> |
| <li>Module-type-specific subinterface is implemented differently by each |
| module factory that can create instances of the module type.</li> |
| <li>These object only needs to be useful for the limited duration of |
| publishing (or resyncing).</li> |
| <li>The method should not be available to other parties.</li> |
| </ul> |
| </li> |
| <ul> |
| <li> |
| <pre>[somewhere available to server delegate (only)] |
| public IPublishableModule resolveForPublish(IModuleHandle moduleHandle); |
| public interface IPublishableModule {}</pre> |
| </li> |
| </ul> |
| <li>Module factories are things that create and modules. |
| <ul> |
| <li>Client API provides global list of module factories.</li> |
| <li>Each module factory can support any number of different module types.</li> |
| <li>Each module factory is responsible for creating and managing a global, |
| persistent, list of its module instances. (It would be even better if a |
| factory could keep .)</li> |
| <li>Module factory client API.</li> |
| </ul> |
| <ul> |
| <li> |
| <pre>ServerCore |
| public IModuleFactory[] getModuleFactories(); |
| public interface IModuleFactory { |
| public String getId(); |
| public supportsModuleType(IModuleType moduleType); |
| public IModuleHandle[] getModules(); |
| public IModuleHandle createModule(String moduleId, String moduleTypeId, Object data); |
| public void deleteModule(IModuleHandle); |
| public void addModuleFactoryListener(IModuleFactoryListener); |
| public void removeModuleFactoryListener(IModuleFactoryListener); |
| }</pre> |
| </li> |
| </ul> |
| <ul> |
| <li>Module factory SPI.</li> |
| </ul> |
| </li> |
| <ul> |
| <li> |
| <pre>public abstract class AbstractModuleFactoryDelegate { |
| public AbstractModuleFactoryDelegate(IModuleFactory factory) {...} |
| public final IModuleFactory getFactory() {...} |
| public abstract IModuleHandle[] getModules(); |
| public abstract IModuleHandle createModule(String moduleId, String moduleTypeId, Object data); |
| public abstract deleteModule(IModuleHandle); |
| public abstract IPublishableModule resolveForPublish(IModuleHandle moduleHandle); |
| }</pre> |
| </li> |
| </ul> |
| <li>Example |
| <ul> |
| <li>Declaration of module type: simple static web</li> |
| <li>Include module-type-specific subinterface for publishing module |
| expressed as a tree of files with timestamps.</li> |
| <li> |
| <pre>public interface IWebModule extends IPublishableModule { |
| public interface IModuleResource { |
| public String getName(); |
| public IPath getModuleRelativePath(); |
| } |
| public interface IModuleFile extends IModuleResource { |
| public long getTimeStamp(); |
| public InputStream getContents(); |
| } |
| public interface IModuleFolder extends IModuleResource { |
| public IModuleResource[] members(); |
| } |
| public IModuleResource[] members(); |
| }</pre> |
| </li> |
| <li>IWebModule is used in servers that support simple static web modules |
| <ul> |
| <li>Example server type: simple web server</li> |
| <li>Server delegate uses resolveForPublish(moduleHandle) to get an |
| IPublishableModule</li> |
| <li>Downcasts IPublishableModule to IWebModule</li> |
| <li>Calls methods on IWebModule to discover files comprising content.</li> |
| </ul> |
| </li> |
| <li>IWebModule is implemented by module factories that support simple |
| static web modules |
| <ul> |
| <li>Example module factory 1: static web modules kept in workspace |
| folders |
| <ul> |
| <li>Publishable content lives in workspace</li> |
| <li>Each module has a root folder.</li> |
| <li>Files and folders under root folder are isomorphic to |
| IWebModule layout. |
| <ul> |
| <li>All files and folders under root folder are publishable.</li> |
| <li>File and folder names are as published.</li> |
| <li>File contents and timestamps are as published.</li> |
| </ul> |
| </li> |
| <li>"data" object passed to IModuleFactory.createModule |
| is IContainer for module's root folder.</li> |
| <li>Factory maintains global list of modules in private plug-in |
| state.</li> |
| </ul> |
| </li> |
| <li>Example module factory 2: static web modules kept in zip file |
| <ul> |
| <li>Publishable content lives in zip files outside workspace</li> |
| <li>Each module has a single zip file.</li> |
| <li>"data" object passed to IModuleFactory.createModule |
| is java.io.File (or IPath) for module's zip file.</li> |
| <li>Files and folders within zip file are isomorphic to IWebModule |
| layout.</li> |
| <li>Factory maintains global list of its modules in private |
| plug-in state.</li> |
| </ul> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| <p> </p> |
| |
| </body> |
| |
| </html> |