Hi Daghan,

I’m not sure whether you’ve shown the final code - I note that the class here 
https://github.com/daghanacay/com.easyiot.device/blob/master/com.easyiot.LT100H.device.provider/src/com/easyiot/LT100H/device/provider/LT100HDeviceImpl.java
  
<https://github.com/daghanacay/com.easyiot.device/blob/master/com.easyiot.LT100H.device.provider/src/com/easyiot/LT100H/device/provider/LT100HDeviceImpl.java>
 does not inject the Web Socket connector.

In any event I would strongly urge you to reconsider the model you have 
selected. Having multiple protocols attached to a single component is the 
antithesis of modular development and gives you multiple real problems in your 
environment

Adding another “new” protocol would involve changing an already complex 
component. The risk of introducing problems when doing this is high.
Deploying a consumer implementation requires all of the dependencies of every 
protocol. If I only want to use Web Sockets I still have to provide the 
dependencies for MQTT
I must *always* configure *all* protocols for every device to avoid errors in 
the component. In the case where I want to use Web Sockets I will still get 
injected with an MQTT client if it is available! If I have no configuration for 
MQTT then the code will NPE/explode in some way when it tries to listen to MQTT
Because all of the references are optional the component will report itself as 
available even when there are no connectors! This is in direct violation of 
your statement that “1- a device should have at least one protocol instance but 
any one of them is optional"


Two simple, static components, one for Web Sockets, one for MQTT make much more 
sense to configure, and the code will be much simper and more reliable. 
Aggregating the feeds into a single feed can easily be achieved by a third 
component with a 1..n cardinality.

I believe that you have also overlooked a significant benefit of the whiteboard 
pattern. At the moment your whiteboard still creates a separate connection for 
every single listener - surely all that is needed is a single connection which 
is then distributed across the services. This is exactly the model for which 
Event Admin exists and it could easily be used to provide your whiteboard.


Effectively your whiteboard could be implemented as the single, static 
Websocket component that I’m recommending that you create. On receipt of the 
websocket callback the transformation callback occurs, then the resulting 
object is sent out using Event Admin.

On the whiteboard listener side the components simply listen on the topic for 
their device, and do what they wish with the data (e.g. store the most recent 
value).

The same model could be used for MQTT, posting to the same topic!

Regards,

Tim



