jaxp/test/javax/xml/jaxp/functional/test/auctionportal/XInclHandler.java
changeset 28766 b2569bf771f1
parent 28763 4a400033227b
parent 28758 343c4ddd1520
child 28767 40a8ae3dab56
equal deleted inserted replaced
28763:4a400033227b 28766:b2569bf771f1
     1 /*
       
     2  * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.
       
     8  *
       
     9  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    12  * version 2 for more details (a copy is included in the LICENSE file that
       
    13  * accompanied this code).
       
    14  *
       
    15  * You should have received a copy of the GNU General Public License version
       
    16  * 2 along with this work; if not, write to the Free Software Foundation,
       
    17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    18  *
       
    19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    20  * or visit www.oracle.com if you need additional information or have any
       
    21  * questions.
       
    22  */
       
    23 package test.auctionportal;
       
    24 
       
    25 import java.io.OutputStream;
       
    26 import java.io.OutputStreamWriter;
       
    27 import java.io.PrintWriter;
       
    28 import java.io.UnsupportedEncodingException;
       
    29 import java.util.stream.Collectors;
       
    30 
       
    31 import org.xml.sax.Attributes;
       
    32 import org.xml.sax.SAXException;
       
    33 import org.xml.sax.SAXParseException;
       
    34 import org.xml.sax.ext.LexicalHandler;
       
    35 import org.xml.sax.helpers.DefaultHandler;
       
    36 
       
    37 /**
       
    38  * A SAX2 event handlers.
       
    39  * This SAX2 ContentHandler receives callback event then print whole document
       
    40  * that is parsed.
       
    41  */
       
    42 public class XInclHandler extends DefaultHandler implements LexicalHandler {
       
    43     /**
       
    44      * Print writer.
       
    45      */
       
    46     private final PrintWriter fOut;
       
    47 
       
    48     /**
       
    49      * Canonical output.
       
    50      */
       
    51     private volatile boolean fCanonical;
       
    52 
       
    53     /**
       
    54      * Element depth.
       
    55      */
       
    56     private volatile int fElementDepth;
       
    57 
       
    58     /**
       
    59      * Sets whether output is canonical.
       
    60      */
       
    61     public void setCanonical(boolean canonical) {
       
    62         fCanonical = canonical;
       
    63     }
       
    64 
       
    65     /**
       
    66      * Sets the output stream for printing.
       
    67      * @param stream OutputStream for message output.
       
    68      * @param encoding File encoding for message output.
       
    69      */
       
    70     public XInclHandler(OutputStream stream, String encoding)
       
    71             throws UnsupportedEncodingException {
       
    72         // At least set one encoding.
       
    73         if (encoding == null) {
       
    74             encoding = "UTF8";
       
    75         }
       
    76 
       
    77         fOut = new PrintWriter(new OutputStreamWriter(stream, encoding), false);
       
    78     }
       
    79 
       
    80     /**
       
    81      * Receive notification of the beginning of the document. Write the start
       
    82      * document tag if it's not canonical mode.
       
    83      * @exception org.xml.sax.SAXException Any SAX exception, possibly
       
    84      *            wrapping another exception.
       
    85      */
       
    86     @Override
       
    87     public void startDocument() throws SAXException {
       
    88         fElementDepth = 0;
       
    89 
       
    90         if (!fCanonical) {
       
    91             writeFlush("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
       
    92         }
       
    93     }
       
    94 
       
    95     /**
       
    96      * Receive notification of a processing instruction.
       
    97      * @param target The processing instruction target.
       
    98      * @param data The processing instruction data, or null if
       
    99      *             none is supplied.
       
   100      * @exception org.xml.sax.SAXException Any SAX exception, possibly
       
   101      *            wrapping another exception.
       
   102      */
       
   103     @Override
       
   104     public void processingInstruction (String target, String data)
       
   105         throws SAXException {
       
   106         if (fElementDepth > 0) {
       
   107             StringBuilder instruction = new StringBuilder("<?").append(target);
       
   108             if (data != null && data.length() > 0) {
       
   109                 instruction.append(' ').append(data);
       
   110             }
       
   111             instruction.append("?>");
       
   112             writeFlush(instruction.toString());
       
   113         }
       
   114     }
       
   115 
       
   116     /**
       
   117      * Receive notification of the start of an element then write the normalized
       
   118      * output to the file.
       
   119      * @param uri The Namespace URI, or the empty string if the
       
   120      *        element has no Namespace URI or if Namespace
       
   121      *        processing is not being performed.
       
   122      * @param localName The local name (without prefix), or the
       
   123      *        empty string if Namespace processing is not being
       
   124      *        performed.
       
   125      * @param qName The qualified name (with prefix), or the
       
   126      *        empty string if qualified names are not available.
       
   127      * @param attributes The attributes attached to the element.  If
       
   128      *        there are no attributes, it shall be an empty
       
   129      *        Attributes object.
       
   130      */
       
   131     @Override
       
   132     public void startElement(String uri, String local, String raw,
       
   133             Attributes attrs) throws SAXException {
       
   134         fElementDepth++;
       
   135         StringBuilder start = new StringBuilder().append('<').append(raw);
       
   136         if (attrs != null) {
       
   137             for (int i = 0; i < attrs.getLength(); i++) {
       
   138                 start.append(' ').append(attrs.getQName(i)).append("=\"").
       
   139                     append(normalizeAndPrint(attrs.getValue(i))).append('"');
       
   140             }
       
   141         }
       
   142         start.append('>');
       
   143         writeFlush(start.toString());
       
   144     }
       
   145 
       
   146     /**
       
   147      * Receive notification of character data inside an element and write
       
   148      * normalized characters to file.
       
   149      * @param ch The characters.
       
   150      * @param start The start position in the character array.
       
   151      * @param length The number of characters to use from the
       
   152      *               character array.
       
   153      * @exception org.xml.sax.SAXException Any SAX exception, possibly
       
   154      *            wrapping another exception.
       
   155      */
       
   156     @Override
       
   157     public void characters(char ch[], int start, int length)
       
   158             throws SAXException {
       
   159         writeFlush(normalizeAndPrint(ch, start, length));
       
   160     }
       
   161 
       
   162     /**
       
   163      * Receiving notification of ignorable whitespace in element content and
       
   164      * writing normalized ignorable characters to file.
       
   165      * @param ch The characters.
       
   166      * @param start The start position in the character array.
       
   167      * @param length The number of characters to use from the
       
   168      *               character array.
       
   169      * @exception org.xml.sax.SAXException Any SAX exception, possibly
       
   170      *            wrapping another exception.
       
   171      */
       
   172     @Override
       
   173     public void ignorableWhitespace(char ch[], int start, int length)
       
   174             throws SAXException {
       
   175         characters(ch, start, length);
       
   176     }
       
   177 
       
   178     /**
       
   179      * Receive notification of the end of an element and print end element.
       
   180      *
       
   181      * @param uri The Namespace URI, or the empty string if the
       
   182      *        element has no Namespace URI or if Namespace
       
   183      *        processing is not being performed.
       
   184      * @param localName The local name (without prefix), or the
       
   185      *        empty string if Namespace processing is not being
       
   186      *        performed.
       
   187      * @param qName The qualified name (with prefix), or the
       
   188      *        empty string if qualified names are not available.
       
   189      */
       
   190     @Override
       
   191     public void endElement(String uri, String local, String raw)
       
   192             throws SAXException {
       
   193         fElementDepth--;
       
   194         writeFlush("</" + raw + ">");
       
   195     }
       
   196 
       
   197     /**
       
   198      * Receive notification of a parser warning and print it out.
       
   199      * @param e The warning information encoded as an exception.
       
   200      * @exception org.xml.sax.SAXException Any SAX exception, possibly
       
   201      *            wrapping another exception.
       
   202      */
       
   203     @Override
       
   204     public void warning(SAXParseException ex) throws SAXException {
       
   205         printError("Warning", ex);
       
   206     }
       
   207 
       
   208     /**
       
   209      * Receive notification of a parser error and print it out.
       
   210      * @param e The error information encoded as an exception.
       
   211      * @exception org.xml.sax.SAXException Any SAX exception, possibly
       
   212      *            wrapping another exception.
       
   213 
       
   214      */
       
   215     @Override
       
   216     public void error(SAXParseException ex) throws SAXException {
       
   217         printError("Error", ex);
       
   218     }
       
   219 
       
   220     /**
       
   221      * Receive notification of a parser fatal error. Throw out fatal error
       
   222      * following print fatal error message.
       
   223      * @param e The fatal error information encoded as an exception.
       
   224      * @exception org.xml.sax.SAXException Any SAX exception, possibly
       
   225      *            wrapping another exception.
       
   226 
       
   227      */
       
   228     @Override
       
   229     public void fatalError(SAXParseException ex) throws SAXException {
       
   230         printError("Fatal Error", ex);
       
   231         throw ex;
       
   232     }
       
   233 
       
   234     /**
       
   235      * Do nothing on start DTD.
       
   236      * @param name The document type name.
       
   237      * @param publicId The declared public identifier for the
       
   238      *        external DTD subset, or null if none was declared.
       
   239      * @param systemId The declared system identifier for the
       
   240      *        external DTD subset, or null if none was declared.
       
   241      *        (Note that this is not resolved against the document
       
   242      *        base URI.)
       
   243      * @exception SAXException The application may raise an
       
   244      *            exception.
       
   245      */
       
   246     @Override
       
   247     public void startDTD(String name, String publicId, String systemId)
       
   248         throws SAXException {
       
   249     }
       
   250 
       
   251     /**
       
   252      * Do nothing on end DTD.
       
   253      * @exception SAXException The application may raise an exception.
       
   254      */
       
   255     @Override
       
   256     public void endDTD() throws SAXException {
       
   257     }
       
   258 
       
   259     /**
       
   260      * Do nothing on start entity.
       
   261      * @param name The name of the entity.  If it is a parameter
       
   262      *        entity, the name will begin with '%', and if it is the
       
   263      *        external DTD subset, it will be "[dtd]".
       
   264      * @exception SAXException The application may raise an exception.
       
   265      */
       
   266     @Override
       
   267     public void startEntity(String name) throws SAXException {
       
   268     }
       
   269 
       
   270     /**
       
   271      * Do nothing on end entity.
       
   272      * @param name The name of the entity.  If it is a parameter
       
   273      *        entity, the name will begin with '%', and if it is the
       
   274      *        external DTD subset, it will be "[dtd]".
       
   275      * @exception SAXException The application may raise an exception.
       
   276      */
       
   277     @Override
       
   278     public void endEntity(String name) throws SAXException {
       
   279     }
       
   280 
       
   281     /**
       
   282      * Do nothing on start CDATA section.
       
   283      * @exception SAXException The application may raise an exception.
       
   284      */
       
   285     @Override
       
   286     public void startCDATA() throws SAXException {
       
   287     }
       
   288 
       
   289     /**
       
   290      * Do nothing on end CDATA section.
       
   291      * @exception SAXException The application may raise an exception.
       
   292      */
       
   293     @Override
       
   294     public void endCDATA() throws SAXException {
       
   295     }
       
   296 
       
   297     /**
       
   298      * Report an normalized XML comment when receive a comment in the document.
       
   299      *
       
   300      * @param ch An array holding the characters in the comment.
       
   301      * @param start The starting position in the array.
       
   302      * @param length The number of characters to use from the array.
       
   303      * @exception SAXException The application may raise an exception.
       
   304      */
       
   305     @Override
       
   306     public void comment(char ch[], int start, int length) throws SAXException {
       
   307         if (!fCanonical && fElementDepth > 0) {
       
   308             writeFlush("<!--" + normalizeAndPrint(ch, start, length) + "-->");
       
   309         }
       
   310     }
       
   311 
       
   312     /**
       
   313      * Normalizes and prints the given string.
       
   314      * @param s String to be normalized
       
   315      */
       
   316     private String normalizeAndPrint(String s) {
       
   317         return s.chars().mapToObj(c -> normalizeAndPrint((char)c)).
       
   318                 collect(Collectors.joining());
       
   319     }
       
   320 
       
   321     /**
       
   322      * Normalizes and prints the given array of characters.
       
   323      * @param ch The characters to be normalized.
       
   324      * @param start The start position in the character array.
       
   325      * @param length The number of characters to use from the
       
   326      *               character array.
       
   327      */
       
   328     private String normalizeAndPrint(char[] ch, int offset, int length) {
       
   329         return normalizeAndPrint(new String(ch, offset, length));
       
   330     }
       
   331 
       
   332     /**
       
   333      * Normalizes given character.
       
   334      * @param c char to be normalized.
       
   335      */
       
   336     private String normalizeAndPrint(char c) {
       
   337         switch (c) {
       
   338             case '<':
       
   339                 return "&lt;";
       
   340             case '>':
       
   341                 return "&gt;";
       
   342             case '&':
       
   343                 return "&amp;";
       
   344             case '"':
       
   345                 return "&quot;";
       
   346             case '\r':
       
   347             case '\n':
       
   348                 return fCanonical ? "&#" + Integer.toString(c) + ";" : String.valueOf(c);
       
   349             default:
       
   350                 return String.valueOf(c);
       
   351         }
       
   352     }
       
   353 
       
   354     /**
       
   355      * Prints the error message.
       
   356      * @param type error type
       
   357      * @param ex exception that need to be printed
       
   358      */
       
   359     private void printError(String type, SAXParseException ex) {
       
   360         System.err.print("[" + type + "] ");
       
   361         String systemId = ex.getSystemId();
       
   362         if (systemId != null) {
       
   363             int index = systemId.lastIndexOf('/');
       
   364             if (index != -1)
       
   365                 systemId = systemId.substring(index + 1);
       
   366             System.err.print(systemId);
       
   367         }
       
   368         System.err.print(':' + ex.getLineNumber());
       
   369         System.err.print(':' + ex.getColumnNumber());
       
   370         System.err.println(": " + ex.getMessage());
       
   371         System.err.flush();
       
   372     }
       
   373 
       
   374     /**
       
   375      * Write out and flush.
       
   376      * @param out string to be written.
       
   377      */
       
   378     private void writeFlush(String out) {
       
   379         fOut.print(out);
       
   380         fOut.flush();
       
   381     }
       
   382 }