Source code: com/sun/facelets/compiler/SAXCompiler.java
1 /**
2 * Licensed under the Common Development and Distribution License,
3 * you may not use this file except in compliance with the License.
4 * You may obtain a copy of the License at
5 *
6 * http://www.sun.com/cddl/
7 *
8 * Unless required by applicable law or agreed to in writing, software
9 * distributed under the License is distributed on an "AS IS" BASIS,
10 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
11 * implied. See the License for the specific language governing
12 * permissions and limitations under the License.
13 */
14
15 package com.sun.facelets.compiler;
16
17 import java.io.BufferedInputStream;
18 import java.io.IOException;
19 import java.io.InputStream;
20 import java.net.URL;
21 import java.util.regex.Matcher;
22 import java.util.regex.Pattern;
23
24 import javax.el.ELException;
25 import javax.faces.FacesException;
26 import javax.xml.parsers.ParserConfigurationException;
27 import javax.xml.parsers.SAXParser;
28 import javax.xml.parsers.SAXParserFactory;
29
30 import org.xml.sax.Attributes;
31 import org.xml.sax.InputSource;
32 import org.xml.sax.Locator;
33 import org.xml.sax.SAXException;
34 import org.xml.sax.SAXParseException;
35 import org.xml.sax.XMLReader;
36 import org.xml.sax.ext.LexicalHandler;
37 import org.xml.sax.helpers.DefaultHandler;
38
39 import com.sun.facelets.FaceletException;
40 import com.sun.facelets.FaceletHandler;
41 import com.sun.facelets.tag.Location;
42 import com.sun.facelets.tag.Tag;
43 import com.sun.facelets.tag.TagAttribute;
44 import com.sun.facelets.tag.TagAttributes;
45
46 /**
47 * Compiler implementation that uses SAX
48 *
49 * @see com.sun.facelets.compiler.Compiler
50 *
51 * @author Jacob Hookom
52 * @version $Id: SAXCompiler.java,v 1.13 2006/05/31 04:16:46 jhook Exp $
53 */
54 public final class SAXCompiler extends Compiler {
55
56 private final static Pattern XmlDeclaration = Pattern.compile("^<\\?xml.+?version=['\"](.+?)['\"](.+?encoding=['\"]((.+?))['\"])?.*?\\?>");
57
58 private static class CompilationHandler extends DefaultHandler implements
59 LexicalHandler {
60
61 private final String alias;
62
63 private boolean inDocument = false;
64
65 private Locator locator;
66
67 private final CompilationManager unit;
68
69 public CompilationHandler(CompilationManager unit, String alias) {
70 this.unit = unit;
71 this.alias = alias;
72 }
73
74 public void characters(char[] ch, int start, int length)
75 throws SAXException {
76 if (this.inDocument) {
77 this.unit.writeText(new String(ch, start, length));
78 }
79 }
80
81 public void comment(char[] ch, int start, int length)
82 throws SAXException {
83 if (this.inDocument) {
84 this.unit.writeComment(new String(ch, start, length));
85 }
86 }
87
88 protected TagAttributes createAttributes(Attributes attrs) {
89 int len = attrs.getLength();
90 TagAttribute[] ta = new TagAttribute[len];
91 for (int i = 0; i < len; i++) {
92 ta[i] = new TagAttribute(this.createLocation(),
93 attrs.getURI(i), attrs.getLocalName(i), attrs
94 .getQName(i), attrs.getValue(i));
95 }
96 return new TagAttributes(ta);
97 }
98
99 protected Location createLocation() {
100 return new Location(this.alias, this.locator.getLineNumber(),
101 this.locator.getColumnNumber());
102 }
103
104 public void endCDATA() throws SAXException {
105 if (this.inDocument) {
106 this.unit.writeInstruction("]]>");
107 }
108 }
109
110 public void endDocument() throws SAXException {
111 super.endDocument();
112 }
113
114 public void endDTD() throws SAXException {
115 this.inDocument = true;
116 }
117
118 public void endElement(String uri, String localName, String qName)
119 throws SAXException {
120 this.unit.popTag();
121 }
122
123 public void endEntity(String name) throws SAXException {
124 }
125
126 public void endPrefixMapping(String prefix) throws SAXException {
127 this.unit.popNamespace(prefix);
128 }
129
130 public void fatalError(SAXParseException e) throws SAXException {
131 if (this.locator != null) {
132 throw new SAXException("Error Traced[line: "
133 + this.locator.getLineNumber() + "] " + e.getMessage());
134 } else {
135 throw e;
136 }
137 }
138
139 public void ignorableWhitespace(char[] ch, int start, int length)
140 throws SAXException {
141 if (this.inDocument) {
142 this.unit.writeWhitespace(new String(ch, start, length));
143 }
144 }
145
146 public InputSource resolveEntity(String publicId, String systemId)
147 throws SAXException {
148 String dtd = "default.dtd";
149 /*if ("-//W3C//DTD XHTML 1.0 Transitional//EN".equals(publicId)) {
150 dtd = "xhtml1-transitional.dtd";
151 } else if (systemId != null && systemId.startsWith("file:/")) {
152 return new InputSource(systemId);
153 }*/
154 URL url = Thread.currentThread().getContextClassLoader()
155 .getResource(dtd);
156 return new InputSource(url.toString());
157 }
158
159 public void setDocumentLocator(Locator locator) {
160 this.locator = locator;
161 }
162
163 public void startCDATA() throws SAXException {
164 if (this.inDocument) {
165 this.unit.writeInstruction("<![CDATA[");
166 }
167 }
168
169 public void startDocument() throws SAXException {
170 this.inDocument = true;
171 }
172
173 public void startDTD(String name, String publicId, String systemId)
174 throws SAXException {
175 if (this.inDocument) {
176 StringBuffer sb = new StringBuffer(64);
177 sb.append("<!DOCTYPE ").append(name);
178 if (publicId != null) {
179 sb.append(" PUBLIC \"").append(publicId).append("\"");
180 if (systemId != null) {
181 sb.append(" \"").append(systemId).append("\"");
182 }
183 } else if (systemId != null) {
184 sb.append(" SYSTEM \"").append(systemId).append("\"");
185 }
186 sb.append(" >\n");
187 this.unit.writeInstruction(sb.toString());
188 }
189 this.inDocument = false;
190 }
191
192 public void startElement(String uri, String localName, String qName,
193 Attributes attributes) throws SAXException {
194 this.unit.pushTag(new Tag(this.createLocation(), uri, localName,
195 qName, this.createAttributes(attributes)));
196 }
197
198 public void startEntity(String name) throws SAXException {
199 }
200
201 public void startPrefixMapping(String prefix, String uri)
202 throws SAXException {
203 this.unit.pushNamespace(prefix, uri);
204 }
205
206 public void processingInstruction(String target, String data)
207 throws SAXException {
208 if (this.inDocument) {
209 StringBuffer sb = new StringBuffer(64);
210 sb.append("<?").append(target).append(' ').append(data).append(
211 "?>\n");
212 this.unit.writeInstruction(sb.toString());
213 }
214 }
215 }
216
217 public SAXCompiler() {
218 super();
219 }
220
221 public FaceletHandler doCompile(URL src, String alias) throws IOException,
222 FaceletException, ELException, FacesException {
223 CompilationManager mngr = null;
224 InputStream is = null;
225 String encoding = "UTF-8";
226 try {
227 is = new BufferedInputStream(src.openStream(), 1024);
228 mngr = new CompilationManager(alias, this);
229 encoding = writeXmlDecl(is, mngr);
230 CompilationHandler handler = new CompilationHandler(mngr, alias);
231 SAXParser parser = this.createSAXParser(handler);
232 parser.parse(is, handler);
233 } catch (SAXException e) {
234 throw new FaceletException("Error Parsing " + alias + ": "
235 + e.getMessage(), e.getCause());
236 } catch (ParserConfigurationException e) {
237 throw new FaceletException("Error Configuring Parser " + alias
238 + ": " + e.getMessage(), e.getCause());
239 } finally {
240 if (is != null) {
241 is.close();
242 }
243 }
244 return new EncodingHandler(mngr.createFaceletHandler(), encoding);
245 }
246
247 protected static final String writeXmlDecl(InputStream is, CompilationManager mngr)
248 throws IOException {
249 is.mark(128);
250 String encoding = "UTF-8";
251 try {
252 byte[] b = new byte[128];
253 if (is.read(b) > 0) {
254 String r = new String(b);
255 Matcher m = XmlDeclaration.matcher(r);
256 if (m.find()) {
257 mngr.writeInstruction(m.group(0) + "\n");
258 if (m.group(3) != null) {
259 encoding = m.group(3);
260 }
261 }
262 }
263 } finally {
264 is.reset();
265 }
266 return encoding;
267 }
268
269 private final SAXParser createSAXParser(CompilationHandler handler)
270 throws SAXException, ParserConfigurationException {
271 SAXParserFactory factory = SAXParserFactory.newInstance();
272 factory.setNamespaceAware(true);
273 factory.setFeature("http://xml.org/sax/features/namespace-prefixes",
274 true);
275 factory.setFeature("http://xml.org/sax/features/validation", this
276 .isValidating());
277 factory.setValidating(this.isValidating());
278 SAXParser parser = factory.newSAXParser();
279 XMLReader reader = parser.getXMLReader();
280 reader.setProperty("http://xml.org/sax/properties/lexical-handler",
281 handler);
282 reader.setErrorHandler(handler);
283 reader.setEntityResolver(handler);
284 return parser;
285 }
286
287 }