// Copyright (c) Corporation for National Research Initiatives
package org.python.core;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
import java.lang.reflect.InvocationTargetException;
import java.lang.InstantiationException;
public class PyReflectedConstructor extends PyReflectedFunction {
public PyReflectedConstructor(String name) {
super(name);
__name__ = name;
argslist = new ReflectedArgs[1];
nargs = 0;
}
public PyReflectedConstructor(Constructor c) {
this(c.getDeclaringClass().getName());
addConstructor(c);
}
private ReflectedArgs makeArgs(Constructor m) {
return new ReflectedArgs(m, m.getParameterTypes(), m.getDeclaringClass(), true);
}
public void addConstructor(Constructor m) {
int mods = m.getModifiers();
// Only add public methods unless we're overriding
if (!Modifier.isPublic(mods) && !JavaAccessibility.accessIsMutable())
return;
addArgs(makeArgs(m));
}
// xxx temporary solution, type ctr will go through __new__ ...
PyObject make(PyObject[] args, String[] keywords) {
ReflectedArgs[] argsl = argslist;
ReflectedCallData callData = new ReflectedCallData();
Object method = null;
boolean consumes_keywords = false;
int n = nargs;
int nkeywords = keywords.length;
PyObject[] allArgs = null;
// Check for a matching constructor to call
if (n > 0) { // PyArgsKeywordsCall signature, if present, is the first
if (argsl[0].matches(null, args, keywords, callData)) {
method = argsl[0].data;
consumes_keywords = argsl[0].flags == ReflectedArgs.PyArgsKeywordsCall;
} else {
allArgs = args;
int i = 1;
if (nkeywords > 0) {
args = new PyObject[allArgs.length - nkeywords];
System.arraycopy(allArgs, 0, args, 0, args.length);
i = 0;
}
for (; i < n; i++) {
ReflectedArgs rargs = argsl[i];
if (rargs.matches(null, args, Py.NoKeywords, callData)) {
method = rargs.data;
break;
}
}
}
}
// Throw an error if no valid set of arguments
if (method == null) {
throwError(callData.errArg, args.length, true /*xxx?*/, false);
}
// Do the actual constructor call
PyObject obj = null;
Constructor ctor = (Constructor) method;
try {
obj = (PyObject) ctor.newInstance(callData.getArgsArray());
} catch (Throwable t) {
throw Py.JavaError(t);
}
if (!consumes_keywords) {
int offset = args.length;
for (int i = 0; i < nkeywords; i++) {
obj.__setattr__(keywords[i], allArgs[i + offset]);
}
}
return obj;
}
public PyObject __call__(PyObject self, PyObject[] args, String[] keywords) {
ReflectedArgs[] argsl = argslist;
if (self == null || !(self instanceof PyInstance)) {
throw Py.TypeError("invalid self argument to constructor");
}
PyInstance iself = (PyInstance) self;
Class javaClass = iself.instclass.proxyClass;
//Class[] javaClasses = iself.__class__.proxyClasses;
//int myIndex = -1;
boolean proxyConstructor = false;
Class declaringClass = argsl[0].declaringClass;
// If this is the constructor for a proxy class or not...
if (PyProxy.class.isAssignableFrom(declaringClass)) {
// if (self instanceof PyJavaInstance) {
// throw Py.TypeError(
// "invalid self argument to proxy constructor");
// }
} else {
if (!(iself instanceof PyJavaInstance)) {
// Get proxy constructor and call it
if (declaringClass.isAssignableFrom(javaClass)) {
proxyConstructor = true;
} else {
throw Py.TypeError("invalid self argument");
}
PyJavaClass jc = PyJavaClass.lookup(javaClass); // xxx
jc.initConstructors();
return jc.__init__.__call__(iself, args, keywords);
}
}
if (declaringClass.isAssignableFrom(javaClass)) {
proxyConstructor = true;
} else {
throw Py.TypeError("self invalid - must implement: " + declaringClass.getName());
}
if (iself.javaProxy != null) {
Class sup = iself.instclass.proxyClass;
if (PyProxy.class.isAssignableFrom(sup))
sup = sup.getSuperclass();
throw Py.TypeError("instance already instantiated for " + sup.getName());
}
ReflectedCallData callData = new ReflectedCallData();
Object method = null;
// Remove keyword args
int nkeywords = keywords.length;
PyObject[] allArgs = args;
if (nkeywords > 0) {
args = new PyObject[allArgs.length - nkeywords];
System.arraycopy(allArgs, 0, args, 0, args.length);
}
// Check for a matching constructor to call
int n = nargs;
for (int i = 0; i < n; i++) {
ReflectedArgs rargs = argsl[i];
if (rargs.matches(null, args, Py.NoKeywords, callData)) {
method = rargs.data;
break;
}
}
// Throw an error if no valid set of arguments
if (method == null) {
throwError(callData.errArg, args.length, self != null, false);
}
// Do the actual constructor call
Object jself = null;
ThreadState ts = Py.getThreadState();
try {
ts.pushInitializingProxy(iself);
Constructor ctor = (Constructor) method;
try {
jself = ctor.newInstance(callData.getArgsArray());
} catch (InvocationTargetException e) {
if (e.getTargetException() instanceof InstantiationException) {
Class sup = iself.instclass.proxyClass.getSuperclass();
String msg = "Constructor failed for Java superclass";
if (sup != null)
msg += " " + sup.getName();
throw Py.TypeError(msg);
} else
throw Py.JavaError(e);
} catch (Throwable t) {
throw Py.JavaError(t);
}
} finally {
ts.popInitializingProxy();
}
iself.javaProxy = jself;
// Do setattr's for keyword args
int offset = args.length;
for (int i = 0; i < nkeywords; i++) {
iself.__setattr__(keywords[i], allArgs[i + offset]);
}
return Py.None;
}
public PyObject __call__(PyObject[] args, String[] keywords) {
if (args.length < 1) {
throw Py.TypeError("constructor requires self argument");
}
PyObject[] newArgs = new PyObject[args.length - 1];
System.arraycopy(args, 1, newArgs, 0, newArgs.length);
return __call__(args[0], newArgs, keywords);
}
public String toString() {
//printArgs();
return "<java constructor " + __name__ + " " + Py.idstr(this) + ">";
}
}