org.apache.cocoon.components.expression.jexl.JSIntrospector.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.cocoon.components.expression.jexl.JSIntrospector.java

Source

/*
 * Copyright 1999-2005 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.
 */
package org.apache.cocoon.components.expression.jexl;

import java.util.Enumeration;
import java.util.Iterator;

import org.apache.commons.jexl.util.introspection.Info;
import org.apache.commons.jexl.util.introspection.UberspectImpl;
import org.apache.commons.jexl.util.introspection.VelMethod;
import org.apache.commons.jexl.util.introspection.VelPropertyGet;
import org.apache.commons.jexl.util.introspection.VelPropertySet;
import org.apache.commons.lang.StringUtils;
import org.mozilla.javascript.*;

/**
 * Jexl Introspector that supports Rhino JavaScript objects
 * as well as Java Objects
 * @version SVN $Id: JSIntrospector.java 169483 2005-05-10 14:57:03Z lgawron $
 */
public class JSIntrospector extends UberspectImpl {

    static class JSMethod implements VelMethod {

        Scriptable scope;
        String name;

        public JSMethod(Scriptable scope, String name) {
            this.scope = scope;
            this.name = name;
        }

        public Object invoke(Object thisArg, Object[] args) throws Exception {
            Context cx = Context.enter();
            try {
                Object result;
                Scriptable thisObj = !(thisArg instanceof Scriptable) ? Context.toObject(thisArg, scope)
                        : (Scriptable) thisArg;
                result = ScriptableObject.getProperty(thisObj, name);
                Object[] newArgs = null;
                if (args != null) {
                    newArgs = new Object[args.length];
                    int len = args.length;
                    for (int i = 0; i < len; i++) {
                        newArgs[i] = args[i];
                        if (args[i] != null && !(args[i] instanceof Number) && !(args[i] instanceof Boolean)
                                && !(args[i] instanceof String) && !(args[i] instanceof Scriptable)) {
                            newArgs[i] = Context.toObject(args[i], scope);
                        }
                    }
                }
                result = ScriptRuntime.call(cx, result, thisObj, newArgs, scope);
                if (result == Undefined.instance || result == Scriptable.NOT_FOUND) {
                    result = null;
                } else if (!(result instanceof NativeJavaClass)) {
                    while (result instanceof Wrapper) {
                        result = ((Wrapper) result).unwrap();
                    }
                }
                return result;
            } catch (JavaScriptException e) {
                throw new java.lang.reflect.InvocationTargetException(e);
            } finally {
                Context.exit();
            }
        }

        public boolean isCacheable() {
            return false;
        }

        public String getMethodName() {
            return name;
        }

        public Class getReturnType() {
            return Object.class;
        }

    }

    static class JSPropertyGet implements VelPropertyGet {

        Scriptable scope;
        String name;

        public JSPropertyGet(Scriptable scope, String name) {
            this.scope = scope;
            this.name = name;
        }

        public Object invoke(Object thisArg) throws Exception {
            Context cx = Context.enter();
            try {
                Scriptable thisObj = !(thisArg instanceof Scriptable) ? Context.toObject(thisArg, scope)
                        : (Scriptable) thisArg;
                Object result = ScriptableObject.getProperty(thisObj, name);
                if (result == Scriptable.NOT_FOUND) {
                    result = ScriptableObject.getProperty(thisObj, "get" + StringUtils.capitalize(name));
                    if (result != Scriptable.NOT_FOUND && result instanceof Function) {
                        try {
                            result = ((Function) result).call(cx, ScriptableObject.getTopLevelScope(thisObj),
                                    thisObj, new Object[] {});
                        } catch (JavaScriptException exc) {
                            exc.printStackTrace();
                            result = null;
                        }
                    }
                }
                if (result == Scriptable.NOT_FOUND || result == Undefined.instance) {
                    result = null;
                } else if (result instanceof Wrapper && !(result instanceof NativeJavaClass)) {
                    result = ((Wrapper) result).unwrap();
                }
                return result;
            } finally {
                Context.exit();
            }
        }

        public boolean isCacheable() {
            return false;
        }

        public String getMethodName() {
            return name;
        }
    }

    static class JSPropertySet implements VelPropertySet {

        Scriptable scope;
        String name;

        public JSPropertySet(Scriptable scope, String name) {
            this.scope = scope;
            this.name = name;
        }

