001: /**
002: * Licensed under the Common Development and Distribution License,
003: * you may not use this file except in compliance with the License.
004: * You may obtain a copy of the License at
005: *
006: * http://www.sun.com/cddl/
007: *
008: * Unless required by applicable law or agreed to in writing, software
009: * distributed under the License is distributed on an "AS IS" BASIS,
010: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
011: * implied. See the License for the specific language governing
012: * permissions and limitations under the License.
013: */package com.sun.facelets.compiler;
014:
015: import java.io.BufferedInputStream;
016: import java.io.IOException;
017: import java.io.InputStream;
018: import java.net.URL;
019: import java.util.regex.Matcher;
020: import java.util.regex.Pattern;
021:
022: import javax.el.ELException;
023: import javax.faces.FacesException;
024: import javax.xml.parsers.ParserConfigurationException;
025: import javax.xml.parsers.SAXParser;
026: import javax.xml.parsers.SAXParserFactory;
027:
028: import org.xml.sax.Attributes;
029: import org.xml.sax.InputSource;
030: import org.xml.sax.Locator;
031: import org.xml.sax.SAXException;
032: import org.xml.sax.SAXParseException;
033: import org.xml.sax.XMLReader;
034: import org.xml.sax.ext.LexicalHandler;
035: import org.xml.sax.helpers.DefaultHandler;
036:
037: import com.sun.facelets.FaceletException;
038: import com.sun.facelets.FaceletHandler;
039: import com.sun.facelets.tag.Location;
040: import com.sun.facelets.tag.Tag;
041: import com.sun.facelets.tag.TagAttribute;
042: import com.sun.facelets.tag.TagAttributes;
043:
044: /**
045: * Compiler implementation that uses SAX
046: *
047: * @see com.sun.facelets.compiler.Compiler
048: *
049: * @author Jacob Hookom
050: * @version $Id: SAXCompiler.java,v 1.13 2006/05/31 04:16:46 jhook Exp $
051: */
052: public final class SAXCompiler extends Compiler {
053:
054: private final static Pattern XmlDeclaration = Pattern
055: .compile("^<\\?xml.+?version=['\"](.+?)['\"](.+?encoding=['\"]((.+?))['\"])?.*?\\?>");
056:
057: private static class CompilationHandler extends DefaultHandler
058: implements LexicalHandler {
059:
060: private final String alias;
061:
062: private boolean inDocument = false;
063:
064: private Locator locator;
065:
066: private final CompilationManager unit;
067:
068: public CompilationHandler(CompilationManager unit, String alias) {
069: this .unit = unit;
070: this .alias = alias;
071: }
072:
073: public void characters(char[] ch, int start, int length)
074: throws SAXException {
075: if (this .inDocument) {
076: this .unit.writeText(new String(ch, start, length));
077: }
078: }
079:
080: public void comment(char[] ch, int start, int length)
081: throws SAXException {
082: if (this .inDocument) {
083: this .unit.writeComment(new String(ch, start, length));
084: }
085: }
086:
087: protected TagAttributes createAttributes(Attributes attrs) {
088: int len = attrs.getLength();
089: TagAttribute[] ta = new TagAttribute[len];
090: for (int i = 0; i < len; i++) {
091: ta[i] = new TagAttribute(this .createLocation(), attrs
092: .getURI(i), attrs.getLocalName(i), attrs
093: .getQName(i), attrs.getValue(i));
094: }
095: return new TagAttributes(ta);
096: }
097:
098: protected Location createLocation() {
099: return new Location(this .alias, this .locator
100: .getLineNumber(), this .locator.getColumnNumber());
101: }
102:
103: public void endCDATA() throws SAXException {
104: if (this .inDocument) {
105: this .unit.writeInstruction("]]>");
106: }
107: }
108:
109: public void endDocument() throws SAXException {
110: super .endDocument();
111: }
112:
113: public void endDTD() throws SAXException {
114: this .inDocument = true;
115: }
116:
117: public void endElement(String uri, String localName,
118: String qName) throws SAXException {
119: this .unit.popTag();
120: }
121:
122: public void endEntity(String name) throws SAXException {
123: }
124:
125: public void endPrefixMapping(String prefix) throws SAXException {
126: this .unit.popNamespace(prefix);
127: }
128:
129: public void fatalError(SAXParseException e) throws SAXException {
130: if (this .locator != null) {
131: throw new SAXException("Error Traced[line: "
132: + this .locator.getLineNumber() + "] "
133: + 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
143: .writeWhitespace(new String(ch, start, length));
144: }
145: }
146:
147: public InputSource resolveEntity(String publicId,
148: String systemId) throws SAXException {
149: String dtd = "default.dtd";
150: /*if ("-//W3C//DTD XHTML 1.0 Transitional//EN".equals(publicId)) {
151: dtd = "xhtml1-transitional.dtd";
152: } else if (systemId != null && systemId.startsWith("file:/")) {
153: return new InputSource(systemId);
154: }*/
155: URL url = Thread.currentThread().getContextClassLoader()
156: .getResource(dtd);
157: return new InputSource(url.toString());
158: }
159:
160: public void setDocumentLocator(Locator locator) {
161: this .locator = locator;
162: }
163:
164: public void startCDATA() throws SAXException {
165: if (this .inDocument) {
166: this .unit.writeInstruction("<![CDATA[");
167: }
168: }
169:
170: public void startDocument() throws SAXException {
171: this .inDocument = true;
172: }
173:
174: public void startDTD(String name, String publicId,
175: String systemId) throws SAXException {
176: if (this .inDocument) {
177: StringBuffer sb = new StringBuffer(64);
178: sb.append("<!DOCTYPE ").append(name);
179: if (publicId != null) {
180: sb.append(" PUBLIC \"").append(publicId).append(
181: "\"");
182: if (systemId != null) {
183: sb.append(" \"").append(systemId).append("\"");
184: }
185: } else if (systemId != null) {
186: sb.append(" SYSTEM \"").append(systemId).append(
187: "\"");
188: }
189: sb.append(" >\n");
190: this .unit.writeInstruction(sb.toString());
191: }
192: this .inDocument = false;
193: }
194:
195: public void startElement(String uri, String localName,
196: String qName, Attributes attributes)
197: throws SAXException {
198: this .unit
199: .pushTag(new Tag(this .createLocation(), uri,
200: localName, qName, this
201: .createAttributes(attributes)));
202: }
203:
204: public void startEntity(String name) throws SAXException {
205: }
206:
207: public void startPrefixMapping(String prefix, String uri)
208: throws SAXException {
209: this .unit.pushNamespace(prefix, uri);
210: }
211:
212: public void processingInstruction(String target, String data)
213: throws SAXException {
214: if (this .inDocument) {
215: StringBuffer sb = new StringBuffer(64);
216: sb.append("<?").append(target).append(' ').append(data)
217: .append("?>\n");
218: this .unit.writeInstruction(sb.toString());
219: }
220: }
221: }
222:
223: public SAXCompiler() {
224: super ();
225: }
226:
227: public FaceletHandler doCompile(URL src, String alias)
228: throws IOException, FaceletException, ELException,
229: FacesException {
230: CompilationManager mngr = null;
231: InputStream is = null;
232: String encoding = "UTF-8";
233: try {
234: is = new BufferedInputStream(src.openStream(), 1024);
235: mngr = new CompilationManager(alias, this );
236: encoding = writeXmlDecl(is, mngr);
237: CompilationHandler handler = new CompilationHandler(mngr,
238: alias);
239: SAXParser parser = this .createSAXParser(handler);
240: parser.parse(is, handler);
241: } catch (SAXException e) {
242: throw new FaceletException("Error Parsing " + alias + ": "
243: + e.getMessage(), e.getCause());
244: } catch (ParserConfigurationException e) {
245: throw new FaceletException("Error Configuring Parser "
246: + alias + ": " + e.getMessage(), e.getCause());
247: } finally {
248: if (is != null) {
249: is.close();
250: }
251: }
252: return new EncodingHandler(mngr.createFaceletHandler(),
253: encoding);
254: }
255:
256: protected static final String writeXmlDecl(InputStream is,
257: CompilationManager mngr) throws IOException {
258: is.mark(128);
259: String encoding = "UTF-8";
260: try {
261: byte[] b = new byte[128];
262: if (is.read(b) > 0) {
263: String r = new String(b);
264: Matcher m = XmlDeclaration.matcher(r);
265: if (m.find()) {
266: mngr.writeInstruction(m.group(0) + "\n");
267: if (m.group(3) != null) {
268: encoding = m.group(3);
269: }
270: }
271: }
272: } finally {
273: is.reset();
274: }
275: return encoding;
276: }
277:
278: private final SAXParser createSAXParser(CompilationHandler handler)
279: throws SAXException, ParserConfigurationException {
280: SAXParserFactory factory = SAXParserFactory.newInstance();
281: factory.setNamespaceAware(true);
282: factory.setFeature(
283: "http://xml.org/sax/features/namespace-prefixes", true);
284: factory.setFeature("http://xml.org/sax/features/validation",
285: this .isValidating());
286: factory.setValidating(this .isValidating());
287: SAXParser parser = factory.newSAXParser();
288: XMLReader reader = parser.getXMLReader();
289: reader.setProperty(
290: "http://xml.org/sax/properties/lexical-handler",
291: handler);
292: reader.setErrorHandler(handler);
293: reader.setEntityResolver(handler);
294: return parser;
295: }
296:
297: }
|