Coverage Report - net.sourceforge.jeuclid.DOMBuilder
 
Classes in this File Line Coverage Branch Coverage Complexity
DOMBuilder
65%
38/58
64%
9/14
2,3
DOMBuilder$SingletonHolder
50%
2/4
N/A
2,3
 
 1  
 /*
 2  
  * Copyright 2002 - 2007 JEuclid, http://jeuclid.sf.net
 3  
  * 
 4  
  * Licensed under the Apache License, Version 2.0 (the "License");
 5  
  * you may not use this file except in compliance with the License.
 6  
  * You may obtain a copy of the License at
 7  
  *
 8  
  *      http://www.apache.org/licenses/LICENSE-2.0
 9  
  *
 10  
  * Unless required by applicable law or agreed to in writing, software
 11  
  * distributed under the License is distributed on an "AS IS" BASIS,
 12  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  
  * See the License for the specific language governing permissions and
 14  
  * limitations under the License.
 15  
  */
 16  
 
 17  
 /* $Id: DOMBuilder.java,v 2bab6eb875e8 2010/08/11 16:45:50 max $ */
 18  
 
 19  
 package net.sourceforge.jeuclid;
 20  
 
 21  
 import javax.annotation.concurrent.GuardedBy;
 22  
 import javax.annotation.concurrent.ThreadSafe;
 23  
 import javax.xml.transform.Transformer;
 24  
 import javax.xml.transform.TransformerException;
 25  
 import javax.xml.transform.TransformerFactory;
 26  
 import javax.xml.transform.dom.DOMResult;
 27  
 import javax.xml.transform.dom.DOMSource;
 28  
 import javax.xml.transform.stream.StreamSource;
 29  
 
 30  
 import net.sourceforge.jeuclid.elements.generic.DocumentElement;
 31  
 
 32  
 import org.apache.commons.logging.Log;
 33  
 import org.apache.commons.logging.LogFactory;
 34  
 import org.w3c.dom.DOMException;
 35  
 import org.w3c.dom.Document;
 36  
 import org.w3c.dom.DocumentFragment;
 37  
 import org.w3c.dom.Element;
 38  
 import org.w3c.dom.Node;
 39  
 
 40  
 /**
 41  
  * Builds a MathML tree from a given DOM tree.
 42  
  * 
 43  
  * @version $Revision: 2bab6eb875e8 $
 44  
  */
 45  209
 @ThreadSafe
 46  
 public final class DOMBuilder {
 47  
     /**
 48  
      * Logger for this class
 49  
      */
 50  209
     private static final Log LOGGER = LogFactory.getLog(DOMBuilder.class);
 51  
 
 52  11976
     private static final class SingletonHolder {
 53  209
         private static final DOMBuilder INSTANCE = new DOMBuilder();
 54  
 
 55  0
         private SingletonHolder() {
 56  0
         }
 57  
     }
 58  
 
 59  
     @GuardedBy("itself")
 60  
     private final Transformer contentTransformer;
 61  
 
 62  
     @GuardedBy("itself")
 63  
     private final Transformer identityTransformer;
 64  
 
 65  
     @GuardedBy("itself")
 66  
     private final Transformer namespaceTransformer;
 67  
 
 68  
     /**
 69  
      * Default constructor.
 70  
      */
 71  209
     protected DOMBuilder() {
 72  209
         this.identityTransformer = this.createIdentityTransformer();
 73  209
         this.contentTransformer = this.createTransformer(
 74  
                 "/net/sourceforge/jeuclid/content/mathmlc2p.xsl",
 75  
                 this.identityTransformer);
 76  209
         this.namespaceTransformer = this.createTransformer(
 77  
                 "/net/sourceforge/jeuclid/addMathMLNamespace.xsl",
 78  
                 this.identityTransformer);
 79  209
     }
 80  
 
 81  
     private Transformer createIdentityTransformer() {
 82  
         Transformer t;
 83  
         try {
 84  209
             t = TransformerFactory.newInstance().newTransformer();
 85  0
         } catch (final TransformerException e) {
 86  0
             DOMBuilder.LOGGER.warn(e.getMessage());
 87  0
             t = null;
 88  0
             assert false;
 89  209
         }
 90  209
         return t;
 91  
     }
 92  
 
 93  
     private Transformer createTransformer(final String sourceFile,
 94  
             final Transformer fallback) {
 95  
         Transformer t;
 96  
         try {
 97  418
             t = TransformerFactory.newInstance().newTemplates(
 98  
                     new StreamSource(DOMBuilder.class
 99  
                             .getResourceAsStream(sourceFile))).newTransformer();
 100  0
         } catch (final TransformerException e) {
 101  0
             DOMBuilder.LOGGER.warn(e.getMessage());
 102  0
             t = fallback;
 103  418
         }
 104  418
         return t;
 105  
     }
 106  
 
 107  
     /**
 108  
      * @return the singleton instance of the DOMBuilder
 109  
      */
 110  
     public static DOMBuilder getInstance() {
 111  11976
         return DOMBuilder.SingletonHolder.INSTANCE;
 112  
     }
 113  
 
 114  
     /**
 115  
      * use {@link #getInstance()} instead.
 116  
      * 
 117  
      * @return see {@link #getInstance()}
 118  
      * @deprecated use {@link #getInstance()} instead.
 119  
      */
 120  
     @Deprecated
 121  
     public static DOMBuilder getDOMBuilder() {
 122  0
         return DOMBuilder.getInstance();
 123  
     }
 124  
 
 125  
     /**
 126  
      * Constructs a builder with content math support.
 127  
      * 
 128  
      * @param node
 129  
      *            The MathML document. Can be an instance of Document, Element
 130  
      *            or DocumentFragment with Element child
 131  
      * @return the parsed Document
 132  
      * @see #createJeuclidDom(Node, boolean)
 133  
      */
 134  
     public DocumentElement createJeuclidDom(final Node node) {
 135  8162
         return this.createJeuclidDom(node, true);
 136  
     }
 137  
 
 138  
     /**
 139  
      * Constructs a builder.
 140  
      * <p>
 141  
      * This constructor needs a valid DOM Tree. To obtain a DOM tree, you may
 142  
      * use {@link MathMLParserSupport}.
 143  
      * 
 144  
      * @param node
 145  
      *            The MathML document. Can be an instance of Document, Element
 146  
      *            or DocumentFragment with Element child
 147  
      * @param supportContent
 148  
      *            if set to true, content Math will be supported. This impacts
 149  
      *            performance.
 150  
      * @return the parsed Document
 151  
      * @see MathMLParserSupport
 152  
      */
 153  
     public DocumentElement createJeuclidDom(final Node node,
 154  
             final boolean supportContent) {
 155  8162
         return this.createJeuclidDom(node, supportContent, false);
 156  
     }
 157  
 
 158  
     /**
 159  
      * Constructs a builder.
 160  
      * <p>
 161  
      * This constructor needs a valid DOM Tree. To obtain a DOM tree, you may
 162  
      * use {@link MathMLParserSupport}.
 163  
      * 
 164  
      * @param node
 165  
      *            The MathML document. Can be an instance of Document, Element
 166  
      *            or DocumentFragment with Element child
 167  
      * @param supportContent
 168  
      *            if set to true, content Math will be supported. This impacts
 169  
      *            performance.
 170  
      * @param addNamespace
 171  
      *            if set to true, the MathML namespace will be added to all
 172  
      *            elements.
 173  
      * @return the parsed Document
 174  
      * @see MathMLParserSupport
 175  
      */
 176  
     public DocumentElement createJeuclidDom(final Node node,
 177  
             final boolean supportContent, final boolean addNamespace) {
 178  
         Node documentElement;
 179  11976
         if (node instanceof Document) {
 180  11558
             documentElement = ((Document) node).getDocumentElement();
 181  418
         } else if (node instanceof Element) {
 182  0
             documentElement = node;
 183  418
         } else if (node instanceof DocumentFragment) {
 184  209
             final Node child = node.getFirstChild();
 185  209
             if (!(child instanceof Element)) {
 186  0
                 throw new IllegalArgumentException(
 187  
                         "Expected DocumentFragment with Element child");
 188  
             }
 189  209
             documentElement = child;
 190  209
         } else {
 191  209
             throw new IllegalArgumentException("Unsupported node: " + node
 192  
                     + ". Expected either Document, Element or DocumentFragment");
 193  
         }
 194  
 
 195  11767
         if (addNamespace) {
 196  3814
             documentElement = this.applyTransform(documentElement,
 197  
                     this.namespaceTransformer);
 198  
         }
 199  
 
 200  
         final DocumentElement d;
 201  11767
         if (supportContent) {
 202  11767
             d = this.applyTransform(documentElement, this.contentTransformer);
 203  
         } else {
 204  0
             d = this.applyTransform(documentElement, this.identityTransformer);
 205  
         }
 206  11767
         return d;
 207  
     }
 208  
 
 209  
     private DocumentElement applyTransform(final Node src,
 210  
             final Transformer transformer) {
 211  
         DocumentElement d;
 212  
         try {
 213  15581
             final DOMSource source = new DOMSource(src);
 214  15581
             d = new DocumentElement();
 215  15581
             final DOMResult result = new DOMResult(d);
 216  15581
             synchronized (transformer) {
 217  15581
                 transformer.transform(source, result);
 218  15581
             }
 219  0
         } catch (final TransformerException e) {
 220  0
             d = null;
 221  0
             DOMBuilder.LOGGER.warn(e.getMessage());
 222  0
         } catch (final NullPointerException e) {
 223  0
             d = null;
 224  
             // Happens if the stylesheet was not loaded correctly
 225  0
             DOMBuilder.LOGGER.warn(e.getMessage());
 226  0
         } catch (final DOMException e) {
 227  0
             d = null;
 228  0
             DOMBuilder.LOGGER.warn(e.getMessage());
 229  15581
         }
 230  15581
         return d;
 231  
     }
 232  
 
 233  
 }