diff --git a/build b/build index 99f7b447d3f..8cf4e45de41 100755 --- a/build +++ b/build @@ -403,6 +403,11 @@ function invoke_ant if [ "$tgtver" = "" ] ; then tgtver=1.4 fi + deprecation=$(grep '^deprecation=' version) + deprecation=${deprecation#deprecation=} + if [ "$deprecation" = "" ] ; then + deprecation=on + fi this_dflag=$dflag dflagtmp=$(grep '^debug=' version) @@ -447,6 +452,7 @@ function invoke_ant -Dear.libs="$ear_libs" \ -Dproject.name="$pronm" -Dproject.version="$prjver" \ -Dsource.version="$srcver" -Dtarget.version="$tgtver" \ + -Ddeprecation="$deprecation" \ -Dhaltonerror=$haltonerror -Dout.dir=$outdir \ -Ddebug=$this_dflag -Doptimize=$this_oflag ${nojc} \ -Dshare.javadoc.dir="$javadocdir" \ diff --git a/zk/format b/zk/format index 4ef66f41e6c..dc047e1b59a 100644 --- a/zk/format +++ b/zk/format @@ -1,2 +1,2 @@ jar -time=archive/metainfo/zk/build \ No newline at end of file +time=archive/metainfo/zk/build diff --git a/zk/src/org/zkoss/zk/scripting/HierachicalAware.java b/zk/src/org/zkoss/zk/scripting/HierachicalAware.java index 141b4bd2141..fbec3e9e3a8 100644 --- a/zk/src/org/zkoss/zk/scripting/HierachicalAware.java +++ b/zk/src/org/zkoss/zk/scripting/HierachicalAware.java @@ -19,6 +19,7 @@ package org.zkoss.zk.scripting; import org.zkoss.xel.Function; +import org.zkoss.zk.ui.ext.Scope; /** * An extra interface implemented by an interpreter ({@link Interpreter}) @@ -26,9 +27,9 @@ * *

By supporting the hierachical scopes we mean the interpreter * associates one interpreter-dependent scope with each ZK's - * {@link Namespace}. And, variables, classes and methods defined + * {@link org.zkoss.zk.ui.IdSpace}. And, variables, classes and methods defined * in zscript are then stored in an individual scope depending on - * the namespace when calling {@link Interpreter#interpret}. + * the scope when calling {@link Interpreter#interpret}. * *

On the other hand, if the interpreter doesn't support the hierachical * scopes, it maintains only one global scope and all variables, classes @@ -39,72 +40,73 @@ */ public interface HierachicalAware { /** Tests whether a variable defined in this interpreter. - * Note: it doesn't search the namespace ({@link Namespace}). + * Note: it doesn't search the scope ({@link Scope}). * *

It is similar to {@link Interpreter#containsVariable}, except - * it uses the specified namespace as a reference to identify the + * it uses the specified scope as a reference to identify the * correct scope for searching the variable. * - * @param ns the namespace used as a reference to identify the + * @param scope the scope used as a reference to identify the * correct scope for searching the variable. - * Note: this method doesn't look for any variable stored in ns. - * @since 2.4.0 + * Note: this method doesn't look for any variable stored in scope. + * @since 5.0.0 */ - public boolean containsVariable(Namespace ns, String name); + public boolean containsVariable(Scope scope, String name); /** Returns the value of a variable defined in this interpreter's - * scope identified by the specified namespace. - * Note: it doesn't search the specified namespace ({@link Namespace}). + * scope identified by the specified scope. + * Note: it doesn't search the specified scope ({@link Scope}). * *

It is similar to {@link Interpreter#getVariable}, except - * it uses the specified namespace as a reference to identify the + * it uses the specified scope as a reference to identify the * correct scope for searching the variable. * - * @param ns the namespace used as a reference to identify the + * @param scope the scope used as a reference to identify the * correct scope for searching the variable. - * Note: this method doesn't look for any variable stored in ns. + * Note: this method doesn't look for any variable stored in scope. + * @since 5.0.0 */ - public Object getVariable(Namespace ns, String name); + public Object getVariable(Scope scope, String name); /** Sets the value of a variable to this interpreter's scope - * identified by the specified namespace. + * identified by the specified scope. * *

It is similar to {@link Interpreter#setVariable}, except - * it uses the specified namespace as a reference to identify the + * it uses the specified scope as a reference to identify the * correct scope for storing the variable. * - * @param ns the namespace used as a reference to identify the + * @param scope the scope used as a reference to identify the * correct scope for searching the variable. - * Note: this method doesn't look for any variable stored in ns. - * @since 2.4.0 + * Note: this method doesn't look for any variable stored in scope. + * @since 5.0.0 */ - public void setVariable(Namespace ns, String name, Object value); + public void setVariable(Scope scope, String name, Object value); /** Removes the value of a variable defined in the interpreter's - * scope identified by the specified namespace. + * scope identified by the specified scope. * *

It is similar to {@link Interpreter#unsetVariable}, except - * it uses the specified namespace as a reference to identify the + * it uses the specified scope as a reference to identify the * correct scope for removing the variable. * - * @param ns the namespace used as a reference to identify the + * @param scope the scope used as a reference to identify the * correct scope for searching the variable. - * Note: this method doesn't look for any variable stored in ns. - * @since 2.4.0 + * Note: this method doesn't look for any variable stored in scope. + * @since 5.0.0 */ - public void unsetVariable(Namespace ns, String name); + public void unsetVariable(Scope scope, String name); /** Returns the method of the specified name defined in - * this interpreter's scope identified by the specified namespace, + * this interpreter's scope identified by the specified scope, * or null if not defined. * *

It is similar to {@link Interpreter#getFunction}, except - * it uses the specified namespace as a reference to identify the + * it uses the specified scope as a reference to identify the * correct scope for searching the variable. * - * @param ns the namespace used as a reference to identify the + * @param scope the scope used as a reference to identify the * correct scope for searching the method. - * Note: this method doesn't look for any variable stored in ns. + * Note: this method doesn't look for any variable stored in scope. * @param argTypes the list of argument (aka., parameter) types. * If null, Class[0] is assumed. - * @since 3.0.0 + * @since 5.0.0 */ - public Function getFunction(Namespace ns, String name, Class[] argTypes); + public Function getFunction(Scope scope, String name, Class[] argTypes); } diff --git a/zk/src/org/zkoss/zk/scripting/Interpreter.java b/zk/src/org/zkoss/zk/scripting/Interpreter.java index 10e19f875cd..bc8fcb696e9 100644 --- a/zk/src/org/zkoss/zk/scripting/Interpreter.java +++ b/zk/src/org/zkoss/zk/scripting/Interpreter.java @@ -20,6 +20,7 @@ import org.zkoss.xel.Function; import org.zkoss.zk.ui.Page; +import org.zkoss.zk.ui.ext.Scope; /** * Represents an interpter that can interpret the scripting codes. @@ -55,7 +56,11 @@ public interface Interpreter { */ public Object getNativeInterpreter(); - /** Evaluates the script against the specified namespace. + /** @deprecated As of release 5.0.0, replaced with {@link #interpret(String, Scope}} + *

Evaluates the script against the specified namespace. + */ + public void interpret(String script, Namespace ns); + /** Evaluates the script against the specified scope. * *

Implementation Note: *

    @@ -63,17 +68,18 @@ public interface Interpreter { * the string returned by * {@link org.zkoss.zk.ui.metainfo.LanguageDefinition#getEachTimeScript} * if not null. - *
  1. The implementation must use {@link Namespaces#getCurrent} - * to retrieve the current namesace if the ns argument is null. + *
  2. The implementation must use {@link Scopes#getCurrent} + * to retrieve the current namesace if the comp argument is null. * - * @param ns the namspace. If null, the current namespace is assumed. - * The current namespace is {@link Namespaces#getCurrent}, which - * is the event target's namespace, if the thread is processing an event. + * @param scope the scope as the context to interpret the script. + * If null, the current scope is assumed. + * The current scope is {@link Scopes#getCurrent}, which + * is the event target's scope, if the thread is processing an event. * The event target is {@link org.zkoss.zk.ui.event.Event#getTarget}. - * Otherwise, the current namespace is the owner page's namespace - * ({@link #getOwner}. + * Otherwise, the current scope is the owner page ({@link #getOwner}. + * @since 5.0.0 */ - public void interpret(String script, Namespace ns); + public void interpret(String script, Scope scope); /** Returns the class defined in this interpreter, or null if not found. */ @@ -88,13 +94,13 @@ public interface Interpreter { public Function getFunction(String name, Class[] argTypes); /** Tests whether the variable is defined in this interpreter. - * Note: it doesn't search the namespace ({@link Namespace}). + * Note: it doesn't search the attributes ({@link Scope}). * * @since 2.4.0 */ public boolean containsVariable(String name); /** Returns the value of a variable defined in this interpreter. - * Note: it doesn't search the namespace ({@link Namespace}). + * Note: it doesn't search the scope ({@link Scope}). */ public Object getVariable(String name); /** Sets the value of a variable to this interpreter, as if diff --git a/zk/src/org/zkoss/zk/scripting/Namespace.java b/zk/src/org/zkoss/zk/scripting/Namespace.java index 8a8b24f335d..285efad759a 100644 --- a/zk/src/org/zkoss/zk/scripting/Namespace.java +++ b/zk/src/org/zkoss/zk/scripting/Namespace.java @@ -23,7 +23,9 @@ import org.zkoss.zk.ui.Component; /** - * To represent the name space for storing variables. + * @deprecated As of release 5.0, replaced with {@link org.zkoss.zk.ui.ext.Scope}. + * + *

    To represent the name space for storing variables. * There are two ways to declare variables: by zscirpt, or by * {@link org.zkoss.zk.ui.Component#setVariable}/ * {@link org.zkoss.zk.ui.Page#setVariable}. diff --git a/zk/src/org/zkoss/zk/scripting/NamespaceActivationListener.java b/zk/src/org/zkoss/zk/scripting/NamespaceActivationListener.java index 1991e843e75..7f0dca266b2 100644 --- a/zk/src/org/zkoss/zk/scripting/NamespaceActivationListener.java +++ b/zk/src/org/zkoss/zk/scripting/NamespaceActivationListener.java @@ -15,7 +15,11 @@ package org.zkoss.zk.scripting; /** - * Used to notify an object stored in a namespace, when the namespace + * @deprecated As of release 5.0.0, use + * {@link org.zkoss.zk.ui.util.ComponentActivationListener} + * or {@link org.zkoss.zk.ui.util.PageActivationListener} instead. + * + *

    Used to notify a variable stored in a namespace, when the namespace * is going to be deactivated or has been activated. * *

    When a namespace is going to be deactivate, it checks every @@ -28,11 +32,11 @@ * @since 3.6.2 */ public interface NamespaceActivationListener { - /** Called when a session has just been activated + /** Called when a namespace has just been activated * (and its value has been deserialized). */ public void didActivate(Namespace ns); - /** Called when a session is about to be passivated + /** Called when a namespace is about to be passivated * (and then serialize its value). */ public void willPassivate(Namespace ns); diff --git a/zk/src/org/zkoss/zk/scripting/NamespaceChangeListener.java b/zk/src/org/zkoss/zk/scripting/NamespaceChangeListener.java index 75e33306896..997e2c3aff8 100644 --- a/zk/src/org/zkoss/zk/scripting/NamespaceChangeListener.java +++ b/zk/src/org/zkoss/zk/scripting/NamespaceChangeListener.java @@ -18,8 +18,10 @@ */ package org.zkoss.zk.scripting; -/** - * A listener used to listen whether {@link Namespace} is changed. +/** @deprecated, As of release 5.0.0, the concept of namespace is + * deprecated. + * + *

    A listener used to listen whether {@link Namespace} is changed. * *

    To add a listener to the namespace, invoke * {@link Namespace#addChangeListener}. @@ -35,7 +37,9 @@ public interface NamespaceChangeListener { /** Called when a variable is removed from {@link Namespace}. */ public void onRemove(String name); - /** Called when the parent is changed. + /** @deprecated As of release 5.0.0, the concept of namespace is + * deprecated. + *

    Called when the parent is changed. * * @param newparent the new parent. */ diff --git a/zk/src/org/zkoss/zk/scripting/Namespaces.java b/zk/src/org/zkoss/zk/scripting/Namespaces.java index 9d2a252de5c..c3a3479f712 100644 --- a/zk/src/org/zkoss/zk/scripting/Namespaces.java +++ b/zk/src/org/zkoss/zk/scripting/Namespaces.java @@ -16,125 +16,43 @@ */ package org.zkoss.zk.scripting; -import java.util.Map; -import java.util.HashMap; -import java.util.List; -import java.util.LinkedList; -import java.util.Iterator; - -import org.zkoss.util.logging.Log; -import org.zkoss.zk.ui.Desktop; import org.zkoss.zk.ui.Page; import org.zkoss.zk.ui.Component; -import org.zkoss.zk.ui.Execution; -import org.zkoss.zk.ui.Executions; -import org.zkoss.zk.scripting.util.SimpleNamespace; +import org.zkoss.zk.ui.ext.Scopes; /** - * {@link Namespace} relevant utilities. - * + * @deprecated As of release 5.0, replaced with {@link Scopes}. * @author tomyeh */ public class Namespaces { - private static final Log log = Log.lookup(Namespaces.class); - - /** A stack of implict objects ({@link Implicts}. */ - private static final ThreadLocal _implicits = new ThreadLocal(); - /** A stack of current namespace. */ - private static final ThreadLocal _curnss = new ThreadLocal(); - - /** Prepares implicit variable before calling {@link Page#interpret}. - * - *

    Typical use: - *

    
    -final Namespace ns = Namespaces.beforeInterpret(comp);
    -try {
    -  Namespaces.setImplicit("some", value);
    -  page.interpret(zslang, zscript, ns); //it will push ns as the current namespace
    -} finally {
    -  Namespaces.afterInterpret();
    -}
    -
    - * - *

    Another example: - *

    
    -Namespaces.beforeInterpret(comp);
    -try {
    -  constr.validate(comp); //if constr might be an instance of a class implemented in zscript
    -} finally {
    -  Namespaces.afterInterpret();
    -}
    -
    - * - *

    If you need to set some implicit variables, you can invoke - * {@link #setImplicit} between {@link #beforeInterpret} - * and {@link #afterInterpret}. - * - * @param comp the component, never null. - * @return the namespace that owns the specified component - * @since 3.6.1 + /** @deprecated As of release 5.0, replaced with {@link Scopes}. */ public static final Namespace beforeInterpret(Component comp) { - Namespace ns = comp.getNamespace(); - if (ns == null) ns = new SimpleNamespace(); - - final Implicit impl = beforeInterpret0(ns); - impl.setImplicit("self", comp); - impl.setImplicit("componentScope", comp.getAttributes(Component.COMPONENT_SCOPE)); - - return ns; + return null; } - /** Prepares builtin variable before calling - * {@link org.zkoss.zk.ui.Page#interpret} or a method that might be - * implemented with zscript. - * - * @see #beforeInterpret(Component) - * @param page the page, never null. - * @return the namespace that owns the specified page - * @since 3.6.1 + /** @deprecated As of release 5.0, replaced with {@link Scopes}. */ public static final Namespace beforeInterpret(Page page) { - final Namespace ns = page.getNamespace(); - final Implicit impl = beforeInterpret0(ns); - impl.setImplicit("self", page); - return ns; - } - private static Implicit beforeInterpret0(Namespace ns) { - List impls = (List)_implicits.get(); - if (impls == null) - _implicits.set(impls = new LinkedList()); - final Implicit impl = new Implicit(); - impls.add(0, impl); - - final Execution exec = Executions.getCurrent(); - impl.setImplicit("arg", exec != null ? exec.getArg(): null); - - push(ns); - - return impl; + return null; } - /** Used with {@link #beforeInterpret} to clean up implicit - * variables. - * - * @since 3.6.1 + /** @deprecated As of release 5.0, replaced with {@link Scopes}. */ public static final void afterInterpret() { - ((List)_implicits.get()).remove(0); - pop(); } - /** Sets an implicit object. + /** @deprecated As of release 5.0, replaced with {@link Scopes}. + * Sets an implicit object. * It can be called only between {@link #beforeInterpret} and * {@link #afterInterpret}. * * @since 3.6.1 */ public static void setImplicit(String name, Object value) { - ((Implicit)((List)_implicits.get()).get(0)) - .setImplicit(name, value); + Scopes.setImplicit(name, value); } - /** Returns the implict object. + /** @deprecated As of release 5.0, replaced with {@link Scopes}. + * Returns the implict object. * * @param name the variable to retrieve * @param defValue the default vale that is used if the implicit @@ -142,54 +60,20 @@ public static void setImplicit(String name, Object value) { * @since 3.6.1 */ public static Object getImplicit(String name, Object defValue) { - final List implicits = (List)_implicits.get(); - if (implicits != null && !implicits.isEmpty()) //in case: beforeInterpret not called - return ((Implicit)implicits.get(0)).getImplicit(name, defValue); - return defValue; + return Scopes.getImplicit(name, defValue); } - /** Returns the current namespace. - * The current namespace is the event target's namespace if this thread - * is processing an event ({@link org.zkoss.zk.ui.event.Event#getTarget}. - * Otherwise, the namespace of the page specified is assumed. - * - *

    This method is used only to implement {@link org.zkoss.zk.scripting.Interpreter}. - * You rarely need to access it other than implementing an interpreter. + /** @deprecated As of release 5.0, replaced with {@link Scopes}. */ public static final Namespace getCurrent(Page page) { - final List nss = (List)_curnss.get(); - final Namespace ns = - nss != null && !nss.isEmpty() ? (Namespace)nss.get(0): null; - return ns != null ? ns: page.getNamespace(); + return null; } - /** Pushes the specified namespace as the current namespace. - * - * @param ns the namespace. If null, it means page's namespace. + /** @deprecated As of release 5.0, replaced with {@link Scopes}. */ private static final void push(Namespace ns) { - List nss = (List)_curnss.get(); - if (nss == null) - _curnss.set(nss = new LinkedList()); - nss.add(0, ns); } - /** Pops the current namespce (pushed by {@link #push}). + /** @deprecated As of release 5.0, replaced with {@link Scopes}. */ private static final void pop() { - ((List)_curnss.get()).remove(0); - } - - private static class Implicit { - /** Implicit variables. */ - private final Map _vars = new HashMap(); - - private Implicit() { - } - private void setImplicit(String name, Object value) { - _vars.put(name, value); - } - private Object getImplicit(String name, Object defValue) { - final Object o = _vars.get(name); - return o != null || _vars.containsKey(name) ? o: defValue; - } } } diff --git a/zk/src/org/zkoss/zk/scripting/bsh/BSHInterpreter.java b/zk/src/org/zkoss/zk/scripting/bsh/BSHInterpreter.java index b92e56fde24..8877052941c 100644 --- a/zk/src/org/zkoss/zk/scripting/bsh/BSHInterpreter.java +++ b/zk/src/org/zkoss/zk/scripting/bsh/BSHInterpreter.java @@ -39,15 +39,20 @@ import bsh.EvalError; import bsh.UtilEvalError; +import org.zkoss.lang.D; import org.zkoss.lang.Classes; import org.zkoss.lang.reflect.Fields; import org.zkoss.xel.Function; import org.zkoss.util.logging.Log; +import org.zkoss.zk.ui.Executions; +import org.zkoss.zk.ui.Execution; import org.zkoss.zk.ui.Page; +import org.zkoss.zk.ui.Component; +import org.zkoss.zk.ui.IdSpace; import org.zkoss.zk.ui.UiException; -import org.zkoss.zk.scripting.Namespace; -import org.zkoss.zk.scripting.NamespaceChangeListener; +import org.zkoss.zk.ui.ext.Scope; +import org.zkoss.zk.ui.ext.ScopeListener; import org.zkoss.zk.scripting.util.GenericInterpreter; import org.zkoss.zk.scripting.SerializableAware; import org.zkoss.zk.scripting.HierachicalAware; @@ -59,14 +64,14 @@ * scopes ({@link HierachicalAware}). * That is, it uses an independent BeanShell NameSpace * (aka. interpreter's scope) to store the variables/classes/methods - * defined in BeanShell script for each ZK namespace ({@link Namespace}). - * Since one-to-one relationship between BeanShell's scope and ZK namespace, + * defined in BeanShell script for each ZK scope ({@link Scope}). + * Since one-to-one relationship between BeanShell's scope and ZK scope, * the invocation of BeanShell methods can execute correctly without knowing - * what namespace it is. + * what scope it is. * However, if you want your codes portable across different interpreters, * you had better to call - * {@link org.zkoss.zk.scripting.Namespaces#beforeInterpret} - * to prepare the proper namespace, before calling any method defined in + * {@link org.zkoss.zk.ui.ext.Scopes#beforeInterpret} + * to prepare the proper scope, before calling any method defined in * zscript. * * @author tomyeh @@ -75,7 +80,7 @@ public class BSHInterpreter extends GenericInterpreter implements SerializableAware, HierachicalAware { /*package*/ static final Log log = Log.lookup(BSHInterpreter.class); - /** A variable of {@link Namespace}. The value is an instance of + /** A variable in {@link Scope}. The value is an instance of * BeanShell's NameSpace. */ private static final String VAR_NSW = "z_bshnsw"; @@ -94,7 +99,7 @@ public BSHInterpreter() { } //Deriving to override// - /** Called when the top-level BeanShell namespace is created. + /** Called when the top-level BeanShell scope is created. * By default, it does nothing. * *

    Note: to speed up the performance, this implementation @@ -115,8 +120,8 @@ protected void loadDefaultImports(NameSpace bshns) { //GenericInterpreter// protected void exec(String script) { try { - final Namespace ns = getCurrent(); - if (ns != null) _ip.eval(script, prepareNS(ns)); + final Scope scope = getCurrent(); + if (scope != null) _ip.eval(script, prepareNS(scope)); else _ip.eval(script); //unlikely (but just in case) } catch (EvalError ex) { throw UiException.Aide.wrap(ex); @@ -154,9 +159,9 @@ protected void unset(String name) { } } - protected boolean contains(Namespace ns, String name) { - if (ns != null) { - final NameSpace bshns = prepareNS(ns); + protected boolean contains(Scope scope, String name) { + if (scope != null) { + final NameSpace bshns = prepareNS(scope); //note: we have to create NameSpace (with prepareNS) //to have the correct chain if (bshns != _bshns) { @@ -169,9 +174,9 @@ protected boolean contains(Namespace ns, String name) { } return contains(name); } - protected Object get(Namespace ns, String name) { - if (ns != null) { - final NameSpace bshns = prepareNS(ns); + protected Object get(Scope scope, String name) { + if (scope != null) { + final NameSpace bshns = prepareNS(scope); //note: we have to create NameSpace (with prepareNS) //to have the correct chain if (bshns != _bshns) { @@ -184,9 +189,9 @@ protected Object get(Namespace ns, String name) { } return get(name); } - protected void set(Namespace ns, String name, Object val) { - if (ns != null) { - final NameSpace bshns = prepareNS(ns); + protected void set(Scope scope, String name, Object val) { + if (scope != null) { + final NameSpace bshns = prepareNS(scope); //note: we have to create NameSpace (with prepareNS) //to have the correct chain if (bshns != _bshns) { @@ -201,9 +206,9 @@ protected void set(Namespace ns, String name, Object val) { } set(name, val); } - protected void unset(Namespace ns, String name) { - if (ns != null) { - final NameSpace bshns = prepareNS(ns); + protected void unset(Scope scope, String name) { + if (scope != null) { + final NameSpace bshns = prepareNS(scope); //note: we have to create NameSpace (with prepareNS) //to have the correct chain if (bshns != _bshns) { @@ -225,7 +230,7 @@ public void init(Page owner, String zslang) { _ip.setNameSpace(_bshns); } public void destroy() { - getOwner().getNamespace().unsetVariable(VAR_NSW, false); + getOwner().removeAttribute(VAR_NSW); //bug 1814819 ,clear variable, dennis try{ @@ -259,8 +264,8 @@ public Class getClass(String clsnm) { public Function getFunction(String name, Class[] argTypes) { return getFunction0(_bshns, name, argTypes); } - public Function getFunction(Namespace ns, String name, Class[] argTypes) { - return getFunction0(prepareNS(ns), name, argTypes); + public Function getFunction(Scope scope, String name, Class[] argTypes) { + return getFunction0(prepareNS(scope), name, argTypes); } private Function getFunction0(NameSpace bshns, String name, Class[] argTypes) { try { @@ -272,42 +277,45 @@ private Function getFunction0(NameSpace bshns, String name, Class[] argTypes) { } } - /** Prepares the namespace for non-top-level namespace. + /** Prepares the namespace for non-top-level scope. */ - private NameSpace prepareNS(Namespace ns) { - if (ns == getOwner().getNamespace()) + private NameSpace prepareNS(Scope scope) { + scope = getIdSpace(scope); + if (scope == null || scope == getOwner()) return _bshns; - NSWrap nsw = (NSWrap)ns.getVariable(VAR_NSW, true); + NSWrap nsw = (NSWrap)scope.getAttribute(VAR_NSW, true); if (nsw != null) - return nsw.unwrap(ns); + return nsw.unwrap(scope); - //bind bshns and ns - final NS bshns = newNS(ns); - ns.setVariable(VAR_NSW, NSWrap.getInstance(bshns), true); + //bind bshns and scope + final NS bshns = newNS(scope); + scope.setAttribute(VAR_NSW, NSWrap.getInstance(bshns)); return bshns; } - /*package*/ NS newNS(Namespace ns) { - Namespace p = ns.getParent(); - return new NS(p != null ? prepareNS(p): _bshns, _ip.getClassManager(), ns); + /*package*/ NS newNS(Scope scope) { + scope = getIdSpace(scope); + Scope p = getParentIdSpace(scope); + return new NS(p != null ? prepareNS(p): _bshns, _ip.getClassManager(), scope); //Bug 1831534: we have to pass class manager //Bug 1899353: we have to use _bshns instead of null (Reason: unknown) } /** Prepares the namespace for detached components. */ - private static NameSpace prepareDetachedNS(Namespace ns) { - NSWrap nsw = (NSWrap)ns.getVariable(VAR_NSW, true); + private static NameSpace prepareDetachedNS(Scope scope) { + scope = getIdSpace(scope); + NSWrap nsw = (NSWrap)scope.getAttribute(VAR_NSW, true); if (nsw != null) - return nsw.unwrap(ns); + return nsw.unwrap(scope); - //bind bshns and ns - Namespace p = ns.getParent(); - NameSpace bshns = new NS(p != null ? prepareDetachedNS(p): null, null, ns); - ns.setVariable(VAR_NSW, NSWrap.getInstance(bshns), true); + //bind bshns and scope + Scope p = getParentIdSpace(scope); + NameSpace bshns = new NS(p != null ? prepareDetachedNS(p): null, null, scope); + scope.setAttribute(VAR_NSW, NSWrap.getInstance(bshns)); return bshns; } - /*package*/ static BSHInterpreter getInterpreter(Namespace ns) { - Page owner = ns.getOwnerPage(); + /*package*/ static BSHInterpreter getInterpreter(Scope scope) { + Page owner = getPage(scope); if (owner != null) { for (Iterator it = owner.getLoadedInterpreters().iterator(); it.hasNext();) { @@ -319,10 +327,34 @@ private static NameSpace prepareDetachedNS(Namespace ns) { return null; } + /** Returns the nearest IdSpace (scope), never null. */ + private static Scope getIdSpace(Scope scope) { + if (scope instanceof IdSpace) + return scope; + if (scope instanceof Component) { + scope = ((Component)scope).getSpaceOwner(); + if (scope != null) return scope; + } + return null; + } + /** Returns the parent IdSpace (scope), or null if no parent. */ + private static Scope getParentIdSpace(Scope scope) { + if (scope == null || !(scope instanceof Component)) + return null; + final Component p = ((Component)scope).getParent(); + return p != null ? p.getSpaceOwner(): null; + } + private static Page getPage(Scope scope) { + return scope instanceof Component ? + ((Component)scope).getPage(): + scope instanceof Page ? ((Page)scope): null; + } + //supporting classes// /** The global namespace. */ private static abstract class AbstractNS extends NameSpace { private boolean _inGet; + protected boolean _firstGet; protected AbstractNS(NameSpace parent, BshClassManager classManager, String name) { @@ -330,7 +362,7 @@ protected AbstractNS(NameSpace parent, BshClassManager classManager, } /** Deriver has to override this method. */ - abstract protected Object getFromNamespace(String name); + abstract protected Object getFromScope(String name); //super// protected Variable getVariableImpl(String name, boolean recurse) @@ -346,7 +378,8 @@ protected Variable getVariableImpl(String name, boolean recurse) //so use _inGet to prevent dead loop Variable var = super.getVariableImpl(name, false); if (!_inGet && var == null) { - Object v = getFromNamespace(name); + _firstGet = true; + Object v = getFromScope(name); if (v != UNDEFINED) { //Variable has no public/protected contructor, so we have to //store the value back (with setVariable) and retrieve again @@ -391,42 +424,75 @@ private GlobalNS(BshClassManager classManager, String name) { super(null, classManager, name); } - protected Object getFromNamespace(String name) { - if (getCurrent() == null) - return getImplicit(name); //ignore ns + protected Object getFromScope(String name) { + if (getCurrent() == null) //no scope allowed + return getImplicit(name); + + if (_firstGet) { + _firstGet = false; + final Execution exec = Executions.getCurrent(); + if (exec != null) { + Object val = exec.getAttribute(name); + if (val != null /*||exec.hasAttribute(name)*/) //exec not support hasAttribute + return val; + } + } - final Namespace ns = getOwner().getNamespace(); - Object v = ns.getVariable(name, true); - return v != null || ns.containsVariable(name, true) ? v: getImplicit(name); - //local-only since getVariableImpl will look up its parent + final Page page = getOwner(); + Object val = page.getFellowOrAttribute(name, false); //page/desktop/session + return val != null || page.hasFellowOrAttribute(name, false) ? + val: getImplicit(name); } public void loadDefaultImports() { BSHInterpreter.this.loadDefaultImports(this); } } - /** The per-Namespace NameSpace. */ + /** The per-IdSpace NameSpace. */ /*package*/ static class NS extends AbstractNS { - private Namespace _ns; + private Scope _scope; - private NS(NameSpace parent, BshClassManager classManager, Namespace ns) { - super(parent, classManager, "ns" + System.identityHashCode(ns)); - _ns = ns; - _ns.addChangeListener(new NSCListener(this)); + private NS(NameSpace parent, BshClassManager classManager, Scope scope) { + super(parent, classManager, "scope" + System.identityHashCode(scope)); + _scope = scope; + _scope.addScopeListener(new NSCListener(this)); } //super// - /** Search _ns instead. */ - protected Object getFromNamespace(String name) { - final BSHInterpreter ip = getInterpreter(_ns); - if (ip != null && ip.getCurrent() == null) - return getImplicit(name); //ignore ns + /** Search _scope instead. */ + protected Object getFromScope(String name) { + final BSHInterpreter ip = getInterpreter(_scope); + final Scope curr = ip != null ? ip.getCurrent(): null; + if (curr== null) + return getImplicit(name); //ignore scope + + if (_firstGet) { + _firstGet = false; + final Execution exec = Executions.getCurrent(); + if (exec != null && exec != curr) { + Object val = exec.getAttribute(name); + if (val != null /*||exec.hasAttribute(name)*/) //exec not support hasAttribute + return val; + } + + //_scope is the nearest IdSpace so it might not be curr + if (curr != _scope && curr instanceof Component) { + for (Component c = (Component)curr; + c != null && c != _scope; c = c.getParent()) { + Object val = c.getAttribute(name); + if (val != null || c.hasAttribute(name)) + return val; + } + } + } - Object v = _ns.getVariable(name, true); - return v != null || _ns.containsVariable(name, true) ? v: getImplicit(name); - //local-only since getVariableImpl will look up its parent + Component comp = (Component)_scope; + //local-only since getVariableImpl will look up its parent + Object val = comp.getFellowOrAttribute(name, true); + return val != null || comp.hasFellowOrAttribute(name, true) ? + val: getImplicit(name); } } - private static class NSCListener implements NamespaceChangeListener { + private static class NSCListener implements ScopeListener { private final NS _bshns; private NSCListener(NS bshns) { _bshns = bshns; @@ -435,9 +501,9 @@ public void onAdd(String name, Object value) { } public void onRemove(String name) { } - public void onParentChanged(Namespace newparent) { + public void onParentChanged(Scope newparent) { if (newparent != null) { - final BSHInterpreter ip = getInterpreter(_bshns._ns); + final BSHInterpreter ip = getInterpreter(_bshns._scope); _bshns.setParent( ip != null ? ip.prepareNS(newparent): prepareDetachedNS(newparent)); @@ -662,7 +728,8 @@ protected NSWrap(NameSpace ns) { } public NSWrap() { } - public NameSpace unwrap(Namespace ns) { + /** Returns the associated NameSpace. */ + public NameSpace unwrap(Scope ns) { return _bshns; } } @@ -676,9 +743,10 @@ public NameSpace unwrap(Namespace ns) { } public NSWrapX() { } - public NameSpace unwrap(Namespace ns) { + /** Returns the associated NameSpace. */ + public NameSpace unwrap(Scope scope) { if (_bshns == null) { - _bshns = BSHInterpreter.getInterpreter(ns).newNS(ns); + _bshns = BSHInterpreter.getInterpreter(scope).newNS(scope); if (_vars != null) { for (Iterator it = _vars.entrySet().iterator(); it.hasNext();) { final Map.Entry me = (Map.Entry)it.next(); diff --git a/zk/src/org/zkoss/zk/scripting/util/AbstractNamespace.java b/zk/src/org/zkoss/zk/scripting/util/AbstractNamespace.java deleted file mode 100644 index 0005c2663c8..00000000000 --- a/zk/src/org/zkoss/zk/scripting/util/AbstractNamespace.java +++ /dev/null @@ -1,81 +0,0 @@ -/* AbstractNamespace.java - -{{IS_NOTE - Purpose: - - Description: - - History: - Thu Feb 8 09:45:18 2007, Created by tomyeh -}}IS_NOTE - -Copyright (C) 2007 Potix Corporation. All Rights Reserved. - -{{IS_RIGHT -}}IS_RIGHT -*/ -package org.zkoss.zk.scripting.util; - -import java.util.Iterator; -import java.util.List; -import java.util.LinkedList; - -import org.zkoss.zk.scripting.Namespace; -import org.zkoss.zk.scripting.NamespaceChangeListener; - -/** - * A skeletal class for implementing {@link Namespace}. - * - * @author tomyeh - */ -abstract public class AbstractNamespace implements Namespace { - private List _listeners; - - /** Invokes {@link NamespaceChangeListener#onAdd} for registered - * listeners. - * - * @see #addChangeListener - */ - protected void notifyAdd(String name, Object value) { - if (_listeners != null) - for (Iterator it = _listeners.iterator(); it.hasNext();) - ((NamespaceChangeListener)it.next()).onAdd(name, value); - } - /** Invokes {@link NamespaceChangeListener#onRemove} for registered - * listeners. - * - * @see #addChangeListener - */ - protected void notifyRemove(String name) { - if (_listeners != null) - for (Iterator it = _listeners.iterator(); it.hasNext();) - ((NamespaceChangeListener)it.next()).onRemove(name); - } - /** Invokes {@link NamespaceChangeListener#onParentChanged} for registered - * listeners. - * - * @see #addChangeListener - */ - protected void notifyParentChanged(Namespace newparent) { - if (_listeners != null) - for (Iterator it = _listeners.iterator(); it.hasNext();) - ((NamespaceChangeListener)it.next()).onParentChanged(newparent); - } - - //Namespace// - public boolean addChangeListener(NamespaceChangeListener listener) { - if (listener == null) - throw new IllegalArgumentException("null"); - - if (_listeners == null) - _listeners = new LinkedList(); - else if (_listeners.contains(listener)) - return false; - - _listeners.add(listener); - return true; - } - public boolean removeChangeListener(NamespaceChangeListener listener) { - return _listeners != null && _listeners.remove(listener); - } -} diff --git a/zk/src/org/zkoss/zk/scripting/util/GenericInterpreter.java b/zk/src/org/zkoss/zk/scripting/util/GenericInterpreter.java index c18b80a3af1..fdecca31bca 100644 --- a/zk/src/org/zkoss/zk/scripting/util/GenericInterpreter.java +++ b/zk/src/org/zkoss/zk/scripting/util/GenericInterpreter.java @@ -29,15 +29,15 @@ import org.zkoss.zk.ui.Execution; import org.zkoss.zk.ui.Executions; import org.zkoss.zk.ui.Page; +import org.zkoss.zk.ui.Component; +import org.zkoss.zk.ui.IdSpace; +import org.zkoss.zk.ui.ext.Scope; +import org.zkoss.zk.ui.ext.Scopes; import org.zkoss.zk.ui.sys.PageCtrl; import org.zkoss.zk.scripting.Interpreter; -import org.zkoss.zk.scripting.Namespace; -import org.zkoss.zk.scripting.Namespaces; -import org.zkoss.zk.scripting.NamespaceChangeListener; /** - * A skeletal class for implementing a interpreter ({@link Interpreter}) that - * support {@link Namespace}. + * A skeletal class for implementing a interpreter ({@link Interpreter}). * *

    Derive classes usually override {@link #exec} instead of {@link #interpret}; * In addition, don't override {@link #getVariable}, @@ -48,17 +48,17 @@ *

    If an interpreter doesn't support hierachical scopes, * it can simply implement a global scope, and then use * {@link #getFromNamespace} to - * retrieve variables from ZK's hierachical namespaces. + * retrieve variables from ZK's hierachical scopes. * *

    If it supports hierachical scopes * (example: {@link org.zkoss.zk.scripting.bsh.BSHInterpreter}), it * can maintain a one-to-one relationship among interpreter's scopes - * and ZK's {@link Namespace}. Thus, it can retrieve - * the correct scope by giving ZK's {@link Namespace}, and vice versa. - * It also has to implement {@link #get(Namespace,String)}, {@link #contains(Namespace,String)} - * {@link #set(Namespace,String,Object)} and {@link #unset(Namespace,String)}. + * and ZK's {@link IdSpace}. Thus, it can retrieve + * the correct scope by giving ZK's {@link IdSpace}, and vice versa. + * It also has to implement {@link #get(Scope,String)}, {@link #contains(Scope,String)} + * {@link #set(Scope,String,Object)} and {@link #unset(Scope,String)}. * - *

    Whether to support hierachical namespaces is optional. + *

    Whether to support hierachical scopes is optional. * * @author tomyeh */ @@ -70,10 +70,10 @@ abstract public class GenericInterpreter implements Interpreter { public String toString() {return "undefined";} }; - /** A list of {@link Namespace}. - * Top of it is the current one (if null, it means Namespaces.getCurrent) + /** A list of {@link Scope}. + * Top of it is the current one (if null, it means Scopes.getCurrent) */ - private final List _nss = new LinkedList(); + private final List _scopes = new LinkedList(); private Page _owner; private String _zslang; @@ -103,7 +103,7 @@ protected boolean contains(String name) { * *

    {@link #beforeExec} is called first, before this method is invoked. * - *

    An empty (and fake) namespace is pushed so {@link #getFromNamespace} + *

    An empty (and fake) scope is pushed so {@link #getFromNamespace} * always returns null. */ protected Object get(String name) { @@ -127,19 +127,19 @@ protected void unset(String name) { } /** Tests whether a variable is defined in the interpreter's scope - * associated with the specified namespace. + * associated with the specified scope. * Optional. Implement it if the interpreter can tell the difference * between null and undefined. * - *

    By default, it tests whether {@link #get(Namespace, String)} + *

    By default, it tests whether {@link #get(Scope, String)} * returns non-null. - * @since 2.4.0 + * @since 5.0.0 */ - protected boolean contains(Namespace ns, String name) { - return get(ns, name) != null; + protected boolean contains(Scope scope, String name) { + return get(scope, name) != null; } /** Gets the variable from the interpreter's scope associated with - * the giving namespace. + * the giving scope. * Optional. Implement it if you want to expose variables defined * in the interpreter to Java codes. * @@ -150,14 +150,15 @@ protected boolean contains(Namespace ns, String name) { * *

    {@link #beforeExec} is called first, before this method is invoked. * - *

    An empty (and fake) namespace is pushed so {@link #getFromNamespace} + *

    An empty (and fake) scope is pushed so {@link #getFromNamespace} * always returns null. + * @since 5.0.0 */ - protected Object get(Namespace ns, String name) { + protected Object get(Scope scope, String name) { return get(name); } /** Sets the variable to the interpreter's scope associated with the - * giving namespace. + * giving scope. * Optional. Implement it if you want to allow Java codes to define * a variable in the interpreter. * @@ -167,9 +168,9 @@ protected Object get(Namespace ns, String name) { *

    Default: the same as {@link #set(String, Object)}. * *

    {@link #beforeExec} is called first, before this method is invoked. - * @since 2.4.0 + * @since 5.0.0 */ - protected void set(Namespace ns, String name, Object value) { + protected void set(Scope scope, String name, Object value) { set(name, value); } /** Removes the variable from the interpreter. @@ -182,24 +183,26 @@ protected void set(Namespace ns, String name, Object value) { *

    Default: the same as {@link #unset(String)}. * *

    {@link #beforeExec} is called first, before this method is invoked. - * @since 2.4.0 + * @since 5.0.0 */ - protected void unset(Namespace ns, String name) { + protected void unset(Scope scope, String name) { unset(name); } /** Called before {@link #exec}. - *

    Default: call {@link #beforeExec} and push the namespace + *

    Default: call {@link #beforeExec} and push the scope * as the active one. + * @since 5.0.0 */ - protected void beforeInterpret(Namespace ns) { + protected void beforeInterpret(Scope scope) { beforeExec(); - push(ns); //getFromNamespace will handle null + push(scope); //getFromNamespace will handle null } /** Called after {@link #exec}. *

    Default: call {@link #afterExec}. + * @since 5.0.0 */ - protected void afterInterpret(Namespace ns) { + protected void afterInterpret(Scope scope) { pop(); afterExec(); } @@ -215,21 +218,40 @@ protected void afterExec() { } //utilities// - /** Returns the variable through namespaces and variable resolvers, + /** Returns the variable through scopes and variable resolvers, * or {@link #UNDEFINED} if the variable not defined. * - *

    It is usually called to search namespaces and variable resolvers, + *

    It is usually called to search scopes and variable resolvers, * when the real interpreter failed to find a variable in its own scope. * *

    Note: We use {@link #UNDEFINED} to denote undefined since 2.4.0, * while null is a valid value. */ protected Object getFromNamespace(String name) { - final Namespace ns = getCurrent(); - if (ns != null) { - Object val = ns.getVariable(name, false); - if (val != null || ns.containsVariable(name, false)) - return val; + final Scope scope = getCurrent(); + if (scope != null) { //null means no scope allowed! + final Execution exec = Executions.getCurrent(); + if (exec != null && exec != scope) { + Object val = exec.getAttribute(name); + if (val != null /*|| exec.hasAttribute(name)*/) //request's hasAttribute same as getAttribute + return val; + } + + if (scope instanceof Component) { + Component comp = (Component)scope; + Object val = comp.getFellowOrAttribute(name, false); + if (val != null || comp.hasFellowOrAttribute(name, false)) + return val; + } else if (scope instanceof Page) { + Page page = (Page)scope; + Object val = page.getFellowOrAttribute(name, false); + if (val != null || page.hasFellowOrAttribute(name, false)) + return val; + } else { + Object val = scope.getAttribute(name, false); + if (val != null || scope.hasAttribute(name, false)) + return val; + } } return getImplicit(name); } @@ -245,39 +267,33 @@ protected static Object getImplicit(String name) { final Execution exec = Executions.getCurrent(); if (exec != null) return exec; } - return Namespaces.getImplicit(name, UNDEFINED); + return Scopes.getImplicit(name, UNDEFINED); } - /** Returns the variable through the specified namespaces and + /** Returns the variable through the specified scopes and * variable resolvers, or {@link #UNDEFINED} if the variable is not * defined. * - *

    It is usually called to search namespaces and variable resolvers, + *

    It is usually called to search scopes and variable resolvers, * when the real interpreter failed to find a variable in its own scope. * *

    This method is used with the interpreter that supports * hierachical scopes ({@link org.zkoss.zk.scripting.HierachicalAware}). * - * @param ns the namespace to search from (never null). + * @param scope the scope to search from (never null). * Note: if {@link #getCurrent} returns null, this method simply returns - * null (i.e., ignoring ns). - * @param localOnly whether to look for the current namespace only. - * If false, it looks up the parent namespace, if any. - * @since 3.6.0 - */ - protected Object getFromNamespace(Namespace ns, String name, boolean localOnly) { - if (getCurrent() != null) { - Object val = ns.getVariable(name, localOnly); - if (val != null || ns.containsVariable(name, localOnly)) + * null (i.e., ignoring scope). + * @param localOnly whether to look for the current scope only. + * If false, it looks up the parent scope, if any. + * @since 5.0.0 + */ + protected Object getFromNamespace(Scope scope, String name, boolean localOnly) { + if (getCurrent() != null) { //null means no scope allowed! + Object val = scope.getAttribute(name, localOnly); + if (val != null || scope.hasAttribute(name, localOnly)) return val; } return getImplicit(name); } - /** It is a shortcut of getFromNamespace(ns, name, false). - * @see #getFromNamespace(Namespace, String, boolean) - */ - protected Object getFromNamespace(Namespace ns, String name) { - return getFromNamespace(ns, name, false); - } //Interpreter// public void init(Page owner, String zslang) { @@ -296,20 +312,31 @@ public String getLanguage() { return _zslang; } - /** Handles the namespace and then invoke {@link #exec}. + /** @deprecated As of release 5.0.0, replaced with {@link #interpret(String, Scope}} + */ + public void interpret(String script, org.zkoss.zk.scripting.Namespace ns) { + Scope scope = null; + if (ns != null) { + scope = ns.getOwner(); + if (scope == null) scope = ns.getOwnerPage(); + } + interpret(script, scope); + } + /** Handles the scope and then invoke {@link #exec}. *

    Don't override this method, rather, override {@link #exec}. + * @since 5.0.0 */ - public void interpret(String script, Namespace ns) { + public void interpret(String script, Scope scope) { final String each = _owner.getLanguageDefinition().getEachTimeScript(_zslang); if (each != null) script = each + '\n' + script; - beforeInterpret(ns); + beforeInterpret(scope); try { exec(script); } finally { - afterInterpret(ns); + afterInterpret(scope); } } /** Returns null since retrieving class is not supported. @@ -324,9 +351,9 @@ public Function getFunction(String name, Class[] argTypes) { return null; } /** Returns null since retrieving methods is not supported. - * @since 3.0.0 + * @since 5.0.0 */ - public Function getFunction(Namespace ns, String name, Class[] argTypes) { + public Function getFunction(Scope scope, String name, Class[] argTypes) { return null; } @@ -338,7 +365,7 @@ public Function getFunction(Namespace ns, String name, Class[] argTypes) { public boolean containsVariable(String name) { beforeExec(); push(Objects.UNKNOWN); - //don't use null since it means Namespaces#getCurrent, see below + //don't use null since it means Scopes#getCurrent, see below try { return contains(name); } finally { @@ -353,7 +380,7 @@ public boolean containsVariable(String name) { public Object getVariable(String name) { beforeExec(); push(Objects.UNKNOWN); - //don't use null since it means Namespaces#getCurrent, see below + //don't use null since it means Scopes#getCurrent, see below try { return get(name); } finally { @@ -389,99 +416,101 @@ public final void unsetVariable(String name) { /** Tests whether the variable exists by using the specified name * as a reference to identify the interpreter's scope. * - *

    Deriving class shall override {@link #contains(Namespace,String)}, instead of this method. - * @since 2.4.0 + *

    Deriving class shall override {@link #contains(Scope,String)}, instead of this method. + * @since 5.0.0 */ - public boolean containsVariable(Namespace ns, String name) { + public boolean containsVariable(Scope scope, String name) { beforeExec(); push(Objects.UNKNOWN); - //don't use null since it means Namespaces#getCurrent, see below + //don't use null since it means Scopes#getCurrent, see below try { - return contains(ns, name); + return contains(scope, name); } finally { pop(); afterExec(); } } /** Returns the value of a variable defined in this interpreter's - * scope identified by the specified namespace. - * Note: it doesn't search the specified namespace ({@link Namespace}). + * scope identified by the specified scope. + * Note: it doesn't search the specified scope ({@link Scope}). * - *

    Deriving class shall override {@link #get(Namespace,String)}, + *

    Deriving class shall override {@link #get(Scope,String)}, * instead of this method. * *

    This method is part of {@link org.zkoss.zk.scripting.HierachicalAware}. * It is defined here to simplify the implementation of the * deriving classes, if they support the hierachical scopes. + * @since 5.0.0 */ - public Object getVariable(Namespace ns, String name) { + public Object getVariable(Scope scope, String name) { beforeExec(); push(Objects.UNKNOWN); - //don't use null since it means Namespaces#getCurrent, see below + //don't use null since it means Scopes#getCurrent, see below try { - return get(ns, name); + return get(scope, name); } finally { pop(); afterExec(); } } /** Sets the value of a variable to this interpreter's scope - * identified by the specified namespace. + * identified by the specified scope. * - *

    Deriving class shall override {@link #set(Namespace,String,Object)}, + *

    Deriving class shall override {@link #set(Scope,String,Object)}, * instead of this method. - * @since 2.4.0 + * @since 5.0.0 */ - public final void setVariable(Namespace ns, String name, Object value) { + public final void setVariable(Scope scope, String name, Object value) { beforeExec(); try { - set(ns, name, value); + set(scope, name, value); } finally { afterExec(); } } /** Removes the value of a variable defined in the interpreter's - * scope identified by the specified namespace. + * scope identified by the specified scope. * - *

    Deriving class shall override {@link #unset(Namespace,String)}, instead of this method. - * @since 2.4.0 + *

    Deriving class shall override {@link #unset(Scope,String)}, instead of this method. + * @since 5.0.0 */ - public final void unsetVariable(Namespace ns, String name) { + public final void unsetVariable(Scope scope, String name) { beforeExec(); try { - unset(ns, name); + unset(scope, name); } finally { afterExec(); } } - /** Use the specified namespace as the active namespace. + /** Use the specified scope as the active scope. */ - private void push(Object ns) { - _nss.add(0, ns); + private void push(Object scope) { + _scopes.add(0, scope); } - /** Remove the active namespace. + /** Remove the active scope. */ private void pop() { - _nss.remove(0); + _scopes.remove(0); } - /** Returns the current namespace, or null if no namespace is allowed. + /** Returns the current scope, or null if no scope is allowed. * Note: if this method returns null, it means the interpreter shall - * not search variables defined in ZK namespace. + * not search variables defined in ZK scope. * - *

    This method will handle {@link Namespaces#getCurrent} automatically. + *

    This method will handle {@link Scopes#getCurrent} automatically. + * @since 5.0.0 */ - protected Namespace getCurrent() { - if (!_nss.isEmpty()) { - Object o = _nss.get(0); + protected Scope getCurrent() { + if (!_scopes.isEmpty()) { + Object o = _scopes.get(0); if (o == Objects.UNKNOWN) - return null; //no namespace allowed + return null; //no scope allowed if (o != null) - return (Namespace)o; - //we assume owner's namespace if null, because zscript might + return (Scope)o; + //we assume owner's scope if null, because zscript might //define a class that will be invoke thru, say, event listener - //In other words, interpret is not called, so ns is not specified + //In other words, interpret is not called, so scope is not specified } - return Namespaces.getCurrent(_owner); //never null + return Scopes.getCurrent(_owner); //never null } } diff --git a/zk/src/org/zkoss/zk/scripting/util/SimpleNamespace.java b/zk/src/org/zkoss/zk/scripting/util/SimpleNamespace.java deleted file mode 100644 index 446246d6ce7..00000000000 --- a/zk/src/org/zkoss/zk/scripting/util/SimpleNamespace.java +++ /dev/null @@ -1,137 +0,0 @@ -/* SimpleNamespace.java - -{{IS_NOTE - Purpose: - - Description: - - History: - Tue May 8 12:56:25 2007, Created by tomyeh -}}IS_NOTE - -Copyright (C) 2007 Potix Corporation. All Rights Reserved. - -{{IS_RIGHT - This program is distributed under GPL Version 3.0 in the hope that - it will be useful, but WITHOUT ANY WARRANTY. -}}IS_RIGHT -*/ -package org.zkoss.zk.scripting.util; - -import java.util.Iterator; -import java.util.Set; -import java.util.Map; -import java.util.HashMap; - -import org.zkoss.zk.ui.Page; -import org.zkoss.zk.ui.Component; -import org.zkoss.zk.scripting.Namespace; - -/** - * A simple implementation of {@link Namespace}. - * - * @author tomyeh - */ -public class SimpleNamespace extends AbstractNamespace { - private Namespace _parent; - private final Map _vars; - private final Component _owner; - - public SimpleNamespace() { - _vars = new HashMap(8); - _owner = null; - } - /** - * @param owner the owner of this namespace. - * If not null, the fellow of the owner is considered as part of this namespace. - * In other words, {@link #containsVariable} and {@link #getVariable} - * will check {@link Component#getFellow}. - * @since 3.0.0 - */ - public SimpleNamespace(Component owner) { - _vars = new HashMap(8); - _owner = owner; - } - - /** Copies all variables from the specified namespace. - * Note: only variables local to the specified namespace is copied. - */ - public void copy(Namespace ns) { - for (Iterator it = ns.getVariableNames().iterator(); it.hasNext();) { - final String name = (String)it.next(); - final Object value = ns.getVariable(name, true); - _vars.put(name, value); - notifyAdd(name, value); - } - } - - //Namespace// - public Component getOwner() { - return _owner; - } - public Page getOwnerPage() { - return _owner != null ? _owner.getPage(): null; - } - public Set getVariableNames() { - return _vars.keySet(); - } - public boolean containsVariable(String name, boolean local) { - return _vars.containsKey(name) - || (_owner != null && _owner.getFellowIfAny(name) != null) - || (!local && _parent != null && _parent.containsVariable(name, false)); - } - public Object getVariable(String name, boolean local) { - Object val = _vars.get(name); - if (val != null || _vars.containsKey(name)) - return val; - - if (_owner != null) { - val = _owner.getFellowIfAny(name); - if (val != null) - return val; - } - return local || _parent == null ? null: _parent.getVariable(name, false); - } - public void setVariable(String name, Object value, boolean local) { - if (!local && _parent != null && !_vars.containsKey(name)) { - for (Namespace p = _parent;;) { - if (p.getVariableNames().contains(name)) { - p.setVariable(name, value, true); - return; //done; - } - if ((p = p.getParent()) == null) - break; - } - } - - _vars.put(name, value); - notifyAdd(name, value); - } - public void unsetVariable(String name, boolean local) { - if (_vars.remove(name) != null || _vars.containsKey(name)) { - notifyRemove(name); - } else if (!local && _parent != null) { - for (Namespace p = _parent; p != null; p = p.getParent()) { - if (p.getVariableNames().contains(name)) { - p.unsetVariable(name, true); - break; - } - if ((p = p.getParent()) == null) - break; - } - } - } - - public Namespace getParent() { - return _parent; - } - public void setParent(Namespace parent) { - if (_parent != parent) { - for (Namespace p = parent; p != null; p = p.getParent()) - if (p == this) - throw new IllegalArgumentException("Recursive namespace: "+this+" with "+parent); - _parent = parent; - notifyParentChanged(parent); - } - } -} diff --git a/zk/src/org/zkoss/zk/ui/AbstractComponent.java b/zk/src/org/zkoss/zk/ui/AbstractComponent.java index 7b60ef837dc..3fb29fd680b 100644 --- a/zk/src/org/zkoss/zk/ui/AbstractComponent.java +++ b/zk/src/org/zkoss/zk/ui/AbstractComponent.java @@ -56,6 +56,8 @@ import org.zkoss.zk.ui.ext.Macro; import org.zkoss.zk.ui.ext.RawId; import org.zkoss.zk.ui.ext.NonFellow; +import org.zkoss.zk.ui.ext.SimpleScope; +import org.zkoss.zk.ui.ext.ScopeListener; import org.zkoss.zk.ui.ext.render.Cropper; import org.zkoss.zk.ui.util.ComponentSerializationListener; import org.zkoss.zk.ui.util.ComponentActivationListener; @@ -91,10 +93,7 @@ import org.zkoss.zk.au.AuResponse; import org.zkoss.zk.au.AuService; import org.zkoss.zk.au.out.AuClientInfo; -import org.zkoss.zk.scripting.Namespace; -import org.zkoss.zk.scripting.Interpreter; -import org.zkoss.zk.scripting.NamespaceActivationListener; -import org.zkoss.zk.scripting.util.SimpleNamespace; +import org.zkoss.zk.scripting.*; /** * A skeletal implementation of {@link Component}. Though it is OK @@ -119,7 +118,7 @@ public class AbstractComponent private String _mold = "default"; /** The info of the ID space, or null if IdSpace is NOT implemented. */ private transient SpaceInfo _spaceInfo; - private transient Map _attrs; + private transient SimpleScope _attrs; //don't create it dynamically because _ip bind it at constructor /** A map of event listener: Map(evtnm, List(EventListener)). */ private transient Map _listeners; @@ -212,9 +211,9 @@ public AbstractComponent() { } } - init(false); + init(); - _spaceInfo = this instanceof IdSpace ? new SpaceInfo(this): null; + _spaceInfo = this instanceof IdSpace ? new SpaceInfo(): null; // if (D.ON && log.debugable()) log.debug("Create comp: "+this); } @@ -275,11 +274,9 @@ ComponentDefinition lookupDefinition(Execution exec, Class cls) { /** Initialize for contructor and serialization. * @param cloning whether this method is called by clone() */ - private void init(boolean cloning) { + private void init() { _apiChildren = newChildren(); - - if (!cloning) - _attrs = new HashMap(4); + _attrs = new SimpleScope(); } /** * Creates and returns the instance for storing child components. @@ -610,9 +607,6 @@ private void setPage0(Page page) { onPageDetached(oldpage); } - if (_spaceInfo != null && _parent == null) - _spaceInfo.ns.setParent(page != null ? page.getNamespace(): null); - //process all children recursively for (AbstractComponent p = _first; p != null; p = p._next) p.setPage0(page); //recursive @@ -799,7 +793,7 @@ public Map getAttributes(int scope) { switch (scope) { case SPACE_SCOPE: if (this instanceof IdSpace) - return _spaceInfo.attrs; + return _attrs.getAttributes(); final IdSpace idspace = getSpaceOwner(); return idspace instanceof Page ? ((Page)idspace).getAttributes(): idspace == null ? Collections.EMPTY_MAP: @@ -817,7 +811,7 @@ public Map getAttributes(int scope) { return _page != null ? _page.getDesktop().getWebApp().getAttributes(): Collections.EMPTY_MAP; case COMPONENT_SCOPE: - return _attrs; + return _attrs.getAttributes(); case REQUEST_SCOPE: final Execution exec = getExecution(); if (exec != null) return exec.getAttributes(); @@ -833,6 +827,9 @@ private final Execution getExecution() { public Object getAttribute(String name, int scope) { return getAttributes(scope).get(name); } + public boolean hasAttribute(String name, int scope) { + return getAttributes(scope).containsKey(name); + } public Object setAttribute(String name, Object value, int scope) { if (value != null) { final Map attrs = getAttributes(scope); @@ -852,27 +849,126 @@ public Object removeAttribute(String name, int scope) { } public final Map getAttributes() { - return _attrs; + return _attrs.getAttributes(); } public final Object getAttribute(String name) { - return _attrs.get(name); + return _attrs.getAttribute(name); + } + public boolean hasAttribute(String name) { + return _attrs.hasAttribute(name); } public final Object setAttribute(String name, Object value) { - return value != null ? _attrs.put(name, value): _attrs.remove(name); + return _attrs.setAttribute(name, value); } public final Object removeAttribute(String name) { - return _attrs.remove(name); + return _attrs.removeAttribute(name); + } + + public Object getAttribute(String name, boolean local) { + Object val = getAttribute(name); + if (val != null || local || hasAttribute(name)) + return val; + + if (_parent != null) + return _parent.getAttribute(name, false); + if (_page != null) + return _page.getAttribute(name, false); + return null; + } + public boolean hasAttribute(String name, boolean local) { + if (hasAttribute(name)) + return true; + + if (!local) { + if (_parent != null) + return _parent.hasAttribute(name, false); + if (_page != null) + return _page.hasAttribute(name, false); + } + return false; + } + + public Object getFellowOrAttribute(String name, boolean local) { + if (this instanceof IdSpace) { + Object val = _spaceInfo.vars.get(name); //backward compatible (variable first) + if (val != null || _spaceInfo.vars.containsKey(name)) + return val; + } + + Object val = getAttribute(name); + if (val != null || hasAttribute(name)) + return val; + + if (this instanceof IdSpace) { //fellow last + val = getFellowIfAny(name); + if (val != null) + return val; + } + + if (!local) { + if (_parent != null) + return _parent.getFellowOrAttribute(name, false); + if (_page != null) + return _page.getFellowOrAttribute(name, false); + } + return null; + } + public boolean hasFellowOrAttribute(String name, boolean local) { + if (hasAttribute(name) + || (this instanceof IdSpace && (hasFellow(name) + || _spaceInfo.vars.containsKey(name)))) //backward compatible + return true; + + if (!local) { + if (_parent != null) + return _parent.hasFellowOrAttribute(name, false); + if (_page != null) + return _page.hasFellowOrAttribute(name, false); + } + return false; } + public Object setAttribute(String name, Object value, boolean local) { + if (!local) { + for (Component p = this; (p = p.getParent()) != null;) + if (p.hasAttribute(name)) + return p.setAttribute(name, value); + if (_page != null && _page.hasAttribute(name)) + return _page.setAttribute(name, value); + } + return setAttribute(name, value); + } + public Object removeAttribute(String name, boolean local) { + if (!local) { + for (Component p = this; (p = p.getParent()) != null;) + if (p.hasAttribute(name)) + return p.removeAttribute(name); + if (_page != null && _page.hasAttribute(name)) + return _page.removeAttribute(name); + } + return removeAttribute(name); + } + + public boolean addScopeListener(ScopeListener listener) { + return _attrs.addScopeListener(listener); + } + public boolean removeScopeListener(ScopeListener listener) { + return _attrs.removeScopeListener(listener); + } + + /** @deprecated As of release 5.0.0, replaced with {@link #setAttribute}. */ public void setVariable(String name, Object val, boolean local) { getNamespace().setVariable(name, val, local); } + /** @deprecated As of release 5.0.0, replaced with {@link #hasAttribute}. */ public boolean containsVariable(String name, boolean local) { return getNamespace().containsVariable(name, local); } + /** @deprecated As of release 5.0.0, replaced with {@link #getAttribute}. */ public Object getVariable(String name, boolean local) { return getNamespace().getVariable(name, local); } + /** @deprecated As of release 5.0.0, replaced with {@link #removeAttribute}. */ public void unsetVariable(String name, boolean local) { getNamespace().unsetVariable(name, local); } @@ -932,7 +1028,6 @@ public void setParent(Component parent) { addMoved(op, _page, newpg); //Not depends on UUID setPage0(newpg); //UUID might be changed here - fixSpaceParentDown(this, _parent != null ? _parent.getNamespace(): null); if (idSpaceChanged) addToIdSpacesDown(this); //called after setPage //call back UiLifeCycle @@ -945,13 +1040,6 @@ public void setParent(Component parent) { } } } - private static void fixSpaceParentDown(AbstractComponent comp, Namespace ns) { - if (comp._spaceInfo != null) //ID space owner - comp._spaceInfo.ns.setParent(ns); - else //Bug 2468048: we have to check all children - for (comp = comp._first; comp != null; comp = comp._next) - fixSpaceParentDown(comp, ns); - } private void afterComponentPageChanged(Page newpg, Page oldpg) { if (newpg == oldpg) return; @@ -1856,6 +1944,9 @@ private boolean removeForward0( return false; } + /** @deprecated As of release 5.0.0, use {@link #getAttribute}, + * {@link #setAttribute} instead. + */ public Namespace getNamespace() { if (this instanceof IdSpace) return _spaceInfo.ns; @@ -2046,21 +2137,18 @@ private void unshareAnnotationMap(boolean autocreate) { } public void sessionWillPassivate(Page page) { - willPassivate(_attrs.values()); + willPassivate(_attrs.getAttributes().values()); if (_listeners != null) for (Iterator it = _listeners.values().iterator(); it.hasNext();) willPassivate((Collection)it.next()); if (this instanceof IdSpace) { - willPassivate(_spaceInfo.attrs.values()); - - //Invoke NamespaceActivationListener after all loaded for (Iterator it = _spaceInfo.ns.getVariableNames().iterator(); it.hasNext();) { final Object val = _spaceInfo.ns.getVariable((String)it.next(), true); willPassivate(val); - if (val instanceof NamespaceActivationListener) + if (val instanceof NamespaceActivationListener) //backward compatible ((NamespaceActivationListener)val).willPassivate(_spaceInfo.ns); } } @@ -2068,21 +2156,18 @@ public void sessionWillPassivate(Page page) { public void sessionDidActivate(Page page) { sessDidActivate0(page, this, true); - didActivate(_attrs.values()); + didActivate(_attrs.getAttributes().values()); if (_listeners != null) for (Iterator it = _listeners.values().iterator(); it.hasNext();) didActivate((Collection)it.next()); if (this instanceof IdSpace) { - didActivate(_spaceInfo.attrs.values()); - - //Invoke NamespaceActivationListener after all loaded for (Iterator it = _spaceInfo.ns.getVariableNames().iterator(); it.hasNext();) { final Object val = _spaceInfo.ns.getVariable((String)it.next(), true); didActivate(val); - if (val instanceof NamespaceActivationListener) + if (val instanceof NamespaceActivationListener) //backward compatible ((NamespaceActivationListener)val).didActivate(_spaceInfo.ns); } } @@ -2099,7 +2184,7 @@ private static void sessDidActivate0(Page page, //Others are handled by readObject if (pageLevelIdSpace && comp._spaceInfo != null) { pageLevelIdSpace = false; - comp._spaceInfo.ns.setParent(page.getNamespace()); + comp._spaceInfo.ns.setParent(page.getNamespace()); //backward compatible } for (AbstractComponent p = comp._first; p != null; p = p._next) { @@ -2259,25 +2344,69 @@ public final boolean equals(Object o) { //no more override } /** Holds info shared of the same ID space. */ - private static class SpaceInfo { - private Map attrs = new HashMap(8); - //don't create it dynamically because _ip bind it at constructor - private SimpleNamespace ns; + private class SpaceInfo { + private NS ns; /** A map of ((String id, Component fellow). */ private Map fellows = new HashMap(32); + /** deprecated (for backward compatible). */ + private final Map vars = new HashMap(4); + + private SpaceInfo() { + ns = new NS(); + init(); + } + private void init() { + ns.setVariable("spaceScope", AbstractComponent.this._attrs, true); + ns.setVariable("spaceOwner", AbstractComponent.this, true); + } + /** @deprecated */ + private class NS implements Namespace { + //Namespace// + public Component getOwner() { + return AbstractComponent.this; + } + public Page getOwnerPage() { + return AbstractComponent.this._page; + } + public Set getVariableNames() { + return vars.keySet(); + } + public boolean containsVariable(String name, boolean local) { + return vars.containsKey(name) || hasFellow(name); + } + public Object getVariable(String name, boolean local) { + Object val = vars.get(name); + if (val != null || vars.containsKey(name)) + return val; - private SpaceInfo(Component owner) { - ns = new SimpleNamespace(owner); - init(owner); - } - private SpaceInfo(Component owner, SimpleNamespace from) { - ns = new SimpleNamespace(owner); - ns.copy(from); - init(owner); - } - private void init(Component owner) { - ns.setVariable("spaceScope", attrs, true); - ns.setVariable("spaceOwner", owner, true); + val = getFellowIfAny(name); + return val != null ? val: null; + } + public void setVariable(String name, Object value, boolean local) { + vars.put(name, value); + } + public void unsetVariable(String name, boolean local) { + vars.remove(name); + } + + /** @deprecated */ + public Namespace getParent() { + final IdSpace owner = getSpaceOwnerOfParent(AbstractComponent.this); + return owner instanceof Component ? ((Component)owner).getNamespace(): + owner instanceof Page ? ((Page)owner).getNamespace(): null; + } + /** @deprecated */ + public void setParent(Namespace parent) { + throw new UnsupportedOperationException(); + } + /** @deprecated */ + public boolean addChangeListener(NamespaceChangeListener listener) { + return false; + } + /** @deprecated */ + public boolean removeChangeListener(NamespaceChangeListener listener) { + return false; + } } } @@ -2390,15 +2519,16 @@ public Object clone() { clone._xtrl = null; //Bug 1892396: _xtrl is an inner object so recreation is required //1a. clone attributes - clone._attrs = new HashMap(4); - for (Iterator it = _attrs.entrySet().iterator(); it.hasNext();) { + clone._attrs = new SimpleScope(); + for (Iterator it = _attrs.getAttributes().entrySet().iterator(); + it.hasNext();) { final Map.Entry me = (Map.Entry)it.next(); Object val = me.getValue(); if (val instanceof ComponentCloneListener) { val = ((ComponentCloneListener)val).clone(clone); if (val == null) continue; //don't use it in clone } - clone._attrs.put(me.getKey(), val); + clone._attrs.getAttributes().put(me.getKey(), val); } //1b. clone listeners @@ -2433,12 +2563,13 @@ public Object clone() { //2. clone children (deep cloning) cloneChildren(clone); - clone.init(true); + clone.init(); + clone._attrs = (SimpleScope)_attrs.clone(); //3. spaceinfo if (clone._spaceInfo != null) { - clone._spaceInfo = new SpaceInfo(clone, _spaceInfo.ns); - cloneSpaceInfo(clone, this._spaceInfo); + clone._spaceInfo = clone.new SpaceInfo(); + clone.cloneSpaceInfoFrom(this._spaceInfo); } //4. clone _forwards @@ -2462,25 +2593,22 @@ public Object clone() { clone._ausvc = (AuService)((ComponentCloneListener)val).clone(clone); return clone; } - private static final - void cloneSpaceInfo(AbstractComponent clone, SpaceInfo from) { - final SpaceInfo to = clone._spaceInfo; - to.attrs = new HashMap(8); - for (Iterator it = from.attrs.entrySet().iterator(); it.hasNext();) { + private final void cloneSpaceInfoFrom(SpaceInfo from) { + for (Iterator it = from.vars.entrySet().iterator(); it.hasNext();) { final Map.Entry me = (Map.Entry)it.next(); Object val = me.getValue(); if (val instanceof ComponentCloneListener) { - val = ((ComponentCloneListener)val).clone(clone); + val = ((ComponentCloneListener)val).clone(this); if (val == null) continue; //don't use it in clone } - to.attrs.put(me.getKey(), val); + this._spaceInfo.vars.put(me.getKey(), val); } //rebuild ID space by binding itself and all children - if (!ComponentsCtrl.isAutoId(getIdDirectly(clone))) - clone.bindToIdSpace(clone); - for (AbstractComponent p = clone._first; p != null; p = p._next) - addToIdSpacesDown(p, clone); + if (!ComponentsCtrl.isAutoId(getIdDirectly(this))) + this.bindToIdSpace(this); + for (AbstractComponent p = _first; p != null; p = p._next) + addToIdSpacesDown(p, this); } private static final void cloneChildren(final AbstractComponent comp) { AbstractComponent q = null; @@ -2527,8 +2655,9 @@ private synchronized void writeObject(java.io.ObjectOutputStream s) s.writeObject(null); //write attrs - willSerialize(_attrs.values()); - Serializables.smartWrite(s, _attrs); + final Map attrs = _attrs.getAttributes(); + willSerialize(attrs.values()); + Serializables.smartWrite(s, attrs); if (_listeners != null) for (Iterator it = _listeners.entrySet().iterator(); it.hasNext();) { @@ -2543,10 +2672,6 @@ private synchronized void writeObject(java.io.ObjectOutputStream s) //store _spaceInfo if (this instanceof IdSpace) { - //write _spaceInfo.attrs - willSerialize(_spaceInfo.attrs.values()); - Serializables.smartWrite(s, _spaceInfo.attrs); - //write _spaceInfo.ns (only variables that are not fellows) for (Iterator it = _spaceInfo.ns.getVariableNames().iterator(); it.hasNext();) { @@ -2602,7 +2727,7 @@ private synchronized void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { s.defaultReadObject(); - init(false); + init(); //read definition Object def = s.readObject(); @@ -2630,8 +2755,9 @@ private synchronized void readObject(java.io.ObjectInputStream s) } //read attrs - Serializables.smartRead(s, _attrs); - didDeserialize(_attrs.values()); + final Map attrs = _attrs.getAttributes(); + Serializables.smartRead(s, attrs); + didDeserialize(attrs.values()); for (;;) { final String evtnm = (String)s.readObject(); @@ -2645,11 +2771,7 @@ private synchronized void readObject(java.io.ObjectInputStream s) //restore _spaceInfo if (this instanceof IdSpace) { - _spaceInfo = new SpaceInfo(this); - - //fix children's _spaceInfo's parent - for (AbstractComponent child = _first; child != null; child = child._next) - fixSpaceParentDown(child, _spaceInfo.ns); + _spaceInfo = new SpaceInfo(); //restore ID space by binding itself and all children if (!ComponentsCtrl.isAutoId(getIdDirectly(this))) @@ -2657,10 +2779,6 @@ private synchronized void readObject(java.io.ObjectInputStream s) for (AbstractComponent ac = _first; ac != null; ac = ac._next) addToIdSpacesDown(ac, this); - //read _spaceInfo.attrs - Serializables.smartRead(s, _spaceInfo.attrs); - didDeserialize(_spaceInfo.attrs.values()); - //_spaceInfo.ns for (;;) { final String nm = (String)s.readObject(); diff --git a/zk/src/org/zkoss/zk/ui/Component.java b/zk/src/org/zkoss/zk/ui/Component.java index 3c315dd2391..72530260b36 100644 --- a/zk/src/org/zkoss/zk/ui/Component.java +++ b/zk/src/org/zkoss/zk/ui/Component.java @@ -27,7 +27,6 @@ import org.zkoss.zk.ui.ext.Scope; import org.zkoss.zk.ui.metainfo.ComponentDefinition; import org.zkoss.zk.ui.event.EventListener; -import org.zkoss.zk.scripting.Namespace; import org.zkoss.zk.au.AuService; /** @@ -88,7 +87,7 @@ public interface Component extends Scope, java.io.Serializable, Cloneable { * See {@link IdSpace} for more details. * *

    The ID space relevant methods include {@link #getFellow}, - * {@link #getAttribute} and {@link #getVariable}. + * {@link #getAttribute} and {@link #getFellowOrAttribute}. * * @see #getNamespace */ @@ -243,6 +242,10 @@ public interface Component extends Scope, java.io.Serializable, Cloneable { * @since 3.0.6 */ public Collection getFellows(); + /** Returns whether a fellow exists in the same ID space of this component. + * @since 5.0.0 + */ + public boolean hasFellow(String compId); /** Returns the next sibling, or null if it is the last child. * @since 3.0.0 @@ -338,6 +341,25 @@ public interface Component extends Scope, java.io.Serializable, Cloneable { * {@link #REQUEST_SCOPE} or {@link #APPLICATION_SCOPE}, */ public Object getAttribute(String name, int scope); + /** Returns if the custom attribute is associate with this component. + *

    If scope is {@link #COMPONENT_SCOPE}, it means attributes private + * to this component. + *

    If scope is {@link #SPACE_SCOPE}, it means custom attributes shared + * by components from the same ID space as this one's. + *

    If scope is {@link #PAGE_SCOPE}, it means custom attributes shared + * by components from the same page as this one's. + *

    If scope is {@link #DESKTOP_SCOPE}, it means custom attributes shared + * by components from the same desktopas this one's. + * + *

    Notice that null is a valid value, so you can + * tell if an attribute is assoicated by examining the return value + * of {@link #getAttribute}. + * @param scope {@link #COMPONENT_SCOPE}, {@link #SPACE_SCOPE}, + * {@link #PAGE_SCOPE}, {@link #DESKTOP_SCOPE}, {@link #SESSION_SCOPE}, + * {@link #REQUEST_SCOPE} or {@link #APPLICATION_SCOPE}, + * @since 5.0.0 + */ + public boolean hasAttribute(String name, int scope); /** Sets the value of the specified custom attribute in the specified scope. * *

    Note: The attribute is removed (by {@link #removeAttribute} @@ -382,6 +404,13 @@ public interface Component extends Scope, java.io.Serializable, Cloneable { * {@link #COMPONENT_SCOPE}. */ public Object getAttribute(String name); + /** Returns if the custom attribute is associate with this component. + *

    Notice that null is a valid value, so you can + * tell if an attribute is assoicated by examining the return value + * of {@link #getAttribute}. + * @since 5.0.0 + */ + public boolean hasAttribute(String name); /** Sets the custom attribute associated with this component, i.e., * {@link #COMPONENT_SCOPE}. */ @@ -391,10 +420,50 @@ public interface Component extends Scope, java.io.Serializable, Cloneable { */ public Object removeAttribute(String name); - /** Sets a variable to the namespace. + /** Sets the custom attribute associated with this component, or the parent + * component. + * @param local whether not to look up the parent component for the + * existence of the attribute.
    + * If local is false and the attribute is defined in + * one of its ancestor (including page), the attribute is replaced. + * Otherwise, it is the same as {@link #setAttribute(String,Object)}. + * @since 5.0.0 + */ + public Object setAttribute(String name, Object value, boolean local); + /** Removes the custom attribute associated with this component, i.e., + * {@link #COMPONENT_SCOPE}. + * @param local whether not to look up the parent component for the + * existence of the attribute.
    + * If local is false and the attribute is defined in + * one of its ancestor (including page), the attribute is removed. + * Otherwise, it is the same as {@link #removeAttribute(String)}. + * @since 5.0.0 + */ + public Object removeAttribute(String name, boolean local); + + /** Returns the custom attribute associated with this component, + * or the fellow of this component. * - *

    This method is the same as - * getNamespace().setVariable(name, value, local). + * @param local whether not to look up the parent component for the + * existence of the attribute.
    + * Notice that, if local is false and this component is not an ID + * space owner, it won't look at the fellow + * @since 5.0.0 + */ + public Object getFellowOrAttribute(String name, boolean local); + /** Returns if a custom attribute is associated with this component, + * or the fellow of this component. + * + * @param local whether not to look up the parent component for the + * existence of the attribute.
    + * Notice that, if local is false and this component is not an ID + * space owner, it won't look at the fellow + * @since 5.0.0 + */ + public boolean hasFellowOrAttribute(String name, boolean local); + + /** @deprecated As of release 5.0.0, replaced with {@link #setAttribute}. + *

    Sets a variable to the namespace. * *

    Once a variable is set thru this method, it is visible to * both the interpreter and EL. @@ -405,30 +474,15 @@ public interface Component extends Scope, java.io.Serializable, Cloneable { * Otherwise, it is the same as the namspace returned by the component * owning this ID space. * - *

    When to use setVariable and setAttribute?

    - * - *

    First, only the ID space support {@link #setVariable} and so. - * Second, the variables can be referenced directly in zscript and EL - * expressions, while attributes are referenced thru the scope, - * such as spaceScope. - * On the other hand, using attributes causes less name popultion. - * In general, if you could use attributes, don't use variable. - * * @param local whether not to search any of the ancestor namespace defines * the variable. If local is false and an ancesotor has defined a variable * with the same name, the variable in the ancestor is changed directly. * Otherwise, a new variable is created in the namespace containing * this component. - * @see #getSpaceOwner - * @see #getNamespace */ public void setVariable(String name, Object val, boolean local); - /** Returns whether the specified variable is defined. - * - *

    Note: null is a valid value for variable, so this method is used - * to know whether a variable is defined. - * On the other hand, {@link #setAttribute} actually remove - * an attribute (by {@link #removeAttribute} if value is null. + /** @deprecated As of release 5.0.0, replaced with {@link #hasFellowOrAttribute}. + *

    Returns whether the specified variable is defined. * * @param local whether not to search its ancestor. * If false and the current namespace doen't define the variable, @@ -436,36 +490,23 @@ public interface Component extends Scope, java.io.Serializable, Cloneable { * any of them has defined the specified variable. */ public boolean containsVariable(String name, boolean local); - /** Returns the value of a variable defined in the namespace, + /** @deprecated As of release 5.0.0, replaced with {@link #getFellowOrAttribute}. + *

    Returns the value of a variable defined in the namespace, * or null if not defined or the value is null. * - *

    This method is the same as getNamespace().getVariable(name, local). - * - *

    Differences between {@link #getVariable} and {@link Page#getZScriptVariable}

    - * - *

    {@link #getVariable} returns only variables defined by - * {@link #setVariable} (i.e., a shortcut of {@link Namespace#setVariable}). - * On the other hand, {@link Page#getZScriptVariable} returns these variables - * and those defined when executing zscripts. - * * @param local whether not to search its ancestor. * If false and the current namespace doen't define the variable, * it searches up its ancestor (via {@link #getParent}) to see * any of them has defined the specified variable. - * @see #getSpaceOwner - * @see #getNamespace */ public Object getVariable(String name, boolean local); - /** Unsets a variable defined in the namespace. - * - *

    This method is the same as getNamespace().getVariable(name, local). + /** @deprecated As of release 5.0.0, replaced with {@link #removeAttribute}. + *

    Unsets a variable defined in the namespace. * * @param local whether not to search its ancestor. * If false and the current namespace doen't define the variable, * it searches up its ancestor (via {@link #getParent}) to see * any of them has defined the specified variable. - * @see #getSpaceOwner - * @see #getNamespace */ public void unsetVariable(String name, boolean local); @@ -744,7 +785,9 @@ public boolean removeForward( */ public void invalidate(); - /** Returns the namespace to store variables and functions belonging + /** @deprecated As of release 5.0.0, the concept of namespace + * is replaced with attributes. + *

    Returns the namespace to store variables and functions belonging * to the ID space of this component. * *

    Exactly one namespace is allocated for each ID space. @@ -752,16 +795,8 @@ public boolean removeForward( * the returned namespace is the same as {@link Page#getNamespace}. * Otherwise, it is the same as the namspace returned by the component * owning this ID space. - * - *

    Namspace is another part of an ID space. It holds only variables - * defined thru {@link #setVariable} (and {@link Namespace#setVariable}. - * - *

    Note: The namespace doesn't include any variable defined by - * executing zscripts. To retrieve them, use {@link Page#getZScriptVariable}. - * - * @see #getSpaceOwner */ - public Namespace getNamespace(); + public org.zkoss.zk.scripting.Namespace getNamespace(); /** Initializes the properties (aka. members) and custom-attributes * based on what are defined in the component definition. diff --git a/zk/src/org/zkoss/zk/ui/Components.java b/zk/src/org/zkoss/zk/ui/Components.java index c6284c3c08a..8bb2b9be613 100644 --- a/zk/src/org/zkoss/zk/ui/Components.java +++ b/zk/src/org/zkoss/zk/ui/Components.java @@ -51,6 +51,7 @@ import org.zkoss.zk.ui.event.EventListener; import org.zkoss.zk.ui.metainfo.PageDefinition; import org.zkoss.zk.ui.sys.ExecutionCtrl; +import org.zkoss.zk.ui.ext.ScopeListener; import org.zkoss.zk.xel.Evaluator; import org.zkoss.zk.ui.event.Events; @@ -518,7 +519,7 @@ void wireController(Component comp, Object controller, char separator) { *

    The controller is a POJO file with onXxx$myid methods (the event handler * codes). This utility method search such onXxx$myid methods and adds * forward condition to the source myid component looked up by - * {@link Component#getVariable} of the specified component, so you + * {@link Component#getFellowOrAttribute} of the specified component, so you * don't have to specify in zul file the "forward" attribute one by one. * If the source component cannot be looked up or the object looked up is * not a component, this method will log the error and ignore it. @@ -564,7 +565,7 @@ void addForwards(Component comp, Object controller, char separator) { final String srcevt = mdname.substring(0, k); if ((k+1) < mdname.length()) { final String srccompid = mdname.substring(k+1); - final Object srccomp = xcomp.getVariable(srccompid, false); + final Object srccomp = xcomp.getFellowOrAttribute(srccompid, false); if (srccomp == null || !(srccomp instanceof Component)) { if (log.debugable()) { log.debug("Cannot find the associated component to forward event: "+mdname); @@ -789,18 +790,18 @@ public Wire(Object controller, char separator) { public void wireController(Component comp, String id) { //feature #2778513, support {id}$composer name final String composerid = id + _separator + "composer"; - if (!comp.containsVariable(composerid, true)) { - comp.setVariable(composerid, _controller, true); + if (!comp.hasFellowOrAttribute(composerid, true)) { + comp.setAttribute(composerid, _controller); } - comp.setVariable(varname(id, _controller.getClass()), _controller, true); + comp.setAttribute(varname(id, _controller.getClass()), _controller); } public void wireController(Page page, String id) { final String composerid = id + _separator + "composer"; - if (!page.containsVariable(composerid)) { - page.setVariable(composerid, _controller); + if (!page.hasFellowOrAttribute(composerid, true)) { + page.setAttribute(composerid, _controller); } - page.setVariable(varname(id, _controller.getClass()), _controller); + page.setAttribute(varname(id, _controller.getClass()), _controller); } public void wireFellows(IdSpace idspace) { @@ -895,12 +896,12 @@ private boolean containsVariable(Object x, String fdname) { if (x instanceof Page) { final Page pg = (Page) x; return pg.getZScriptVariable(fdname) != null - || pg.containsVariable(fdname); + || pg.hasFellowOrAttribute(fdname, false); } else { final Component cmp = (Component) x; final Page page = getPage(cmp); return (page != null && page.getZScriptVariable(cmp, fdname) != null) - || cmp.containsVariable(fdname, false); + || cmp.hasFellowOrAttribute(fdname, false); } } @@ -910,7 +911,7 @@ private Object getVariable(Object x, String fdname) { final Page pg = (Page) x; Object arg = pg.getZScriptVariable(fdname); if (arg == null) { - arg = pg.getVariable(fdname); + arg = pg.getFellowOrAttribute(fdname, false); } return arg; } else { @@ -918,7 +919,7 @@ private Object getVariable(Object x, String fdname) { final Page page = getPage(cmp); Object arg = page != null ? page.getZScriptVariable(cmp, fdname): null; if (arg == null) { - arg = cmp.getVariable(fdname, false); + arg = cmp.getFellowOrAttribute(fdname, false); } return arg; } @@ -1128,6 +1129,21 @@ public Map getArg() { public Object getAttribute(String name) { return exec().getAttribute(name); } + public boolean hasAttribute(String name) { + return exec().hasAttribute(name); + } + public Object getAttribute(String name, boolean local) { + return exec().getAttribute(name, local); + } + public boolean hasAttribute(String name, boolean local) { + return exec().hasAttribute(name, local); + } + public boolean addScopeListener(ScopeListener listener) { + return exec().addScopeListener(listener); + } + public boolean removeScopeListener(ScopeListener listener) { + return exec().removeScopeListener(listener); + } public Map getAttributes() { return exec().getAttributes(); @@ -1326,8 +1342,8 @@ public void pushArg(Map arg) { exec().pushArg(arg); } - public void removeAttribute(String name) { - exec().removeAttribute(name); + public Object removeAttribute(String name) { + return exec().removeAttribute(name); } public void sendRedirect(String uri) { @@ -1338,8 +1354,8 @@ public void sendRedirect(String uri, String target) { exec().sendRedirect(uri, target); } - public void setAttribute(String name, Object value) { - exec().setAttribute(name, value); + public Object setAttribute(String name, Object value) { + return exec().setAttribute(name, value); } public void setVoided(boolean voided) { diff --git a/zk/src/org/zkoss/zk/ui/Execution.java b/zk/src/org/zkoss/zk/ui/Execution.java index 9cb9a4838b2..e9094d7b850 100644 --- a/zk/src/org/zkoss/zk/ui/Execution.java +++ b/zk/src/org/zkoss/zk/ui/Execution.java @@ -858,11 +858,13 @@ public Component[] createComponentsDirectly(Reader reader, String extension, /** Sets the value of the specified request attribute. * * @param value the value. If null, the attribute is removed. + * @return the previous value if any (since ZK5) */ - public void setAttribute(String name, Object value); + public Object setAttribute(String name, Object value); /** Removes the specified request attribute. + * @return the previous value if any (since ZK5) */ - public void removeAttribute(String name); + public Object removeAttribute(String name); /** Returns a map of request attributes associated with this session. */ public Map getAttributes(); diff --git a/zk/src/org/zkoss/zk/ui/IdSpace.java b/zk/src/org/zkoss/zk/ui/IdSpace.java index 897f89acc02..7762a247df1 100644 --- a/zk/src/org/zkoss/zk/ui/IdSpace.java +++ b/zk/src/org/zkoss/zk/ui/IdSpace.java @@ -19,6 +19,7 @@ package org.zkoss.zk.ui; import java.util.Collection; +import org.zkoss.zk.ui.ext.Scope; /** * Implemented by a component ({@link Component}) and a page @@ -58,7 +59,7 @@ * * @author tomyeh */ -public interface IdSpace { +public interface IdSpace extends Scope { /** Returns a component of the specified ID in the same ID space. * Components in the same ID space are called fellows. * diff --git a/zk/src/org/zkoss/zk/ui/Page.java b/zk/src/org/zkoss/zk/ui/Page.java index 135f7c3ff0f..4b49bc676f6 100644 --- a/zk/src/org/zkoss/zk/ui/Page.java +++ b/zk/src/org/zkoss/zk/ui/Page.java @@ -28,7 +28,6 @@ import org.zkoss.xel.Function; import org.zkoss.zk.scripting.Interpreter; -import org.zkoss.zk.scripting.Namespace; import org.zkoss.zk.scripting.InterpreterNotFoundException; import org.zkoss.zk.ui.ext.Scope; import org.zkoss.zk.ui.event.EventListener; @@ -205,7 +204,8 @@ public interface Page extends IdSpace, Scope { public static final int REQUEST_SCOPE = Component.REQUEST_SCOPE; /** Returns all custom attributes of the specified scope. - * You could reference them thru componentScope, spaceScope, pageScope, + * You could reference them directly, or + * thru componentScope, spaceScope, pageScope, * requestScope and desktopScope in zscript and EL. * *

    If scope is {@link #PAGE_SCOPE}, it means custom attributes shared @@ -226,6 +226,12 @@ public interface Page extends IdSpace, Scope { * {@link #PAGE_SCOPE}, {@link #REQUEST_SCOPE} or {@link #DESKTOP_SCOPE}. */ public Object getAttribute(String name, int scope); + /** Returns if an attribute exists. + *

    Notice that null is a valid value, so you need this + * method to really know if an atribute is defined. + * @since 5.0.0 + */ + public boolean hasAttribute(String name, int scope); /** Sets the value of the specified custom attribute in the specified scope. * *

    If scope is {@link #PAGE_SCOPE}, it means custom attributes shared @@ -253,55 +259,52 @@ public interface Page extends IdSpace, Scope { /** Returns the value of the specified attribute associated with this page. */ public Object getAttribute(String name); + /** Returns if an attribute exists. + *

    Notice that null is a valid value, so you need this + * method to really know if an atribute is defined. + * @since 5.0.0 + */ + public boolean hasAttribute(String name); /** Sets the value of the specified custom attribute associated with this page. - * - *

    Note: The attribute is removed (by {@link #removeAttribute} - * if value is null, while {@link #setVariable} considers null as a legal value. - * - * @param value the value. If null, the attribute is removed. + * @param value the value. */ public Object setAttribute(String name, Object value); /** Removes the specified attribute custom associated with the page. */ public Object removeAttribute(String name); - /** Sets a variable to the namespace ({@link #getNamespace}). + /** Returns the custom attribute associated with this page, + * or the fellow of this page. * - *

    It is the same as getNamespace().setVariable(name, value, true). + * @param local whether not to look up the desktop/session for the + * existence of the attribute.
    + * @since 5.0.0 + */ + public Object getFellowOrAttribute(String name, boolean local); + /** Returns if a custom attribute is associated with this page, + * or a fellow of this page. * - * @see Component#setVariable - * @see Component#getNamespace + * @param local whether not to look up the desktop/session for the + * existence of the attribute.
    + * @since 5.0.0 */ - public void setVariable(String name, Object val); - /** Returns whether the specified variable is defined. + public boolean hasFellowOrAttribute(String name, boolean local); + + /** @deprecated As of release 5.0.0, replaced with {@link #setAttribute}. * - *

    Note: null is a valid value for variable, so this method is used - * to know whether a variable is defined. - * On the other hand, {@link #setAttribute} actually remove - * an attribute (by {@link #removeAttribute} if value is null. + *

    Sets a variable to the namespace ({@link #getNamespace}). + */ + public void setVariable(String name, Object val); + /** @deprecated As of release 5.0.0, replaced with {@link #hasFellowOrAttribute}. + *

    Returns whether the specified variable is defined. */ public boolean containsVariable(String name); - /** Returns the value of a variable defined in the namespace ({@link #getNamespace}). - * - *

    It is the same as getNamespace().getVariable(name, true). - * - *

    Differences between {@link #getVariable} and {@link #getZScriptVariable}

    - * - *

    {@link #getVariable} returns only variables defined by - * {@link #setVariable} (i.e., a shortcut to {@link Namespace#setVariable}). - * On the other hand, {@link #getZScriptVariable} returns these variables - * and those defined when executing zscripts. - * - * @see Component#getVariable - * @see Component#getNamespace + /** @deprecated As of release 5.0.0, replaced with {@link #getFellowOrAttribute}. + *

    Returns the value of a variable defined in the namespace ({@link #getNamespace}). */ public Object getVariable(String name); - /** Unsets a variable from the namespace ({@link #getNamespace}). - * - *

    It is the same as getNamespace().unsetVariable(name, true). - * - * @see Component#unsetVariable - * @see Component#getNamespace + /** @deprecated As of release 5.0.0, replaced with {@link #removeAttribute}. + *

    Unsets a variable from the namespace ({@link #getNamespace}). */ public void unsetVariable(String name); @@ -333,7 +336,7 @@ public interface Page extends IdSpace, Scope { */ public Class resolveClass(String clsnm) throws ClassNotFoundException; - /** Returns the variable of the specified name by searching + /** Returns the function of the specified name by searching * the loaded interpreters. * * @return the method, or null if not found @@ -341,15 +344,11 @@ public interface Page extends IdSpace, Scope { * @since 3.0.0 */ public Function getZScriptFunction(String name, Class[] argTypes); - /** Returns the variable of the specified name by searching - * the logical scope of the specified namespace for all - * the loaded interpreters. + /** @deprecated As of release 5.0.0, replaced with {@link #getZScriptFunction(Component,String,Class[])} * - *

    It is similar to {@link #getZScriptVariable(String)}, except - * it uses the specified namespace as a reference to identify the - * correct scope for searching the variable. - * If the interpreter does NOT support hierachical scopes, - * this method is the same as {@link #getZScriptVariable(String)}. + *

    Returns the function of the specified name by searching + * the logical scope of the specified namespace in all + * the loaded interpreters. * * @param ns the namespace used as a reference to identify the * correct scope for searching the variable. @@ -359,12 +358,15 @@ public interface Page extends IdSpace, Scope { * @see #getLoadedInterpreters * @since 2.4.1 */ - public Function getZScriptFunction(Namespace ns, String name, Class[] argTypes); - /** Returns the variable of the specified name by searching - * the logical scope of the namespace of the specified component - * for all the loaded interpreters. + public Function getZScriptFunction(org.zkoss.zk.scripting.Namespace ns, String name, Class[] argTypes); + /** Returns the function of the specified name by searching + * the logical scope of the specified component + * in all the loaded interpreters. * - *

    It is a shortcut: getZScriptFunction(comp.getNamespace(), name, argTypes); + * @param comp the component to start the search. If null, this + * method searches only the page's attributes. + * In other words, if comp is null, this method is the same as + * {@link #getZScriptFunction(String, Class[])}. * @since 3.0.0 */ public Function getZScriptFunction(Component comp, String name, Class[] argTypes); @@ -372,38 +374,30 @@ public interface Page extends IdSpace, Scope { /** Returns the value of the variable of the specified name by searching * the loaded interpreters, if any. * - *

    Differences between {@link #getVariable} and {@link #getZScriptVariable}

    - * - *

    {@link #getVariable} returns variables defined by - * {@link #setVariable} (i.e., a shortcut to {@link Namespace#setVariable}). - * On the other hand, {@link #getZScriptVariable} returns the variables - * that are defined when executing zscripts. - * * @return the value of the variable, or null if not found * @see #getLoadedInterpreters */ public Object getZScriptVariable(String name); - /** Returns the value of the variable of the specified name by searching - * the logical scope of the specified namespace for all - * the loaded interpreters, if any. + /** @deprecated As of release 5.0.0, replaced with + * {@link #getZScriptVariable(Component, String)}. * - *

    It is similar to {@link #getZScriptVariable(String)}, except - * it uses the specified namespace as a reference to identify the - * correct scope for searching the variable. - * If the interpreter does NOT support hierachical scopes, - * this method is the same as {@link #getZScriptVariable(String)}. + *

    Returns the value of the variable of the specified name by searching + * the logical scope of the specified namespace in all + * the loaded interpreters, if any. * * @param ns the namespace used as a reference to identify the * correct scope for searching the variable. * It is ignored if the interpreter doesn't support hierachical scopes. * Note: this method doesn't look for any variable stored in ns. */ - public Object getZScriptVariable(Namespace ns, String name); + public Object getZScriptVariable(org.zkoss.zk.scripting.Namespace ns, String name); /** Returns the value of the variable of the specified name by searching - * the logical scope of the namespace of the specified component - * for all the loaded interpreters, if any. + * the logical scope of the specified component + * in all the loaded interpreters, if any. * - *

    It is a shortcut: getZScriptVariable(comp.getNamespace(), name); + * @param comp the component as the context to look for the variable + * defined in an interpreter. If null, the context is assumed to + * be this page. * @since 3.0.0 */ public Object getZScriptVariable(Component comp, String name); @@ -471,13 +465,20 @@ public interface Page extends IdSpace, Scope { */ public void invalidate(); - /** Returns the namespace used to store variables belonging to + /** @deprecated As of release 5.0.0, the concept of namespace is + * deprecated, and please use the attributes of an ID space (such as page) + * instead. + * + *

    Returns the namespace used to store variables belonging to * the ID space of this page. * * @see #interpret */ - public Namespace getNamespace(); - /** Interpret a script of the specified scripting language against + public org.zkoss.zk.scripting.Namespace getNamespace(); + /** @deprecated As of release 5.0.0, replaced with + * {@link interpret(String,String,Component)}. + * + *

    Interpret a script of the specified scripting language against * the specified namespace. * * @param zslang the scripting language. If null, {@link #getZScriptLanguage} @@ -488,7 +489,20 @@ public interface Page extends IdSpace, Scope { * if the thread is processing an event. * Otherwise, the current namespace is this page's namespace */ - public void interpret(String zslang, String script, Namespace ns); + public void interpret(String zslang, String script, org.zkoss.zk.scripting.Namespace ns); + /** Interprets a script in the sepcified scripting language in + * the context of the specified scope. + * + * @param zslang the scripting language. If null, {@link #getZScriptLanguage} + * is assumed. + * @param scope the scope used as the context. + * Since a component is a scope, you can pass a component as the context. + * By context we mean the attribute of the scope, its space owner, + * spacer owner's space owner, page and desktop will be searched. + *If null, this page is assumed. + * @since 5.0.0 + */ + public void interpret(String zslang, String script, Scope scope); /** Returns the interpreter of the specified scripting language. * *

    The interpreter will be loaded and initialized, diff --git a/zk/src/org/zkoss/zk/ui/Session.java b/zk/src/org/zkoss/zk/ui/Session.java index ad3efebaa7c..ae06b9cad98 100644 --- a/zk/src/org/zkoss/zk/ui/Session.java +++ b/zk/src/org/zkoss/zk/ui/Session.java @@ -58,11 +58,13 @@ public interface Session extends Scope { */ public Object getAttribute(String name); /** Sets the value of the specified custom attribute. + * @return the previous value if any (since ZK 5) */ - public void setAttribute(String name, Object value); + public Object setAttribute(String name, Object value); /** Removes the specified custom attribute. + * @return the previous value if any (since ZK 5) */ - public void removeAttribute(String name); + public Object removeAttribute(String name); /** Returns a map of custom attributes associated with this session. */ diff --git a/zk/src/org/zkoss/zk/ui/WebApp.java b/zk/src/org/zkoss/zk/ui/WebApp.java index 08f78631597..8369e95deac 100644 --- a/zk/src/org/zkoss/zk/ui/WebApp.java +++ b/zk/src/org/zkoss/zk/ui/WebApp.java @@ -82,11 +82,13 @@ public interface WebApp extends Scope, Locator { */ public Object getAttribute(String name); /** Sets the value of the specified custom attribute. + * @return the previous value if any (since ZK 5) */ - public void setAttribute(String name, Object value); + public Object setAttribute(String name, Object value); /** Removes the specified custom attribute. + * @return the previous value if any (since ZK 5) */ - public void removeAttribute(String name); + public Object removeAttribute(String name); /** Returns a map of custom attributes associated with this object. */ diff --git a/zk/src/org/zkoss/zk/ui/ext/Scope.java b/zk/src/org/zkoss/zk/ui/ext/Scope.java index 7821546f06d..d65554b06b7 100644 --- a/zk/src/org/zkoss/zk/ui/ext/Scope.java +++ b/zk/src/org/zkoss/zk/ui/ext/Scope.java @@ -22,10 +22,68 @@ * @since 3.6.0 */ public interface Scope { - /** Returns all custom attributes associated with this object. + /** Returns all custom attributes associated with this object (scope). */ public Map getAttributes(); - /** Returns the custom attribute associated with this object. + /** Returns the custom attribute associated with this object (scope). */ public Object getAttribute(String name); + /** Returns if a custom attribute is associated with this object (scope). + *

    Notice that null is a valid value, so you can + * tell if an attribute is assoicated by examining the return value + * of {@link #getAttribute}. + * @since 5.0.0 + */ + public boolean hasAttribute(String name); + /** Sets (aka., associates) the value for a custom attribute with this object (scope). + * @returns the previous value associated with the attribute, if any + * @since 5.0.0 + */ + public Object setAttribute(String name, Object value); + /** Removes the attribute from the current scope if any. + * @return the previous value associated with the attribute, if any, + * @since 5.0.0 + */ + public Object removeAttribute(String name); + + /** Returns the custom attribute associated with this object. + * + * @param local whether not to search its ancestor scope. + * If false and the current scope doen't define the variable, + * it searches up its ancestor (via {@link #getParent}) to see + * any of them has defined the specified variable. + * Notice: for a component, the ancestor scope is the space owner. + * @since 5.0.0 + */ + public Object getAttribute(String name, boolean local); + /** Returns if a custom attribute is associated with this object. + *

    Notice that null is a valid value, so you can + * tell if an attribute is assoicated by examining the return value + * of {@link #getAttribute}. + * + * @param local whether not to search its ancestor scope. + * If false and the current scope doen't define the variable, + * it searches up its ancestor (via {@link #getParent}) to see + * any of them has defined the specified variable. + * Notice: for a component, the ancestor scope is the space owner. + * @since 5.0.0 + */ + public boolean hasAttribute(String name, boolean local); + + /** Adds a listener to listen whether this scope is changed. + * The listener is called when a custom attribute is added, removed, or + * the parent is changed. + * + * @return wether the listener is added successfully. + * Note: if the resolver was added before, it won't be added again + * and this method returns false. + * @since 5.0.0 + */ + public boolean addScopeListener(ScopeListener listener); + /** Removes a change listener from this scope. + * + * @return false if listener is not added before. + * @since 5.0.0 + */ + public boolean removeScopeListener(ScopeListener listener); } diff --git a/zk/src/org/zkoss/zk/ui/ext/ScopeListener.java b/zk/src/org/zkoss/zk/ui/ext/ScopeListener.java new file mode 100644 index 00000000000..90df5ed51ce --- /dev/null +++ b/zk/src/org/zkoss/zk/ui/ext/ScopeListener.java @@ -0,0 +1,40 @@ +/* ScopeListener.java + + Purpose: + + Description: + + History: + Fri Sep 11 09:32:53 2009, Created by tomyeh + +Copyright (C) 2009 Potix Corporation. All Rights Reserved. + +This program is distributed under GPL Version 3.0 in the hope that +it will be useful, but WITHOUT ANY WARRANTY. +*/ +package org.zkoss.zk.ui.ext; + +/** + *

    A listener used to listen whether a scope ({@link Scope}) is changed. + * + *

    To add a listener to the scope, invoke + * {@link Scope#addChangeListener}. + * + * @author tomyeh + * @since 5.0.0 + */ +public interface ScopeListener { + /** Called when a variable is set to {@link Namespace}. + * + * @param value the new value. + */ + public void onAdd(String name, Object value); + /** Called when a variable is removed from {@link Namespace}. + */ + public void onRemove(String name); + /** Called when the parent is changed. + * + * @param newparent the new parent. + */ + public void onParentChanged(Scope newparent); +} diff --git a/zk/src/org/zkoss/zk/ui/ext/Scopes.java b/zk/src/org/zkoss/zk/ui/ext/Scopes.java new file mode 100644 index 00000000000..7ee7e149fcd --- /dev/null +++ b/zk/src/org/zkoss/zk/ui/ext/Scopes.java @@ -0,0 +1,174 @@ +/* Scopes.java + + Purpose: + + Description: + + History: + Thu Sep 10 14:19:27 2009, Created by tomyeh + +Copyright (C) 2009 Potix Corporation. All Rights Reserved. + +This program is distributed under GPL Version 3.0 in the hope that +it will be useful, but WITHOUT ANY WARRANTY. +*/ +package org.zkoss.zk.ui.ext; + +import java.util.Map; +import java.util.HashMap; +import java.util.List; +import java.util.LinkedList; +import java.util.Iterator; + +import org.zkoss.util.logging.Log; +import org.zkoss.zk.ui.Desktop; +import org.zkoss.zk.ui.Page; +import org.zkoss.zk.ui.Component; +import org.zkoss.zk.ui.Execution; +import org.zkoss.zk.ui.Executions; + +/** + * Utilities to manage the current scope ({@link Scope}). + * + * @author tomyeh + * @since 5.0.0 + */ +public class Scopes { + private static final Log log = Log.lookup(Scopes.class); + + /** A stack of implict objects ({@link Implicts}. */ + private static final ThreadLocal _implicits = new ThreadLocal(); + /** A stack of current scope. */ + private static final ThreadLocal _scopes = new ThreadLocal(); + + /** Prepares implicit variable before calling {@link Page#interpret}. + * + *

    Typical use: + *

    
    +final Scope scope = Scopes.beforeInterpret(comp);
    +try {
    +  Scopes.setImplicit("some", value);
    +  page.interpret(zslang, zscript, scope); //it will push scope as the current scope
    +} finally {
    +  Scopes.afterInterpret();
    +}
    +
    + * + *

    Another example: + *

    
    +Scopes.beforeInterpret(comp);
    +try {
    +  constr.validate(comp); //if constr might be an instance of a class implemented in zscript
    +} finally {
    +  Scopess.afterInterpret();
    +}
    +
    + * + *

    If you need to set some implicit variables, you can invoke + * {@link #setImplicit} between {@link #beforeInterpret} + * and {@link #afterInterpret}. + * + * @param comp the component, never null. + * @return the scope that owns the specified component + */ + public static final Scope beforeInterpret(Scope scope) { + if (scope == null) + scope = new SimpleScope(); + + final Implicit impl = beforeInterpret0(scope); + impl.setImplicit("self", scope); + + if (scope instanceof Component) + impl.setImplicit("componentScope", + ((Component)scope).getAttributes(Component.COMPONENT_SCOPE)); + + return scope; + } + private static Implicit beforeInterpret0(Scope scope) { + List impls = (List)_implicits.get(); + if (impls == null) + _implicits.set(impls = new LinkedList()); + final Implicit impl = new Implicit(); + impls.add(0, impl); + + final Execution exec = Executions.getCurrent(); + impl.setImplicit("arg", exec != null ? exec.getArg(): null); + + push(scope); + + return impl; + } + /** Used with {@link #beforeInterpret} to clean up implicit + * variables. + */ + public static final void afterInterpret() { + ((List)_implicits.get()).remove(0); + pop(); + } + + /** Sets an implicit object. + * It can be called only between {@link #beforeInterpret} and + * {@link #afterInterpret}. + */ + public static void setImplicit(String name, Object value) { + ((Implicit)((List)_implicits.get()).get(0)) + .setImplicit(name, value); + } + /** Returns the implict object. + * + * @param name the variable to retrieve + * @param defValue the default vale that is used if the implicit + * object is not defined. + */ + public static Object getImplicit(String name, Object defValue) { + final List implicits = (List)_implicits.get(); + if (implicits != null && !implicits.isEmpty()) //in case: beforeInterpret not called + return ((Implicit)implicits.get(0)).getImplicit(name, defValue); + return defValue; + } + + /** Returns the current scope. + * The current scope is the event target's scope if this thread + * is processing an event ({@link org.zkoss.zk.ui.event.Event#getTarget}. + * Otherwise, the scope of the page specified is assumed. + * + *

    This method is used only to implement {@link org.zkoss.zk.scripting.Interpreter}. + * You rarely need to access it other than implementing an interpreter. + */ + public static final Scope getCurrent(Page page) { + final List nss = (List)_scopes.get(); + final Scope scope = + nss != null && !nss.isEmpty() ? (Scope)nss.get(0): null; + return scope != null ? scope: page; + } + /** Pushes the specified scope as the current scope. + * + * @param scope the scope. If null, it means page's scope. + */ + private static final void push(Scope scope) { + List nss = (List)_scopes.get(); + if (nss == null) + _scopes.set(nss = new LinkedList()); + nss.add(0, scope); + } + /** Pops the current namespce (pushed by {@link #push}). + */ + private static final void pop() { + ((List)_scopes.get()).remove(0); + } + + private static class Implicit { + /** Implicit variables. */ + private final Map _vars = new HashMap(); + + private Implicit() { + } + private void setImplicit(String name, Object value) { + _vars.put(name, value); + } + private Object getImplicit(String name, Object defValue) { + final Object o = _vars.get(name); + return o != null || _vars.containsKey(name) ? o: defValue; + } + } +} diff --git a/zk/src/org/zkoss/zk/ui/ext/SimpleScope.java b/zk/src/org/zkoss/zk/ui/ext/SimpleScope.java new file mode 100644 index 00000000000..c1e0f0df66d --- /dev/null +++ b/zk/src/org/zkoss/zk/ui/ext/SimpleScope.java @@ -0,0 +1,188 @@ +/* SimpleScope.java + + Purpose: + + Description: + + History: + Sat Sep 12 13:22:02 2009, Created by tomyeh + +Copyright (C) 2009 Potix Corporation. All Rights Reserved. + +This program is distributed under GPL Version 3.0 in the hope that +it will be useful, but WITHOUT ANY WARRANTY. +*/ +package org.zkoss.zk.ui.ext; + +import java.util.Iterator; +import java.util.AbstractSet; +import java.util.Set; +import java.util.List; +import java.util.LinkedList; +import java.util.Map; +import java.util.HashMap; + +/** + * A simple implementation of {@link Scope}. + * It supports {@link ScopeListener}, but it doesn't support + * the concept of parent scope. + * Thus, the deriving class can override + * {@link #getAttribute(String,Object,boolean)}, + * {@link #hasAttribute(string,Object)}, + * and invoke {@link #notifyParentChanged} if the parent is changed. + * + * @author tomyeh + * @since 5.0.0 + */ +public class SimpleScope implements Scope { + private Map _attrs; + private List _listeners; + + //Scope// + public Map getAttributes() { + if (_attrs == null) _attrs = new Attrs(); + return _attrs; + } + public Object getAttribute(String name) { + return _attrs != null ? _attrs.get(name): null; + } + public boolean hasAttribute(String name) { + return _attrs != null && _attrs.containsKey(name); + } + public Object setAttribute(String name, Object value) { + if (_attrs == null) _attrs = new Attrs(); + return _attrs.put(name, value); + } + public Object removeAttribute(String name) { + return _attrs != null ? _attrs.remove(name): null; + } + + /** The same as getAttribute(name). */ + public Object getAttribute(String name, boolean local) { + return getAttribute(name); + } + /** The same as hasAttribute(name). */ + public boolean hasAttribute(String name, boolean local) { + return hasAttribute(name); + } + + public boolean addScopeListener(ScopeListener listener) { + if (listener == null) + throw new IllegalArgumentException("null"); + + if (_listeners == null) + _listeners = new LinkedList(); + else if (_listeners.contains(listener)) + return false; + + _listeners.add(listener); + return true; + } + public boolean removeScopeListener(ScopeListener listener) { + return _listeners != null && _listeners.remove(listener); + } + + /** Invokes {@link ScopeListener#onAdd} for registered + * listeners. + */ + private void notifyAdd(String name, Object value) { + if (_listeners != null) + for (Iterator it = _listeners.iterator(); it.hasNext();) + ((ScopeListener)it.next()).onAdd(name, value); + } + /** Invokes {@link ScopeListener#onRemove} for registered + * listeners. + */ + private void notifyRemove(String name) { + if (_listeners != null) + for (Iterator it = _listeners.iterator(); it.hasNext();) + ((ScopeListener)it.next()).onRemove(name); + } + /** Invokes {@link ScopeListener#onParentChanged} for registered + * listeners. + * + * @see #addChangeListener + */ + public void notifyParentChanged(Scope newparent) { + if (_listeners != null) + for (Iterator it = _listeners.iterator(); it.hasNext();) + ((ScopeListener)it.next()).onParentChanged(newparent); + } + + //clone// + /** Clones this scope. */ + public Object clone() { + final SimpleScope clone = new SimpleScope(); + clone._attrs = _attrs != null ? new HashMap(_attrs): null; + //TODO: handle _listeners + return clone; + } + + //Helper Class// + private class Attrs extends HashMap { + public Object remove(Object key) { + if (_listeners != null && super.containsKey(key)) + notifyRemove((String)key); + return super.remove(key); + } + public Object put(Object key, Object val) { + notifyAdd((String)key, val); + return super.put(key, val); + } + public Set entrySet() { + return new AttrSet(super.entrySet(), true); + } + public Set keySet() { + return new AttrSet(super.keySet(), false); + } + private class AttrSet extends AbstractSet { + private final Set _set; + private final boolean _entry; + private AttrSet(Set set, boolean entry) { + _set = set; + _entry = entry; + } + public Iterator iterator() { + return new AttrIter(_set.iterator()); + } + public int size() { + return _set.size(); + } + public boolean add(Object o) { + if (_entry) { + final Map.Entry me = (Map.Entry)o; + notifyAdd((String)me.getKey(), me.getValue()); + } else + notifyAdd((String)o, null); + return _set.add(o); + } + public boolean remove(Object o) { + if (_set.remove(o)) { + notifyRemove((String)(_entry ? ((Map.Entry)o).getKey(): o)); + return true; + } + return false; + } + public boolean contains(Object o) { + return _set.contains(o); + } + private class AttrIter implements Iterator { + private final Iterator _it; + private Object _last; + private AttrIter(Iterator it) { + _it = it; + } + public boolean hasNext() { + return _it.hasNext(); + } + public Object next() { + return _last = _it.next(); + } + public void remove() { + _it.remove(); + notifyRemove((String)(_entry ? ((Map.Entry)_last).getKey(): _last)); + } + } + } + } +} diff --git a/zk/src/org/zkoss/zk/ui/http/ExecutionImpl.java b/zk/src/org/zkoss/zk/ui/http/ExecutionImpl.java index fd9c9731e21..c2e74af6960 100644 --- a/zk/src/org/zkoss/zk/ui/http/ExecutionImpl.java +++ b/zk/src/org/zkoss/zk/ui/http/ExecutionImpl.java @@ -59,6 +59,7 @@ import org.zkoss.zk.ui.Page; import org.zkoss.zk.ui.Desktop; import org.zkoss.zk.ui.WebApp; +import org.zkoss.zk.ui.ext.ScopeListener; import org.zkoss.zk.ui.impl.AbstractExecution; import org.zkoss.zk.ui.metainfo.PageDefinition; import org.zkoss.zk.ui.metainfo.PageDefinitions; @@ -448,16 +449,40 @@ public Object getNativeResponse() { public Object getAttribute(String name) { return _request.getAttribute(name); } - public void setAttribute(String name, Object value) { + public boolean hasAttribute(String name) { + return getAttribute(name) != null; //Servlet limitation + } + public Object setAttribute(String name, Object value) { + Object old = _request.getAttribute(name); _request.setAttribute(name, value); + return old; } - public void removeAttribute(String name) { + public Object removeAttribute(String name) { + Object old = _request.getAttribute(name); _request.removeAttribute(name); + return old; + } + public Object getAttribute(String name, boolean local) { + Object val = getAttribute(name); + Desktop desktop; + return val != null || local || (desktop=getDesktop()) == null ? + val: desktop.getAttribute(name, false); + } + public boolean hasAttribute(String name, boolean local) { + Desktop desktop; + return hasAttribute(name) + || (!local && (desktop=getDesktop()) != null && desktop.hasAttribute(name, false)); } public Map getAttributes() { return _attrs; } + public boolean addScopeListener(ScopeListener listener) { + throw new UnsupportedOperationException(); //TODO + } + public boolean removeScopeListener(ScopeListener listener) { + throw new UnsupportedOperationException(); //TODO + } public String getHeader(String name) { return _request.getHeader(name); diff --git a/zk/src/org/zkoss/zk/ui/http/SimpleSession.java b/zk/src/org/zkoss/zk/ui/http/SimpleSession.java index f58b78d12b5..bb55f3d995c 100644 --- a/zk/src/org/zkoss/zk/ui/http/SimpleSession.java +++ b/zk/src/org/zkoss/zk/ui/http/SimpleSession.java @@ -39,6 +39,7 @@ import org.zkoss.zk.ui.WebApp; import org.zkoss.zk.ui.UiException; import org.zkoss.zk.ui.Session; +import org.zkoss.zk.ui.ext.ScopeListener; import org.zkoss.zk.ui.sys.SessionsCtrl; import org.zkoss.zk.ui.sys.SessionCtrl; import org.zkoss.zk.ui.sys.WebAppCtrl; @@ -220,7 +221,11 @@ public Object getAttribute(String name) { .getAttribute(name, PortletSession.APPLICATION_SCOPE): null; } - public void setAttribute(String name, Object value) { + public boolean hasAttribute(String name) { + return getAttribute(name) != null; //Servlet limitation + } + public Object setAttribute(String name, Object value) { + final Object old = getAttribute(name); if (!(this instanceof Serializable || this instanceof Externalizable)) { final boolean bStore = value instanceof Serializable || value instanceof Externalizable; synchronized (this) { @@ -239,14 +244,33 @@ public void setAttribute(String name, Object value) { } else { setAttr(name, value); } + return old; + } + public Object getAttribute(String name, boolean local) { + Object val = getAttribute(name); + return val != null || local || _wapp == null ? + val: _wapp.getAttribute(name, false); } + public boolean hasAttribute(String name, boolean local) { + return hasAttribute(name) + || (!local && _wapp != null && _wapp.hasAttribute(name, false)); + } + + public boolean addScopeListener(ScopeListener listener) { + throw new UnsupportedOperationException(); //TODO + } + public boolean removeScopeListener(ScopeListener listener) { + throw new UnsupportedOperationException(); //TODO + } + private void setAttr(String name, Object value) { if (_navsess instanceof HttpSession) ((HttpSession)_navsess).setAttribute(name, value); else if (_navsess != null) ((PortletSession)_navsess).setAttribute(name, value, PortletSession.APPLICATION_SCOPE); } - public void removeAttribute(String name) { + public Object removeAttribute(String name) { + Object old = getAttribute(name); if (!(this instanceof Serializable || this instanceof Externalizable)) { synchronized (this) { rmAttr(name); @@ -258,6 +282,7 @@ public void removeAttribute(String name) { } else { rmAttr(name); } + return old; } private void rmAttr(String name) { if (_navsess instanceof HttpSession) diff --git a/zk/src/org/zkoss/zk/ui/http/SimpleWebApp.java b/zk/src/org/zkoss/zk/ui/http/SimpleWebApp.java index 3891ca5bf70..e27602e2bfc 100644 --- a/zk/src/org/zkoss/zk/ui/http/SimpleWebApp.java +++ b/zk/src/org/zkoss/zk/ui/http/SimpleWebApp.java @@ -36,6 +36,7 @@ import org.zkoss.zk.ui.WebApp; import org.zkoss.zk.ui.UiException; import org.zkoss.zk.ui.util.Configuration; +import org.zkoss.zk.ui.ext.ScopeListener; import org.zkoss.zk.ui.impl.AbstractWebApp; /** @@ -75,15 +76,35 @@ protected void removeValue(String key) { public Object getAttribute(String name) { return _ctx.getAttribute(name); } - public void setAttribute(String name, Object value) { + public boolean hasAttribute(String name) { + return getAttribute(name) != null; //Servlet limitation + } + public Object setAttribute(String name, Object value) { + Object old = _ctx.getAttribute(name); _ctx.setAttribute(name, value); + return old; } - public void removeAttribute(String name) { + public Object removeAttribute(String name) { + Object old = _ctx.getAttribute(name); _ctx.removeAttribute(name); + return old; } public Map getAttributes() { return _attrs; } + public Object getAttribute(String name, boolean local) { + return getAttribute(name); + } + public boolean hasAttribute(String name, boolean local) { + return hasAttribute(name); + } + + public boolean addScopeListener(ScopeListener listener) { + throw new UnsupportedOperationException(); //TODO + } + public boolean removeScopeListener(ScopeListener listener) { + throw new UnsupportedOperationException(); //TODO + } public String getUpdateURI() { return getUpdateURI(true); diff --git a/zk/src/org/zkoss/zk/ui/impl/DesktopImpl.java b/zk/src/org/zkoss/zk/ui/impl/DesktopImpl.java index dc2afc0163b..45609c0a0f8 100644 --- a/zk/src/org/zkoss/zk/ui/impl/DesktopImpl.java +++ b/zk/src/org/zkoss/zk/ui/impl/DesktopImpl.java @@ -58,6 +58,8 @@ import org.zkoss.zk.ui.util.DesktopActivationListener; import org.zkoss.zk.ui.util.EventInterceptor; import org.zkoss.zk.ui.event.*; +import org.zkoss.zk.ui.ext.SimpleScope; +import org.zkoss.zk.ui.ext.ScopeListener; import org.zkoss.zk.ui.ext.render.DynamicMedia; import org.zkoss.zk.ui.sys.PageCtrl; import org.zkoss.zk.ui.sys.SessionCtrl; @@ -120,7 +122,7 @@ public class DesktopImpl implements Desktop, DesktopCtrl, java.io.Serializable { /** Map (String uuid, Component comp). */ private transient Map _comps; /** A map of attributes. */ - private transient Map _attrs; + private transient SimpleScope _attrs; //don't create it dynamically because PageImp._ip bind it at constructor private transient Execution _exec; /** Next available key. */ @@ -253,7 +255,7 @@ private void init() { _uvLock = new Object(); _rque = newRequestQueue(); _comps = new HashMap(64); - _attrs = new HashMap(); + _attrs = new SimpleScope(); } /** Updates _uuidPrefix based on _id. */ private void updateUuidPrefix() { @@ -437,16 +439,43 @@ public void removeComponent(Component comp) { } public Map getAttributes() { - return _attrs; + return _attrs.getAttributes(); } public Object getAttribute(String name) { - return _attrs.get(name); + return _attrs.getAttribute(name); + } + public boolean hasAttribute(String name) { + return _attrs.hasAttribute(name); } public Object setAttribute(String name, Object value) { - return value != null ? _attrs.put(name, value): removeAttribute(name); + return _attrs.setAttribute(name, value); } public Object removeAttribute(String name) { - return _attrs.remove(name); + return _attrs.removeAttribute(name); + } + public Object getAttribute(String name, boolean local) { + Object val = getAttribute(name); + if (val != null || local || hasAttribute(name)) + return val; + if (_sess != null) return _sess.getAttribute(name, false); + if (_wapp != null) return _wapp.getAttribute(name, false); + return null; + } + public boolean hasAttribute(String name, boolean local) { + if (hasAttribute(name)) + return true; + if (!local) { + if (_sess != null) return _sess.hasAttribute(name, false); + if (_wapp != null) return _wapp.hasAttribute(name, false); + } + return false; + } + + public boolean addScopeListener(ScopeListener listener) { + return _attrs.addScopeListener(listener); + } + public boolean removeScopeListener(ScopeListener listener) { + return _attrs.removeScopeListener(listener); } public WebApp getWebApp() { @@ -607,7 +636,7 @@ public void destroy() { //theorectically, the following is not necessary, but, to be safe... _pages.clear(); - _attrs.clear(); + _attrs.getAttributes().clear(); _comps = new HashMap(2); //not clear() since # of comps might huge _meds = null; _rque = null; @@ -670,7 +699,7 @@ private void sessWillPassivate() { if (_dev != null) _dev.sessionWillPassivate(this); - willPassivate(_attrs.values()); + willPassivate(_attrs.getAttributes().values()); willPassivate(_dtCleans); willPassivate(_execInits); willPassivate(_execCleans); @@ -682,7 +711,7 @@ private void sessDidActivate() { for (Iterator it = _pages.values().iterator(); it.hasNext();) ((PageCtrl)it.next()).sessionDidActivate(this); - didActivate(_attrs.values()); + didActivate(_attrs.getAttributes().values()); didActivate(_dtCleans); didActivate(_execInits); didActivate(_execCleans); @@ -713,8 +742,9 @@ private synchronized void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { s.defaultWriteObject(); - willSerialize(_attrs.values()); - Serializables.smartWrite(s, _attrs); + final Map attrs = _attrs.getAttributes(); + willSerialize(attrs.values()); + Serializables.smartWrite(s, attrs); willSerialize(_dtCleans); Serializables.smartWrite(s, _dtCleans); willSerialize(_execInits); @@ -749,8 +779,9 @@ private synchronized void readObject(java.io.ObjectInputStream s) e.hasNext();) addAllComponents((Component)e.next()); - Serializables.smartRead(s, _attrs); - didDeserialize(_attrs.values()); + final Map attrs = _attrs.getAttributes(); + Serializables.smartRead(s, attrs); + didDeserialize(attrs.values()); _dtCleans = (List)Serializables.smartRead(s, _dtCleans); didDeserialize(_dtCleans); _execInits = (List)Serializables.smartRead(s, _execInits); diff --git a/zk/src/org/zkoss/zk/ui/impl/EventProcessor.java b/zk/src/org/zkoss/zk/ui/impl/EventProcessor.java index c1fb51f45c9..cecc1e2502f 100644 --- a/zk/src/org/zkoss/zk/ui/impl/EventProcessor.java +++ b/zk/src/org/zkoss/zk/ui/impl/EventProcessor.java @@ -34,6 +34,8 @@ import org.zkoss.zk.ui.event.Event; import org.zkoss.zk.ui.event.EventListener; import org.zkoss.zk.ui.event.Express; +import org.zkoss.zk.ui.ext.Scope; +import org.zkoss.zk.ui.ext.Scopes; import org.zkoss.zk.ui.sys.SessionsCtrl; import org.zkoss.zk.ui.sys.ExecutionCtrl; import org.zkoss.zk.ui.sys.ExecutionsCtrl; @@ -42,8 +44,6 @@ import org.zkoss.zk.ui.sys.ComponentsCtrl; import org.zkoss.zk.ui.sys.EventProcessingThread; import org.zkoss.zk.ui.metainfo.ZScript; -import org.zkoss.zk.scripting.Namespace; -import org.zkoss.zk.scripting.Namespaces; /** * A utility class that simplify the implementation of @@ -131,22 +131,22 @@ public final Component getComponent() { public void process() throws Exception { //Bug 1506712: event listeners might be zscript, so we have to //keep built-in variables as long as possible - final Namespace ns = Namespaces.beforeInterpret(_comp); + final Scope scope = Scopes.beforeInterpret(_comp); //we have to push since process0 might invoke methods from zscript class try { - Namespaces.setImplicit("event", _event); + Scopes.setImplicit("event", _event); _event = ((DesktopCtrl)_desktop).beforeProcessEvent(_event); if (_event != null) { - Namespaces.setImplicit("event", _event); //_event might change - process0(ns); + Scopes.setImplicit("event", _event); //_event might change + process0(scope); ((DesktopCtrl)_desktop).afterProcessEvent(_event); } } finally { - Namespaces.afterInterpret(); + Scopes.afterInterpret(); } } - private void process0(Namespace ns) throws Exception { + private void process0(Scope scope) throws Exception { final Page page = getPage(); final String evtnm = _event.getName(); @@ -175,7 +175,7 @@ private void process0(Namespace ns) throws Exception { final ZScript zscript = ((ComponentCtrl)_comp).getEventHandler(evtnm); if (zscript != null) { page.interpret( - zscript.getLanguage(), zscript.getContent(page, _comp), ns); + zscript.getLanguage(), zscript.getContent(page, _comp), scope); if (!_event.isPropagatable()) return; //done } diff --git a/zk/src/org/zkoss/zk/ui/impl/PageImpl.java b/zk/src/org/zkoss/zk/ui/impl/PageImpl.java index 5a263f46312..61bc18ce75f 100644 --- a/zk/src/org/zkoss/zk/ui/impl/PageImpl.java +++ b/zk/src/org/zkoss/zk/ui/impl/PageImpl.java @@ -72,6 +72,9 @@ import org.zkoss.zk.ui.util.PageSerializationListener; import org.zkoss.zk.ui.util.PageActivationListener; import org.zkoss.zk.ui.ext.Includer; +import org.zkoss.zk.ui.ext.Scope; +import org.zkoss.zk.ui.ext.SimpleScope; +import org.zkoss.zk.ui.ext.ScopeListener; import org.zkoss.zk.ui.sys.ExecutionCtrl; import org.zkoss.zk.ui.sys.WebAppCtrl; import org.zkoss.zk.ui.sys.DesktopCtrl; @@ -85,14 +88,7 @@ import org.zkoss.zk.ui.sys.PageRenderer; import org.zkoss.zk.xel.ExValue; import org.zkoss.zk.au.out.AuSetTitle; -import org.zkoss.zk.scripting.Interpreter; -import org.zkoss.zk.scripting.Interpreters; -import org.zkoss.zk.scripting.HierachicalAware; -import org.zkoss.zk.scripting.SerializableAware; -import org.zkoss.zk.scripting.Namespace; -import org.zkoss.zk.scripting.NamespaceActivationListener; -import org.zkoss.zk.scripting.InterpreterNotFoundException; -import org.zkoss.zk.scripting.util.AbstractNamespace; +import org.zkoss.zk.scripting.*; /** * An implmentation of {@link Page} and {@link PageCtrl}. @@ -129,7 +125,7 @@ public class PageImpl extends AbstractPage implements java.io.Serializable { /** A list of deferred zscript [Component parent, {@link ZScript}]. */ private List _zsDeferred; /** A map of attributes. */ - private transient Map _attrs; + private transient SimpleScope _attrs; /** A map of event listener: Map(evtnm, List(EventListener)). */ private transient Map _listeners; /** The reason to store it is PageDefinition is not serializable. */ @@ -215,8 +211,8 @@ public PageImpl(Richlet richlet, String path) { */ protected void init() { _ips = new LinkedHashMap(4); - _ns = new NS(); - _attrs = new HashMap(); + _ns = new NS(); //backwad compatible + _attrs = new SimpleScope(); } /** Returns the UI engine. @@ -301,7 +297,7 @@ public Map getAttributes(int scope) { return _desktop != null ? _desktop.getWebApp().getAttributes(): Collections.EMPTY_MAP; case PAGE_SCOPE: - return _attrs; + return _attrs.getAttributes(); case REQUEST_SCOPE: final Execution exec = getExecution(); if (exec != null) return exec.getAttributes(); @@ -313,15 +309,14 @@ public Map getAttributes(int scope) { public Object getAttribute(String name, int scope) { return getAttributes(scope).get(name); } + public boolean hasAttribute(String name, int scope) { + return getAttributes(scope).containsKey(name); + } public Object setAttribute(String name, Object value, int scope) { - if (value != null) { - final Map attrs = getAttributes(scope); - if (attrs == Collections.EMPTY_MAP) - throw new IllegalStateException("This component doesn't belong to any ID space: "+this); - return attrs.put(name, value); - } else { - return removeAttribute(name, scope); - } + final Map attrs = getAttributes(scope); + if (attrs == Collections.EMPTY_MAP) + throw new IllegalStateException("This component doesn't belong to any ID space: "+this); + return attrs.put(name, value); } public Object removeAttribute(String name, int scope) { final Map attrs = getAttributes(scope); @@ -331,16 +326,62 @@ public Object removeAttribute(String name, int scope) { } public Map getAttributes() { - return _attrs; + return _attrs.getAttributes(); } public Object getAttribute(String name) { - return _attrs.get(name); + return _attrs.getAttribute(name); + } + public boolean hasAttribute(String name) { + return _attrs.hasAttribute(name); } public Object setAttribute(String name, Object value) { - return value != null ? _attrs.put(name, value): removeAttribute(name); + return _attrs.setAttribute(name, value); } public Object removeAttribute(String name) { - return _attrs.remove(name); + return _attrs.removeAttribute(name); + } + public Object getAttribute(String name, boolean local) { + Object val = getAttribute(name); + return val != null || local || hasAttribute(name) ? val: + _desktop != null ? _desktop.getAttribute(name, false): null; + } + public boolean hasAttribute(String name, boolean local) { + return hasAttribute(name) + || (!local && _desktop != null && _desktop.hasAttribute(name, false)); + } + + public Object getFellowOrAttribute(String name, boolean local) { + Object val = _ns.vars.get(name); //backward compatible (variable first) + if (val != null || _ns.vars.containsKey(name)) + return val; + + val = getAttribute(name); + if (val != null || hasAttribute(name)) + return val; + + val = getFellowIfAny(name); + if (val != null) + return val; + + val = resolveVariable(name); + if (val != null) + return val; + + return !local && _desktop != null ? + _desktop.getAttribute(name, false): null; + } + public boolean hasFellowOrAttribute(String name, boolean local) { + return hasAttribute(name) || hasFellow(name) + || _ns.vars.containsKey(name) //backward compatible + || resolveVariable(name) != null + || (!local && _desktop != null && _desktop.hasAttribute(name, false)); + } + + public boolean addScopeListener(ScopeListener listener) { + return _attrs.addScopeListener(listener); + } + public boolean removeScopeListener(ScopeListener listener) { + return _attrs.removeScopeListener(listener); } public void invalidate() { @@ -360,15 +401,19 @@ public Class resolveClass(String clsnm) throws ClassNotFoundException { throw ex; } } + /** @deprecated As of release 5.0.0, replaced with {@link #setAttribute}. */ public void setVariable(String name, Object val) { _ns.setVariable(name, val, true); } + /** @deprecated As of release 5.0.0, replaced with {@link #hasAttribute}. */ public boolean containsVariable(String name) { return _ns.containsVariable(name, true); } + /** @deprecated As of release 5.0.0, replaced with {@link #getAttribute}. */ public Object getVariable(String name) { return _ns.getVariable(name, true); } + /** @deprecated As of release 5.0.0, replaced with {@link #removeAttribute}. */ public void unsetVariable(String name) { _ns.unsetVariable(name, true); } @@ -396,24 +441,27 @@ public Function getZScriptFunction(String name, Class[] argTypes) { } return null; } - public Function getZScriptFunction(Namespace ns, String name, Class[] argTypes) { + public Function getZScriptFunction( + Component comp, String name, Class[] argTypes) { for (Iterator it = getLoadedInterpreters().iterator(); it.hasNext();) { final Object ip = it.next(); Function mtd = ip instanceof HierachicalAware ? - ((HierachicalAware)ip).getFunction(ns, name, argTypes): + ((HierachicalAware)ip).getFunction(comp, name, argTypes): ((Interpreter)ip).getFunction(name, argTypes); if (mtd != null) return mtd; } return null; } - public Function getZScriptFunction( - Component comp, String name, Class[] argTypes) { - return getZScriptFunction(comp != null ? comp.getNamespace(): null, - name, argTypes); + /** @deprecated As of release 5.0.0, replaced with + * {@link getZScriptFunction(Component,String,Class[])}. + */ + public Function getZScriptFunction(org.zkoss.zk.scripting.Namespace ns, String name, Class[] argTypes) { + return getZScriptFunction(ns != null ? ns.getOwner(): null, name, argTypes); } + public Object getZScriptVariable(String name) { for (Iterator it = getLoadedInterpreters().iterator(); it.hasNext();) { @@ -423,21 +471,23 @@ public Object getZScriptVariable(String name) { } return null; } - public Object getZScriptVariable(Namespace ns, String name) { + public Object getZScriptVariable(Component comp, String name) { for (Iterator it = getLoadedInterpreters().iterator(); it.hasNext();) { final Object ip = it.next(); final Object val = ip instanceof HierachicalAware ? - ((HierachicalAware)ip).getVariable(ns, name): + ((HierachicalAware)ip).getVariable(comp, name): ((Interpreter)ip).getVariable(name); if (val != null) return val; } return null; } - public Object getZScriptVariable(Component comp, String name) { - return getZScriptVariable(comp != null ? comp.getNamespace(): null, - name); + /** @deprecated As of release 5.0.0, replaced with + * {@link getZScriptVariable(Component,String,Class[])}. + */ + public Object getZScriptVariable(org.zkoss.zk.scripting.Namespace ns, String name) { + return getZScriptVariable(ns != null ? ns.getOwner(): null, name); } public Object getXelVariable(String name) { @@ -618,7 +668,7 @@ public void destroy() { _ips.clear(); //theorectically, the following is not necessary, but, to be safe... - _attrs.clear(); + _attrs.getAttributes().clear(); _ips = null; //not clear since it is better to NPE than memory leak _desktop = null; _owner = null; @@ -736,11 +786,28 @@ public void redraw(Writer out) _langdef.getPageRenderer().render(this, out); } - public final Namespace getNamespace() { + /** @deprecated As of release 5.0.0, the concept of namespace is + * deprecated and replaced with the attributes of a scope (such as + * a page and a component). + */ + public final org.zkoss.zk.scripting.Namespace getNamespace() { return _ns; } - public void interpret(String zslang, String script, Namespace ns) { - getInterpreter(zslang).interpret(script, ns); + public void interpret(String zslang, String script, Scope scope) { + getInterpreter(zslang).interpret(script, scope); + } + /** @deprecated As of release 5.0.0, replaced with + * {@link #interpret(String,String,Scope)}. + */ + public void interpret(String zslang, String script, org.zkoss.zk.scripting.Namespace ns) { + interpret(zslang, script, getScope(ns)); + } + /** @deprecated + */ + private static Scope getScope(org.zkoss.zk.scripting.Namespace ns) { + if (ns == null) return null; + Scope s = ns.getOwner(); + return s != null ? s: ns.getOwnerPage(); } public Interpreter getInterpreter(String zslang) { zslang = (zslang != null ? zslang: _zslang).toLowerCase(); @@ -752,7 +819,7 @@ public Interpreter getInterpreter(String zslang) { final String script = _langdef.getInitScript(zslang); if (script != null) - ip.interpret(script, _ns); + ip.interpret(script, this); //evaluate deferred zscripts, if any try { @@ -805,7 +872,7 @@ private void evalDeferredZScripts(Interpreter ip, String zslang) if ((parent == null || parent.getPage() == this) && isEffective(zscript, parent)) { ip.interpret(zscript.getContent(this, parent), - parent != null ? parent.getNamespace(): _ns); + parent != null ? (Scope)parent: this); } } } @@ -857,7 +924,7 @@ public void sessionWillPassivate(Desktop desktop) { for (Iterator it = getRoots().iterator(); it.hasNext();) ((ComponentCtrl)it.next()).sessionWillPassivate(this); - willPassivate(_attrs.values()); + willPassivate(_attrs.getAttributes().values()); if (_listeners != null) for (Iterator it = _listeners.values().iterator(); it.hasNext();) @@ -869,8 +936,8 @@ public void sessionWillPassivate(Desktop desktop) { it.hasNext();) { final Object val = _ns.getVariable((String)it.next(), true); willPassivate(val); - if (val instanceof NamespaceActivationListener) - ((NamespaceActivationListener)val).willPassivate(_ns); + if (val instanceof org.zkoss.zk.scripting.NamespaceActivationListener) //backward compatible + ((org.zkoss.zk.scripting.NamespaceActivationListener)val).willPassivate(_ns); } } public void sessionDidActivate(Desktop desktop) { @@ -886,7 +953,7 @@ public void sessionDidActivate(Desktop desktop) { initVariables(); //since some variables depend on desktop - didActivate(_attrs.values()); + didActivate(_attrs.getAttributes().values()); if (_listeners != null) for (Iterator it = _listeners.values().iterator(); it.hasNext();) @@ -898,8 +965,8 @@ public void sessionDidActivate(Desktop desktop) { it.hasNext();) { final Object val = _ns.getVariable((String)it.next(), true); didActivate(val); - if (val instanceof NamespaceActivationListener) - ((NamespaceActivationListener)val).didActivate(_ns); + if (val instanceof org.zkoss.zk.scripting.NamespaceActivationListener) //backward compatible + ((org.zkoss.zk.scripting.NamespaceActivationListener)val).didActivate(_ns); } } private void willPassivate(Collection c) { @@ -967,8 +1034,9 @@ private synchronized void writeObject(java.io.ObjectOutputStream s) s.writeObject(_langdef != null ? _langdef.getName(): null); s.writeObject(_owner != null ? _owner.getUuid(): null); - willSerialize(_attrs.values()); - Serializables.smartWrite(s, _attrs); + final Map attrs = _attrs.getAttributes(); + willSerialize(attrs.values()); + Serializables.smartWrite(s, attrs); if (_listeners != null) for (Iterator it = _listeners.entrySet().iterator(); it.hasNext();) { @@ -985,7 +1053,7 @@ private synchronized void writeObject(java.io.ObjectOutputStream s) Serializables.smartWrite(s, _resolvers); //handle namespace - for (Iterator it = _ns._vars.entrySet().iterator(); it.hasNext();) { + for (Iterator it = _ns.vars.entrySet().iterator(); it.hasNext();) { final Map.Entry me = (Map.Entry)it.next(); final String nm = (String)me.getKey(); final Object val = me.getValue(); @@ -1039,8 +1107,9 @@ private synchronized void readObject(java.io.ObjectInputStream s) _ownerUuid = (String)s.readObject(); //_owner is restored later when sessionDidActivate is called - Serializables.smartRead(s, _attrs); - didDeserialize(_attrs.values()); + final Map attrs = _attrs.getAttributes(); + Serializables.smartRead(s, attrs); + didDeserialize(attrs.values()); for (;;) { final String evtnm = (String)s.readObject(); @@ -1101,8 +1170,9 @@ public String toString() { return "[Page "+_id+']'; } - private class NS extends AbstractNamespace { - private final Map _vars = new HashMap(); + /** @deprecated */ + private class NS implements Namespace { + private final Map vars = new HashMap(4); //Namespace// public Component getOwner() { @@ -1112,34 +1182,43 @@ public Page getOwnerPage() { return PageImpl.this; } public Set getVariableNames() { - return _vars.keySet(); + return vars.keySet(); } public boolean containsVariable(String name, boolean local) { - return _vars.containsKey(name) || hasFellow(name) + return vars.containsKey(name) + || hasFellow(name) || resolveVariable(name) != null; } public Object getVariable(String name, boolean local) { - Object val = _vars.get(name); - if (val != null || _vars.containsKey(name)) + Object val = vars.get(name); + if (val != null || vars.containsKey(name)) return val; val = getFellowIfAny(name); return val != null ? val: resolveVariable(name); } public void setVariable(String name, Object value, boolean local) { - _vars.put(name, value); - notifyAdd(name, value); + vars.put(name, value); } public void unsetVariable(String name, boolean local) { - _vars.remove(name); - notifyRemove(name); + vars.remove(name); } + /** @deprecated */ public Namespace getParent() { return null; } + /** @deprecated */ public void setParent(Namespace parent) { throw new UnsupportedOperationException(); } + /** @deprecated */ + public boolean addChangeListener(NamespaceChangeListener listener) { + return false; + } + /** @deprecated */ + public boolean removeChangeListener(NamespaceChangeListener listener) { + return false; + } } } diff --git a/zk/src/org/zkoss/zk/ui/impl/PhantomExecution.java b/zk/src/org/zkoss/zk/ui/impl/PhantomExecution.java index f7be251d282..9cf6f281f66 100644 --- a/zk/src/org/zkoss/zk/ui/impl/PhantomExecution.java +++ b/zk/src/org/zkoss/zk/ui/impl/PhantomExecution.java @@ -32,6 +32,7 @@ import org.zkoss.zk.ui.Page; import org.zkoss.zk.ui.Component; import org.zkoss.zk.ui.metainfo.PageDefinition; +import org.zkoss.zk.ui.ext.ScopeListener; /** * A 'phantom' execution that is used when no request/response available. @@ -192,16 +193,32 @@ public Object getNativeResponse() { public Object getAttribute(String name) { return null; } - public void setAttribute(String name, Object value) { + public boolean hasAttribute(String name) { + return false; + } + public Object getAttribute(String name, boolean local) { + return null; + } + public boolean hasAttribute(String name, boolean local) { + return false; + } + public Object setAttribute(String name, Object value) { throw new UnsupportedOperationException(); } - public void removeAttribute(String name) { + public Object removeAttribute(String name) { throw new UnsupportedOperationException(); } public Map getAttributes() { return Collections.EMPTY_MAP; } + public boolean addScopeListener(ScopeListener listener) { + throw new UnsupportedOperationException(); + } + public boolean removeScopeListener(ScopeListener listener) { + throw new UnsupportedOperationException(); + } + public String getHeader(String name) { return null; } diff --git a/zk/src/org/zkoss/zk/ui/impl/UiEngineImpl.java b/zk/src/org/zkoss/zk/ui/impl/UiEngineImpl.java index 3f8b2823f16..d2c894be56f 100644 --- a/zk/src/org/zkoss/zk/ui/impl/UiEngineImpl.java +++ b/zk/src/org/zkoss/zk/ui/impl/UiEngineImpl.java @@ -53,10 +53,12 @@ import org.zkoss.zk.ui.metainfo.*; import org.zkoss.zk.ui.ext.AfterCompose; import org.zkoss.zk.ui.ext.Native; +import org.zkoss.zk.ui.ext.Scope; +import org.zkoss.zk.ui.ext.Scopes; import org.zkoss.zk.ui.ext.render.PrologAllowed; import org.zkoss.zk.ui.util.*; import org.zkoss.zk.xel.Evaluators; -import org.zkoss.zk.scripting.*; +import org.zkoss.zk.scripting.Interpreter; import org.zkoss.zk.au.*; import org.zkoss.zk.au.out.*; @@ -735,14 +737,13 @@ private static final void execNonComponent( ((PageCtrl)page).addDeferredZScript(comp, zscript); //isEffective is handled later } else if (isEffective(zscript, page, comp)) { - final Namespace ns = comp != null ? - Namespaces.beforeInterpret(comp): - Namespaces.beforeInterpret(page); + final Scope scope = + Scopes.beforeInterpret(comp != null ? (Scope)comp: page); try { page.interpret(zscript.getLanguage(), - zscript.getContent(page, comp), ns); + zscript.getContent(page, comp), scope); } finally { - Namespaces.afterInterpret(); + Scopes.afterInterpret(); } } } else if (meta instanceof AttributesInfo) { diff --git a/zk/src/org/zkoss/zk/ui/impl/ZScriptInitiator.java b/zk/src/org/zkoss/zk/ui/impl/ZScriptInitiator.java index 4c2219858b2..044c9aa24e9 100644 --- a/zk/src/org/zkoss/zk/ui/impl/ZScriptInitiator.java +++ b/zk/src/org/zkoss/zk/ui/impl/ZScriptInitiator.java @@ -23,8 +23,8 @@ import org.zkoss.zk.ui.Page; import org.zkoss.zk.ui.metainfo.ZScript; import org.zkoss.zk.ui.util.Initiator; -import org.zkoss.zk.scripting.Namespace; -import org.zkoss.zk.scripting.Namespaces; +import org.zkoss.zk.ui.ext.Scope; +import org.zkoss.zk.ui.ext.Scopes; /** * An initiator used to evaluate a zscript file. @@ -42,12 +42,12 @@ public ZScriptInitiator(ZScript script) { _zscript = script; } public void doInit(Page page, Map args) throws Exception { - final Namespace ns = Namespaces.beforeInterpret(page); + final Scope scope = Scopes.beforeInterpret(page); try { page.interpret( - _zscript.getLanguage(), _zscript.getContent(page, null), ns); + _zscript.getLanguage(), _zscript.getContent(page, null), scope); } finally { - Namespaces.afterInterpret(); + Scopes.afterInterpret(); } } public void doAfterCompose(Page page) throws Exception { diff --git a/zk/src/org/zkoss/zk/ui/metainfo/NodeInfo.java b/zk/src/org/zkoss/zk/ui/metainfo/NodeInfo.java index b51cc6606b4..740309362cb 100644 --- a/zk/src/org/zkoss/zk/ui/metainfo/NodeInfo.java +++ b/zk/src/org/zkoss/zk/ui/metainfo/NodeInfo.java @@ -32,7 +32,7 @@ * {@link PageDefinition} and {@link ComponentInfo}. * The root must be an instance of {@link PageDefinition} * and the other nodes must be instances of {@link ComponentInfo}, - * {@link ZScript}, {@link VariablesInfo}, or {@link AttributesInfo}. + * {@link ZScript}, or {@link AttributesInfo}. * *

    Note:it is not thread-safe. * diff --git a/zk/src/org/zkoss/zk/ui/util/ForEachImpl.java b/zk/src/org/zkoss/zk/ui/util/ForEachImpl.java index 84572d21652..ff9ba089f69 100644 --- a/zk/src/org/zkoss/zk/ui/util/ForEachImpl.java +++ b/zk/src/org/zkoss/zk/ui/util/ForEachImpl.java @@ -31,6 +31,7 @@ import org.zkoss.zk.ui.Component; import org.zkoss.zk.ui.UiException; import org.zkoss.zk.ui.Page; +import org.zkoss.zk.ui.ext.Scope; import org.zkoss.zk.xel.ExValue; import org.zkoss.zk.xel.impl.EvaluatorRef; @@ -242,8 +243,8 @@ public boolean next() { && _it.hasNext()) { ++_status.index; _status.each = _it.next(); - if (_comp != null) _comp.setVariable("each", _status.each, true); - else _page.setVariable("each", _status.each); + if (_comp != null) _comp.setAttribute("each", _status.each); + else _page.setAttribute("each", _status.each); return true; } @@ -253,36 +254,21 @@ public boolean next() { return false; } private void setupStatus() { - if (_comp != null) { - _oldEach = _comp.getVariable("each", true); - _status = new Status(_comp.getVariable("forEachStatus", true)); - _comp.setVariable("forEachStatus", _status, true); - } else { - _oldEach = _page.getVariable("each"); - _status = new Status(_page.getVariable("forEachStatus")); - _page.setVariable("forEachStatus", _status); - } + final Scope scope = _comp != null ? (Scope)_comp: _page; + _oldEach = scope.getAttribute("each", true); + _status = new Status(scope.getAttribute("forEachStatus", true)); + scope.setAttribute("forEachStatus", _status); } private void restoreStatus() { - if (_comp != null) { - if (_status.previous != null) - _comp.setVariable("forEachStatus", _status.previous, true); - else - _comp.unsetVariable("forEachStatus", true); - if (_oldEach != null) - _comp.setVariable("each", _oldEach, true); - else - _comp.unsetVariable("each", true); - } else { - if (_status.previous != null) - _page.setVariable("forEachStatus", _status.previous); - else - _page.unsetVariable("forEachStatus"); - if (_oldEach != null) - _page.setVariable("each", _oldEach); - else - _page.unsetVariable("each"); - } + final Scope scope = _comp != null ? (Scope)_comp: _page; + if (_status.previous != null) + scope.setAttribute("forEachStatus", _status.previous); + else + scope.removeAttribute("forEachStatus"); + if (_oldEach != null) + scope.setAttribute("each", _oldEach); + else + scope.removeAttribute("each"); _it = null; _status = null; //recycle (just in case) } diff --git a/zk/src/org/zkoss/zk/ui/util/GenericComposer.java b/zk/src/org/zkoss/zk/ui/util/GenericComposer.java index 1f89b8c9ddf..cfbb3a95390 100644 --- a/zk/src/org/zkoss/zk/ui/util/GenericComposer.java +++ b/zk/src/org/zkoss/zk/ui/util/GenericComposer.java @@ -28,8 +28,7 @@ import org.zkoss.zk.ui.metainfo.ComponentInfo; import org.zkoss.zk.ui.util.Composer; import org.zkoss.zk.ui.util.ComposerExt; -import org.zkoss.zk.scripting.Namespace; -import org.zkoss.zk.scripting.NamespaceActivationListener; +import org.zkoss.zk.ui.util.ComponentActivationListener; /** *

    An abstract composer that you can extend and write intuitive onXxx event handler methods; @@ -73,7 +72,7 @@ * @since 3.0.1 */ abstract public class GenericComposer extends GenericEventListener -implements Composer, ComposerExt, NamespaceActivationListener, +implements Composer, ComposerExt, ComponentActivationListener, java.io.Serializable { /** * Registers onXxx events to the supervised component; a subclass that override @@ -110,19 +109,19 @@ public void doFinally() throws Exception { //do nothing } - //NamespaceActivationListener// - /** Called when a namespace is going to passivate this object. + //ScopeActivationListener// + /** Called when the component is going to passivate this object. * Default: does nothing. */ - public void willPassivate(Namespace ns) { + public void willPassivate(Component comp) { } - /** Called when a namespace has activated this object back. + /** Called when the component has activated this object back. * Default: invokes {@link #doAfterCompose}. * @since 3.6.2 */ - public void didActivate(Namespace ns) { + public void didActivate(Component comp) { try { - doAfterCompose(ns.getOwner()); + doAfterCompose(comp); } catch (Throwable ex) { throw UiException.Aide.wrap(ex); } diff --git a/zk/src/org/zkoss/zk/xel/impl/ExecutionResolver.java b/zk/src/org/zkoss/zk/xel/impl/ExecutionResolver.java index e2f09ac58c9..53a0adbb961 100644 --- a/zk/src/org/zkoss/zk/xel/impl/ExecutionResolver.java +++ b/zk/src/org/zkoss/zk/xel/impl/ExecutionResolver.java @@ -147,12 +147,16 @@ public Object resolveVariable(String name) throws XelException { final Page page = comp.getPage(); if (page != null) { final Object o = - page.getZScriptVariable(comp.getNamespace(), name); + page.getZScriptVariable(comp, name); if (o != null) return o; } - final Object o = comp.getVariable(name, false); + Object o = _exec.getAttribute(name); + if (o != null || _exec.hasAttribute(name)) + return o; + + o = comp.getFellowOrAttribute(name, false); if (o != null) return o; } else { @@ -168,9 +172,17 @@ public Object resolveVariable(String name) throws XelException { if (o != null) return o; - o = page.getVariable(name); + o = _exec.getAttribute(name); + if (o != null || _exec.hasAttribute(name)) + return o; + + o = page.getFellowOrAttribute(name, false); if (o != null) return o; + } else { + Object o = _exec.getAttribute(name, false); + if (o != null || _exec.hasAttribute(name, false)) + return o; } } diff --git a/zk/version b/zk/version index 28cbf7c0aae..595f5feb836 100644 --- a/zk/version +++ b/zk/version @@ -1 +1,2 @@ -5.0.0 \ No newline at end of file +5.0.0 +deprecation=off diff --git a/zkdemo/src/archive/test/z5-attrvar.zul b/zkdemo/src/archive/test/z5-attrvar.zul new file mode 100644 index 00000000000..cd05aa4be7f --- /dev/null +++ b/zkdemo/src/archive/test/z5-attrvar.zul @@ -0,0 +1,45 @@ + + + + + + + + + ${s}, ${r}, ${a} and ${b} + + title: ${main.title} + + diff --git a/zkdemo/src/org/zkoss/zkdemo/userguide/DemoItem.java b/zkdemo/src/org/zkoss/zkdemo/userguide/DemoItem.java index fe25387c9dd..6b795faf8b8 100644 --- a/zkdemo/src/org/zkoss/zkdemo/userguide/DemoItem.java +++ b/zkdemo/src/org/zkoss/zkdemo/userguide/DemoItem.java @@ -49,4 +49,7 @@ public String getFile() { public String getLabel() { return _label; } + public String toString() { + return "[DemoItem:" + _id +", "+_file+']'; + } } diff --git a/zkdemo/src/org/zkoss/zkdemo/userguide/MainLayoutComposer.java b/zkdemo/src/org/zkoss/zkdemo/userguide/MainLayoutComposer.java index 5cb54b2e043..da185ed8091 100644 --- a/zkdemo/src/org/zkoss/zkdemo/userguide/MainLayoutComposer.java +++ b/zkdemo/src/org/zkoss/zkdemo/userguide/MainLayoutComposer.java @@ -22,7 +22,9 @@ import java.util.List; import java.util.Map; +import org.zkoss.util.logging.Log; import org.zkoss.lang.reflect.FusionInvoker; + import org.zkoss.zk.ui.Component; import org.zkoss.zk.ui.ComponentNotFoundException; import org.zkoss.zk.ui.Execution; @@ -57,6 +59,8 @@ */ public class MainLayoutComposer extends GenericForwardComposer implements MainLayoutAPI, ComposerExt { + private static final Log log = Log.lookup(MainLayoutComposer.class); + Textbox searchBox; Listbox itemList; @@ -190,7 +194,7 @@ public void onMainCreate(Event event) { if (item == null) { item = (Listitem) main.getFellow("f1"); setSelectedCategory(item); - } + } xcontents.setSrc(((DemoItem) item.getValue()).getFile()); itemList.selectItem(item); @@ -306,12 +310,12 @@ public ComponentInfo doBeforeCompose(Page page, Component parent, public void doBeforeComposeChildren(Component comp) throws Exception { bindComponent(comp); Object obj = FusionInvoker.newInstance(new Object[] { comp, this }); - comp.setVariable("main", obj, true); + comp.setAttribute("main", obj); main = (Borderlayout) comp; } public boolean doCatch(Throwable ex) throws Exception { - ex.printStackTrace(); + log.error("Failed to compose "+this, ex); return false; } diff --git a/zkplus/src/org/zkoss/zkplus/databind/AnnotateDataBinderInit.java b/zkplus/src/org/zkoss/zkplus/databind/AnnotateDataBinderInit.java index e4c77b74545..973c84f9470 100644 --- a/zkplus/src/org/zkoss/zkplus/databind/AnnotateDataBinderInit.java +++ b/zkplus/src/org/zkoss/zkplus/databind/AnnotateDataBinderInit.java @@ -109,13 +109,13 @@ public void doAfterCompose(Page page, Component[] comps) throws Exception { boolean b = _defaultConfig != null ? Boolean.valueOf(_defaultConfig).booleanValue() : true; if (_comp instanceof Component) { //a specified component instance _binder = new AnnotateDataBinder(_comp, b); - _comp.setVariable(_name, _binder, true); + _comp.setAttribute(_name, _binder); } else if (_compPath == null || "page".equals(_compPath)) { //page _binder = new AnnotateDataBinder(page, b); - if (page.getVariable(_name) != null) { //already a binder on the page + if (page.getAttribute(_name) != null) { //already a binder on the page throw new UiException("Page is already covered by another Data Binder. Cannot be covered by this Data Binder again. Page:"+page.getId()); } else { - page.setVariable(_name, _binder); + page.setAttribute(_name, _binder); } } else if (_compPath.startsWith("/")) { //absolute path final Component comp = Path.getComponent(_compPath); @@ -123,14 +123,14 @@ public void doAfterCompose(Page page, Component[] comps) throws Exception { throw new UiException("Cannot find the specified component. Absolute Path:"+_compPath); } _binder = new AnnotateDataBinder(comp, b); - comp.setVariable(_name, _binder, true); + comp.setAttribute(_name, _binder); } else if (_compPath.startsWith("./") || _compPath.startsWith("../")) { //relative path for (int j = 0; j < comps.length; ++j) { final Component vroot = comps[j]; final Component comp = Path.getComponent(vroot.getSpaceOwner(), _compPath); if (comp != null) { //found _binder = new AnnotateDataBinder(comp, b); - comp.setVariable(_name, _binder, true); + comp.setAttribute(_name, _binder); break; } } @@ -140,7 +140,7 @@ public void doAfterCompose(Page page, Component[] comps) throws Exception { } else { final Component comp = page.getFellow(_compPath); _binder = new AnnotateDataBinder(comp, b); - comp.setVariable(_name, _binder, true); + comp.setAttribute(_name, _binder); } _binder.loadAll(); //load data bean properties into UI components } diff --git a/zkplus/src/org/zkoss/zkplus/databind/DataBinder.java b/zkplus/src/org/zkoss/zkplus/databind/DataBinder.java index 33322dfdfb7..0b6c016a4a7 100644 --- a/zkplus/src/org/zkoss/zkplus/databind/DataBinder.java +++ b/zkplus/src/org/zkoss/zkplus/databind/DataBinder.java @@ -36,8 +36,6 @@ import org.zkoss.util.ModificationException; import org.zkoss.zk.scripting.HierachicalAware; import org.zkoss.zk.scripting.Interpreter; -import org.zkoss.zk.scripting.Namespace; -import org.zkoss.zk.scripting.Namespaces; import org.zkoss.zk.ui.Component; import org.zkoss.zk.ui.Page; import org.zkoss.zk.ui.Path; @@ -1043,7 +1041,7 @@ private Object fetchValue(Object bean, BindingNode node, String nodeid, boolean if (existsBean(beanid)) { setBean(beanid, val); } else if (!setZScriptVariable(comp, beanid, val)) { - comp.setVariable(beanid, val, false); + comp.setAttribute(beanid, val, false); } refChanged = true; } else { @@ -1189,14 +1187,13 @@ private boolean isPrimitive(Object bean) { private boolean setZScriptVariable(Component comp, String beanid, Object val) { //for all loaded interperter, assign val to beanid boolean found = false; - final Namespace ns = comp.getNamespace(); for(final Iterator it = comp.getPage().getLoadedInterpreters().iterator(); it.hasNext();) { final Interpreter ip = (Interpreter) it.next(); if (ip instanceof HierachicalAware) { final HierachicalAware ha = (HierachicalAware)ip; - if (ha.containsVariable(ns, beanid)) { - ha.setVariable(ns, beanid, val); + if (ha.containsVariable(comp, beanid)) { + ha.setVariable(comp, beanid, val); found = true; } } else if (ip.containsVariable(beanid)) { @@ -1232,19 +1229,17 @@ private boolean setZScriptVariable(Component comp, String beanid, Object val) { //variable resolving final Page page = comp.getPage(); if (page != null) - bean = page.getZScriptVariable(comp.getNamespace(), beanid); + bean = page.getZScriptVariable(comp, beanid); if (bean == null) { - final Object self = - page.getNamespace().getVariableNames().contains("self") ? - page.getNamespace().getVariable("self", true) : null; + final Object self = page.getAttribute("self"); try { - page.setVariable("self", comp); - bean = comp.getVariable(beanid, false); + page.setAttribute("self", comp); + bean = comp.getAttribute(beanid, false); } finally { if (self == null) { - page.unsetVariable("self"); + page.removeAttribute("self"); } else { - page.setVariable("self", self); + page.setAttribute("self", self); } } } diff --git a/zul/src/org/zkoss/zul/Column.java b/zul/src/org/zkoss/zul/Column.java index 02e38ae7513..7d6dd067051 100644 --- a/zul/src/org/zkoss/zul/Column.java +++ b/zul/src/org/zkoss/zul/Column.java @@ -37,7 +37,7 @@ import org.zkoss.zk.ui.UiException; import org.zkoss.zk.ui.WrongValueException; import org.zkoss.zk.ui.event.Events; -import org.zkoss.zk.scripting.Namespaces; +import org.zkoss.zk.ui.ext.Scopes; import org.zkoss.zul.impl.HeaderElement; import org.zkoss.zul.mesg.MZul; @@ -333,7 +333,7 @@ public boolean sort(boolean ascending) { if (grid == null || rows == null) return false; //comparator might be zscript - Namespaces.beforeInterpret(this); + Scopes.beforeInterpret(this); try { final ListModel model = grid.getModel(); boolean isPagingMold = grid.inPagingMold(); @@ -356,7 +356,7 @@ public boolean sort(boolean ascending) { // the wrong active page when dynamically add/remove the item (i.e. sorting). // Therefore, we have to reset the correct active page. } finally { - Namespaces.afterInterpret(); + Scopes.afterInterpret(); } fixDirection(grid, ascending); @@ -427,7 +427,7 @@ public boolean group(boolean ascending) { if (grid == null) return false; //comparator might be zscript - Namespaces.beforeInterpret(this); + Scopes.beforeInterpret(this); try { final ListModel model = grid.getModel(); int index = grid.getColumns().getChildren().indexOf(this); @@ -493,7 +493,7 @@ public int compare(Object o1, Object o2) { sort0(grid, cmpr); //need to sort each group } } finally { - Namespaces.afterInterpret(); + Scopes.afterInterpret(); } fixDirection(grid, ascending); diff --git a/zul/src/org/zkoss/zul/Listheader.java b/zul/src/org/zkoss/zul/Listheader.java index 30420c30044..7b6f0f9ac9f 100644 --- a/zul/src/org/zkoss/zul/Listheader.java +++ b/zul/src/org/zkoss/zul/Listheader.java @@ -34,8 +34,7 @@ import org.zkoss.zk.ui.UiException; import org.zkoss.zk.ui.WrongValueException; import org.zkoss.zk.ui.event.Events; -import org.zkoss.zk.scripting.Namespace; -import org.zkoss.zk.scripting.Namespaces; +import org.zkoss.zk.ui.ext.Scopes; import org.zkoss.zul.impl.HeaderElement; @@ -372,7 +371,7 @@ public boolean sort(boolean ascending) { if (box == null) return false; //comparator might be zscript - Namespaces.beforeInterpret(this); + Scopes.beforeInterpret(this); try { final ListModel model = box.getModel(); boolean isPagingMold = box.inPagingMold(); @@ -394,7 +393,7 @@ public boolean sort(boolean ascending) { // the wrong active page when dynamically add/remove the item (i.e. sorting). // Therefore, we have to reset the correct active page. } finally { - Namespaces.afterInterpret(); + Scopes.afterInterpret(); } //maintain diff --git a/zul/src/org/zkoss/zul/impl/InputElement.java b/zul/src/org/zkoss/zul/impl/InputElement.java index 824071ab929..760fdcd1714 100644 --- a/zul/src/org/zkoss/zul/impl/InputElement.java +++ b/zul/src/org/zkoss/zul/impl/InputElement.java @@ -28,10 +28,9 @@ import org.zkoss.zk.ui.WrongValueException; import org.zkoss.zk.ui.util.Clients; import org.zkoss.zk.ui.event.*; +import org.zkoss.zk.ui.ext.Scopes; import org.zkoss.zk.ui.sys.ComponentsCtrl; import org.zkoss.zk.au.out.AuSelect; -import org.zkoss.zk.scripting.Namespace; -import org.zkoss.zk.scripting.Namespaces; import org.zkoss.zul.mesg.MZul; import org.zkoss.zul.Constraint; @@ -326,7 +325,7 @@ protected void validate(Object value) throws WrongValueException { final Constraint constr = getConstraint(); if (constr != null) { //Bug 1698190: contructor might be zscript - Namespaces.beforeInterpret(this); + Scopes.beforeInterpret(this); try { constr.validate(this, value); if (!_checkOnly && (constr instanceof CustomConstraint)) { @@ -342,7 +341,7 @@ protected void validate(Object value) throws WrongValueException { ((CustomConstraint)constr).showCustomError(this, ex); throw ex; } finally { - Namespaces.afterInterpret(); + Scopes.afterInterpret(); } } } @@ -359,13 +358,13 @@ protected void validate(Object value) throws WrongValueException { */ protected WrongValueException showCustomError(WrongValueException ex) { if (_constr instanceof CustomConstraint) { - Namespaces.beforeInterpret(this); + Scopes.beforeInterpret(this); try { ((CustomConstraint)_constr).showCustomError(this, ex); } catch (Throwable t) { log.realCause(t); //and ignore it } finally { - Namespaces.afterInterpret(); + Scopes.afterInterpret(); } } return ex;