org.glyptodon.guacamole.xml.DocumentHandler Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of guacamole-ext Show documentation
Show all versions of guacamole-ext Show documentation
The Java API for extending the main Guacamole web application. This
is not needed for authoring a new Guacamole-based web application.
The newest version!
/*
* Copyright (C) 2013 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.glyptodon.guacamole.xml;
import java.util.Deque;
import java.util.LinkedList;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
/**
* A simple ContentHandler implementation which digests SAX document events and
* produces simpler tag-level events, maintaining its own stack for the
* convenience of the tag handlers.
*
* @author Mike Jumper
*/
public class DocumentHandler extends DefaultHandler {
/**
* The name of the root element of the document.
*/
private String rootElementName;
/**
* The handler which will be used to handle element events for the root
* element of the document.
*/
private TagHandler root;
/**
* The stack of all states applicable to the current parser state. Each
* element of the stack references the TagHandler for the element being
* parsed at that level of the document, where the current element is
* last in the stack, and the root element is first.
*/
private Deque stack =
new LinkedList();
/**
* Creates a new DocumentHandler which will use the given TagHandler
* to handle the root element.
*
* @param rootElementName The name of the root element of the document
* being handled.
* @param root The TagHandler to use for the root element.
*/
public DocumentHandler(String rootElementName, TagHandler root) {
this.root = root;
this.rootElementName = rootElementName;
}
/**
* Returns the current element state. The current element state is the
* state of the element the parser is currently within.
*
* @return The current element state.
*/
private DocumentHandlerState getCurrentState() {
// If no state, return null
if (stack.isEmpty())
return null;
return stack.getLast();
}
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
// Get current state
DocumentHandlerState current = getCurrentState();
// Handler for tag just read
TagHandler handler;
// If no stack, use root handler
if (current == null) {
// Validate element name
if (!localName.equals(rootElementName))
throw new SAXException("Root element must be '" + rootElementName + "'");
handler = root;
}
// Otherwise, get handler from parent
else {
TagHandler parent_handler = current.getTagHandler();
handler = parent_handler.childElement(localName);
}
// If no handler returned, the element was not expected
if (handler == null)
throw new SAXException("Unexpected element: '" + localName + "'");
// Initialize handler
handler.init(attributes);
// Append new element state to stack
stack.addLast(new DocumentHandlerState(handler));
}
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
// Pop last element from stack
DocumentHandlerState completed = stack.removeLast();
// Finish element by sending text content
completed.getTagHandler().complete(
completed.getTextContent().toString());
}
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
// Get current state
DocumentHandlerState current = getCurrentState();
if (current == null)
throw new SAXException("Character data not allowed outside XML document.");
// Append received chunk to text content
current.getTextContent().append(ch, start, length);
}
/**
* The current state of the DocumentHandler.
*/
private static class DocumentHandlerState {
/**
* The current text content of the current element being parsed.
*/
private StringBuilder textContent = new StringBuilder();
/**
* The TagHandler which must handle document events related to the
* element currently being parsed.
*/
private TagHandler tagHandler;
/**
* Creates a new DocumentHandlerState which will maintain the state
* of parsing of the current element, as well as contain the TagHandler
* which will receive events related to that element.
*
* @param tagHandler The TagHandler which should receive any events
* related to the element being parsed.
*/
public DocumentHandlerState(TagHandler tagHandler) {
this.tagHandler = tagHandler;
}
/**
* Returns the mutable StringBuilder which contains the current text
* content of the element being parsed.
*
* @return The mutable StringBuilder which contains the current text
* content of the element being parsed.
*/
public StringBuilder getTextContent() {
return textContent;
}
/**
* Returns the TagHandler which must handle any events relating to the
* element being parsed.
*
* @return The TagHandler which must handle any events relating to the
* element being parsed.
*/
public TagHandler getTagHandler() {
return tagHandler;
}
}
}