blob: d42b56336d38d4ec891364a3e665fd118647f2f3 [file] [log] [blame]
<!-- 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
&quot;modules&quot; 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 &quot;virtual&quot;
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
&quot;virtual&quot; files with standard names; or as a &quot;virtual&quot;
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.)&nbsp;</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&nbsp;
- 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>&quot;Marker&quot; 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>&quot;data&quot; 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>&quot;data&quot; 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>&nbsp;</p>
</body>
</html>