Note that there are some explanatory texts on larger screens.

plurals
  1. POProgramming a distributed application written in C#, Ruby and Java using XML-RPC
    text
    copied!<p>I am tasked with writing a distributed event managing tool where each client, either a Ruby, C# or Java Client, synchronises all changes with a list of registered clients. I have to use <code>XML-RPC</code> to achieve the goal. My team and I have written up an <code>XML-RPC</code> client and server in each language and will provide the relevant source code below. If you require more code, please let me know.</p> <p>The problem is that I can get Java and C# to communicate with each other. Ruby can communicate with the others but C# (and maybe Java, haven't tested yet) have problems addressing the Ruby server. I guess the problem is with the Endpoint. First let me give you some code. When reading please be aware that the code is actually written by a team and naming conventions differ a bit:</p> <p><strong>C# client</strong></p> <pre><code>Uri _address = new Uri("http://" + _s + ":8000/xmlrpc/EventManagerService"); ChannelFactory&lt;IEventManagerWCF_XML_RPC&gt; _factory = new ChannelFactory&lt;IEventManagerWCF_XML_RPC&gt;(new WebHttpBinding(WebHttpSecurityMode.None), new EndpointAddress(_address)); _factory.Endpoint.Behaviors.Add(new XmlRpcEndpointBehavior()); IEventManagerWCF_XML_RPC _proxy = _factory.CreateChannel(); </code></pre> <p><code>_proxy</code> will not hold the client for a given URI. Those are stored in a dictionary and used when the need arises to synchronise events. One such synchronisation would happen in the case of a modification;</p> <pre><code> foreach(IEventManagerWCF_XML_RPC proxy in this.peers.Values) proxy.modify(_id, _field, _newValue); </code></pre> <p>Here is an extract from the IEventManagerWCF_XML_RPC interface;</p> <pre><code> [OperationContract(Action = "EventManagerService.modify")] bool modify(int id, string field, string newValue); </code></pre> <p><strong>C# XML RPC service</strong></p> <pre><code> Uri _baseAddress = new Uri("http://localhost:8000/xmlrpc"); _eventManagerHost = new ServiceHost(typeof(EventManagerService), _baseAddress); try { ServiceEndpoint epXmlRpc = _eventManagerHost.AddServiceEndpoint(typeof(IEventManagerWCF_XML_RPC), new WebHttpBinding(WebHttpSecurityMode.None), "EventManagerService"); epXmlRpc.Behaviors.Add(new XmlRpcEndpointBehavior()); ServiceMetadataBehavior smb = new ServiceMetadataBehavior(); smb.HttpGetEnabled = true; _eventManagerHost.Description.Behaviors.Add(smb); _eventManagerHost.Open(); } catch (CommunicationException ce) { Console.WriteLine("An exception occurred: {0}", ce.Message); _eventManagerHost.Abort(); } </code></pre> <p>Nothing special here I guess. Lets move on to the Java code!</p> <p><strong>Java Client</strong></p> <pre><code>XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl(); try { config.setServerURL(new URL("http://"+ip+":8000/xmlrpc/EventManagerService")); } catch (MalformedURLException e) { e.printStackTrace(); } config.setEnabledForExtensions(true); config.setConnectionTimeout(60 * 1000); config.setReplyTimeout(60 * 1000); XmlRpcClient client = new XmlRpcClient(); client.setTransportFactory(new XmlRpcCommonsTransportFactory(client)); client.setConfig(config); xmlRpcPeers.put(ip, client); </code></pre> <p><code>xmlRpcPeers</code> now holds the different clients. They are called as follows;</p> <pre><code>for(XmlRpcClient peer : this.xmlRpcPeers.values()) { try { peer.execute("EventManagerService.modify", params); } catch (Exception e) { e.printStackTrace(); } } </code></pre> <p>The <strong>Java Server</strong> has it's own class and is instantiated with a simple <code>new</code> call;</p> <pre><code>public class Server extends Thread{ /** * Server port */ private static final int port = 8000; /** * Starts the XML-RPC server */ public void run(){ WebServer webServer = new WebServer(port); XmlRpcServer xmlRpcServer = webServer.getXmlRpcServer(); PropertyHandlerMapping phm = new PropertyHandlerMapping(); try { phm.addHandler("EventManagerService", lu.uni.binfo.ds.EventManager_Java.EventManagerService.class); } catch (XmlRpcException e1) { e1.printStackTrace(); } xmlRpcServer.setHandlerMapping(phm); XmlRpcServerConfigImpl serverConfig = (XmlRpcServerConfigImpl) xmlRpcServer.getConfig(); serverConfig.setEnabledForExtensions(true); serverConfig.setContentLengthOptional(false); try { webServer.start(); } catch (IOException e) { e.printStackTrace(); } } } </code></pre> <p>Up till now everything seemed to work fine. Adding Ruby to the mix is what gives the most trouble. Here is the relevant code;</p> <p><strong>Ruby Client</strong> Ruby clients are also stored in a dictionary. It is populated as follows;</p> <pre><code>@devices_XMLRPC[key] = EventManagerClient_XMLRPC.new(tokens[0]).device </code></pre> <p>The code for the class is:</p> <pre><code>class EventManagerClient_XMLRPC @uri @device attr_accessor :uri, :device def initialize(uri) @uri = uri @device = XMLRPC::Client.new2( uri="http://" &lt;&lt; @uri.to_s &lt;&lt; ":8000/xmlrpc/EventManagerService", proxy=nil, timeout=30) end end </code></pre> <p>A call to synchronise on modifications looks like this:</p> <pre><code>@devices_XMLRPC.each_value { |client| client.call("EventManagerService.modify", tokens[0], field, value) } </code></pre> <p><strong>Ruby Server</strong></p> <pre><code>server = XMLRPC::Server.new(8000, "127.0.0.1") server.add_handler("xmlrpc/EventManagerService", EventManagerService.instance) puts "Server ready!" server.serve </code></pre> <p>The EventManagerService class:</p> <pre><code>class EventManagerService include Singleton @manager def initialize() @manager = EventManager.instance end def modify(id, field, newValue) puts "modify called" @manager.modify([id, field, newValue], 1) end end </code></pre> <p><code>EventManager</code> being the class where all the logic resides.</p> <p>The error when trying to communicate from C# to Ruby is an <code>EndPointNotFoundException</code> that reads:</p> <p><code>There was no endpoint listening at http://ip:8000/xmlrpc/EventManagerService that could accept the message.[...]</code></p> <p>I tried fiddling around with the endpoint declaration but cannot seem to get it to work. The Ruby documentation does not help either. I am in need of help!</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload