zk/src/main/java/org/zkoss/zk/ui/metainfo/VariableResolverInfo.java

Summary

Maintainability
C
1 day
Test Coverage
/* VariableResolverInfo.java

    Purpose:
        
    Description:
        
    History:
        Thu Jun  1 18:12:56     2006, Created by tomyeh

Copyright (C) 2006 Potix Corporation. All Rights Reserved.

{{IS_RIGHT
    This program is distributed under LGPL Version 2.1 in the hope that
    it will be useful, but WITHOUT ANY WARRANTY.
}}IS_RIGHT
*/
package org.zkoss.zk.ui.metainfo;

import java.util.Map;

import org.zkoss.lang.Classes;
import org.zkoss.xel.VariableResolver;
import org.zkoss.zk.ui.Page;
import org.zkoss.zk.ui.UiException;
import org.zkoss.zk.xel.Evaluator;
import org.zkoss.zk.xel.ExValue;

/**
 * A definition of the variable resolver ({@link VariableResolver}).
 *
 * <p>Note: we resolve the class by using Classes.forNameByThread.
 * In other words, it doesn't support the class defined in zscript.
 * Why not? Since there is no way to run zscript before
 * the variable-resolver directive (and better performance).
 * </p>
 * <p>Note: it is not serializable.</p>
 * 
 * @author tomyeh
 */
public class VariableResolverInfo extends ArgumentInfo { //directive
    //    private static final Logger log = LoggerFactory.getLogger(VariableResolverInfo.class);

    /** A class, an ExValue or an VariableResolver. */
    private Object _resolver;

    /** Constructs with a class.
     * @param args the map of arguments. Ignored if null.<br/>
     * Notice that, once assigned, the map belongs to this object, and the caller
     * shall not access it again
     * @since 3.6.2
     */
    public VariableResolverInfo(Class<? extends VariableResolver> cls, Map<String, String> args) {
        super(args);
        checkClass(cls);
        _resolver = cls;
    }

    /** Constructs with a class.
     */
    public VariableResolverInfo(Class<? extends VariableResolver> cls) {
        this(cls, null);
    }

    private static void checkClass(Class<?> cls) {
        if (!VariableResolver.class.isAssignableFrom(cls))
            throw new UiException(VariableResolver.class + " must be implemented: " + cls);
    }

    /** Constructs with a class name.
     *
     * @param clsnm the class name; it could be an EL expression.
     * @since 3.6.2
     */
    public VariableResolverInfo(String clsnm, Map<String, String> args) throws ClassNotFoundException {
        super(args);

        if (clsnm == null || clsnm.length() == 0)
            throw new IllegalArgumentException("empty");

        if (clsnm.indexOf("${") < 0) {
            if (clsnm.indexOf('.') >= 0) { //resolve it now
                try {
                    final Class<?> cls = Classes.forNameByThread(clsnm);
                    checkClass(cls);
                    _resolver = cls;
                } catch (ClassNotFoundException ex) {
                    throw new ClassNotFoundException("Class not found: " + clsnm, ex);
                }
            } else { //it might depend on <?import?>
                _resolver = clsnm;
            }
        } else {
            _resolver = new ExValue(clsnm, String.class);
        }
    }

    /** Constructs with a class name.
     *
     * @param clsnm the class name; it could be an EL expression.
     */
    public VariableResolverInfo(String clsnm) throws ClassNotFoundException {
        this(clsnm, null);
    }

    /** Constructs with an initiator that will be reuse each time
     * {@link #newVariableResolver} is called.
     */
    public VariableResolverInfo(VariableResolver resolver) {
        super(null);

        if (resolver == null)
            throw new IllegalArgumentException("null");
        _resolver = resolver;
    }

    /** Creates and returns the variable resolver for the specified page.
     */
    public VariableResolver newVariableResolver(PageDefinition pgdef, Page page) throws Exception {
        return newVariableResolver(pgdef.getEvaluator(), page);
    }

    /** Creates and returns the variable resolver for the specified page.
     * @since 3.6.2
     */
    public VariableResolver newVariableResolver(Evaluator eval, Page page) throws Exception {
        if (_resolver instanceof VariableResolver)
            return (VariableResolver) _resolver;

        String clsnm = null;
        if (_resolver instanceof ExValue) {
            clsnm = (String) ((ExValue) _resolver).getValue(eval, page);
            if (clsnm == null || clsnm.length() == 0) {
                //                if (log.isDebugEnabled()) log.debug("Ignore "+_resolver+" due to empty");
                return null; //ignore it!!
            }
        } else if (_resolver instanceof String) {
            clsnm = (String) _resolver;
        }

        final Class<?> cls;
        if (clsnm != null) {
            try {
                cls = page != null ? page.resolveClass(clsnm) : Classes.forNameByThread(clsnm);
                checkClass(cls);
            } catch (ClassNotFoundException ex) {
                throw new ClassNotFoundException("Class not found: " + clsnm + " (" + _resolver + ")", ex);
            }
            if (clsnm.equals(_resolver))
                _resolver = cls; //cache it for better performance
        } else {
            cls = (Class<?>) _resolver;
        }

        return (VariableResolver) newInstance(cls, eval, page);
    }

    //Object//
    public String toString() {
        return "[variable-resolver " + _resolver + "]";
    }
}