alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (FunctionCall.java)

This example Java source code file (FunctionCall.java) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

class, errormsg, expression, hashtable, javatype, namespace_format_java, objecttype, override, qname, reflection, string, stringbuffer, type, typecheckerror, util, vector

The FunctionCall.java Java example source code

/*
 * reserved comment block
 * DO NOT REMOVE OR ALTER!
 */
/*
 * Copyright 2001-2004 The Apache Software Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/*
 * $Id: FunctionCall.java,v 1.2.4.1 2005/09/12 10:31:32 pvedula Exp $
 */

package com.sun.org.apache.xalan.internal.xsltc.compiler;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;

import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
import com.sun.org.apache.bcel.internal.generic.IFEQ;
import com.sun.org.apache.bcel.internal.generic.INVOKEINTERFACE;
import com.sun.org.apache.bcel.internal.generic.INVOKESPECIAL;
import com.sun.org.apache.bcel.internal.generic.INVOKESTATIC;
import com.sun.org.apache.bcel.internal.generic.INVOKEVIRTUAL;
import com.sun.org.apache.bcel.internal.generic.InstructionConstants;
import com.sun.org.apache.bcel.internal.generic.InstructionList;
import com.sun.org.apache.bcel.internal.generic.InvokeInstruction;
import com.sun.org.apache.bcel.internal.generic.LocalVariableGen;
import com.sun.org.apache.bcel.internal.generic.NEW;
import com.sun.org.apache.bcel.internal.generic.PUSH;
import com.sun.org.apache.xalan.internal.utils.FeatureManager;
import com.sun.org.apache.xalan.internal.xsltc.compiler.util.BooleanType;
import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg;
import com.sun.org.apache.xalan.internal.xsltc.compiler.util.IntType;
import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodType;
import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MultiHashtable;
import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ObjectType;
import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ReferenceType;
import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError;
import com.sun.org.apache.xalan.internal.utils.ObjectFactory;
import java.util.Objects;

/**
 * @author Jacek Ambroziak
 * @author Santiago Pericas-Geertsen
 * @author Morten Jorgensen
 * @author Erwin Bolwidt <ejb@klomp.org>
 * @author Todd Miller
 */
class FunctionCall extends Expression {

    // Name of this function call
    private QName  _fname;
    // Arguments to this function call (might not be any)
    private final Vector _arguments;
    // Empty argument list, used for certain functions
    private final static Vector EMPTY_ARG_LIST = new Vector(0);

    // Valid namespaces for Java function-call extension
    protected final static String EXT_XSLTC =
        TRANSLET_URI;

    protected final static String JAVA_EXT_XSLTC =
        EXT_XSLTC + "/java";

    protected final static String EXT_XALAN =
        "http://xml.apache.org/xalan";

    protected final static String JAVA_EXT_XALAN =
        "http://xml.apache.org/xalan/java";

    protected final static String JAVA_EXT_XALAN_OLD =
        "http://xml.apache.org/xslt/java";

    protected final static String EXSLT_COMMON =
        "http://exslt.org/common";

    protected final static String EXSLT_MATH =
        "http://exslt.org/math";

    protected final static String EXSLT_SETS =
        "http://exslt.org/sets";

    protected final static String EXSLT_DATETIME =
        "http://exslt.org/dates-and-times";

    protected final static String EXSLT_STRINGS =
        "http://exslt.org/strings";

    // Namespace format constants
    protected final static int NAMESPACE_FORMAT_JAVA = 0;
    protected final static int NAMESPACE_FORMAT_CLASS = 1;
    protected final static int NAMESPACE_FORMAT_PACKAGE = 2;
    protected final static int NAMESPACE_FORMAT_CLASS_OR_PACKAGE = 3;

    // Namespace format
    private int _namespace_format = NAMESPACE_FORMAT_JAVA;

    /**
     * Stores reference to object for non-static Java calls
     */
    Expression _thisArgument = null;

    // External Java function's class/method/signature
    private String      _className;
    private Class       _clazz;
    private Method      _chosenMethod;
    private Constructor _chosenConstructor;
    private MethodType  _chosenMethodType;

    // Encapsulates all unsupported external function calls
    private boolean    unresolvedExternal;

    // If FunctionCall is a external java constructor
    private boolean     _isExtConstructor = false;

    // If the java method is static
    private boolean       _isStatic = false;

    // Legal conversions between internal and Java types.
    private static final MultiHashtable _internal2Java = new MultiHashtable();

    // Legal conversions between Java and internal types.
    private static final Hashtable _java2Internal = new Hashtable();

    // The mappings between EXSLT extension namespaces and implementation classes
    private static final Hashtable _extensionNamespaceTable = new Hashtable();

