On 6/13/13 20:55 , Mark Richards wrote:
I thought I'd implement an example of this and I get ClassCastExceptions in
the Consumer.
Please feel free to checkout:
https://bitbucket.org/markalanrichards/discussion-points/overview
It's not that big (each bundle has only one Java class in it).
When these start (in order) everything is fine: service-api, model10,
model15, model20, model-provider10, model-provider15, model-provider20.
However, when I start modelConsumer10, model 1.0 and model 1.5 are fine for
the consumer, but model 2.0 hits the ClassCastException.
What did I miss?
You are basically hiding package dependencies behind generic types.
There is no easy way for the framework to do a consistency check for "T
provide()" in a Provider<T>. It can't do it at resolve time because
there is no "uses" constraint on T since it doesn't know what it is; it
technically might be able to figure it out at run time when doing
service lookups, but that would be tricky and costly and still not
complete since incompatible stuff could still be passed back in Objects
or supertypes and accessed via downcasting.
The only guarantees OSGi gives you are with respect to packages and
their associated "uses" constraints, your example expects it to analyze
all reachable types from a given service interface at run time. It
doesn't do that.
You would have to create specific concrete versions of your generic
interface for each model type so that you could establish a "uses"
constraint between the service interface and the concrete model it provides.
-> richard
Many Thanks
Mark
PS: If you don't wish to checkout/run this, but are interested in what
happens, the output when I start model-consumer10 is:
finding refs
objectClass: [Ljava.lang.String;@df54977
provides: com.example.markoffline.model.Model
service.id: 226
TO STRING: Date: 1371160741853
Description: null
THE LONG: 1371160741853
objectClass: [Ljava.lang.String;@11df24ba
provides: com.example.markoffline.model.Model
service.id: 227
TO STRING: Date: 1371160741856
Description: The time now
THE LONG: 1371160741856
objectClass: [Ljava.lang.String;@373984fd
provides: com.example.markoffline.model.Model
service.id: 228
---
--- Here the bundle hits an exception trace, probably not too useful except
for:
---
Caused by: java.lang.ClassCastException:
com.example.markoffline.model.Model cannot be cast to
com.example.markoffline.model.Model
at
com.example.markoffline.consumer.ModelConsumer.start(ModelConsumer.java:27)
On 13 June 2013 11:27, Felix Meschberger <[email protected]> wrote:
Hi
Am 13.06.2013 um 12:18 schrieb Mark Richards:
Thanks...
"In addition the service registry makes sure, that D only gets V1 Model
service instances and E only gets V2 Model service instances."
I assumed the registry would only care about the versions of Producer and
Consumer, as the Models aren't bound directly to the service.
The service registry does not care for versions at all. It cares to make
sure a consumer (retrieving the service) can use the service by making
sure, the consumer and the service object see the same service object class
objects and thus are compatible.
Regards
Felix
On 13 June 2013 09:56, Felix Meschberger <[email protected]> wrote:
Hi
OSGi wires API by import and export package version.
In you example of two incompatible model classes, you might have bundle
B
export the Model API at version 1.0 and bundle C export the Model API at
version 2.0.
Your consumer bundles D and E would then import the appropriate Model
API
versions such as [1,2) and [2,3).
The actual Model class objects are then different for D and E (even
though
the fully qualified class name is the same). In addition the service
registry makes sure, that D only gets V1 Model service instances and E
only
gets V2 Model service instances.
Hope this helps.
Regards
Felix
Am 12.06.2013 um 17:56 schrieb Mark Richards:
Hi,
I'm new to this list and hopefully this question isn't too long...
please
let me know if you'd like further details.
Context: I'd like to create a service architecture that represents
EIPs,
a
bit like Camel but more OSGi friendly, however the safe wiring of
objects
must ensure the producers are wired to consumers that provide and
consumer
compatible versions of the objects.
Problem: How do you handle the versions dependencies of objects used a
layer beneath the services provided?
I believe this issue also affects the listener model, if you wanted to
use
a generic listener model like so I'm hoping somebody has already solved
it:
interface Listener<T> { //Listener class is handled by bundle
resolution
void Notify(T event); //but what about this T?
}
When you create an implementation you usually know T, so it's quite
easy
to
call "bundleContext.register(Listener.class, this, props)" where props
includes {"listenerOf":"t.class}" and to then filter the class.
However,
I'm not sure where to get the version for T from (it may be an imported
class) and versions are ranges with different rules for import and
export.
Any help advice or also, an idea of whether I'm the only one trying to
do
this would be useful.
Thanks,
Mark
Ps: if it helps here is an example of the style of problem in
semi-pseudo
code.
If you cannot filter the version of the Model through the services
layer
ModelProvider will provide a Date object and ModelConsumer will try to
read
a Long. The two shouldn't be allowed to bind to each other.
bundle A: wiring-api
interface Provider<T> {
T giveMeAnObject();
}
interface Consumer<T> {
void hereIsAnObject(T object);
}
bundle B: model version 1:
class Model {
long getDate();{ return (long) 99 }
}
bundle C: model version 2:
class Model {
Date getDate() { return new Date(); }
}
bundle D: model-provder version 2: import-packages wiring-api 1 and
model 2
class ModelProvider implements Provider <Model> implements
BundleActivator { {
void start(BundleContext context) {
context.register(Provider.class, this, ???? )* // here you'd
need to specify it is model 2, but how do you get this*
}
Model giveMeAnObject() {
return new Model();
}
}
bundle E: consumer imports wiring-api and model 1:
class ModelConsumer implements Consumer<Model>, BundleActivator {
void start(BundleContext context) {
context.register(Consumer.class, this, ???? )* // here you'd
need to specify it is model 1, but how do you get this**
* }*
*
void hereIsAnObject(Model object) {
System.out.println(Long.valueOf(model.getDate())); // if no
object version filtering this will fail as bundle D should not be
connected
to bundle E
}
}
// here I envisage there should be a Provider Manager perhaps along the
lines of that could be exposed to have wiring done through a UI,
interface
or config settings like WireAdmin
// this isn't too important at this point, except it would need some
way
to
manage this *version filtering/matching*!
bundle F: provider-service imports wiring-api
class ProviderManager {
Map<ClassVersion, Provider> providers;
Map<ClassVersion, Consumer, consumers
void registerProvider(ClassVersion<T> provided, Provider<T>
provider);
void registerConsumer(ClassVersion<T> consumed, Consumer<T>
provider);
// methods to lookup and match providers with consumers
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]