package com.revolsys.io.map;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import com.revolsys.logging.Logs;
import com.revolsys.parallel.InvokeMethodRunnable;
import com.revolsys.record.io.format.json.JsonParser;
import com.revolsys.util.CaseConverter;
import com.revolsys.util.Property;
@SuppressWarnings("unchecked")
public class MapObjectFactoryRegistry {
public static final Map<String, MapObjectFactory> TYPE_NAME_TO_FACTORY = new HashMap<>();
static {
final List<Runnable> postInitMethods = new ArrayList<>();
try {
final ClassLoader classLoader = MapObjectFactoryRegistry.class.getClassLoader();
final String resourceName = "META-INF/" + MapObjectFactory.class.getName() + ".json";
final Enumeration<URL> resources = classLoader.getResources(resourceName);
while (resources.hasMoreElements()) {
final URL resource = resources.nextElement();
try {
final Map<String, Object> config = JsonParser.getMap(resource.openStream());
final List<Map<String, Object>> factories = (List<Map<String, Object>>)config
.get("factories");
for (final Map<String, Object> factoryConfig : factories) {
try {
final String typeName = (String)factoryConfig.get("typeName");
final String description = (String)factoryConfig.get("description");
final String typeClassName = (String)factoryConfig.get("typeClass");
final String methodName = (String)factoryConfig.get("methodName");
if (Property.hasValue(typeClassName)) {
final Class<?> factoryClass = Class.forName(typeClassName, false, classLoader);
for (final Method method : factoryClass.getDeclaredMethods()) {
if (method.getName().equals("mapObjectFactoryInit")) {
if (Modifier.isStatic(method.getModifiers())) {
if (method.getParameterTypes().length == 0) {
if (method.getReturnType() == Void.TYPE) {
try {
method.invoke(null);
} catch (final Throwable e) {
Logs.error(factoryClass, e);
}
}
}
}
}
if (method.getName().equals("mapObjectFactoryPostInit")) {
if (Modifier.isStatic(method.getModifiers())) {
if (method.getParameterTypes().length == 0) {
if (method.getReturnType() == Void.TYPE) {
postInitMethods.add(new InvokeMethodRunnable(method));
}
}
}
}
}
if (Property.hasValue(typeName)) {
final MapObjectFactory factory;
if (Property.hasValue(methodName)) {
factory = new InvokeMethodMapObjectFactory(typeName, description, factoryClass,
methodName);
} else {
factory = new InvokeConstructorMapObjectFactory(typeName, description,
factoryClass);
}
addFactory(factory);
}
}
} catch (final Throwable e) {
Logs.error(MapObjectFactoryRegistry.class, "Unable to add factory: " + factoryConfig,
e);
}
}
} catch (final Throwable e) {
Logs.error(MapObjectFactoryRegistry.class, "Unable to read resource: " + resource, e);
}
}
} catch (final Throwable e) {
Logs.error(MapObjectFactoryRegistry.class, "Unable to read resources", e);
}
for (final Runnable runnable : postInitMethods) {
runnable.run();
}
}
public static void addFactory(final MapObjectFactory factory) {
final String typeName = factory.getTypeName();
TYPE_NAME_TO_FACTORY.put(typeName, factory);
}
public static MapObjectFactory getFactory(final String type) {
return TYPE_NAME_TO_FACTORY.get(type);
}
public static void init() {
}
public static void newFactory(final String typeName,
final Function<Map<String, ? extends Object>, Object> function) {
newFactory(typeName, CaseConverter.toCapitalizedWords(typeName), function);
}
public static void newFactory(final String typeName, final String description,
final Function<Map<String, ? extends Object>, Object> function) {
final FunctionMapObjectFactory factory = new FunctionMapObjectFactory(typeName, description,
function);
addFactory(factory);
}
}