    // Extension functions that are implemented in BasisLibrary
    private static final Hashtable _extensionFunctionTable = new Hashtable();
    /**
     * inner class to used in internal2Java mappings, contains
     * the Java type and the distance between the internal type and
     * the Java type.
     */
    static class JavaType {
        public Class  type;
        public int distance;

        public JavaType(Class type, int distance){
            this.type = type;
            this.distance = distance;
        }

        @Override
        public int hashCode() {
            return Objects.hashCode(this.type);
        }

        @Override
        public boolean equals(Object query){
            return query != null && query.equals(type);
        }
    }

    /**
     * Defines 2 conversion tables:
     * 1. From internal types to Java types and
     * 2. From Java types to internal types.
     * These two tables are used when calling external (Java) functions.
     */
    static {
        try {
            final Class nodeClass     = Class.forName("org.w3c.dom.Node");
            final Class nodeListClass = Class.forName("org.w3c.dom.NodeList");

            // -- Internal to Java --------------------------------------------

            // Type.Boolean -> { boolean(0), Boolean(1), Object(2) }
            _internal2Java.put(Type.Boolean, new JavaType(Boolean.TYPE, 0));
            _internal2Java.put(Type.Boolean, new JavaType(Boolean.class, 1));
            _internal2Java.put(Type.Boolean, new JavaType(Object.class, 2));

            // Type.Real -> { double(0), Double(1), float(2), long(3), int(4),
            //                short(5), byte(6), char(7), Object(8) }
            _internal2Java.put(Type.Real, new JavaType(Double.TYPE, 0));
            _internal2Java.put(Type.Real, new JavaType(Double.class, 1));
            _internal2Java.put(Type.Real, new JavaType(Float.TYPE, 2));
            _internal2Java.put(Type.Real, new JavaType(Long.TYPE, 3));
            _internal2Java.put(Type.Real, new JavaType(Integer.TYPE, 4));
            _internal2Java.put(Type.Real, new JavaType(Short.TYPE, 5));
            _internal2Java.put(Type.Real, new JavaType(Byte.TYPE, 6));
            _internal2Java.put(Type.Real, new JavaType(Character.TYPE, 7));
            _internal2Java.put(Type.Real, new JavaType(Object.class, 8));

            // Type.Int must be the same as Type.Real
            _internal2Java.put(Type.Int, new JavaType(Double.TYPE, 0));
            _internal2Java.put(Type.Int, new JavaType(Double.class, 1));
            _internal2Java.put(Type.Int, new JavaType(Float.TYPE, 2));
            _internal2Java.put(Type.Int, new JavaType(Long.TYPE, 3));
            _internal2Java.put(Type.Int, new JavaType(Integer.TYPE, 4));
            _internal2Java.put(Type.Int, new JavaType(Short.TYPE, 5));
            _internal2Java.put(Type.Int, new JavaType(Byte.TYPE, 6));
            _internal2Java.put(Type.Int, new JavaType(Character.TYPE, 7));
            _internal2Java.put(Type.Int, new JavaType(Object.class, 8));

            // Type.String -> { String(0), Object(1) }
            _internal2Java.put(Type.String, new JavaType(String.class, 0));
            _internal2Java.put(Type.String, new JavaType(Object.class, 1));

            // Type.NodeSet -> { NodeList(0), Node(1), Object(2), String(3) }
            _internal2Java.put(Type.NodeSet, new JavaType(nodeListClass, 0));
            _internal2Java.put(Type.NodeSet, new JavaType(nodeClass, 1));
            _internal2Java.put(Type.NodeSet, new JavaType(Object.class, 2));
            _internal2Java.put(Type.NodeSet, new JavaType(String.class, 3));

            // Type.Node -> { Node(0), NodeList(1), Object(2), String(3) }
            _internal2Java.put(Type.Node, new JavaType(nodeListClass, 0));
            _internal2Java.put(Type.Node, new JavaType(nodeClass, 1));
            _internal2Java.put(Type.Node, new JavaType(Object.class, 2));
            _internal2Java.put(Type.Node, new JavaType(String.class, 3));

            // Type.ResultTree -> { NodeList(0), Node(1), Object(2), String(3) }
            _internal2Java.put(Type.ResultTree, new JavaType(nodeListClass, 0));
            _internal2Java.put(Type.ResultTree, new JavaType(nodeClass, 1));
            _internal2Java.put(Type.ResultTree, new JavaType(Object.class, 2));
            _internal2Java.put(Type.ResultTree, new JavaType(String.class, 3));

            _internal2Java.put(Type.Reference, new JavaType(Object.class, 0));

            // Possible conversions between Java and internal types
            _java2Internal.put(Boolean.TYPE, Type.Boolean);
            _java2Internal.put(Void.TYPE, Type.Void);
            _java2Internal.put(Character.TYPE, Type.Real);
            _java2Internal.put(Byte.TYPE, Type.Real);
            _java2Internal.put(Short.TYPE, Type.Real);
            _java2Internal.put(Integer.TYPE, Type.Real);
            _java2Internal.put(Long.TYPE, Type.Real);
            _java2Internal.put(Float.TYPE, Type.Real);
            _java2Internal.put(Double.TYPE, Type.Real);

            _java2Internal.put(String.class, Type.String);

            _java2Internal.put(Object.class, Type.Reference);

            // Conversions from org.w3c.dom.Node/NodeList to internal NodeSet
            _java2Internal.put(nodeListClass, Type.NodeSet);
            _java2Internal.put(nodeClass, Type.NodeSet);

            // Initialize the extension namespace table
            _extensionNamespaceTable.put(EXT_XALAN, "com.sun.org.apache.xalan.internal.lib.Extensions");
            _extensionNamespaceTable.put(EXSLT_COMMON, "com.sun.org.apache.xalan.internal.lib.ExsltCommon");
            _extensionNamespaceTable.put(EXSLT_MATH, "com.sun.org.apache.xalan.internal.lib.ExsltMath");
            _extensionNamespaceTable.put(EXSLT_SETS, "com.sun.org.apache.xalan.internal.lib.ExsltSets");
            _extensionNamespaceTable.put(EXSLT_DATETIME, "com.sun.org.apache.xalan.internal.lib.ExsltDatetime");
            _extensionNamespaceTable.put(EXSLT_STRINGS, "com.sun.org.apache.xalan.internal.lib.ExsltStrings");

            // Initialize the extension function table
            _extensionFunctionTable.put(EXSLT_COMMON + ":nodeSet", "nodeset");
            _extensionFunctionTable.put(EXSLT_COMMON + ":objectType", "objectType");
            _extensionFunctionTable.put(EXT_XALAN + ":nodeset", "nodeset");
        }
        catch (ClassNotFoundException e) {
            System.err.println(e);
        }
    }

