felix-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Richard S. Hall" <he...@ungoverned.org>
Subject Re: Object versions in services
Date Fri, 14 Jun 2013 03:36:38 GMT

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 <fmeschbe@adobe.com> 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 <fmeschbe@adobe.com> 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: users-unsubscribe@felix.apache.org
>>>> For additional commands, e-mail: users-help@felix.apache.org
>>>>
>>>>
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: users-unsubscribe@felix.apache.org
>> For additional commands, e-mail: users-help@felix.apache.org
>>
>>


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@felix.apache.org
For additional commands, e-mail: users-help@felix.apache.org


Mime
View raw message