001: /***** BEGIN LICENSE BLOCK *****
002: * Version: CPL 1.0/GPL 2.0/LGPL 2.1
003: *
004: * The contents of this file are subject to the Common Public
005: * License Version 1.0 (the "License"); you may not use this file
006: * except in compliance with the License. You may obtain a copy of
007: * the License at http://www.eclipse.org/legal/cpl-v10.html
008: *
009: * Software distributed under the License is distributed on an "AS
010: * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
011: * implied. See the License for the specific language governing
012: * rights and limitations under the License.
013: *
014: * Copyright (C) 2006 Kresten Krab Thorup <krab@gnu.org>
015: *
016: * Alternatively, the contents of this file may be used under the terms of
017: * either of the GNU General Public License Version 2 or later (the "GPL"),
018: * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
019: * in which case the provisions of the GPL or the LGPL are applicable instead
020: * of those above. If you wish to allow use of your version of this file only
021: * under the terms of either the GPL or the LGPL, and not to allow others to
022: * use your version of this file under the terms of the CPL, indicate your
023: * decision by deleting the provisions above and replace them with the notice
024: * and other provisions required by the GPL or the LGPL. If you do not delete
025: * the provisions above, a recipient may use your version of this file under
026: * the terms of any one of the CPL, the GPL or the LGPL.
027: ***** END LICENSE BLOCK *****/package org.jruby.javasupport.proxy;
028:
029: import java.lang.reflect.Constructor;
030: import java.lang.reflect.InvocationTargetException;
031:
032: import org.jruby.Ruby;
033: import org.jruby.RubyArray;
034: import org.jruby.RubyClass;
035: import org.jruby.RubyFixnum;
036: import org.jruby.RubyModule;
037: import org.jruby.RubyObject;
038: import org.jruby.RubyProc;
039: import org.jruby.exceptions.RaiseException;
040: import org.jruby.javasupport.Java;
041: import org.jruby.javasupport.JavaObject;
042: import org.jruby.javasupport.JavaUtil;
043: import org.jruby.runtime.Arity;
044: import org.jruby.runtime.Block;
045: import org.jruby.runtime.CallbackFactory;
046: import org.jruby.runtime.ObjectAllocator;
047: import org.jruby.runtime.builtin.IRubyObject;
048:
049: public class JavaProxyConstructor extends JavaProxyReflectionObject {
050:
051: private final Constructor proxyConstructor;
052: private final Class[] parameterTypes;
053:
054: private final JavaProxyClass declaringProxyClass;
055:
056: JavaProxyConstructor(Ruby runtime, JavaProxyClass pClass,
057: Constructor constructor) {
058: super (runtime, runtime.getModule("Java").getClass(
059: "JavaProxyConstructor"));
060: this .declaringProxyClass = pClass;
061: this .proxyConstructor = constructor;
062: this .parameterTypes = proxyConstructor.getParameterTypes();
063: }
064:
065: public Class[] getParameterTypes() {
066: Class[] result = new Class[parameterTypes.length - 1];
067: System.arraycopy(parameterTypes, 0, result, 0, result.length);
068: return result;
069: }
070:
071: public JavaProxyClass getDeclaringClass() {
072: return declaringProxyClass;
073: }
074:
075: public Object newInstance(Object[] args,
076: JavaProxyInvocationHandler handler)
077: throws IllegalArgumentException, InstantiationException,
078: IllegalAccessException, InvocationTargetException {
079: if (args.length + 1 != parameterTypes.length) {
080: throw new IllegalArgumentException(
081: "wrong number of parameters");
082: }
083:
084: Object[] realArgs = new Object[args.length + 1];
085: System.arraycopy(args, 0, realArgs, 0, args.length);
086: realArgs[args.length] = handler;
087:
088: return proxyConstructor.newInstance(realArgs);
089: }
090:
091: public static RubyClass createJavaProxyConstructorClass(
092: Ruby runtime, RubyModule javaProxyModule) {
093: RubyClass result = javaProxyModule.defineClassUnder(
094: "JavaProxyConstructor", runtime.getObject(),
095: ObjectAllocator.NOT_ALLOCATABLE_ALLOCATOR);
096:
097: CallbackFactory callbackFactory = runtime
098: .callbackFactory(JavaProxyConstructor.class);
099:
100: JavaProxyReflectionObject.registerRubyMethods(runtime, result);
101:
102: result.defineFastMethod("argument_types", callbackFactory
103: .getFastMethod("argument_types"));
104:
105: result.defineFastMethod("declaring_class", callbackFactory
106: .getFastMethod("getDeclaringClass"));
107:
108: result.defineMethod("new_instance", callbackFactory
109: .getOptMethod("new_instance"));
110:
111: result.defineFastMethod("arity", callbackFactory
112: .getFastMethod("arity"));
113:
114: return result;
115:
116: }
117:
118: public RubyFixnum arity() {
119: return getRuntime().newFixnum(getParameterTypes().length);
120: }
121:
122: protected String nameOnInspection() {
123: return getDeclaringClass().nameOnInspection();
124: }
125:
126: public IRubyObject inspect() {
127: StringBuffer result = new StringBuffer();
128: result.append(nameOnInspection());
129: Class[] parameterTypes = getParameterTypes();
130: for (int i = 0; i < parameterTypes.length; i++) {
131: result.append(parameterTypes[i].getName());
132: if (i < parameterTypes.length - 1) {
133: result.append(',');
134: }
135: }
136: result.append(")>");
137: return getRuntime().newString(result.toString());
138: }
139:
140: public RubyArray argument_types() {
141: return buildRubyArray(getParameterTypes());
142: }
143:
144: public RubyObject new_instance(IRubyObject[] args, Block block) {
145: int size = Arity.checkArgumentCount(getRuntime(), args, 1, 2) - 1;
146: final RubyProc proc;
147:
148: // Is there a supplied proc argument or do we assume a block was
149: // supplied
150: if (args[size] instanceof RubyProc) {
151: proc = (RubyProc) args[size];
152: } else {
153: proc = getRuntime().newProc(false, block);
154: size++;
155: }
156:
157: RubyArray constructor_args = (RubyArray) args[0];
158: Class[] parameterTypes = getParameterTypes();
159:
160: int count = (int) constructor_args.length().getLongValue();
161: Object[] converted = new Object[count];
162: for (int i = 0; i < count; i++) {
163: // TODO: call ruby method
164: IRubyObject ith = constructor_args
165: .aref(new IRubyObject[] { getRuntime().newFixnum(i) });
166: converted[i] = JavaUtil.convertArgument(Java.ruby_to_java(
167: this , ith, Block.NULL_BLOCK), parameterTypes[i]);
168: }
169:
170: final IRubyObject recv = this ;
171:
172: JavaProxyInvocationHandler handler = new JavaProxyInvocationHandler() {
173:
174: public Object invoke(Object proxy, JavaProxyMethod method,
175: Object[] nargs) throws Throwable {
176: int length = nargs == null ? 0 : nargs.length;
177: IRubyObject[] rubyArgs = new IRubyObject[length + 2];
178: rubyArgs[0] = JavaObject.wrap(recv.getRuntime(), proxy);
179: rubyArgs[1] = method;
180: for (int i = 0; i < length; i++) {
181: rubyArgs[i + 2] = JavaUtil.convertJavaToRuby(
182: getRuntime(), nargs[i]);
183: }
184: IRubyObject call_result = proc.call(rubyArgs);
185: Object converted_result = JavaUtil.convertRubyToJava(
186: call_result, method.getReturnType());
187: return converted_result;
188: }
189:
190: };
191:
192: Object result;
193: try {
194: result = newInstance(converted, handler);
195: } catch (Exception e) {
196: RaiseException ex = getRuntime().newArgumentError(
197: "Constructor invocation failed: " + e.getMessage());
198: ex.initCause(e);
199: throw ex;
200: }
201:
202: return JavaObject.wrap(getRuntime(), result);
203:
204: }
205:
206: }
|