Why Java proxies does not implement the slice interface ?

in Comments
Hello,
ICE is a great product and one of the best achievement both in its design and implementation i ever see so far.
But it is quite disturbing do have the client Java proxies (those endind in Prx) not implementing the interface when the underlying slice definition is itself an interface.
This breaks the contract between the server and the client.
While one can certainly live with such a difference, it has some deeper impacts than expected on client applications.
One of the most interesting is that because a MyInterfacePrx class does not implements MyInterface, any client application obtaining such a proxy is closely tied to the Prx class, not the interface: it is very difficult then to design applications whose communication layer can be pluggable (i.e. using ICE or a fake, local implementation for testing).
More, any attempt to reverse engineer the application code to obtain an UML model miserably fails to exhibits the original intent.
I'm sure you have carefully designed the slice compiler and there is some reasonable answer to that question.
But, based on an experiment with ICe over the last six monthes in a strong industrial environment it has been found the slice compiler should generate the Prx classes in conformance with the initial contract.
Not doing so have generated much unnecessary work.
Regards
ICE is a great product and one of the best achievement both in its design and implementation i ever see so far.
But it is quite disturbing do have the client Java proxies (those endind in Prx) not implementing the interface when the underlying slice definition is itself an interface.
This breaks the contract between the server and the client.
While one can certainly live with such a difference, it has some deeper impacts than expected on client applications.
One of the most interesting is that because a MyInterfacePrx class does not implements MyInterface, any client application obtaining such a proxy is closely tied to the Prx class, not the interface: it is very difficult then to design applications whose communication layer can be pluggable (i.e. using ICE or a fake, local implementation for testing).
More, any attempt to reverse engineer the application code to obtain an UML model miserably fails to exhibits the original intent.
I'm sure you have carefully designed the slice compiler and there is some reasonable answer to that question.
But, based on an experiment with ICe over the last six monthes in a strong industrial environment it has been found the slice compiler should generate the Prx classes in conformance with the initial contract.
Not doing so have generated much unnecessary work.
Regards
0
Comments
You are not supposed to be able to use a servant reference where you can use a proxy and vice versa. If this were possible, then the lifetime and location of proxies and servants would not be independent anymore, which destroys location and implementation transparency.
Both side of the channel have to implement the same contract.
As a client, i am interested in the contract of the object i use, whatever it is local or remote: i can always replace a local implementation with a proxy if i need to make the service local or remote (for example through the use of a factory and a configuration file).
In the case of the generated proxies, they do not implement the interface of the servant so this does not work "out of the box". Here is an example:
The slice def. is:
interface I {
void doIt();
}
The generated proxy is:
public interface IPrx extends Ice.ObjectPrx {
public void doIt():
...
}
And the generated interface from the slice definition:
public interface I extends Ice.Object, IOperations, _IOperationsNC {
}
But, i expect IPrx to also implements I so that i have a true type correspondence: IPrx should really be an instance of I, not a separate hierarchy.
The modification i suggest is simply:
public interface IPrx extends Ice.ObjectPrx, I {
public void doIt():
...
}
So that IPrx can now be returned as an object implementing I through some adhoc factory.
The I interface is the really one i care of because it holds the contract i have defined in my model for example.
This is why I takes the center stage of the design, not the implementation classes or ICE-aware interfaces.
Proxies are not supposed to provide only remote access to servants. In your code you must use a proxy, whether or not the Ice object that it refers to is local or remote. This is the principle of location transparency: regardless of where an Ice object is implemented, you can always use the same proxy to access such Ice object. The proxy doesn't change, even if the Ice object changes location from local to remote or vice versa.
If proxies could be used to call servants directly, you would also bypass servant locators. For example, you couldn't use the Freeze evictor or other servant locators, which instantiate servants for the Ice object on demand. This is the principle of implementation transparency: Regardless of what technique you use to implement an Ice object, the proxy will not change. It also means that the lifetime of proxies and servants can be decoupled, which is important for scalability.
This is exactly what i mean. But reading your next arguments, i understand where our roads have forked: i was not talking about replacing a servant by a proxy or accessing it outside the regular way, but ICE by any other - equivalent (in its usage), pluggable - framework, including one which has nothing to do with remote calls - if i use ICE, CORBA, RMI, whatever, i (try) to use it the academic way.
From the client application point of view, the ICE proxy is never seen as such, only the semantics of the realized contract matters: having an underlying RPC-aware implementation is only a side-effect, and a design choice to better achieve some functional goals.
In essence, we must be able to write applications (not servants) that are unaware of ICE (through the quasi-exclusive use of interfaces) and then "plug" it into that framework: a required condition is then the ICE proxies really are semantically equivalent to the interfaces there are meant to represent.
Anyway, while the slice compiler would make that job a little easier by declaring the required implement clause, one can always wrap the proxy into another class: it is just tedious when dozens of such classes have to be created.
I hear your concerns - We had the same issue, our components should not be ICE (in this case Proxies). I have implemented some Spring extensions to do the job, it does quite a nice job and you don't need to have classes to wrap the proxies manually - rather Spring returns a dynamic proxy which does the same job.
For more information - visit http://www.springframework.org, download the source and look at the remoting package...
HTH.
Thanks,
--Venkat.
We have used another framework to do it because of licensing isues, but i just wonder if with little help from the slice compiler itself some other patterns may work out of the box support, like:
Specifiying common implementations for a hierarchy of sevants, i.e. with slice definitions:
interface A {};
interface B extends A {};
interface C extends A {};
I would like my servants for B & C inherits from a common implementation of A (implementations mimics the inheritence tree).
Today, only delegation will do the job because the _*Disp classes all have the same root.
Maybe some meta data will allow to specify a base class for the servant.
Thanks,
--Venkat.
In light of Waldo et al's seminal paper on distributed computing, does this location transparency argument still hold water?
Cheers,
Michi.
I would like to add some comments to this rather old thread...
In fact, I have the same concern as annekat: I woulld like to implement (in java) a set of class that make use of a type only knowing the interface definition. I don't want my code to depend at all in the ICE system. Indeed, I am coding a part of a project which should stay unaware of what would be the final implementation of the interface: it maybe a 100% local implementation, or more probably a ICE servant, or something else which is beyond my control.
Precisely because it is beyond my control, I cannot tightly bind my code with a particular semantic, but ICE require me to do so, exactly because the Prx do not implement the interface.
I must admit I did not understand the final answer to this question, and why it would really be a problem to use the solution proposed by annekat .
I can live with the "IPrx is a I" ...
Anyway, since I am using Java5, I solve this problem for me using generics, and I would like to know whether specialists think this is a good workaround or not.
Thanks in advance.
You start instead from Slice definitions: you define types, interfaces, operations in Slice, and then generate Java (C++, C# etc) code. Different sets of interfaces/classes are generated for the implementations of your remote objects (servants) and for the objects providing access to these objects (proxies).
If you want to have an Ice-independent interface with several possible implementations, one being Ice-based, you would just write your own Java interface and then write an implementation of this interface using an Ice proxy.
Best regards,
Bernard