1 package net.sf.cantina.util;
2 import org.apache.log4j.Logger;
3 import org.xml.sax.InputSource;
4 import org.xml.sax.SAXException;
5 import org.xml.sax.SAXParseException;
6 import org.xml.sax.helpers.DefaultHandler;
7
8 import java.io.IOException;
9 import java.net.URL;
10 import java.util.ArrayList;
11 import java.util.Arrays;
12 import java.util.List;
13
14 /***
15 * SAX Default Handler.
16 * Provided to a SAXParser as DefaultHandler,
17 * will monitor parsing exceptions and provide
18 * cached dtds (the ones that come with the dostribution,
19 * i.e. xhtml, etc.).
20 * @author Stephane JAIS
21 *
22 */
23
24 public class SAXDefaultHandler
25 extends DefaultHandler
26 {
27 static Logger logger = Logger.getLogger(SAXDefaultHandler.class);
28
29 /*** The SYSTEM of the XHTML transitional dtd */
30 public static final String DTD_XHTML_TRANS = "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd";
31 /*** The SYSTEM of the XHTML latin1 entites */
32 public static final String ENT_XHTML_LAT1 = "http://www.w3.org/TR/xhtml1/DTD/xhtml-lat1.ent";
33 /*** The SYSTEM of the XHTML special entites */
34 public static final String ENT_XHTML_SPECIAL = "http://www.w3.org/TR/xhtml1/DTD/xhtml-special.ent";
35 /*** The SYSTEM of the XHTML symbol entites */
36 public static final String ENT_XHTML_SYMBOL = "http://www.w3.org/TR/xhtml1/DTD/xhtml-symbol.ent";
37 /*** The SYSTEM of the Cantina Text DTD */
38 public static final String TEXT_SYSTEM = "http://www.cantinaweb.org/dtds/text.dtd";
39 /*** The PUBLIC ID of the Cantina Text DTD */
40 public static final String TEXT_PUBLIC_ID = "-//Cantina SW.//DTD Cantina Text 1.0//EN";
41 /*** The name of the text DTD */
42 public static final String TEXT_NAME = "text";
43
44 /*** The directory used to store cached DTDs */
45 public static final String CACHE_DIR = "net/sf/cantina/resources";
46
47 /*** All the DTDs that should be found in net.sf.cantina.resources */
48 public static final String[] CACHED_RESOURCES = {
49 DTD_XHTML_TRANS,
50 ENT_XHTML_LAT1,
51 ENT_XHTML_SPECIAL,
52 ENT_XHTML_SYMBOL,
53 TEXT_SYSTEM
54 };
55
56
57 private List errors = new ArrayList();
58 private StringBuffer buffer = new StringBuffer();
59
60 /***
61 * Contructs a SAXDefaultHandler that will
62 * put any SAXException in the provided List.
63 * @param c The List that should hold sax errors.
64 */
65
66 public SAXDefaultHandler(List c)
67 {
68 errors=c;
69 }
70
71 /***
72 * Contructs a SAXDefaultHandler that will
73 * put any SAXException in the provided List,
74 * and append all CDATA to the privded StringBuffer
75 * @param c The List that should hold sax errors.
76 * @param s The string buffer that should contain CDATA
77 */
78
79 public SAXDefaultHandler(List c, StringBuffer s)
80 {
81 this(c);
82 buffer=s;
83 }
84
85 /***
86 * This method is called by the SAX parser when CDATA is encountered.
87 */
88
89 public void characters(char[] ch, int start, int length)
90 {
91 this.buffer.append(new String(ch, start, length));
92 }
93
94
95 /*** Captures warning */
96 public void warning (SAXParseException e)
97 throws SAXException
98 {
99 logger.debug("Invalid XML (warning).",e);
100 errors.add(e);
101 throw e;
102 }
103
104 /*** Captures fatalErrors */
105 public void fatalError (SAXParseException e)
106 throws SAXException
107 {
108 error(e);
109 }
110
111 /*** Captures errors */
112 public void error (SAXParseException e)
113 throws SAXException
114 {
115 logger.debug("Invalid XML (error).",e);
116 errors.add(e);
117 throw e;
118 }
119
120 /*** Provide an InputSource to cached DTDs */
121 public InputSource resolveEntity (String publicId, String systemId) {
122 List cachedResources = Arrays.asList(CACHED_RESOURCES);
123 if (cachedResources.contains(systemId))
124 {
125 String filename = systemId.substring(systemId.lastIndexOf("/") + 1);
126 logger.debug("Trying to locate ["+systemId+"] as file ["+filename+"]");
127 URL resource = Loader.getResource(CACHE_DIR + "/" + filename);
128 if (resource == null)
129 {
130 logger.debug("Resource ["+systemId+"] not found in classpath");
131 return null;
132 }
133 logger.debug("Found resource ["+resource.toString()+"]");
134 try
135 {
136 InputSource source = new InputSource(resource.openStream());
137 source.setPublicId(publicId);
138 source.setSystemId(systemId);
139 logger.debug("Returning InputSource ["+source.toString()+"]");
140 return source;
141 } catch (IOException e)
142 {
143 logger.warn("Could not open stream to URL ["+resource.toString()+"]",e);
144 }
145 } else
146 {
147 logger.debug("Resource ["+systemId+"] is not cached, getting it from the Internet.");
148 }
149
150 return null;
151 }
152 }
153