1/*************************************************************************
2 * libjson-rpc-cpp
3 *************************************************************************
4 * @file specificationparser.cpp
5 * @date 12.03.2013
6 * @author Peter Spiess-Knafl <dev@spiessknafl.at>
7 * @license See attached LICENSE.txt
8 ************************************************************************/
9
10#include "specificationparser.h"
11#include <fstream>
12#include <iomanip>
13#include <jsonrpccpp/common/jsonparser.h>
14
15using namespace std;
16using namespace jsonrpc;
17
18vector<Procedure> SpecificationParser::GetProceduresFromFile(const string &filename) {
19 string content;
20 GetFileContent(filename, content);
21 return GetProceduresFromString(content);
22}
23vector<Procedure> SpecificationParser::GetProceduresFromString(const string &content) {
24
25 Json::Value val;
26
27 try {
28 std::istringstream(content) >> val;
29 } catch (Json::Exception &e) {
30 throw JsonRpcException(Errors::ERROR_RPC_JSON_PARSE_ERROR, " specification file contains syntax errors");
31 }
32 if (!val.isArray()) {
33 throw JsonRpcException(Errors::ERROR_SERVER_PROCEDURE_SPECIFICATION_SYNTAX, " top level json value is not an array");
34 }
35
36 vector<Procedure> result;
37 map<string, Procedure> procnames;
38 for (unsigned int i = 0; i < val.size(); i++) {
39 Procedure proc;
40 GetProcedure(val[i], proc);
41 if (procnames.find(proc.GetProcedureName()) != procnames.end()) {
42 throw JsonRpcException(Errors::ERROR_SERVER_PROCEDURE_SPECIFICATION_SYNTAX, "Procedurename not unique: " + proc.GetProcedureName());
43 }
44 procnames[proc.GetProcedureName()] = proc;
45 result.push_back(proc);
46 }
47 return result;
48}
49void SpecificationParser::GetProcedure(Json::Value &signature, Procedure &result) {
50 if (signature.isObject() && !GetProcedureName(signature).empty()) {
51 result.SetProcedureName(GetProcedureName(signature));
52 if (signature.isMember(KEY_SPEC_RETURN_TYPE)) {
53 result.SetProcedureType(RPC_METHOD);
54 result.SetReturnType(toJsonType(signature[KEY_SPEC_RETURN_TYPE]));
55 } else {
56 result.SetProcedureType(RPC_NOTIFICATION);
57 }
58 if (signature.isMember(KEY_SPEC_PROCEDURE_PARAMETERS)) {
59 if (signature[KEY_SPEC_PROCEDURE_PARAMETERS].isObject() || signature[KEY_SPEC_PROCEDURE_PARAMETERS].isArray()) {
60 if (signature[KEY_SPEC_PROCEDURE_PARAMETERS].isArray()) {
61 result.SetParameterDeclarationType(PARAMS_BY_POSITION);
62 GetPositionalParameters(signature, result);
63 } else if (signature[KEY_SPEC_PROCEDURE_PARAMETERS].isObject()) {
64 result.SetParameterDeclarationType(PARAMS_BY_NAME);
65 GetNamedParameters(signature, result);
66 }
67 } else {
68 throw JsonRpcException(Errors::ERROR_SERVER_PROCEDURE_SPECIFICATION_SYNTAX, "Invalid signature types in fileds: " + signature.toStyledString());
69 }
70 }
71 } else {
72 throw JsonRpcException(Errors::ERROR_SERVER_PROCEDURE_SPECIFICATION_SYNTAX,
73 "procedure declaration does not contain name or parameters: " + signature.toStyledString());
74 }
75}
76void SpecificationParser::GetFileContent(const std::string &filename, std::string &target) {
77 ifstream config(filename.c_str());
78
79 if (config) {
80 config.open(filename.c_str(), ios::in);
81 target.assign((std::istreambuf_iterator<char>(config)), (std::istreambuf_iterator<char>()));
82 } else {
83 throw JsonRpcException(Errors::ERROR_SERVER_PROCEDURE_SPECIFICATION_NOT_FOUND, filename);
84 }
85}
86jsontype_t SpecificationParser::toJsonType(Json::Value &val) {
87 jsontype_t result;
88 switch (val.type()) {
89 case Json::uintValue:
90 case Json::intValue:
91 result = JSON_INTEGER;
92 break;
93 case Json::realValue:
94 result = JSON_REAL;
95 break;
96 case Json::stringValue:
97 result = JSON_STRING;
98 break;
99 case Json::booleanValue:
100 result = JSON_BOOLEAN;
101 break;
102 case Json::arrayValue:
103 result = JSON_ARRAY;
104 break;
105 case Json::objectValue:
106 result = JSON_OBJECT;
107 break;
108 default:
109 throw JsonRpcException(Errors::ERROR_SERVER_PROCEDURE_SPECIFICATION_SYNTAX, "Unknown parameter type: " + val.toStyledString());
110 }
111 return result;
112}
113void SpecificationParser::GetPositionalParameters(Json::Value &val, Procedure &result) {
114 // Positional parameters
115 for (unsigned int i = 0; i < val[KEY_SPEC_PROCEDURE_PARAMETERS].size(); i++) {
116 stringstream paramname;
117 paramname << "param" << std::setfill('0') << std::setw(2) << (i + 1);
118 result.AddParameter(paramname.str(), toJsonType(val[KEY_SPEC_PROCEDURE_PARAMETERS][i]));
119 }
120}
121void SpecificationParser::GetNamedParameters(Json::Value &val, Procedure &result) {
122 vector<string> parameters = val[KEY_SPEC_PROCEDURE_PARAMETERS].getMemberNames();
123 for (unsigned int i = 0; i < parameters.size(); ++i) {
124 result.AddParameter(parameters.at(i), toJsonType(val[KEY_SPEC_PROCEDURE_PARAMETERS][parameters.at(i)]));
125 }
126}
127
128string SpecificationParser::GetProcedureName(Json::Value &signature) {
129 if (signature[KEY_SPEC_PROCEDURE_NAME].isString())
130 return signature[KEY_SPEC_PROCEDURE_NAME].asString();
131
132 if (signature[KEY_SPEC_PROCEDURE_METHOD].isString())
133 return signature[KEY_SPEC_PROCEDURE_METHOD].asString();
134
135 if (signature[KEY_SPEC_PROCEDURE_NOTIFICATION].isString())
136 return signature[KEY_SPEC_PROCEDURE_NOTIFICATION].asString();
137 return "";
138}
139