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>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.