abstractsaxeventgenerator.java

来自「jsr170接口的java实现。是个apache的开源项目。」· Java 代码 · 共 450 行

JAVA
450
字号
/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements.  See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License.  You may obtain a copy of the License at * *      http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package org.apache.jackrabbit.core.xml;import java.util.HashMap;import java.util.Map;import org.apache.jackrabbit.name.NameException;import org.apache.jackrabbit.name.QName;import org.apache.jackrabbit.name.SessionNamespaceResolver;import org.apache.jackrabbit.name.NamespaceResolver;import org.apache.jackrabbit.name.NameFormat;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.xml.sax.ContentHandler;import org.xml.sax.SAXException;import org.xml.sax.helpers.AttributesImpl;import javax.jcr.Node;import javax.jcr.NodeIterator;import javax.jcr.Property;import javax.jcr.PropertyIterator;import javax.jcr.RepositoryException;import javax.jcr.Session;/** * <code>AbstractSAXEventGenerator</code> serves as the base class for * <code>SysViewSAXEventGenerator</code> and <code>DocViewSAXEventGenerator</code> * <p/> * It traverses a tree of <code>Node</code> & <code>Property</code> * instances, and calls the abstract methods * <ul> * <li><code>{@link #entering(Node, int)}</code></li> * <li><code>{@link #enteringProperties(Node, int)}</code></li> * <li><code>{@link #leavingProperties(Node, int)}</code></li> * <li><code>{@link #leaving(Node, int)}</code></li> * <li><code>{@link #entering(Property, int)}</code></li> * <li><code>{@link #leaving(Property, int)}</code></li> * </ul> * for every item it encounters. */abstract class AbstractSAXEventGenerator {    private static Logger log = LoggerFactory.getLogger(AbstractSAXEventGenerator.class);    /**     * the session to be used for resolving namespace mappings     */    protected final Session session;    /**     * the session's namespace resolver     */    protected final NamespaceResolver nsResolver;    /**     * the content handler to feed the SAX events to     */    protected final ContentHandler contentHandler;    protected final Node startNode;    protected final boolean skipBinary;    protected final boolean noRecurse;    /**     * the set of namespace declarations that have already been serialized     */    protected NamespaceStack namespaces;    /**     * The jcr:primaryType property name (allowed for session-local prefix mappings)     */    protected final String jcrPrimaryType;    /**     * The jcr:mixinTypes property name (allowed for session-local prefix mappings)     */    protected final String jcrMixinTypes;    /**     * The jcr:uuid property name (allowed for session-local prefix mappings)     */    protected final String jcrUUID;    /**     * The jcr:root node name (allowed for session-local prefix mappings)     */    protected final String jcrRoot;    /**     * The jcr:xmltext node name (allowed for session-local prefix mappings)     */    protected final String jcrXMLText;    /**     * The jcr:xmlCharacters property name (allowed for session-local prefix mappings)     */    protected final String jcrXMLCharacters;    /**     * Constructor     *     * @param node           the node state which should be serialized     * @param noRecurse      if true, only <code>node</code> and its properties will     *                       be serialized; otherwise the entire hierarchy starting with     *                       <code>node</code> will be serialized.     * @param skipBinary     flag governing whether binary properties are to be serialized.     * @param contentHandler the content handler to feed the SAX events to     * @throws RepositoryException if an error occurs     */    protected AbstractSAXEventGenerator(Node node, boolean noRecurse,                                        boolean skipBinary,                                        ContentHandler contentHandler)            throws RepositoryException {        startNode = node;        session = node.getSession();        nsResolver = new SessionNamespaceResolver(session);        this.contentHandler = contentHandler;        this.skipBinary = skipBinary;        this.noRecurse = noRecurse;        // start with an empty set of known prefixes        this.namespaces = new NamespaceStack(null);        // resolve the names of some wellknown properties        // allowing for session-local prefix mappings        try {            jcrPrimaryType = NameFormat.format(QName.JCR_PRIMARYTYPE, nsResolver);            jcrMixinTypes = NameFormat.format(QName.JCR_MIXINTYPES, nsResolver);            jcrUUID = NameFormat.format(QName.JCR_UUID, nsResolver);            jcrRoot = NameFormat.format(QName.JCR_ROOT, nsResolver);            jcrXMLText = NameFormat.format(QName.JCR_XMLTEXT, nsResolver);            jcrXMLCharacters = NameFormat.format(QName.JCR_XMLCHARACTERS, nsResolver);        } catch (NameException e) {            // should never get here...            String msg = "internal error: failed to resolve namespace mappings";            log.error(msg, e);            throw new RepositoryException(msg, e);        }    }    /**     * Serializes the hierarchy of nodes and properties.     *     * @throws RepositoryException if an error occurs while traversing the hierarchy     * @throws SAXException        if an error occured while feeding the events     *                             to the content handler     */    public void serialize() throws RepositoryException, SAXException {        // start document and declare namespaces        contentHandler.startDocument();        startNamespaceDeclarations();        // serialize node and subtree        process(startNode, 0);        // clear namespace declarations and end document        endNamespaceDeclarations();        contentHandler.endDocument();    }    /**     * @throws RepositoryException     * @throws SAXException     */    protected void startNamespaceDeclarations()            throws RepositoryException, SAXException {        // start namespace declarations        String[] prefixes = session.getNamespacePrefixes();        for (int i = 0; i < prefixes.length; i++) {            String prefix = prefixes[i];            if (QName.NS_XML_PREFIX.equals(prefix)) {                // skip 'xml' prefix as this would be an illegal namespace declaration                continue;            }            String uri = session.getNamespaceURI(prefix);            contentHandler.startPrefixMapping(prefix, uri);        }    }    /**     * @throws RepositoryException     * @throws SAXException     */    protected void endNamespaceDeclarations()            throws RepositoryException, SAXException {        // end namespace declarations        String[] prefixes = session.getNamespacePrefixes();        for (int i = 0; i < prefixes.length; i++) {            String prefix = prefixes[i];            if (QName.NS_XML_PREFIX.equals(prefix)) {                // skip 'xml' prefix as this would be an illegal namespace declaration                continue;            }            contentHandler.endPrefixMapping(prefix);        }    }    /**     * Adds explicit <code>xmlns:prefix="uri"</code> attributes to the     * XML element as required (e.g., normally just on the root     * element). The effect is the same as setting the     * "<code>http://xml.org/sax/features/namespace-prefixes</code>"     * property on an SAX parser.     *     * @param level level of the current XML element     * @param attributes attributes of the current XML element     * @throws RepositoryException on a repository error     */    protected void addNamespacePrefixes(int level, AttributesImpl attributes)            throws RepositoryException {        String[] prefixes = session.getNamespacePrefixes();        NamespaceStack newNamespaces = null;        for (int i = 0; i < prefixes.length; i++) {            String prefix = prefixes[i];            if (prefix.length() > 0                    && !QName.NS_XML_PREFIX.equals(prefix)) {                String uri = session.getNamespaceURI(prefix);                // get the matching namespace from previous declarations                String mappedToNs = this.namespaces.getNamespaceURI(prefix);                if (!uri.equals(mappedToNs)) {                    // when not the same, add a declaration                    attributes.addAttribute(                        QName.NS_XMLNS_URI,                        prefix,                        QName.NS_XMLNS_PREFIX + ":" + prefix,                        "CDATA",                        uri);                    if (newNamespaces == null) {                        // replace current namespace stack when needed                        newNamespaces = new NamespaceStack(this.namespaces);                        this.namespaces = newNamespaces;                    }                    // remember the new declaration                    newNamespaces.setNamespacePrefix(prefix, uri);                }            }        }    }    /**     * @param node     * @param level     * @throws RepositoryException     * @throws SAXException     */    protected void process(Node node, int level)            throws RepositoryException, SAXException {        // enter node        entering(node, level);        // enter properties        enteringProperties(node, level);        // serialize jcr:primaryType, jcr:mixinTypes & jcr:uuid first:        // jcr:primaryType        if (node.hasProperty(jcrPrimaryType)) {            process(node.getProperty(jcrPrimaryType), level + 1);        } else {            String msg = "internal error: missing jcr:primaryType property on node "                    + node.getPath();            log.debug(msg);            throw new RepositoryException(msg);        }        // jcr:mixinTypes        if (node.hasProperty(jcrMixinTypes)) {            process(node.getProperty(jcrMixinTypes), level + 1);        }        // jcr:uuid        if (node.hasProperty(jcrUUID)) {            process(node.getProperty(jcrUUID), level + 1);        }        // serialize remaining properties        PropertyIterator propIter = node.getProperties();        while (propIter.hasNext()) {            Property prop = propIter.nextProperty();            String name = prop.getName();            if (jcrPrimaryType.equals(name)                    || jcrMixinTypes.equals(name)                    || jcrUUID.equals(name)) {                continue;            }            // serialize property            process(prop, level + 1);        }        // leaving properties        leavingProperties(node, level);        if (!noRecurse) {            // child nodes            NodeIterator nodeIter = node.getNodes();            while (nodeIter.hasNext()) {                // recurse                Node childNode = nodeIter.nextNode();                // remember the current namespace declarations                NamespaceStack previousNamespaces = this.namespaces;                process(childNode, level + 1);                // restore the effective namespace declarations                // (from before visiting the child node)                this.namespaces = previousNamespaces;            }        }        // leaving node        leaving(node, level);    }    /**     * @param prop     * @param level     * @throws RepositoryException     * @throws SAXException     */    protected void process(Property prop, int level)            throws RepositoryException, SAXException {        // serialize property        entering(prop, level);        leaving(prop, level);    }    /**     * @param node     * @param level     * @throws RepositoryException     * @throws SAXException     */    protected abstract void entering(Node node, int level)            throws RepositoryException, SAXException;    /**     * @param node     * @param level     * @throws RepositoryException     * @throws SAXException     */    protected abstract void enteringProperties(Node node, int level)            throws RepositoryException, SAXException;    /**     * @param node     * @param level     * @throws RepositoryException     * @throws SAXException     */    protected abstract void leavingProperties(Node node, int level)            throws RepositoryException, SAXException;    /**     * @param node     * @param level     * @throws RepositoryException     * @throws SAXException     */    protected abstract void leaving(Node node, int level)            throws RepositoryException, SAXException;    /**     * @param prop     * @param level     * @throws RepositoryException     * @throws SAXException     */    protected abstract void entering(Property prop, int level)            throws RepositoryException, SAXException;    /**     * @param prop     * @param level     * @throws RepositoryException     * @throws SAXException     */    protected abstract void leaving(Property prop, int level)            throws RepositoryException, SAXException;    /**     * Implements a simple stack of namespace declarations.     */    private static class NamespaceStack {        /**         * Parent stack (may be <code>null</code>)         */        private final NamespaceStack parent;        /**         * Local namespace declarations.         */        private final Map namespaces;        /**         * Instantiate a new stack         *         * @param parent parent stack (may be <code>null</code> for the initial stack)         */        public NamespaceStack(NamespaceStack parent) {            this.parent = parent;            this.namespaces = new HashMap();        }        /**         * Obtain namespace URI for a prefix         *         * @param prefix prefix         * @return namespace URI (or <code>null</code> when unknown)         */        public String getNamespaceURI(String prefix) {            String namespace = (String) namespaces.get(prefix);            if (namespace != null) {                // found in this element, return right away                return namespace;            } else if (parent != null) {                // ask parent, when present                return parent.getNamespaceURI(prefix);            } else {                return null;            }        }        /**         * Add a new prefix mapping         *         * @param prefix namespace prefix         * @param uri namespace URI         */        public void setNamespacePrefix(String prefix, String uri) {            namespaces.put(prefix, uri);        }    }}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?