Package cambridge

Source Code of cambridge.Cambridge$BindStatic

package cambridge;

import cambridge.behaviors.AltAdderStaticBehavior;
import cambridge.behaviors.ConditionalAttributeBehavior;
import cambridge.behaviors.ElseBehavior;
import cambridge.behaviors.ElseIfBehavior;
import cambridge.behaviors.ForeachBehavior;
import cambridge.behaviors.FromBehavior;
import cambridge.behaviors.HideBehavior;
import cambridge.behaviors.IfBehavior;
import cambridge.behaviors.OverridesStaticBehavior;
import cambridge.behaviors.RepeatBehavior;
import cambridge.behaviors.SelectedBehavior;
import cambridge.behaviors.WhileBehavior;
import cambridge.behaviors.WithBehavior;
import cambridge.model.Attribute;
import cambridge.model.AttributeKey;
import cambridge.model.DynamicAttribute;
import cambridge.parser.expressions.FunctionRunner;
import cambridge.parser.expressions.IfFunction;
import cambridge.parser.expressions.ResourceBundleFunction;
import cambridge.parser.expressions.StaticMethodCaller;
import cambridge.runtime.Filter;
import cambridge.runtime.LowerCaseFilter;
import cambridge.runtime.SimpleDateFormatFilter;
import cambridge.runtime.UpperCaseFilter;
import cambridge.tags.DummyTag;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;

/**
* <p>Cambridge is a singleton which holds mappings of names to behaviors, functions, filters
* etc.</p>
* <p/>
* <p>If new behaviors are to be added or the default ones are to be overridden, this
* can be achieved by getting an instance of Cambridge first</p>
*/
public class Cambridge {
    private static Cambridge instance;

    public static String DefaultNamespaceURI = "http://cambridge.googlecode.com";

    private final HashMap<String, FunctionRunner> functions = new HashMap<String, FunctionRunner>();
    private final HashMap<String, Class<? extends Filter>> filters = new HashMap<String, Class<? extends Filter>>();
    private final HashSet<String> namespaces;
    private final HashMap<String, String> namespaceMappings;
    private final HashMap<DynamicAttributeKey, BehaviorProvider<? extends TagBehavior>> providers;
    private final HashMap<DynamicAttributeKey, Class<? extends StaticBehavior>> staticBehaviorClasses;
    private final HashMap<DynamicAttributeKey, StaticBehavior> staticBehaviors;
    private final HashMap<DynamicAttributeKey, Class<? extends DynamicTag>> dynamicTagClasses;
    private final HashMap<DynamicAttributeKey, DynamicTagProvider> dynamicTagProviders;

    /**
     * This is an internal class to support the builder pattern for binding behaviors
     */
    public class Bind {
        final DynamicAttributeKey k;

        Bind(DynamicAttributeKey k) {
            this.k = k;
        }

        public void to(BehaviorProvider<? extends TagBehavior> provider) {
            providers.put(k, provider);
        }
    }

    /**
     * This is an internal class to support the builder pattern for binding static behaviors
     */
    public class BindStatic {
        final DynamicAttributeKey k;

        BindStatic(DynamicAttributeKey k) {
            this.k = k;
        }

        public void to(Class<? extends StaticBehavior> behaviorClass) {
            staticBehaviorClasses.put(k, behaviorClass);
        }
    }

    /**
     * This is an internal class to support the builder pattern for binding tags
     */
    public class BindTag {
        final DynamicAttributeKey[] keys;

        BindTag(DynamicAttributeKey[] k) {
            this.keys = k;
        }

        public void to(Class<? extends DynamicTag> tagClass) {
            for (DynamicAttributeKey k : keys) {
                dynamicTagClasses.put(k, tagClass);
            }
        }

        public void toProvider(DynamicTagProvider provider) {
            for (DynamicAttributeKey k : keys) {
                dynamicTagProviders.put(k, provider);
            }
        }
    }

