Archived

This forum has been archived. Please start a new discussion on GitHub.

Multiple Server Implementations?

From the Ice 3.0.1 manual:

You are not limited to a single implementation of a client or server. For
example, you can build multiple servers, each of which implements the same
interfaces but uses different implementations (for example, with different performance characteristics).


It is possible to have a client which can use different servers that implement the same interface by just changing configuration data rather than re-compiling?

Comments

  • matthew
    matthew NL, Canada
    Sure. For example, with the hello world client/server you can change the server the client will use by altering the value of Hello.Proxy in the config file. By default this is:

    Hello.Proxy=hello:tcp -p 10000:udp -p 10000:ssl -p 10001

    If you wanted to use a different object, say hello2 on host foo.bar.com then you could change it as follows:

    Hello.Proxy=hello2:tcp -h foo.bar.com -p 10000

    If you use IceGrid you don't need to provide the endpoints of the server at all. Your client will resolve them automatically at runtime using IceGrid. You can also provide fault tolerance and load balancing in this way. You might want to read my article on IceGrid for more details on this in the Connections newsletter.
  • benoit
    benoit Rennes, France
    Hi Paul,

    Yes, the client is using a proxy to talk to the server so if your client is getting the proxy through a configuration property stored in a file for example, you can just change the configuration property to get your client to talk to another server. Of course, the proxy must point to an Ice object implementing the interface that your client expects.

    Cheers,
    Benoit.
  • Thanks for the quick replies (as usual!).

    I realise the proxy endpoint information is just a string and can be set in the configuration file rather than hard-coded, but at some point you need to make a concrete instance of a servant. Let me expand with an example.
    //Slice
    interface DataServer
    {
        sequence<Element> getAllElements();
    };
    

    Lets say, I want two different server processes one which implements DataServer using SQL, the other using XML.

    How would the client be able to switch between SQL and XML servers without changing the code?

    Sorry, if I am getting confused (again) here - I am currently trying to get to grips with IceGrid, IceStorm, and IceBox - I get very confused very quickly :)
  • benoit
    benoit Rennes, France
    What do you think would need to be changed in your client to use the 2 different Ice objects implementing this DataServer interface?

    I don't think anything needs to be changed in the client. For example, suppose the proxy for the DataServer object using the XML implementation is "xmldataserver:tcp -h localhost -p 12400". The proxy for the DataServer object using the SQL implementation is "sqldataserver:tcp -h localhost -p 12401". Your client just need to use one of these proxies to talk to a given DataServer interface.

    Cheers,
    Benoit.
  • benoit wrote:
    What do you think would need to be changed in your client to use the 2 different Ice objects implementing this DataServer interface?

    Hmmm. This is what I would do in the client:
    Ice::ObjectPrx pBase = communicator->stringToProxy("MapSQLServer:default -p 10001");
    MapSQLServerPrx proxy = MapSQLServerPrx::checkedCast(pBase);
    

    I must specifically cast to the concrete implementation - As I understand it (which is not very well) I would need to change this if I wanted to use MapXMLServerPrx.
  • benoit
    benoit Rennes, France
    This is different from what you described in the previous posts. Here, you have 2 different interfaces: the MapSQLServer and MapXMLServer interfaces, not just one DataServer interface.

    Unless you want to access specific features of a given implementation you shouldn't declare two interfaces, you should declare only one interface. For example:
       // Slice
       interface DataServer
       {
           string getDataAsString(string key);
       };
    

    You can have different implementations for this interface. For example here's the declaration of 2 different servants implementing the DataServer interface:
       // C++
       class XmlDataServerI : public class DataServer
       {
       public:
           std::string getDataAsString(const std::string& key, const Ice::Current& current) { /* Implementation here. */ }
       };
    
       class SqlDataServerI : public class DataServer
       {
       public:
           std::string getDataAsString(const std::string& key, const Ice::Current& current) { /* Implementation here. */ }
       };
    

    Your client doesn't have to cast the proxy to a specific implementation. It just has to cast the proxy to a DataServer proxy:
    Ice::ObjectPrx pBase = communicator->stringToProxy("MapSQLServer:default -p 10001");
    DataServerPrx proxy = DataServerPrx::checkedCast(pBase);
    string str = proxy->getDataAsString("key1");
    

    Let us know if this is still not clear!

    Cheers,
    Benoit.
  • :o:o I knew it - I knew I was getting it all mixed up again! :o:o

    I am trying to read about and learn Ice while also learning the features provided by IceGrid, Glacier2, IceBox and IceStorm and my head hurts!

    Yet again, thankyou for answering my stupid questions - someday this will all fall into place and make sense!! :D