Archived

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

Why Java proxies does not implement the slice interface ?

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

Comments

  • I'm afraid I don't understand what you mean. A proxy does not implement an interface. Servants implement interfaces. Proxies are, as the name implies, surrogates for Ice objects, and Ice objects are implemented using servants.

    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.
  • Proxies are supposed to be the remote access of a servant.
    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.
  • PS:
    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.
  • If a proxy would derive from an interface, it would establish an is-a relationship: A proxy for an interface Foo is-a Foo. But this is not what a proxy is about. A proxy is a surrogate for an Ice object, but it is not an Ice object. Therefore derivation would be wrong. In other words, you are not supposed to be able to replace an implementation with a proxy. You are supposed to access an implementation with a proxy.

    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.
  • You say:
    If a proxy would derive from an interface, it would establish an is-a relationship

    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.
  • annekat wrote:
    You say:


    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.
  • Thanks for the tip,

    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.
  • Just curious - which framework did you guys use? What was the licensing issue you faced with Spring?

    Thanks,
    --Venkat.
  • marc wrote:
    [...]

    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:

    [...]

    In light of Waldo et al's seminal paper on distributed computing, does this location transparency argument still hold water?
  • I happen to disagree with Waldo's paper (and I'm on record as having disagreed with it for years). I agree that distributed invocations have different semantics from local invocations, and that a distributed program cannot be written as if it were a non-distributed program. But, from that, it does not follow to me that the API for invoking on a distributed object that happens to be local should be different from the API for invoking on that same object if it happens to be remote.

    Cheers,

    Michi.
  • what about using generics?

    I would like to add some comments to this rather old thread...
    annekat wrote:
    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.

    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
    annekat wrote:
    The modification i suggest is simply:

    public interface IPrx extends Ice.ObjectPrx, I {
    public void doIt():
    ...
    }
    .
    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.
  • bernard
    bernard Jupiter, FL
    With Ice, you don't start with a Java interface and somehow generate code that gives you access to a remote implementation of this interface.

    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