001: /*
002: * JFox - The most lightweight Java EE Application Server!
003: * more details please visit http://www.huihoo.org/jfox or http://www.jfox.org.cn.
004: *
005: * JFox is licenced and re-distributable under GNU LGPL.
006: */
007: package org.jfox.mvc.freemarker;
008:
009: import java.io.File;
010: import java.io.IOException;
011: import java.util.HashMap;
012: import java.util.Locale;
013: import java.util.Map;
014: import javax.servlet.ServletConfig;
015: import javax.servlet.ServletException;
016: import javax.servlet.http.HttpServletRequest;
017: import javax.servlet.http.HttpServletResponse;
018:
019: import freemarker.template.Configuration;
020: import freemarker.template.Template;
021: import freemarker.template.TemplateException;
022: import org.apache.log4j.Logger;
023: import org.jfox.mvc.ActionContext;
024: import org.jfox.mvc.PageContext;
025: import org.jfox.mvc.Render;
026: import org.jfox.mvc.WebContextLoader;
027: import org.jfox.mvc.servlet.ControllerServlet;
028:
029: /**
030: * @author <a href="mailto:jfox.young@gmail.com">Young Yang</a>
031: */
032: public class FreemarkerRender implements Render {
033: static Logger logger = Logger.getLogger(FreemarkerRender.class);
034: /**
035: * Encoding for the output stream
036: */
037: public static final String DEFAULT_OUTPUT_ENCODING = "ISO-8859-1";
038:
039: /**
040: * The default content type for the response
041: */
042: public static final String DEFAULT_CONTENT_TYPE = "text/html";
043: private String defaultContentType = DEFAULT_CONTENT_TYPE;
044:
045: /**
046: * �个 Module 对应的 Configuration
047: * module view base dir => module's freemarker Configuration
048: */
049: private static Map<String, Configuration> baseDir2ConfigurationMap = new HashMap<String, Configuration>();
050:
051: public String getContentType() {
052: return DEFAULT_CONTENT_TYPE;
053: }
054:
055: public void init(ServletConfig config) throws ServletException {
056: logger.info("Initializaing Freemarker...");
057: try {
058: for (String moduleDirName : WebContextLoader
059: .getModuleDirNames()) {
060: String modulePath = WebContextLoader
061: .getModulePathByModuleDirName(moduleDirName);
062: File moduleDir = WebContextLoader
063: .getModuleDirByModuleDirName(moduleDirName);
064: String templateBaseDir = moduleDir.getCanonicalFile()
065: .getAbsoluteFile().getPath()
066: + "/" + ControllerServlet.getViewDir();
067:
068: Configuration configuration = new Configuration();
069: configuration
070: .setDefaultEncoding(ControllerServlet.DEFAULT_ENCODING);
071: configuration
072: .setOutputEncoding(ControllerServlet.DEFAULT_ENCODING);
073: configuration.setDirectoryForTemplateLoading(new File(
074: templateBaseDir));
075:
076: // 注册相对 module template base dirï¼Œä»¥ä¾¿æ ¹æ?®è®¿é—®çš„ URL,æ?¥åˆ¤æ–访问的Module,获得 VelocityEngine
077: baseDir2ConfigurationMap
078: .put(modulePath + "/"
079: + ControllerServlet.getViewDir(),
080: configuration);
081: }
082: logger.info("Freemarker engine initialized!");
083: } catch (Exception e) {
084: logger.error("Error initializing Freemarker: "
085: + e.getMessage(), e);
086: }
087: }
088:
089: public void render(HttpServletRequest request,
090: HttpServletResponse response) throws Exception {
091: response.setContentType(getContentType());
092: Locale locale = request.getLocale();
093: String servletPath = request.getServletPath();
094: processTemplate(getTemplate(servletPath, locale),
095: createFreemarkerContext(request, response), response);
096: }
097:
098: /**
099: * create VelocityContext and set key/value
100: *
101: * @param request http request
102: * @param response http response
103: */
104: protected Map createFreemarkerContext(HttpServletRequest request,
105: HttpServletResponse response) {
106: ActionContext actionContext = (ActionContext) request
107: .getAttribute(ControllerServlet.INVOCATION_CONTEXT);
108: PageContext pageContext = actionContext.getPageContext();
109: Map<String, Object> freemarkerMap = new HashMap<String, Object>(
110: pageContext.getResultMap());
111: return freemarkerMap;
112: }
113:
114: protected Template getTemplate(String servletPath, Locale locale)
115: throws IOException {
116: // 首先è¦?æ ¹æ?® servletPath 获得所访问的 Module,进而得到 Module çš„ VelocityEngine,用 startsWith 判æ–?
117: String templateName = null;
118: Configuration engine = null;
119: for (Map.Entry<String, Configuration> entry : baseDir2ConfigurationMap
120: .entrySet()) {
121: String baseDir = entry.getKey();
122: Configuration configuration = entry.getValue();
123: int index = servletPath.indexOf(baseDir);
124: if (index >= 0) {
125: engine = configuration;
126: templateName = servletPath.substring(index
127: + baseDir.length());
128: }
129: }
130: if (engine == null) {
131: throw new IOException(
132: "Can not found Framemarker engine for servlet path: "
133: + servletPath);
134: }
135:
136: return engine.getTemplate(templateName, locale);
137: }
138:
139: /**
140: * Process the FreeMarker template to the servlet response.
141: * <p>Can be overridden to customize the behavior.
142: *
143: * @param template the template to process
144: * @param model the model for the template
145: * @param response servlet response (use this to get the OutputStream or Writer)
146: * @throws IOException if the template file could not be retrieved
147: * @throws TemplateException if thrown by FreeMarker
148: * @see freemarker.template.Template#process(Object,java.io.Writer)
149: */
150: protected void processTemplate(Template template, Map model,
151: HttpServletResponse response) throws IOException,
152: TemplateException {
153: template.process(model, response.getWriter());
154: }
155:
156: /**
157: * Sets the content type of the response, defaulting to {@link
158: * #defaultContentType} if not overriden.
159: *
160: * @param request The servlet request from the client.
161: * @param response The servlet reponse to the client.
162: */
163: protected void setContentType(HttpServletRequest request,
164: HttpServletResponse response) {
165: String contentType = defaultContentType;
166: int index = contentType.lastIndexOf(';') + 1;
167: if (index <= 0
168: || (index < contentType.length() && contentType
169: .indexOf("charset", index) == -1)) {
170: // Append the character encoding which we'd like to use.
171: String encoding = ControllerServlet.DEFAULT_ENCODING;
172: //System.out.println("Chose output encoding of '" +
173: // encoding + '\'');
174: if (!DEFAULT_OUTPUT_ENCODING.equalsIgnoreCase(encoding)) {
175: contentType += "; charset=" + encoding;
176: }
177: }
178: response.setContentType(contentType);
179: }
180:
181: public static void main(String[] args) {
182:
183: }
184: }
|