    public FunctionCall(QName fname, Vector arguments) {
        _fname = fname;
        _arguments = arguments;
        _type = null;
    }

    public FunctionCall(QName fname) {
        this(fname, EMPTY_ARG_LIST);
    }

    public String getName() {
        return(_fname.toString());
    }

    @Override
    public void setParser(Parser parser) {
        super.setParser(parser);
        if (_arguments != null) {
            final int n = _arguments.size();
            for (int i = 0; i < n; i++) {
                final Expression exp = (Expression)_arguments.elementAt(i);
                exp.setParser(parser);
                exp.setParent(this);
            }
        }
    }

    public String getClassNameFromUri(String uri)
    {
        String className = (String)_extensionNamespaceTable.get(uri);

        if (className != null)
            return className;
        else {
            if (uri.startsWith(JAVA_EXT_XSLTC)) {
                int length = JAVA_EXT_XSLTC.length() + 1;
                return (uri.length() > length) ? uri.substring(length) : EMPTYSTRING;
            }
            else if (uri.startsWith(JAVA_EXT_XALAN)) {
                int length = JAVA_EXT_XALAN.length() + 1;
                return (uri.length() > length) ? uri.substring(length) : EMPTYSTRING;
            }
            else if (uri.startsWith(JAVA_EXT_XALAN_OLD)) {
                int length = JAVA_EXT_XALAN_OLD.length() + 1;
                return (uri.length() > length) ? uri.substring(length) : EMPTYSTRING;
            }
            else {
                int index = uri.lastIndexOf('/');
                return (index > 0) ? uri.substring(index+1) : uri;
            }
        }
    }

    /**
     * Type check a function call. Since different type conversions apply,
     * type checking is different for standard and external (Java) functions.
     */
    @Override
    public Type typeCheck(SymbolTable stable)
        throws TypeCheckError
    {
        if (_type != null) return _type;

        final String namespace = _fname.getNamespace();
        String local = _fname.getLocalPart();

        if (isExtension()) {
            _fname = new QName(null, null, local);
            return typeCheckStandard(stable);
        }
        else if (isStandard()) {
            return typeCheckStandard(stable);
        }
        // Handle extension functions (they all have a namespace)
        else {
            try {
                _className = getClassNameFromUri(namespace);

                final int pos = local.lastIndexOf('.');
                if (pos > 0) {
                    _isStatic = true;
                    if (_className != null && _className.length() > 0) {
                        _namespace_format = NAMESPACE_FORMAT_PACKAGE;
                        _className = _className + "." + local.substring(0, pos);
                    }
                    else {
                        _namespace_format = NAMESPACE_FORMAT_JAVA;
                        _className = local.substring(0, pos);
                    }

                    _fname = new QName(namespace, null, local.substring(pos + 1));
                }
                else {
                    if (_className != null && _className.length() > 0) {
                        try {
                            _clazz = ObjectFactory.findProviderClass(_className, true);
                            _namespace_format = NAMESPACE_FORMAT_CLASS;
                        }
                        catch (ClassNotFoundException e) {
                            _namespace_format = NAMESPACE_FORMAT_PACKAGE;
                        }
                    }
                    else
                        _namespace_format = NAMESPACE_FORMAT_JAVA;

                    if (local.indexOf('-') > 0) {
                        local = replaceDash(local);
                    }

                    String extFunction = (String)_extensionFunctionTable.get(namespace + ":" + local);
                    if (extFunction != null) {
                        _fname = new QName(null, null, extFunction);
                        return typeCheckStandard(stable);
                    }
                    else
                        _fname = new QName(namespace, null, local);
                }

                return typeCheckExternal(stable);
            }
            catch (TypeCheckError e) {
                ErrorMsg errorMsg = e.getErrorMsg();
                if (errorMsg == null) {
                    final String name = _fname.getLocalPart();
                    errorMsg = new ErrorMsg(ErrorMsg.METHOD_NOT_FOUND_ERR, name);
                }
                getParser().reportError(ERROR, errorMsg);
                return _type = Type.Void;
            }
          }
    }

    /**
     * Type check a call to a standard function. Insert CastExprs when needed.
     * If as a result of the insertion of a CastExpr a type check error is
     * thrown, then catch it and re-throw it with a new "this".
     */
    public Type typeCheckStandard(SymbolTable stable) throws TypeCheckError {
        _fname.clearNamespace();        // HACK!!!

        final int n = _arguments.size();
        final Vector argsType = typeCheckArgs(stable);
        final MethodType args = new MethodType(Type.Void, argsType);
        final MethodType ptype =
            lookupPrimop(stable, _fname.getLocalPart(), args);

        if (ptype != null) {
            for (int i = 0; i < n; i++) {
                final Type argType = (Type) ptype.argsType().elementAt(i);
                final Expression exp = (Expression)_arguments.elementAt(i);
                if (!argType.identicalTo(exp.getType())) {
                    try {
                        _arguments.setElementAt(new CastExpr(exp, argType), i);
                    }
                    catch (TypeCheckError e) {
                        throw new TypeCheckError(this); // invalid conversion
                    }
                }
            }
            _chosenMethodType = ptype;
            return _type = ptype.resultType();
        }
        throw new TypeCheckError(this);
    }



    public Type typeCheckConstructor(SymbolTable stable) throws TypeCheckError{
        final Vector constructors = findConstructors();
        if (constructors == null) {
            // Constructor not found in this class
            throw new TypeCheckError(ErrorMsg.CONSTRUCTOR_NOT_FOUND,
                _className);

        }

        final int nConstructors = constructors.size();
        final int nArgs = _arguments.size();
        final Vector argsType = typeCheckArgs(stable);

        // Try all constructors
        int bestConstrDistance = Integer.MAX_VALUE;
        _type = null;                   // reset
        for (int j, i = 0; i < nConstructors; i++) {
            // Check if all parameters to this constructor can be converted
            final Constructor constructor =
                (Constructor)constructors.elementAt(i);
            final Class[] paramTypes = constructor.getParameterTypes();

            Class extType = null;
            int currConstrDistance = 0;
            for (j = 0; j < nArgs; j++) {
                // Convert from internal (translet) type to external (Java) type
                extType = paramTypes[j];
                final Type intType = (Type)argsType.elementAt(j);
                Object match = _internal2Java.maps(intType, extType);
                if (match != null) {
                    currConstrDistance += ((JavaType)match).distance;
                }
                else if (intType instanceof ObjectType) {
                    ObjectType objectType = (ObjectType)intType;
                    if (objectType.getJavaClass() == extType)
                        continue;
                    else if (extType.isAssignableFrom(objectType.getJavaClass()))
                        currConstrDistance += 1;
                    else {
                        currConstrDistance = Integer.MAX_VALUE;
                        break;
                    }
                }
                else {
                    // no mapping available
                    currConstrDistance = Integer.MAX_VALUE;
                    break;
                }
            }

            if (j == nArgs && currConstrDistance < bestConstrDistance ) {
                _chosenConstructor = constructor;
                _isExtConstructor = true;
                bestConstrDistance = currConstrDistance;

                _type = (_clazz != null) ? Type.newObjectType(_clazz)
                    : Type.newObjectType(_className);
            }
        }

        if (_type != null) {
            return _type;
        }

        throw new TypeCheckError(ErrorMsg.ARGUMENT_CONVERSION_ERR, getMethodSignature(argsType));
    }


