package org.myrobotlab.framework;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.HashMap;
import org.myrobotlab.logging.Level;
import org.myrobotlab.logging.LoggerFactory;
import org.myrobotlab.logging.Logging;
import org.myrobotlab.logging.LoggingFactory;
import org.slf4j.Logger;
import com.google.gson.Gson;
/**
* JSON TypeConverter - used in general REST api to convert url JSON parameters
* appropriately to hard types for method invoking used in WebGui and Cli
*
* @author GroG
*
*/
public class TypeConverter {
public final static Logger log = LoggerFactory.getLogger(TypeConverter.class);
private static Gson gson = new Gson();
// Possible Optimization -> pointers to known method signatures -
// optimization so that once a
// method's signature is processed and
// known conversion exists - it is saved
static public HashMap<String, Method[]> knownMethodSignatureConverters = new HashMap<String, Method[]>();
// pointers to conversion methods
// static public HashMap<String, Method> conversions = new HashMap<String,
// Method>();
/**
* this method tries to get the appropriate 'Typed parameter array for a
* specific method It "converts" parameters of strings into typed parameters
* which can then be used to reflectively invoke the appropriate method
*
* @param clazz
* @param method
* @param stringParams
* @return
*/
static public Object[] getTypedParamsFromJson(Class<?> clazz, String method, String[] stringParams) throws IOException {
// try {
Method[] methods = clazz.getMethods();
for (int i = 0; i < methods.length; ++i) {
Method m = methods[i];
Class<?>[] types = m.getParameterTypes();
// TODO optimize getting name ??? why didn't Java reflect api
// use a HashMap ???
if (method.equals(m.getName()) && stringParams.length == types.length) {
log.debug("method with same ordinal of params found {}.{} - building new converter", method, stringParams.length);
try {
Object[] newGSONTypedParamters = new Object[stringParams.length];
for (int j = 0; j < types.length; ++j) {
Class<?> pType = types[j];
String param = stringParams[j];
log.debug(String.format("attempting conversion into %s from inbound data %s", pType.getSimpleName(), stringParams[j]));
if (pType == String.class) {
// escape quotes
param = param.replaceAll("\"", "\\\"");
// add quotes
param = String.format("\"%s\"", param);
}
newGSONTypedParamters[j] = gson.fromJson(param, pType);
}
log.debug("successfully converted all types");
return newGSONTypedParamters;
} catch (Exception e) {
// Logging.logException(e);
log.warn("could not match type from inbound data");
continue;
}
} // if name and ordinal match
} // through each method
String error = String.format("could not find or convert %s", method);
log.error(error);
/*
* } catch (Exception e) { Logging.logError(e); }
*
* return null;
*/
throw new IOException(error);
}
public static void main(String[] args) {
try {
LoggingFactory.init(Level.DEBUG);
/*
* FIXME PUT IN JUNIT TEST !!
* org.myrobotlab.service.Runtime.createAndStart("clock", "Clock");
*
* ServiceInterface si =
* org.myrobotlab.service.Runtime.getService("clock");
*
*
* String stringParams[] = new String[] { "13", "1" }; String method =
* "digitalWrite"; Class<?> clazz = si.getClass();
*
* Object[] params = getTypedParamsFromJson(clazz, method, stringParams);
*
* si.invoke(method, params);
*
* log.info("here");
*
* Object[] params2 = getTypedParamsFromJson(clazz, method, stringParams);
* log.info("here");
*/
} catch (Exception e) {
Logging.logError(e);
}
}
static public boolean StringToBoolean(String in) {
return Boolean.parseBoolean(in);
}
// -------- primitive boxed types conversion begin ------------
static public byte StringToByte(String in) {
return Byte.parseByte(in);
}
static public char StringToChar(String in) {
return in.charAt(0);
}
static public double StringToDouble(String in) {
return Double.parseDouble(in);
}
static public float StringToFloat(String in) {
return Float.parseFloat(in);
}
static public int StringToInteger(String in) {
return Integer.parseInt(in);
}
static public long StringToLong(String in) {
return Long.parseLong(in);
}
// -------- primitive boxed types conversion end ------------
static public short StringToShort(String in) {
return Short.parseShort(in);
}
/*
* static public Object[] convert(String[] stringParams, Method[] converter) {
* try { Object[] newTypedParams = new Object[stringParams.length]; for (int i
* = 0; i < stringParams.length; ++i) { // static calls on conversion -
* probably not thread safe newTypedParams[0] = converter[i].invoke(null,
* stringParams[i]); }
*
* return newTypedParams; } catch (Exception e) { Logging.logException(e); }
*
* return null; }
*/
static public String StringToString(String in) {
return in;
}
}