Configuration for Multiple Callbacks in Interface

afcarlafcarl Member Andy CarlOrganization: Northrop Grumman CorpProject: Distributed analysis of air vehicle subsystems ✭✭
Hello!

The client config file for the demo/ice/callback example contains the following entry:

"CallbackSender.Proxy=callback:tcp -p 10000:udp -p 10000:ssl -p 10001"

which is used by the "stringToIdentity" method to generate a proxy for the "callback" method in the "CallbackReceiver" interface of the client, to the server through the "CallbackSender" interface.

My question is, how is the same methodology used in the client config file when there are multiple callbacks in the same interface? It appears that you can only handle one per interface/adapter/object. Is this true?

Thanks,
Andy

Comments

  • joshmoorejoshmoore GermanyMember Josh MooreOrganization: Glencoe Software, Inc.Project: OME, http://openmicroscopy.org
    Hi Andy,

    I'm sure the ZeroC guys can clarify further, but in general:
    afcarl wrote: »
    "CallbackSender.Proxy=callback:tcp -p 10000:udp -p 10000:ssl -p 10001"

    which is used by the "stringToIdentity" method to generate a proxy for the "callback" method in the "CallbackReceiver" interface of the client, to the server through the "CallbackSender" interface.
    is a bit wrong. Instead, you could say that the string is used by the stringToIdentity method to generate a proxy to the "callback" object which happens to have a "callback()" method. If you look in CallbackSenderI.cpp you can see how it calls the callback() method.

    Another way of putting this is that "callback" in the config file is a coincidence and could have been "CallbackObject" or "foo", as long as it was properly changed in both config files, Server.cpp, and Client.cpp at the same time.

    ~Josh
  • benoitbenoit Rennes, FranceAdministrators, ZeroC Staff Benoit FoucherOrganization: ZeroC, Inc.Project: Ice ZeroC Staff
    Hi Andy,

    A client can receive many different callbacks, through different operations and different Ice objects (implementing different Slice interfaces). Let me try to summarize what the callback client is doing using the right terminology (see 2.2 Terminology), hopefully this will be clearer.

    The client CallbackSender.Proxy property specifies a stringified proxy to an Ice object from the callback server (the identity of this object is "callback" and the endpoints where it can be reached are "tcp -p 10000:udp -p 10000:ssl -p 10001"). This Ice object implements the CallbackSender interface. This property is transformed into a proxy object in the client using the propertyToString method:
        CallbackSenderPrx twoway = CallbackSenderPrx::checkedCast(
            communicator()->propertyToProxy("CallbackSender.Proxy")->ice_twoway()->ice_timeout(-1)->ice_secure(false));
    

    Now, the client also creates an Ice object in order to be able to receive callbacks from the server. This Ice object has the identity "callbackReceiver" and it implements the CallbackReceiver interface (defined in Callback.ice, this interface has for instance a callback() operation, but it could have many more operations). It's registered with the client object adapter named "Callback.Client" whose endpoints are "tcp:udp:ssl" (specified in the client config with the Callback.Client.Endpoints property):
        Ice::ObjectAdapterPtr adapter = communicator()->createObjectAdapter("Callback.Client");
        CallbackReceiverPtr cr = new CallbackReceiverI;
        adapter->add(cr, communicator()->stringToIdentity("callbackReceiver"));
        adapter->activate();
    

    In order to receive callbacks from the server through the "callbackReceiver" Ice object it just created, the client needs to pass the proxy of this Ice object to the server. So the client creates the proxy and then calls the initiateCallback method on the callback sender Ice object hosted by the server:
        CallbackReceiverPrx twowayR = CallbackReceiverPrx::uncheckedCast(
            adapter->createProxy(communicator()->stringToIdentity("callbackReceiver")));
        twoway->initiateCallback(twowayR);
    

    The "twoway" proxy here points to the Ice object from the server which implements the CallbackSender interface and the "twowayR" proxy points to the Ice object from the client which implements the CallbackReceiver interface. Then, if you take a look at the server implementation, you'll see that the server calls the "callback()" operation on the client callback receiver Ice object (through the proxy it received with the initiateCallback operation).

    So to summarize:
    1. The client create a proxy to the callback sender Ice object hosted by the server.
    2. The client creates a callback receiver Ice object, it's through this object that the client will receive callbacks from the server.
    3. The client pass the proxy on its callback receiver Ice object to the server by invoking initiateCallback on the proxy obtained in 1.

    To receive different callbacks from the server the client could either:
    • Create more Ice objects implementing other interfaces than the CallbackReceiver interface and pass the proxies to these Ice objects to the server.
    • Add additional operations to the CallbackReceiver interface.

    Cheers,
    Benoit.
  • afcarlafcarl Member Andy CarlOrganization: Northrop Grumman CorpProject: Distributed analysis of air vehicle subsystems ✭✭
    How to config multiple callbacks in the same interface

    Benoit,
    Thank you for your explaination. I have previously added additional callbacks in the CallbackReceiver interface. The source of my question lies w/ uniquely specifying the individual callback methods. It appears that the entry:

    "CallbackSender.Proxy=callback:tcp -p 10000:udp -p 10000:ssl -p 10001"

    is only able to be used to invoke one method, the "callback" method in the CallbackReceiver interface. My attempts to use the same proxy ("twowayR") to invoke a second method, say "callback2", meet w/ an error as follows:

    "servant for identity callback does not define operation 'callback2'

    So, I guess one specific question is: Can the client CallbackSender.Proxy property be used to invoke more than one callback method defined in CallbackReceiver, by the server, back into the client via the CallbackReceiver interface?

    Thanks,
    Andy
  • xdmxdm La Coruña, SpainAdministrators, ZeroC Staff Jose Gutierrez de la ConchaOrganization: ZeroC, Inc.Project: Ice Developer ZeroC Staff
    Hi Andy,

    The client application use CallbackSender.Proxy property to create a proxy to the CallbackSender servant whose identity is 'callback'.

    Then the client application create a CallbackReceiver object and add the object to the client adapter, then client creates a proxy to this CallbackReceiver and pass it to the server application using initiateCallback operation, once the server has received a proxy to a CallbackReceiber it could call any method defined by this interface.

    So i think that what is wrong with your test is that you are trying to call callback2 operation on the CallbackSender that is the object whose identity is 'callback', but callback2 is defined in CallbackReceiver that is the proxy that is send to initializeCallback implemented by CallbackSender.

    In general once you have a proxy to an Ice Object you could call any method defined by the interface, it doesn´t matter if the object is a callback or not.


    Regards,
    José.
  • afcarlafcarl Member Andy CarlOrganization: Northrop Grumman CorpProject: Distributed analysis of air vehicle subsystems ✭✭
    Meaning of "callback" in "CallbackSender.Proxy=callback..."

    Josh / Jose,
    Thanks for the replies, but the apparent disconnect revolves around the meaning of "callback" in

    "CallbackSender.Proxy=callback..."

    You have stated that it is the ICE object ID, and could be called "foo". But I have only been able to get the example problem to work as long as the "name" corresponds exactly to the name of the callback method defined in the "CallbackReceiver" interface. Any added callback methods to "CallbackReceiver" are not recognized.

    Your explaination seems reasonable, it just has not yet matched up with a successful test. Please advise.

    Thanks,
    Andy
  • xdmxdm La Coruña, SpainAdministrators, ZeroC Staff Jose Gutierrez de la ConchaOrganization: ZeroC, Inc.Project: Ice Developer ZeroC Staff
    Hi Andy,

    To better understand the things try this

    get and unmodified version of callback demo

    Edit Callback.ice to add a new operation to CallbackReceiver interface
    interface CallbackReceiver
    {
        void callback();
        void callback2();
    };
    

    Then edit CallbackSenderI,cpp to also call this new operation.
    void
    CallbackSenderI::initiateCallback(const CallbackReceiverPrx& proxy, const Current& current)
    {
        cout << "initiating callback" << endl;
        try
        {
            proxy->callback();
            proxy->callback2();
        }
        catch(const Exception& ex)
        {
            cout << ex << endl;
        }
    }
    

    Then you need to add an implementation for the new operation edit Client.cpp
    class CallbackReceiverI : public CallbackReceiver
    {
    public:
    
        virtual void callback(const Ice::Current&)
        {
    #ifdef __xlC__
            //
            // The xlC compiler synchronizes cin and cout; to see the messages
            // while accepting input through cin, we have to print the messages
            // with printf
            //
            printf("received callback\n");
            fflush(0);
    #else
            cout << "received callback" << endl;
    #endif
        }
    
        virtual void callback2(const Ice::Current&)
        {
    #ifdef __xlC__
            //
            // The xlC compiler synchronizes cin and cout; to see the messages
            // while accepting input through cin, we have to print the messages
            // with printf
            //
            printf("received callback2\n");
            fflush(0);
    #else
            cout << "received callback2" << endl;
    #endif
        }
    };
    

    Now recompile the demo start server

    Start client press 't' and you will see both operations being called.

    received callback
    received callback2


    If you want to also change the identity of the CallbackSender

    edit Server.cpp and change
        adapter->add(cbs, communicator()->stringToIdentity("callback"));
    

    To
        adapter->add(cbs, communicator()->stringToIdentity("foo"));
    

    Edit config file and change the proxy property
    CallbackSender.Proxy=foo:tcp -p 10000:udp -p 10000:ssl -p 10001
    

    Recompile the demo and try it again , the output should be the same.

    Regards,
    José
  • afcarlafcarl Member Andy CarlOrganization: Northrop Grumman CorpProject: Distributed analysis of air vehicle subsystems ✭✭
    The Apparent Answer to the Question

    The apparent answer is that the "name" = "callback" in

    "CallbackSender.Proxy=callback..." (from config.client)

    can be used to invoke more than one callback method in "CallbackReceiver", as long as the following changes are made:

    1) Callback.ICE File: Add "callback2" to "CallbackReceiver" Interface

    2) config.client File: Change

    From:
    "CallbackSender.Proxy=callback:tcp -p 10000:udp -p 10000:ssl -p 10001" &
    "Callback.Client.Endpoints=tcp:udp:ssl"

    To:
    "CallbackSender.Proxy=foo:tcp -p 10000:udp -p 10000:ssl -p 10001" &
    "foo.Client.Endpoints=tcp:udp:ssl"

    3) Client.py File: a) Add def of "callback2" to "CallbackReceiverI", b) Change

    From:
    "adapter = self.communicator().createObjectAdapter("Callback.Client")"

    To:
    "adapter = self.communicator().createObjectAdapter("foo.Client")"

    4) Server.py File: a) Add invocation "proxy.callback2()", b) Change

    From:
    "adapter.add(CallbackSenderI(), self.communicator().stringToIdentity("callback"))"

    To:
    "adapter.add(CallbackSenderI(), self.communicator().stringToIdentity("foo"))"

    This seems obtuse, but at least it works and clairifies in my own mind the usage meaning of the "name" = "callback" in

    "CallbackSender.Proxy=callback..." (from config.client)

    Thanks,
    Andy
  • benoitbenoit Rennes, FranceAdministrators, ZeroC Staff Benoit FoucherOrganization: ZeroC, Inc.Project: Ice ZeroC Staff
    The "callback" string in the proxy from the client has nothing to do with the method named "callback" in the CallbackReceiver interface.

    The "callback" string in the proxy from the client is the identity of the Ice object from the server. If you change the identity in the proxy from the client, you also need to change it in the server. The client and the server must use the same identity.

    To make an analogy with object oriented programming languages, you can see a proxy as a reference and an Ice object as a programming language object (Java for example). Just like Java interface operations really have nothing to do with the value of a reference to a Java object implementing this interface, the operations of a Slice interface have nothing to do with a proxy for an Ice object implementing the Slice interface.

    In short, just add the Slice operation to the CallbackReceiver interface and don't worry about the proxy in the client, it doesn't need to be changed :)

    Cheers,
    Benoit.
  • xdmxdm La Coruña, SpainAdministrators, ZeroC Staff Jose Gutierrez de la ConchaOrganization: ZeroC, Inc.Project: Ice Developer ZeroC Staff
    afcarl wrote: »
    1) Callback.ICE File: Add "callback2" to "CallbackReceiver" Interface
    This is right
    afcarl wrote: »
    2) config.client File: Change

    From:
    "CallbackSender.Proxy=callback:tcp -p 10000:udp -p 10000:ssl -p 10001" &
    "Callback.Client.Endpoints=tcp:udp:ssl"

    To:
    "CallbackSender.Proxy=foo:tcp -p 10000:udp -p 10000:ssl -p 10001" &
    "foo.Client.Endpoints=tcp:udp:ssl"

    You don't need to do that
    afcarl wrote: »
    3) Client.py File: a) Add def of "callback2" to "CallbackReceiverI",
    Right again
    afcarl wrote: »
    b) Change

    From:
    "adapter = self.communicator().createObjectAdapter("Callback.Client")"

    To:
    "adapter = self.communicator().createObjectAdapter("foo.Client")"
    You aslo don't need to do that.
    afcarl wrote: »
    4) Server.py File: a) Add invocation "proxy.callback2()",
    Right
    afcarl wrote: »
    b) Change

    From:
    "adapter.add(CallbackSenderI(), self.communicator().stringToIdentity("callback"))"

    To:
    "adapter.add(CallbackSenderI(), self.communicator().stringToIdentity("foo"))"

    You don't need to do that.

    So only the steps i marked with right are needed, if this is not the case could you provide a modified version so we could look what is going wrong there.

    Bests,
    José
Sign In or Register to comment.