> On 16 Oct 2016, at 08:21, Daghan ACAY <daghana...@hotmail.com> wrote:
> 
> Hi all,
> 
> Thanks for your help. I would like to provide my reasoning why references are 
> optional and dynamic. First of all both protocols and devices are created 
> through configuration. That is, while the system is running a user can create 
> a new device through web console. Every device will have at least one 
> protocol, however a users can capture a "single real" device which "may" 
> provide data from multiple protocols. In the second case "device" is used to 
> correlate data from "possibly" multiple data sources (at this point you might 
> ask why I am transferring same data of same real device through different 
> protocols. I rather think that you did not ask that question and just accept 
> that I should:). At the same time single protocol can be used by multiple 
> devices, by protocol I mean protocol instance that is generated by the 
> corresponding configuration. Hence, relationship between device and protocol 
> becomes many to many. 
> 
> In this case
> 1- a device should have at least one protocol instance but any one of them is 
> optional
> 2- if a new protocol instance is created by the user through configuration 
> during runtime, device should recognize this and start receiving data from it 
> in addition to the original, hence it is dynamic
> 
> Just to clarify one point, if you look at the original code, you can see 
> device itself is not doing anything that a protocol needs to do, e.g. sending 
> receiving data. It is just registering itself to the protocol based on its 
> device specific configuration. This functionality is perfect place for 
> whiteboard pattern I agree but I wanted to keep Tim's solution as well due to 
> simplicity and another reason I will discuss later. Below is the final code, 
> showcasing Tims's "policyOption=greedy" and Peter's whiteboard suggestion.
> 
> You can find device code here:
> https://github.com/daghanacay/com.easyiot.device/blob/master/com.easyiot.LT100H.device.provider/src/com/easyiot/LT100H/device/provider/LT100HDeviceImpl.java
>  
> <https://github.com/daghanacay/com.easyiot.device/blob/master/com.easyiot.LT100H.device.provider/src/com/easyiot/LT100H/device/provider/LT100HDeviceImpl.java>
> 
> Whiteboard code can be found here:
> https://github.com/daghanacay/com.easyiot.protocol/blob/master/com.easyiot.auslora-websocket.protocol.provider/src/com/easyiot/auslora_websocket/protocol/provider/AusloraWebsocketWhiteBoard.java
>  
> <https://github.com/daghanacay/com.easyiot.protocol/blob/master/com.easyiot.auslora-websocket.protocol.provider/src/com/easyiot/auslora_websocket/protocol/provider/AusloraWebsocketWhiteBoard.java>
> 
> 
> Finally the configuration:
> https://github.com/daghanacay/com.easyiot.application/blob/master/com.easyiot.heatmap.application/configuration/configuration.json
>  
> <https://github.com/daghanacay/com.easyiot.application/blob/master/com.easyiot.heatmap.application/configuration/configuration.json>
> 
> 1- From config you can see device.LT100H.1 is getting data from multiple 
> protocols (real.auslora.wss, ttn.staging.mqtt), yet there may be many of type 
> LT100H that might receive data from the same protocol. Also there might be 
> other types of devices that can use the same protocol as in the next item.
> 2- Second device "device.development.board.1" gets data only from 
> "real.auslora.wss"although it can get from the other protocol (optional)
> 3- Assume that someone updated the "real.auslora.wss" configuration or added 
> a new protocol and updated second device, the system should recognize those 
> changes and devices should register/unregister themselves automatically.
> 
> If you read until here and still not confused then I have some more questions 
> about the whiteboard code because I am still not convinced that it is the way 
> to go, mostly because it is more abstracted/indirect/hard-to-understand than 
> Tim's solution:
> 
> 1- What happens if a device is picked up before its corresponding protocol is 
> picked up, the same old timing problem? I tried to use "_" infront of method 
> "_addAusloraProtocol" but will it work or should I do a more elaborate logic, 
> e.g. store all the devices without a corresponding protocol and register them 
> when the new protocol is available? This is a valid case since the user can 
> create the device configuration before the protocol configuration.
> 
> 2- I prefer not to use String and properties Map since it is fragile. Can I 
> use configuration objects instead of "Map<String, Object> props" at 
> "_addAusloraProtocol"? I know I cannot use it in "addAusloraListener" method 
> since the configuration object for the listener, e.g. 
> LT100HDeviceConfiguration.class is not available in the classpath, and I dont 
> want them to be.
> 
> 3- As you can see in the device code above, I had to change the Listener 
> interface with "setProtocolHandler" method to set the protocol reference 
> inside device. This reference is used in "sendData" method. Tim suggested 
> using EventAdmin for this, and listener but in general I do not prefer using 
> EventAdmin since the messages are not type checked, also very hard to apply 
> security. Is there any other way to inject protocol reference into the 
> device? Here is Tim's solution shines because it gets the ttnMqttClient 
> reference directly from OSGi registry.
> 
> Thanks for your suggestions, I hope I executed them correctly. One final 
> round and the design will be settled <OutlookEmoji-😊.png>
> 
> Regards
> -Daghan Acay
> 
> 
> 
> 
> From: osgi-dev-boun...@mail.osgi.org <osgi-dev-boun...@mail.osgi.org> on 
> behalf of Tim Ward <tim.w...@paremus.com>
> Sent: Friday, October 14, 2016 10:48 AM
> To: OSGi Developer Mail List
> Subject: Re: [osgi-dev] DS component life cycle.
>  
> A policy option of Greedy tells DS to shut down and restart your component if 
> a "better" service arrives. The default is Reluctant which avoids stopping 
> the component unless it absolutely has to. Reluctant Static optional services 
> therefore will not pick up their dependencies if they arrive late.
> 
> As we covered earlier, in this case, the simplest option is not to use 
> Optional at all, but to have two components with mandatory references.
> 
> Tim
> 
> Sent from my iPhone
> 
> On 14 Oct 2016, at 11:21, Daghan ACAY <daghana...@hotmail.com 
> <mailto:daghana...@hotmail.com>> wrote:
> 
>> Hi Tim,
>> 
>> Thanks for the sample code. I remember doing this and it somehow did not 
>> bind all the optional dependencies although they were available. However the 
>> "policyOption=greedy" might do the trick. I  will definitely look into it 
>> and see in debug how to component behaves. As for the thread safety and 
>> synchronisation I tried CountdownLatch in @Reference method and it was dead 
>> lock. I should admit I am not huge on multi-threaded applications so I might 
>> have violated millions of rules at that moment <OutlookEmoji-😊.png>  
>> 
>> 
>> From: osgi-dev-boun...@mail.osgi.org <mailto:osgi-dev-boun...@mail.osgi.org> 
>> <osgi-dev-boun...@mail.osgi.org <mailto:osgi-dev-boun...@mail.osgi.org>> on 
>> behalf of Timothy Ward <tim.w...@paremus.com <mailto:tim.w...@paremus.com>>
>> Sent: Friday, October 14, 2016 7:26 AM
>> To: OSGi Developer Mail List
>> Subject: Re: [osgi-dev] DS component life cycle.
>>  
>> Separating the two consumers into separate components would be a far better 
>> encapsulation. There is no reason that one component should be doing both 
>> MQTT and WebSocket work - in fact the configuration that you provide doesn’t 
>> even configure the MQTT reference, meaning that it could get bound to 
>> anything!
>> 
>> You should really separate the two consumers into separate components. What 
>> happens then is down to how the consumed data is supposed to be used. It 
>> appears as though there is no use of “pushed” data (i.e. there is a get 
>> method and that’s it), which seems a bit odd for a data stream like this. I 
>> would really expect the converted data to be published to an Event Admin 
>> Topic. The person who wants to use the data can then register an event 
>> listener, and will get told whenever the data is updated.
>> 
>> In any event, the correct way to handle the original ordering dependency 
>> that you asked about is to do the initialisation in the activate method 
>> (https://github.com/timothyjward/com.easyiot.device/blob/df6999f1cb741a4c55b0ce217169ec912afc6741/com.easyiot.LT100H.device.provider/src/com/easyiot/LT100H/device/provider/LT100HDeviceImpl.java
>>  
>> <https://github.com/timothyjward/com.easyiot.device/blob/df6999f1cb741a4c55b0ce217169ec912afc6741/com.easyiot.LT100H.device.provider/src/com/easyiot/LT100H/device/provider/LT100HDeviceImpl.java>).
>>  
>>  
>> <https://github.com/timothyjward/com.easyiot.device/blob/df6999f1cb741a4c55b0ce217169ec912afc6741/com.easyiot.LT100H.device.provider/src/com/easyiot/LT100H/device/provider/LT100HDeviceImpl.java>
>>   
>> timothyjward/com.easyiot.device 
>> <https://github.com/timothyjward/com.easyiot.device/blob/df6999f1cb741a4c55b0ce217169ec912afc6741/com.easyiot.LT100H.device.provider/src/com/easyiot/LT100H/device/provider/LT100HDeviceImpl.java>
>> github.com <http://github.com/>
>> Contribute to com.easyiot.device development by creating an account on 
>> GitHub.
>> 
>> 
>> Note that I still think that this is a poorly constructed component, as the 
>> optional references aren’t really optional, just two mandatory components 
>> stuck together. I also don’t think that the code needs to be dynamic, but if 
>> you want it to be then I leave the thread safety as an exercise for the 
>> reader ;).
>> 
>> Regards,
>> 
>> Tim
>>> On 14 Oct 2016, at 08:15, Daghan ACAY <daghana...@hotmail.com 
>>> <mailto:daghana...@hotmail.com>> wrote:
>>> 
>>> Hi Peter,
>>> This looks great. I thought about white board pattern but problem is this, 
>>> there is no single mqttProtocolProvider! they are also created through 
>>> factory configuration and bind to device through configuration. Please see 
>>> the actual configuration used in application project here. 
>>> https://github.com/daghanacay/com.easyiot.application/blob/master/com.easyiot.heatmap.application/configuration/configuration.json
>>>  
>>> <https://github.com/daghanacay/com.easyiot.application/blob/master/com.easyiot.heatmap.application/configuration/configuration.json>
>>> Correct me if i am wrong but Whiteboard pattern assumes there is only one 
>>> mqttprotocolprovider. Peter, I still can work with the code that you have 
>>> explained but still won't be as clean. I am thinking of using service 
>>> tracker may be in the device but then it is not DS. I think it is an 
>>> interesting case that might be worthy of you experts time :)
>>> PS: please excuse me if i misunderstand you or i am making this something 
>>> more complicated then it should be.
>>> Cheers
>>> Daghan
>>> Sent by MailWise <http://www.mail-wise.com/installation/2> – See your 
>>> emails as clean, short chats.
>>> 
>>> 
>>> -------- Original Message --------
>>> From: Peter Kriens <peter.kri...@aqute.biz <mailto:peter.kri...@aqute.biz>>
>>> Sent: Friday, October 14, 2016 05:58 PM
>>> To: OSGi Developer Mail List <osgi-dev@mail.osgi.org 
>>> <mailto:osgi-dev@mail.osgi.org>>
>>> Subject: Re: [osgi-dev] DS component life cycle.
>>> 
>>> @Christian: The MQTT client is optional and dynamic. So the activate method 
>>> cannot be used. You need to subscribe/unsubscribe based on the availability 
>>> of the mqtt server.
>>> 
>>> @Daghan:
>>> 
>>> Divide and conquer! You’re trying to do multiple responsibilities in one 
>>> component and that is the antithesis of modularity, also called lack of 
>>> cohesion. This is a perfect example of how things could get simpler by 
>>> choosing the right decomposition.
>>> 
>>> The best solution imho is to introduce a second,component. Let the Device 
>>> component just be a Device, it should not have to worry about Mqtt. After 
>>> all, you could be connected to other event queues. (It also makes it easier 
>>> to test.) You made mqtt optional to reflect this. This is exactly the 
>>> reason the Whiteboard Pattern was invented!
>>> 
>>> This would look like:
>>> 
>>> 
>>>         @Component( property = “subscriptionChannel=” )
>>>         public class LT100HDeviceImpl implements Device, 
>>> TtnMqttMessageListener {
>>>                 // remove the mqtt subscription code but
>>>                 // implement the TtnMqttMessageListener
>>>        }
>>> 
>>> And the whiteboard component. Notice the _ in the _mqtt field. This ensures 
>>> it is set before the event method that has a name that will appear in a 
>>> sorted list later. (References are sorted by name.) (I vaguely recall field 
>>> references are done before bind methods but this makes it certain.)
>>> 
>>>         @Component(immediate=true)
>>>         public class MQTTWhiteboard {
>>> 
>>>                 @Reference
>>>                 TtnMqttProtocol _mqtt;
>>> 
>>>                 @Reference( cardinality = ReferenceCardinality.OPTIONAL, 
>>> policy = ReferencePolicy.DYNAMIC )
>>>                 void addMqttListener( TtnMqttMessageListener l, 
>>> Map<String,Object> props ) {
>>>                         String channel = props.get( “subscriptionChannel” );
>>>                         if ( channel != null && !channel.isEmpty() ) {
>>>                                 _mqtt. subscribe( channel, l );
>>>                 }
>>> 
>>>                 void removeMqttListener( TtnMqttMessageListener l, 
>>> Map<String,Object> props ) {
>>>                         String channel = props.get( “subscriptionChannel” );
>>>                         if ( channel != null && !channel.isEmpty() ) {
>>>                                 _mqtt.unsubscribe( channel );
>>> 
>>>                 }
>>>         }
>>> 
>>> You now created a whiteboard service that can also be used by other Device 
>>> implementations while significantly reducing the complexity of your 
>>> implementation. 
>>> 
>>> This is why after all those years I still love OSGi … you can only do this 
>>> when you have dynamic components. As your struggle showed, trying to manage 
>>> this is quickly becoming quite complex. Whenever you enter in such a 
>>> struggle, think, lack of cohesion is often your problem.
>>> 
>>> Kind regards,
>>> 
>>>         Peter Kriens
>>> 
>>> 
>>> > 
>>> > On 14 okt. 2016, at 08:09, Christian Schneider <ch...@die-schneider.net 
>>> > <mailto:ch...@die-schneider.net>> wrote:
>>> > 
>>> > In your case simply inject the ttnMqttClient in the @Reference and do the 
>>> > subscribe in @Activate when you get the config and the unsubscribe in 
>>> > @Deactivate.
>>> > 
>>> > Christian
>>> > 
>>> > 2016-10-13 23:00 GMT+02:00 Daghan ACAY <daghana...@hotmail.com 
>>> > <mailto:daghana...@hotmail.com>>:
>>> > Hi all,
>>> > 
>>> > I am trying to create a component that is instantiated by ConfigAdmin and 
>>> > uses multiple references to operate. Basically the component should 
>>> > instantiate through a factory configuration and use that configuration to 
>>> > set up its own @Reference s. You can see the code here:
>>> > 
>>> > https://github.com/daghanacay/com.easyiot.device/blob/master/com.easyiot.LT100H.device.provider/src/com/easyiot/LT100H/device/provider/LT100HDeviceImpl.java
>>> >  
>>> > <https://github.com/daghanacay/com.easyiot.device/blob/master/com.easyiot.LT100H.device.provider/src/com/easyiot/LT100H/device/provider/LT100HDeviceImpl.java>
>>> > 
>>> > All the mentioned @Reference ed components are instantiated by 
>>> > configuration as well, so at a given time the @Reference might not be 
>>> > available but my own component should still work. yet should the 
>>> > Reference available then it should be injected, basic 0-1 strategy.
>>> > 
>>> > Problem I am facing with the current form of the code is that, the 
>>> > @Reference injection is happening before the @Activate method is called. 
>>> > This leads to NPE in the @Reference method due to null configuration. Is 
>>> > it possible to make this code work such that config is provided to the 
>>> > component before the dependency injection?
>>> > 
>>> > I have tried annotating the class fields and set them "volatile". I even 
>>> > make them a list and use the class fields in the activate method this 
>>> > time the class fields were null due to 0-1 strategy. so I end up with 
>>> > annotating the methods.
>>> > 
>>> > I might have designed this all wrong, so any help simple or fundamental 
>>> > is appreciated.
>>> > 
>>> > Regards
>>> > 
>>> > -Daghan
>>> > 
>>> > Sent by MailWise – See your emails as clean, short chats.
>>> > 
>>> > 
>>> > _______________________________________________
>>> > OSGi Developer Mail List
>>> > osgi-dev@mail.osgi.org <mailto:osgi-dev@mail.osgi.org>
>>> > https://mail.osgi.org/mailman/listinfo/osgi-dev 
>>> > <https://mail.osgi.org/mailman/listinfo/osgi-dev>
>>> > 
>>> > 
>>> > 
>>> > -- 
>>> > -- 
>>> > Christian Schneider
>>> > http://www.liquid-reality.de <http://www.liquid-reality.de/>
>>> > 
>>> > Open Source Architect
>>> > http://www.talend.com <http://www.talend.com/>
>>> > _______________________________________________
>>> > OSGi Developer Mail List
>>> > osgi-dev@mail.osgi.org <mailto:osgi-dev@mail.osgi.org>
>>> > https://mail.osgi.org/mailman/listinfo/osgi-dev 
>>> > <https://mail.osgi.org/mailman/listinfo/osgi-dev>
>>> 
>>> _______________________________________________
>>> OSGi Developer Mail List
>>> osgi-dev@mail.osgi.org <mailto:osgi-dev@mail.osgi.org>
>>> https://mail.osgi.org/mailman/listinfo/osgi-dev 
>>> <https://mail.osgi.org/mailman/listinfo/osgi-dev>
>> _______________________________________________
>> OSGi Developer Mail List
>> osgi-dev@mail.osgi.org <mailto:osgi-dev@mail.osgi.org>
>> https://mail.osgi.org/mailman/listinfo/osgi-dev 
>> <https://mail.osgi.org/mailman/listinfo/osgi-dev>_______________________________________________
> OSGi Developer Mail List
> osgi-dev@mail.osgi.org <mailto:osgi-dev@mail.osgi.org>
> https://mail.osgi.org/mailman/listinfo/osgi-dev 
> <https://mail.osgi.org/mailman/listinfo/osgi-dev>
_______________________________________________
OSGi Developer Mail List
osgi-dev@mail.osgi.org
https://mail.osgi.org/mailman/listinfo/osgi-dev

Reply via email to