    /**
     * <p>Maps the provided function name to the Function implementation.</p>
     * <p/>
     * <p>These registered functions are only available if you use the built-in expression language.
     * If you decide to use MVEL or OGNL as your expression language, you should consult
     * the documentation of that project in defining functions</p>
     *
     * @param name   Function name
     * @param runner Function runner
     * @see FunctionRunner The implementation of a function
     */
    public void registerFunction(String name, FunctionRunner runner) {
        functions.put(name, runner);
    }

    /**
     * FunctionRunners are classes that implement a function in Cambridge Template Engine
     * Expression Language.
     * <p/>
     * This method returns the instance of a FunctionRunner by name. FunctionRunner implementations
     * should be thread safe.
     *
     * @param name Name of the FunctionRunner
     * @return Returns an instance of FunctionRunner if there is one with the name provided.
     *         Returns null otherwise.
     */
    public FunctionRunner getFunctionRunner(String name) {
        return functions.get(name);
    }

    /**
     * Registers an expression filter for the given name to be used in built in
     * Expression Language. Filters are used to format variable rendering.
     *
     * @param name   Name of the filter
     * @param filter Class implementing the filter
     */
    public void registerFilter(String name, Class<? extends Filter> filter) {
        filters.put(name.toLowerCase(), filter);
    }

    /**
     * Returns an instance of Filter by name. During template parsing/compilation
     * phase, an instance of Filter is created for each time it is used in a template.
     * The same Filter instance gets re-used throughout template document lifecycle.
     *
     * @param name Name of the filter to be returned.
     * @param line Line number on the template which tries to instantiate a filter instance
     * @param col Column number on the template which tries to instantiate a filter instance
     * @return Returns an instance of the Filter
     * @throws TemplateParsingException Might be thrown if the filter is unknown or can not be instantiated.
     */
    public Filter getFilter(String name, int line, int col) throws TemplateParsingException {
        try {
            String key = name.toLowerCase();
            Class<? extends Filter> filterClass = filters.get(key);

            if (filterClass == null)
            {
                throw new TemplateParsingException("Unknown filter: " + name, line, col);
            }

            return filterClass.newInstance();
        } catch (InstantiationException e) {
            throw new TemplateParsingException("Could not instantiate filter: " + name, e, line, col);
        } catch (IllegalAccessException e) {
            throw new TemplateParsingException("Could not instantiate filter: " + name, e, line, col);
        }
    }

    /**
     * Maps the specified namespace uri to provided name or names as default name for
     * the namespace uri.
     * <p/>
     * For cambridge template engine's built-in behaviors and tags, "a" is the default
     * namespace short name. If you create your own behaviors or tags, you can
     * use this method to map your namespace uri to a default namespace.
     * <p/>
     * Behavior libraries may also call this method to set default namespace for
     * the behaviors or tags that they provide.
     *
     * @param uri   URI of the behavior or tag
     * @param names List of names that may be used as default names.
     */
    public void mapNamespace(String uri, String... names) {
        for (String n : names) {
            namespaceMappings.put(n, uri);
        }
    }

    /**
     * Returns the namespace uri for the given name if there is a previously set
     * matching default name for the namespace uri.
     *
     * @param name Namespace name
     * @return Returns the URI if the provided name is the default name for a namespace
     */
    public String getDefaultNamespace(String name) {
        return namespaceMappings.get(name);
    }

    /**
     * Bind an attribute with the specified namespace uri and attribute name
     * to a dynamic behavior. The returned Bind object should be used to complete
     * the mapping to a Behavior Provider.
     *
     * @param uri       Namespace uri
     * @param attribute Attribute name
     * @return Returns a Bind object which will be used to map the namespace to a Behavior.
     */
    public Bind bind(String uri, String attribute) {
        DynamicAttributeKey key = new DynamicAttributeKey(uri, "", attribute);
        namespaces.add(uri);
        return new Bind(key);
    }

