river-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Peter Firmstone <j...@zeus.net.au>
Subject Re: correctness, generics, and spaces
Date Fri, 03 Jun 2011 04:14:48 GMT
James Grahn wrote:
> What is the bigger picture you're concerned with?
Reliability, developers experiencing unexpected run time errors and 
compatibility issues in deployed code when using Generics in Service API.

In our earlier discussions I provided an example of how generics can 
remain inside compile time boundaries while interacting with a service.

I have an experimental section that can be found on svn.

http://svn.apache.org/viewvc/river/jtsk/skunk/pepe/src/org/apache/river/api/lookup/

I've used a wrapper class that performs type checks, so the client can 
use generics safely, this gets rid of most of the boilerplate code 
without the compromise in type safety.

If you use a wrapper class with your new javaspace interface using 
generics, you can use the existing Javaspace API,  and perform type 
checks in the wrapper class, this will eliminate the boilerplate code. 

Since this sort of wrapper class could be reused by a number of clients, 
it might make sense to use annotations, or a wrapper service as Gregg 
mentioned.

When the wrapper class receives the return object, it checks it's class 
is the same type as the parameter before returning it to the client, if 
incorrect it can throw a RemoteException that will be handled by the 
client rather than a runtime exception which will cause the client jvm 
to exit.

But because it can be difficult to test for generic types in java 
syntax, it would appear more logical to weave the check in byte code 
when the Generic type has been replace by a specific known cast.  So we 
throw a RemoteException prior to the cast, rather than a Runtime exception.

Alternatively we can just catch a ClassCastException and treat it the 
same as a RemoteException.

Doing so would allow people to develop using Generics in their service 
API, without degrading reliability.   This doesn't take into account any 
incompatibilities that Generics would introduce to services, just type 
safety and reliability.

Obviously during lookup, we'd want to ensure we've selected the 
implementation of the service we want.

EG:

interface DeliveryService<T> {
<T> deliver();
}

Due to erasure T will be replaced by Object, in all cases, now we might 
have a service that delivers Apples, another might deliver Sausages, you 
don't want a Sausage if your expecting an Apple.

In this case you'd want an Entry in the lookup service that defines the 
expected return value.  However a service Entry might be misconfigured 
(the risk arises whenever data is duplicated) and return a Papaya 
instead of a Sausage.

If the client bytecode performs a type check, the client will be able to 
catch an exception

So it's worth asking a question, should we promote the use of Generics 
in Service API?

We could require they must explicitly declare a ClassCastException as 
well as a RemoteException or IOException and leave the onus on the 
client to catch the ClassCastException?

So far there have been the following proposed approaches for handling 
Generics over Remote connections:

   1. With force of sufficient reasoning for each application, attempt
      to avoid incorrect type casts.
   2. Provide a wrapper class for a service (Gregg's also made a similar
      suggestion), to perform type conversions over compile time boundaries.
   3. Provide a tool to weave class cast checks that throw a subclass of
      RemoteException.
   4. Require a Service that contains Generics to declare it throws
      ClassCastException, even though this is a runtime exception.

4 is ok for the return values, but what about Generic parameters?  On 
the service side,  the server would need to catch a ClassCastException 
and return a RemoteException to the client if it needs anything other 
than Object.

The Service would need an Entry describing Generic parameter types it 
accepts?

The Service and it's smart proxy were compiled together, so they are 
type compatible, however the client and smart proxy were compiled 
separately, this is exactly where ClassCastExceptions will occur with 
compiler generated type casts when the proxy and client interact.  A 
ClassCastException will cause a runtime exception in the client JVM, it 
will exit.  It could potentially be used for DOS attacks.

The Service API contract between the client and proxy will have a degree 
of uncertainty when using Generics, it's a vague contract that's missing 
a vital piece of information due to erasure. 

This degree of uncertainty doesn't exist in an interface lacking 
Generics.  Note the Service API doesn't need to extend Remote, it can be 
a local interface.

This is an interesting exercise, but I do wonder what exactly it is we 
gain by using Generics in Service API?

It's worth noting that Generics are not supported in arrays either, 
developers readily accept that design decision, not all developers 
appear ready to accept the limitations Generics present with separately 
compiled code.

This is a limitation of the Java language rather than a limitation with 
River.

I'm not convinced we should promote the use of Generics in Service API, 
but I encourage James to continue with his experiment and perhaps even 
release an implementation of Generic JavaSpaces, this could become a 
subproject if there's enough interest.  In James case JavaSpace can 
infer the ambiguous Generic information via the template parameter, but 
the client must trust the JavaSpace service to return the correct type 
or be prepared to catch a ClassCastException.

Remember this is our first release of River that uses Java 5 language 
features, so we must carefully consider their application.  Generics 
also introduce additional restrictions evolving API, while retaining 
backward compatibility.

I apologise in advance, I won't be able to continue this conversation 
due to external time pressures.

Peter.


Mime
View raw message