You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by ju...@apache.org on 2008/05/22 13:54:49 UTC

svn commit: r659085 - /jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/xml/WorkspaceContentHandler.java

Author: jukka
Date: Thu May 22 04:54:49 2008
New Revision: 659085

URL: http://svn.apache.org/viewvc?rev=659085&view=rev
Log:
JCR-1350: Add a serializing content handler
    - Use SerializingContentHandler in jackrabbit-jcr2spi

Modified:
    jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/xml/WorkspaceContentHandler.java

Modified: jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/xml/WorkspaceContentHandler.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/xml/WorkspaceContentHandler.java?rev=659085&r1=659084&r2=659085&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/xml/WorkspaceContentHandler.java (original)
+++ jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/xml/WorkspaceContentHandler.java Thu May 22 04:54:49 2008
@@ -15,7 +15,16 @@
 */
 package org.apache.jackrabbit.jcr2spi.xml;
 
-import org.apache.jackrabbit.spi.Name;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Workspace;
+
+import org.apache.jackrabbit.commons.xml.SerializingContentHandler;
 import org.apache.jackrabbit.util.Text;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -23,27 +32,8 @@
 import org.xml.sax.ContentHandler;
 import org.xml.sax.Locator;
 import org.xml.sax.SAXException;
-import org.xml.sax.helpers.AttributesImpl;
 import org.xml.sax.helpers.DefaultHandler;
 
-import javax.jcr.RepositoryException;
-import javax.jcr.Workspace;
-import javax.xml.transform.TransformerConfigurationException;
-import javax.xml.transform.TransformerException;
-import javax.xml.transform.sax.SAXTransformerFactory;
-import javax.xml.transform.sax.TransformerHandler;
-import javax.xml.transform.stream.StreamResult;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.StringWriter;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
 /**
  * <code>WorkspaceContentHandler</code>...
  */
@@ -66,24 +56,12 @@
         try {
             String tmpName = Text.md5(parentAbsPath);
             this.tmpFile = File.createTempFile("___" + tmpName, ".xml");
-
-            SAXTransformerFactory stf = (SAXTransformerFactory) SAXTransformerFactory.newInstance();
-            TransformerHandler th = stf.newTransformerHandler();
-            th.setResult(new StreamResult(new FileOutputStream(tmpFile)));
-
-            if (NamespaceFixingContentHandler.isRequired(stf)) {
-                this.delegatee =  new NamespaceFixingContentHandler(th);
-            } else {
-                this.delegatee = th;
-            }
+            this.delegatee = SerializingContentHandler.getSerializer(
+                    new FileOutputStream(tmpFile));
         } catch (FileNotFoundException e) {
             throw new RepositoryException(e);
         } catch (IOException e) {
             throw new RepositoryException(e);
-        } catch (TransformerConfigurationException e) {
-            throw new RepositoryException(e);
-        } catch (TransformerException e) {
-            throw new RepositoryException(e);
         } catch (SAXException e) {
             throw new RepositoryException(e);
         }
@@ -141,292 +119,4 @@
     public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {
         delegatee.startElement(namespaceURI, localName, qName, atts);
     }
