Source Code Cross Referenced for JSONRPCCallingConvention.java in  » Web-Services » xins » org » xins » server » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Web Services » xins » org.xins.server 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * $Id: JSONRPCCallingConvention.java,v 1.21 2007/09/18 08:45:03 agoubard Exp $
003:         *
004:         * Copyright 2003-2007 Orange Nederland Breedband B.V.
005:         * See the COPYRIGHT file for redistribution and use restrictions.
006:         */
007:        package org.xins.server;
008:
009:        import java.io.IOException;
010:        import java.io.PrintWriter;
011:        import java.io.Reader;
012:        import java.io.StringReader;
013:        import java.util.Iterator;
014:        import java.util.Map;
015:        import java.util.Properties;
016:
017:        import javax.servlet.http.HttpServletRequest;
018:        import javax.servlet.http.HttpServletResponse;
019:
020:        import org.json.JSONArray;
021:        import org.json.JSONException;
022:        import org.json.JSONObject;
023:        import org.json.XML;
024:
025:        import org.xins.common.MandatoryArgumentChecker;
026:        import org.xins.common.Utils;
027:        import org.xins.common.collections.BasicPropertyReader;
028:        import org.xins.common.collections.PropertyReader;
029:        import org.xins.common.collections.PropertyReaderConverter;
030:        import org.xins.common.spec.APISpec;
031:        import org.xins.common.spec.EntityNotFoundException;
032:        import org.xins.common.spec.ErrorCodeSpec;
033:        import org.xins.common.spec.FunctionSpec;
034:        import org.xins.common.spec.InvalidSpecificationException;
035:        import org.xins.common.spec.ParameterSpec;
036:        import org.xins.common.text.ParseException;
037:        import org.xins.common.types.Type;
038:        import org.xins.common.xml.Element;
039:        import org.xins.common.xml.ElementParser;
040:        import org.xins.logdoc.ExceptionUtils;
041:
042:        /**
043:         * The JSON-RPC calling convention.
044:         * Version <a href='http://json-rpc.org/wiki/specification'>1.0</a>
045:         * and <a href='http://json-rpc.org/wd/JSON-RPC-1-1-WD-20060807.html'>1.1</a> are supported.
046:         * The service description is also returned on request when calling the
047:         * <em>system.describe</em> function.
048:         * The returned object is a JSON Object with a similar structure as the input
049:         * parameters when HTTP POST is used.
050:         *
051:         * @since XINS 2.0.
052:         * @version $Revision: 1.21 $ $Date: 2007/09/18 08:45:03 $
053:         * @author <a href="mailto:anthony.goubard@japplis.com">Anthony Goubard</a>
054:         */
055:        public class JSONRPCCallingConvention extends CallingConvention {
056:
057:            /**
058:             * The content type of the HTTP response.
059:             */
060:            protected static final String RESPONSE_CONTENT_TYPE = "application/json";
061:
062:            /**
063:             * The API. Never <code>null</code>.
064:             */
065:            private final API _api;
066:
067:            /**
068:             * Creates a new <code>JSONRPCCallingConvention</code> instance.
069:             *
070:             * @param api
071:             *    the API, needed for the JSON-RPC messages, cannot be <code>null</code>.
072:             *
073:             * @throws IllegalArgumentException
074:             *    if <code>api == null</code>.
075:             */
076:            public JSONRPCCallingConvention(API api)
077:                    throws IllegalArgumentException {
078:                MandatoryArgumentChecker.check("api", api);
079:                _api = api;
080:            }
081:
082:            /**
083:             * Returns the XML-RPC equivalent for the XINS type.
084:             *
085:             * @param parameterType
086:             *    the XINS type, cannot be <code>null</code>.
087:             *
088:             * @return
089:             *    the XML-RPC type, never <code>null</code>.
090:             */
091:            private static String convertType(Type parameterType) {
092:                if (parameterType instanceof  org.xins.common.types.standard.Boolean) {
093:                    return "bit";
094:                } else if (parameterType instanceof  org.xins.common.types.standard.Int8
095:                        || parameterType instanceof  org.xins.common.types.standard.Int16
096:                        || parameterType instanceof  org.xins.common.types.standard.Int32
097:                        || parameterType instanceof  org.xins.common.types.standard.Int64
098:                        || parameterType instanceof  org.xins.common.types.standard.Float32
099:                        || parameterType instanceof  org.xins.common.types.standard.Float64) {
100:                    return "num";
101:                } else {
102:                    return "str";
103:                }
104:            }
105:
106:            protected String[] getSupportedMethods() {
107:                return new String[] { "GET", "POST" };
108:            }
109:
110:            protected boolean matches(HttpServletRequest httpRequest)
111:                    throws Exception {
112:
113:                // Note that matches will only accept calls that matches the 1.1 specification of JSON-RPC.
114:                if (httpRequest.getHeader("User-Agent") == null) {
115:                    return false;
116:                }
117:                if (!"application/json".equals(httpRequest.getHeader("Accept"))) {
118:                    return false;
119:                }
120:                if ("post".equalsIgnoreCase(httpRequest.getMethod())) {
121:                    return "application/json".equals(httpRequest
122:                            .getContentType());
123:                }
124:                return true;
125:            }
126:
127:            protected FunctionRequest convertRequestImpl(
128:                    HttpServletRequest httpRequest)
129:                    throws InvalidRequestException,
130:                    FunctionNotSpecifiedException {
131:
132:                if ("post".equalsIgnoreCase(httpRequest.getMethod())) {
133:                    return parsePostRequest(httpRequest);
134:                } else if ("get".equalsIgnoreCase(httpRequest.getMethod())) {
135:                    return parseGetRequest(httpRequest);
136:                } else {
137:                    throw new InvalidRequestException("Incorrect HTTP method: "
138:                            + httpRequest.getMethod());
139:                }
140:            }
141:
142:            protected void convertResultImpl(FunctionResult xinsResult,
143:                    HttpServletResponse httpResponse,
144:                    HttpServletRequest httpRequest) throws IOException {
145:
146:                // Send the XML output to the stream and flush
147:                httpResponse.setContentType(RESPONSE_CONTENT_TYPE);
148:                PrintWriter out = httpResponse.getWriter();
149:                httpResponse.setStatus(HttpServletResponse.SC_OK);
150:
151:                // Return the service description when asked.
152:                String functionName = (String) httpRequest.getSession()
153:                        .getAttribute("functionName");
154:                if ("system.describe".equals(functionName)) {
155:                    String uri = httpRequest.getRequestURI();
156:                    if (uri.indexOf("system.describe") != -1) {
157:                        uri = uri.substring(0, uri.indexOf("system.describe"));
158:                    }
159:                    try {
160:                        JSONObject serviceDescriptionObject = createServiceDescriptionObject(uri);
161:                        out.print(serviceDescriptionObject.toString());
162:                        out.close();
163:                        return;
164:                    } catch (JSONException jsonex) {
165:                        throw new IOException(jsonex.getMessage());
166:                    }
167:                }
168:
169:                // Transform the XINS result to a JSON object
170:                JSONObject returnObject = new JSONObject();
171:                try {
172:                    String version = (String) httpRequest.getSession()
173:                            .getAttribute("version");
174:                    if (version != null) {
175:                        returnObject.put("version", version);
176:                    }
177:                    if (xinsResult.getErrorCode() != null) {
178:                        if (version == null) {
179:                            returnObject.put("result", JSONObject.NULL);
180:                            returnObject
181:                                    .put("error", xinsResult.getErrorCode());
182:                        } else {
183:                            JSONObject errorObject = new JSONObject();
184:                            String errorCode = xinsResult.getErrorCode();
185:                            errorObject.put("name", errorCode);
186:                            errorObject.put("code", new Integer(123));
187:                            errorObject.put("message", getErrorDescription(
188:                                    functionName, errorCode));
189:                            JSONObject paramsObject = createResultObject(xinsResult);
190:                            errorObject.put("error", paramsObject);
191:                            returnObject.put("error", errorObject);
192:                        }
193:                    } else {
194:                        JSONObject paramsObject = createResultObject(xinsResult);
195:                        returnObject.put("result", paramsObject);
196:                        if (version == null) {
197:                            returnObject.put("error", JSONObject.NULL);
198:                        }
199:                    }
200:                    Object requestId = httpRequest.getSession().getAttribute(
201:                            "id");
202:                    if (requestId != null) {
203:                        returnObject.put("id", requestId);
204:                    }
205:
206:                    // Write the result to the servlet response
207:                    String returnString = returnObject.toString();
208:                    out.print(returnString);
209:                } catch (JSONException jsonex) {
210:                    throw new IOException(jsonex.getMessage());
211:                }
212:
213:                out.close();
214:            }
215:
216:            /**
217:             * Parses the JSON-RPC HTTP GET request according to the specs.
218:             *
219:             * @param httpRequest
220:             *    the HTTP request.
221:             *
222:             * @return
223:             *    the XINS request object, should not be <code>null</code>.
224:             *
225:             * @throws InvalidRequestException
226:             *    if the request is considerd to be invalid.
227:             *
228:             * @throws FunctionNotSpecifiedException
229:             *    if the request does not indicate the name of the function to execute.
230:             */
231:            private FunctionRequest parseGetRequest(
232:                    HttpServletRequest httpRequest)
233:                    throws InvalidRequestException,
234:                    FunctionNotSpecifiedException {
235:                String functionName;
236:                PropertyReader functionParams;
237:                Element dataElement = null;
238:
239:                String pathInfo = httpRequest.getPathInfo();
240:                if (pathInfo.lastIndexOf("/") == pathInfo.length() - 1) {
241:                    throw new FunctionNotSpecifiedException();
242:                } else {
243:                    functionName = pathInfo
244:                            .substring(pathInfo.lastIndexOf("/") + 1);
245:                }
246:                httpRequest.getSession(true).setAttribute("functionName",
247:                        functionName);
248:                if (functionName.equals("system.describe")) {
249:                    return new FunctionRequest(functionName, null, null, true);
250:                }
251:                httpRequest.getSession().setAttribute("version", "1.1");
252:                functionParams = gatherParams(httpRequest);
253:
254:                // Get data section
255:                String dataSectionValue = httpRequest.getParameter("_data");
256:                if (dataSectionValue != null && dataSectionValue.length() > 0) {
257:                    ElementParser parser = new ElementParser();
258:                    try {
259:                        dataElement = parser.parse(new StringReader(
260:                                dataSectionValue));
261:
262:                        // I/O error, should never happen on a StringReader
263:                    } catch (IOException exception) {
264:                        throw Utils.logProgrammingError(exception);
265:
266:                        // Parsing error
267:                    } catch (ParseException exception) {
268:                        String detail = "Cannot parse the data section.";
269:                        throw new InvalidRequestException(detail, exception);
270:                    }
271:                }
272:                return new FunctionRequest(functionName, functionParams,
273:                        dataElement);
274:            }
275:
276:            /**
277:             * Parses the JSON-RPC HTTP POST request according to the specs.
278:             * http://json-rpc.org/wd/JSON-RPC-1-1-WD-20060807.html
279:             *
280:             * @param httpRequest
281:             *    the HTTP request.
282:             *
283:             * @return
284:             *    the XINS request object, should not be <code>null</code>.
285:             *
286:             * @throws InvalidRequestException
287:             *    if the request is considerd to be invalid.
288:             *
289:             * @throws FunctionNotSpecifiedException
290:             *    if the request does not indicate the name of the function to execute.
291:             */
292:            private FunctionRequest parsePostRequest(
293:                    HttpServletRequest httpRequest)
294:                    throws InvalidRequestException,
295:                    FunctionNotSpecifiedException {
296:                String functionName;
297:                BasicPropertyReader functionParams = new BasicPropertyReader();
298:                Element dataElement = null;
299:
300:                // Read the message
301:                // TODO replace with IOReader.readFully()
302:                StringBuffer requestBuffer = new StringBuffer(2048);
303:                try {
304:                    Reader reader = httpRequest.getReader();
305:                    char[] buffer = new char[2048];
306:                    int length;
307:                    while ((length = reader.read(buffer)) != -1) {
308:                        requestBuffer.append(buffer, 0, length);
309:                    }
310:                } catch (IOException ioe) {
311:                    throw new InvalidRequestException(
312:                            "I/O Error while reading the request: "
313:                                    + ioe.getMessage());
314:                }
315:                String requestString = requestBuffer.toString();
316:
317:                // Extract the request from the message
318:                try {
319:                    JSONObject requestObject = new JSONObject(requestString);
320:
321:                    Object version = requestObject.opt("version");
322:                    if (version != null) {
323:                        httpRequest.getSession(true).setAttribute("version",
324:                                (String) version);
325:                    }
326:
327:                    functionName = requestObject.getString("method");
328:                    httpRequest.getSession(true).setAttribute("functionName",
329:                            functionName);
330:                    if (functionName.equals("system.describe")) {
331:                        return new FunctionRequest(functionName, null, null,
332:                                true);
333:                    }
334:
335:                    Object paramsParam = requestObject.get("params");
336:                    if (paramsParam instanceof  JSONArray) {
337:                        JSONArray paramsArray = (JSONArray) paramsParam;
338:                        Iterator itInputParams = _api.getAPISpecification()
339:                                .getFunction(functionName).getInputParameters()
340:                                .keySet().iterator();
341:                        int paramPos = 0;
342:                        while (itInputParams.hasNext()
343:                                && paramPos < paramsArray.length()) {
344:                            String nextParamName = (String) itInputParams
345:                                    .next();
346:                            Object nextParamValue = paramsArray.get(paramPos);
347:                            functionParams.set(nextParamName, String
348:                                    .valueOf(nextParamValue));
349:                            paramPos++;
350:                        }
351:                    } else if (paramsParam instanceof  JSONObject) {
352:                        JSONObject paramsObject = (JSONObject) paramsParam;
353:                        JSONArray paramNames = paramsObject.names();
354:                        for (int i = 0; i < paramNames.length(); i++) {
355:                            String nextName = paramNames.getString(i);
356:                            if (nextName.equals("_data")) {
357:                                JSONObject dataSectionObject = paramsObject
358:                                        .getJSONObject("_data");
359:                                String dataSectionString = XML
360:                                        .toString(dataSectionObject);
361:                                dataElement = new ElementParser()
362:                                        .parse(dataSectionString);
363:                            } else {
364:                                String value = paramsObject.get(nextName)
365:                                        .toString();
366:                                functionParams.set(nextName, value);
367:                            }
368:                        }
369:                    }
370:                    Object id = requestObject.opt("id");
371:                    if (id != null) {
372:                        httpRequest.getSession().setAttribute("id", id);
373:                    }
374:                } catch (ParseException parseEx) {
375:                    throw new InvalidRequestException(parseEx.getMessage());
376:                } catch (JSONException jsonex) {
377:                    throw new InvalidRequestException(jsonex.getMessage());
378:                } catch (InvalidSpecificationException isex) {
379:                    RuntimeException exception = new RuntimeException();
380:                    ExceptionUtils.setCause(exception, isex);
381:                    throw exception;
382:                } catch (EntityNotFoundException enfex) {
383:                    RuntimeException exception = new RuntimeException();
384:                    ExceptionUtils.setCause(exception, enfex);
385:                    throw exception;
386:                }
387:                return new FunctionRequest(functionName, functionParams,
388:                        dataElement);
389:            }
390:
391:            /**
392:             * Creates the JSON object from the result returned by the function.
393:             *
394:             * @param xinsResult
395:             *    the result returned by the function, cannot be <code>null</code>.
396:             *
397:             * @return
398:             *    the JSON object created from the result of the function, never <code>null</code>.
399:             *
400:             * @throws JSONException
401:             *    if the object cannot be created for any reason.
402:             */
403:            static JSONObject createResultObject(FunctionResult xinsResult)
404:                    throws JSONException {
405:                Properties params = PropertyReaderConverter
406:                        .toProperties(xinsResult.getParameters());
407:                JSONObject paramsObject = new JSONObject(params);
408:                if (xinsResult.getDataElement() != null) {
409:                    String dataSection = xinsResult.getDataElement().toString();
410:                    JSONObject dataSectionObject = XML
411:                            .toJSONObject(dataSection);
412:                    paramsObject.accumulate("data", dataSectionObject);
413:                }
414:                return paramsObject;
415:            }
416:
417:            /**
418:             * Creates the JSON object containing the description of the API.
419:             * Specifications are available at http://json-rpc.org/wd/JSON-RPC-1-1-WD-20060807.html
420:             *
421:             * @param address
422:             *    the URL address of the service, cannot be <code>null</code>.
423:             *
424:             * @return
425:             *    the JSON object containing the description of the API, or <code>null</code>
426:             *    if an error occured.
427:             *
428:             * @throws JSONException
429:             *    if the object cannot be created for any reason.
430:             */
431:            private JSONObject createServiceDescriptionObject(String address)
432:                    throws JSONException {
433:                JSONObject serviceObject = new JSONObject();
434:                serviceObject.put("sdversion", "1.0");
435:                serviceObject.put("name", _api.getName());
436:                String apiClassName = _api.getClass().getName();
437:                serviceObject.put("id", "xins:"
438:                        + apiClassName.substring(0, apiClassName
439:                                .indexOf(".api.API")));
440:                serviceObject.put("version", _api.getBootstrapProperties().get(
441:                        API.API_VERSION_PROPERTY));
442:                try {
443:                    APISpec apiSpec = _api.getAPISpecification();
444:                    String description = apiSpec.getDescription();
445:                    serviceObject.put("summary", description);
446:                    serviceObject.put("address", address);
447:
448:                    // Add the functions
449:                    JSONArray procs = new JSONArray();
450:                    Iterator itFunctions = apiSpec.getFunctions().entrySet()
451:                            .iterator();
452:                    while (itFunctions.hasNext()) {
453:                        Map.Entry nextFunction = (Map.Entry) itFunctions.next();
454:                        JSONObject functionObject = new JSONObject();
455:                        functionObject.put("name", (String) nextFunction
456:                                .getKey());
457:                        FunctionSpec functionSpec = (FunctionSpec) nextFunction
458:                                .getValue();
459:                        functionObject.put("summary", functionSpec
460:                                .getDescription());
461:                        JSONArray params = getParamsDescription(functionSpec
462:                                .getInputParameters(), functionSpec
463:                                .getInputDataSectionElements());
464:                        functionObject.put("params", params);
465:                        JSONArray result = getParamsDescription(functionSpec
466:                                .getOutputParameters(), functionSpec
467:                                .getOutputDataSectionElements());
468:                        functionObject.put("return", result);
469:                    }
470:                    serviceObject.put("procs", procs);
471:                } catch (InvalidSpecificationException ex) {
472:                    return serviceObject;
473:                }
474:                return serviceObject;
475:            }
476:
477:            /**
478:             * Returns the description of the input or output parameters.
479:             *
480:             * @param paramsSpecs
481:             *    the specification of the input of output parameters, cannot be <code>null</code>.
482:             *
483:             * @param dataSectionSpecs
484:             *    the specification of the input of output data section, cannot be <code>null</code>.
485:             *
486:             * @return
487:             *    the JSON array containing the description of the input or output parameters, never <code>null</code>.
488:             *
489:             * @throws JSONException
490:             *    if the JSON object cannot be created.
491:             */
492:            static JSONArray getParamsDescription(Map paramsSpecs,
493:                    Map dataSectionSpecs) throws JSONException {
494:                JSONArray params = new JSONArray();
495:                Iterator itParams = paramsSpecs.entrySet().iterator();
496:                while (itParams.hasNext()) {
497:                    Map.Entry nextParam = (Map.Entry) itParams.next();
498:                    JSONObject paramObject = new JSONObject();
499:                    paramObject.put("name", (String) nextParam.getKey());
500:                    String jsonType = convertType(((ParameterSpec) nextParam
501:                            .getValue()).getType());
502:                    paramObject.put("type", jsonType);
503:                    params.put(paramObject);
504:                    // TODO data section
505:                }
506:                return params;
507:            }
508:
509:            /**
510:             * Gets a description of the error.
511:             *
512:             * @param functionName
513:             *   the name of the function called, cannot be <code>null</code>.
514:             * @param errorCode
515:             *   the error code returned by the function, cannot be <code>null</code>.
516:             *
517:             * @return
518:             *    a single sentence containing the description of the error.
519:             */
520:            private String getErrorDescription(String functionName,
521:                    String errorCode) {
522:                if (errorCode.equals("_InvalidRequest")) {
523:                    return "The request is invalid.";
524:                } else if (errorCode.equals("_InvalidResponse")) {
525:                    return "The response is invalid.";
526:                } else if (errorCode.equals("_DisabledFunction")) {
527:                    return "The \"" + functionName + "\" function is disabled.";
528:                } else if (errorCode.equals("_InternalError")) {
529:                    return "There was an internal error.";
530:                }
531:                try {
532:                    ErrorCodeSpec errorSpec = _api.getAPISpecification()
533:                            .getFunction(functionName).getErrorCode(errorCode);
534:                    String errorDescription = errorSpec.getDescription();
535:                    if (errorDescription.indexOf(". ") != -1) {
536:                        errorDescription = errorDescription.substring(0,
537:                                errorDescription.indexOf(". "));
538:                    } else if (errorDescription.indexOf(".\n") != -1) {
539:                        errorDescription = errorDescription.substring(0,
540:                                errorDescription.indexOf(".\n"));
541:                    }
542:                    return errorDescription;
543:                } catch (Exception ex) {
544:                    return "Unknown error: \"" + errorCode + "\".";
545:                }
546:            }
547:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.