root / client / src / com / gonnatrak / JsonServlet.java @ 1

View | Annotate | Download

1
/**
2
 * Created by Andrey Khalzov
3
 * 22.07.2008 23:53:29
4
 */
5
package com.gonnatrak;
6
7
import antlr.RecognitionException;
8
import antlr.TokenStreamException;
9
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
10
import net.sf.json.JSON;
11
import net.sf.json.JSONArray;
12
import net.sf.json.JSONObject;
13
14
import javax.servlet.ServletException;
15
import javax.servlet.http.HttpServlet;
16
import javax.servlet.http.HttpServletRequest;
17
import javax.servlet.http.HttpServletResponse;
18
import java.io.IOException;
19
import java.lang.reflect.InvocationTargetException;
20
import java.lang.reflect.Method;
21
import java.text.ParseException;
22
import java.text.SimpleDateFormat;
23
import java.util.Date;
24
import java.util.concurrent.ConcurrentHashMap;
25
26
public class JsonServlet extends HttpServlet {
27
    private ConcurrentHashMap<Class<? extends RemoteServiceServlet>, ServletMethods> servlets
28
            = new ConcurrentHashMap<Class<? extends RemoteServiceServlet>, ServletMethods>();
29
30
    @SuppressWarnings("unchecked")
31
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
32
        final String[] paths = request.getPathInfo().split("/");
33
        if (paths.length < 3) {
34
            throw new IllegalArgumentException("Wrong path:" + request.getPathInfo());
35
        }
36
        final String className = paths[1];
37
        final String methodName = paths[2];
38
        try {
39
            final Class<? extends RemoteServiceServlet> servletClass
40
                    = (Class<? extends RemoteServiceServlet>) Class.forName("com.gonnatrak.server." + className + "Impl");
41
            ServletMethods servletMethods = servlets.get(servletClass);
42
            if (servletMethods == null) {
43
                final RemoteServiceServlet servlet = servletClass.getConstructor().newInstance();
44
                servletMethods = new ServletMethods(servlet);
45
                servlets.put(servletClass, servletMethods);
46
            }
47
            final String result = servletMethods.invokeMethod(methodName, paths);
48
            final byte[] resultBytes = result.getBytes("utf-8");
49
            response.setContentType("text/javascript; charset=utf-8");
50
            response.setContentLength(resultBytes.length);
51
            response.getOutputStream().write(resultBytes);
52
        } catch (Exception e) {
53
            throw new IllegalArgumentException("Wrong path:" + request.getPathInfo(), e);
54
        }
55
    }
56
57
    class ServletMethods {
58
        final RemoteServiceServlet servlet;
59
        final ConcurrentHashMap<String, Method> methods = new ConcurrentHashMap<String, Method>();
60
61
        ServletMethods(RemoteServiceServlet servlet) {
62
            this.servlet = servlet;
63
        }
64
65
        @SuppressWarnings("unchecked")
66
        String invokeMethod(String methodName, String[] paths)
67
                throws InvocationTargetException, IllegalAccessException, TokenStreamException, RecognitionException
68
        {
69
            Method method = methods.get(methodName);
70
            if (method == null) {
71
                final Method[] methods = servlet.getClass().getMethods();
72
                for (Method _method : methods) {
73
                    if (_method.getName().equals(methodName)) {
74
                        method = _method;
75
                        break;
76
                    }
77
                }
78
                if (method == null) {
79
                    throw new IllegalArgumentException(
80
                            "No such method in " + servlet.getClass().getSimpleName() + ": " + methodName
81
                    );
82
                }
83
                this.methods.put(methodName, method);
84
            }
85
            final Class[] paramClasses = method.getParameterTypes();
86
            final Object[] params = new Object[paramClasses.length];
87
            int i = 0;
88
            for (Class paramClass : paramClasses) {
89
                final String param = paths[i + 3];
90
                params[i++] = paramToPojo(param, paramClass);
91
            }
92
            final Object result = method.invoke(servlet, params);
93
            final JSON jsonResult
94
                    = result.getClass().isArray() ? JSONArray.fromObject(result) : JSONObject.fromObject(result);
95
            return jsonResult.toString();
96
        }
97
    }
98
99
    private Object paramToPojo(String param, Class clazz) {
100
        if (Boolean.class.equals(clazz) || Boolean.TYPE.equals(clazz)) {
101
            return convertBoolean(param, clazz);
102
        } else if (clazz.equals(Date.class)) {
103
            return convertDate(param);
104
        } else if (isNumberClass(clazz)) {
105
            return convertNumber(param, clazz);
106
        } else if (clazz.isEnum()) {
107
            return convertEnum(param, clazz);
108
        } else if (String.class.equals(clazz)) {
109
            return param;
110
        } else {
111
            return JSONObject.toBean(JSONObject.fromObject(param), clazz);
112
        }
113
    }
114
115
    private static Date convertDate(String param) {
116
        if (param.isEmpty()) {
117
            return null;
118
        } else {
119
            try {
120
                return new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ").parse(param);
121
            } catch (ParseException e) {
122
                throw new IllegalArgumentException(e);
123
            }
124
        }
125
    }
126
127
    private boolean isNumberClass(Class clazz) {
128
        return Number.class.isAssignableFrom(clazz) ||
129
                (clazz.isPrimitive()
130
                && (Byte.TYPE.equals(clazz)
131
                    || Short.TYPE.equals(clazz)
132
                    || Integer.TYPE.equals(clazz)
133
                    || Long.TYPE.equals(clazz)
134
                    || Float.TYPE.equals(clazz)
135
                    || Double.TYPE.equals(clazz)
136
                )
137
        );
138
    }
139
140
    private Object convertBoolean(String value, Class clazz) {
141
        if (value.isEmpty()) {
142
            return clazz.isPrimitive() ? Boolean.FALSE : null;
143
        } else {
144
            return Boolean.valueOf(value);
145
        }
146
    }
147
148
    private Object convertNumber(String value, Class clazz) {
149
        if (value.isEmpty()) {
150
            return clazz.isPrimitive() ? 0 : null;
151
        } else {
152
            try {
153
                if (clazz.equals(Byte.class) || Byte.TYPE.equals(clazz)) {
154
                    return Byte.parseByte(value);
155
                } else if (clazz.equals(Short.class) || Short.TYPE.equals(clazz)) {
156
                    return Short.parseShort(value);
157
                } else if (clazz.equals(Integer.class) || Integer.TYPE.equals(clazz)) {
158
                    return Integer.parseInt(value);
159
                } else if (clazz.equals(Long.class) || Long.TYPE.equals(clazz)) {
160
                    return Long.parseLong(value);
161
                } else if (clazz.equals(Float.class) || Float.TYPE.equals(clazz)) {
162
                    return Float.parseFloat(value);
163
                } else if (clazz.equals(Double.class) || Double.TYPE.equals(clazz)) {
164
                    return Double.parseDouble(value);
165
                } else {
166
                    throw new IllegalArgumentException(String.format("Cannot cast <%s> to <%s>", value, clazz.toString()));
167
                }
168
            } catch (NumberFormatException e) {
169
                throw new IllegalArgumentException(String.format("Cannot cast <%s> to <%s>", value, clazz.toString()));
170
            }
171
        }
172
    }
173
174
    private Object convertEnum(String value, Class clazz) {
175
        if (value.isEmpty()) {
176
            return null;
177
        } else {
178
            //noinspection unchecked
179
            return Enum.valueOf(clazz, value);
180
        }
181
    }
182
}