-
-    //--------------------------------------------------------< inner class >---
-    /**
-     * A ContentHandler implementation that ensures that all namespace prefixes
-     * are also present as 'xmlns:' attributes. This used to circumvent Xalan's
-     * serialization behaviour which ignores namespaces if they're not present
-     * as 'xmlns:xxx' attributes.
-     * The problem arises with SAX implementations such as the default present
-     * with JDK 1.4.2.
-     */
-    private static class NamespaceFixingContentHandler implements ContentHandler {
-
-        /** The wrapped content handler. */
-        private final ContentHandler contentHandler;
-
-        /**
-         * The prefixes of startPrefixMapping() declarations for the coming element.
-         */
-        private final List prefixList = new ArrayList();
-
-        /**
-         * The URIs of startPrefixMapping() declarations for the coming element.
-         */
-        private final List uriList = new ArrayList();
-
-        /**
-         * Maps of URI<->prefix mappings. Used to work around a bug in the Xalan
-         * serializer.
-         */
-        private final Map uriToPrefixMap = new HashMap();
-        private final Map prefixToUriMap = new HashMap();
-
-        /**
-         * True if there has been some startPrefixMapping() for the coming element.
-         */
-        private boolean hasMappings = false;
-
-        /**
-         * Create an instance of this ContentHandler implementation wrapping
-         * the given ContentHandler.
-         *
-         * @param ch ContentHandler to be wrapped.
-         */
-        private NamespaceFixingContentHandler(ContentHandler ch) {
-            this.contentHandler = ch;
-        }
-
-        /**
-         * Checks if the used TransformerHandler implementation correctly handles
-         * namespaces set using <code>startPrefixMapping()</code>, but wants them
-         * also as 'xmlns:' attributes.<p/>
-         * The check consists in sending SAX events representing a minimal namespaced document
-         * with namespaces defined only with calls to <code>startPrefixMapping</code> (no
-         * xmlns:xxx attributes) and check if they are present in the resulting text.
-         */
-        private  static boolean isRequired(SAXTransformerFactory factory)
-                throws TransformerException, SAXException {
-            // Serialize a minimal document to check how namespaces are handled.
-            StringWriter writer = new StringWriter();
-
-            String uri = "namespaceuri";
-            String prefix = "nsp";
-            String check = "xmlns:" + prefix + "='" + uri + "'";
-
-            TransformerHandler handler = factory.newTransformerHandler();
-            handler.setResult(new StreamResult(writer));
-
-            // Output a single element
-            handler.startDocument();
-            handler.startPrefixMapping(prefix, uri);
-            handler.startElement(uri, "element", "element", new AttributesImpl());
-            handler.endElement(uri, "element", "element");
-            handler.endPrefixMapping(prefix);
-            handler.endDocument();
-
-            String text = writer.toString();
-
-            // Check if the namespace is there (replace " by ' to be sure of what we search in)
-            return (text.replace('"', '\'').indexOf(check) == -1);
-        }
-
-        private void clearMappings() {
-            hasMappings = false;
-            prefixList.clear();
-            uriList.clear();
-        }
-
-        //-------------------------------------------------< ContentHandler >---
-        /**
-         * @see ContentHandler#startDocument()
-         */
-        public void startDocument() throws SAXException {
-            uriToPrefixMap.clear();
-            prefixToUriMap.clear();
-            clearMappings();
-            contentHandler.startDocument();
-        }
-
-        /**
-         * Track mappings to be able to add <code>xmlns:</code> attributes
-         * in <code>startElement()</code>.
-         *
-         * @see org.xml.sax.ContentHandler#startPrefixMapping(String, String)
-         */
-        public void startPrefixMapping(String prefix, String uri) throws SAXException {
-            // Store the mappings to reconstitute xmlns:attributes
-            // except prefixes starting with "xml": these are reserved
-            // VG: (uri != null) fixes NPE in startElement
-            if (uri != null && !prefix.startsWith("xml")) {
-                hasMappings = true;
-                prefixList.add(prefix);
-                uriList.add(uri);
-
-                // append the prefix colon now, in order to save concatenations
-                // later, but only for non-empty prefixes.
-                if (prefix.length() > 0) {
-                    uriToPrefixMap.put(uri, prefix + ":");
-                } else {
-                    uriToPrefixMap.put(uri, prefix);
-                }
-                prefixToUriMap.put(prefix, uri);
-            }
-            contentHandler.startPrefixMapping(prefix, uri);
-        }
-
-        /**
-         * Ensure all namespace declarations are present as <code>xmlns:</code> attributes
-         * and add those needed before calling superclass. This is a workaround for a Xalan bug
-         * (at least in version 2.0.1) : <code>org.apache.xalan.serialize.SerializerToXML</code>
-         * ignores <code>start/endPrefixMapping()</code>.
-         */
-        public void startElement(String eltUri, String eltLocalName, String eltQName, Attributes attrs)
-                throws SAXException {
-
-            // try to restore the qName. The map already contains the colon
-            if (null != eltUri && eltUri.length() != 0 && uriToPrefixMap.containsKey(eltUri)) {
-                eltQName = uriToPrefixMap.get(eltUri) + eltLocalName;
-            }
-            if (!hasMappings) {
-                // no mappings present -> simply delegate.
-                contentHandler.startElement(eltUri, eltLocalName, eltQName, attrs);
-            } else {
-                // add xmlns* attributes where needed
-                AttributesImpl newAttrs = null;
-                int attrCount = attrs.getLength();
-
-                // check if namespaces present in the uri/prefix list are present
-                // in the attributes and eventually add them to the attributes.
-                for (int mapping = 0; mapping < prefixList.size(); mapping++) {
-
-                    // Build infos for the namespace
-                    String uri = (String) uriList.get(mapping);
-                    String prefix = (String) prefixList.get(mapping);
-                    String qName = prefix.length() == 0 ? "xmlns" : ("xmlns:" + prefix);
-
-                    // Search for the corresponding xmlns* attribute
-                    boolean found = false;
-                    for (int attr = 0; attr < attrCount; attr++) {
-                        if (qName.equals(attrs.getQName(attr))) {
-                            // Check if mapping and attribute URI match
-                            if (!uri.equals(attrs.getValue(attr))) {
-                                throw new SAXException("URI in prefix mapping and attribute do not match");
-                            }
-                            found = true;
-                            break;
-                        }
-                    }
-
-                    if (!found) {
-                        // Need to add the namespace
-                        if (newAttrs == null) {
-                            // test if attrs passed into this call is empty in
-                            // order to avoid an infinite loop (known SAX bug)
-                            if (attrCount == 0) {
-                                newAttrs = new AttributesImpl();
-                            } else {
-                                newAttrs = new AttributesImpl(attrs);
-                            }
-                        }
-
-                        if (prefix.length() == 0) {
-                            newAttrs.addAttribute(Name.NS_XML_URI, "xmlns", "xmlns", "CDATA", uri);
-                        } else {
-                            newAttrs.addAttribute(Name.NS_XML_URI, prefix, qName, "CDATA", uri);
-                        }
-                    }
-                } // end for mapping
-
-                // cleanup mappings for the next element
-                clearMappings();
-
-                // delegate startElement call to the wrapped content handler
-                // with new attributes if adjustment for namespaces was made.
-                contentHandler.startElement(eltUri, eltLocalName, eltQName, newAttrs == null ? attrs : newAttrs);
-            }
-        }
-
-
-        /**
-         * Receive notification of the end of an element.
-         * Try to restore the element qName.
-         *
-         * @see org.xml.sax.ContentHandler#endElement(String, String, String)
-         */
-        public void endElement(String eltUri, String eltLocalName, String eltQName) throws SAXException {
-            // try to restore the qName. The map already contains the colon
-            if (null != eltUri && eltUri.length() != 0 && uriToPrefixMap.containsKey(eltUri)) {
-                eltQName = uriToPrefixMap.get(eltUri) + eltLocalName;
-            }
-            contentHandler.endElement(eltUri, eltLocalName, eltQName);
-        }
-
-        /**
-         * End the scope of a prefix-URI mapping:
-         * remove entry from mapping tables.
-         *
-         * @see org.xml.sax.ContentHandler#endPrefixMapping(String)
-         */
-        public void endPrefixMapping(String prefix) throws SAXException {
-            // remove mappings for xalan-bug-workaround.
-            // Unfortunately, we're not passed the uri, but the prefix here,
-            // so we need to maintain maps in both directions.
-            if (prefixToUriMap.containsKey(prefix)) {
-                uriToPrefixMap.remove(prefixToUriMap.get(prefix));
-                prefixToUriMap.remove(prefix);
-            }
-
-            if (hasMappings) {
-                // most of the time, start/endPrefixMapping calls have an element event between them,
-                // which will clear the hasMapping flag and so this code will only be executed in the
-                // rather rare occasion when there are start/endPrefixMapping calls with no element
-                // event in between. If we wouldn't remove the items from the prefixList and uriList here,
-                // the namespace would be incorrectly declared on the next element following the
-                // endPrefixMapping call.
-                int pos = prefixList.lastIndexOf(prefix);
-                if (pos != -1) {
-                    prefixList.remove(pos);
-                    uriList.remove(pos);
-                }
-            }
-            contentHandler.endPrefixMapping(prefix);
-        }
-
-        /**
-         * @see org.xml.sax.ContentHandler#endDocument()
-         */
-        public void endDocument() throws SAXException {
-            uriToPrefixMap.clear();
-            prefixToUriMap.clear();
-            clearMappings();
-            contentHandler.endDocument();
-        }
-
-        /**
-         * @see org.xml.sax.ContentHandler#characters(char[], int, int)
-         */
-        public void characters(char[] ch, int start, int length) throws SAXException {
-            contentHandler.characters(ch, start, length);
-        }
-
-        /**
-         * @see org.xml.sax.ContentHandler#ignorableWhitespace(char[], int, int)
-         */
-        public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {
-            contentHandler.ignorableWhitespace(ch, start, length);
-        }
-
-        /**
-         * @see org.xml.sax.ContentHandler#processingInstruction(java.lang.String, java.lang.String)
-         */
-        public void processingInstruction(String target, String data) throws SAXException {
-            contentHandler.processingInstruction(target, data);
-        }
-
-        /**
-         * @see org.xml.sax.ContentHandler#setDocumentLocator(org.xml.sax.Locator)
-         */
-        public void setDocumentLocator(Locator locator) {
-            contentHandler.setDocumentLocator(locator);
-        }
-
-        /**
-         * @see org.xml.sax.ContentHandler#skippedEntity(java.lang.String)
-         */
-        public void skippedEntity(String name) throws SAXException {
-            contentHandler.skippedEntity(name);
-        }
-    }
 }
\ No newline at end of file