001: /*
002: * This file is part of PFIXCORE.
003: *
004: * PFIXCORE is free software; you can redistribute it and/or modify
005: * it under the terms of the GNU Lesser General Public License as published by
006: * the Free Software Foundation; either version 2 of the License, or
007: * (at your option) any later version.
008: *
009: * PFIXCORE is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
012: * GNU Lesser General Public License for more details.
013: *
014: * You should have received a copy of the GNU Lesser General Public License
015: * along with PFIXCORE; if not, write to the Free Software
016: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
017: *
018: */
019:
020: package de.schlund.pfixcore.webservice.jsonqx;
021:
022: import java.io.IOException;
023: import java.io.StringReader;
024: import java.io.Writer;
025: import java.lang.reflect.InvocationTargetException;
026: import java.lang.reflect.Method;
027: import java.lang.reflect.Type;
028: import java.net.URL;
029: import java.util.Calendar;
030: import java.util.Date;
031: import java.util.GregorianCalendar;
032: import java.util.Iterator;
033: import java.util.List;
034:
035: import org.apache.log4j.Logger;
036:
037: import de.schlund.pfixcore.beans.BeanDescriptorFactory;
038: import de.schlund.pfixcore.beans.InitException;
039: import de.schlund.pfixcore.beans.metadata.DefaultLocator;
040: import de.schlund.pfixcore.webservice.ProcessingInfo;
041: import de.schlund.pfixcore.webservice.ServiceCallContext;
042: import de.schlund.pfixcore.webservice.ServiceDescriptor;
043: import de.schlund.pfixcore.webservice.ServiceException;
044: import de.schlund.pfixcore.webservice.ServiceProcessor;
045: import de.schlund.pfixcore.webservice.ServiceRegistry;
046: import de.schlund.pfixcore.webservice.ServiceRequest;
047: import de.schlund.pfixcore.webservice.ServiceResponse;
048: import de.schlund.pfixcore.webservice.ServiceRuntime;
049: import de.schlund.pfixcore.webservice.config.ServiceConfig;
050: import de.schlund.pfixcore.webservice.fault.Fault;
051: import de.schlund.pfixcore.webservice.fault.FaultHandler;
052: import de.schlund.pfixcore.webservice.json.JSONArray;
053: import de.schlund.pfixcore.webservice.json.JSONObject;
054: import de.schlund.pfixcore.webservice.json.parser.JSONParser;
055: import de.schlund.pfixcore.webservice.jsonws.DeserializerRegistry;
056: import de.schlund.pfixcore.webservice.jsonws.JSONDeserializer;
057: import de.schlund.pfixcore.webservice.jsonws.JSONSerializer;
058: import de.schlund.pfixcore.webservice.jsonws.SerializationException;
059: import de.schlund.pfixcore.webservice.jsonws.Serializer;
060: import de.schlund.pfixcore.webservice.jsonws.SerializerRegistry;
061:
062: /**
063: * @author mleidig@schlund.de
064: */
065: public class JSONQXProcessor implements ServiceProcessor {
066:
067: private Logger LOG = Logger.getLogger(JSONQXProcessor.class);
068:
069: private BeanDescriptorFactory beanDescFactory;
070: private SerializerRegistry serializerRegistry;
071: private DeserializerRegistry deserializerRegistry;
072:
073: public JSONQXProcessor(URL defaultBeanMetaDataURL)
074: throws ServiceException {
075: try {
076: beanDescFactory = new BeanDescriptorFactory(
077: new DefaultLocator(defaultBeanMetaDataURL));
078: } catch (InitException x) {
079: throw new ServiceException(
080: "BeanDescriptorFactory initialization failed.", x);
081: }
082: serializerRegistry = new SerializerRegistry(beanDescFactory);
083: Serializer dateSerializer = new CalendarSerializer();
084: serializerRegistry.register(Date.class, dateSerializer);
085: serializerRegistry.register(Calendar.class, dateSerializer);
086: serializerRegistry.register(GregorianCalendar.class,
087: dateSerializer);
088: deserializerRegistry = new DeserializerRegistry(beanDescFactory);
089: }
090:
091: public void process(ServiceRequest req, ServiceResponse res,
092: ServiceRuntime runtime, ServiceRegistry registry,
093: ProcessingInfo procInfo) throws ServiceException {
094:
095: int errorOrigin = 0;
096: int errorCode = 0;
097: Throwable error = null;
098: String serviceName = null;
099: ServiceConfig service = null;
100: JSONObject jsonReq = null;
101: Object resultObject = null;
102: String jsonData = null;
103:
104: try {
105:
106: jsonData = req.getMessage();
107:
108: //Parsing
109: try {
110: long t1 = System.currentTimeMillis();
111: JSONParser parser = new JSONParser(new StringReader(
112: jsonData));
113: jsonReq = (JSONObject) parser.getJSONValue();
114: long t2 = System.currentTimeMillis();
115: if (LOG.isDebugEnabled())
116: LOG.debug("Parsing: " + (t2 - t1) + "ms");
117: } catch (Throwable t) {
118: errorOrigin = 1;
119: throw new ServiceException("Error during parsing", t);
120: }
121:
122: //Service lookup
123: serviceName = jsonReq.getStringMember("service");
124: if (serviceName == null || serviceName.trim().equals("")) {
125: errorOrigin = 1;
126: errorCode = 1;
127: throw new ServiceException("Illegal service name: "
128: + serviceName);
129: } else
130: service = registry.getService(serviceName);
131: if (service == null) {
132: errorOrigin = 1;
133: errorCode = 2;
134: throw new ServiceException("Service not found: "
135: + serviceName);
136: }
137:
138: //Service method lookup
139: Method method = null;
140: JSONArray params = jsonReq.getArrayMember("params");
141: JSONDeserializer jsonDeser = new JSONDeserializer(
142: deserializerRegistry);
143: String methodName = jsonReq.getStringMember("method");
144: ServiceDescriptor serviceDesc = runtime
145: .getServiceDescriptorCache().getServiceDescriptor(
146: service);
147: List<Method> methods = serviceDesc.getMethods(methodName);
148: if (methods.size() == 0) {
149: errorOrigin = 1;
150: errorCode = 4;
151: throw new ServiceException("Method not found: "
152: + methodName);
153: } else if (methods.size() == 1)
154: method = methods.get(0);
155: else {
156: //ambiguous methods, guess the right one
157: Iterator<Method> methIt = methods.iterator();
158: while (methIt.hasNext() && method == null) {
159: Method testMeth = methIt.next();
160: Type[] types = testMeth.getGenericParameterTypes();
161: if (types.length == params.size()) {
162: boolean canDeserialize = true;
163: for (int i = 0; i < params.size()
164: && canDeserialize; i++) {
165: if (!jsonDeser.canDeserialize(
166: params.get(i), types[i]))
167: canDeserialize = false;
168: }
169: if (canDeserialize)
170: method = testMeth;
171: }
172: }
173: }
174: if (method == null) {
175: errorOrigin = 1;
176: errorCode = 5;
177: throw new ServiceException("No matching method found: "
178: + methodName);
179: }
180:
181: //Deserialization
182: Object[] paramObjects = null;
183: try {
184: long t1 = System.currentTimeMillis();
185: paramObjects = new Object[params.size()];
186: Type[] types = method.getGenericParameterTypes();
187: for (int i = 0; i < params.size(); i++) {
188: Object obj = params.get(i);
189: Object deserObj = jsonDeser.deserialize(obj,
190: types[i]);
191: paramObjects[i] = deserObj;
192: }
193: long t2 = System.currentTimeMillis();
194: if (LOG.isDebugEnabled())
195: LOG.debug("Deserialization: " + (t2 - t1) + "ms");
196: } catch (Throwable t) {
197: errorOrigin = 1;
198: throw new ServiceException(
199: "Error during deserialization", t);
200: }
201:
202: procInfo.setService(serviceName);
203: procInfo.setMethod(method.getName());
204: procInfo.startInvocation();
205:
206: //Invocation
207: try {
208: Object serviceObject = registry
209: .getServiceObject(serviceName);
210: resultObject = method.invoke(serviceObject,
211: paramObjects);
212: } catch (Throwable t) {
213: if (t instanceof InvocationTargetException
214: && t.getCause() != null) {
215: errorOrigin = 2;
216: throw t.getCause();
217: } else {
218: errorOrigin = 1;
219: throw new ServiceException(
220: "Error during invocation", t);
221: }
222: }
223:
224: procInfo.endInvocation();
225: if (LOG.isDebugEnabled())
226: LOG.debug("Invocation: " + procInfo.getInvocationTime()
227: + "ms");
228:
229: } catch (Throwable t) {
230: if (errorOrigin == 0)
231: errorOrigin = 1;
232: error = t;
233: LOG.error(error, error);
234: }
235:
236: try {
237:
238: res.setContentType("text/plain");
239: res.setCharacterEncoding("utf-8");
240: Writer writer = res.getMessageWriter();
241: writer.write("{");
242: if (jsonReq.hasMember("id")) {
243: writer.write("\"id\":");
244: writer.write(jsonReq.getMember("id").toString());
245: writer.write(",");
246: }
247: if (error == null) {
248: writer.write("\"result\":");
249: //Serialization
250: long t1 = System.currentTimeMillis();
251: if (resultObject instanceof Void
252: || resultObject == null) {
253: writer.write("null");
254: } else {
255: JSONSerializer jsonSer = new JSONSerializer(
256: serializerRegistry, service
257: .getJSONClassHinting());
258: jsonSer.serialize(resultObject, writer);
259: }
260: long t2 = System.currentTimeMillis();
261: if (LOG.isDebugEnabled())
262: LOG.debug("Serialization: " + (t2 - t1) + "ms");
263: } else {
264: //Handle error
265: LOG.error(error, error);
266: ServiceCallContext callContext = ServiceCallContext
267: .getCurrentContext();
268: Fault fault = new Fault(serviceName, callContext
269: .getServiceRequest(), callContext
270: .getServiceResponse(), jsonData, callContext
271: .getContext());
272: fault.setThrowable(error);
273: FaultHandler faultHandler = service.getFaultHandler();
274: if (faultHandler == null)
275: faultHandler = runtime.getConfiguration()
276: .getGlobalServiceConfig().getFaultHandler();
277: if (faultHandler != null)
278: faultHandler.handleFault(fault);
279: error = fault.getThrowable();
280: JSONObject errobj = new JSONObject();
281: errobj.putMember("origin", errorOrigin);
282: errobj.putMember("code", errorCode);
283: writer.write("\"error\":");
284: writer.write(errobj.toJSONString());
285: }
286: writer.write("}");
287: writer.flush();
288: writer.close();
289:
290: } catch (SerializationException x) {
291: new ServiceException(
292: "Error while processing service request.", x);
293: } catch (IOException x) {
294: new ServiceException(
295: "Error while processing service request.", x);
296: }
297:
298: }
299:
300: public void processException(ServiceRequest req,
301: ServiceResponse res, Exception exception)
302: throws ServiceException {
303: try {
304: res.setContentType("text/plain");
305: res.setCharacterEncoding("utf-8");
306: Writer writer = res.getMessageWriter();
307: writer.write("{");
308: JSONObject errobj = new JSONObject();
309: errobj.putMember("origin", 1);
310: errobj.putMember("code", 6);
311: writer.write("\"error\":");
312: writer.write(errobj.toJSONString());
313: writer.write("}");
314: writer.flush();
315: writer.close();
316: } catch (IOException x) {
317: throw new ServiceException(
318: "IOException during service exception processing.",
319: x);
320: }
321: }
322:
323: }
|