/*
* This file is part of the Vamsas Client version 0.2.
* Copyright 2010 by Jim Procter, Iain Milne, Pierre Marguerite,
* Andrew Waterhouse and Dominik Lindner.
*
* Earlier versions have also been incorporated into Jalview version 2.4
* since 2008, and TOPALi version 2 since 2007.
*
* The Vamsas Client is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The Vamsas Client is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the Vamsas Client. If not, see 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 filenameString
path to XML document.
*/
public void init(String xmlURI) throws IOException, SAXException {
init(xmlURI, null);
}
/**
* This will construct the tree using Swing.
* * @param filenameString
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. * @throwsIOException
- 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 * @throwsIOException
- 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.
*
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}
.
*
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.. *
* * @throwsSAXException
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 targetString
target of PI
* @param data String
SAXException 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.
*
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.
*
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
.
*
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
* 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.
*
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 chchar[]
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 chchar[]
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 nameString
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 exceptionSAXParseException
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 exceptionSAXParseException
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 exceptionSAXParseException
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");
}
}