/* * Copyright 2001-2008 Geert Bevin (gbevin[remove] at uwyn dot com) * Licensed under the Apache License, Version 2.0 (the "License") * $Id: TemplateFactory.java 3918 2008-04-14 17:35:35Z gbevin $ */ package com.uwyn.rife.template; import com.uwyn.rife.config.RifeConfig; import com.uwyn.rife.datastructures.EnumClass; import com.uwyn.rife.resources.ResourceFinder; import com.uwyn.rife.resources.ResourceFinderClasspath; import com.uwyn.rife.site.ValidationBuilder; import com.uwyn.rife.template.exceptions.InvalidBlockFilterException; import com.uwyn.rife.template.exceptions.InvalidValueFilterException; import com.uwyn.rife.template.exceptions.TemplateException; import com.uwyn.rife.template.exceptions.TemplateNotFoundException; import com.uwyn.rife.tools.Localization; import java.util.ArrayList; import java.util.Collection; import java.util.ResourceBundle; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; public class TemplateFactory extends EnumClass<String> { private static final Parser.Config CONFIG_COMPACT_STANDARD = new Parser.Config("[!", "]", "[!/", "/]", new Parser.OptionalConfigPart(Parser.PartType.STRING_DELIMITER_BEGIN, "'"), new Parser.OptionalConfigPart(Parser.PartType.STRING_DELIMITER_END, "'"), "V", "B", "BV", "BA", "I", "C"); public static final Parser.Config CONFIG_INVISIBLE_XML = new Parser.Config("<!--", "-->", "<!--/", "/-->", new Parser.OptionalConfigPart(Parser.PartType.STRING_DELIMITER_BEGIN, "'"), new Parser.OptionalConfigPart(Parser.PartType.STRING_DELIMITER_END, "'"), "V", "B", "BV", "BA", "I", "C"); public static final Parser.Config CONFIG_XML_TAGS = new Parser.Config("<r:", ">", "</r:", "/>", new Parser.MandatoryConfigPart(Parser.PartType.STRING_DELIMITER_BEGIN, "name=\""), new Parser.MandatoryConfigPart(Parser.PartType.STRING_DELIMITER_END, "\""), "v", "b", "bv", "ba", "i", "c"); public static final Parser.Config CONFIG_VELOCITY = new Parser.Config("${", "}", "${/", "/}", new Parser.OptionalConfigPart(Parser.PartType.STRING_DELIMITER_BEGIN, "'"), new Parser.OptionalConfigPart(Parser.PartType.STRING_DELIMITER_END, "'"), "v", "b", "bv", "ba", "i", "c"); public static final Parser.Config CONFIG_INVISIBLE_TXT = new Parser.Config("<!", ">", "<!/", "/>", new Parser.OptionalConfigPart(Parser.PartType.STRING_DELIMITER_BEGIN, "'"), new Parser.OptionalConfigPart(Parser.PartType.STRING_DELIMITER_END, "'"), "V", "B", "BV", "BA", "I", "C"); public static final Parser.Config CONFIG_INVISIBLE_SQL = new Parser.Config("/*", "*/", "/*-", "-*/", new Parser.OptionalConfigPart(Parser.PartType.STRING_DELIMITER_BEGIN, "'"), new Parser.OptionalConfigPart(Parser.PartType.STRING_DELIMITER_END, "'"), "V", "B", "BV", "BA", "I", "C"); public static final Parser.Config CONFIG_INVISIBLE_JAVA = new Parser.Config("/*", "*/", "/*-", "-*/", new Parser.OptionalConfigPart(Parser.PartType.STRING_DELIMITER_BEGIN, "'"), new Parser.OptionalConfigPart(Parser.PartType.STRING_DELIMITER_END, "'"), "V", "B", "BV", "BA", "I", "C"); public static final Parser.Config[] CONFIGS_XML = new Parser.Config[] {CONFIG_XML_TAGS, CONFIG_INVISIBLE_XML, CONFIG_VELOCITY, CONFIG_COMPACT_STANDARD}; public static final Parser.Config[] CONFIGS_TXT = new Parser.Config[] {CONFIG_INVISIBLE_TXT, CONFIG_COMPACT_STANDARD}; public static final Parser.Config[] CONFIGS_SQL = new Parser.Config[] {CONFIG_INVISIBLE_SQL, CONFIG_COMPACT_STANDARD}; public static final Parser.Config[] CONFIGS_JAVA = new Parser.Config[] {CONFIG_INVISIBLE_JAVA, CONFIG_COMPACT_STANDARD}; public static final String PREFIX_CONFIG = "CONFIG:"; public static final String PREFIX_L10N = "L10N:"; public static final String PREFIX_LANG = "LANG:"; public static final String PREFIX_OGNL_CONFIG = "OGNL:CONFIG:"; public static final String PREFIX_OGNL = "OGNL:"; public static final String PREFIX_MVEL_CONFIG = "MVEL:CONFIG:"; public static final String PREFIX_MVEL = "MVEL:"; public static final String PREFIX_GROOVY_CONFIG = "GROOVY:CONFIG:"; public static final String PREFIX_GROOVY = "GROOVY:"; public static final String PREFIX_JANINO_CONFIG = "JANINO:CONFIG:"; public static final String PREFIX_JANINO = "JANINO:"; public static final String PREFIX_RENDER = "RENDER:"; public static final String TAG_CONFIG = "^"+PREFIX_CONFIG+"\\s*(.*)\\s*$"; public static final String TAG_L10N = "^"+PREFIX_L10N+"\\s*([^:]*)(?::([^:]*))?\\s*$"; public static final String TAG_LANG = "(?s)^("+PREFIX_LANG+".*):\\s*(\\w*)\\s*$"; public static final String TAG_OGNL_CONFIG = "(?s)^("+PREFIX_OGNL_CONFIG+".*):\\s*\\[\\[\\s*+(.*?)\\s*+\\]\\]\\s*$"; public static final String TAG_OGNL = "(?s)^("+PREFIX_OGNL+".*):\\s*\\[\\[\\s*+(.*?)\\s*+\\]\\]\\s*$"; public static final String TAG_MVEL_CONFIG = "(?s)^("+PREFIX_MVEL_CONFIG+".*):\\s*\\[\\[\\s*+(.*?)\\s*+\\]\\]\\s*$"; public static final String TAG_MVEL = "(?s)^("+PREFIX_MVEL+".*):\\s*\\[\\[\\s*+(.*?)\\s*+\\]\\]\\s*$"; public static final String TAG_GROOVY_CONFIG = "(?s)^("+PREFIX_GROOVY_CONFIG+".*):\\s*\\[\\[\\s*+(.*?)\\s*+\\]\\]\\s*$"; public static final String TAG_GROOVY = "(?s)^("+PREFIX_GROOVY+".*):\\s*\\[\\[\\s*+(.*?)\\s*+\\]\\]\\s*$"; public static final String TAG_JANINO_CONFIG = "(?s)^("+PREFIX_JANINO_CONFIG+".*):\\s*\\[\\[\\s*+(.*?)\\s*+\\]\\]\\s*$"; public static final String TAG_JANINO = "(?s)^("+PREFIX_JANINO+".*):\\s*\\[\\[\\s*+(.*?)\\s*+\\]\\]\\s*$"; public static final String TAG_RENDER = "^"+PREFIX_RENDER+"\\s*(.*?)\\s*(:[^:]*)?$"; public static TemplateFactory HTML = new TemplateFactory(ResourceFinderClasspath.getInstance(), "html", CONFIGS_XML, "text/html", ".html", new String[] { ValidationBuilder.TAG_ERRORS, ValidationBuilder.TAG_ERRORMESSAGE, TAG_LANG, TAG_OGNL_CONFIG, TAG_OGNL, TAG_MVEL_CONFIG, TAG_MVEL, TAG_GROOVY_CONFIG, TAG_GROOVY, TAG_JANINO_CONFIG, TAG_JANINO }, new String[] { ValidationBuilder.TAG_MARK, ValidationBuilder.TAG_ERRORS, TAG_CONFIG, TAG_L10N, TAG_RENDER }, BeanHandlerXhtml.getInstance(), EncoderHtmlSingleton.INSTANCE, null); public static TemplateFactory XHTML = new TemplateFactory(ResourceFinderClasspath.getInstance(), "xhtml", CONFIGS_XML, "text/html", ".xhtml", new String[] { ValidationBuilder.TAG_ERRORS, ValidationBuilder.TAG_ERRORMESSAGE, TAG_LANG, TAG_OGNL_CONFIG, TAG_OGNL, TAG_MVEL_CONFIG, TAG_MVEL, TAG_GROOVY_CONFIG, TAG_GROOVY, TAG_JANINO_CONFIG, TAG_JANINO }, new String[] { ValidationBuilder.TAG_MARK, ValidationBuilder.TAG_ERRORS, TAG_CONFIG, TAG_L10N, TAG_RENDER }, BeanHandlerXhtml.getInstance(), EncoderHtmlSingleton.INSTANCE, null); public static TemplateFactory XML = new TemplateFactory(ResourceFinderClasspath.getInstance(), "xml", CONFIGS_XML, "application/xml", ".xml", new String[] { ValidationBuilder.TAG_ERRORS, ValidationBuilder.TAG_ERRORMESSAGE, TAG_LANG, TAG_OGNL_CONFIG, TAG_OGNL, TAG_MVEL_CONFIG, TAG_MVEL, TAG_GROOVY_CONFIG, TAG_GROOVY, TAG_JANINO_CONFIG, TAG_JANINO }, new String[] { ValidationBuilder.TAG_MARK, ValidationBuilder.TAG_ERRORS, TAG_CONFIG, TAG_L10N, TAG_RENDER }, BeanHandlerXml.getInstance(), EncoderXmlSingleton.INSTANCE, null); public static TemplateFactory TXT = new TemplateFactory(ResourceFinderClasspath.getInstance(), "txt", CONFIGS_TXT, "text/plain", ".txt", new String[] { TAG_LANG, TAG_OGNL_CONFIG, TAG_OGNL, TAG_MVEL_CONFIG, TAG_MVEL, TAG_GROOVY_CONFIG, TAG_GROOVY, TAG_JANINO_CONFIG, TAG_JANINO }, new String[] { TAG_CONFIG, TAG_L10N, TAG_RENDER }, BeanHandlerPlain.getInstance(), null, null); public static TemplateFactory SQL = new TemplateFactory(ResourceFinderClasspath.getInstance(), "sql", CONFIGS_SQL, "text/plain", ".sql", new String[] { TAG_LANG, TAG_OGNL_CONFIG, TAG_OGNL, TAG_MVEL_CONFIG, TAG_MVEL, TAG_GROOVY_CONFIG, TAG_GROOVY, TAG_JANINO_CONFIG, TAG_JANINO }, new String[] { TAG_CONFIG, TAG_L10N, TAG_RENDER }, BeanHandlerPlain.getInstance(), EncoderHtmlSingleton.INSTANCE, null); public static TemplateFactory JAVA = new TemplateFactory(ResourceFinderClasspath.getInstance(), "java", CONFIGS_JAVA, "text/x-java-source", ".java", new String[] { TAG_LANG, TAG_OGNL_CONFIG, TAG_OGNL, TAG_MVEL_CONFIG, TAG_MVEL, TAG_GROOVY_CONFIG, TAG_GROOVY, TAG_JANINO_CONFIG, TAG_JANINO }, new String[] { TAG_CONFIG, TAG_L10N, TAG_RENDER }, BeanHandlerPlain.getInstance(), null, null); public static TemplateFactory ENGINEHTML; public static TemplateFactory ENGINEXHTML; public static TemplateFactory ENGINEXML; public static TemplateFactory ENGINETXT; static { Class engine_types = null; try { engine_types = Class.forName("com.uwyn.rife.template.TemplateFactoryEngineTypes"); } catch (ClassNotFoundException e) { engine_types = null; } if (engine_types != null) { TemplateFactory factory = null; try { factory = (TemplateFactory)engine_types.getField("ENGINEHTML").get(null); } catch (Throwable e) { factory = null; } ENGINEHTML = factory; try { factory = (TemplateFactory)engine_types.getField("ENGINEXHTML").get(null); } catch (Throwable e) { factory = null; } ENGINEXHTML = factory; try { factory = (TemplateFactory)engine_types.getField("ENGINEXML").get(null); } catch (Throwable e) { factory = null; } ENGINEXML = factory; try { factory = (TemplateFactory)engine_types.getField("ENGINETXT").get(null); } catch (Throwable e) { factory = null; } ENGINETXT = factory; } else { ENGINEHTML = null; ENGINEXHTML = null; ENGINEXML = null; ENGINETXT = null; } } private TemplateClassLoader mLastClassloader = null; private Parser mParser = null; private BeanHandler mBeanHandler = null; private TemplateEncoder mEncoder = null; private ResourceFinder mResourceFinder = null; private TemplateInitializer mInitializer = null; private String mIdentifierUppercase = null; protected String mDefaultContentType = null; public TemplateFactory(ResourceFinder resourceFinder, String identifier, Parser.Config[] configs, String defaultContentType, String extension, String[] blockFilters, String[] valueFilters, BeanHandler beanHandler, TemplateEncoder encoder, TemplateInitializer initializer) { super(TemplateFactory.class, identifier); Pattern[] block_filter_patterns = null; try { block_filter_patterns = compileFilters(blockFilters); } catch (PatternSyntaxException e) { throw new InvalidBlockFilterException(e.getPattern()); } Pattern[] value_filter_patterns = null; try { value_filter_patterns = compileFilters(valueFilters); } catch (PatternSyntaxException e) { throw new InvalidValueFilterException(e.getPattern()); } mIdentifierUppercase = identifier.toUpperCase(); mParser = new Parser(this, identifier, configs, extension, block_filter_patterns, value_filter_patterns); mResourceFinder = resourceFinder; mBeanHandler = beanHandler; mEncoder = encoder; mInitializer = initializer; mDefaultContentType = defaultContentType; assert mParser != null; } private Pattern[] compileFilters(String[] filters) throws PatternSyntaxException { if (filters != null) { Pattern[] patterns = new Pattern[filters.length]; for (int i = 0; i < filters.length; i++) { patterns[i] = Pattern.compile(filters[i]); } return patterns; } return null; } public TemplateFactory(String identifier, TemplateFactory base) { super(TemplateFactory.class, identifier); mIdentifierUppercase = identifier.toUpperCase(); mParser = new Parser(this, identifier, base.getParser().getConfigs(), base.getParser().getExtension(), base.getParser().getBlockFilters(), base.getParser().getValueFilters()); mResourceFinder = base.getResourceFinder(); mBeanHandler = base.getBeanHandler(); mEncoder = base.getEncoder(); mInitializer = base.getInitializer(); mDefaultContentType = base.getDefaultContentType(); assert mParser != null; } public String getIdentifierUppercase() { return mIdentifierUppercase; } public String getDefaultContentType() { return mDefaultContentType; } public static Collection<String> getFactoryTypes() { return (Collection<String>)getIdentifiers(TemplateFactory.class); } public static TemplateFactory getFactory(String identifier) { return getMember(TemplateFactory.class, identifier); } public Template get(String name) throws TemplateException { return get(name, null, null); } public Template get(String name, TemplateTransformer transformer) throws TemplateException { return get(name, null, transformer); } public Template get(String name, String encoding) throws TemplateException { return get(name, encoding, null); } public Template get(String name, String encoding, TemplateTransformer transformer) throws TemplateException { if (null == name) throw new IllegalArgumentException("name can't be null."); if (0 == name.length()) throw new IllegalArgumentException("name can't be empty."); try { AbstractTemplate template = (AbstractTemplate)parse(name, encoding, transformer).newInstance(); template.setBeanHandler(mBeanHandler); template.setEncoder(mEncoder); template.setInitializer(mInitializer); template.setDefaultContentType(mDefaultContentType); assert template != null; Collection<String> default_resourcebundles = RifeConfig.Template.getDefaultResourcebundles(this); if (default_resourcebundles != null) { ArrayList<ResourceBundle> default_bundles = new ArrayList<ResourceBundle>(); for (String bundle_name : default_resourcebundles) { // try to look it up as a filename in the classpath ResourceBundle bundle = Localization.getResourceBundle(bundle_name); if (bundle != null) { default_bundles.add(bundle); continue; } } template.setDefaultResourceBundles(default_bundles); } template.initialize(); return template; } catch (IllegalAccessException e) { // this should not happen throw new TemplateException("TemplateFactory.get() : '"+name+"' IllegalAccessException : "+e.getMessage(), e); } catch (InstantiationException e) { // this should not happen throw new TemplateException("TemplateFactory.get() : '"+name+"' InstantiationException : "+e.getMessage(), e); } } public Class parse(String name, String encoding, TemplateTransformer transformer) throws TemplateException { if (null == name) throw new IllegalArgumentException("name can't be null."); if (0 == name.length()) throw new IllegalArgumentException("name can't be empty."); try { return getClassLoader().loadClass(mParser.getPackage()+mParser.escapeClassname(name), false, encoding, transformer); } catch (ClassNotFoundException e) { throw new TemplateNotFoundException(name, e); } } public TemplateFactory setResourceFinder(ResourceFinder resourceFinder) { if (null == resourceFinder) throw new IllegalArgumentException("resourceFinder can't be null."); mResourceFinder = resourceFinder; return this; } public ResourceFinder getResourceFinder() { assert mResourceFinder != null; return mResourceFinder; } Parser getParser() { assert mParser != null; return mParser; } public TemplateFactory setBeanHandler(BeanHandler beanHandler) { mBeanHandler = beanHandler; return this; } public BeanHandler getBeanHandler() { return mBeanHandler; } public TemplateFactory setEncoder(TemplateEncoder encoder) { mEncoder = encoder; return this; } public TemplateEncoder getEncoder() { return mEncoder; } public TemplateFactory setInitializer(TemplateInitializer initializer) { mInitializer = initializer; return this; } public TemplateInitializer getInitializer() { return mInitializer; } private TemplateClassLoader getClassLoader() { if (null == mLastClassloader) { setClassLoader(new TemplateClassLoader(this, getClass().getClassLoader())); } assert mLastClassloader != null; return mLastClassloader; } synchronized void setClassLoader(TemplateClassLoader classloader) { mLastClassloader = classloader; } }