    /**
     * Type check a call to an external (Java) method.
     * The method must be static an public, and a legal type conversion
     * must exist for all its arguments and its return type.
     * Every method of name <code>_fname is inspected
     * as a possible candidate.
     */
    public Type typeCheckExternal(SymbolTable stable) throws TypeCheckError {
        int nArgs = _arguments.size();
        final String name = _fname.getLocalPart();

        // check if function is a contructor 'new'
        if (_fname.getLocalPart().equals("new")) {
            return typeCheckConstructor(stable);
        }
        // check if we are calling an instance method
        else {
            boolean hasThisArgument = false;

            if (nArgs == 0)
                _isStatic = true;

            if (!_isStatic) {
                if (_namespace_format == NAMESPACE_FORMAT_JAVA
                    || _namespace_format == NAMESPACE_FORMAT_PACKAGE)
                    hasThisArgument = true;

                Expression firstArg = (Expression)_arguments.elementAt(0);
                Type firstArgType = (Type)firstArg.typeCheck(stable);

                if (_namespace_format == NAMESPACE_FORMAT_CLASS
                    && firstArgType instanceof ObjectType
                    && _clazz != null
                    && _clazz.isAssignableFrom(((ObjectType)firstArgType).getJavaClass()))
                    hasThisArgument = true;

                if (hasThisArgument) {
                    _thisArgument = (Expression) _arguments.elementAt(0);
                    _arguments.remove(0); nArgs--;
                    if (firstArgType instanceof ObjectType) {
                        _className = ((ObjectType) firstArgType).getJavaClassName();
                    }
                    else
                        throw new TypeCheckError(ErrorMsg.NO_JAVA_FUNCT_THIS_REF, name);
                }
            }
            else if (_className.length() == 0) {
                /*
                 * Warn user if external function could not be resolved.
                 * Warning will _NOT_ be issued is the call is properly
                 * wrapped in an <xsl:if> or  element. For details
                 * see If.parserContents() and When.parserContents()
                 */
                final Parser parser = getParser();
                if (parser != null) {
                    reportWarning(this, parser, ErrorMsg.FUNCTION_RESOLVE_ERR,
                                  _fname.toString());
                }
                unresolvedExternal = true;
                return _type = Type.Int;        // use "Int" as "unknown"
            }
        }

        final Vector methods = findMethods();

        if (methods == null) {
            // Method not found in this class
            throw new TypeCheckError(ErrorMsg.METHOD_NOT_FOUND_ERR, _className + "." + name);
        }

        Class extType = null;
        final int nMethods = methods.size();
        final Vector argsType = typeCheckArgs(stable);

        // Try all methods to identify the best fit
        int bestMethodDistance  = Integer.MAX_VALUE;
        _type = null;                       // reset internal type
        for (int j, i = 0; i < nMethods; i++) {
            // Check if all paramteters to this method can be converted
            final Method method = (Method)methods.elementAt(i);
            final Class[] paramTypes = method.getParameterTypes();

            int currMethodDistance = 0;
            for (j = 0; j < nArgs; j++) {
                // Convert from internal (translet) type to external (Java) type
                extType = paramTypes[j];
                final Type intType = (Type)argsType.elementAt(j);
                Object match = _internal2Java.maps(intType, extType);
                if (match != null) {
                    currMethodDistance += ((JavaType)match).distance;
                }
                else {
                    // no mapping available
                    //
                    // Allow a Reference type to match any external (Java) type at
                    // the moment. The real type checking is performed at runtime.
                    if (intType instanceof ReferenceType) {
                       currMethodDistance += 1;
                    }
                    else if (intType instanceof ObjectType) {
                        ObjectType object = (ObjectType)intType;
                        if (extType.getName().equals(object.getJavaClassName()))
                            currMethodDistance += 0;
                        else if (extType.isAssignableFrom(object.getJavaClass()))
                            currMethodDistance += 1;
                        else {
                            currMethodDistance = Integer.MAX_VALUE;
                            break;
                        }
                    }
                    else {
                        currMethodDistance = Integer.MAX_VALUE;
                        break;
                    }
                }
            }

            if (j == nArgs) {
                  // Check if the return type can be converted
                  extType = method.getReturnType();

                  _type = (Type) _java2Internal.get(extType);
                  if (_type == null) {
                      _type = Type.newObjectType(extType);
                  }

                  // Use this method if all parameters & return type match
                  if (_type != null && currMethodDistance < bestMethodDistance) {
                      _chosenMethod = method;
                      bestMethodDistance = currMethodDistance;
                  }
            }
        }

        // It is an error if the chosen method is an instance menthod but we don't
        // have a this argument.
        if (_chosenMethod != null && _thisArgument == null &&
            !Modifier.isStatic(_chosenMethod.getModifiers())) {
            throw new TypeCheckError(ErrorMsg.NO_JAVA_FUNCT_THIS_REF, getMethodSignature(argsType));
        }

        if (_type != null) {
            if (_type == Type.NodeSet) {
                getXSLTC().setMultiDocument(true);
            }
            return _type;
        }

        throw new TypeCheckError(ErrorMsg.ARGUMENT_CONVERSION_ERR, getMethodSignature(argsType));
    }

