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

com.astamuse.asta4d.snippet.resolve.DefaultSnippetResolver Maven / Gradle / Ivy

Go to download

core functionalities of asta4d framework, including template and snippt implemention

There is a newer version: 1.2-M2
Show newest version
/*
 * Copyright 2012 astamuse company,Ltd.
 * 
 * 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.astamuse.asta4d.snippet.resolve;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import com.astamuse.asta4d.Configuration;
import com.astamuse.asta4d.Context;
import com.astamuse.asta4d.render.Renderer;
import com.astamuse.asta4d.snippet.SnippetDeclarationInfo;
import com.astamuse.asta4d.snippet.SnippetExcecutionInfo;
import com.astamuse.asta4d.snippet.SnippetNotResovlableException;
import com.astamuse.asta4d.util.MultiSearchPathResourceLoader;

public class DefaultSnippetResolver extends MultiSearchPathResourceLoader implements SnippetResolver {

    private final static String InstanceMapCacheKey = DefaultSnippetResolver.class.getName() + "##InstanceMapCacheKey";

    private final static ConcurrentHashMap MethodCache = new ConcurrentHashMap<>();

    @Override
    public SnippetExcecutionInfo resloveSnippet(SnippetDeclarationInfo declaration) throws SnippetNotResovlableException {
        Object instance = retrieveInstance(declaration);
        Method method = retrieveMethod(declaration);
        return new SnippetExcecutionInfo(declaration, instance, method);
    }

    protected Object retrieveInstance(SnippetDeclarationInfo declaration) throws SnippetNotResovlableException {
        String snippetName = declaration.getSnippetName();
        Map instanceMap = getCacheMap(InstanceMapCacheKey);
        Object instance = instanceMap.get(snippetName);
        if (instance == null) {
            instance = createInstance(snippetName);
            instanceMap.put(snippetName, instance);
        }
        return instance;
    }

    protected Object createInstance(String snippetName) throws SnippetNotResovlableException {
        try {
            Object instance = super.searchResource(".", snippetName);
            if (instance == null) {
                throw new ClassNotFoundException("Can not found class for snippet name:" + snippetName);
            }
            return instance;
        } catch (Exception ex) {
            throw new SnippetNotResovlableException(String.format("Snippet [%s] resolve failed.", snippetName), ex);
        }
    }

    @Override
    protected Object loadResource(String name) {
        Class clz = null;
        try {
            clz = Class.forName(name);
        } catch (ClassNotFoundException e) {
            return null;
        }
        try {
            return clz.newInstance();
        } catch (InstantiationException | IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

    protected Method retrieveMethod(SnippetDeclarationInfo declaration) throws SnippetNotResovlableException {
        Method m = Configuration.getConfiguration().isCacheEnable() ? MethodCache.get(declaration) : null;
        if (m == null) {
            Object instance = retrieveInstance(declaration);
            m = findSnippetMethod(instance, declaration.getSnippetHandler());
            if (m == null) {
                throw new SnippetNotResovlableException("Snippet handler cannot be resolved for " + declaration);
            }
            // we do not mind that the exited method instance would be
            // overrode in multi-threads environment
            MethodCache.put(declaration, m);
        }
        return m;
    }

    protected Method findSnippetMethod(Object snippetInstance, String methodName) {
        Method[] methodList = snippetInstance.getClass().getMethods();
        Class rendererCls = Renderer.class;
        for (Method method : methodList) {
            if (method.getName().equals(methodName) && rendererCls.isAssignableFrom(method.getReturnType())) {
                return method;
            }
        }
        return null;
    }

    private Map getCacheMap(String key) {
        Context context = Context.getCurrentThreadContext();
        Map map = context.getData(key);
        if (map == null) {
            map = new HashMap<>();
            context.setData(key, map);
        }
        return map;
    }

}