/*
* ******************************************************************************
* MontiCore Language Workbench
* Copyright (c) 2015, MontiCore, All rights reserved.
*
* This project is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this project. If not, see <http://www.gnu.org/licenses/>.
* ******************************************************************************
*/
package de.monticore.generating.templateengine;
import de.se_rwth.commons.logging.Log;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.List;
/**
* Factory to instantiate any object from Templates
* using op.instantiate(classname)
*
* @author Martin Schindler
*/
public class ObjectFactory {
protected static ObjectFactory factory = null;
protected ClassLoader classLoader;
protected ObjectFactory() {
classLoader = getClass().getClassLoader();
}
public static Object createObject(String qualifiedName) {
return createObject(qualifiedName, new ArrayList<>(), new ArrayList<>());
}
public static Object createObject(String qualifiedName, List<Object> params) {
return createObject(qualifiedName, getTypes(params), params);
}
public static Object createObject(String qualifiedName, List<Class<?>> paramTypes, List<Object> params) {
if (factory == null) {
factory = new ObjectFactory();
}
return factory.doCreateObject(qualifiedName, paramTypes, params);
}
protected Object doCreateObject(String qualifiedName, List<Class<?>> paramTypes, List<Object> params) {
Class<?> referencedClass = null;
// try to call constructor directly
try {
referencedClass = classLoader.loadClass(qualifiedName);
return referencedClass
.getConstructor(paramTypes.toArray(new Class<?>[] {}))
.newInstance(params.toArray(new Object[] {}));
}
catch (ClassNotFoundException e) {
Log.error("0xA0118 Template-execution: Could not find Class " + qualifiedName);
}
catch (Exception e) {
// types of direct constructor-call are not identical
// try to fix it by searching for a matching constructor (using supertypes of the given params)
if (referencedClass != null) {
for (Constructor<?> constr : referencedClass.getConstructors()) {
if (constr.getParameterTypes().length == paramTypes.size()) {
for (int i = 0; i < paramTypes.size(); i++) {
if (!constr.getParameterTypes()[i].isAssignableFrom(paramTypes.get(i))) {
continue;
}
try {
return constr.newInstance(params.toArray(new Object[] {}));
}
catch (Exception e2) {
Log.error("0xA0119 Template-execution: Could not instanciate Class " +
qualifiedName + " with parameters " + paramTypes);
}
}
}
}
}
}
return null;
}
protected static List<Class<?>> getTypes(List<Object> params) {
if (factory == null) {
factory = new ObjectFactory();
}
return factory.doGetTypes(params);
}
protected List<Class<?>> doGetTypes(List<Object> params) {
List<Class<?>> paramTypes = new ArrayList<>();
for (Object obj : params) {
paramTypes.add(obj.getClass());
}
return paramTypes;
}
static void setClassLoader(ClassLoader loader) {
if (loader == null) {
return;
}
if (factory == null) {
factory = new ObjectFactory();
}
factory.doSetClassLoader(loader);
}
protected void doSetClassLoader(ClassLoader loader) {
this.classLoader = loader;
}
}