    /**
     * Bind an attribute with the specified namespace uri and the attribute name
     * as a static behavior. The returned BindStatic object should be used to
     * complete the mapping to class that implements {@link StaticBehavior}
     *
     * @param uri       Namespace uri
     * @param attribute Attribute name
     * @return Returns a BindStatic object which will be used to map the namespace to a StaticBehavior class.
     */
    public BindStatic bindStatic(String uri, String attribute) {
        DynamicAttributeKey key = new DynamicAttributeKey(uri, "", attribute);
        namespaces.add(uri);
        return new BindStatic(key);
    }

    /**
     * Checks if there is a static behavior that is defined for the supplied namespace
     * uri and the attribute name.
     *
     * @param uri       Namespace uri
     * @param attribute Attribute name
     * @return Returns true if the attribute is defined as a static behavior attribute.
     */
    public boolean isStaticAttribute(String uri, String attribute) {
        DynamicAttributeKey key = new DynamicAttributeKey(uri, "", attribute);
        return staticBehaviorClasses.containsKey(key);
    }

    /**
     * Binds a tag which has the supplied namespace uri and the provided tag name
     * or names (Multiple tag names may be used as aliases) to a class that extends
     * {@link DynamicTag}.
     *
     * @param uri     Namespace uri
     * @param tagName Name of the tag with aliases
     * @return Returns a BindTag object that should be used to complete the mapping to the Tag class.
     */
    public BindTag bindTag(String uri, String... tagName) {
        namespaces.add(uri);

        DynamicAttributeKey[] keys = new DynamicAttributeKey[tagName.length];
        for (int i = 0; i < tagName.length; i++) {
            String a = tagName[i];
            keys[i] = new DynamicAttributeKey(uri, "", a);
        }

        return new BindTag(keys);
    }

    /**
     * Checks if the supplied uri has been registered for a tag behavior or tag.
     *
     * @param uri Namespace uri
     * @return Returns true if the namespace uri has been registered
     */
    public boolean isRegisteredNamespace(String uri) {
        return namespaces.contains(uri);
    }

    /**
     * Using the BehaviorProvider that is registered for a specific namespace uri and attribute name
     * that is supplied (as a DynamicAttributeKey object), this method creates a new instance of the
     * TagBehavior and returns it. This method is called internally while template parsing occurs.
     *
     * @param key        The attribute key which identifies the attribute with the namespace uri and attribute name.
     * @param attributes Other attributes of the tag that has this dynamic attribute.
     * @param line       Line number of the tag attribute that is initiating this behavior
     * @param col        Column number of the tag attribute that is initiating this behavior
     * @return Returns an instance of TagBehavior for the matching behavior implementation.
     * @throws BehaviorInstantiationException
     * @throws ExpressionParsingException
     */
    public TagBehavior getBehavior(DynamicAttributeKey key, Map<AttributeKey, Attribute> attributes, int line, int col) throws BehaviorInstantiationException, ExpressionParsingException {
        BehaviorProvider<? extends TagBehavior> provider = providers.get(key);

        if (provider != null) {
            return provider.get((DynamicAttribute) attributes.get(key.toAttributeKey()), attributes, line, col);
        }

        return null;
    }

    /**
     * If there is any static behavior assigned to the supplied DynamicAttributeKey object,
     * this method creates and returns an instance of that.
     * <p/>
     * If there is no static behavior associated with the supplied key, it returns null.
     *
     * @param key Dynamic attribute key (Namespace uri + attribute name)
     * @return Returns a new instance of StaticBehavior for the supplied static attribute.
     */
    public StaticBehavior getStaticBehavior(DynamicAttributeKey key) {
        StaticBehavior b = staticBehaviors.get(key);
        if (b != null) {
            return b;
        }

        Class<? extends StaticBehavior> clazz = staticBehaviorClasses.get(key);
        if (clazz == null) {
            return null;
        }

        try {
            b = clazz.newInstance();
            staticBehaviors.put(key, b);
            return b;
        } catch (InstantiationException e) {
            return null;
        } catch (IllegalAccessException e) {
            return null;
        }
    }