    /**
     * Type check the actual arguments of this function call.
     */
    public Vector typeCheckArgs(SymbolTable stable) throws TypeCheckError {
        final Vector result = new Vector();
        final Enumeration e = _arguments.elements();
        while (e.hasMoreElements()) {
            final Expression exp = (Expression)e.nextElement();
            result.addElement(exp.typeCheck(stable));
        }
        return result;
    }

    protected final Expression argument(int i) {
        return (Expression)_arguments.elementAt(i);
    }

    protected final Expression argument() {
        return argument(0);
    }

    protected final int argumentCount() {
        return _arguments.size();
    }

    protected final void setArgument(int i, Expression exp) {
        _arguments.setElementAt(exp, i);
    }

    /**
     * Compile the function call and treat as an expression
     * Update true/false-lists.
     */
    @Override
    public void translateDesynthesized(ClassGenerator classGen,
                                       MethodGenerator methodGen)
    {
        Type type = Type.Boolean;
        if (_chosenMethodType != null)
            type = _chosenMethodType.resultType();

        final InstructionList il = methodGen.getInstructionList();
        translate(classGen, methodGen);

        if ((type instanceof BooleanType) || (type instanceof IntType)) {
            _falseList.add(il.append(new IFEQ(null)));
        }
    }


    /**
     * Translate a function call. The compiled code will leave the function's
     * return value on the JVM's stack.
     */
    @Override
    public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
        final int n = argumentCount();
        final ConstantPoolGen cpg = classGen.getConstantPool();
        final InstructionList il = methodGen.getInstructionList();
        final boolean isSecureProcessing = classGen.getParser().getXSLTC().isSecureProcessing();
        final boolean isExtensionFunctionEnabled = classGen.getParser().getXSLTC()
                .getFeature(FeatureManager.Feature.ORACLE_ENABLE_EXTENSION_FUNCTION);
        int index;

