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