1 /***************************************************************************
2 introspect.cpp -- lists information about available methods
3
4 copyright : (C) 2002-2007 by Ewald Arnold
5 email : ulxmlrpcpp@ewald-arnold.de
6
7 $Id: introspect.cpp 1151 2009-08-12 15:12:01Z ewald-arnold $
8
9 ***************************************************************************/
10
11 /**************************************************************************
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU Lesser General Public License as
15 * published by the Free Software Foundation; either version 2 of the License,
16 * or (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU Lesser General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 *
27 ***************************************************************************/
28
29 #include <ulxmlrpcpp/ulxmlrpcpp.h> // always first header
30
31 #include <cstdlib>
32 #include <cstdio>
33
34 #include <ulxmlrpcpp/ulxr_tcpip_connection.h> // first, don't move: important msvc #include bug
35 #include <ulxmlrpcpp/ulxr_requester.h>
36 #include <ulxmlrpcpp/ulxr_value.h>
37 #include <ulxmlrpcpp/ulxr_except.h>
38 #include <ulxmlrpcpp/ulxr_http_protocol.h>
39 #include <ulxmlrpcpp/ulxr_log4j.h>
40
41 using namespace ulxr;
42
43 #include <iostream>
44
splitUrl(const std::string & url,ulxr::CppString & server,ulxr::CppString & resource,unsigned & port)45 bool splitUrl(const std::string &url,
46 ulxr::CppString &server,
47 ulxr::CppString &resource,
48 unsigned &port)
49 {
50 server = ULXR_GET_STRING(url);
51 std::size_t pos;
52
53 if ((pos = server.find('/') ) != ulxr::CppString::npos)
54 {
55 resource = server.substr(pos);
56 server.erase(pos);
57 }
58
59 if ((pos = server.find(':')) != ulxr::CppString::npos)
60 {
61 ulxr::CppString ps = server.substr(pos+1);
62 char *endp;
63 std::string s = getLatin1(ps);
64 port = strtol(s.c_str(), &endp, 10);
65 if (endp != 0 && *endp != '\0')
66 {
67 ULXR_CERR << ULXR_PCHAR( "Error in port number: ")
68 << ULXR_GET_STRING(endp) << ULXR_PCHAR("\n\n");
69 return false;
70 }
71 server.erase(pos);
72 }
73
74 return true;
75 }
76
77
usage()78 void usage()
79 {
80 ULXR_CERR << ULXR_PCHAR("usage:\n")
81 << ULXR_PCHAR(" --host=server:port/resource \n")
82 << ULXR_PCHAR(" [--use-proxy=host:port]\n")
83 << ULXR_PCHAR(" [--cpp-decl=filename]\n")
84 << ULXR_PCHAR(" [--cpp-impl=filename]\n")
85 << ULXR_PCHAR(" example: introspect --host=myhost.com:80/rpc/server.php --use-proxy=host:8080\n")
86 << ULXR_PCHAR("\n");
87 }
88
89
main(int argc,char ** argv)90 int main(int argc, char **argv)
91 {
92 try
93 {
94 ulxr::intializeLog4J(argv[0]);
95 ulxr::getLogger4J()->send(ULXR_PCHAR("DEBUG"),
96 ULXR_PCHAR("introspect started"),
97 ULXR_GET_STRING(__FILE__),
98 __LINE__);
99 if (argc < 2)
100 {
101 usage();
102 return 1;
103 }
104
105 unsigned proxyport = 0;
106 ulxr::CppString proxyname;
107
108 unsigned port = 80;
109 ulxr::CppString resource = ULXR_PCHAR("/");
110 ulxr::CppString server;
111 bool have_host = false;
112
113 std::string declfile;
114 std::string implfile;
115
116 for (int i = 1; i < argc; ++i)
117 {
118 std::string arg = argv[i];
119 if (arg.substr(0, 12) == "--use-proxy=")
120 {
121 proxyport = 8080;
122 ulxr::CppString rsc;
123 if (!splitUrl(arg.substr(12), proxyname, rsc, proxyport))
124 {
125 usage();
126 return 1;
127 }
128 }
129
130 else if (arg.substr(0, 7) == "--host=")
131 {
132 have_host = true;
133 if (!splitUrl(arg.substr(7), server, resource, port))
134 {
135 usage();
136 return 1;
137 }
138 }
139
140 else if (arg.substr(0, 11) == "--cpp-decl=")
141 declfile = arg.substr(11);
142
143 else if (arg.substr(0, 11) == "--cpp-impl=")
144 implfile = arg.substr(11);
145
146 else
147 {
148 std::cerr << "Unknown option: " << arg << std::endl;
149 {
150 usage();
151 return 1;
152 }
153 }
154 }
155
156 if (!have_host)
157 {
158 std::cerr << "No target host given\n";
159 usage();
160 return 1;
161 }
162
163 ULXR_COUT << ULXR_PCHAR("Connecting to ")
164 << server << ULXR_PCHAR(":") << port << resource
165 << ULXR_PCHAR("\n");
166
167 Integer i(1);
168 TcpIpConnection conn (false, server, port);
169
170 if (proxyport != 0 && proxyname.length() != 0)
171 {
172 ULXR_COUT << ULXR_PCHAR("using http proxy ")
173 << proxyname << ULXR_PCHAR(":") << proxyport
174 << ULXR_PCHAR("\n");
175 conn.setProxy(proxyname, proxyport);
176 }
177 HttpProtocol prot(&conn);
178 Requester client(&prot);
179 MethodResponse resp;
180
181 MethodCall list_methods (ULXR_PCHAR("system.listMethods"));
182 MethodCall method_help (ULXR_PCHAR("system.methodHelp"));
183 MethodCall method_sig (ULXR_PCHAR("system.methodSignature"));
184 MethodCall get_capabilities (ULXR_PCHAR("system.getCapabilities"));
185
186 resp = client.call(list_methods, resource);
187 Array meth = resp.getResult();
188
189 bool have_capabilities = false;
190 ULXR_COUT << ULXR_PCHAR("Found ") << meth.size() << ULXR_PCHAR(" methods:\n\n");
191
192 std::FILE *decl_fs = 0;
193 if (declfile.length() != 0)
194 decl_fs = std::fopen(declfile.c_str(), "w");
195
196 std::FILE *impl_fs = 0;
197 if (implfile.length() != 0)
198 impl_fs = std::fopen(implfile.c_str(), "w");
199
200 for (unsigned m = 0; m < meth.size(); ++m)
201 {
202 RpcString name = meth.getItem(m);
203 if (name.getString() == get_capabilities.getMethodName() )
204 have_capabilities = true;
205
206 ULXR_COUT << m+1 << ULXR_PCHAR(") ") << name.getString() << std::endl;
207 method_sig.clear();
208 method_sig.addParam(name);
209 resp = client.call(method_sig, resource);
210 ulxr::CppString signature;
211 ulxr::CppString purpose;
212 if (resp.getResult().getType() == RpcArray)
213 {
214 Array meths = resp.getResult();
215 for (unsigned ms = 0; ms < meths.size(); ++ms)
216 {
217 Array sign = meths.getItem(ms);
218 signature.clear();
219 for (unsigned is = 0; is < sign.size(); ++is)
220 {
221 if (signature.length() != 0)
222 signature += ULXR_PCHAR(", ");
223 signature +=RpcString(sign.getItem(is)).getString();
224 }
225 ULXR_COUT << ULXR_PCHAR(" Signature: ") << signature << ULXR_PCHAR("\n");
226 }
227 ULXR_COUT << ULXR_PCHAR("\n");
228 }
229 else
230 {
231 signature = ULXR_PCHAR("not available");
232 ULXR_COUT << ULXR_PCHAR(" Signature: none available\n\n");
233 }
234
235 method_help.clear();
236 method_help.addParam(name);
237 resp = client.call(method_help, resource);
238 purpose = RpcString(resp.getResult()).getString();
239 ulxr::CppString cpurpose = purpose;
240
241 unsigned pos = 0;
242 bool multi = false;
243 while ((pos = cpurpose.find(L'\n', pos)) != ulxr::CppString::npos)
244 {
245 multi = true;
246 cpurpose.insert(pos+1, ULXR_PCHAR(" // "));
247 pos += 1; // 2 spaces indentation
248 }
249 if (multi)
250 cpurpose.insert(0, ULXR_PCHAR("\n // "));
251
252 pos = 0;
253 while ((pos = purpose.find('\n', pos)) != ulxr::CppString::npos)
254 {
255 purpose.insert (pos+1, ULXR_PCHAR(" "));
256 pos += 3; // 2 spaces indentation
257 }
258
259 ULXR_COUT << ULXR_PCHAR(" Documentation: \n")
260 << ULXR_PCHAR(" ") << purpose << ULXR_PCHAR("\n\n");
261
262 std::string s = ulxr::getLatin1(name.getString());
263 std::string cname = s;
264 while((pos = cname.find(".")) != std::string::npos)
265 cname[pos] = '_';
266
267 if (decl_fs != 0)
268 {
269 if (m == 0)
270 std::fprintf(decl_fs, "\n///////////////////////////////////////////////////////\n"
271 "// XMLRPC Methods imported from %s\n\n", ulxr::getLatin1(server+resource).c_str());
272
273 std::fprintf(decl_fs, " // signature: %s\n", ulxr::getLatin1(signature).c_str() );
274 std::fprintf(decl_fs, " // purpose: %s\n", ulxr::getLatin1(cpurpose).c_str() );
275 std::fprintf(decl_fs, " ulxr::MethodCall %s;\n\n", cname.c_str());
276 }
277
278 if (impl_fs != 0)
279 std::fprintf(impl_fs, " , %s (ULXR_PCHAR(\"%s\"))\n", cname.c_str(), s.c_str() );
280 }
281
282 if (decl_fs != 0)
283 std::fprintf(decl_fs, "///////////////////////////////////////////////////////\n\n");
284
285 if (impl_fs != 0)
286 std::fclose(impl_fs);
287
288 if (decl_fs != 0)
289 std::fclose(decl_fs);
290
291 ULXR_COUT << ULXR_PCHAR("Checking for well known system capabilities:\n");
292 if (have_capabilities)
293 {
294 resp = client.call(get_capabilities, resource);
295 Struct cap = resp.getResult();
296 if (cap.hasMember(ULXR_PCHAR("faults_interop")))
297 {
298 Struct inter = cap.getMember(ULXR_PCHAR("faults_interop"));
299 RpcString url = inter.getMember(ULXR_PCHAR("specUrl"));
300 Integer vers = inter.getMember(ULXR_PCHAR("specVersion"));
301
302 ULXR_COUT << ULXR_PCHAR(" Server supports interoperational fault codes as defined at:\n ")
303 << url.getString() << ULXR_PCHAR(" with version ")
304 << vers.getInteger() << std::endl;
305 }
306 }
307 else
308 ULXR_COUT << ULXR_PCHAR(" None avaliable.\n");
309 }
310
311 catch(XmlException &ex)
312 {
313 ULXR_COUT << ULXR_PCHAR("Xml Error occured: ") << ex.why()
314 << ULXR_PCHAR(" (") << ex.getErrorString() << ULXR_PCHAR(") ")
315 << ULXR_PCHAR(" in line ") << ex.getErrorLine() << std::endl;
316 }
317 catch(Exception &ex)
318 {
319 ULXR_COUT << ULXR_PCHAR("Error occured: ") << ex.why() << std::endl;
320 return 1;
321 }
322 catch(std::exception &ex)
323 {
324 ULXR_COUT << ULXR_PCHAR("Error occured: ") << ULXR_GET_STRING(ex.what()) << std::endl;
325 return 1;
326 }
327 catch(...)
328 {
329 ULXR_COUT << ULXR_PCHAR("unknown Error occured.\n");
330 return 1;
331 }
332
333 return 0;
334 }
335