001: /*
002: * Copyright 2001-2007 Geert Bevin <gbevin[remove] at uwyn dot com>
003: * Distributed under the terms of either:
004: * - the common development and distribution license (CDDL), v1.0; or
005: * - the GNU Lesser General Public License, v2.1 or later
006: * $Id: TemplateFactory.java 3816 2007-06-27 09:06:35Z gbevin $
007: */
008: package com.uwyn.rife.template;
009:
010: import com.uwyn.rife.config.RifeConfig;
011: import com.uwyn.rife.datastructures.EnumClass;
012: import com.uwyn.rife.resources.ResourceFinder;
013: import com.uwyn.rife.resources.ResourceFinderClasspath;
014: import com.uwyn.rife.site.ValidationBuilder;
015: import com.uwyn.rife.template.exceptions.InvalidBlockFilterException;
016: import com.uwyn.rife.template.exceptions.InvalidValueFilterException;
017: import com.uwyn.rife.template.exceptions.TemplateException;
018: import com.uwyn.rife.template.exceptions.TemplateNotFoundException;
019: import com.uwyn.rife.tools.Localization;
020: import java.util.ArrayList;
021: import java.util.Collection;
022: import java.util.ResourceBundle;
023: import java.util.regex.Pattern;
024: import java.util.regex.PatternSyntaxException;
025:
026: public class TemplateFactory extends EnumClass<String> {
027: private static final Parser.Config CONFIG_COMPACT_STANDARD = new Parser.Config(
028: "[!", "]", "[!/", "/]", new Parser.OptionalConfigPart(
029: Parser.PartType.STRING_DELIMITER_BEGIN, "'"),
030: new Parser.OptionalConfigPart(
031: Parser.PartType.STRING_DELIMITER_END, "'"), "V",
032: "B", "BV", "BA", "I", "C");
033:
034: public static final Parser.Config CONFIG_INVISIBLE_XML = new Parser.Config(
035: "<!--", "-->", "<!--/", "/-->",
036: new Parser.OptionalConfigPart(
037: Parser.PartType.STRING_DELIMITER_BEGIN, "'"),
038: new Parser.OptionalConfigPart(
039: Parser.PartType.STRING_DELIMITER_END, "'"), "V",
040: "B", "BV", "BA", "I", "C");
041: public static final Parser.Config CONFIG_XML_TAGS = new Parser.Config(
042: "<r:", ">", "</r:", "/>", new Parser.MandatoryConfigPart(
043: Parser.PartType.STRING_DELIMITER_BEGIN, "name=\""),
044: new Parser.MandatoryConfigPart(
045: Parser.PartType.STRING_DELIMITER_END, "\""), "v",
046: "b", "bv", "ba", "i", "c");
047: public static final Parser.Config CONFIG_VELOCITY = new Parser.Config(
048: "${", "}", "${/", "/}", new Parser.OptionalConfigPart(
049: Parser.PartType.STRING_DELIMITER_BEGIN, "'"),
050: new Parser.OptionalConfigPart(
051: Parser.PartType.STRING_DELIMITER_END, "'"), "v",
052: "b", "bv", "ba", "i", "c");
053: public static final Parser.Config CONFIG_INVISIBLE_TXT = new Parser.Config(
054: "<!", ">", "<!/", "/>", new Parser.OptionalConfigPart(
055: Parser.PartType.STRING_DELIMITER_BEGIN, "'"),
056: new Parser.OptionalConfigPart(
057: Parser.PartType.STRING_DELIMITER_END, "'"), "V",
058: "B", "BV", "BA", "I", "C");
059: public static final Parser.Config CONFIG_INVISIBLE_SQL = new Parser.Config(
060: "/*", "*/", "/*-", "-*/", new Parser.OptionalConfigPart(
061: Parser.PartType.STRING_DELIMITER_BEGIN, "'"),
062: new Parser.OptionalConfigPart(
063: Parser.PartType.STRING_DELIMITER_END, "'"), "V",
064: "B", "BV", "BA", "I", "C");
065: public static final Parser.Config CONFIG_INVISIBLE_JAVA = new Parser.Config(
066: "/*", "*/", "/*-", "-*/", new Parser.OptionalConfigPart(
067: Parser.PartType.STRING_DELIMITER_BEGIN, "'"),
068: new Parser.OptionalConfigPart(
069: Parser.PartType.STRING_DELIMITER_END, "'"), "V",
070: "B", "BV", "BA", "I", "C");
071:
072: public static final Parser.Config[] CONFIGS_XML = new Parser.Config[] {
073: CONFIG_XML_TAGS, CONFIG_INVISIBLE_XML, CONFIG_VELOCITY,
074: CONFIG_COMPACT_STANDARD };
075: public static final Parser.Config[] CONFIGS_TXT = new Parser.Config[] {
076: CONFIG_INVISIBLE_TXT, CONFIG_COMPACT_STANDARD };
077: public static final Parser.Config[] CONFIGS_SQL = new Parser.Config[] {
078: CONFIG_INVISIBLE_SQL, CONFIG_COMPACT_STANDARD };
079: public static final Parser.Config[] CONFIGS_JAVA = new Parser.Config[] {
080: CONFIG_INVISIBLE_JAVA, CONFIG_COMPACT_STANDARD };
081:
082: public static final String PREFIX_CONFIG = "CONFIG:";
083: public static final String PREFIX_L10N = "L10N:";
084: public static final String PREFIX_LANG = "LANG:";
085: public static final String PREFIX_OGNL_CONFIG = "OGNL:CONFIG:";
086: public static final String PREFIX_OGNL = "OGNL:";
087: public static final String PREFIX_MVEL_CONFIG = "MVEL:CONFIG:";
088: public static final String PREFIX_MVEL = "MVEL:";
089: public static final String PREFIX_GROOVY_CONFIG = "GROOVY:CONFIG:";
090: public static final String PREFIX_GROOVY = "GROOVY:";
091: public static final String PREFIX_JANINO_CONFIG = "JANINO:CONFIG:";
092: public static final String PREFIX_JANINO = "JANINO:";
093: public static final String PREFIX_RENDER = "RENDER:";
094:
095: public static final String TAG_CONFIG = "^" + PREFIX_CONFIG
096: + "\\s*(.*)\\s*$";
097: public static final String TAG_L10N = "^" + PREFIX_L10N
098: + "\\s*(.*)\\s*$";
099: public static final String TAG_LANG = "(?s)^(" + PREFIX_LANG
100: + ".*):\\s*(\\w*)\\s*$";
101: public static final String TAG_OGNL_CONFIG = "(?s)^("
102: + PREFIX_OGNL_CONFIG
103: + ".*):\\s*\\[\\[\\s*+(.*?)\\s*+\\]\\]\\s*$";
104: public static final String TAG_OGNL = "(?s)^(" + PREFIX_OGNL
105: + ".*):\\s*\\[\\[\\s*+(.*?)\\s*+\\]\\]\\s*$";
106: public static final String TAG_MVEL_CONFIG = "(?s)^("
107: + PREFIX_MVEL_CONFIG
108: + ".*):\\s*\\[\\[\\s*+(.*?)\\s*+\\]\\]\\s*$";
109: public static final String TAG_MVEL = "(?s)^(" + PREFIX_MVEL
110: + ".*):\\s*\\[\\[\\s*+(.*?)\\s*+\\]\\]\\s*$";
111: public static final String TAG_GROOVY_CONFIG = "(?s)^("
112: + PREFIX_GROOVY_CONFIG
113: + ".*):\\s*\\[\\[\\s*+(.*?)\\s*+\\]\\]\\s*$";
114: public static final String TAG_GROOVY = "(?s)^(" + PREFIX_GROOVY
115: + ".*):\\s*\\[\\[\\s*+(.*?)\\s*+\\]\\]\\s*$";
116: public static final String TAG_JANINO_CONFIG = "(?s)^("
117: + PREFIX_JANINO_CONFIG
118: + ".*):\\s*\\[\\[\\s*+(.*?)\\s*+\\]\\]\\s*$";
119: public static final String TAG_JANINO = "(?s)^(" + PREFIX_JANINO
120: + ".*):\\s*\\[\\[\\s*+(.*?)\\s*+\\]\\]\\s*$";
121: public static final String TAG_RENDER = "^" + PREFIX_RENDER
122: + "\\s*(.*?)\\s*(:[^:]*)?$";
123:
124: public static TemplateFactory HTML = new TemplateFactory(
125: ResourceFinderClasspath.getInstance(), "html", CONFIGS_XML,
126: "text/html", ".html", new String[] {
127: ValidationBuilder.TAG_ERRORS,
128: ValidationBuilder.TAG_ERRORMESSAGE, TAG_LANG,
129: TAG_OGNL_CONFIG, TAG_OGNL, TAG_MVEL_CONFIG,
130: TAG_MVEL, TAG_GROOVY_CONFIG, TAG_GROOVY,
131: TAG_JANINO_CONFIG, TAG_JANINO }, new String[] {
132: ValidationBuilder.TAG_MARK,
133: ValidationBuilder.TAG_ERRORS, TAG_CONFIG, TAG_L10N,
134: TAG_RENDER }, BeanHandlerXhtml.getInstance(),
135: EncoderHtmlSingleton.INSTANCE, null);
136:
137: public static TemplateFactory XHTML = new TemplateFactory(
138: ResourceFinderClasspath.getInstance(), "xhtml",
139: CONFIGS_XML, "text/html", ".xhtml", new String[] {
140: ValidationBuilder.TAG_ERRORS,
141: ValidationBuilder.TAG_ERRORMESSAGE, TAG_LANG,
142: TAG_OGNL_CONFIG, TAG_OGNL, TAG_MVEL_CONFIG,
143: TAG_MVEL, TAG_GROOVY_CONFIG, TAG_GROOVY,
144: TAG_JANINO_CONFIG, TAG_JANINO }, new String[] {
145: ValidationBuilder.TAG_MARK,
146: ValidationBuilder.TAG_ERRORS, TAG_CONFIG, TAG_L10N,
147: TAG_RENDER }, BeanHandlerXhtml.getInstance(),
148: EncoderHtmlSingleton.INSTANCE, null);
149:
150: public static TemplateFactory XML = new TemplateFactory(
151: ResourceFinderClasspath.getInstance(), "xml", CONFIGS_XML,
152: "application/xml", ".xml", new String[] {
153: ValidationBuilder.TAG_ERRORS,
154: ValidationBuilder.TAG_ERRORMESSAGE, TAG_LANG,
155: TAG_OGNL_CONFIG, TAG_OGNL, TAG_MVEL_CONFIG,
156: TAG_MVEL, TAG_GROOVY_CONFIG, TAG_GROOVY,
157: TAG_JANINO_CONFIG, TAG_JANINO }, new String[] {
158: ValidationBuilder.TAG_MARK,
159: ValidationBuilder.TAG_ERRORS, TAG_CONFIG, TAG_L10N,
160: TAG_RENDER }, BeanHandlerXml.getInstance(),
161: EncoderXmlSingleton.INSTANCE, null);
162:
163: public static TemplateFactory TXT = new TemplateFactory(
164: ResourceFinderClasspath.getInstance(), "txt", CONFIGS_TXT,
165: "text/plain", ".txt", new String[] { TAG_LANG,
166: TAG_OGNL_CONFIG, TAG_OGNL, TAG_MVEL_CONFIG,
167: TAG_MVEL, TAG_GROOVY_CONFIG, TAG_GROOVY,
168: TAG_JANINO_CONFIG, TAG_JANINO }, new String[] {
169: TAG_CONFIG, TAG_L10N, TAG_RENDER },
170: BeanHandlerPlain.getInstance(), null, null);
171:
172: public static TemplateFactory SQL = new TemplateFactory(
173: ResourceFinderClasspath.getInstance(), "sql", CONFIGS_SQL,
174: "text/plain", ".sql", new String[] { TAG_LANG,
175: TAG_OGNL_CONFIG, TAG_OGNL, TAG_MVEL_CONFIG,
176: TAG_MVEL, TAG_GROOVY_CONFIG, TAG_GROOVY,
177: TAG_JANINO_CONFIG, TAG_JANINO }, new String[] {
178: TAG_CONFIG, TAG_L10N, TAG_RENDER },
179: BeanHandlerPlain.getInstance(),
180: EncoderHtmlSingleton.INSTANCE, null);
181:
182: public static TemplateFactory JAVA = new TemplateFactory(
183: ResourceFinderClasspath.getInstance(), "java",
184: CONFIGS_JAVA, "text/x-java-source", ".java", new String[] {
185: TAG_LANG, TAG_OGNL_CONFIG, TAG_OGNL,
186: TAG_MVEL_CONFIG, TAG_MVEL, TAG_GROOVY_CONFIG,
187: TAG_GROOVY, TAG_JANINO_CONFIG, TAG_JANINO },
188: new String[] { TAG_CONFIG, TAG_L10N, TAG_RENDER },
189: BeanHandlerPlain.getInstance(), null, null);
190:
191: public static TemplateFactory ENGINEHTML;
192: public static TemplateFactory ENGINEXHTML;
193: public static TemplateFactory ENGINEXML;
194: public static TemplateFactory ENGINETXT;
195:
196: static {
197: Class engine_types = null;
198: try {
199: engine_types = Class
200: .forName("com.uwyn.rife.template.TemplateFactoryEngineTypes");
201: } catch (ClassNotFoundException e) {
202: engine_types = null;
203: }
204:
205: if (engine_types != null) {
206: TemplateFactory factory = null;
207: try {
208: factory = (TemplateFactory) engine_types.getField(
209: "ENGINEHTML").get(null);
210:
211: } catch (Throwable e) {
212: factory = null;
213: }
214:
215: ENGINEHTML = factory;
216:
217: try {
218: factory = (TemplateFactory) engine_types.getField(
219: "ENGINEXHTML").get(null);
220: } catch (Throwable e) {
221: factory = null;
222: }
223:
224: ENGINEXHTML = factory;
225:
226: try {
227: factory = (TemplateFactory) engine_types.getField(
228: "ENGINEXML").get(null);
229: } catch (Throwable e) {
230: factory = null;
231: }
232:
233: ENGINEXML = factory;
234:
235: try {
236: factory = (TemplateFactory) engine_types.getField(
237: "ENGINETXT").get(null);
238: } catch (Throwable e) {
239: factory = null;
240: }
241:
242: ENGINETXT = factory;
243: } else {
244: ENGINEHTML = null;
245: ENGINEXHTML = null;
246: ENGINEXML = null;
247: ENGINETXT = null;
248: }
249: }
250:
251: private TemplateClassLoader mLastClassloader = null;
252: private Parser mParser = null;
253: private BeanHandler mBeanHandler = null;
254: private TemplateEncoder mEncoder = null;
255: private ResourceFinder mResourceFinder = null;
256: private TemplateInitializer mInitializer = null;
257: private String mIdentifierUppercase = null;
258: protected String mDefaultContentType = null;
259:
260: public TemplateFactory(ResourceFinder resourceFinder,
261: String identifier, Parser.Config[] configs,
262: String defaultContentType, String extension,
263: String[] blockFilters, String[] valueFilters,
264: BeanHandler beanHandler, TemplateEncoder encoder,
265: TemplateInitializer initializer) {
266: super (TemplateFactory.class, identifier);
267:
268: Pattern[] block_filter_patterns = null;
269: try {
270: block_filter_patterns = compileFilters(blockFilters);
271: } catch (PatternSyntaxException e) {
272: throw new InvalidBlockFilterException(e.getPattern());
273: }
274:
275: Pattern[] value_filter_patterns = null;
276: try {
277: value_filter_patterns = compileFilters(valueFilters);
278: } catch (PatternSyntaxException e) {
279: throw new InvalidValueFilterException(e.getPattern());
280: }
281:
282: mIdentifierUppercase = identifier.toUpperCase();
283: mParser = new Parser(this , identifier, configs, extension,
284: block_filter_patterns, value_filter_patterns);
285: mResourceFinder = resourceFinder;
286: mBeanHandler = beanHandler;
287: mEncoder = encoder;
288: mInitializer = initializer;
289: mDefaultContentType = defaultContentType;
290:
291: assert mParser != null;
292: }
293:
294: private Pattern[] compileFilters(String[] filters)
295: throws PatternSyntaxException {
296: if (filters != null) {
297: Pattern[] patterns = new Pattern[filters.length];
298:
299: for (int i = 0; i < filters.length; i++) {
300: patterns[i] = Pattern.compile(filters[i]);
301: }
302:
303: return patterns;
304: }
305:
306: return null;
307: }
308:
309: public TemplateFactory(String identifier, TemplateFactory base) {
310: super (TemplateFactory.class, identifier);
311:
312: mIdentifierUppercase = identifier.toUpperCase();
313: mParser = new Parser(this , identifier, base.getParser()
314: .getConfigs(), base.getParser().getExtension(), base
315: .getParser().getBlockFilters(), base.getParser()
316: .getValueFilters());
317: mResourceFinder = base.getResourceFinder();
318: mBeanHandler = base.getBeanHandler();
319: mEncoder = base.getEncoder();
320: mInitializer = base.getInitializer();
321: mDefaultContentType = base.getDefaultContentType();
322:
323: assert mParser != null;
324: }
325:
326: public String getIdentifierUppercase() {
327: return mIdentifierUppercase;
328: }
329:
330: public String getDefaultContentType() {
331: return mDefaultContentType;
332: }
333:
334: public static Collection<String> getFactoryTypes() {
335: return (Collection<String>) getIdentifiers(TemplateFactory.class);
336: }
337:
338: public static TemplateFactory getFactory(String identifier) {
339: return getMember(TemplateFactory.class, identifier);
340: }
341:
342: public Template get(String name) throws TemplateException {
343: return get(name, null, null);
344: }
345:
346: public Template get(String name, TemplateTransformer transformer)
347: throws TemplateException {
348: return get(name, null, transformer);
349: }
350:
351: public Template get(String name, String encoding)
352: throws TemplateException {
353: return get(name, encoding, null);
354: }
355:
356: public Template get(String name, String encoding,
357: TemplateTransformer transformer) throws TemplateException {
358: if (null == name)
359: throw new IllegalArgumentException("name can't be null.");
360: if (0 == name.length())
361: throw new IllegalArgumentException("name can't be empty.");
362:
363: try {
364: AbstractTemplate template = (AbstractTemplate) parse(name,
365: encoding, transformer).newInstance();
366: template.setBeanHandler(mBeanHandler);
367: template.setEncoder(mEncoder);
368: template.setInitializer(mInitializer);
369: template.setDefaultContentType(mDefaultContentType);
370:
371: assert template != null;
372:
373: Collection<String> default_resourcebundles = RifeConfig.Template
374: .getDefaultResourcebundles(this );
375: if (default_resourcebundles != null) {
376: ArrayList<ResourceBundle> default_bundles = new ArrayList<ResourceBundle>();
377: for (String bundle_name : default_resourcebundles) {
378: // try to look it up as a filename in the classpath
379: ResourceBundle bundle = Localization
380: .getResourceBundle(bundle_name);
381: if (bundle != null) {
382: default_bundles.add(bundle);
383: continue;
384: }
385: }
386: template.setDefaultResourceBundles(default_bundles);
387: }
388:
389: template.initialize();
390:
391: return template;
392: } catch (IllegalAccessException e) {
393: // this should not happen
394: throw new TemplateException("TemplateFactory.get() : '"
395: + name + "' IllegalAccessException : "
396: + e.getMessage(), e);
397: } catch (InstantiationException e) {
398: // this should not happen
399: throw new TemplateException("TemplateFactory.get() : '"
400: + name + "' InstantiationException : "
401: + e.getMessage(), e);
402: }
403: }
404:
405: public Class parse(String name, String encoding,
406: TemplateTransformer transformer) throws TemplateException {
407: if (null == name)
408: throw new IllegalArgumentException("name can't be null.");
409: if (0 == name.length())
410: throw new IllegalArgumentException("name can't be empty.");
411:
412: try {
413: return getClassLoader().loadClass(
414: mParser.getPackage()
415: + mParser.escapeClassname(name), false,
416: encoding, transformer);
417: } catch (ClassNotFoundException e) {
418: throw new TemplateNotFoundException(name, e);
419: }
420: }
421:
422: public TemplateFactory setResourceFinder(
423: ResourceFinder resourceFinder) {
424: if (null == resourceFinder)
425: throw new IllegalArgumentException(
426: "resourceFinder can't be null.");
427:
428: mResourceFinder = resourceFinder;
429:
430: return this ;
431: }
432:
433: public ResourceFinder getResourceFinder() {
434: assert mResourceFinder != null;
435:
436: return mResourceFinder;
437: }
438:
439: Parser getParser() {
440: assert mParser != null;
441:
442: return mParser;
443: }
444:
445: public TemplateFactory setBeanHandler(BeanHandler beanHandler) {
446: mBeanHandler = beanHandler;
447:
448: return this ;
449: }
450:
451: public BeanHandler getBeanHandler() {
452: return mBeanHandler;
453: }
454:
455: public TemplateFactory setEncoder(TemplateEncoder encoder) {
456: mEncoder = encoder;
457:
458: return this ;
459: }
460:
461: public TemplateEncoder getEncoder() {
462: return mEncoder;
463: }
464:
465: public TemplateFactory setInitializer(
466: TemplateInitializer initializer) {
467: mInitializer = initializer;
468:
469: return this ;
470: }
471:
472: public TemplateInitializer getInitializer() {
473: return mInitializer;
474: }
475:
476: private TemplateClassLoader getClassLoader() {
477: if (null == mLastClassloader) {
478: setClassLoader(new TemplateClassLoader(this , getClass()
479: .getClassLoader()));
480: }
481:
482: assert mLastClassloader != null;
483:
484: return mLastClassloader;
485: }
486:
487: synchronized void setClassLoader(TemplateClassLoader classloader) {
488: mLastClassloader = classloader;
489: }
490: }
|