All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.noear.solon.view.beetl.BeetlRender Maven / Gradle / Ivy

There is a newer version: 3.0.0-RC
Show newest version
/*
 * Copyright 2017-2024 noear.org and authors
 *
 * 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
 *
 *      https://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 org.noear.solon.view.beetl;

import org.beetl.core.Configuration;
import org.beetl.core.GroupTemplate;
import org.beetl.core.Template;
import org.beetl.core.resource.ClasspathResourceLoader;
import org.beetl.core.resource.FileResourceLoader;
import org.beetl.core.statement.ErrorGrammarProgram;
import org.beetl.core.tag.Tag;
import org.beetl.core.tag.TagFactory;
import org.noear.solon.Solon;
import org.noear.solon.boot.web.DebugUtils;
import org.noear.solon.core.AppClassLoader;
import org.noear.solon.core.event.EventBus;
import org.noear.solon.core.handle.Render;
import org.noear.solon.core.handle.ModelAndView;
import org.noear.solon.core.handle.Context;
import org.noear.solon.core.util.ResourceUtil;
import org.noear.solon.core.util.SupplierEx;
import org.noear.solon.view.ViewConfig;
import org.noear.solon.boot.ServerProps;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.OutputStream;
import java.net.URI;
import java.net.URL;

/**
 * Beetl 视图渲染器
 *
 * @author noear
 * @since 1.0
 * */
public class BeetlRender implements Render {
    static final Logger log = LoggerFactory.getLogger(BeetlRender.class);

    private static BeetlRender _global;

    public static BeetlRender global() {
        if (_global == null) {
            _global = new BeetlRender();
        }

        return _global;
    }



    private final ClassLoader classLoader;
    private final String viewPrefix;

    private Configuration config = null;

    private GroupTemplate provider = null;
    private GroupTemplate providerOfDebug = null;

    /**
     * 引擎提供者
     * */
    public GroupTemplate getProvider() {
        return provider;
    }

    /**
     * 引擎提供者(调试模式)
     * */
    public GroupTemplate getProviderOfDebug() {
        return providerOfDebug;
    }

    /**
     * 获取配置
     * */
    public Configuration getConfig() {
        return config;
    }

    //不要要入参,方便后面多视图混用
    //
    public BeetlRender() {
        this(AppClassLoader.global(), null);
    }

    public BeetlRender(ClassLoader classLoader) {
        this(classLoader, null);
    }

    public BeetlRender(ClassLoader classLoader, String viewPrefix) {
        this.classLoader = classLoader;
        if(viewPrefix == null){
            this.viewPrefix = ViewConfig.getViewPrefix();
        }else {
            this.viewPrefix = viewPrefix;
        }

        try {
            config = Configuration.defaultConfiguration();
            config.setCharset(ServerProps.response_encoding);
            config.setNativeCall(true);
            config.setNativeSecurity("org.beetl.core.DefaultNativeSecurityManager");
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }

        forDebug();
        forRelease();

        Solon.app().shared().forEach((k, v) -> {
            putVariable(k, v);
        });

        Solon.app().onSharedAdd((k, v) -> {
            putVariable(k, v);
        });
    }

    private void forDebug() {
        if (Solon.cfg().isDebugMode() == false) {
            return;
        }

        if (Solon.cfg().isFilesMode() == false) {
            return;
        }

        if (providerOfDebug != null) {
            return;
        }

        //添加调试模式
        File dir = DebugUtils.getDebugLocation(classLoader, viewPrefix);

        if(dir == null){
            return;
        }

        try {
            if (dir.exists()) {
                FileResourceLoader loader = new FileResourceLoader(dir.getPath(), Solon.encoding());
                loader.setAutoCheck(true);
                providerOfDebug = new GroupTemplate(loader, config);

                //通过事件扩展
                EventBus.publish(providerOfDebug);
            }
        } catch (Exception e) {
            log.warn(e.getMessage(), e);
        }
    }

    private void forRelease() {
        if (provider != null) {
            return;
        }

        try {
            if (ResourceUtil.hasFile(viewPrefix)) {
                //file:...
                URL dir = ResourceUtil.findResource(classLoader, viewPrefix, false);
                FileResourceLoader loader = new FileResourceLoader(dir.getFile(), Solon.encoding());
                providerOfDebug = new GroupTemplate(loader, config);
            } else {
                ClasspathResourceLoader loader = new ClasspathResourceLoader(classLoader, viewPrefix);
                provider = new GroupTemplate(loader, config);
            }

            //通过事件扩展
            EventBus.publish(provider);
        } catch (Exception e) {
            log.warn(e.getMessage(), e);
        }
    }

    /**
     * 添加共享指令(自定义标签)
     */
    public void putDirective(String name, Class clz) {
        try {
            provider.registerTag(name, clz);

            if (providerOfDebug != null) {
                providerOfDebug.registerTag(name, clz);
            }
        } catch (Exception e) {
            log.warn(e.getMessage(), e);
        }
    }

    /**
     * 添加共享指令(自定义标签)
     */
    public void putDirective(String name, TagFactory tagFactory) {
        try {
            provider.registerTagFactory(name, tagFactory);

            if (providerOfDebug != null) {
                providerOfDebug.registerTagFactory(name, tagFactory);
            }
        } catch (Exception e) {
            log.warn(e.getMessage(), e);
        }
    }

    /**
     * 添加共享变量
     */
    public void putVariable(String name, Object value) {
        try {
            provider.getSharedVars().put(name, value);

            if (providerOfDebug != null) {
                providerOfDebug.getSharedVars().put(name, value);
            }
        } catch (Exception e) {
            log.warn(e.getMessage(), e);
        }
    }

    @Override
    public void render(Object obj, Context ctx) throws Throwable {
        if (obj == null) {
            return;
        }

        if (obj instanceof ModelAndView) {
            render_mav((ModelAndView) obj, ctx, () -> ctx.outputStream());
        } else {
            ctx.output(obj.toString());
        }
    }

    @Override
    public String renderAndReturn(Object obj, Context ctx) throws Throwable {
        if (obj == null) {
            return null;
        }

        if (obj instanceof ModelAndView) {
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            render_mav((ModelAndView) obj, ctx, () -> outputStream);

            return outputStream.toString();
        } else {
            return obj.toString();
        }
    }

    private void render_mav(ModelAndView mv, Context ctx, SupplierEx outputStream) throws Throwable {
        if (ctx.contentTypeNew() == null) {
            ctx.contentType("text/html;charset=utf-8");
        }

        if (ViewConfig.isOutputMeta()) {
            ctx.headerSet(ViewConfig.HEADER_VIEW_META, "BeetlRender");
        }

        //添加 context 变量
        mv.putIfAbsent("context", ctx);

        Template template = null;

        if (providerOfDebug != null) {
            try {
                template = providerOfDebug.getTemplate(mv.view());
                if (template != null && template.program instanceof ErrorGrammarProgram) {
                    template = null;
                }
            }catch (Exception e){
                //忽略不计
            }
        }

        if (template == null) {
            template = provider.getTemplate(mv.view());
        }


        template.binding(mv.model());
        template.renderTo(outputStream.get());
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy