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

webit.script.Engine Maven / Gradle / Ivy

// Copyright (c) 2013-2014, Webit Team. All Rights Reserved.
package webit.script;

import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import webit.script.core.NativeFactory;
import webit.script.core.text.TextStatementFactory;
import webit.script.exceptions.ResourceNotFoundException;
import webit.script.global.GlobalManager;
import webit.script.io.Out;
import webit.script.io.charset.CoderFactory;
import webit.script.io.impl.DiscardOut;
import webit.script.lang.Bag;
import webit.script.lang.KeyValues;
import webit.script.loaders.Loader;
import webit.script.loggers.Logger;
import webit.script.resolvers.ResolverManager;
import webit.script.security.NativeSecurityManager;
import webit.script.util.ClassEntry;
import webit.script.util.ClassUtil;
import webit.script.util.KeyValuesUtil;
import webit.script.util.Petite;
import webit.script.util.Props;
import webit.script.util.PropsUtil;
import webit.script.util.StringUtil;

/**
 *
 * @author Zqq
 */
public final class Engine {

    public static final String UTF_8 = internEncoding("UTF-8");

    //settings
    private ClassEntry resourceLoaderType;
    private ClassEntry textStatementFactoryType;
    private ClassEntry nativeSecurityManagerType;
    private ClassEntry coderFactoryType;
    private ClassEntry globalManagerType;
    private ClassEntry loggerType;
    private ClassEntry resolverManagerType;
    private ClassEntry nativeFactoryType;
    private boolean looseVar;
    private boolean shareRootData = true;
    private boolean trimCodeBlockBlankLine = true;
    private boolean appendLostSuffix;
    private String suffix = ".wit";
    private String encoding = UTF_8;
    private String inits;
    private String[] vars;
    private String[] assistantSuffixs;

    private Logger logger;
    private Loader resourceLoader;
    private GlobalManager globalManager;
    private TextStatementFactory textStatementFactory;
    private NativeSecurityManager nativeSecurityManager;
    private CoderFactory coderFactory;
    private NativeFactory nativeFactory;
    private ResolverManager resolverManager;

    private final ConcurrentMap templateCache;
    private final Map componentContainer;
    private final Petite petite;

    private Engine(final Petite petite) {
        this.petite = petite;
        this.templateCache = new ConcurrentHashMap();
        this.componentContainer = new HashMap();
    }

    @SuppressWarnings("unchecked")
    private void init() {
        this.logger = (Logger) newComponentInstance(this.loggerType, webit.script.loggers.impl.NOPLogger.class);
        this.nativeFactory = (NativeFactory) newComponentInstance(this.nativeFactoryType, webit.script.asm.AsmNativeFactory.class);
        this.resolverManager = (ResolverManager) newComponentInstance(this.resolverManagerType, webit.script.asm.AsmResolverManager.class);
        this.coderFactory = (CoderFactory) newComponentInstance(this.coderFactoryType, webit.script.io.charset.impl.DefaultCoderFactory.class);
        this.nativeSecurityManager = (NativeSecurityManager) newComponentInstance(this.nativeSecurityManagerType, webit.script.security.impl.NoneNativeSecurityManager.class);
        this.textStatementFactory = (TextStatementFactory) newComponentInstance(this.textStatementFactoryType, webit.script.core.text.impl.SimpleTextStatementFactory.class);
        this.resourceLoader = (Loader) newComponentInstance(this.resourceLoaderType, webit.script.loaders.impl.ClasspathLoader.class);
        this.globalManager = (GlobalManager) newComponentInstance(this.globalManagerType, webit.script.global.GlobalManager.class);

        resolveComponent(this.logger, this.loggerType);
        this.petite.setLogger(this.logger);

        resolveComponent(this.nativeFactory, this.nativeFactoryType);
        resolveComponent(this.resolverManager, this.resolverManagerType);
        resolveComponent(this.coderFactory, this.coderFactoryType);
        resolveComponent(this.nativeSecurityManager, this.nativeSecurityManagerType);
        resolveComponent(this.textStatementFactory, this.textStatementFactoryType);
        resolveComponent(this.resourceLoader, this.resourceLoaderType);
        resolveComponent(this.globalManager, this.globalManagerType);

        this.globalManager.commit();
    }

    private void executeInitTemplates() throws ResourceNotFoundException {
        if (this.inits != null) {
            final Out out = new DiscardOut();
            final GlobalManager myGlobalManager = this.globalManager;
            final Bag globalBag = myGlobalManager.getGlobalBag();
            final Bag constBag = myGlobalManager.getGlobalBag();
            final KeyValues params = KeyValuesUtil.wrap(
                    new String[]{"GLOBAL", "CONST"},
                    new Object[]{globalBag, constBag}
            );
            for (String templateName : StringUtil.toArray(this.inits)) {
                if (this.logger.isInfoEnabled()) {
                    this.logger.info("Merge init template: {}", templateName);
                }
                this.getTemplate(templateName)
                        .merge(params, out);
                //Commit Global
                myGlobalManager.commit();
            }
        }
    }

    /**
     * get config by key form engine
     *
     * @since 1.4.0
     * @param key
     * @return config value
     */
    public Object getConfig(String key) {
        return this.petite.get(key);
    }

    /**
     *
     * @since 1.4.0
     */
    private void resolveComponent(final Object bean, final ClassEntry type) {
        String beanName = type != null
                ? type.profile
                : Petite.resolveBeanName(bean);
        this.petite.wireBean(beanName, bean);
        if (bean instanceof Initable) {
            ((Initable) bean).init(this);
        }
        this.componentContainer.put(beanName, bean);
    }

    /**
     *
     * @param type
     * @return Component
     * @since 1.4.0
     */
    public Object getComponent(final Class type) {
        return getComponent(ClassEntry.wrap(type));
    }

    /**
     *
     * @param type
     * @return Component
     * @since 1.4.0
     */
    public synchronized Object getComponent(final ClassEntry type) {
        Object bean = this.componentContainer.get(type.profile);
        if (bean == null) {
            bean = ClassUtil.newInstance(type.value);
            resolveComponent(bean, type);
        }
        return bean;
    }

    /**
     * get template by parent template's name and it's relative name.
     *
     * @param parentName parent template's name
     * @param name template's relative name
     * @return Template
     * @throws ResourceNotFoundException
     */
    public Template getTemplate(final String parentName, final String name) throws ResourceNotFoundException {
        return getTemplate(this.resourceLoader.concat(parentName, name));
    }

    /**
     * get template by name.
     *
     * @param name template's name
     * @return Template
     * @throws ResourceNotFoundException
     */
    public Template getTemplate(final String name) throws ResourceNotFoundException {
        final Template template;
        if ((template = this.templateCache.get(name)) != null) {
            return template;
        } else {
            return createTemplateIfAbsent(name);
        }
    }

    /**
     * if exists this resource.
     *
     * @param resourceName
     * @return boolean
     * @since 1.4.1
     */
    public boolean exists(final String resourceName) {
        final String normalizedName;
        final Loader loader;
        if ((normalizedName = (loader = this.resourceLoader).normalize(resourceName)) != null) {
            return loader.get(normalizedName).exists();
        }
        return false;
    }

    private Template createTemplateIfAbsent(final String name) throws ResourceNotFoundException {
        Template template;
        final Loader loader = this.resourceLoader;
        final String normalizedName = loader.normalize(name);
        if (normalizedName == null) {
            //if normalized-name is null means not found resource.
            throw new ResourceNotFoundException("Illegal template path: ".concat(name));
        }
        template = this.templateCache.get(normalizedName);
        if (template == null) {
            //then create Template
            template = new Template(this, normalizedName,
                    loader.get(normalizedName));
            if (loader.isEnableCache(normalizedName)) {
                Template oldTemplate;
                oldTemplate = this.templateCache.putIfAbsent(normalizedName, template);
                //if old Template exist, use the old one
                if (oldTemplate != null) {
                    template = oldTemplate;
                }
                if (!name.equals(normalizedName)) {
                    // cache Template with un-normalized name
                    oldTemplate = this.templateCache.putIfAbsent(name, template);
                    if (oldTemplate != null) {
                        template = oldTemplate;
                    }
                }
            }
        }
        return template;
    }

    public boolean checkNativeAccess(String path) {
        return this.nativeSecurityManager.access(path);
    }

    /**
     * @since 1.5.0
     */
    public void setNativeFactory(ClassEntry nativeFactory) {
        this.nativeFactoryType = nativeFactory;
    }

    /**
     * @since 1.5.0
     */
    public void setResolverManager(ClassEntry resolverManager) {
        this.resolverManagerType = resolverManager;
    }

    public void setNativeSecurityManager(ClassEntry nativeSecurityManager) {
        this.nativeSecurityManagerType = nativeSecurityManager;
    }

    public void setCoderFactory(ClassEntry coderFactory) {
        this.coderFactoryType = coderFactory;
    }

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

    public void setTextStatementFactory(ClassEntry textStatementFactory) {
        this.textStatementFactoryType = textStatementFactory;
    }

    public void setGlobalManager(ClassEntry globalManager) {
        this.globalManagerType = globalManager;
    }

    public void setLogger(ClassEntry logger) {
        this.loggerType = logger;
    }

    /**
     *
     * @since 1.4.0
     * @return Loader
     */
    public Loader getResourceLoader() {
        return resourceLoader;
    }

    public String getEncoding() {
        return encoding;
    }

    public void setEncoding(String encoding) {
        if (encoding != null) {
            this.encoding = internEncoding(encoding);
        }
        //else ignore
    }

    public NativeFactory getNativeFactory() {
        return nativeFactory;
    }

    public boolean isLooseVar() {
        return looseVar;
    }

    public void setLooseVar(boolean looseVar) {
        this.looseVar = looseVar;
    }

    public boolean isShareRootData() {
        return shareRootData;
    }

    public void setShareRootData(boolean shareRootData) {
        this.shareRootData = shareRootData;
    }

    public boolean isTrimCodeBlockBlankLine() {
        return trimCodeBlockBlankLine;
    }

    public void setTrimCodeBlockBlankLine(boolean trimCodeBlockBlankLine) {
        this.trimCodeBlockBlankLine = trimCodeBlockBlankLine;
    }

    public NativeSecurityManager getNativeSecurityManager() {
        return nativeSecurityManager;
    }

    public ResolverManager getResolverManager() {
        return resolverManager;
    }

    public TextStatementFactory getTextStatementFactory() {
        return textStatementFactory;
    }

    public CoderFactory getCoderFactory() {
        return coderFactory;
    }

    public GlobalManager getGlobalManager() {
        return globalManager;
    }

    public Logger getLogger() {
        return logger;
    }

    public boolean isAppendLostSuffix() {
        return appendLostSuffix;
    }

    public void setAppendLostSuffix(boolean appendLostSuffix) {
        this.appendLostSuffix = appendLostSuffix;
    }

    public String getSuffix() {
        return suffix;
    }

    public void setSuffix(String suffix) {
        this.suffix = suffix;
    }

    public String[] getVars() {
        return vars;
    }

    public void setVars(String vars) {
        this.vars = StringUtil.toArray(vars);
    }

    public String[] getAssistantSuffixs() {
        return assistantSuffixs;
    }

    public void setAssistantSuffixs(String assistantSuffixs) {
        this.assistantSuffixs = StringUtil.toArray(assistantSuffixs);
    }

    public void setInits(String inits) {
        this.inits = inits;
    }

    /**
     * @since 1.5.0
     */
    private static Object newComponentInstance(ClassEntry classEntry, Class defaultType) {
        if (classEntry == null) {
            return ClassUtil.newInstance(defaultType);
        }
        return ClassUtil.newInstance(classEntry.value);
    }

    public static Props createConfigProps(final String configPath) {
        return PropsUtil.loadFromClasspath(new Props(), CFG.DEFAULT_WIM, configPath);
    }

    /**
     * Create a Engine with default configPath.
     *
     * @return
     * @since 1.5.0
     */
    public static Engine create() {
        return create("", null);
    }

    /**
     * Create a Engine with given configPath.
     *
     * @param configPath
     * @return
     * @since 1.5.0
     */
    public static Engine create(final String configPath) {
        return create(configPath, null);
    }

    /**
     * Create a Engine with given configPath and extra-parameters.
     *
     * @param configPath
     * @param parameters
     * @return
     * @since 1.5.0
     */
    public static Engine create(final String configPath, final Map parameters) {
        return create(createConfigProps(configPath), parameters);
    }

    /**
     * Create a Engine with given baseProps and extra-parameters.
     *
     * @param props
     * @param parameters
     * @return
     * @since 1.5.0
     */
    public static Engine create(final Props props, final Map parameters) {

        final Petite petite = new Petite();
        petite.set(props, parameters);

        final Engine engine = new Engine(petite);
        petite.wireBean(engine);

        engine.init();
        if (engine.getLogger().isInfoEnabled()) {
            engine.getLogger().info("Loaded props: {}", petite.get(CFG.WIM_FILE_LIST));
        }
        try {
            engine.executeInitTemplates();
        } catch (ResourceNotFoundException ex) {
            throw new RuntimeException(ex);
        }
        return engine;
    }

    /**
     * @deprecated
     */
    @Deprecated
    public static Engine createEngine(final String configPath) {
        return create(configPath, null);
    }

    /**
     * @deprecated
     */
    @Deprecated
    public static Engine createEngine(final String configPath, final Map parameters) {
        return create(configPath, parameters);
    }

    /**
     *
     * @deprecated
     */
    @Deprecated
    public static Engine createEngine(final Props props, final Map parameters) {
        return create(props, parameters);
    }

    /**
     * Intern encoding
     *
     * @param encoding
     * @return
     * @since 1.5.0
     */
    public static String internEncoding(final String encoding) {
        try {
            return Charset.forName(encoding).name();
        } catch (Exception e) {
            return encoding.intern();
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy