Package com.caucho.quercus.env

Source Code of com.caucho.quercus.env.QuercusClass$StaticField

/*
* Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
*
* This file is part of Resin(R) Open Source
*
* Each copy or derived work must preserve the copyright notice and this
* notice unmodified.
*
* Resin Open Source is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Resin Open Source is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
* of NON-INFRINGEMENT.  See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with Resin Open Source; if not, write to the
*
*   Free Software Foundation, Inc.
*   59 Temple Place, Suite 330
*   Boston, MA 02111-1307  USA
*
* @author Scott Ferguson
*/

package com.caucho.quercus.env;

import com.caucho.quercus.QuercusRuntimeException;
import com.caucho.quercus.expr.ClassConstExpr;
import com.caucho.quercus.expr.Expr;
import com.caucho.quercus.expr.UnicodeLiteralExpr;
import com.caucho.quercus.expr.StringLiteralExpr;
import com.caucho.quercus.module.ModuleContext;
import com.caucho.quercus.function.AbstractFunction;
import com.caucho.quercus.program.ClassDef;
import com.caucho.quercus.program.InstanceInitializer;
import com.caucho.quercus.program.JavaClassDef;
import com.caucho.util.IntMap;
import com.caucho.util.L10N;

import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.io.UnsupportedEncodingException;

/**
* Represents a Quercus runtime class.
*/
public class QuercusClass {
  private static final L10N L = new L10N(QuercusClass.class);
  private static final Logger log
    = Logger.getLogger(QuercusClass.class.getName());

  private final JavaClassDef _javaClassDef;
  private final ClassDef _classDef;
  private final String _className;

  private QuercusClass _parent;
 
  private WeakReference<QuercusClass> _cacheRef;

  private boolean _isAbstract;
  private boolean _isInterface;
  private boolean _isJavaWrapper;
 
  private ClassDef []_classDefList;

  private AbstractFunction _constructor;
  private AbstractFunction _destructor;

  private AbstractFunction _fieldGet;
  private AbstractFunction _fieldSet;
 
  private AbstractFunction _call;

  private ArrayDelegate _arrayDelegate;
  private TraversableDelegate _traversableDelegate;
  private CountDelegate _countDelegate;

  private final ArrayList<InstanceInitializer> _initializers;
 
  private final ArrayList<StringValue> _fieldNames;
 
  private final IntMap _fieldMap;
 
  private final HashMap<StringValue,Expr> _fieldInitMap;
 
  private final MethodMap<AbstractFunction> _methodMap;

  private final HashMap<String,Expr> _constMap;

  private final HashMap<String,ArrayList<StaticField>> _staticFieldExprMap;

  private final HashSet<String> _instanceofSet;

  private boolean _isModified;

  public QuercusClass(ClassDef classDef, QuercusClass parent)
  {
    this(ModuleContext.getLocalContext(Thread.currentThread().getContextClassLoader()),
         classDef,
         parent);
  }

  public QuercusClass(ModuleContext moduleContext,
                      ClassDef classDef,
                      QuercusClass parent)
  {
    _classDef = classDef.loadClassDef(); // force load of any lazy classes
    _className = classDef.getName();
    _parent = parent;

    _isAbstract = _classDef.isAbstract();
    _isInterface = _classDef.isInterface();
   
    _initializers = new ArrayList<InstanceInitializer>();
    _fieldNames = new ArrayList<StringValue>();
    _fieldMap = new IntMap(16);
 
    _fieldInitMap = new HashMap<StringValue,Expr>();
    _methodMap = new MethodMap<AbstractFunction>();

    _constMap = new HashMap<String,Expr>();

    _staticFieldExprMap = new LinkedHashMap<String,ArrayList<StaticField>>();

    JavaClassDef javaClassDef = null;

    if (classDef instanceof JavaClassDef) {
      javaClassDef = (JavaClassDef) classDef;
      _isJavaWrapper = ! javaClassDef.isDelegate();
    }
   
    for (QuercusClass cls = parent; cls != null; cls = cls.getParent()) {
      AbstractFunction cons = cls.getConstructor();
     
      if (cons != null) {
        addMethod(cls.getName(), cons);
      }
    }

    ClassDef []classDefList;
   
    if (_parent != null) {
      classDefList = new ClassDef[parent._classDefList.length + 1];

      System.arraycopy(parent._classDefList, 0, classDefList, 1,
                       parent._classDefList.length);

      classDefList[0] = classDef;
    }
    else {
      classDefList = new ClassDef[] { classDef };
    }
         
    _classDefList = classDefList;

    for (int i = 0; i < classDefList.length; i++) {
      if (classDefList[i] instanceof JavaClassDef)
        javaClassDef = (JavaClassDef) classDefList[i];
    }
   
    _javaClassDef = javaClassDef;

    _instanceofSet = new HashSet<String>();

    HashSet<String> ifaces = new HashSet<String>();

    for (int i = classDefList.length - 1; i >= 0; i--) {
      classDef = classDefList[i];

      if (classDef == null) {
        throw new NullPointerException("classDef:" + _classDef
                                       + " i:" + i + " parent:" + parent);
      }

      classDef.init();

      addInstances(_instanceofSet, ifaces, classDef);

      classDef.initClass(this);
    }
   
    if (_constructor == null && parent != null)
      _constructor = parent.getConstructor();
   
    // php/093n
    if (_constructor != null
        && ! _constructor.getName().equals("__construct")) {
      addMethodIfNotExist(_className, _constructor);
    }

    if (_destructor == null && parent != null)
      _destructor = parent.getDestructor();
  }

  private void addInstances(HashSet<String> instanceofSet,
                            HashSet<String> ifaces,
                            ClassDef classDef)
  {
    // _instanceofSet.add(classDef.getName());
    classDef.addInterfaces(instanceofSet);

    for (String iface : classDef.getInterfaces()) {
      // XXX: php/0cn2, but this is wrong:
      QuercusClass cl = Env.getInstance().findClass(iface, true, true);
       
      if (cl == null)
        throw new QuercusRuntimeException(L.l("cannot find interface {0}",
                                              iface));

      // _instanceofSet.addAll(cl.getInstanceofSet());
       
      ClassDef ifaceDef = cl.getClassDef();
      // ClassDef ifaceDef = moduleContext.findClass(iface);

      if (ifaceDef != null) {
        if (ifaces.add(iface)) {
          addInstances(instanceofSet, ifaces, ifaceDef);

          ifaceDef.initClass(this);
        }
      }
    }
  }

  /**
   * Copy based on a cached value
   */
  public QuercusClass(QuercusClass cacheClass, QuercusClass parent)
  {
    _cacheRef = new WeakReference<QuercusClass>(cacheClass);
   
    _javaClassDef = cacheClass._javaClassDef;
    _classDef = cacheClass._classDef;
    _className = cacheClass._className;

    _isJavaWrapper = cacheClass._isJavaWrapper;
    _classDefList = cacheClass._classDefList;

    _parent = parent;

    _constructor = cacheClass._constructor;
    _destructor = cacheClass._destructor;
   
    _fieldGet = cacheClass._fieldGet;
    _fieldSet = cacheClass._fieldSet;
 
    _call = cacheClass._call;

    _arrayDelegate = cacheClass._arrayDelegate;
    _traversableDelegate = cacheClass._traversableDelegate;
    _countDelegate = cacheClass._countDelegate;

    _initializers = cacheClass._initializers;
 
    _fieldNames = cacheClass._fieldNames;
    _fieldMap = cacheClass._fieldMap;
    _fieldInitMap = cacheClass._fieldInitMap;
    _methodMap = cacheClass._methodMap;
    _constMap = cacheClass._constMap;
    _staticFieldExprMap = cacheClass._staticFieldExprMap;
    _instanceofSet = cacheClass._instanceofSet;
  }

  public ClassDef getClassDef()
  {
    return _classDef;
  }
 
  public JavaClassDef getJavaClassDef()
  {
    return _javaClassDef;
  }

  public MethodMap<AbstractFunction> getMethodMap()
  {
    return _methodMap;
  }

  public HashSet<String> getInstanceofSet()
  {
    return _instanceofSet;
  }

  /**
   * Returns the name.
   */
  public String getName()
  {
    return _className;
  }

  /**
   * Returns the parent class.
   */
  public QuercusClass getParent()
  {
    return _parent;
  }

  /*
   * Returns the class definitions for this class.
   */
  public ClassDef []getClassDefList()
  {
    return _classDefList;
  }
 
  /*
   * Returns the name of the extension that this class is part of.
   */
  public String getExtension()
  {
    return _classDef.getExtension();
  }

  public boolean isInterface()
  {
    return _isInterface;
  }
 
  public boolean isAbstract()
  {
    return _isAbstract;
  }
 
  public boolean isFinal()
  {
    return _classDef.isFinal();
  }

  /**
   * Sets the constructor.
   */
  public void setConstructor(AbstractFunction fun)
  {
    _constructor = fun;
  }

  /**
   * Gets the constructor.
   */
  public AbstractFunction getConstructor()
  {
    return _constructor;
  }

  /**
   * Sets the destructor.
   */
  public void setDestructor(AbstractFunction fun)
  {
    _destructor = fun;
  }

  /**
   * Gets the destructor.
   */
  public AbstractFunction getDestructor()
  {
    return _destructor;
  }

  /**
   * Returns true if the class is modified for caching.
   */
  public boolean isModified()
  {
    if (_isModified)
      return true;
    else if (_parent != null)
      return _parent.isModified();
    else
      return false;
  }

  /**
   * Mark the class as modified for caching.
   */
  public void setModified()
  {
    if (! _isModified) {
      _isModified = true;
     
      if (_cacheRef != null) {
        QuercusClass cacheClass = _cacheRef.get();

        if (cacheClass != null)
          cacheClass.setModified();
      }
    }
  }
 
  /**
   * Sets the array delegate (see ArrayAccess)
   */
  public void setArrayDelegate(ArrayDelegate delegate)
  {
    if (log.isLoggable(Level.FINEST))
      log.log(Level.FINEST, L.l("{0} adding array delegate {1}",
                                this,  delegate));

    _arrayDelegate = delegate;
  }
 
  /**
   * Gets the array delegate (see ArrayAccess)
   */
  public final ArrayDelegate getArrayDelegate()
  {
    return _arrayDelegate;
  }
 
  /**
   * Sets the traversable delegate
   */
  public void setTraversableDelegate(TraversableDelegate delegate)
  {
    if (log.isLoggable(Level.FINEST))
      log.log(Level.FINEST, L.l("{0} setting traversable delegate {1}",
                                this,  delegate));

    _traversableDelegate = delegate;
  }
 
  /**
   * Gets the traversable delegate
   */
  public final TraversableDelegate getTraversableDelegate()
  {
    return _traversableDelegate;
  }
 
  /**
   * Sets the count delegate
   */
  public void setCountDelegate(CountDelegate delegate)
  {
    if (log.isLoggable(Level.FINEST))
      log.log(Level.FINEST, L.l("{0} setting count delegate {1}",
                                this,  delegate));

    _countDelegate = delegate;
  }
 
  /**
   * Gets the count delegate
   */
  public final CountDelegate getCountDelegate()
  {
    return _countDelegate;
  }

  /**
   * Sets the __fieldGet
   */
  public void setFieldGet(AbstractFunction fun)
  {
    _fieldGet = fun;
  }

  /**
   * Returns the __fieldGet
   */
  public AbstractFunction getFieldGet()
  {
    return _fieldGet;
  }

  /**
   * Sets the __fieldSet
   */
  public void setFieldSet(AbstractFunction fun)
  {
    _fieldSet = fun;
  }

  /**
   * Returns the __fieldSet
   */
  public AbstractFunction getFieldSet()
  {
    return _fieldSet;
  }

  /**
   * Sets the __call
   */
  public void setCall(AbstractFunction fun)
  {
    _call = fun;
  }

  /**
   * Gets the __call
   */
  public AbstractFunction getCall()
  {
    return _call;
  }

  /**
   * Adds an initializer
   */
  public void addInitializer(InstanceInitializer init)
  {
    _initializers.add(init);
  }

  /**
   * Adds a field.
   */
  public void addField(StringValue name,
                       int index,
                       Expr initExpr,
                       FieldVisibility visibility)
  {
    _fieldNames.add(name);
    _fieldMap.put(name, index);
    _fieldInitMap.put(name, initExpr);
  }

  /**
   * Adds a field.
   */
  public int addFieldIndex(StringValue name)
  {
    int index = _fieldMap.get(name);

    if (index >= 0)
      return index;
    else {
      index = _fieldNames.size();
   
      _fieldMap.put(name, index);
      _fieldNames.add(name);

      return index;
    }
  }
 
  /**
   * Returns a set of the fields and their initial values
   */
  public HashMap<StringValue,Expr> getClassVars()
  {
    return _fieldInitMap;
  }
 
  /**
   * Returns the declared functions.
   */
  public Iterable<AbstractFunction> getClassMethods()
  {
    return _methodMap.values();
  }

  /**
   * Adds a method.
   */
  public void addMethod(String name, AbstractFunction fun)
  {
    if (fun == null)
      throw new NullPointerException(L.l("'{0}' is a null function", name));
   
    //php/09j9
    // XXX: this is a hack to get Zend Framework running, the better fix is
    // to initialize all interface classes before any concrete classes
    AbstractFunction existingFun = _methodMap.get(name);
   
    if (existingFun == null || ! fun.isAbstract())
      _methodMap.put(name, fun);
  }
 
  /*
   * Adds a method if it does not exist.
   */
  public void addMethodIfNotExist(String name, AbstractFunction fun)
  {
    if (fun == null)
      throw new NullPointerException(L.l("'{0}' is a null function", name));
   
    //php/09j9
    // XXX: this is a hack to get Zend Framework running, the better fix is
    // to initialize all interface classes before any concrete classes
    AbstractFunction existingFun = _methodMap.get(name);
   
    if (existingFun == null && ! fun.isAbstract())
      _methodMap.put(name, fun);
  }

  /**
   * Adds a static class field.
   */
  public void addStaticFieldExpr(String className, String name, Expr value)
  {
    ArrayList<StaticField> fieldList = _staticFieldExprMap.get(className);
   
    if (fieldList == null) {
      fieldList = new ArrayList<StaticField>();

      _staticFieldExprMap.put(className, fieldList);
    }
   
    fieldList.add(new StaticField(name, value));
  }

  /**
   * Returns the static field names.
   */
  public ArrayList<String> getStaticFieldNames()
  {
    ArrayList<String> names = new ArrayList<String>();

    if (_staticFieldExprMap != null) {
      for (Map.Entry<String,ArrayList<StaticField>> entry
           : _staticFieldExprMap.entrySet()) {
        ArrayList<StaticField> fieldList = entry.getValue();
       
        for (StaticField field : fieldList) {
          names.add(field.getName());
        }
      }
    }

    return names;
  }

  /**
   * Adds a constant definition
   */
  public void addConstant(String name, Expr expr)
  {
    _constMap.put(name, expr);
  }

  /**
   * Returns the number of fields.
   */
  public int getFieldSize()
  {
    return _fieldNames.size();
  }

  /**
   * Returns the field index.
   */
  public int findFieldIndex(StringValue name)
  {
    return _fieldMap.get(name);
  }

  /**
   * Returns the key set.
   */
  public ArrayList<StringValue> getFieldNames()
  {
    return _fieldNames;
  }

  public void validate(Env env)
  {
    if (! _isAbstract && ! _isInterface) {
      for (AbstractFunction fun : _methodMap.values()) {
        /* XXX: abstract methods need to be validated
              php/393g, php/393i, php/39j2
        if (! (absFun instanceof Function))
          continue;

        Function fun = (Function) absFun;
         */

        boolean isAbstract;

        // php/093g constructor
        if (_constructor != null && fun.getName().equals(_constructor.getName()))
          isAbstract = _constructor.isAbstract();
        else
          isAbstract = fun.isAbstract();

        if (isAbstract) {
          throw env.createErrorException(
            _classDef.getLocation(),
            L.l("Abstract function '{0}' must be implemented in concrete class {1}.",
                fun.getName(), getName()));
        }
      }
    }
  }

  public void init(Env env)
  {
    if (_staticFieldExprMap.size() == 0)
      return;

    for (Map.Entry<String,ArrayList<StaticField>> map
           : _staticFieldExprMap.entrySet()) {
      if (env.isInitializedClass(map.getKey()))
        continue;
     
      for (StaticField field : map.getValue()) {
        Value val;
        Expr expr = field._expr;

        //php/096f
        if (expr instanceof ClassConstExpr)
          val = ((ClassConstExpr) expr).eval(env);
        else
          val = expr.eval(env);

        String fullName = _className + "::" + field._name;
       
        env.setGlobalValue(fullName, val);
      }
     
      env.addInitializedClass(map.getKey());
    }
  }

  public Var getStaticField(Env env, String name)
  {
    Var var = getStaticFieldRec(env, name);

    if (var != null)
      return var;

    /*
    String fullName = _className + "::" + name;
     
    EnvVar envVar = env.getGlobalEnvVar(fullName);
     
    return envVar.getRef();
    */

    return null;
  }

  protected Var getStaticFieldRec(Env env, String name)
  {
    String fullName = _className + "::" + name;
     
    EnvVar envVar = env.getGlobalRaw(fullName);

    if (envVar != null)
      return envVar.getRef();
   
    QuercusClass parent = getParent();
   
    if (parent != null)
      return parent.getStaticFieldRec(env, name);
    else
      return null;
  }
 
  //
  // Constructors
  //
 
  /**
   * Creates a new instance.
   */
  /*
  public Value callNew(Env env, Expr []args)
  {
    Value object = _classDef.callNew(env, args);

    if (object != null)
      return object;
   
    object = newInstance(env);

    AbstractFunction fun = findConstructor();

    if (fun != null) {
      fun.callMethod(env, object, args);
    }

    return object;
  }
  */
 
  /*
   * Creates a new object without calling the constructor.  This is used
   * for unserializing classes.
   */
  public Value createObject(Env env)
  {
    if (_isAbstract) {
      throw env.createErrorException(L.l("abstract class '{0}' cannot be instantiated.",
                                     _className));
    }
    else if (_isInterface) {
      throw env.createErrorException(L.l("interface '{0}' cannot be instantiated.",
                                     _className));
    }

    ObjectValue objectValue = null;

    if (_isJavaWrapper) {
      // Java objects always need to call the constructor?
      return _javaClassDef.callNew(env, Value.NULL_ARGS);
    }
    else if (_javaClassDef != null && _javaClassDef.isDelegate()) {
      objectValue = new ObjectExtValue(this);
    }
    else if (_javaClassDef != null && ! _javaClassDef.isDelegate()) {
      // Java objects always need to call the constructor?
      Value javaWrapper = _javaClassDef.callNew(env, Value.NULL_ARGS);
      Object object = javaWrapper.toJavaObject();
     
      objectValue = new ObjectExtJavaValue(this, object, _javaClassDef);
    }
    else {
      objectValue = _classDef.createObject(env, this);
    }

    initObject(env, objectValue);

    return objectValue;
  }
 
  /*
   * Initializes the object's methods and fields.
   */
  public void initObject(Env env, ObjectValue obj)
  {
    for (int i = 0; i < _initializers.size(); i++) {
      _initializers.get(i).initInstance(env, obj);
    }
  }

  /**
   * Creates a new instance.
   */
  public Value callNew(Env env, Value ...args)
  {
    QuercusClass oldCallingClass = env.setCallingClass(this);
   
    try {
      if (_classDef.isAbstract()) {
        throw env.createErrorException(L.l("abstract class '{0}' cannot be instantiated.",
                                       _className));
      }
      else if (_classDef.isInterface()) {
        throw env.createErrorException(L.l("interface '{0}' cannot be instantiated.",
                                       _className));
      }

      ObjectValue objectValue = null;

      if (_isJavaWrapper) {
        return _javaClassDef.callNew(env, args);
      }
      else if (_javaClassDef != null && _javaClassDef.isDelegate()) {
        objectValue = new ObjectExtValue(this);
      }
      else if (_javaClassDef != null && ! _javaClassDef.isDelegate()) {
        // php/0k3-
        Value javaWrapper = _javaClassDef.callNew(env, args);
        Object object = javaWrapper.toJavaObject();
       
        objectValue = new ObjectExtJavaValue(this, object, _javaClassDef);
      }
      else {
        objectValue = _classDef.newInstance(env, this);
      }

      initObject(env, objectValue);
     
      AbstractFunction fun = findConstructor();

      if (fun != null)
        fun.callMethod(env, objectValue, args);
      else {
        //  if expr
      }

      return objectValue;

    } finally {
      env.setCallingClass(oldCallingClass);
    }
  }

  /**
   * Returns the parent class.
   */
  public String getParentName()
  {
    return _classDefList[0].getParentName();
  }

  /**
   * Returns true for an implementation of a class
   */
  public boolean isA(String name)
  {
    return _instanceofSet.contains(name.toLowerCase());
  }
 
  /*
   * Returns an array of the interfaces that this class and its parents
   * implements.
   */
  public ArrayValue getInterfaces(Env env, boolean autoload)
  {
    ArrayValue array = new ArrayValueImpl();
   
    getInterfaces(env, array, autoload, true);
   
    return array;
  }
 
  /*
   * Puts the interfaces that this class and its parents implements
   * into the array.
   */
  private void getInterfaces(Env env, ArrayValue array,
                             boolean autoload, boolean isTop)
  {
    ClassDef [] defList = _classDefList;
   
    for (int i = 0; i < defList.length; i++) {
      ClassDef def = defList[i];
     
      if (! isTop && def.isInterface()) {
        String name = def.getName();
       
        array.put(name, name);
      }

      String []defNames = def.getInterfaces();
     
      for (int j = 0; j < defNames.length; j++) {
        QuercusClass cls = env.findClass(defNames[j]);
       
        cls.getInterfaces(env, array, autoload, false);
      }
    }

    if (_parent != null)
      _parent.getInterfaces(env, array, autoload, false);
  }
 
  /*
   * Returns true if this class or its parents implements specified interface.
   */
  public boolean implementsInterface(Env env, String name)
  {
    ClassDef [] defList = _classDefList;
   
    for (int i = 0; i < defList.length; i++) {
      ClassDef def = defList[i];
     
      if (def.isInterface() && def.getName().equals(name))
        return true;

      String []defNames = def.getInterfaces();
     
      for (int j = 0; j < defNames.length; j++) {
        QuercusClass cls = env.findClass(defNames[j]);

        if (cls.implementsInterface(env, name))
          return true;
      }
    }
   
    if (_parent != null)
      return _parent.implementsInterface(env, name);
    else
      return false;
  }

  /**
   * Finds the matching constructor.
   */
  public AbstractFunction findConstructor()
  {
    return _constructor;
  }

  //
  // Fields
  //

  /**
   * Implements the __get method call.
   */
  public Value getField(Env env, Value qThis, StringValue name)
  {
    // php/09km, php/09kn
    // push/pop to prevent infinite recursion
   
    if (_fieldGet != null) {
      if (! env.pushFieldGet(qThis.getClassName(), name))
        return UnsetValue.UNSET;
     
      try {
        return _fieldGet.callMethod(env, qThis, name);
      } finally {
        env.popFieldGet();
      }
    }
    else
      return UnsetValue.UNSET;
  }

  /**
   * Implements the __set method call.
   */
  public void setField(Env env, Value qThis, StringValue name, Value value)
  {
    if (_fieldSet != null)
      _fieldSet.callMethod(env, qThis, name, value);
  }

  /**
   * Finds the matching function.
   */
  public AbstractFunction findFunction(String name)
  {
    char []key = name.toCharArray();
    int hash = MethodMap.hash(key, key.length);

    AbstractFunction fun = _methodMap.get(hash, key, key.length);

    return fun;
  }

  /**
   * Finds the matching function.
   */
  public AbstractFunction findStaticFunction(String name)
  {
    return findFunction(name);
  }

  /**
   * Finds the matching function.
   */
  public final AbstractFunction getFunction(String name)
  {
    return _methodMap.get(name);
  }

  /**
   * Finds the matching function.
   */
  public final AbstractFunction getFunction(int hash, char []name, int nameLen)
  {
    AbstractFunction fun = _methodMap.get(hash, name, nameLen);
   
    if (fun != null)
      return fun;
    else if (_className.equalsIgnoreCase(toMethod(name, nameLen))
             && _parent != null) {
      // php/093j
      return _parent.getFunction(_parent.getName());
    }
    else {
      throw new QuercusRuntimeException(L.l("{0}::{1} is an unknown method",
                                        getName(), toMethod(name, nameLen)));
    }
  }

  /**
   * calls the function.
   */
  public Value callMethod(Env env,
                          Value thisValue,
                          int hash, char []name, int nameLength,
                          Expr []args)
  {
    QuercusClass oldClass = env.setCallingClass(this);
    try {
      AbstractFunction fun = _methodMap.get(hash, name, nameLength);
     
      if (fun != null)
        return fun.callMethod(env, thisValue, args);
      else if (getCall() != null) {
        Expr []newArgs = new Expr[args.length + 1];
        String mtd = toMethod(name, nameLength);
        if (env.isUnicodeSemantics())
          newArgs[0] = new UnicodeLiteralExpr(mtd);
        else {
          try {
            newArgs[0] = new StringLiteralExpr(new StringBuilderValue(mtd.getBytes(env.getQuercus().getScriptEncoding())));
          } catch (UnsupportedEncodingException e) {
            newArgs[0] = new StringLiteralExpr(new ConstStringValue(mtd));
          }
        }
        System.arraycopy(args, 0, newArgs, 1, args.length);
       
        return getCall().callMethod(env, thisValue, newArgs);
      }
      else
        return env.error(L.l("Call to undefined method {0}::{1}",
                             getName(), toMethod(name, nameLength)));
    } finally {
      env.setCallingClass(oldClass);
    }
  }

  /**
   * calls the function.
   */
  public Value callMethod(Env env,
                          Value thisValue,
                          StringValue methodName,
                          Expr []args)
  {
    QuercusClass oldClass = env.setCallingClass(this);
   
    try {
      AbstractFunction fun = _methodMap.get(methodName.toString());
     
      if (fun != null)
        return fun.callMethod(env, thisValue, args);
      else if (getCall() != null) {
        Expr []newArgs = new Expr[args.length + 1];
        String mtd = methodName.toString();
        if (env.isUnicodeSemantics())
          newArgs[0] = new UnicodeLiteralExpr(mtd);
        else {
          try {
            newArgs[0] = new StringLiteralExpr(new StringBuilderValue(mtd.getBytes(env.getQuercus().getScriptEncoding())));
          } catch (UnsupportedEncodingException e) {
            newArgs[0] = new StringLiteralExpr(new ConstStringValue(mtd));
          }
        }
        System.arraycopy(args, 0, newArgs, 1, args.length);
       
        return getCall().callMethod(env, thisValue, newArgs);
      }
      else
        return env.error(L.l("Call to undefined method {0}::{1}",
                             getName(), methodName));
    } finally {
      env.setCallingClass(oldClass);
    }
  }

  /**
   * calls the function.
   */
  public Value callMethod(Env env,
                          Value thisValue,
                          int hash, char []name, int nameLen,
                          Value []args)
  {
    QuercusClass oldClass = env.setCallingClass(this);
   
    try {
      AbstractFunction fun = _methodMap.get(hash, name, nameLen);

      if (fun != null)
        return fun.callMethod(env, thisValue, args);
      else if (getCall() != null) {
        return getCall().callMethod(env,
                    thisValue,
                    env.createString(name, nameLen),
                    new ArrayValueImpl(args));
      }
      else
        return env.error(L.l("Call to undefined method {0}::{1}()",
                             getName(), toMethod(name, nameLen)));
    } finally {
      env.setCallingClass(oldClass);
    }
  } 

  /**
   * calls the function.
   */
  public Value callMethod(Env env,
                          Value thisValue,
                          StringValue name,

                          Value []args)
  {
    QuercusClass oldClass = env.setCallingClass(this);
   
    try {
      AbstractFunction fun = _methodMap.get(name.toString());

      if (fun != null)
        return fun.callMethod(env, thisValue, args);
      else if (getCall() != null) {
        return getCall().callMethod(env,
                    thisValue,
                    name,
                    new ArrayValueImpl(args));
      }
      else
        return env.error(L.l("Call to undefined method {0}::{1}()",
                             getName(), name));
    } finally {
      env.setCallingClass(oldClass);
    }
  } 

  /**
   * calls the function.
   */
  public Value callMethod(Env env, Value thisValue,
                          int hash, char []name, int nameLen)
  {
    QuercusClass oldClass = env.setCallingClass(this);
   
    try {
      AbstractFunction fun = _methodMap.get(hash, name, nameLen);

      if (fun != null)
        return fun.callMethod(env, thisValue);
      else if (getCall() != null) {
        return getCall().callMethod(env,
                    thisValue,
                    env.createString(name, nameLen),
                    new ArrayValueImpl());
      }
      else
        return env.error(L.l("Call to undefined method {0}::{1}()",
                             getName(), toMethod(name, nameLen)));
    } finally {
      env.setCallingClass(oldClass);
    }
  } 

  /**
   * calls the function.
   */
  public Value callMethod(Env env, Value thisValue,
                          int hash, char []name, int nameLen,
                          Value a1)
  {
    QuercusClass oldClass = env.setCallingClass(this);
   
    try {
      AbstractFunction fun = _methodMap.get(hash, name, nameLen);

      if (fun != null)
        return fun.callMethod(env, thisValue, a1);
      else if (getCall() != null) {
        return getCall().callMethod(env,
                    thisValue,
                    env.createString(name, nameLen),
                    new ArrayValueImpl()
                    .append(a1));
      }
      else
        return env.error(L.l("Call to undefined method {0}::{1}()",
                             getName(), toMethod(name, nameLen)));
    } finally {
      env.setCallingClass(oldClass);
    }
  } 

  /**
   * calls the function.
   */
  public Value callMethod(Env env, Value thisValue,
                          int hash, char []name, int nameLen,
                          Value a1, Value a2)
  {
    QuercusClass oldClass = env.setCallingClass(this);
   
    try {
      AbstractFunction fun = _methodMap.get(hash, name, nameLen);

      if (fun != null)
        return fun.callMethod(env, thisValue, a1, a2);
      else if (getCall() != null) {
        return getCall().callMethod(env,
                    thisValue,
                    env.createString(name, nameLen),
                    new ArrayValueImpl()
                    .append(a1)
                    .append(a2));
      }
      else
        return env.error(L.l("Call to undefined method {0}::{1}()",
                             getName(), toMethod(name, nameLen)));
    } finally {
      env.setCallingClass(oldClass);
    }
  } 

  /**
   * calls the function.
   */
  public Value callMethod(Env env, Value thisValue,
                          int hash, char []name, int nameLen,
                          Value a1, Value a2, Value a3)
  {
    QuercusClass oldClass = env.setCallingClass(this);
   
    try {
      AbstractFunction fun = _methodMap.get(hash, name, nameLen);

      if (fun != null)
        return fun.callMethod(env, thisValue, a1, a2, a3);
      else if (getCall() != null) {
        return getCall().callMethod(env,
                    thisValue,
                    env.createString(name, nameLen),
                    new ArrayValueImpl()
                    .append(a1)
                    .append(a2)
                    .append(a3));
      }
      else
        return env.error(L.l("Call to undefined method {0}::{1}()",
                             getName(), toMethod(name, nameLen)));
    } finally {
      env.setCallingClass(oldClass);
    }
  } 

  /**
   * calls the function.
   */
  public Value callMethod(Env env, Value thisValue,
                          int hash, char []name, int nameLen,
                          Value a1, Value a2, Value a3, Value a4)
  {
    QuercusClass oldClass = env.setCallingClass(this);
   
    try {
      AbstractFunction fun = _methodMap.get(hash, name, nameLen);

      if (fun != null)
        return fun.callMethod(env, thisValue, a1, a2, a3, a4);
      else if (getCall() != null) {
        return getCall().callMethod(env,
                    thisValue,
                    env.createString(name, nameLen),
                    new ArrayValueImpl()
                    .append(a1)
                    .append(a2)
                    .append(a3)
                    .append(a4));
      }
      else
        return env.error(L.l("Call to undefined method {0}::{1}()",
                             getName(), toMethod(name, nameLen)));
    } finally {
      env.setCallingClass(oldClass);
    }
  } 

  /**
   * calls the function.
   */
  public Value callMethod(Env env, Value thisValue,
                          int hash, char []name, int nameLen,
                          Value a1, Value a2, Value a3, Value a4, Value a5)
  {
    QuercusClass oldClass = env.setCallingClass(this);
   
    try {
      AbstractFunction fun = _methodMap.get(hash, name, nameLen);

      if (fun != null)
        return fun.callMethod(env, thisValue, a1, a2, a3, a4, a5);
      else if (getCall() != null) {
        return getCall().callMethod(env,
                    thisValue,
                    env.createString(name, nameLen),
                    new ArrayValueImpl()
                    .append(a1)
                    .append(a2)
                    .append(a3)
                    .append(a4)
                    .append(a5));
      }
      else
        return env.error(L.l("Call to undefined method {0}::{1}()",
                             getName(), toMethod(name, nameLen)));
    } finally {
      env.setCallingClass(oldClass);
    }
  } 

  /**
   * calls the function.
   */
  public Value callMethodRef(Env env, Value thisValue,
                             int hash, char []name, int nameLen,
                             Expr []args)
  {
    QuercusClass oldClass = env.setCallingClass(this);
   
    try {
      AbstractFunction fun = getFunction(hash, name, nameLen);
     
      return fun.callMethodRef(env, thisValue, args);
    } finally {
      env.setCallingClass(oldClass);
    }
  } 

  /**
   * calls the function.
   */
  public Value callMethodRef(Env env,
                             Value thisValue,
                             StringValue methodName,
                             Expr []args)
  {
    QuercusClass oldClass = env.setCallingClass(this);
   
    try {
      AbstractFunction fun = _methodMap.get(methodName.toString());
     
      if (fun != null)
        return fun.callMethodRef(env, thisValue, args);
      else if (getCall() != null) {
        Expr []newArgs = new Expr[args.length + 1];
        if (env.isUnicodeSemantics())
          newArgs[0] = new UnicodeLiteralExpr(methodName);
        else
          newArgs[0] = new StringLiteralExpr(methodName);

        System.arraycopy(args, 0, newArgs, 1, args.length);
       
        return getCall().callMethodRef(env, thisValue, newArgs);
      }
      else
        return env.error(L.l("Call to undefined method {0}::{1}",
                             getName(), methodName));
    } finally {
      env.setCallingClass(oldClass);
    }
  }

  /**
   * calls the function.
   */
  public Value callMethodRef(Env env, Value thisValue,
                             int hash, char []name, int nameLen,
                             Value []args)
  {
    QuercusClass oldClass = env.setCallingClass(this);
   
    try {
      AbstractFunction fun = _methodMap.get(hash, name, nameLen);

      if (fun != null)
        return fun.callMethodRef(env, thisValue, args);
      else if (getCall() != null) {
        return getCall().callMethodRef(env,
                                       thisValue,
                                       env.createString(name, nameLen),
                                       new ArrayValueImpl(args));
      }
      else
        return env.error(L.l("Call to undefined method {0}::{1}()",
                             getName(), toMethod(name, nameLen)));
    } finally {
      env.setCallingClass(oldClass);
    }
  } 

  /**
   * calls the function.
   */
  public Value callMethodRef(Env env, Value thisValue,
                             StringValue name,
                             Value []args)
  {
    QuercusClass oldClass = env.setCallingClass(this);
   
    try {
      AbstractFunction fun = _methodMap.get(name.toString());

      if (fun != null)
        return fun.callMethodRef(env, thisValue, args);
      else if (getCall() != null) {
        return getCall().callMethodRef(env,
                                       thisValue,
                                       name,
                                       new ArrayValueImpl(args));
      }
      else
        return env.error(L.l("Call to undefined method {0}::{1}()",
                             getName(), name));
    } finally {
      env.setCallingClass(oldClass);
    }
  } 

  /**
   * calls the function.
   */
  public Value callMethodRef(Env env, Value thisValue,
                             int hash, char []name, int nameLen)
  {
    QuercusClass oldClass = env.setCallingClass(this);
   
    try {
      AbstractFunction fun = _methodMap.get(hash, name, nameLen);

      if (fun != null)
        return fun.callMethodRef(env, thisValue);
      else if (getCall() != null) {
        return getCall().callMethodRef(env,
                                       thisValue,
                                       env.createString(name, nameLen),
                                       new ArrayValueImpl());
      }
      else
        return env.error(L.l("Call to undefined method {0}::{1}()",
                             getName(), toMethod(name, nameLen)));
    } finally {
      env.setCallingClass(oldClass);
    }
  } 

  /**
   * calls the function.
   */
  public Value callMethodRef(Env env, Value thisValue,
                             int hash, char []name, int nameLen,
                             Value a1)
  {
    QuercusClass oldClass = env.setCallingClass(this);
   
    try {
      AbstractFunction fun = _methodMap.get(hash, name, nameLen);

      if (fun != null)
        return fun.callMethodRef(env, thisValue, a1);
      else if (getCall() != null) {
        return getCall().callMethodRef(env,
                                       thisValue,
                                       env.createString(name, nameLen),
                                       new ArrayValueImpl()
                                       .append(a1));
      }
      else
        return env.error(L.l("Call to undefined method {0}::{1}()",
                             getName(), toMethod(name, nameLen)));
    } finally {
      env.setCallingClass(oldClass);
    }
  } 

