001: /* ====================================================================
002: * The Jcorporate Apache Style Software License, Version 1.2 05-07-2002
003: *
004: * Copyright (c) 1995-2002 Jcorporate Ltd. All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions
008: * are met:
009: *
010: * 1. Redistributions of source code must retain the above copyright
011: * notice, this list of conditions and the following disclaimer.
012: *
013: * 2. Redistributions in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in
015: * the documentation and/or other materials provided with the
016: * distribution.
017: *
018: * 3. The end-user documentation included with the redistribution,
019: * if any, must include the following acknowledgment:
020: * "This product includes software developed by Jcorporate Ltd.
021: * (http://www.jcorporate.com/)."
022: * Alternately, this acknowledgment may appear in the software itself,
023: * if and wherever such third-party acknowledgments normally appear.
024: *
025: * 4. "Jcorporate" and product names such as "Expresso" must
026: * not be used to endorse or promote products derived from this
027: * software without prior written permission. For written permission,
028: * please contact info@jcorporate.com.
029: *
030: * 5. Products derived from this software may not be called "Expresso",
031: * or other Jcorporate product names; nor may "Expresso" or other
032: * Jcorporate product names appear in their name, without prior
033: * written permission of Jcorporate Ltd.
034: *
035: * 6. No product derived from this software may compete in the same
036: * market space, i.e. framework, without prior written permission
037: * of Jcorporate Ltd. For written permission, please contact
038: * partners@jcorporate.com.
039: *
040: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
041: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
042: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
043: * DISCLAIMED. IN NO EVENT SHALL JCORPORATE LTD OR ITS CONTRIBUTORS
044: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
045: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
046: * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
047: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
048: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
049: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
050: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
051: * SUCH DAMAGE.
052: * ====================================================================
053: *
054: * This software consists of voluntary contributions made by many
055: * individuals on behalf of the Jcorporate Ltd. Contributions back
056: * to the project(s) are encouraged when you make modifications.
057: * Please send them to support@jcorporate.com. For more information
058: * on Jcorporate Ltd. and its products, please see
059: * <http://www.jcorporate.com/>.
060: *
061: * Portions of this software are based upon other open source
062: * products and are subject to their respective licenses.
063: */
064:
065: package com.jcorporate.expresso.ext.report;
066:
067: import com.jcorporate.expresso.core.misc.StringUtil;
068: import com.jcorporate.expresso.kernel.exception.ExpressoRuntimeException;
069: import com.jcorporate.expresso.kernel.management.DOMWriter;
070: import com.jcorporate.expresso.kernel.util.FastStringBuffer;
071: import org.apache.log4j.Logger;
072: import org.w3c.dom.Attr;
073: import org.w3c.dom.Document;
074: import org.w3c.dom.DocumentType;
075: import org.w3c.dom.Entity;
076: import org.w3c.dom.NamedNodeMap;
077: import org.w3c.dom.Node;
078: import org.w3c.dom.NodeList;
079: import org.xml.sax.ErrorHandler;
080: import org.xml.sax.InputSource;
081: import org.xml.sax.SAXException;
082: import org.xml.sax.SAXParseException;
083:
084: import javax.xml.parsers.DocumentBuilder;
085: import javax.xml.parsers.DocumentBuilderFactory;
086: import java.io.BufferedWriter;
087: import java.io.File;
088: import java.io.FileWriter;
089: import java.io.IOException;
090: import java.io.OutputStream;
091: import java.io.OutputStreamWriter;
092: import java.io.StringWriter;
093: import java.io.Writer;
094: import java.util.StringTokenizer;
095:
096: /**
097: * XMLPrinter is a simple (DOM) parser that outputs XML to a Writer stream.
098: *
099: * @author David Lloyd
100: */
101:
102: public class XMLPrinter implements ErrorHandler, DOMWriter {
103:
104: protected static Logger log;
105: public static final OutputStreamWriter SYSTEM_OUT = new OutputStreamWriter(
106: System.out);
107: public static final String DEFAULT_INDENT = " "; //3-spaces
108:
109: /**
110: * The writer that will contain the XML written.
111: */
112: protected Writer _out = null;
113:
114: /**
115: * The indention prefix string.
116: */
117: protected String _indent = DEFAULT_INDENT;
118:
119: /**
120: * The character to use for indenting.
121: */
122: protected char _indentChar = ' ';
123:
124: /**
125: * The virtual area occupied by an indention.
126: */
127: protected int _indentLength = 0;
128:
129: /**
130: * The current indention level.
131: */
132: protected int _column = 0;
133:
134: /**
135: * Set to keep the <?xml ... header from printing.
136: */
137: protected boolean _omitXmlDecl = false;
138:
139: /**
140: * The character sequence for a newline.
141: */
142: protected String _newline = System.getProperty("line.separator");
143:
144: public XMLPrinter() {
145: log = Logger.getLogger(XMLPrinter.class);
146: setWriter(SYSTEM_OUT);
147: }
148:
149: /**
150: * Override to actually save a DOM document to the output stream via whatever
151: * method you desire
152: *
153: * @param os The output stream to save to
154: * @param document the DOM document representing the config.
155: * @throws ExpressoRuntimeException if there's an error saving the file.
156: */
157: public void saveDocument(OutputStream os, Document document)
158: throws ExpressoRuntimeException {
159: try {
160: setWriter(new OutputStreamWriter(os));
161: outputDocument(document.getDocumentElement());
162: getWriter().flush();
163: } catch (IOException ioe) {
164: throw new ExpressoRuntimeException(ioe);
165: }
166: }
167:
168: /**
169: * Retrieve a class that must exist in the classpath for this to work.
170: * Used as a sanity check to make sure the appropriate jars are installed.
171: *
172: * @return java.lang.String a name of a class
173: */
174: public String getRequiredClass() {
175: return "org.w3c.dom.Document";
176: }
177:
178: /**
179: * Output the document whose root element is the specified node.
180: */
181: public void outputDocument(Node node) throws IOException {
182: if (!_omitXmlDecl && node.getNodeType() == Node.ELEMENT_NODE) {
183: println("<?xml version='1.0' ?>");
184: println("");
185: }
186: printTree(node);
187: }
188:
189: /**
190: * Set the output writer.
191: */
192: public void setWriter(Writer out) {
193: this ._out = out;
194: }
195:
196: /**
197: * Get the output writer.
198: */
199: public Writer getWriter() {
200: return this ._out;
201: }
202:
203: /**
204: * Set the indentation size to the number of characters specified using the
205: * current indent character.
206: */
207: public void setIndentSize(int indentSize) {
208: _indent = "";
209: _indentLength = 0;
210:
211: int inc;
212: if (_indentChar == '\t') {
213: inc = 4;
214: } else {
215: inc = 1;
216: }
217:
218: for (int i = 0; i < indentSize; i++) {
219: _indent += _indentChar;
220: _indentLength += inc;
221: }
222: }
223:
224: /**
225: * Set the indent semantics.
226: *
227: * @param indentChar The character to use for indentions.
228: * @param size The number of characters to use for each indention level.
229: */
230: public void setIndent(char indentChar, int size) {
231: _indentChar = indentChar;
232: setIndentSize(size);
233: }
234:
235: /**
236: * Set whether the xml declaration should be output at the start of a document.
237: */
238: public void setOmitXmlDecl(boolean b) {
239: _omitXmlDecl = b;
240: }
241:
242: /**
243: * Closes the output writer ignoring any errors recieved. You are encouraged
244: * to close the writer yourself to recieve any errors encountered.
245: */
246: public void closeWriter() {
247: try {
248: this ._out.close();
249: } catch (IOException ioe) {
250: //oe.printStackTrace();
251: }
252: }
253:
254: /**
255: * Creates an output writer that will create the file specified and any
256: * parent directories needed to do so.
257: */
258: public void setFile(File file) throws IOException {
259: File parentDirectory = file.getParentFile();
260:
261: if (parentDirectory != null && !parentDirectory.exists()) {
262: parentDirectory.mkdirs();
263: }
264:
265: setWriter(new BufferedWriter(new FileWriter(file)));
266: }
267:
268: /**
269: * Creates an output writer that will create the file specified and any
270: * parent directories needed to do so.
271: */
272: public void setFile(String filename) throws IOException {
273: setFile(new File(filename));
274: }
275:
276: /**
277: * Return the given node as a string. If any error occurs
278: * in processing (likely an io exception from outputDocument()),
279: * null will be returned.
280: */
281: public static String nodeToString(Node node) {
282: try {
283: XMLPrinter printer = new XMLPrinter();
284:
285: StringWriter writer = new StringWriter();
286:
287: printer.setWriter(writer);
288:
289: printer.outputDocument(node);
290:
291: return writer.getBuffer().toString();
292:
293: } catch (IOException e) {
294: return null;
295: }
296: }
297:
298: /**
299: * Parse an string and convert it to xml style
300: *
301: * @param html The string to be parsed
302: * @return The resulting xml string
303: */
304: public static String toXML(String html) {
305: return toXML(html, true);
306: }
307:
308: /**
309: * Parse an string and convert it to xml style
310: *
311: * @param html The string to be parsed
312: * @param escapeAll If false, the semicolon, apostrophe, and quote are left alone (useful for text nodes).
313: * @return The resulting xml string
314: */
315: public static String toXML(String html, boolean escapeAll) {
316: if (html == null) {
317: return "";
318: }
319:
320: FastStringBuffer parsedString = new FastStringBuffer(html
321: .length());
322:
323: String delim;
324: delim = "&;><'\"";
325:
326: StringTokenizer st;
327: st = new StringTokenizer(html, delim, true);
328:
329: String token;
330:
331: while (st.hasMoreTokens()) {
332: token = st.nextToken();
333:
334: // recognizes and replaces html tokens with xml style tokens
335: if (token.equals("&")) {
336: token = "&";
337: } else if (token.equals(">")) {
338: token = ">";
339: } else if (token.equals("<")) {
340: token = "<";
341: } else if (escapeAll) {
342: if (token.equals(";")) {
343: token = ";";
344: } else if (token.equals("'")) {
345: token = "'";
346: } else if (token.equals("\"")) {
347: token = """;
348: }
349: }
350: parsedString.append(token);
351: }
352: return parsedString.toString();
353: }
354:
355: /**
356: * Prints the string to the output at an indentation.
357: *
358: * @param string The string to print.
359: * @param indent The indentation to prefix the string.
360: */
361: public void print(String string, String indent) throws IOException {
362: print(indent);
363: if (string != null) {
364: print(string.trim());
365: }
366: }
367:
368: /**
369: * Prints the string to the output at an indentation following it with a newline.
370: *
371: * @param string The string to print.
372: * @param indent The indentation to prefix the string.
373: */
374: public void println(String string, String indent)
375: throws IOException {
376: print(indent);
377: if (string != null) {
378: println(string.trim());
379: } else {
380: println("");
381: }
382: }
383:
384: /**
385: * Prints the string to the output.
386: *
387: * @param string The string to print.
388: */
389: public void print(String string) throws IOException {
390: this ._out.write(string);
391: }
392:
393: /**
394: * Prints the string to the output following it with a newline.
395: *
396: * @param string The string to print.
397: */
398: public void println(String string) throws IOException {
399: print(string);
400: print(_newline);
401: }
402:
403: /**
404: * Get the normal indentation for a level.
405: *
406: * @param col The level of indentation.
407: */
408: protected String getIndent(int col) {
409: String indent = "";
410:
411: // go by twos to improve performance
412: String indent2x = this ._indent + this ._indent;
413: for (int i = (col & 0x7ffffe); i > 0; i -= 2) {
414: indent += indent2x;
415: }
416: if ((col & 0x01) == 1) {
417: indent += this ._indent;
418: }
419:
420: return indent;
421: }
422:
423: /**
424: * Output the node (and children) at the specified indentation level.
425: */
426: protected void printTree(Node node, int col) throws IOException {
427: int old = _column;
428: _column = col;
429: printTree(node);
430: _column = old;
431: }
432:
433: /**
434: * Output the node (and children) at the current indentation level.
435: */
436: protected void printTree(Node node) throws IOException {
437: int nodeType = -1;
438:
439: if (node != null) {
440: nodeType = node.getNodeType();
441: switch (nodeType) {
442: case Node.DOCUMENT_NODE: {
443: NodeList nodes = node.getChildNodes();
444:
445: if (nodes != null) {
446: for (int i = 0; i < nodes.getLength(); i++) {
447: printTree(nodes.item(i));
448: }
449: }
450:
451: break;
452: }
453:
454: case Node.ELEMENT_NODE: {
455: String name = node.getNodeName();
456: this .print("<" + name, getIndent(this ._column));
457:
458: NamedNodeMap attributes = node.getAttributes();
459: for (int i = 0; i < attributes.getLength(); i++) {
460: Attr current = (Attr) attributes.item(i);
461:
462: /*
463: With some DOM implementations the default value shows up in addition to a
464: specified value so you get duplicate attributes. We will only write
465: specified attributes.
466: */
467: if (current.getSpecified() == true) {
468: this .print(" " + current.getNodeName() + "='"
469: + current.getNodeValue() + "'");
470: }
471:
472: }//for attrs
473:
474: if (!node.hasChildNodes()) {
475: // Close opening tag, because no children
476: this .println(" />");
477: } else {
478: // Close opening tag normally to account for children
479: this .print(">");
480:
481: NodeList children = node.getChildNodes();
482:
483: // If a child is a text node, we don't want to print carriage returns that get picked
484: // up as string text
485: boolean hasChildElements = false;
486: if (children != null) {
487: int len = children.getLength();
488: for (int i = 0; i < len; i++) {
489: if (children.item(i).getNodeType() != Node.TEXT_NODE) {
490: hasChildElements = true;
491: break;
492: }
493: }
494: }
495:
496: // If non-text node as child, we can print enter
497: if (hasChildElements) {
498: this .println("");
499: }
500:
501: this ._column++;
502:
503: for (int i = 0; i < children.getLength(); i++) {
504: printTree(children.item(i));
505: }
506: this ._column--;
507:
508: // Write closing tag. Once again for text nodes treat differently
509: if (hasChildElements) {
510: this .println("</" + name + ">",
511: getIndent(this ._column));
512: } else {
513: this .println("</" + name + ">");
514: }
515: }
516:
517: break;
518: }
519:
520: case Node.TEXT_NODE: {
521: String nodeValue = node.getNodeValue().trim();
522: if (!nodeValue.equals("")) {
523: // Normalize string
524: this .print(toXML(nodeValue));
525: }
526: break;
527: }
528:
529: case Node.CDATA_SECTION_NODE: {
530: this .print("<![CDATA[", getIndent(this ._column));
531:
532: this .print(convertNewline(node.getNodeValue()));
533: this .println("]]>");
534: break;
535: }
536:
537: case Node.PROCESSING_INSTRUCTION_NODE: {
538: if (node.getNodeName() != null) {
539: if (!_omitXmlDecl
540: && (false == node.getNodeName().startsWith(
541: "xml"))
542: && (false == node.getNodeName().startsWith(
543: "xsl"))) {
544: // This should NOT be correct, but Xerces seems to have a bug - bt 4/2001
545: this .println("<?xml " + node.getNodeName()
546: + "=\"" + node.getNodeValue() + "\"?>");
547: } else {
548: // This should be the normal behaviour
549: if (!_omitXmlDecl
550: || !"xml".equals(node.getNodeName())) {
551: this
552: .println("<?" + node.getNodeName()
553: + " " + node.getNodeValue()
554: + " ?>");
555: }
556: }
557: }
558: break;
559: }
560:
561: case Node.ENTITY_REFERENCE_NODE: {
562: this .println("&" + node.getNodeName() + ";");
563: break;
564: }
565:
566: case Node.DOCUMENT_TYPE_NODE: {
567: DocumentType docType = (DocumentType) node;
568:
569: // Note: below is since DOM 2 - bt
570: // Print either SYSTEM '...' or PUBLIC '...' '...'
571: this .print("<!DOCTYPE " + docType.getName());
572: if (docType.getPublicId() != null) {
573: this .print(" PUBLIC ");
574: } else if (docType.getSystemId() != null) {
575: this .print(" SYSTEM ");
576: }
577: // There may not even be a public or system, that's OK
578:
579: if (docType.getPublicId() != null) {
580:
581: this .print("\"" + docType.getPublicId() + "\" ");
582: }
583: if (docType.getSystemId() != null) {
584: this .print("\"" + docType.getSystemId() + "\" ");
585: }
586:
587: // Also print any entities that were defined, such as [<!ENTITY lt "<" >]
588: NamedNodeMap nodes = docType.getEntities();
589:
590: for (int i = 0; i < nodes.getLength(); i++) {
591: this .println("");
592: Entity entity = (Entity) nodes.item(i);
593: this .print(" [<!ENTITY " + entity.getNodeName()
594: + " ");
595:
596: // Entity should have a child node that is its value
597: NodeList children = entity.getChildNodes();
598: if (children != null && children.getLength() > 0) {
599: this .print("\""
600: + XMLPrinter.nodeToString(children
601: .item(0)) + "\">]");
602: } else {
603: this .print("\"" + entity.getNodeValue()
604: + "\">]");
605: }
606: }
607:
608: // End the doctype entry
609: this .println("");
610: this .println(">");
611:
612: break;
613: }
614: }
615:
616: }
617:
618: this ._out.flush();
619: }
620:
621: /**
622: * Convert newlines to what we want.
623: */
624: protected String convertNewline(String text) {
625: //convert MSDOS crlf to a lf
626: text = StringUtil.replace(text, "\r\n", "\n");
627: //convert lf to the set newline seq
628: text = StringUtil.replace(text, "\n", _newline);
629:
630: return text;
631: }
632:
633: public static int run(String[] args, XMLPrinter printer) {
634: String filename = null;
635: String outputname = null;
636:
637: File tempOut = null;
638:
639: try {
640: if (System.getProperty("log4j.configuration") == null
641: || System.getProperty("log4j.configuration").trim()
642: .length() == 0) {
643: System.err
644: .println("ERROR: Logging will not work - 'log4j.configuration' must be defined.");
645: } else {
646: org.apache.log4j.PropertyConfigurator
647: .configureAndWatch(System
648: .getProperty("log4j.configuration"));
649: }
650:
651: for (int i = 0; i < args.length; i++) {
652: if (args[i].toLowerCase().startsWith("-omitxml=")) {
653: printer.setOmitXmlDecl(StringUtil.toBoolean(args[i]
654: .substring(9)));
655: } else if (args[i].toLowerCase().equals("-out")
656: && args.length > i + 1) {
657: outputname = args[++i];
658: } else if (args[i].toLowerCase().equals("-in")
659: && args.length > i + 1) {
660: filename = args[++i];
661: }
662: }
663:
664: if (filename == null) {
665: log.error("No input file specified.");
666: return (2);
667: }
668:
669: File inputfile = new File(filename);
670:
671: Document doc = null;
672:
673: java.io.Reader inputReader = null;
674: try {
675: inputReader = new DocBookFilterReader(
676: new java.io.FileReader(inputfile));
677: InputSource inputSource = new InputSource(inputReader);
678: DocumentBuilderFactory dbf = DocumentBuilderFactory
679: .newInstance();
680: dbf.setNamespaceAware(true);
681: dbf.setValidating(false);
682:
683: DocumentBuilder db = dbf.newDocumentBuilder();
684: db.setErrorHandler(printer);
685:
686: // Set the path so that relative SYSTEM entities can be found
687: if (inputfile.getParentFile() != null) {
688: inputSource.setSystemId(inputfile.getParentFile()
689: .toURL().toString());
690: }
691:
692: doc = db.parse(inputSource);
693: } catch (Exception e) {
694: log.error("Error Parsing XML Document.", e);
695: return (1);
696: } finally {
697: try {
698: inputReader.close();
699: } catch (Throwable t) {
700: }
701: }
702:
703: // The parsing has now succeeded.
704:
705: File outputfile = null;
706: if (outputname != null) {
707: outputfile = new File(outputname);
708: } else {
709: outputfile = inputfile;
710: }
711:
712: tempOut = File.createTempFile(outputfile.getName() + "-",
713: ".xmlpp", outputfile.getParentFile());
714:
715: try {
716: Writer outfilewriter = new java.io.FileWriter(tempOut);
717: printer
718: .setWriter(new DocBookFilterWriter(
719: outfilewriter));
720:
721: // The parsing has now succeeded.
722: printer.outputDocument(doc.getDocumentElement());
723: } catch (Exception e) {
724: log.error("Error formatting XML Document.", e);
725: return (1);
726: } finally {
727: try {
728: printer.getWriter().close();
729: } catch (Throwable t) {
730: }
731: }
732:
733: // try to rename the input file to keep from trashing the input
734: if (outputname == null) {
735: File bak = new File(inputfile.getParentFile(),
736: inputfile.getName() + ".bak");
737: if (!inputfile.renameTo(bak) || inputfile.exists()) {
738: bak = File.createTempFile(
739: inputfile.getName() + "-", ".xmlpp",
740: inputfile.getParentFile());
741:
742: log
743: .warn("Can't rename input to *.bak - trying copy to "
744: + bak.getName());
745:
746: try {
747: copyFile(inputfile, bak);
748: log.info("input file backed up");
749: } catch (IOException ioe) {
750: tempOut = null;
751: log.error(
752: "Unable to backup the input file. The output was left in "
753: + tempOut.getAbsolutePath(),
754: ioe);
755: return 1;
756: }
757: }
758: }
759:
760: // write the output file
761: try {
762: copyFile(tempOut, outputfile);
763: } catch (IOException ioe) {
764: log.error("Unable to overwrite output file "
765: + outputfile.getAbsolutePath());
766: return 1;
767: }
768:
769: } catch (Exception e) {
770: log.error("Error prettying XML Document.", e);
771: return (1);
772: } finally {
773: if (tempOut != null) {
774: try {
775: if (tempOut.delete()) {
776: return 0;
777: }
778: } catch (Throwable t) {
779: }
780: try {
781: log.warn("A temporary file was left on disk - "
782: + tempOut.getAbsolutePath());
783: } catch (Throwable t) {
784: log.warn("A temporary file was left on disk - ");
785: }
786: }
787: }
788: return 0;
789: }
790:
791: public static int run(String[] args) {
792: org.apache.log4j.BasicConfigurator.configure();
793:
794: XMLPrinter printer = new XMLPrinter();
795:
796: return run(args, printer);
797: }
798:
799: public static void main(String[] args) {
800: System.exit(run(args));
801: }
802:
803: protected static void copyFile(File in, File out)
804: throws IOException {
805: java.io.FileWriter filewriter = null;
806: java.io.FileReader filereader = null;
807: try {
808: filewriter = new java.io.FileWriter(out);
809: filereader = new java.io.FileReader(in);
810:
811: char[] buf = new char[4096];
812: int nread = filereader.read(buf, 0, 4096);
813: while (nread >= 0) {
814: filewriter.write(buf, 0, nread);
815: nread = filereader.read(buf, 0, 4096);
816: }
817: buf = null;
818: } finally {
819: try {
820: filereader.close();
821: } catch (Throwable t) {
822: }
823: try {
824: filewriter.close();
825: } catch (Throwable t) {
826: }
827: }
828: }
829:
830: //
831: // ErrorHandler methods
832: //
833: /**
834: * Issue a warning on parsing errors
835: *
836: * @param ex A Sax Parse Exception event
837: */
838: public void warning(SAXParseException ex) {
839:
840: log.warn(getLocationString(ex) + ": " + ex.getMessage());
841: }
842:
843: /**
844: * Issue an error
845: *
846: * @param ex A Sax Parse Exception event
847: */
848: public void error(SAXParseException ex) {
849: log.error(getLocationString(ex) + ": " + ex.getMessage());
850: }
851:
852: /**
853: * Fatal error. Used Internally for parsing only
854: *
855: * @param ex A Sax Parse Exception event
856: * @throws SAXException after logging the Parsing Exception
857: */
858: public void fatalError(SAXParseException ex) throws SAXException {
859: log.error(getLocationString(ex) + ": " + ex.getMessage());
860: throw ex;
861: }
862:
863: /**
864: * Returns a string of the location. Used Internally For Parsing Only
865: *
866: * @param ex A Sax Parse Exception event
867: * @return java.lang.String
868: */
869: private String getLocationString(SAXParseException ex) {
870: FastStringBuffer str = new FastStringBuffer(128);
871: String systemId = ex.getSystemId();
872:
873: if (systemId != null) {
874: int index = systemId.lastIndexOf('/');
875:
876: if (index != -1) {
877: systemId = systemId.substring(index + 1);
878: }
879:
880: str.append(systemId);
881: }
882:
883: str.append(':');
884: str.append(ex.getLineNumber());
885: str.append(':');
886: str.append(ex.getColumnNumber());
887:
888: return str.toString();
889: } // getLocationString(SAXParseException):String
890: }
|