Java tutorial
/* * Copyright (c) 2000-2004 Netspective Communications LLC. All rights reserved. * * Netspective Communications LLC ("Netspective") permits redistribution, modification and use of this file in source * and binary form ("The Software") under the Netspective Source License ("NSL" or "The License"). The following * conditions are provided as a summary of the NSL but the NSL remains the canonical license and must be accepted * before using The Software. Any use of The Software indicates agreement with the NSL. * * 1. Each copy or derived work of The Software must preserve the copyright notice and this notice unmodified. * * 2. Redistribution of The Software is allowed in object code form only (as Java .class files or a .jar file * containing the .class files) and only as part of an application that uses The Software as part of its primary * functionality. No distribution of the package is allowed as part of a software development kit, other library, * or development tool without written consent of Netspective. Any modified form of The Software is bound by these * same restrictions. * * 3. Redistributions of The Software in any form must include an unmodified copy of The License, normally in a plain * ASCII text file unless otherwise agreed to, in writing, by Netspective. * * 4. The names "Netspective", "Axiom", "Commons", "Junxion", and "Sparx" are trademarks of Netspective and may not be * used to endorse or appear in products derived from The Software without written consent of Netspective. * * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT A WARRANTY OF ANY KIND. ALL EXPRESS OR IMPLIED REPRESENTATIONS AND * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, * ARE HEREBY DISCLAIMED. * * NETSPECTIVE AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE OR ANY THIRD PARTY AS A * RESULT OF USING OR DISTRIBUTING THE SOFTWARE. IN NO EVENT WILL NETSPECTIVE OR ITS LICENSORS BE LIABLE FOR ANY LOST * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THE SOFTWARE, EVEN * IF IT HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. */ package com.netspective.commons.xml; import java.io.File; import java.io.IOException; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Stack; import javax.xml.parsers.ParserConfigurationException; import org.apache.commons.jexl.Expression; import org.apache.commons.jexl.ExpressionFactory; import org.apache.commons.jexl.JexlContext; import org.apache.commons.jexl.JexlHelper; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.xml.sax.Attributes; import org.xml.sax.Locator; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; import com.netspective.commons.io.InputSourceLocator; import com.netspective.commons.io.Resource; import com.netspective.commons.xml.template.Template; import com.netspective.commons.xml.template.TemplateApplyContext; import com.netspective.commons.xml.template.TemplateCatalog; import com.netspective.commons.xml.template.TemplateContentHandler; import com.netspective.commons.xml.template.TemplateElement; import com.netspective.commons.xml.template.TemplateProducer; import com.netspective.commons.xml.template.TemplateText; public abstract class AbstractContentHandler implements TemplateContentHandler { private static final Log log = LogFactory.getLog(AbstractContentHandler.class); private NodeIdentifiers nodeIdentifiers; private ParseContext parseContext; private Stack nodeStack = new Stack(); // stack that manages the non-ignored, non-template definition nodes private Stack ignoreStack = new Stack(); // stack that manages the nodes that should be ignored (will be empty if not inside an ignorable element) private Stack templateDefnStack = new Stack(); // stack that manages nodes for template definitions (will be empty if no template is being defined) private StringBuffer characters = new StringBuffer(); private boolean inInclude; // set to true when processing inside an include element public AbstractContentHandler(ParseContext pc, String xmlNameSpace) { this.parseContext = pc; this.nodeIdentifiers = new NodeIdentifiers(xmlNameSpace); } public NodeIdentifiers getNodeIdentifiers() { return nodeIdentifiers; } public void setNodeIdentifiers(NodeIdentifiers nodeIdentifiers) { this.nodeIdentifiers = nodeIdentifiers; } public Stack getIgnoreStack() { return ignoreStack; } public Stack getTemplateDefnStack() { return templateDefnStack; } public boolean isInInclude() { return inInclude; } public void setInInclude(boolean inInclude) { this.inInclude = inInclude; } public boolean isInIgnoreNode() { return !ignoreStack.isEmpty(); } public String getStateText() { return null; } public TemplateCatalog getTemplatCatalog() { return parseContext.getTemplateCatalog(); } public TemplateProducer getDynamicTemplatesProducer() { if (parseContext.getParentPC() != null) return ((TemplateContentHandler) parseContext.getParentPC().getParser().getContentHandler()) .getDynamicTemplatesProducer(); else return nodeIdentifiers.getDynamicTemplatesProducer(); } public void addDynamicTemplate(Template template) { parseContext.getTemplateCatalog().registerTemplate(getDynamicTemplatesProducer(), Integer.toString(template.hashCode()), template); } public ContentHandlerNodeStackEntry getActiveNodeEntry() { return (ContentHandlerNodeStackEntry) getNodeStack().peek(); } public boolean haveActiveNodeEntry() { return getNodeStack().size() > 0; } public Stack getNodeStack() { return nodeStack; } public ParseContext getParseContext() { return parseContext; } public void setParseContext(ParseContext parseContext) { this.parseContext = parseContext; } public Object evaluateHandlerExpression(String exprText) throws ContentHandlerException { try { Expression expression = ExpressionFactory.createExpression(exprText); JexlContext context = JexlHelper.createContext(); Map vars = new HashMap(); vars.put("handler", this); vars.put("parseContext", parseContext); vars.put("activeNode", nodeStack.peek()); vars.put("nodeStack", nodeStack); return expression.evaluate(context); } catch (Exception e) { if (e instanceof ContentHandlerException) throw (ContentHandlerException) e; else throw new ContentHandlerException(parseContext, e); } } public void includeInputSource(ContentHandlerNodeStackEntry activeEntry, Attributes attrs) throws ContentHandlerException, ParserConfigurationException, SAXException, IOException, TransformProcessingInstructionEncounteredException { String resourceName = attrs.getValue(NodeIdentifiers.ATTRNAME_INCLUDE_RESOURCE); String templateName = attrs.getValue(NodeIdentifiers.ATTRNAME_INCLUDE_TEMPLATE); if (resourceName != null && resourceName.length() > 0) { Resource resource = null; Object relativeTo = activeEntry.getResourceIncludeRelativeTo(); String relativeToExpr = attrs.getValue(NodeIdentifiers.ATTRNAME_INCLUDE_RESOURCE_RELATIVE_TO); if (relativeToExpr != null) relativeTo = evaluateHandlerExpression(relativeToExpr); log.trace("Including resource '" + resourceName + "' relative to '" + relativeTo + "'."); if (relativeTo instanceof Class) resource = new Resource((Class) relativeTo, resourceName); else if (relativeTo instanceof ClassLoader) resource = new Resource((ClassLoader) relativeTo, resourceName); else if (relativeTo instanceof String) { try { resource = new Resource(Class.forName((String) relativeTo), resourceName); } catch (ClassNotFoundException e) { throw new ContentHandlerException(parseContext, "The result of '" + NodeIdentifiers.ATTRNAME_INCLUDE_RESOURCE_RELATIVE_TO + "' attribute expression '" + relativeTo + "' in <" + nodeIdentifiers.getIncludeElementName() + "> (" + relativeToExpr + ") must be either a Class or a ClassLoader."); } } else if (relativeToExpr != null) throw new ContentHandlerException(parseContext, "The result of '" + NodeIdentifiers.ATTRNAME_INCLUDE_RESOURCE_RELATIVE_TO + "' attribute expression '" + relativeTo + "' in <" + nodeIdentifiers.getIncludeElementName() + "> (" + relativeToExpr + ") must be either a Class or a ClassLoader."); else resource = new Resource(activeEntry.getClass(), resourceName); ParseContext includePC = resource.getFile() != null ? activeEntry.parseInclude(parseContext, resource.getFile()) : activeEntry.parseInclude(parseContext, resource); parseContext.getErrors().addAll(includePC.getErrors()); } else if (templateName != null && templateName.length() > 0) { log.trace("Including template '" + templateName + "'."); Template template = parseContext.getTemplateCatalog() .getTemplate(nodeIdentifiers.getGenericTemplateProducer(), templateName); if (template == null) throw new SAXParseException( "Generic template '" + templateName + "' was not found in the active document.", parseContext.getLocator()); template.applyChildren( template.createApplyContext(this, nodeIdentifiers.getIncludeElementName(), attrs)); } else { String fileName = attrs.getValue(NodeIdentifiers.ATTRNAME_INCLUDE_FILE); File includeFile = parseContext.resolveFile(fileName); log.trace("Including file '" + includeFile.getAbsolutePath() + "'."); ParseContext includePC = activeEntry.parseInclude(parseContext, includeFile); parseContext.getErrors().addAll(includePC.getErrors()); } } protected boolean handleDefaultText(String text) throws SAXException { if (!templateDefnStack.isEmpty()) { TemplateElement activeTemplate = (TemplateElement) templateDefnStack.peek(); activeTemplate.addChild(new TemplateText(activeTemplate, text)); return true; } else if (nodeStack.isEmpty() || !ignoreStack.isEmpty()) return true; else return false; } public void characters(char[] buf, int start, int end) throws SAXException { characters.append(buf, start, end); } public void consumeCharacters() throws SAXException { if (characters.length() > 0) { text(characters.toString()); characters = new StringBuffer(); } } protected boolean defaultHandleTemplateStartElement(String url, String localName, String qName, Attributes attributes) throws SAXException { String elementName = qName.toLowerCase(); if (!templateDefnStack.isEmpty()) { // we're inside a template already so just grab the contents TemplateElement activeTemplate = (TemplateElement) templateDefnStack.peek(); if (nodeIdentifiers.getTemplateParamDecl().equals(elementName)) { if (activeTemplate instanceof Template) { ((Template) activeTemplate).declareParameter(this, url, localName, qName, attributes); templateDefnStack.push(activeTemplate); } else throw new SAXParseException( "<" + nodeIdentifiers.getTemplateParamDecl() + "> not allowed here.", parseContext.getLocator()); } else { TemplateElement childNode = new TemplateElement(this, url, localName, qName, attributes); activeTemplate.addChild(childNode); templateDefnStack.push(childNode); } return true; } else if (elementName.equals(nodeIdentifiers.getTemplateElementName())) { String templateName = attributes.getValue(NodeIdentifiers.ATTRNAME_GENERIC_TEMPLATE_NAME); if (templateName == null || templateName.length() == 0) throw new SAXParseException("Template must have a '" + NodeIdentifiers.ATTRNAME_GENERIC_TEMPLATE_NAME + "' attribute in <" + elementName + "> ", parseContext.getLocator()); final Locator locator = getParseContext().getLocator(); InputSourceLocator inputSourceLocator = new InputSourceLocator(getParseContext().getInputSrcTracker(), locator.getLineNumber(), locator.getColumnNumber()); Template template = new Template(templateName, this, inputSourceLocator, parseContext.getTemplateCatalog(), nodeIdentifiers.getGenericTemplateProducer(), url, localName, qName, attributes); parseContext.getTemplateCatalog().registerTemplate(nodeIdentifiers.getGenericTemplateProducer(), templateName, template); templateDefnStack.push(template); return true; } else return false; } public String getStackDepthPrefix() { StringBuffer sb = new StringBuffer(); for (int i = 1; i < nodeStack.size(); i++) sb.append(" "); return sb.toString(); } public String getAttributeNames(Attributes attributes) { StringBuffer sb = new StringBuffer(" Attrs: ["); for (int i = 0; i < attributes.getLength(); i++) { sb.append(attributes.getQName(i)); sb.append("="); sb.append(attributes.getValue(i)); sb.append(" "); } sb.append(attributes); sb.append("]"); return sb.toString(); } public void executeDynamicTemplates() throws SAXException { // see if we have any dynamic templates that we now need to process List dynTemplates = getDynamicTemplatesProducer().getInstances(); if (dynTemplates.size() > 0) { TemplateApplyContext tac = new TemplateApplyContext(this); for (int i = 0; i < dynTemplates.size(); i++) { Template template = (Template) dynTemplates.get(i); template.applySelfAndChildren(tac); } } } public void endDocument() throws SAXException { nodeStack.clear(); ignoreStack.clear(); templateDefnStack.clear(); } public boolean handleDefaultStartElement(String url, String localName, String qName, Attributes attributes) throws SAXException { consumeCharacters(); // containers are simply holders of other elements and should not be processed if (qName.equals(nodeIdentifiers.getContainerElementName())) return true; return false; } public boolean handleDefaultEndElement(String url, String localName, String qName) throws SAXException { consumeCharacters(); // containers are simply holders of other elements and should not be processed if (qName.equals(nodeIdentifiers.getContainerElementName())) return true; if (inInclude) { inInclude = false; return true; } return false; } public void endPrefixMapping(String s) throws SAXException { } public void ignorableWhitespace(char[] chars, int i, int i1) throws SAXException { } public void processingInstruction(String target, String pi) throws SAXException { if (target.equals(parseContext.getTransformInstruction())) { if (parseContext.prepareTransformInstruction(pi)) throw new SAXException(new TransformProcessingInstructionEncounteredException()); } } public Locator getDocumentLocator() { return parseContext.getLocator(); } public void setDocumentLocator(Locator locator) { parseContext.setLocator(locator); } public void skippedEntity(String s) throws SAXException { } public void startDocument() throws SAXException { } public void startPrefixMapping(String s, String s1) throws SAXException { } }