  /**
   * calls the function.
   */
  public Value callMethodRef(Env env, Value thisValue,
                             int hash, char []name, int nameLen,
                             Value a1, Value a2)
  {
    QuercusClass oldClass = env.setCallingClass(this);
   
    try {
      AbstractFunction fun = _methodMap.get(hash, name, nameLen);

      if (fun != null)
        return fun.callMethodRef(env, thisValue, a1, a2);
      else if (getCall() != null) {
        return getCall().callMethodRef(env,
                                       thisValue,
                                       env.createString(name, nameLen),
                                       new ArrayValueImpl()
                                       .append(a1)
                                       .append(a2));
      }
      else
        return env.error(L.l("Call to undefined method {0}::{1}()",
                             getName(), toMethod(name, nameLen)));
    } finally {
      env.setCallingClass(oldClass);
    }
  } 

  /**
   * calls the function.
   */
  public Value callMethodRef(Env env, Value thisValue,
                             int hash, char []name, int nameLen,
                             Value a1, Value a2, Value a3)
  {
    QuercusClass oldClass = env.setCallingClass(this);
   
    try {
      AbstractFunction fun = _methodMap.get(hash, name, nameLen);

      if (fun != null)
        return fun.callMethodRef(env, thisValue, a1, a2, a3);
      else if (getCall() != null) {
        return getCall().callMethodRef(env,
                                       thisValue,
                                       env.createString(name, nameLen),
                                       new ArrayValueImpl()
                                       .append(a1)
                                       .append(a2)
                                       .append(a3));
      }
      else
        return env.error(L.l("Call to undefined method {0}::{1}()",
                             getName(), toMethod(name, nameLen)));
    } finally {
      env.setCallingClass(oldClass);
    }
  } 

  /**
   * calls the function.
   */
  public Value callMethodRef(Env env, Value thisValue,
                             int hash, char []name, int nameLen,
                             Value a1, Value a2, Value a3, Value a4)
  {
    QuercusClass oldClass = env.setCallingClass(this);
   
    try {
      AbstractFunction fun = _methodMap.get(hash, name, nameLen);

      if (fun != null)
        return fun.callMethodRef(env, thisValue, a1, a2, a3, a4);
      else if (getCall() != null) {
        return getCall().callMethodRef(env,
                                       thisValue,
                                       env.createString(name, nameLen),
                                       new ArrayValueImpl()
                                       .append(a1)
                                       .append(a2)
                                       .append(a3)
                                       .append(a4));
      }
      else
        return env.error(L.l("Call to undefined method {0}::{1}()",
                             getName(), toMethod(name, nameLen)));
    } finally {
      env.setCallingClass(oldClass);
    }
  } 

  /**
   * calls the function.
   */
  public Value callMethodRef(Env env, Value thisValue,
                             int hash, char []name, int nameLen,
                             Value a1, Value a2, Value a3, Value a4, Value a5)
  {
    QuercusClass oldClass = env.setCallingClass(this);
   
    try {
      AbstractFunction fun = _methodMap.get(hash, name, nameLen);

      if (fun != null)
        return fun.callMethodRef(env, thisValue, a1, a2, a3, a4, a5);
      else if (getCall() != null) {
        return getCall().callMethodRef(env,
                                       thisValue,
                                       env.createString(name, nameLen),
                                       new ArrayValueImpl()
                                       .append(a1)
                                       .append(a2)
                                       .append(a3)
                                       .append(a4)
                                       .append(a5));
      }
      else
        return env.error(L.l("Call to undefined method {0}::{1}()",
                             getName(), toMethod(name, nameLen)));
    } finally {
      env.setCallingClass(oldClass);
    }
  } 

  private String toMethod(char []key, int keyLength)
  {
    return new String(key, 0, keyLength);
  }

  /**
   * Finds a function.
   */
  public AbstractFunction findStaticFunctionLowerCase(String name)
  {
    return null;
  }

  /**
   * Finds the matching function.
   */
  public final AbstractFunction getStaticFunction(String name)
  {
    AbstractFunction fun = findStaticFunction(name);
    /*
    if (fun != null)
      return fun;

    fun = findStaticFunctionLowerCase(name.toLowerCase());
    */
   
    if (fun != null)
      return fun;
    else {
      throw new QuercusRuntimeException(L.l("{0}::{1} is an unknown method",
                                        getName(), name));
    }
  }

  /**
   * Finds the matching constant
   */
  public final Value getConstant(Env env, String name)
  {
    Expr expr = _constMap.get(name);

    if (expr != null)
      return expr.eval(env);

    throw new QuercusRuntimeException(L.l("{0}::{1} is an unknown constant",
                                        getName(), name));
  }
 
  /**
   * Returns true if the constant exists.
   */
  public final boolean hasConstant(String name)
  {
    return _constMap.get(String.valueOf(name)) != null;
  }
 
  /*
   * Returns the constants defined in this class.
   */
  public final HashMap<String, Expr> getConstantMap()
  {
    return _constMap;
  }

  public int hashCode()
  {
    return _className.hashCode();
  }

  public boolean equals(Object o)
  {
    if (this == o)
      return true;
    else if (! (o instanceof QuercusClass))
      return false;

    QuercusClass qClass = (QuercusClass) o;

    if (_classDef != qClass._classDef)
      return false;
   
    if (_javaClassDef != qClass._javaClassDef)
      return false;

    if (_parent == qClass._parent)
      return true;

    else
      return (_parent != null && _parent.equals(qClass._parent));
  }

  public String toString()
  {
    return getClass().getSimpleName() + "[" + getName() + "]";
  }
 
  static class StaticField
  {
    String _name;
    Expr _expr;
   
    StaticField(String name, Expr expr)
    {
      _name = name;
      _expr = expr;
    }
   
    String getName()
    {
      return _name;
    }
  }
}
TOP

Related Classes of com.caucho.quercus.env.QuercusClass$StaticField

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.