aboutsummaryrefslogtreecommitdiffstats
path: root/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/MemberBox.java
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/MemberBox.java')
-rw-r--r--trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/MemberBox.java362
1 files changed, 362 insertions, 0 deletions
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/MemberBox.java b/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/MemberBox.java
new file mode 100644
index 0000000..2d3553f
--- /dev/null
+++ b/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/MemberBox.java
@@ -0,0 +1,362 @@
+/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (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.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Rhino code, released
+ * May 6, 1999.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1997-1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Igor Bukanov
+ * Felix Meschberger
+ * Norris Boyd
+ * Ulrike Mueller <umueller@demandware.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * the GNU General Public License Version 2 or later (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of those above. If
+ * you wish to allow use of your version of this file only under the terms of
+ * the GPL and not to allow others to use your version of this file under the
+ * MPL, indicate your decision by deleting the provisions above and replacing
+ * them with the notice and other provisions required by the GPL. If you do
+ * not delete the provisions above, a recipient may use your version of this
+ * file under either the MPL or the GPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+package org.mozilla.javascript;
+
+import java.lang.reflect.*;
+import java.io.*;
+
+/**
+ * Wrappper class for Method and Constructor instances to cache
+ * getParameterTypes() results, recover from IllegalAccessException
+ * in some cases and provide serialization support.
+ *
+ * @author Igor Bukanov
+ */
+
+final class MemberBox implements Serializable
+{
+ static final long serialVersionUID = 6358550398665688245L;
+
+ private transient Member memberObject;
+ transient Class[] argTypes;
+ transient Object delegateTo;
+ transient boolean vararg;
+
+
+ MemberBox(Method method)
+ {
+ init(method);
+ }
+
+ MemberBox(Constructor constructor)
+ {
+ init(constructor);
+ }
+
+ private void init(Method method)
+ {
+ this.memberObject = method;
+ this.argTypes = method.getParameterTypes();
+ this.vararg = VMBridge.instance.isVarArgs(method);
+ }
+
+ private void init(Constructor constructor)
+ {
+ this.memberObject = constructor;
+ this.argTypes = constructor.getParameterTypes();
+ this.vararg = VMBridge.instance.isVarArgs(constructor);
+ }
+
+ Method method()
+ {
+ return (Method)memberObject;
+ }
+
+ Constructor ctor()
+ {
+ return (Constructor)memberObject;
+ }
+
+ Member member()
+ {
+ return memberObject;
+ }
+
+ boolean isMethod()
+ {
+ return memberObject instanceof Method;
+ }
+
+ boolean isCtor()
+ {
+ return memberObject instanceof Constructor;
+ }
+
+ boolean isStatic()
+ {
+ return Modifier.isStatic(memberObject.getModifiers());
+ }
+
+ String getName()
+ {
+ return memberObject.getName();
+ }
+
+ Class getDeclaringClass()
+ {
+ return memberObject.getDeclaringClass();
+ }
+
+ String toJavaDeclaration()
+ {
+ StringBuffer sb = new StringBuffer();
+ if (isMethod()) {
+ Method method = method();
+ sb.append(method.getReturnType());
+ sb.append(' ');
+ sb.append(method.getName());
+ } else {
+ Constructor ctor = ctor();
+ String name = ctor.getDeclaringClass().getName();
+ int lastDot = name.lastIndexOf('.');
+ if (lastDot >= 0) {
+ name = name.substring(lastDot + 1);
+ }
+ sb.append(name);
+ }
+ sb.append(JavaMembers.liveConnectSignature(argTypes));
+ return sb.toString();
+ }
+
+ public String toString()
+ {
+ return memberObject.toString();
+ }
+
+ Object invoke(Object target, Object[] args)
+ {
+ Method method = method();
+ try {
+ try {
+ return method.invoke(target, args);
+ } catch (IllegalAccessException ex) {
+ Method accessible = searchAccessibleMethod(method, argTypes);
+ if (accessible != null) {
+ memberObject = accessible;
+ method = accessible;
+ } else {
+ if (!VMBridge.instance.tryToMakeAccessible(method)) {
+ throw Context.throwAsScriptRuntimeEx(ex);
+ }
+ }
+ // Retry after recovery
+ return method.invoke(target, args);
+ }
+ } catch (Exception ex) {
+ throw Context.throwAsScriptRuntimeEx(ex);
+ }
+ }
+
+ Object newInstance(Object[] args)
+ {
+ Constructor ctor = ctor();
+ try {
+ try {
+ return ctor.newInstance(args);
+ } catch (IllegalAccessException ex) {
+ if (!VMBridge.instance.tryToMakeAccessible(ctor)) {
+ throw Context.throwAsScriptRuntimeEx(ex);
+ }
+ }
+ return ctor.newInstance(args);
+ } catch (Exception ex) {
+ throw Context.throwAsScriptRuntimeEx(ex);
+ }
+ }
+
+ private static Method searchAccessibleMethod(Method method, Class[] params)
+ {
+ int modifiers = method.getModifiers();
+ if (Modifier.isPublic(modifiers) && !Modifier.isStatic(modifiers)) {
+ Class c = method.getDeclaringClass();
+ if (!Modifier.isPublic(c.getModifiers())) {
+ String name = method.getName();
+ Class[] intfs = c.getInterfaces();
+ for (int i = 0, N = intfs.length; i != N; ++i) {
+ Class intf = intfs[i];
+ if (Modifier.isPublic(intf.getModifiers())) {
+ try {
+ return intf.getMethod(name, params);
+ } catch (NoSuchMethodException ex) {
+ } catch (SecurityException ex) { }
+ }
+ }
+ for (;;) {
+ c = c.getSuperclass();
+ if (c == null) { break; }
+ if (Modifier.isPublic(c.getModifiers())) {
+ try {
+ Method m = c.getMethod(name, params);
+ int mModifiers = m.getModifiers();
+ if (Modifier.isPublic(mModifiers)
+ && !Modifier.isStatic(mModifiers))
+ {
+ return m;
+ }
+ } catch (NoSuchMethodException ex) {
+ } catch (SecurityException ex) { }
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ private void readObject(ObjectInputStream in)
+ throws IOException, ClassNotFoundException
+ {
+ in.defaultReadObject();
+ Member member = readMember(in);
+ if (member instanceof Method) {
+ init((Method)member);
+ } else {
+ init((Constructor)member);
+ }
+ }
+
+ private void writeObject(ObjectOutputStream out)
+ throws IOException
+ {
+ out.defaultWriteObject();
+ writeMember(out, memberObject);
+ }
+
+ /**
+ * Writes a Constructor or Method object.
+ *
+ * Methods and Constructors are not serializable, so we must serialize
+ * information about the class, the name, and the parameters and
+ * recreate upon deserialization.
+ */
+ private static void writeMember(ObjectOutputStream out, Member member)
+ throws IOException
+ {
+ if (member == null) {
+ out.writeBoolean(false);
+ return;
+ }
+ out.writeBoolean(true);
+ if (!(member instanceof Method || member instanceof Constructor))
+ throw new IllegalArgumentException("not Method or Constructor");
+ out.writeBoolean(member instanceof Method);
+ out.writeObject(member.getName());
+ out.writeObject(member.getDeclaringClass());
+ if (member instanceof Method) {
+ writeParameters(out, ((Method) member).getParameterTypes());
+ } else {
+ writeParameters(out, ((Constructor) member).getParameterTypes());
+ }
+ }
+
+ /**
+ * Reads a Method or a Constructor from the stream.
+ */
+ private static Member readMember(ObjectInputStream in)
+ throws IOException, ClassNotFoundException
+ {
+ if (!in.readBoolean())
+ return null;
+ boolean isMethod = in.readBoolean();
+ String name = (String) in.readObject();
+ Class declaring = (Class) in.readObject();
+ Class[] parms = readParameters(in);
+ try {
+ if (isMethod) {
+ return declaring.getMethod(name, parms);
+ } else {
+ return declaring.getConstructor(parms);
+ }
+ } catch (NoSuchMethodException e) {
+ throw new IOException("Cannot find member: " + e);
+ }
+ }
+
+ private static final Class[] primitives = {
+ Boolean.TYPE,
+ Byte.TYPE,
+ Character.TYPE,
+ Double.TYPE,
+ Float.TYPE,
+ Integer.TYPE,
+ Long.TYPE,
+ Short.TYPE,
+ Void.TYPE
+ };
+
+ /**
+ * Writes an array of parameter types to the stream.
+ *
+ * Requires special handling because primitive types cannot be
+ * found upon deserialization by the default Java implementation.
+ */
+ private static void writeParameters(ObjectOutputStream out, Class[] parms)
+ throws IOException
+ {
+ out.writeShort(parms.length);
+ outer:
+ for (int i=0; i < parms.length; i++) {
+ Class parm = parms[i];
+ boolean primitive = parm.isPrimitive();
+ out.writeBoolean(primitive);
+ if (!primitive) {
+ out.writeObject(parm);
+ continue;
+ }
+ for (int j=0; j < primitives.length; j++) {
+ if (parm.equals(primitives[j])) {
+ out.writeByte(j);
+ continue outer;
+ }
+ }
+ throw new IllegalArgumentException("Primitive " + parm +
+ " not found");
+ }
+ }
+
+ /**
+ * Reads an array of parameter types from the stream.
+ */
+ private static Class[] readParameters(ObjectInputStream in)
+ throws IOException, ClassNotFoundException
+ {
+ Class[] result = new Class[in.readShort()];
+ for (int i=0; i < result.length; i++) {
+ if (!in.readBoolean()) {
+ result[i] = (Class) in.readObject();
+ continue;
+ }
+ result[i] = primitives[in.readByte()];
+ }
+ return result;
+ }
+}
+