    /**
     * Creates and returns an instance of DynamicTag for the supplied dynamic attribute
     * key. If there is no dynamic tag associated with the supplied key, returns null.
     *
     * @param key Dynamic attribute key.
     * @return Returns a new instance of DynamicTag for the supplied key.
     */
    public DynamicTag getDynamicTag(DynamicAttributeKey key) {
        Class<? extends DynamicTag> clazz = dynamicTagClasses.get(key);
        if (clazz == null) {
            DynamicTagProvider provider = dynamicTagProviders.get(key);

            if (provider != null) {
                return provider.getInstance();
            }

            return null;
        }

        try {
            return clazz.newInstance();
        } catch (IllegalAccessException e) {
            return null;
        } catch (InstantiationException e) {
            return null;
        }
    }

    /**
     * @return Returns the Cambridge singleton.
     */
    public static Cambridge getInstance() {
        if (instance != null) {
            return instance;
        }

        synchronized (Cambridge.class) {
            if (instance == null) {
                instance = new Cambridge();
            }

            return instance;
        }
    }

    /**
     * Initializes the internal collections and sets up the default/built-in behaviors and tags.
     */
    protected Cambridge() {
        namespaces = new HashSet<String>();
        namespaceMappings = new HashMap<String, String>();
        providers = new HashMap<DynamicAttributeKey, BehaviorProvider<? extends TagBehavior>>();
        staticBehaviorClasses = new HashMap<DynamicAttributeKey, Class<? extends StaticBehavior>>();
        staticBehaviors = new HashMap<DynamicAttributeKey, StaticBehavior>();
        dynamicTagClasses = new HashMap<DynamicAttributeKey, Class<? extends DynamicTag>>();
        dynamicTagProviders = new HashMap<DynamicAttributeKey, DynamicTagProvider>();

        /**
         * Setup defaults.
         */
        mapNamespace(DefaultNamespaceURI, "a", "cambridge");

        registerFunction("text", new ResourceBundleFunction());
        registerFunction("if", new IfFunction());

        try {
            registerFunction("format", new StaticMethodCaller(String.class.getMethod("format", String.class, Object[].class)));
        } catch (NoSuchMethodException e) {
            // Never going to happen
        }

        registerFilter("lower", LowerCaseFilter.class);
        registerFilter("upper", UpperCaseFilter.class);
        registerFilter("dateformat", SimpleDateFormatFilter.class);

        bind(DefaultNamespaceURI, "if").to(IfBehavior.getProvider());
        bind(DefaultNamespaceURI, "elseif").to(ElseIfBehavior.getProvider());
        bind(DefaultNamespaceURI, "else").to(ElseBehavior.getProvider());
        bind(DefaultNamespaceURI, "foreach").to(ForeachBehavior.getProvider());
        bind(DefaultNamespaceURI, "while").to(WhileBehavior.getProvider());
        bind(DefaultNamespaceURI, "with").to(WithBehavior.getProvider());
        bind(DefaultNamespaceURI, "from").to(FromBehavior.getProvider());
        bind(DefaultNamespaceURI, "repeat").to(RepeatBehavior.getProvider());
        bind(DefaultNamespaceURI, "selectedIf").to(SelectedBehavior.getProvider());
        bind(DefaultNamespaceURI, "next").to(ConditionalAttributeBehavior.getProvider());
        bindStatic(DefaultNamespaceURI, "addAlt").to(AltAdderStaticBehavior.class);
        bindStatic(DefaultNamespaceURI, "hide").to(HideBehavior.class);
        bindStatic(DefaultNamespaceURI, "overrides").to(OverridesStaticBehavior.class);
        bindTag(DefaultNamespaceURI, "hidden", "span").to(DummyTag.class);
    }
}
TOP

Related Classes of cambridge.Cambridge$BindStatic

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.