001: /******************************************************************************
002: * JBoss, a division of Red Hat *
003: * Copyright 2006, Red Hat Middleware, LLC, and individual *
004: * contributors as indicated by the @authors tag. See the *
005: * copyright.txt in the distribution for a full listing of *
006: * individual contributors. *
007: * *
008: * This is free software; you can redistribute it and/or modify it *
009: * under the terms of the GNU Lesser General Public License as *
010: * published by the Free Software Foundation; either version 2.1 of *
011: * the License, or (at your option) any later version. *
012: * *
013: * This software is distributed in the hope that it will be useful, *
014: * but WITHOUT ANY WARRANTY; without even the implied warranty of *
015: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
016: * Lesser General Public License for more details. *
017: * *
018: * You should have received a copy of the GNU Lesser General Public *
019: * License along with this software; if not, write to the Free *
020: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA *
021: * 02110-1301 USA, or see the FSF site: http://www.fsf.org. *
022: ******************************************************************************/package org.jboss.portal.format.template;
023:
024: import javassist.CannotCompileException;
025: import javassist.CtClass;
026: import org.apache.log4j.Logger;
027: import org.dom4j.Document;
028: import org.dom4j.Element;
029:
030: import java.io.IOException;
031: import java.lang.reflect.Constructor;
032: import java.util.Collection;
033: import java.util.Collections;
034: import java.util.HashMap;
035: import java.util.Map;
036: import java.util.Set;
037:
038: /** @author <a href="mailto:julien@jboss.org">Julien Viet</a> */
039: public class TemplateRepository {
040:
041: /** The class logger. */
042: private final Logger log = Logger.getLogger(getClass());
043:
044: /** Template name -> template object. */
045: private Map templates = new HashMap();
046:
047: /** Template name -> Class object. */
048: private Map classes = new HashMap();
049:
050: /** Compile the template definitions to bytecode. */
051: private TemplateClassLoader tcl = new TemplateClassLoader(Thread
052: .currentThread().getContextClassLoader());
053:
054: public TemplateRepository() {
055: }
056:
057: public Template createTemplate(String name) {
058: return createTemplate(name, Context.NULL_CONTEXT);
059: }
060:
061: /**
062: * Creates a new template instance.
063: *
064: * @param name the template name
065: * @param ctx the context with the template properties
066: * @return the template instance or null if it is not found
067: */
068: public Template createTemplate(String name, Context ctx) {
069: Template template = null;
070: try {
071: Class clazz = (Class) classes.get(name);
072: if (clazz != null) {
073: Constructor ctor = clazz
074: .getConstructor(new Class[] { Context.class });
075: template = (Template) ctor
076: .newInstance(new Object[] { ctx });
077: } else {
078: log.warn("Template " + name + " not found");
079: }
080: } catch (Exception e) {
081: log.error("Cannot instantiate template " + name, e);
082: throw new RuntimeException(
083: "An unexpected exception occured during the template instantiation");
084: }
085: return template;
086: }
087:
088: public void addTemplate(String name, Document doc)
089: throws BuildException {
090: addTemplate(name, doc, Collections.EMPTY_SET);
091: }
092:
093: public void addTemplate(String name, Element node)
094: throws BuildException {
095: addTemplate(name, node, Collections.EMPTY_SET);
096: }
097:
098: public void addTemplate(String name, Document doc, Set names)
099: throws BuildException {
100: addTemplate(name, doc.getRootElement(), names);
101: }
102:
103: public void addTemplate(String name, Element node, Set names)
104: throws BuildException {
105: // Keep the original template
106: templates.put(name, node);
107: log.debug("Loaded template " + name);
108:
109: // Generate the class
110: Class clazz = generate(node, names);
111: log.debug("Template " + name + " generated " + clazz.getName());
112:
113: // Save the class for later
114: classes.put(name, clazz);
115: }
116:
117: private Class generate(Element node, Set names)
118: throws BuildException {
119: try {
120: // This is the classloader that will load the template
121: String className = tcl.addTemplate(node, names);
122:
123: // Return the class corresponding to the template
124: return tcl.loadClass(className);
125: } catch (ClassNotFoundException e) {
126: throw new BuildException(
127: "Unexpected error, cannot compile template", e);
128: }
129: }
130:
131: public void clear() {
132: classes.clear();
133: templates.clear();
134: tcl = new TemplateClassLoader(Thread.currentThread()
135: .getContextClassLoader());
136: }
137:
138: public static class TemplateClassLoader extends ClassLoader {
139:
140: private final Map classes;
141:
142: public TemplateClassLoader(ClassLoader parent) {
143: super (parent);
144: this .classes = new HashMap();
145: }
146:
147: public String addTemplate(Document doc, Set names)
148: throws BuildException {
149: return addTemplate(doc.getRootElement(), names);
150: }
151:
152: public String addTemplate(Element node, Set names)
153: throws BuildException {
154: try {
155: TemplateBuilder builder = new TemplateBuilder(node,
156: names);
157: builder.build();
158: CtClass cc = builder.getGeneratedClass();
159: classes.put(cc.getName(), cc.toBytecode());
160: return cc.getName();
161: } catch (IOException e) {
162: throw new BuildException(
163: "Unexpected error cannot compile template", e);
164: } catch (CannotCompileException e) {
165: throw new BuildException(
166: "Unexpected error cannot compile template", e);
167: }
168: }
169:
170: public Collection getClassNames() {
171: return Collections.unmodifiableCollection(classes.keySet());
172: }
173:
174: protected Class findClass(String name)
175: throws ClassNotFoundException {
176: byte[] bytes = (byte[]) classes.get(name);
177: if (bytes == null) {
178: throw new ClassNotFoundException("Class " + name
179: + " does not exists");
180: }
181: return defineClass(name, bytes, 0, bytes.length);
182: }
183: }
184: }
|