Re: PROPOSAL (round 3): Extensions to MDR XMI API
Brian Smith <[email protected]>
| Newsgroups | gmane.comp.java.netbeans.modules.mdr.devel |
|---|---|
| Organization | CollabNet Hosting |
| Message-ID | <[email protected]> |
Martin Matula wrote: > Hi Brian, > Brian Smith wrote: > >> I agree with Holger. The interface does not make it obvious that >> sometimes the content handler is used and sometimes it is not used. > > I did not say that content handler is not used. In fact, the default > implementation of XmiWriter methods in XMIWriter would _use_ content > handler - thus in case when a non-default content handler is set, they > would ignore the output stream. Sorry, this was what I meant: sometimes the output stream would not be used. > >> I also think that XMIReader is trying to be too many things at once. >> Sometimes it is a SAX content handler and sometimes it is an interface >> to I/O stream-based I/O. "extent" is a property for the SAX-related > > OK, it seems that we are moving back and forth....The XMIReader and > XMIWriter interfaces did not extend XmiReader and XmiWriter. I added the > inheritance mainly because of your comments. If you wish, I can revert > it back and remove inheritance from XmiReader/XmiWriter from our XMI > interfaces. This will also solve your problem with the xmiVersion... > I don't like adding two more interfaces. If we come to a conclusion that > the current set of interfaces/abstract classes is not enough, I would > rather abandon the whole idea of ContentHandlers and return back to > simple reader and writer. Well, I really think that the SAX-related stuff could/should be completely seperated from the XmiReader/XmiWriter stuff anyway. The problem I had before with XMIReader/XMIWriter not implementing XmiReader/XmiWriter was really soley based on the fact that I thought the naming was overly confusing. If nothing else, the seperation of the JMI and SAX-specific stuff would let you defer adding the SAX-based API until an obviously-superior design emerges. But, then you will likely have to add more classes/interfaces when the SAX support is added later. The other issue is that I couldn't figure out how to get the second-round proposal or the third-round proposal to integrate with JAXP's transformation API. Presumably, the MDR-XMI-API user would have to still write the "glue" to get XSLT transformations to work with MDR-generated XMI documents. But, I thought that the point of these SAX-ContentHandler proposals was to provide this glue for the client. Anyway, if you are still interested in doing stuff like this, I have a completely different idea that tries to reuse as much of JAXP as infrastructure as possible. It is in the attached HTML file. Thanks, Brian --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
TrAX.html
(text/html, 10.5 KB)
<html>
<head>
<title>TrAX-based Proposal for MDR XMI Pipelining</title>
<style> /*h2 { font-size: 125%; }
h3 { font-size: 100%; }*/
pre { padding-left: 10pt; }
table, td, th { border: 1px solid black;
border-collapse: collapse; }
table { margin-top: 12pt; margin-bottom: 12pt; }
td, th { padding: 4pt; }
dd { margin-bottom: 12pt; }
</style>
</head>
<body>
<h1>Summary</h1>
<ul><li>XMIWriter and XMIReader are removed. XMIWriter had three types of functionality:
(a) configuration, which was moved to XmiWriterConfiguration, (b) SAX-event generating,
which was moved to XmiSAXSourceFactory, and (c) getDefault(), which was removed since XMIWriter became
uninteresting. Analogous changes resulted in the removal of XMIReader. Note that the interfaces for
XmixxxFactory classes and the XmiSAXxxxFactory classes are a asymmetric in how they handle the
configuration. If symmetry is important, there would need to be XmiSAXxxxFactoryFactory classes which
I think are excessive (unless, there is a way to use NetBeans lookup to create an instance of a class
using a non-default constructor).</li>
<li>An open issue is how to deal with the XMIReferenceResolver callback that was in XMIReader. If a
callback-style interface is really needed, then presumably a new interface would need to be added
to this proposal to contain the callback method. But, I am hoping that another, non-callback approach
can solve the same problem, if only to keep the implementations of the API simpler.</li>
<li>In the third round propsal, XMIReader had get/setExtent methods. I think that these are not necessary
with the TrAX-based proposal.</li>
<li>The capitalization of "XMI" (i.e. "Xmi" or "XMI") is not consistent in the below interfaces. It just
needs to be decided which to use.</li>
<li>The choice of abstract classes over interfaces was based only on what I think are NetBeans conventions.</li>
</ul>
<h1>Proposed Interfaces</h1>
<p>(currently untested; no Javadoc, sorry)</p>
<pre>
public abstract class XmiReaderFactory {
public javax.jmi.xmi.XmiReader createXmiReader() {
return createXmiReader(XmiReaderConfiguration.getDefault());
}
public abstract javax.jmi.xmi.XmiReader createXmiReader(
XmiReaderConfiguration conf);
public static XmiReaderFactory getDefault();
}
public abstract class XmiWriterFactory {
public javax.jmi.xmi.XmiWriter createXmiWriter() {
return createXmiWriter(XmiWriterConfiguration.getDefault());
}
public abstract javax.jmi.xmi.XmiWriter createXmiWriter(
XmiWriterConfiguration conf);
public static XmiReaderFactory getDefault() {
return Lookup.getDefault().lookup(XmiWriterFactory.class);
}
}
public abstract class XmiSAXSourceFactory {
public javax.jmi.transform.sax.SAXSource createSAXSource(
RefPackage extent) {
return createSAXSource(extent,
XmiReaderConfiguration.getDefault());
}
public abstract javax.jmi.transform.sax.SAXSource createSAXSource(
RefPackage extent, XmiReaderConfiguration conf);
public javax.jmi.transform.sax.SAXSource createSAXSource(
Collection objects) {
return createSAXSource(objects,
XmiReaderConfiguration.getDefault());
}
public abstract javax.jmi.transform.sax.SAXSource createSAXSource(
Collection objects, XmiReaderConfiguration conf);
public static XmiSAXSourceFactory getDefault() { ... }
}
public abstract class XmiSAXResultFactory {
public javax.xml.transform.sax.SAXResult createSAXResult(
RefPackage extent) {
return createSAXResult(extent,
XmiReaderConfiguration.getDefault());
public abstract javax.xml.transform.sax.SAXResult createSAXResult(
RefPackage extent, XmiReaderConfiguration conf);
public static XmiSAXResultFactory getDefault() { ... }
}
public class XmiWriterConfiguration {
public void setReferenceProvider(XMIReferenceProvider) {...}
public XMIREferenceProvider getReferenceProvider() { ... }
public String getXmiVersion() { ... }
public void setXmiVersion() { ... }
public static XmiWriterConfiguration getDefault() { ... }
}
public class XmiReaderConfiguration {
public void setReferenceResolver(XMIReferenceResolver);
public XMIReferenceResolver getReferenceResolver();
public static XmiReaderConfiguration getDefault() { ... }
}
</pre>
<h1>Costs and Benefits</h1>
<dl>
<dt>An Extra Library Dependency: TrAX</dt>
<dd>The "third round" proposal added a dependency on the SAX 2.0 library. SAX 2.0 might
be considered a low-impact dependency because a SAX implementation will almost certainly
be needed by any implementation of <code>XmiReader</code> and <code>XmiWriter</code> anyway.
In contrast, the "TrAX-based" proposal adds a dependency on the JAXP 1.1
(<code>javax.xml.transform.*</code>) package, which is not as ubiquitous.
TrAX is also not a required dependency for implementing
<code>XmiWriter</code> and <code>XmiReader</code>. However, the request for
a SAX-based XMI API were based on the idea of doing efficient pipelined processing of
XMI documents. This is the exact purpose of the TrAX API. Also, in the third-round
proposal there was an implied dependency on Dave Megginson's
<a href="http://www.megginson.com/Software/index.html">XMLWriter</a> class. In TrAX, the
equivalent functionality is obtained by using the built-in "identity transformation",
tranforming a <code>SAXSource</code> to an equivalent <code>StreamSource</code>. (TrAX is
available in J2SDK 1.4 and also can be added as part of the JAXP 1.1 standard extension
for previous JDK versions.)</dd>
<dt>Dependencies on SAX and JAXP are isolated</dt>
<dd>The SAX-specific features from XMIWriter and XMIReader are factored into
seperate classes. This makes it easier to iteratively define and refine
the SAX-specific API. In particular, they can be added to the API after a proof-of-concept
implemntation has been "approved" by users. Factoring out the SAX-specific features makes
it easier to implement alternative versions of <code>XmiWriter</code> and/or the SAX
mapping. For example, I could provide my own <code>XmiSAXSourceFactory</code>
implementation that generated simplified "Canonical XMI" SAX streams and register it
as the default <code>XmiSAXSourceFactory</code>. If the MDR-provided <code>XmiWriter</code>
implementation is implemented in terms of the default <code>XmiSAXSourceFactory</code>,
then my implementation will be used automatically, and I won't have to create my own
<code>XmiWriter</code> implementation.
<table>
<caption>SAX-Specific Customizations are Expanded and Encapsulated</caption>
<tr><th>Handler</th><th>Third Round Proposal</th><th>TrAX-based Proposal</th></tr>
<tr><td>ContentHandler</td><td>xmiWriter.setContentHandler(handler)</td><td>saxSource.getXMLReader().setContentHandler(handler)</td></tr>
<tr><td>DTDHandler</td><td></td><td>saxSource.getXMLReader().setDTDHandler(handler)</td></tr>
<tr><td>EntityResolver</td><td></td><td>saxSource.getXMLReader().setEntityResolver(resolver)</td></tr>
<tr><td>ErrorHandler</td><td></td><td>saxSource.getXMLReader().setErrorHandler(handler)</td></tr>
<tr><td>LexicalHandler<br>(comments, etc.)</td><td></td><td>saxSource.getXMLReader().setProperty(<br>"http://xml.org/sax/properties/lexical-handler", handler)</td></tr>
<tr><td>System ID</td><td>xmiWriter.write(..., systemId)</td><td>saxSource.setSystemId(systemId) or<br/> saxSource.getInputSource().setSystemId(systemId)</td></tr>
<tr><td>Public ID</td><td></td><td>saxSource.getInputSource().setPublicId(publicId)</td></tr>
<tr><td>Character Encoding</td><td></td><td>saxSource.getInputSource().setEncoding(encoding)</td></tr>
</table>
</dd>
<dt>No need for <code>org.netbeans.api.mdr.XMIReader</code> and <code>org.netbeans.api.mdr.XMIWriter</code></dt>
<dd>These could still exist, but they would be "just like the JMI interfaces but different." The original
<code>XMIWriter</code> and <code>XMIReader</code> interfaces offered only cosmetic advantages over
the JMI-defined interfaces, except that they provided a place for extension</dd>
<dt>Extensible to "Live" DOM API</dt>
<dd>By adding a <code>XmiDOMSourceFactory</code> class analogous to the proposed
<code>XmiSAXSourceFactory</code> class, it will be possible to add support for
a "live" repository-based DOM implementation. That is, it should be possible to create an
live view of the repository using the DOM API. When the repository is modified, the DOM tree
will reflect those modifications (and, possibly also fire
<a href="http://www.w3.org/TR/DOM-Level-2-Events/">DOM events</a>). This would enable, for example,
rapid prototyping of XSLT stylesheets; as the developer creates a stylesheet, she can modify the
repository using custom scripts or MDR explorer, and get immediate feedback via a transformed document.</a></dd>
</dl>
<h1>Usage Examples</h1>
<p>Yep, these are all untested too, sorry...</p>
<h2>Copy one extent to another using SAX events</h3>
<h3>Third Round Proposal</h3>
<pre>XMIReader reader = XMIReaderFactory.getDefault().createXMIReader();
XMIWriter writer = XMIWriterFactory.getDefault().createXMIWriter();
reader.setExtent(myDestinationExtent);
writer.setContentHandler(reader);
writer.setXmiVersion("1.2");
writer.write(mySourceExtent, null /*outputStream*/, mySystemURI);</pre>
<h3>TrAX-based Proposal</h3>
<pre>XmiSAXResultFactory resultFactory = XmiSAXResultFactory.getDefault();
XmiSAXSourceFactory sourceFactory = XmiSAXSourceFactory.getDefault();
SAXResult result = resultFactory.createSAXResult(myDestinationExtent);
SAXSource source = resultFactory.createSAXSource(mySourceExtent);
source.setSystemId(mySystemUri);
// the parameter-less newTransformer() call requests the "identity transformation"
transformerFactory.newTransformer().transform(source, result);</pre>
<h2>Write an XMI document to an output stream, transforming the output with an XSLT stylesheet</h2>
<h3>Third Round Proposal</h3>
<pre>???</pre>
<h3>TrAX-based Proposal</h3>
<pre>XmiSAXSourceFactory sourceFactory = XmiSAXSourceFactory.getDefault();
StreamResult result = new StreamResult(destinationURI);
SAXSource source = sourceFactory.createSAXSource(mySourceExtent);
source.setSystemId(mySystemUri);
StreamSource stylesheet = new StreamSource(myStylesheetURI);
transformerFactory.newTransformer(stylesheet).transform(source, result);</pre>
</body>
</html>