Save This Page
Home » zk-src-3.0.6 » org.zkoss.zk.scripting.util » [javadoc | source]
    1   /* GenericInterpreter.java
    2   
    3   {{IS_NOTE
    4   	Purpose:
    5   		
    6   	Description:
    7   		
    8   	History:
    9   		Thu Feb  8 23:47:29     2007, Created by tomyeh
   10   }}IS_NOTE
   11   
   12   Copyright (C) 2007 Potix Corporation. All Rights Reserved.
   13   
   14   {{IS_RIGHT
   15   	This program is distributed under GPL Version 2.0 in the hope that
   16   	it will be useful, but WITHOUT ANY WARRANTY.
   17   }}IS_RIGHT
   18   */
   19   package org.zkoss.zk.scripting.util;
   20   
   21   import java.util.Set;
   22   import java.util.Collections;
   23   import java.util.List;
   24   import java.util.LinkedList;
   25   
   26   import org.zkoss.lang.Objects;
   27   import org.zkoss.xel.Function;
   28   
   29   import org.zkoss.zk.ui.Page;
   30   import org.zkoss.zk.ui.sys.PageCtrl;
   31   import org.zkoss.zk.scripting.Interpreter;
   32   import org.zkoss.zk.scripting.Namespace;
   33   import org.zkoss.zk.scripting.Namespaces;
   34   import org.zkoss.zk.scripting.NamespaceChangeListener;
   35   
   36   /**
   37    * A skeletal class for implementing a interpreter ({@link Interpreter}) that
   38    * support {@link Namespace}.
   39    *
   40    * <p>Derive classes usually override {@link #exec} instead of {@link #interpret};
   41    * In addition, don't override {@link #getVariable},
   42    * {@link #setVariable} and {@link #unsetVariable}.
   43    * Instead, override {@link #get(String)}, {@link #contains(String)},
   44    * {@link #set(String,Object)} and {@link #unset(String)} instead.
   45    *
   46    * <p>If an interpreter doesn't support hierachical scopes,
   47    * it can simply implement a global scope, and then use
   48    * {@link #getFromNamespace} to
   49    * retrieve variables from ZK's hierachical namespaces.
   50    *
   51    * <p>If it supports hierachical scopes
   52    * (example: {@link org.zkoss.zk.scripting.bsh.BSHInterpreter}), it
   53    * can maintain a one-to-one relationship among interpreter's scopes
   54    * and ZK's {@link Namespace}. Thus, it can retrieve
   55    * the correct scope by giving ZK's {@link Namespace}, and vice versa.
   56    * It also has to implement {@link #get(Namespace,String)}, {@link #contains(Namespace,String)}
   57    * {@link #set(Namespace,String,Object)} and {@link #unset(Namespace,String)}.
   58    *
   59    * <p>Whether to support hierachical namespaces is optional.
   60    *
   61    * @author tomyeh
   62    */
   63   abstract public class GenericInterpreter implements Interpreter {
   64   	/** Used by {@link #getFromNamespace} to denote a variable is not defined.
   65   	 * @since 2.4.0
   66   	 */
   67   	public static final Object UNDEFINED = new Object();
   68   
   69   	/** A list of {@link Namespace}.
   70   	 * Top of it is the current one (if null, it means Namespaces.getCurrent)
   71   	 */
   72   	private final List _nss = new LinkedList();
   73   	private Page _owner;
   74   	private String _zslang;
   75   
   76   	protected GenericInterpreter() {
   77   	}
   78   
   79   	//interface to override//
   80   	/** Executes the specified script.
   81   	 * Deriving class shall provide an implementation of this method, rather
   82   	 * than overriding {@link #interpret}.
   83   	 */
   84   	abstract protected void exec(String script);
   85   
   86   	/** Tests whether a variable is defined in this interpreter.
   87   	 * Optional. Implement it if the interpreter can tell the difference
   88   	 * between null and undefined.
   89   	 *
   90   	 * <p>By default, it tests whether {@link #get(String)} returns non-null.
   91   	 * @since 2.4.0
   92   	 */
   93   	protected boolean contains(String name) {
   94   		return get(name) != null;
   95   	}
   96   	/** Gets the variable from the interpreter.
   97   	 * Optional. Implement it if you want to expose variables defined
   98   	 * in the interpreter to Java codes.
   99   	 *
  100   	 * <p>{@link #beforeExec} is called first, before this method is invoked.
  101   	 *
  102   	 * <p>An empty (and fake) namespace is pushed so {@link #getFromNamespace}
  103   	 * always returns null.
  104   	 */
  105   	protected Object get(String name) {
  106   		return null;
  107   	}
  108   	/** Sets the variable to the interpreter.
  109   	 * Optional. Implement it if you want to allow Java codes to define
  110   	 * a variable in the interpreter.
  111   	 *
  112   	 * <p>{@link #beforeExec} is called first, before this method is invoked.
  113   	 */
  114   	protected void set(String name, Object value) {
  115   	}
  116   	/** Removes the variable from the interpreter.
  117   	 * Optional. Implement it if you want to allow Java codes to undefine
  118   	 * a variable from the interpreter.
  119   	 *
  120   	 * <p>{@link #beforeExec} is called first, before this method is invoked.
  121   	 */
  122   	protected void unset(String name) {
  123   	}
  124   
  125   	/** Tests whether a variable is defined in the interpreter's scope
  126   	 * associated with the specified namespace.
  127   	 * Optional. Implement it if the interpreter can tell the difference
  128   	 * between null and undefined.
  129   	 *
  130   	 * <p>By default, it tests whether {@link #get(Namespace, String)}
  131   	 * returns non-null.
  132   	 * @since 2.4.0
  133   	 */
  134   	protected boolean contains(Namespace ns, String name) {
  135   		return get(ns, name) != null;
  136   	}
  137   	/** Gets the variable from the interpreter's scope associated with
  138   	 * the giving namespace.
  139   	 * Optional. Implement it if you want to expose variables defined
  140   	 * in the interpreter to Java codes.
  141   	 *
  142   	 * <p>This method is implemented only if the interpreter that supports
  143   	 * hierachical scopes ({@link org.zkoss.zk.scripting.HierachicalAware}).
  144   	 *
  145   	 * <p>Default: the same as {@link #get(String)}.
  146   	 *
  147   	 * <p>{@link #beforeExec} is called first, before this method is invoked.
  148   	 *
  149   	 * <p>An empty (and fake) namespace is pushed so {@link #getFromNamespace}
  150   	 * always returns null.
  151   	 */
  152   	protected Object get(Namespace ns, String name) {
  153   		return get(name);
  154   	}
  155   	/** Sets the variable to the interpreter's scope associated with the
  156   	 * giving namespace.
  157   	 * Optional. Implement it if you want to allow Java codes to define
  158   	 * a variable in the interpreter.
  159   	 *
  160   	 * <p>This method is implemented only if the interpreter that supports
  161   	 * hierachical scopes ({@link org.zkoss.zk.scripting.HierachicalAware}).
  162   	 *
  163   	 * <p>Default: the same as {@link #set(String, Object)}.
  164   	 *
  165   	 * <p>{@link #beforeExec} is called first, before this method is invoked.
  166   	 * @since 2.4.0
  167   	 */
  168   	protected void set(Namespace ns, String name, Object value) {
  169   		set(name, value);
  170   	}
  171   	/** Removes the variable from the interpreter.
  172   	 * Optional. Implement it if you want to allow Java codes to undefine
  173   	 * a variable from the interpreter.
  174   	 *
  175   	 * <p>This method is implemented only if the interpreter that supports
  176   	 * hierachical scopes ({@link org.zkoss.zk.scripting.HierachicalAware}).
  177   	 *
  178   	 * <p>Default: the same as {@link #unset(String)}.
  179   	 *
  180   	 * <p>{@link #beforeExec} is called first, before this method is invoked.
  181   	 * @since 2.4.0
  182   	 */
  183   	protected void unset(Namespace ns, String name) {
  184   		unset(name);
  185   	}
  186   
  187   	/** Called before {@link #exec}.
  188   	 * <p>Default: call {@link #beforeExec} and push the namespace
  189   	 * as the active one.
  190   	 */
  191   	protected void beforeInterpret(Namespace ns) {
  192   		beforeExec();
  193   		push(ns); //getFromNamespace will handle null
  194   	}
  195   	/** Called after {@link #exec}.
  196   	 * <p>Default: call {@link #afterExec}.
  197   	 */
  198   	protected void afterInterpret(Namespace ns) {
  199   		pop();
  200   		afterExec();
  201   	}
  202   	/** Called before {@link #exec}, {@link #get} and many others.
  203   	 * <p>Default: does nothing.
  204   	 */
  205   	protected void beforeExec() {
  206   	}
  207   	/** Called after {@link #exec}, {@link #get} and many others.
  208   	 * <p>Default: does nothing.
  209   	 */
  210   	protected void afterExec() {
  211   	}
  212   
  213   	//utilities//
  214   	/** Returns the variable through namespaces and variable resolvers,
  215   	 * or {@link #UNDEFINED} if the variable not defined.
  216   	 *
  217   	 * <p>It is usually called to search namespaces and variable resolvers,
  218   	 * when the real interpreter failed to find a variable in its own scope.
  219   	 *
  220   	 * <p>Note: We use {@link #UNDEFINED} to denote undefined since 2.4.0,
  221   	 * while null is a valid value.
  222   	 */
  223   	protected Object getFromNamespace(String name) {
  224   		final Namespace ns = getCurrent();
  225   		if (ns != null) {
  226   			Object val = ns.getVariable(name, false);
  227   			if (val != null || ns.containsVariable(name, false))
  228   				return val;
  229   		}
  230   		return UNDEFINED;
  231   	}
  232   	/** Returns the variable through the specified namespaces and
  233   	 * variable resolvers, or {@link #UNDEFINED} if the variable is not
  234   	 * defined.
  235   	 *
  236   	 * <p>It is usually called to search namespaces and variable resolvers,
  237   	 * when the real interpreter failed to find a variable in its own scope.
  238   	 *
  239   	 * <p>This method is used with the interpreter that supports
  240   	 * hierachical scopes ({@link org.zkoss.zk.scripting.HierachicalAware}).
  241   	 *
  242   	 * @param ns the namespace to search from (never null).
  243   	 * Note: if {@link #getCurrent} returns null, this method simply returns
  244   	 * null (i.e., ignoring ns).
  245   	 */
  246   	protected Object getFromNamespace(Namespace ns, String name) {
  247   		if (getCurrent() != null) {
  248   			Object val = ns.getVariable(name, false);
  249   			if (val != null || ns.containsVariable(name, false))
  250   				return val;
  251   		}
  252   		return UNDEFINED;
  253   	}
  254   
  255   	//Interpreter//
  256   	public void init(Page owner, String zslang) {
  257   		_owner = owner;
  258   		_zslang = zslang;
  259   	}
  260   	/** Reset the owner ({@link #getOwner}) to null.
  261   	 */
  262   	public void destroy() {
  263   		_owner = null;
  264   	}
  265   	public Page getOwner() {
  266   		return _owner;
  267   	}
  268   	public String getLanguage() {
  269   		return _zslang;
  270   	}
  271   
  272   	/** Handles the namespace and then invoke {@link #exec}.
  273   	 * <p>Don't override this method, rather, override {@link #exec}.
  274   	 */
  275   	public void interpret(String script, Namespace ns) {
  276   		final String each =
  277   			_owner.getLanguageDefinition().getEachTimeScript(_zslang);
  278   		if (each != null)
  279   			script = each + '\n' + script;
  280   
  281   		beforeInterpret(ns);
  282   		try {
  283   			exec(script);
  284   		} finally {
  285   			afterInterpret(ns);
  286   		}
  287   	}
  288   	/** Returns null since retrieving class is not supported.
  289   	 */
  290   	public Class getClass(String clsnm) {
  291   		return null;
  292   	}
  293   	/** Returns null since retrieving methods is not supported.
  294   	 * @since 3.0.0
  295   	 */
  296   	public Function getFunction(String name, Class[] argTypes) {
  297   		return null;
  298   	}
  299   	/** Returns null since retrieving methods is not supported.
  300   	 * @since 3.0.0
  301   	 */
  302   	public Function getFunction(Namespace ns, String name, Class[] argTypes) {
  303   		return null;
  304   	}
  305   
  306   	/** Tests whether the variable exists.
  307   	 *
  308   	 * <p>Deriving class shall override {@link #contains(String)}, instead of this method.
  309   	 * @since 2.4.0
  310   	 */
  311   	public boolean containsVariable(String name) {
  312   		beforeExec();
  313   		push(Objects.UNKNOWN);
  314   			//don't use null since it means Namespaces#getCurrent, see below
  315   		try {
  316   			return contains(name);
  317   		} finally {
  318   			pop();
  319   			afterExec();
  320   		}
  321   	}
  322   	/** Retrieve the variable.
  323   	 *
  324   	 * <p>Deriving class shall override {@link #get(String)}, instead of this method.
  325   	 */
  326   	public Object getVariable(String name) {
  327   		beforeExec();
  328   		push(Objects.UNKNOWN);
  329   			//don't use null since it means Namespaces#getCurrent, see below
  330   		try {
  331   			return get(name);
  332   		} finally {
  333   			pop();
  334   			afterExec();
  335   		}
  336   	}
  337   	/** Sets the variable to this interpreter.
  338   	 *
  339   	 * <p>Deriving class shall override {@link #set(String,Object)}, instead of this method.
  340   	 */
  341   	public final void setVariable(String name, Object value) {
  342   		beforeExec();
  343   		try {
  344   			set(name, value);
  345   		} finally {
  346   			afterExec();
  347   		}
  348   	}
  349   	/** Removes the variable from this interpreter.
  350   	 *
  351   	 * <p>Deriving class shall override {@link #unset(String)}, instead of this method.
  352   	 */
  353   	public final void unsetVariable(String name) {
  354   		beforeExec();
  355   		try {
  356   			unset(name);
  357   		} finally {
  358   			afterExec();
  359   		}
  360   	}
  361   
  362   	/** Tests whether the variable exists by using the specified name
  363   	 * as a reference to identify the interpreter's scope.
  364   	 *
  365   	 * <p>Deriving class shall override {@link #contains(Namespace,String)}, instead of this method.
  366   	 * @since 2.4.0
  367   	 */
  368   	public boolean containsVariable(Namespace ns, String name) {
  369   		beforeExec();
  370   		push(Objects.UNKNOWN);
  371   			//don't use null since it means Namespaces#getCurrent, see below
  372   		try {
  373   			return contains(ns, name);
  374   		} finally {
  375   			pop();
  376   			afterExec();
  377   		}
  378   	}
  379   	/** Returns the value of a variable defined in this interpreter's
  380   	 * scope identified by the specified namespace.
  381   	 * Note: it doesn't search the specified namespace ({@link Namespace}).
  382   	 *
  383   	 * <p>Deriving class shall override {@link #get(Namespace,String)},
  384   	 * instead of this method.
  385   	 *
  386   	 * <p>This method is part of {@link org.zkoss.zk.scripting.HierachicalAware}.
  387   	 * It is defined here to simplify the implementation of the
  388   	 * deriving classes, if they support the hierachical scopes.
  389   	 */
  390   	public Object getVariable(Namespace ns, String name) {
  391   		beforeExec();
  392   		push(Objects.UNKNOWN);
  393   			//don't use null since it means Namespaces#getCurrent, see below
  394   		try {
  395   			return get(ns, name);
  396   		} finally {
  397   			pop();
  398   			afterExec();
  399   		}
  400   	}
  401   	/** Sets the value of a variable to this interpreter's scope
  402   	 * identified by the specified namespace.
  403   	 *
  404   	 * <p>Deriving class shall override {@link #set(Namespace,String,Object)},
  405   	 * instead of this method.
  406   	 * @since 2.4.0
  407   	 */
  408   	public final void setVariable(Namespace ns, String name, Object value) {
  409   		beforeExec();
  410   		try {
  411   			set(ns, name, value);
  412   		} finally {
  413   			afterExec();
  414   		}
  415   	}
  416   	/** Removes the value of a variable defined in the interpreter's
  417   	 * scope identified by the specified namespace.
  418   	 *
  419   	 * <p>Deriving class shall override {@link #unset(Namespace,String)}, instead of this method.
  420   	 * @since 2.4.0
  421   	 */
  422   	public final void unsetVariable(Namespace ns, String name) {
  423   		beforeExec();
  424   		try {
  425   			unset(ns, name);
  426   		} finally {
  427   			afterExec();
  428   		}
  429   	}
  430   
  431   	/** Use the specified namespace as the active namespace.
  432   	 */
  433   	private void push(Object ns) {
  434   		_nss.add(0, ns);
  435   	}
  436   	/** Remove the active namespace.
  437   	 */
  438   	private void pop() {
  439   		_nss.remove(0);
  440   	}
  441   	/** Returns the current namespace, or null if no namespace is allowed.
  442   	 * Note: if this method returns null, it means the interpreter shall
  443   	 * not search variables defined in ZK namespace.
  444   	 *
  445   	 * <p>This method will handle {@link Namespaces#getCurrent} automatically.
  446   	 */
  447   	protected Namespace getCurrent() {
  448   		if (!_nss.isEmpty()) {
  449   			Object o = _nss.get(0);
  450   			if (o == Objects.UNKNOWN)
  451   				return null; //no namespace allowed
  452   			if (o != null)
  453   				return (Namespace)o;
  454   			//we assume owner's namespace if null, because zscript might
  455   			//define a class that will be invoke thru, say, event listener
  456   			//In other words, interpret is not called, so ns is not specified
  457   		}
  458   		return Namespaces.getCurrent(_owner); //never null
  459   	}
  460   }

Save This Page
Home » zk-src-3.0.6 » org.zkoss.zk.scripting.util » [javadoc | source]