From bb723cfb0bdf3404c9776605995dfa993fe83c73 Mon Sep 17 00:00:00 2001 From: jprocter Date: Thu, 18 Feb 2010 13:46:17 +0000 Subject: [PATCH] SAXTreeViewer requires java 1.5 or later. git-svn-id: https://svn.lifesci.dundee.ac.uk/svn/repository/trunk@512 be28352e-c001-0410-b1a7-c7978e42abec --- build.xml | 212 ++++---- docs/SAXTreeViewer.txt | 10 + src/uk/ac/vamsas/test/document/SAXTreeViewer.java | 601 +++++++++++++++++++++ 3 files changed, 714 insertions(+), 109 deletions(-) create mode 100644 docs/SAXTreeViewer.txt create mode 100644 src/uk/ac/vamsas/test/document/SAXTreeViewer.java diff --git a/build.xml b/build.xml index 9302dfc..54cb360 100644 --- a/build.xml +++ b/build.xml @@ -23,9 +23,10 @@ - - - + + + + @@ -37,30 +38,30 @@ - + - - + + - - + + - + - - + + - - + + @@ -68,155 +69,148 @@ - - + + - - - - + + + + - - + + - - - - + + + + - - - - + + + + - + - + - + - - - - - - - - + + + + + + + + - - - + - + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - + - - - - + + + + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - + + + + diff --git a/docs/SAXTreeViewer.txt b/docs/SAXTreeViewer.txt new file mode 100644 index 0000000..08439dd --- /dev/null +++ b/docs/SAXTreeViewer.txt @@ -0,0 +1,10 @@ +uk.ac.vamsas.test.document.SAXTreeViewer +---------------------------------------- + +Instructions. +1. Compile using java 1.5 or later. +2. Execute the main method a single argument: the path to a vamsas document archive that you want to monitor. + +This is a class useful for debugging VAMSAS enabled programs. It uses the VAMSAS document low-level file monitoring mechanism to monitor accesses to the given file, and after each update to the document, it will update a tree representation of the VAMSAS document's XML. + + \ No newline at end of file diff --git a/src/uk/ac/vamsas/test/document/SAXTreeViewer.java b/src/uk/ac/vamsas/test/document/SAXTreeViewer.java new file mode 100644 index 0000000..59c2313 --- /dev/null +++ b/src/uk/ac/vamsas/test/document/SAXTreeViewer.java @@ -0,0 +1,601 @@ +package uk.ac.vamsas.test.document; + + +/*-- + + Copyright (C) 2001 Brett McLaughlin. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions, and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions, and the disclaimer that follows + these conditions in the documentation and/or other materials + provided with the distribution. + + 3. The name "Java and XML" must not be used to endorse or promote products + derived from this software without prior written permission. For + written permission, please contact brett@newInstance.com. + + In addition, we request (but do not require) that you include in the + end-user documentation provided with the redistribution and/or in the + software itself an acknowledgement equivalent to the following: + "This product includes software developed for the + 'Java and XML' book, by Brett McLaughlin (O'Reilly & Associates)." + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + + */ +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import org.xml.sax.Attributes; +import org.xml.sax.ContentHandler; +import org.xml.sax.ErrorHandler; +import org.xml.sax.InputSource; +import org.xml.sax.Locator; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; +import org.xml.sax.XMLReader; +import org.xml.sax.helpers.XMLReaderFactory; + +import uk.ac.vamsas.client.simpleclient.FileWatcher; +import uk.ac.vamsas.client.simpleclient.Lock; +import uk.ac.vamsas.client.simpleclient.SimpleDocument; +import uk.ac.vamsas.client.simpleclient.VamsasArchiveReader; + +// This is an XML book - no need for explicit Swing imports +import java.awt.*; +import javax.swing.*; +import javax.swing.tree.*; + +/** + * SAXTreeViewer uses Swing to graphically + * display an XML document. + */ +public class SAXTreeViewer extends JFrame { + /** Default parser to use */ +private String vendorParserClass = + "org.apache.xerces.parsers.SAXParser"; + +/** The base tree to render */ +private JTree jTree; + +/** Tree model to use */ +DefaultTreeModel defaultTreeModel; + +/** + *

This initializes the needed Swing settings.

