package com.rafali.flickruploader; import java.io.BufferedReader; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.Map; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.rafali.common.ToolString; public class AndroidRpc extends HttpServlet { private static final long serialVersionUID = 1L; private static final Logger logger = LoggerFactory.getLogger(AndroidRpc.class.getPackage().getName()); public static final int appMinimalSupportedVersionCode = 33; public static final int appCurrentVersionCode = 33; private static int appServerVersion = 0; private static final AndroidRpcImpl androidRpcImpl = new AndroidRpcImpl(); private static final Map<String, Method> methods = new HashMap<String, Method>(); static { for (Method javaMethod : AndroidRpcImpl.class.getMethods()) { String key = javaMethod.getName() + "_" + javaMethod.getParameterTypes().length; if (methods.containsKey(key)) { logger.error("duplicate method name : " + key); } methods.put(key, javaMethod); } } @SuppressWarnings("rawtypes") @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String appVersionCode = req.getHeader("rafali-versionCode"); resp.addHeader("Content-Type", "application/xml"); // logger.debug(req.toString()); if (Integer.valueOf(appVersionCode) >= appMinimalSupportedVersionCode) { resp.addHeader("rafali-appServerVersion", "" + appServerVersion); resp.addHeader("rafali-appMinimalSupportedVersionCode", "" + appMinimalSupportedVersionCode); resp.addHeader("rafali-appCurrentVersionCode", "" + appCurrentVersionCode); String method = req.getParameter("method"); String data = getData(req); Object[] args_logs = ToolStream.decodeGzip(data); Object[] args = (Object[]) args_logs[0]; Object obj = null; String key = method + "_" + args.length; Method jMethod = methods.get(key); if (jMethod != null) { logger.debug("method : " + jMethod.getName() + ", version : " + appVersionCode + ", args : " + Arrays.toString(args)); try { if (obj == null) obj = jMethod.invoke(androidRpcImpl, args); } catch (InvocationTargetException e) { obj = e.getTargetException(); } catch (Throwable e) { obj = e; } } else { logger.error("unmapped method : " + method); } if (obj != null) { if (obj instanceof Throwable) { Throwable e = (Throwable) obj; if (e instanceof RuntimeException && e.getMessage() != null && e.getMessage().contains("Wrong userId/deviceId")) { // ignore } else { logger.error(e.getClass().getSimpleName() + " while " + method + "\n" + ToolString.stack2string(e)); } } else { if (obj instanceof Collection) { Collection collection = (Collection) obj; if (collection == null || collection.isEmpty()) { logger.debug("androidRpc return empty list"); } else { logger.debug("androidRpc return " + collection.size() + " " + collection.iterator().next().getClass().getSimpleName()); } } else if (obj instanceof Object[]) { logger.debug("androidRpc return Object[] : " + Arrays.toString((Object[]) obj)); } else if (obj instanceof double[]) { logger.debug("androidRpc return double[] : " + Arrays.toString((double[]) obj)); } else if (obj instanceof String[]) { logger.debug("androidRpc return String[] : " + Arrays.toString((String[]) obj)); } else { logger.debug("androidRpc return : " + obj); } } String base64 = ToolStream.encode(obj); resp.getWriter().println(base64); } } } private static String getData(HttpServletRequest req) throws IOException { BufferedReader reader = req.getReader(); StringBuilder sb = new StringBuilder(); String line = reader.readLine(); while (line != null) { sb.append(line + "\n"); line = reader.readLine(); } reader.close(); return sb.toString(); } }