Archived
This forum has been archived. Please start a new discussion on GitHub.
Configuration for Multiple Callbacks in Interface
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
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
0
Comments
-
Hi Andy,
I'm sure the ZeroC guys can clarify further, but in general:"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.
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.
~Josh0 -
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:- The client create a proxy to the callback sender Ice object hosted by the server.
- The client creates a callback receiver Ice object, it's through this object that the client will receive callbacks from the server.
- 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.0 -
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,
Andy0 -
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é.0 -
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,
Andy0 -
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 interfaceinterface 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.cppclass 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 changeadapter->add(cbs, communicator()->stringToIdentity("callback"));
Toadapter->add(cbs, communicator()->stringToIdentity("foo"));
Edit config file and change the proxy propertyCallbackSender.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é0 -
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,
Andy0 -
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.0 -
1) Callback.ICE File: Add "callback2" to "CallbackReceiver" Interface2) 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 that3) 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"))"
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é0