/** * Copyright (C) 2013-2016 The Rythm Engine project * for LICENSE and other details see: * https://github.com/rythmengine/rythmengine */ package org.rythmengine.template; import org.rythmengine.internal.TemplateBuilder; import org.rythmengine.logger.ILogger; import org.rythmengine.logger.Logger; import org.rythmengine.utils.Escape; import org.rythmengine.utils.RawData; import org.rythmengine.utils.S; import java.util.*; /** * Define a tag interface. */ public interface ITag { /** * A datastructure to store tag calling parameter */ public static class __Parameter { /** * Parameter name */ public String name; /** * Parameter value */ public Object value; /** * Construct a parameter with name and value * * @param name * @param value */ public __Parameter(String name, Object value) { this.name = "".equals(name) ? null : name; this.value = value; } @Override public String toString() { return new StringBuilder("[").append(name).append("]:").append(value).toString(); } } /** * A list of {@link org.rythmengine.template.ITag.__Parameter} */ public static class __ParameterList implements Iterable<__Parameter> { private List<__Parameter> lp = new ArrayList<__Parameter>(); /** * Add an new parameter to the list specified by name and value * * @param name * @param value */ public void add(String name, Object value) { lp.add(new __Parameter(name, value)); } /** * Return parameter value by name from the list * * @param name * @return parameter by name */ public Object getByName(String name) { for (__Parameter para : lp) { if (name.equals(para.name)) return para.value; } return null; } /** * Return parameter value by name and do type cast to left value type. * A default value is specified in case the parameter does not exist in * the list * * @param name * @param defVal * @param <T> * @return parameter by name */ public <T> T getByName(String name, T defVal) { for (__Parameter para : lp) { if (name.equals(para.name)) return (T) para.value; } return defVal; } /** * Get default parameter value. Which is the first parameter in the list * * @return default parameter */ public Object getDefault() { return getByPosition(0); } /** * Get parameter value by position in the list * * @param pos * @return parameter by position */ public Object getByPosition(int pos) { if (pos >= lp.size()) return null; return lp.get(pos).value; } @Override public Iterator<__Parameter> iterator() { return lp.iterator(); } /** * How many parameters are stored in the list * * @return size of the param list */ public int size() { return lp.size(); } /** * Get a {@link org.rythmengine.template.ITag.__Parameter} instance by position in the list * * @param i * @return parameter by position */ public __Parameter get(int i) { return lp.get(i); } /** * Convert the parameter list into a map mapped values to names * * @return parameter as map mapped by name */ public Map<String, Object> asMap() { Map<String, Object> m = new HashMap<String, Object>(); for (__Parameter p : lp) { if (p.name != null) m.put(p.name, p.value); } return m; } private String uuid = null; /** * Used to create unique key for <code>@cacheFor()</code> transformer * * @return the UUID string */ public String toUUID() { if (null == uuid) { StringBuilder sb = new StringBuilder(); for (__Parameter p : lp) { sb.append(";").append(p.name).append("=").append(p.value); } String s = sb.toString(); if (S.isEmpty(s)) s = "EMPTY_PARAMETER_LIST"; uuid = UUID.nameUUIDFromBytes(s.getBytes()).toString(); } return uuid; } } /** * Defines a tag body type */ public abstract static class __Body extends TemplateBuilder { /** * the body logger */ protected final static ILogger __bodyLogger = Logger.get(__Body.class); /** * The context template */ protected TemplateBase __context; /** * This body itself. */ protected __Body __self = this; /** * Construct a body with context template instance * * @param context */ public __Body(TemplateBase context) { __context = context; } private void call(StringBuilder out) { __buffer = out; try { __call(); } finally { __buffer = null; } } public final __Body pe(Object o) { if (null == o) return this; if (o instanceof RawData) { return (__Body) p(o); } Escape escape = __context.__defaultEscape(); return (__Body) pe(o, escape); } protected abstract void __setBodyArgByName(String name, Object val); protected abstract void __setBodyArgByPos(int pos, Object val); public String render(Object... vals) { StringBuilder sb = new StringBuilder(); render(sb, vals); return sb.toString(); } public void render(StringBuilder out, Object... vals) { for (int i = vals.length - 1; i > -1; --i) { __setBodyArgByPos(i, vals[i]); } call(out); } public void render(__ParameterList parameterList, StringBuilder out) { if (null != parameterList) { for (int i = 0; i < parameterList.size(); ++i) { __Parameter p = parameterList.get(i); if (!S.isEmpty(p.name)) { __setBodyArgByName(p.name, p.value); } else { __setBodyArgByPos(i, p.value); } } } call(out); } protected ITemplate __template() { return __context != null ? __context : caller(); } protected abstract void __call(); public abstract void __setProperty(String name, Object val); public abstract Object __getProperty(String name); } /** * Get the tag name * * @return tag name */ String __getName(); /** * Set body context and return this tag * @param body * @return this tag */ public ITag __setBodyContext(__Body body); /** * Call this tag * * @param line the number of the caller template line which invoke this tag */ void __call(int line); }