*/
@SuppressWarnings("unchecked")
public CoreObject<T> spawn(final Option... options) {
// Process each element we might have enclosed.
final CommonCore cc = this.commonCore;
final Options options$ = Options.$(this.commonCore, options);
final Object[] args = options$.args();
return map(new F1<Class<T>, T>() {
@Override
public T f(Class<T> x) {
// Get the class we operate on
if (x == null) return null;
Class<T> toSpawn = x;
// TODO: Selection of implementor could need some improvement
if (x.isInterface()) {
toSpawn = (Class<T>) CoreClass.this.manager.getImplementors(x)[0];
}
// Quick pass for most common option
if (args == null || args.length == 0) {
try {
toSpawn.newInstance();
} catch (InstantiationException e) {
options$.failure(x, e, "spawn:instanceexception", "Unable to create a new instance.");
} catch (IllegalAccessException e) {
options$.failure(x, e, "spawn:illegalaccess", "Unable to access type.");
}
}
// Get constructor types ...
Class<?>[] types = new CoreObject<Object>(cc, args).map(new F1<Object, Class<?>>() {
public Class<?> f(Object xx) {
return xx.getClass();
}
}).array(Class.class);
try {
Constructor<T> constructor = null;
// Get constructor from cache ... (try to)
synchronized (CoreClass.this.constructors) {
constructor = CoreClass.this.constructors.get(types);
// Put a new constructor if it wasn't cached before
if (constructor == null) {
try {
constructor = toSpawn.getDeclaredConstructor(types);
} catch (NoSuchMethodException e) {
// We catch this exception in here, as sometimes we fail to obtain the
// proper constructor with the method above. In that case, we try to get
// the closest match
Constructor<?>[] declaredConstructors = toSpawn.getDeclaredConstructors();
for (Constructor<?> ccc : declaredConstructors) {
// Check if the constructor matches
Class<?>[] parameterTypes = ccc.getParameterTypes();
if (parameterTypes.length != types.length) continue;
boolean mismatch = false;
// Check if each parameter is assignable
for (int i = 0; i < types.length; i++) {
if (!parameterTypes[i].isAssignableFrom(types[i]))
mismatch = true;
}
// In case any parameter mismatched, we can't use this constructor
if (mismatch) continue;
constructor = (Constructor<T>) ccc;
}
}
// If we don't have any constructor at this point, we are in trouble
if (constructor == null)
throw new NoSuchMethodException("No constructor found.");
CoreClass.this.constructors.put(types, constructor);
}
}
return constructor.newInstance(args);
// NOTE: We do not swallow all execptions silently, becasue spawn() is a bit
// special and we cannot return anything that would still be usable.
} catch (SecurityException e) {
options$.failure(x, e, "spawn:security", "Security exception when trying to spawn.");
} catch (NoSuchMethodException e) {
options$.failure(x, e, "spawn:nomethod", "Method not found.");
} catch (IllegalArgumentException e) {
options$.failure(x, e, "spawn:illegalargs", "Illegal passed arguments.");
} catch (InstantiationException e) {
options$.failure(x, e, "spawn:instanceexception:2", "Cannot instantiate.");
} catch (IllegalAccessException e) {
options$.failure(x, e, "spawn:illegalaccess:2", "Unable to access type (2).");
} catch (InvocationTargetException e) {
options$.failure(x, e, "spawn:invocation", "Unable to invoke target.");
}
// TODO Make sure to only use weak references, so that we don't run out of memory
// and prevent
// garbage colleciton.