Package com.alibaba.citrus.service.jsp.impl

Source Code of com.alibaba.citrus.service.jsp.impl.JspEngineImpl

/*
* Copyright (c) 2002-2012 Alibaba Group Holding Limited.
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*    http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.alibaba.citrus.service.jsp.impl;

import static com.alibaba.citrus.springext.util.SpringExtUtil.*;
import static com.alibaba.citrus.util.Assert.*;
import static com.alibaba.citrus.util.FileUtil.*;
import static com.alibaba.citrus.util.StringUtil.*;

import java.io.IOException;
import java.io.OutputStream;
import java.io.Writer;
import java.net.URL;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.alibaba.citrus.service.AbstractService;
import com.alibaba.citrus.service.jsp.JspEngine;
import com.alibaba.citrus.service.template.TemplateContext;
import com.alibaba.citrus.service.template.TemplateException;
import com.alibaba.citrus.service.template.TemplateNotFoundException;
import com.alibaba.citrus.util.ToStringBuilder;
import com.alibaba.citrus.util.ToStringBuilder.MapBuilder;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;

/**
* Jsp模板引擎的实现。
*
* @author Michael Zhou
*/
public class JspEngineImpl extends AbstractService<JspEngine> implements JspEngine, ResourceLoaderAware,
                                                                         InitializingBean {
    private final ServletContext      servletContext;
    private final HttpServletRequest  request;
    private final HttpServletResponse response;
    private       ResourceLoader      resourceLoader;
    private       String              contextRoot;
    private       String              path;

    /**
     * 创建jsp引擎。
     * <p>
     * 需要注意的是,用来创建jsp引擎的参数必须是“全局”作用域的,而不是“request”作用域的。这一点可由
     * <code>RequestContextChainingService</code>来保证。
     * </p>
     */
    public JspEngineImpl(ServletContext servletContext, HttpServletRequest request, HttpServletResponse response) {
        this.servletContext = assertNotNull(servletContext, "servletContext");
        this.request = assertProxy(assertNotNull(request, "request"));
        this.response = assertProxy(assertNotNull(response, "response"));
    }

    public void setResourceLoader(ResourceLoader resourceLoader) {
        this.resourceLoader = resourceLoader;
    }

    public void setPath(String path) {
        this.path = trimToNull(path);
    }

    @Override
    protected void init() throws Exception {
        assertNotNull(resourceLoader, "resourceLoader");

        // 取得搜索路径(相对)。
        if (path == null) {
            path = "/templates";
        }

        // 规格化路径,以"/"结尾。
        path = normalizeAbsolutePath(path + "/");

        // 取得webroot根目录的URL
        URL url = servletContext.getResource("/");

        if (url != null) {
            contextRoot = url.toExternalForm();
        } else {
            // 如果取不到webroot根目录,则试着取得web.xml的URL,以此为基准,计算相对于webroot的URL。
            url = servletContext.getResource("/WEB-INF/web.xml");

            if (url != null) {
                String urlstr = url.toExternalForm();

                if (urlstr.endsWith("/WEB-INF/web.xml")) {
                    contextRoot = urlstr.substring(0, urlstr.length() - "WEB-INF/web.xml".length());
                }
            }
        }

        if (contextRoot == null) {
            throw new IllegalArgumentException("Could not find WEBROOT.  Are you sure you are in webapp?");
        }

        if (!contextRoot.endsWith("/")) {
            contextRoot += "/";
        }

        if (getLogger().isDebugEnabled()) {
            MapBuilder mb = new MapBuilder();

            mb.append("path", path);
            mb.append("contextRoot", contextRoot);

            getLogger().debug(new ToStringBuilder().append("Initialized JSP Template Engine").append(mb).toString());
        }
    }

    /**
     * 取得默认的模板名后缀列表。
     * <p>
     * 当<code>TemplateService</code>没有指定到当前engine的mapping时,将取得本方法所返回的后缀名列表。
     * </p>
     */
    public String[] getDefaultExtensions() {
        return new String[] { "jsp", "jspx" };
    }

    /** 判定模板是否存在。 */
    public boolean exists(String templateName) {
        return getPathWithinServletContextInternal(templateName) != null;
    }

    /**
     * 渲染模板,并以字符串的形式取得渲染的结果。
     *
     * @param template 模板名
     * @param context  template context
     * @return 模板渲然的结果字符串
     * @throws TemplateException 渲染失败
     */
    public String getText(String template, TemplateContext context) throws TemplateException, IOException {
        // 取得JSP相对于webapp的路径。
        String relativeTemplateName = getPathWithinServletContext(template);

        // 取得JSP的RequestDispatcher。
        RequestDispatcher dispatcher = servletContext.getRequestDispatcher(relativeTemplateName);

        if (dispatcher == null) {
            throw new TemplateNotFoundException("Could not dispatch to JSP template " + template);
        }

        try {
            // 将template context适配到request
            HttpServletRequest requestWrapper = new TemplateContextAdapter(request, context);

            // 避免在jsp中修改content type、locale和charset,这应该在模板外部来控制
            HttpServletResponse responseWrapper = new JspResponse(response);

            dispatcher.include(requestWrapper, responseWrapper);
        } catch (ServletException e) {
            throw new TemplateException(e);
        }

        return "";
    }

    /** 渲染模板,并将渲染的结果送到字节输出流中。 */
    public void writeTo(String templateName, TemplateContext context, OutputStream ostream) throws TemplateException,
                                                                                                   IOException {
        getText(templateName, context);
    }

    /** 渲染模板,并将渲染的结果送到字符输出流中。 */
    public void writeTo(String templateName, TemplateContext context, Writer writer) throws TemplateException,
                                                                                            IOException {
        getText(templateName, context);
    }

    /**
     * 取得相对于servletContext的模板路径。这个路径可被
     * <code>javax.servlet.RequestDispatcher</code> 使用,以便找到jsp的实例。
     */
    public String getPathWithinServletContext(String templateName) throws TemplateNotFoundException {
        String path = getPathWithinServletContextInternal(templateName);

        if (path == null) {
            throw new TemplateNotFoundException("Template " + templateName + " not found");
        }

        return path;
    }

    private String getPathWithinServletContextInternal(String templateName) {
        assertInitialized();

        String resourceName = path + (templateName.startsWith("/") ? templateName.substring(1) : templateName);
        Resource resource = resourceLoader.getResource(resourceName);
        String path = null;

        if (resource != null && resource.exists()) {
            try {
                String url = resource.getURL().toExternalForm();

                if (url.startsWith(contextRoot)) {
                    path = url.substring(contextRoot.length() - 1); // 保留slash:/
                }
            } catch (IOException e) {
                // ignore
            }
        }

        return path;
    }

    @Override
    public String toString() {
        return "JspEngine[" + path + "]";
    }
}
TOP

Related Classes of com.alibaba.citrus.service.jsp.impl.JspEngineImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.