001/**
002 * Copyright (c) 2015-2022, Michael Yang 杨福海 (fuhai999@gmail.com).
003 * <p>
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 * <p>
008 * http://www.apache.org/licenses/LICENSE-2.0
009 * <p>
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package io.jboot.web.render;
017
018import com.jfinal.render.Render;
019import com.jfinal.render.RenderException;
020import com.jfinal.render.RenderManager;
021import com.jfinal.template.Engine;
022import io.jboot.Jboot;
023import io.jboot.utils.StrUtil;
024import io.jboot.web.render.cdn.JbootWebCdnConfig;
025import io.jboot.ext.MixedByteArrayOutputStream;
026import io.jboot.web.render.cdn.CdnUtil;
027
028import java.io.IOException;
029import java.io.PrintWriter;
030import java.util.Enumeration;
031import java.util.HashMap;
032import java.util.Map;
033
034public class JbootRender extends Render {
035
036    private static Engine engine;
037    private static String contentType = "text/html; charset=" + getEncoding();
038    private static JbootWebCdnConfig cdnConfig = Jboot.config(JbootWebCdnConfig.class);
039
040    private Engine getEngine() {
041        if (engine == null) {
042            engine = RenderManager.me().getEngine();
043        }
044        return engine;
045    }
046
047    public JbootRender(String view) {
048        if (StrUtil.isBlank(view)){
049            throw new IllegalArgumentException("view cannot be null or empty.");
050        }
051        this.view = view;
052    }
053
054    public String getContentType() {
055        return contentType;
056    }
057
058    @Override
059    public void render() {
060        response.setContentType(getContentType());
061
062        Map<Object, Object> data = new HashMap<Object, Object>();
063        for (Enumeration<String> attrs = request.getAttributeNames(); attrs.hasMoreElements(); ) {
064            String attrName = attrs.nextElement();
065            data.put(attrName, request.getAttribute(attrName));
066        }
067
068        try {
069            if (cdnConfig.isEnable()) {
070                renderWithCdn(data);
071            } else {
072                getEngine().getTemplate(view).render(data, response.getWriter());
073            }
074        } catch (RuntimeException e) {    // 捕获 ByteWriter.close() 抛出的 RuntimeException
075            Throwable cause = e.getCause();
076            if (cause instanceof IOException) {    // ClientAbortException、EofException 直接或间接继承自 IOException
077                String name = cause.getClass().getSimpleName();
078                if ("ClientAbortException".equals(name) || "EofException".equals(name)) {
079                    return;
080                }
081            }
082            throw e;
083        } catch (IOException e) {
084            throw new RenderException(e);
085        }
086    }
087
088    private void renderWithCdn(Map<Object, Object> data) throws IOException {
089        MixedByteArrayOutputStream baos = new MixedByteArrayOutputStream();
090        getEngine().getTemplate(view).render(data, baos);
091
092        PrintWriter responseWriter = response.getWriter();
093        responseWriter.write(CdnUtil.toHtml(baos.getInputStream(), cdnConfig.getDomain()));
094    }
095
096
097    @Override
098    public String toString() {
099        return view;
100    }
101
102
103}