Source code: com/sun/facelets/compiler/TagLibraryConfig.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.IOException;
18 import java.io.InputStream;
19 import java.lang.reflect.Method;
20 import java.net.URL;
21 import java.util.logging.Level;
22 import java.util.logging.Logger;
23
24 import javax.xml.parsers.ParserConfigurationException;
25 import javax.xml.parsers.SAXParser;
26 import javax.xml.parsers.SAXParserFactory;
27
28 import org.xml.sax.Attributes;
29 import org.xml.sax.InputSource;
30 import org.xml.sax.Locator;
31 import org.xml.sax.SAXException;
32 import org.xml.sax.SAXParseException;
33 import org.xml.sax.XMLReader;
34 import org.xml.sax.helpers.DefaultHandler;
35
36 import com.sun.facelets.tag.AbstractTagLibrary;
37 import com.sun.facelets.tag.TagHandler;
38 import com.sun.facelets.tag.TagLibrary;
39 import com.sun.facelets.util.ParameterCheck;
40 import com.sun.facelets.util.Classpath;
41
42 /**
43 * Handles creating a {@link com.sun.facelets.tag.TagLibrary TagLibrary} from a
44 * {@link java.net.URL URL} source.
45 *
46 * @author Jacob Hookom
47 * @version $Id: TagLibraryConfig.java,v 1.9 2006/05/03 05:18:10 jhook Exp $
48 */
49 public final class TagLibraryConfig {
50
51 private final static String SUFFIX = ".taglib.xml";
52
53 protected final static Logger log = Logger.getLogger("facelets.compiler");
54
55 private static class TagLibraryImpl extends AbstractTagLibrary {
56 public TagLibraryImpl(String namespace) {
57 super(namespace);
58 }
59
60 public void putConverter(String name, String id) {
61 ParameterCheck.notNull("name", name);
62 ParameterCheck.notNull("id", id);
63 this.addConverter(name, id);
64 }
65
66 public void putConverter(String name, String id, Class handlerClass) {
67 ParameterCheck.notNull("name", name);
68 ParameterCheck.notNull("id", id);
69 ParameterCheck.notNull("handlerClass", handlerClass);
70 this.addConverter(name, id, handlerClass);
71 }
72
73
74 public void putValidator(String name, String id) {
75 ParameterCheck.notNull("name", name);
76 ParameterCheck.notNull("id", id);
77 this.addValidator(name, id);
78 }
79
80 public void putValidator(String name, String id, Class handlerClass) {
81 ParameterCheck.notNull("name", name);
82 ParameterCheck.notNull("id", id);
83 ParameterCheck.notNull("handlerClass", handlerClass);
84 this.addValidator(name, id, handlerClass);
85 }
86
87 public void putTagHandler(String name, Class type) {
88 ParameterCheck.notNull("name", name);
89 ParameterCheck.notNull("type", type);
90 this.addTagHandler(name, type);
91 }
92
93 public void putComponent(String name, String componentType,
94 String rendererType) {
95 ParameterCheck.notNull("name", name);
96 ParameterCheck.notNull("componentType", componentType);
97 this.addComponent(name, componentType, rendererType);
98 }
99
100 public void putComponent(String name, String componentType,
101 String rendererType, Class handlerClass) {
102 ParameterCheck.notNull("name", name);
103 ParameterCheck.notNull("componentType", componentType);
104 ParameterCheck.notNull("handlerClass", handlerClass);
105 this.addComponent(name, componentType, rendererType, handlerClass);
106 }
107
108
109 public void putUserTag(String name, URL source) {
110 ParameterCheck.notNull("name", name);
111 ParameterCheck.notNull("source", source);
112 this.addUserTag(name, source);
113 }
114
115 public void putFunction(String name, Method method) {
116 ParameterCheck.notNull("name", name);
117 ParameterCheck.notNull("method", method);
118 this.addFunction(name, method);
119 }
120 }
121
122 private static class LibraryHandler extends DefaultHandler {
123 private final String file;
124
125 private final URL source;
126
127 private TagLibrary library;
128
129 private final StringBuffer buffer;
130
131 private Locator locator;
132
133 private String tagName;
134
135 private String componentClassName;
136
137 private String componentType;
138
139 private String rendererType;
140
141 private String functionName;
142
143 private Class handlerClass;
144
145 private Class functionClass;
146
147 private String functionSignature;
148
149 public LibraryHandler(URL source) {
150 this.file = source.getFile();
151 this.source = source;
152 this.buffer = new StringBuffer(64);
153 }
154
155 public TagLibrary getLibrary() {
156 return this.library;
157 }
158
159 public void endElement(String uri, String localName, String qName)
160 throws SAXException {
161 try {
162 if ("facelet-taglib".equals(qName)) {
163 ; // Nothing to do
164 }
165 else if ("library-class".equals(qName)) {
166 this.processLibraryClass();
167 }
168 else if ("namespace".equals(qName)) {
169 this.library = new TagLibraryImpl(this.captureBuffer());
170 }
171 else if ("component-type".equals(qName)) {
172 this.componentType = this.captureBuffer();
173 }
174 else if ("renderer-type".equals(qName)) {
175 this.rendererType = this.captureBuffer();
176 }
177 else if ("tag-name".equals(qName)) {
178 this.tagName = this.captureBuffer();
179 }
180 else if ("function-name".equals(qName)) {
181 this.functionName = this.captureBuffer();
182 }
183 else if ("function-class".equals(qName)) {
184 String className = this.captureBuffer();
185 this.functionClass = this.createClass(Object.class, className);
186 }
187 else
188 {
189 // Make sure there we've seen a namespace element
190 // before trying any of the following elements to avoid
191 // obscure NPEs
192 if (this.library == null) {
193 throw new IllegalStateException("No <namespace> element");
194 }
195
196 TagLibraryImpl impl = (TagLibraryImpl) this.library;
197
198 if ("tag".equals(qName)) {
199 if (this.handlerClass != null) {
200 impl.putTagHandler(this.tagName, this.handlerClass);
201 }
202 }
203 else if ("handler-class".equals(qName)) {
204 String cName = this.captureBuffer();
205 this.handlerClass = this.createClass(
206 TagHandler.class, cName);
207 }
208 else if ("component".equals(qName)) {
209 if (this.handlerClass != null) {
210 impl.putComponent(this.tagName,
211 this.componentType,
212 this.rendererType,
213 this.handlerClass);
214 this.handlerClass = null;
215 }
216 else {
217 impl.putComponent(this.tagName,
218 this.componentType,
219 this.rendererType);
220 }
221 }
222 else if ("converter-id".equals(qName)) {
223 if (this.handlerClass != null) {
224 impl.putConverter(this.tagName,
225 this.captureBuffer(),
226 handlerClass);
227 this.handlerClass = null;
228 }
229 else {
230 impl.putConverter(this.tagName,
231 this.captureBuffer());
232 }
233 }
234 else if ("validator-id".equals(qName)) {
235 if (this.handlerClass != null) {
236 impl.putValidator(this.tagName,
237 this.captureBuffer(),
238 handlerClass);
239 this.handlerClass = null;
240 }
241 else {
242 impl.putValidator(this.tagName,
243 this.captureBuffer());
244 }
245 }
246 else if ("source".equals(qName)) {
247 String path = this.captureBuffer();
248 URL url = new URL(this.source, path);
249 impl.putUserTag(this.tagName, url);
250 }
251 else if ("function-signature".equals(qName)) {
252 this.functionSignature = this.captureBuffer();
253 Method m = this.createMethod(this.functionClass, this.functionSignature);
254 impl.putFunction(this.functionName, m);
255 }
256 }
257 } catch (Exception e) {
258 SAXException saxe =
259 new SAXException("Error Handling [" + this.source + "@"
260 + this.locator.getLineNumber() + ","
261 + this.locator.getColumnNumber() + "] <" + qName
262 + ">");
263 saxe.initCause(e);
264 throw saxe;
265 }
266 }
267
268 private String captureBuffer() throws Exception {
269 String s = this.buffer.toString().trim();
270 if (s.length() == 0) {
271 throw new Exception("Value Cannot be Empty");
272 }
273 this.buffer.setLength(0);
274 return s;
275 }
276
277 private static Class createClass(Class type, String name) throws Exception {
278 Class factory = ReflectionUtil.forName(name);
279 if (!type.isAssignableFrom(factory)) {
280 throw new Exception(name + " must be an instance of "
281 + type.getName());
282 }
283 return factory;
284 }
285
286 private static Method createMethod(Class type, String s) throws Exception {
287 Method m = null;
288 int pos = s.indexOf(' ');
289 if (pos == -1) {
290 throw new Exception("Must Provide Return Type: "+s);
291 } else {
292 String rt = s.substring(0, pos).trim();
293 int pos2 = s.indexOf('(', pos+1);
294 if (pos2 == -1) {
295 throw new Exception("Must provide a method name, followed by '(': "+s);
296 } else {
297 String mn = s.substring(pos+1, pos2).trim();
298 pos = s.indexOf(')', pos2 + 1);
299 if (pos == -1) {
300 throw new Exception("Must close parentheses, ')' missing: "+s);
301 } else {
302 String[] ps = s.substring(pos2 + 1, pos).trim().split(",");
303 Class[] pc;
304 if (ps.length == 1 && "".equals(ps[0])) {
305 pc = new Class[0];
306 } else {
307 pc = new Class[ps.length];
308 for (int i = 0; i < pc.length; i ++) {
309 pc[i] = ReflectionUtil.forName(ps[i].trim());
310 }
311 }
312 try {
313 return type.getMethod(mn, pc);
314 } catch (NoSuchMethodException e) {
315 throw new Exception("No Function Found on type: "+type.getName()+" with signature: "+s);
316 }
317
318 }
319
320 }
321 }
322 }
323
324 private void processLibraryClass() throws Exception {
325 String name = this.captureBuffer();
326 Class type = this.createClass(TagLibrary.class, name);
327 this.library = (TagLibrary) type.newInstance();
328 }
329
330 public InputSource resolveEntity(String publicId, String systemId)
331 throws SAXException {
332 if ("-//Sun Microsystems, Inc.//DTD Facelet Taglib 1.0//EN"
333 .equals(publicId)) {
334 URL url = Thread.currentThread().getContextClassLoader()
335 .getResource("facelet-taglib_1_0.dtd");
336 return new InputSource(url.toExternalForm());
337 }
338 return null;
339 }
340
341 public void characters(char[] ch, int start, int length)
342 throws SAXException {
343 this.buffer.append(ch, start, length);
344 }
345
346 public void startElement(String uri, String localName, String qName,
347 Attributes attributes) throws SAXException {
348 this.buffer.setLength(0);
349 if ("tag".equals(qName)) {
350 this.componentClassName = null;
351 this.handlerClass = null;
352 this.componentType = null;
353 this.rendererType = null;
354 this.tagName = null;
355 } else if ("function".equals(qName)) {
356 this.functionName = null;
357 this.functionClass = null;
358 this.functionSignature = null;
359 }
360 }
361
362 public void error(SAXParseException e) throws SAXException {
363 SAXException saxe =
364 new SAXException("Error Handling [" + this.source + "@"
365 + e.getLineNumber() + "," + e.getColumnNumber() + "]");
366 saxe.initCause(e);
367 throw saxe;
368 }
369
370 public void setDocumentLocator(Locator locator) {
371 this.locator = locator;
372 }
373
374 public void fatalError(SAXParseException e) throws SAXException {
375 throw e;
376 }
377
378 public void warning(SAXParseException e) throws SAXException {
379 throw e;
380 }
381 }
382
383 public TagLibraryConfig() {
384 super();
385 }
386
387 public static TagLibrary create(URL url) throws IOException {
388 InputStream is = null;
389 TagLibrary t = null;
390 try {
391 is = url.openStream();
392 LibraryHandler handler = new LibraryHandler(url);
393 SAXParser parser = createSAXParser(handler);
394 parser.parse(is, handler);
395 t = handler.getLibrary();
396 } catch (SAXException e) {
397 IOException ioe =
398 new IOException("Error parsing [" + url + "]: ");
399 ioe.initCause(e);
400 throw ioe;
401 } catch (ParserConfigurationException e) {
402 IOException ioe =
403 new IOException("Error parsing [" + url + "]: ");
404 ioe.initCause(e);
405 throw ioe;
406 } finally {
407 if (is != null)
408 is.close();
409 }
410 return t;
411 }
412
413 public void loadImplicit(Compiler compiler) throws IOException {
414 ClassLoader cl = Thread.currentThread().getContextClassLoader();
415 URL[] urls = Classpath.search(cl, "META-INF/", SUFFIX);
416 for (int i = 0; i < urls.length; i++) {
417 try {
418 compiler.addTagLibrary(create(urls[i]));
419 log.info("Added Library from: " + urls[i]);
420 } catch (Exception e) {
421 log.log(Level.SEVERE, "Error Loading Library: " + urls[i], e);
422 }
423 }
424 }
425
426 private static final SAXParser createSAXParser(LibraryHandler handler)
427 throws SAXException, ParserConfigurationException {
428 SAXParserFactory factory = SAXParserFactory.newInstance();
429 factory.setNamespaceAware(false);
430 factory.setFeature("http://xml.org/sax/features/validation", true);
431 factory.setValidating(true);
432 SAXParser parser = factory.newSAXParser();
433 XMLReader reader = parser.getXMLReader();
434 reader.setErrorHandler(handler);
435 reader.setEntityResolver(handler);
436 return parser;
437 }
438
439 }