        public Object invoke(Object thisArg, Object rhs) throws Exception {
            Context.enter();
            try {
                Scriptable thisObj;
                Object arg = rhs;
                if (!(thisArg instanceof Scriptable)) {
                    thisObj = Context.toObject(thisArg, scope);
                } else {
                    thisObj = (Scriptable) thisArg;
                }
                if (arg != null && !(arg instanceof Number) && !(arg instanceof Boolean) && !(arg instanceof String)
                        && !(arg instanceof Scriptable)) {
                    arg = Context.toObject(arg, scope);
                }
                ScriptableObject.putProperty(thisObj, name, arg);
                return rhs;
            } finally {
                Context.exit();
            }
        }

        public boolean isCacheable() {
            return false;
        }

        public String getMethodName() {
            return name;
        }
    }

    public static class NativeArrayIterator implements Iterator {

        NativeArray arr;
        int index;

        public NativeArrayIterator(NativeArray arr) {
            this.arr = arr;
            this.index = 0;
        }

        public boolean hasNext() {
            return index < (int) arr.jsGet_length();
        }

        public Object next() {
            Context.enter();
            try {
                Object result = arr.get(index++, arr);
                if (result == Undefined.instance || result == Scriptable.NOT_FOUND) {
                    result = null;
                } else {
                    if (!(result instanceof NativeJavaClass)) {
                        while (result instanceof Wrapper) {
                            result = ((Wrapper) result).unwrap();
                        }
                    }
                }
                return result;
            } finally {
                Context.exit();
            }
        }

        public void remove() {
            arr.delete(index);
        }
    }

    static class ScriptableIterator implements Iterator {

        Scriptable scope;
        Object[] ids;
        int index;

        public ScriptableIterator(Scriptable scope) {
            this.scope = scope;
            this.ids = scope.getIds();
            this.index = 0;
        }

        public boolean hasNext() {
            return index < ids.length;
        }

        public Object next() {
            Context.enter();
            try {
                Object result = ScriptableObject.getProperty(scope, ids[index++].toString());
                if (result == Undefined.instance || result == Scriptable.NOT_FOUND) {
                    result = null;
                } else if (!(result instanceof NativeJavaClass)) {
                    while (result instanceof Wrapper) {
                        result = ((Wrapper) result).unwrap();
                    }
                }
                return result;
            } finally {
                Context.exit();
            }
        }

        public void remove() {
            Context.enter();
            try {
                scope.delete(ids[index].toString());
            } finally {
                Context.exit();
            }
        }
    }

    public Iterator getIterator(Object obj, Info i) throws Exception {
        if (!(obj instanceof Scriptable)) {
            // support Enumeration
            /*
               Booth Enumeration and Iterator are supported in
               Uberspect. The only difference is that they emit a
               rather long warning message to commons logging, telling
               that Enumerations and Iterator not are resettable and
               cannot be reused.
            */
            if (obj instanceof Enumeration) {
                final Enumeration e = (Enumeration) obj;
                return new Iterator() {

                    public boolean hasNext() {
                        return e.hasMoreElements();
                    }

                    public Object next() {
                        return e.nextElement();
                    }

                    public void remove() {
                        // no action
                    }

                };
            }
            if (obj instanceof Iterator) {
                // support Iterator
                return (Iterator) obj;
            }
            return super.getIterator(obj, i);
        }
        if (obj instanceof NativeArray) {
            return new NativeArrayIterator((NativeArray) obj);
        }
        return new ScriptableIterator((Scriptable) obj);
    }

    public VelMethod getMethod(Object obj, String methodName, Object[] args, Info i) throws Exception {
        return !(obj instanceof Scriptable) ? super.getMethod(obj, methodName, args, i)
                : new JSMethod((Scriptable) obj, methodName);
    }

    public VelPropertyGet getPropertyGet(Object obj, String identifier, Info i) throws Exception {
        return !(obj instanceof Scriptable) ? super.getPropertyGet(obj, identifier, i)
                : new JSPropertyGet((Scriptable) obj, identifier);
    }

    public VelPropertySet getPropertySet(Object obj, String identifier, Object arg, Info i) throws Exception {
        return !(obj instanceof Scriptable) ? super.getPropertySet(obj, identifier, arg, i)
                : new JSPropertySet((Scriptable) obj, identifier);
    }
}