        // Translate calls to methods in the BasisLibrary
        if (isStandard() || isExtension()) {
            for (int i = 0; i < n; i++) {
                final Expression exp = argument(i);
                exp.translate(classGen, methodGen);
                exp.startIterator(classGen, methodGen);
            }

            // append "F" to the function's name
            final String name = _fname.toString().replace('-', '_') + "F";
            String args = Constants.EMPTYSTRING;

            // Special precautions for some method calls
            if (name.equals("sumF")) {
                args = DOM_INTF_SIG;
                il.append(methodGen.loadDOM());
            }
            else if (name.equals("normalize_spaceF")) {
                if (_chosenMethodType.toSignature(args).
                    equals("()Ljava/lang/String;")) {
                    args = "I"+DOM_INTF_SIG;
                    il.append(methodGen.loadContextNode());
                    il.append(methodGen.loadDOM());
                }
            }

            // Invoke the method in the basis library
            index = cpg.addMethodref(BASIS_LIBRARY_CLASS, name,
                                     _chosenMethodType.toSignature(args));
            il.append(new INVOKESTATIC(index));
        }
        // Add call to BasisLibrary.unresolved_externalF() to generate
        // run-time error message for unsupported external functions
        else if (unresolvedExternal) {
            index = cpg.addMethodref(BASIS_LIBRARY_CLASS,
                                     "unresolved_externalF",
                                     "(Ljava/lang/String;)V");
            il.append(new PUSH(cpg, _fname.toString()));
            il.append(new INVOKESTATIC(index));
        }
        else if (_isExtConstructor) {
            if (isSecureProcessing && !isExtensionFunctionEnabled)
                translateUnallowedExtension(cpg, il);

            final String clazz =
                _chosenConstructor.getDeclaringClass().getName();
            Class[] paramTypes = _chosenConstructor.getParameterTypes();
            LocalVariableGen[] paramTemp = new LocalVariableGen[n];

            // Backwards branches are prohibited if an uninitialized object is
            // on the stack by section 4.9.4 of the JVM Specification, 2nd Ed.
            // We don't know whether this code might contain backwards branches
            // so we mustn't create the new object until after we've created
            // the suspect arguments to its constructor.  Instead we calculate
            // the values of the arguments to the constructor first, store them
            // in temporary variables, create the object and reload the
            // arguments from the temporaries to avoid the problem.

            for (int i = 0; i < n; i++) {
                final Expression exp = argument(i);
                Type expType = exp.getType();
                exp.translate(classGen, methodGen);
                // Convert the argument to its Java type
                exp.startIterator(classGen, methodGen);
                expType.translateTo(classGen, methodGen, paramTypes[i]);
                paramTemp[i] =
                    methodGen.addLocalVariable("function_call_tmp"+i,
                                               expType.toJCType(),
                                               null, null);
                paramTemp[i].setStart(
                        il.append(expType.STORE(paramTemp[i].getIndex())));

            }

            il.append(new NEW(cpg.addClass(_className)));
            il.append(InstructionConstants.DUP);

            for (int i = 0; i < n; i++) {
                final Expression arg = argument(i);
                paramTemp[i].setEnd(
                        il.append(arg.getType().LOAD(paramTemp[i].getIndex())));
            }

            final StringBuffer buffer = new StringBuffer();
            buffer.append('(');
            for (int i = 0; i < paramTypes.length; i++) {
                buffer.append(getSignature(paramTypes[i]));
            }
            buffer.append(')');
            buffer.append("V");

            index = cpg.addMethodref(clazz,
                                     "<init>",
                                     buffer.toString());
            il.append(new INVOKESPECIAL(index));

            // Convert the return type back to our internal type
            (Type.Object).translateFrom(classGen, methodGen,
                                _chosenConstructor.getDeclaringClass());

        }
        // Invoke function calls that are handled in separate classes
        else {
            if (isSecureProcessing && !isExtensionFunctionEnabled)
                translateUnallowedExtension(cpg, il);

            final String clazz = _chosenMethod.getDeclaringClass().getName();
            Class[] paramTypes = _chosenMethod.getParameterTypes();

            // Push "this" if it is an instance method
            if (_thisArgument != null) {
                _thisArgument.translate(classGen, methodGen);
            }

            for (int i = 0; i < n; i++) {
                final Expression exp = argument(i);
                exp.translate(classGen, methodGen);
                // Convert the argument to its Java type
                exp.startIterator(classGen, methodGen);
                exp.getType().translateTo(classGen, methodGen, paramTypes[i]);
            }

            final StringBuffer buffer = new StringBuffer();
            buffer.append('(');
            for (int i = 0; i < paramTypes.length; i++) {
                buffer.append(getSignature(paramTypes[i]));
            }
            buffer.append(')');
            buffer.append(getSignature(_chosenMethod.getReturnType()));

            if (_thisArgument != null && _clazz.isInterface()) {
                index = cpg.addInterfaceMethodref(clazz,
                                     _fname.getLocalPart(),
                                     buffer.toString());
                il.append(new INVOKEINTERFACE(index, n+1));
            }
            else {
                index = cpg.addMethodref(clazz,
                                     _fname.getLocalPart(),
                                     buffer.toString());
                il.append(_thisArgument != null ? (InvokeInstruction) new INVOKEVIRTUAL(index) :
                          (InvokeInstruction) new INVOKESTATIC(index));
            }

            // Convert the return type back to our internal type
            _type.translateFrom(classGen, methodGen,
                                _chosenMethod.getReturnType());
        }
    }

    @Override
    public String toString() {
        return "funcall(" + _fname + ", " + _arguments + ')';
    }

    public boolean isStandard() {
        final String namespace = _fname.getNamespace();
        return (namespace == null) || (namespace.equals(Constants.EMPTYSTRING));
    }

    public boolean isExtension() {
        final String namespace = _fname.getNamespace();
        return (namespace != null) && (namespace.equals(EXT_XSLTC));
    }

    /**
     * Returns a vector with all methods named <code>_fname
     * after stripping its namespace or <code>null
     * if no such methods exist.
     */
    private Vector findMethods() {

          Vector result = null;
          final String namespace = _fname.getNamespace();

          if (_className != null && _className.length() > 0) {
            final int nArgs = _arguments.size();
            try {
              if (_clazz == null) {
                _clazz = ObjectFactory.findProviderClass(_className, true);

                if (_clazz == null) {
                  final ErrorMsg msg =
                        new ErrorMsg(ErrorMsg.CLASS_NOT_FOUND_ERR, _className);
                  getParser().reportError(Constants.ERROR, msg);
                }
              }

              final String methodName = _fname.getLocalPart();
              final Method[] methods = _clazz.getMethods();

              for (int i = 0; i < methods.length; i++) {
                final int mods = methods[i].getModifiers();
                // Is it public and same number of args ?
                if (Modifier.isPublic(mods)
                    && methods[i].getName().equals(methodName)
                    && methods[i].getParameterTypes().length == nArgs)
                {
                  if (result == null) {
                    result = new Vector();
                  }
                  result.addElement(methods[i]);
                }
              }
            }
            catch (ClassNotFoundException e) {
                  final ErrorMsg msg = new ErrorMsg(ErrorMsg.CLASS_NOT_FOUND_ERR, _className);
                  getParser().reportError(Constants.ERROR, msg);
            }
          }
          return result;
    }

    /**
     * Returns a vector with all constructors named <code>_fname
     * after stripping its namespace or <code>null
     * if no such methods exist.
     */
    private Vector findConstructors() {
        Vector result = null;
        final String namespace = _fname.getNamespace();

        final int nArgs = _arguments.size();
        try {
          if (_clazz == null) {
            _clazz = ObjectFactory.findProviderClass(_className, true);

            if (_clazz == null) {
              final ErrorMsg msg = new ErrorMsg(ErrorMsg.CLASS_NOT_FOUND_ERR, _className);
              getParser().reportError(Constants.ERROR, msg);
            }
          }

          final Constructor[] constructors = _clazz.getConstructors();

          for (int i = 0; i < constructors.length; i++) {
              final int mods = constructors[i].getModifiers();
              // Is it public, static and same number of args ?
              if (Modifier.isPublic(mods) &&
                  constructors[i].getParameterTypes().length == nArgs)
              {
                if (result == null) {
                  result = new Vector();
                }
                result.addElement(constructors[i]);
              }
          }
        }
        catch (ClassNotFoundException e) {
          final ErrorMsg msg = new ErrorMsg(ErrorMsg.CLASS_NOT_FOUND_ERR, _className);
          getParser().reportError(Constants.ERROR, msg);
        }

        return result;
    }


    /**
     * Compute the JVM signature for the class.
     */
    static final String getSignature(Class clazz) {
        if (clazz.isArray()) {
            final StringBuffer sb = new StringBuffer();
            Class cl = clazz;
            while (cl.isArray()) {
                sb.append("[");
                cl = cl.getComponentType();
            }
            sb.append(getSignature(cl));
            return sb.toString();
        }
        else if (clazz.isPrimitive()) {
            if (clazz == Integer.TYPE) {
                return "I";
            }
            else if (clazz == Byte.TYPE) {
                return "B";
            }
            else if (clazz == Long.TYPE) {
                return "J";
            }
            else if (clazz == Float.TYPE) {
                return "F";
            }
            else if (clazz == Double.TYPE) {
                return "D";
            }
            else if (clazz == Short.TYPE) {
                return "S";
            }
            else if (clazz == Character.TYPE) {
                return "C";
            }
            else if (clazz == Boolean.TYPE) {
                return "Z";
            }
            else if (clazz == Void.TYPE) {
                return "V";
            }
            else {
                final String name = clazz.toString();
                ErrorMsg err = new ErrorMsg(ErrorMsg.UNKNOWN_SIG_TYPE_ERR,name);
                throw new Error(err.toString());
            }
        }
        else {
            return "L" + clazz.getName().replace('.', '/') + ';';
        }
    }

    /**
     * Compute the JVM method descriptor for the method.
     */
    static final String getSignature(Method meth) {
        final StringBuffer sb = new StringBuffer();
        sb.append('(');
        final Class[] params = meth.getParameterTypes(); // avoid clone
        for (int j = 0; j < params.length; j++) {
            sb.append(getSignature(params[j]));
        }
        return sb.append(')').append(getSignature(meth.getReturnType()))
            .toString();
    }

    /**
     * Compute the JVM constructor descriptor for the constructor.
     */
    static final String getSignature(Constructor cons) {
        final StringBuffer sb = new StringBuffer();
        sb.append('(');
        final Class[] params = cons.getParameterTypes(); // avoid clone
        for (int j = 0; j < params.length; j++) {
            sb.append(getSignature(params[j]));
        }
        return sb.append(")V").toString();
    }

    /**
     * Return the signature of the current method
     */
    private String getMethodSignature(Vector argsType) {
        final StringBuffer buf = new StringBuffer(_className);
        buf.append('.').append(_fname.getLocalPart()).append('(');

        int nArgs = argsType.size();
        for (int i = 0; i < nArgs; i++) {
            final Type intType = (Type)argsType.elementAt(i);
            buf.append(intType.toString());
            if (i < nArgs - 1) buf.append(", ");
        }

        buf.append(')');
        return buf.toString();
    }

    /**
     * To support EXSLT extensions, convert names with dash to allowable Java names:
     * e.g., convert abc-xyz to abcXyz.
     * Note: dashes only appear in middle of an EXSLT function or element name.
     */
    protected static String replaceDash(String name)
    {
        char dash = '-';
        final StringBuilder buff = new StringBuilder("");
        for (int i = 0; i < name.length(); i++) {
        if (i > 0 && name.charAt(i-1) == dash)
            buff.append(Character.toUpperCase(name.charAt(i)));
        else if (name.charAt(i) != dash)
            buff.append(name.charAt(i));
        }
        return buff.toString();
    }

    /**
     * Translate code to call the BasisLibrary.unallowed_extensionF(String)
     * method.
     */
    private void translateUnallowedExtension(ConstantPoolGen cpg,
                                             InstructionList il) {
        int index = cpg.addMethodref(BASIS_LIBRARY_CLASS,
                                     "unallowed_extension_functionF",
                                     "(Ljava/lang/String;)V");
        il.append(new PUSH(cpg, _fname.toString()));
        il.append(new INVOKESTATIC(index));
    }
}

Other Java examples (source code examples)

Here is a short list of links related to this Java FunctionCall.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.