+ */ +public SAXTreeViewer() { + // Handle Swing setup + super("SAX Tree Viewer"); + setSize(600, 450); +} + +/** + *

This will construct the tree using Swing.

+ * + * @param filename String path to XML document. + */ +public void init(String xmlURI) throws IOException, SAXException { + init(xmlURI, null); +} +/** + *

This will construct the tree using Swing.

+ * + * @param filename String apparent path to XML document. + * @param inputSource InputSource content of XML document + */ + public void init(String xmlURI, InputSource inputSource) throws IOException, SAXException { + + DefaultMutableTreeNode base = + new DefaultMutableTreeNode("XML Document: " + + xmlURI); + + // Build the tree model + defaultTreeModel = new DefaultTreeModel(base); + jTree = new JTree(defaultTreeModel); + + // Construct the tree hierarchy + if (inputSource==null) { + buildTree(defaultTreeModel, base, xmlURI); + } else { + buildTree(defaultTreeModel, base, xmlURI,inputSource); + } + // Display the results + getContentPane().add(new JScrollPane(jTree), + BorderLayout.CENTER); +} + +/** + *

This handles building the Swing UI tree.

+ * + * @param treeModel Swing component to build upon. + * @param base tree node to build on. + * @param xmlURI URI to build XML document from. + * @throws IOException - when reading the XML URI fails. + * @throws SAXException - when errors in parsing occur. + */ +public void buildTree(DefaultTreeModel treeModel, + DefaultMutableTreeNode base, String xmlURI) + throws IOException, SAXException { + // Parse + InputSource inputSource = + new InputSource(xmlURI); + buildTree(treeModel,base,xmlURI,inputSource); +} +/** + *

This handles building the Swing UI tree.

+ * + * @param treeModel Swing component to build upon. + * @param base tree node to build on. + * @param xmlURI apparent URI to build XML document from. + * @param inputSource the xml datasource to get the content from + * @throws SAXException + * @throws IOException + * @throws IOException - when reading the XML URI fails. + * @throws SAXException - when errors in parsing occur. + */ +public void buildTree(DefaultTreeModel treeModel, + DefaultMutableTreeNode base, String xmlURI, InputSource inputSource) throws IOException, SAXException { + + // Create instances needed for parsing + XMLReader reader = + XMLReaderFactory.createXMLReader(vendorParserClass); + ContentHandler jTreeContentHandler = + new JTreeContentHandler(treeModel, base); + ErrorHandler jTreeErrorHandler = new JTreeErrorHandler(); + + // Register content handler + reader.setContentHandler(jTreeContentHandler); + + // Register error handler + reader.setErrorHandler(jTreeErrorHandler); + + reader.parse(inputSource); +} +private static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(SAXTreeViewer.class); + +/** + *

Static entry point for running the viewer.

+ */ +public static void main(String[] args) { + try { + File archive = new File(args[0]); + // start watching a vamsas document archive + // watch + log.info("Endlessly Watching file " + archive); + /* + * if (!archive.exists()) archive.createNewFile(); + */// watch the new file... - taken straight from ClientsFileTest + FileWatcher w = new FileWatcher(archive); + SAXTreeViewer currentview = null; + boolean first=true; + while (true) { + // get watcher's lock to ensure state change is fixed for + // retrieval + Lock chlock = w.getChangedState(); + if (first || chlock != null) { + log.info("Got lock on " + + archive + + (archive.exists() ? " exists l=" + archive.length() + : "(non existant)")); + first = false; + if (archive.length() > 0) { + VamsasArchiveReader vreader = new VamsasArchiveReader(archive); + SimpleDocument sdoc = new SimpleDocument( + "testing vamsas watcher"); + try { + // pass the archive XML content to the xml viewer. + SAXTreeViewer newview = new SAXTreeViewer(); + newview.init(archive.toURI().toString(), new org.xml.sax.InputSource(vreader.getVamsasDocumentStream())); + if (currentview != null) + { + newview.setBounds(currentview.getBounds()); + // somehow copy over expanded state for existing objects and scroll state. + // could also highlight new / modified nodes. + newview.setVisible(true); + currentview.setVisible(false); + currentview.dispose(); + } else { + newview.setVisible(true); + } + currentview = newview; + + /* VamsasDocument d = sdoc.getVamsasDocument(vreader); + if (d != null) { + ArchiveReports.reportDocument(d, vreader, false, + System.out); + }*/ + System.out + .println("Update at " + + System.currentTimeMillis() + + "\n\n********************************************************\n"); + } catch (Exception e) { + log.error("Unmarshalling failed.", e); + } + vreader.close(); + w.setState(); + } + } + Thread.sleep(2000); + } + } catch (Exception e) { + log.info("Going away now.",e); + } +} +} + +/** +* JTreeContentHandler implements the SAX +* ContentHandler interface and defines callback +* behavior for the SAX callbacks associated with an XML +* document's content, bulding up JTree nodes. +*/ +class JTreeContentHandler implements ContentHandler { + +/** Hold onto the locator for location information */ +private Locator locator; + +/** Store URI to prefix mappings */ +private Map namespaceMappings; + +/** Tree Model to add nodes to */ +private DefaultTreeModel treeModel; + +/** Current node to add sub-nodes to */ +private DefaultMutableTreeNode current; + +/** + *

Set up for working with the JTree.

+ * + * @param treeModel tree to add nodes to. + * @param base node to start adding sub-nodes to. + */ +public JTreeContentHandler(DefaultTreeModel treeModel, + DefaultMutableTreeNode base) { + this.treeModel = treeModel; + this.current = base; + this.namespaceMappings = new HashMap(); +} + +/** + *

+ * Provide reference to Locator which provides + * information about where in a document callbacks occur. + *

+ * + * @param locator Locator object tied to callback + * process + */ +public void setDocumentLocator(Locator locator) { + // Save this for later use + this.locator = locator; +} + +/** + *

+ * This indicates the start of a Document parse-this precedes + * all callbacks in all SAX Handlers with the sole exception + * of {@link #setDocumentLocator}. + *

+ * + * @throws SAXException when things go wrong + */ +public void startDocument() throws SAXException { + // No visual events occur here +} + +/** + *

+ * This indicates the end of a Document parse-this occurs after + * all callbacks in all SAX Handlers.. + *

+ * + * @throws SAXException when things go wrong + */ +public void endDocument() throws SAXException { + // No visual events occur here +} + +/** + *

+ * This indicates that a processing instruction (other than + * the XML declaration) has been encountered. + *

+ * + * @param target String target of PI + * @param data StringSAXException when things go wrong + */ +public void processingInstruction(String target, String data) + throws SAXException { + + DefaultMutableTreeNode pi = + new DefaultMutableTreeNode("PI (target = '" + target + + "', data = '" + data + "')"); + current.add(pi); +} + +/** + *

+ * This indicates the beginning of an XML Namespace prefix + * mapping. Although this typically occurs within the root element + * of an XML document, it can occur at any point within the + * document. Note that a prefix mapping on an element triggers + * this callback before the callback for the actual element + * itself ({@link #startElement}) occurs. + *

+ * + * @param prefix String prefix used for the namespace + * being reported + * @param uri String URI for the namespace + * being reported + * @throws SAXException when things go wrong + */ +public void startPrefixMapping(String prefix, String uri) { + // No visual events occur here. + namespaceMappings.put(uri, prefix); +} + +/** + *

+ * This indicates the end of a prefix mapping, when the namespace + * reported in a {@link #startPrefixMapping} callback + * is no longer available. + *

+ * + * @param prefix String of namespace being reported + * @throws SAXException when things go wrong + */ +public void endPrefixMapping(String prefix) { + // No visual events occur here. + for (Iterator i = namespaceMappings.keySet().iterator(); + i.hasNext(); ) { + + String uri = (String)i.next(); + String thisPrefix = (String)namespaceMappings.get(uri); + if (prefix.equals(thisPrefix)) { + namespaceMappings.remove(uri); + break; + } + } +} + +/** + *

+ * This reports the occurrence of an actual element. It includes + * the element's attributes, with the exception of XML vocabulary + * specific attributes, such as + * xmlns:[namespace prefix] and + * xsi:schemaLocation. + *

+ * + * @param namespaceURI String namespace URI this element + * is associated with, or an empty String + * @param localName String name of element (with no + * namespace prefix, if one is present) + * @param qName String XML 1.0 version of element name: + * [namespace prefix]:[localName] + * @param atts Attributes list for this element + * @throws SAXException when things go wrong + */ +public void startElement(String namespaceURI, String localName, + String qName, Attributes atts) + throws SAXException { + + DefaultMutableTreeNode element = + new DefaultMutableTreeNode("Element: " + localName); + current.add(element); + current = element; + + // Determine namespace + if (namespaceURI.length() > 0) { + String prefix = + (String)namespaceMappings.get(namespaceURI); + if (prefix.equals("")) { + prefix = "[None]"; + } + DefaultMutableTreeNode namespace = + new DefaultMutableTreeNode("Namespace: prefix = '" + + prefix + "', URI = '" + namespaceURI + "'"); + current.add(namespace); + } + + // Process attributes + for (int i=0; i 0) { + String attPrefix = + (String)namespaceMappings.get(namespaceURI); + if (attPrefix.equals("")) { + attPrefix = "[None]"; + } + DefaultMutableTreeNode attNamespace = + new DefaultMutableTreeNode("Namespace: prefix = '" + + attPrefix + "', URI = '" + attURI + "'"); + attribute.add(attNamespace); + } + current.add(attribute); + } +} + +/** + *

+ * Indicates the end of an element + * (</[element name]>) is reached. Note that + * the parser does not distinguish between empty + * elements and non-empty elements, so this occurs uniformly. + *

+ * + * @param namespaceURI String URI of namespace this + * element is associated with + * @param localName String name of element without prefix + * @param qName String name of element in XML 1.0 form + * @throws SAXException when things go wrong + */ +public void endElement(String namespaceURI, String localName, + String qName) + throws SAXException { + + // Walk back up the tree + current = (DefaultMutableTreeNode)current.getParent(); +} + +/** + *

+ * This reports character data (within an element). + *

+ * + * @param ch char[] character array with character data + * @param start int index in array where data starts. + * @param length int index in array where data ends. + * @throws SAXException when things go wrong + */ +public void characters(char[] ch, int start, int length) + throws SAXException { + + String s = new String(ch, start, length); + DefaultMutableTreeNode data = + new DefaultMutableTreeNode("Character Data: '" + s + "'"); + current.add(data); +} + +/** + *

+ * This reports whitespace that can be ignored in the + * originating document. This is typically invoked only when + * validation is ocurring in the parsing process. + *

+ * + * @param ch char[] character array with character data + * @param start int index in array where data starts. + * @param end int index in array where data ends. + * @throws SAXException when things go wrong + */ +public void ignorableWhitespace(char[] ch, int start, int length) + throws SAXException { + + // This is ignorable, so don't display it +} + +/** + *

+ * This reports an entity that is skipped by the parser. This + * should only occur for non-validating parsers, and then is still + * implementation-dependent behavior. + *

+ * + * @param name String name of entity being skipped + * @throws SAXException when things go wrong + */ +public void skippedEntity(String name) throws SAXException { + DefaultMutableTreeNode skipped = + new DefaultMutableTreeNode("Skipped Entity: '" + name + "'"); + current.add(skipped); +} +} + +/** +* JTreeErrorHandler implements the SAX +* ErrorHandler interface and defines callback +* behavior for the SAX callbacks associated with an XML +* document's warnings and errors. +*/ +class JTreeErrorHandler implements ErrorHandler { + +/** + *

+ * This will report a warning that has occurred; this indicates + * that while no XML rules were "broken", something appears + * to be incorrect or missing. + *

+ * + * @param exception SAXParseException that occurred. + * @throws SAXException when things go wrong + */ +public void warning(SAXParseException exception) + throws SAXException { + + System.out.println("**Parsing Warning**\n" + + " Line: " + + exception.getLineNumber() + "\n" + + " URI: " + + exception.getSystemId() + "\n" + + " Message: " + + exception.getMessage()); + throw new SAXException("Warning encountered"); +} + +/** + *

+ * This will report an error that has occurred; this indicates + * that a rule was broken, typically in validation, but that + * parsing can reasonably continue. + *

+ * + * @param exception SAXParseException that occurred. + * @throws SAXException when things go wrong + */ +public void error(SAXParseException exception) + throws SAXException { + + System.out.println("**Parsing Error**\n" + + " Line: " + + exception.getLineNumber() + "\n" + + " URI: " + + exception.getSystemId() + "\n" + + " Message: " + + exception.getMessage()); + throw new SAXException("Error encountered"); +} + +/** + *

+ * This will report a fatal error that has occurred; this indicates + * that a rule has been broken that makes continued parsing either + * impossible or an almost certain waste of time. + *

+ * + * @param exception SAXParseException that occurred. + * @throws SAXException when things go wrong + */ +public void fatalError(SAXParseException exception) + throws SAXException { + + System.out.println("**Parsing Fatal Error**\n" + + " Line: " + + exception.getLineNumber() + "\n" + + " URI: " + + exception.getSystemId() + "\n" + + " Message: " + + exception.getMessage()); + throw new SAXException("Fatal Error encountered"); +} +} \ No newline at end of file -- 1.7.10.2