1 /*
2 * Copyright (C) 2011 Tommi Maekitalo
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * As a special exception, you may use this file as part of a free
10 * software library without restriction. Specifically, if other files
11 * instantiate templates or use macros or inline functions from this
12 * file, or you compile this file and link it with other files to
13 * produce an executable, this file does not by itself cause the
14 * resulting executable to be covered by the GNU General Public
15 * License. This exception does not however invalidate any other
16 * reasons why the executable file might be covered by the GNU Library
17 * General Public License.
18 *
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
23 *
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
27 */
28
29 #include "responder.h"
30 #include "rpcserverimpl.h"
31 #include <cxxtools/serviceprocedure.h>
32 #include <cxxtools/serviceregistry.h>
33 #include <cxxtools/remoteexception.h>
34 #include <cxxtools/textstream.h>
35 #include <cxxtools/utf8codec.h>
36 #include <cxxtools/log.h>
37
38 log_define("cxxtools.json.responder")
39
40 namespace cxxtools
41 {
42 namespace json
43 {
Responder(ServiceRegistry & serviceRegistry)44 Responder::Responder(ServiceRegistry& serviceRegistry)
45 : _serviceRegistry(serviceRegistry)
46 {
47 }
48
~Responder()49 Responder::~Responder()
50 {
51 }
52
begin()53 void Responder::begin()
54 {
55 _deserializer.begin();
56 _parser.begin(_deserializer);
57 }
58
finalize(std::ostream & out)59 void Responder::finalize(std::ostream& out)
60 {
61 log_trace("finalize");
62
63 std::string methodName;
64 ServiceProcedure* proc = 0;
65
66 TextOStream ts(out, new Utf8Codec());
67 JsonFormatter formatter;
68
69 formatter.begin(ts);
70
71 formatter.beginObject(std::string(), std::string());
72 formatter.addValueString("jsonrpc", "string", L"2.0");
73
74 try
75 {
76 _deserializer.si()->getMember("method") >>= methodName;
77
78 log_debug("method = " << methodName);
79 proc = _serviceRegistry.getProcedure(methodName);
80 if( ! proc )
81 throw std::runtime_error("no such procedure \"" + methodName + '"');
82
83 // compose arguments
84 IComposer** args = proc->beginCall();
85
86 // process args
87 const SerializationInfo* paramsPtr = _deserializer.si()->findMember("params");
88
89 // params may be ommited in request
90 SerializationInfo emptyParams;
91
92 const SerializationInfo& params = paramsPtr ? *paramsPtr : emptyParams;
93
94 SerializationInfo::ConstIterator it = params.begin();
95 if (args)
96 {
97 for (int a = 0; args[a]; ++a)
98 {
99 if (it == params.end())
100 throw RemoteException("argument expected");
101 args[a]->fixup(*it);
102 ++it;
103 }
104 }
105
106 if (it != params.end())
107 throw RemoteException("too many arguments");
108
109 IDecomposer::formatEach(_deserializer.si()->getMember("id"), formatter);
110
111 IDecomposer* result;
112 result = proc->endCall();
113
114 formatter.beginValue("result");
115 result->format(formatter);
116 formatter.finishValue();
117 }
118 catch (const RemoteException& e)
119 {
120 log_debug("method \"" << methodName << "\" exited with RemoteException: " << e.what());
121
122 formatter.beginObject("error", std::string());
123
124 formatter.addValueInt("code", "int", static_cast<Formatter::int_type>(e.rc()));
125 formatter.addValueStdString("message", std::string(), e.what());
126
127 formatter.finishObject();
128 }
129 catch (const std::exception& e)
130 {
131 log_debug("method \"" << methodName << "\" exited with exception: " << e.what());
132 formatter.addValueStdString("error", std::string(), e.what());
133 }
134
135 formatter.finishObject();
136
137 if (proc)
138 _serviceRegistry.releaseProcedure(proc);
139 }
140
advance(char ch)141 bool Responder::advance(char ch)
142 {
143 return _parser.advance(ch) != 0;
144 }
145
146 }
147 }
148