kaju74
Newbie
Posts: 25
|
|
« on: January 04, 2010, 02:43:58 PM » |
|
Hello.
I need to write a XML-RPC-Server which will be contacted by a hardware-product. The specifications for this (hardware) product requires the presence of the "system.multicall" support. Does the RTC-Server supports this method and what does this means exactly i.e. what to do to activate this?
Thank you, Marc
|
|
|
Logged
|
|
|
|
D.Tkalcec (RTC)
|
|
« Reply #1 on: January 04, 2010, 05:38:26 PM » |
|
With the RTC SDK you can send any number of remote calls in a single request as well as box remote function calls to any depth, but it will depend on the system you are working with how the data will be received and what you will need to do to process it correctly. Since "system.multicall" isn't part of the XML-RPC standard but an extension of the standard, there is more than one way it can be implemented, but here are the two most commonly used, which should get you going:
1) If clients are calling your Server by sending their remote function calls inside a special "system.multicall" remote function, passing the actual remote function calls as parameters to "system.multicall", you will have to add a "system.multicall" remote function to your Server (using the TRtcFunction component, just like for any other remote function) to be able to process boxed "system.multicall" calls.
The OnExecute event of your "system.multicall" remote function will receive all the results from all boxed remote function calls, once they have been executed using their own TRtcFunction components OnExecute events. For the client to receive the results, you will need to "forward" all received results to the client by doing the following in the OnExecute event of the "system.multicall" function:
Result.asArray:=Data.asArray['params'];
2) If clients are sending multiple calls as an array of remote function calls without boxing them inside a "system.multicall" remote function, you will NOT need a "system.multicall" remote function on the Server. Writing a Server which has to receive multiple remote function calls as an array in a single request when the functions are not "boxed", there is nothing special you need to do. Each remote call sent will trigger its own OnExecute event where you will get data from that specific remote function. But if you want to stay on the safe side and you know your clients are sending multiple calls in a single request, you should implement the "system.multicall" remote function as explained above.
Should you have problems communicating with the system you have to work with, please post the plain XML-RPC data you are receiving and let me know what the system expects as a response.
Best Regards, Danijel Tkalcec
|
|
|
Logged
|
|
|
|
kaju74
Newbie
Posts: 25
|
|
« Reply #2 on: January 05, 2010, 08:46:36 AM » |
|
Hi..
Thank you for this detailled answer...at this moment, I had to find out, what the client tries to request. What is the best way to monitor, what the client tries to request from my xmlrpc-server?
Thank you so much, Marc
|
|
|
Logged
|
|
|
|
D.Tkalcec (RTC)
|
|
« Reply #3 on: January 05, 2010, 04:08:09 PM » |
|
Use a TRtcDataProvider component on the Server (linked to TRtcHttpServer, ofcourse). That will give you access to the complete unmodified request.
Best Regards, Danijel Tkalcec
|
|
|
Logged
|
|
|
|
kaju74
Newbie
Posts: 25
|
|
« Reply #4 on: January 06, 2010, 05:28:14 PM » |
|
Hi.
I'll try this today...thank you 8-)
Regards, Marc
|
|
|
Logged
|
|
|
|
kaju74
Newbie
Posts: 25
|
|
« Reply #5 on: January 07, 2010, 10:45:05 AM » |
|
Hi... I've monitored, what's happend and noticed the following: The event "BeforeExecute" triggers with the functionname "system.multicall": <methodCall> <methodName>system.multicall</methodName> <params> <param> <value> <array> <data> <value> <struct> <member> <name>methodName</name> <value><string>event</string></value> </member> <member><name>params</name> <value> <array> <data> <value><string>text1</string></value> <value><string>text2</string></value> <value><string>text3</string></value> <value><double>0.00</double></value> </data> </array> </value> </member> </struct> </value> <value> <struct> <member> <name>methodName</name> <value><string>event</string></value> </member> <member> <name>params</name> <value> <array> <data> <value><string>texta</string></value> <value><string>textb</string></value> <value><string>textc</string></value> <value><boolean>1</boolean></value> </data> </array> </value> </member> </struct> </value> </data> </array> </value> </param> </params> </methodCall>
As you see, there are some inside calls to the event-method. I also noticed, that the "event"-method will be triggered without a previous "system.multicall". So, I'm thinking, as soon as there will be more than one call, all methods are embedded inside a multicall. If only ONE method needs to be triggered, it will be received directly by the corresponding function-component (TRtcFunction). Is it possible to extract the embedded methods inside the "system.multicall" and deligate them to their corrsponding TRtcFunction? Another question: I had to implement a method, which has the following syntax: Array<Description> listDescriptions() The method will be called, but how to retrieve the array? It could be possible, that this array is very long (~2 MB)...but I don't know how to implement a function instead of a method...?!?! Best regards, Marc
|
|
|
Logged
|
|
|
|
D.Tkalcec (RTC)
|
|
« Reply #6 on: January 07, 2010, 11:46:24 AM » |
|
Looks like the client isn't packing the data the way I though it would. Instead of packing remote functions as <methodcall> elements inside the array, they are sending each remote function as a record having one "methodName" field and a "params" array. This means you will need to re-package the data in the "system.multicall" function and use the "Execute" method of the FunctionGroup component to which your TRtcFunction components are linked in order to pass the data over to your TRtcFunctions OnExecute events and get the results back. I haven't tried this, but I think this function should do the trick: procedure ExecMultiCall(Sender:TRtcConnection; FuncGroup:TRtcFunctionGroup; Param:TRtcFunctionInfo; Result:TRtcValue); var arr : TRtcArray; rec : TRtcRecord; func : TRtcFunctionInfo; methName : String; MyData : TRtcValue; MyResult : TRtcValueObject; i : integer; begin if Param.isType['Params']<>rtc_Array then Exit;
arr := Param.asArray['Params']; // "remote functions" array MyData.newArray; // result will also be an array
// use data from the array to create remote function objects for i := 0 to arr.Count-1 do begin if arr.isType=rtc_Record then begin rec := arr.asRecord; methName := rec.asText['methodName']; if methName<>'' then begin // create the function object func := MyData.newArray(i).newFunction(methName); // *move* the params object as-is to the function object func.asObject['params'] := rec.asObject['Params']; rec.asObject['params'] := nil; end; end; end;
// Execute all remote functions by using TRtcFunction components // linked to the FuncGroup function group. MyResult:=FuncGroup.Execute(Sender,MyData);
// Set the combined result received from Execute() as our result. if MyResult<>MyData then MyData.Free; Result.asObject:=MyResult; end;
After copying the above function into your code, call it from the OnExecute event of your "system.multicall" TRtcFunction component like this: begin ExecMultiCall(Sender, MyFunctionGroup, Data, Result); end;
MyFunctionGroup is the name of the TRtcFunctionGroup component which you have linked to your TRtcServerModule, to which all your TRtcFunction components are linked. Please let me know if this works. As for your 2nd question, I am sorry but I have no clue what you mean by "Array<Description> listDescriptions()". I would also like to ask you to start a new thread if the 2nd question is not directly related to the subject line. Best Regards, Danijel Tkalcec
|
|
|
Logged
|
|
|
|
kaju74
Newbie
Posts: 25
|
|
« Reply #7 on: January 07, 2010, 12:08:24 PM » |
|
Hi.
Wow....thank you for you quick answer. I'll try this at home this evening and tell you, if it's working 8-) It seems to be a lit bit tricky to work with XMLRPC...8-)))
Well, I'll ask the manufactor how the "listDescription" method should be implemented and create another topic.
Best regards, Marc
|
|
|
Logged
|
|
|
|
D.Tkalcec (RTC)
|
|
« Reply #8 on: January 07, 2010, 12:49:47 PM » |
|
XML-RPC is not the problem. The problem is when some wanna-be experts decide to "stretch" the standard beyond its original design and come up with constructs like the one your client is using, instead of doing things the right way. The right way would be to send boxed remote function calls as normal <methodCall> structures, in which case every server implemented correctly would know what to do with it. But now, the structure looks just like an ordinary array with records holding more arrays. And that's plain wrong. But it can be fixed on the server side if you know what "the artist wanted to say". This is what the above "system.multicall" code *should* have looked like ... <methodCall> <methodName>system.multicall</methodName> <params> <param> <methodCall> <methodName>event</methodName> <params> <param><string>text1</string></param> <param><string>text2</string></param> <param><string>text3</string></param> <param><double>0.00</double></param> </params> <methodCall> </param> <param> <methodCall> <methodName>event</methodName> <params> <param><string>texta</string></param> <param><string>textb</string></param> <param><string>textc</string></param> <param><boolean>1</boolean></param> </params> </methodCall> </param> </params> </methodCall>
If you compare this to the XML-RPC code you've posted above (which your client is sending), you will see that it contains all the elements, but its intentions are clear and ... it is shorter (less overhead). Best Regards, Danijel Tkalcec
|
|
|
Logged
|
|
|
|
kaju74
Newbie
Posts: 25
|
|
« Reply #9 on: January 07, 2010, 08:09:26 PM » |
|
Hi again. Hmm..I've tryed you "ExecMultiCall"-method with the latest SDK but get a lot of errors if compiling: if arr.isType = rtc_Record then ifType seems to be indexed... asRecord seems to be indexed... func := MyData.newArray(i).newFunction(methName); has to much parameters... Not sure, if I fixed it right... Regards, Marc
|
|
|
Logged
|
|
|
|
D.Tkalcec (RTC)
|
|
« Reply #10 on: January 07, 2010, 08:19:56 PM » |
|
Looks like "BBCode" on the Forums has swallowed function parameters. I've also noticed there is anothe bug which the compiler did not catch. Anyway ... here is fixed version ... procedure ExecMultiCall(Sender:TRtcConnection; FuncGroup:TRtcFunctionGroup; Param:TRtcFunctionInfo; Result:TRtcValue); var arr : TRtcArray; rec : TRtcRecord; func : TRtcFunctionInfo; methName : String; MyData : TRtcArray; // <- TRtcArray instead of TRtcValue MyResult : TRtcValueObject; i : integer; begin if Param.isType['Params']<>rtc_Array then Exit;
arr := Param.asArray['Params']; // "remote functions" array
MyData:=TRtcArray.Create; // create our data object
// use data from the array to create remote function objects for i := 0 to arr.Count-1 do begin if arr.isType[i]=rtc_Record then begin rec := arr.asRecord[i]; methName := rec.asText['methodName']; if methName<>'' then begin // create the function object func := MyData.newFunction(i,methName); // *move* the params object as-is to the function object func.asObject['params'] := rec.asObject['Params']; rec.asObject['params'] := nil; end; end; end;
// Execute all remote functions by using TRtcFunction components // linked to the FuncGroup function group. MyResult:=FuncGroup.Execute(Sender,MyData);
// Set the combined result received from Execute() as our result. if MyResult<>MyData then MyData.Free; Result.asObject:=MyResult; end; PS. Sorry, but I am in the middle of an update for the RTC SDK and can't test if the above code works. Should you bump into any other problems, please let me know. Best Regards, Danijel Tkalcec
|
|
|
Logged
|
|
|
|
kaju74
Newbie
Posts: 25
|
|
« Reply #11 on: January 07, 2010, 08:27:16 PM » |
|
Hi again. After replacing Execute with ExecuteData the code compiles fine, but: for i := 0 to arr.Count - 1 do begin if arr.isType[i] = rtc_Record then begin rec := arr.asRecord[i];
"if arr.isType = rtc_Record then" won't be called anytime, cause isType seems to be an rtc_Array instead...?!?
Any idea?
Regard, Marc
|
|
|
Logged
|
|
|
|
D.Tkalcec (RTC)
|
|
« Reply #12 on: January 07, 2010, 08:37:50 PM » |
|
Oh. You are right. Data inside the remote function is packed inside a <params> *and* inside an <array>, which means the first "arr" assignment (line 2) is wrong and should be ...
arr := Param.asArray['Params']; // "remote functions" array while arr.isType[0]=rtc_Array do arr:=arr.asArray[0];
This will also work with parameters nested knee deep in arrays ;-)
If you find any other problems, please let me know.
Best Regards, Danijel Tkalcec
|
|
|
Logged
|
|
|
|
kaju74
Newbie
Posts: 25
|
|
« Reply #13 on: January 07, 2010, 10:14:14 PM » |
|
Hi.
Superb...everything works as expected 8-))))) Thank you very much.
Best regards, Marc
|
|
|
Logged
|
|
|
|
|