Hi Tanvir,

> Though the example I used is LogService, the issue is for many other 
> services, such as usage, db access etc
> 


These would be quite different, in that I’m fairly sure that your database 
access is not optional, and should be using a mandatory reference.

> Many examples in the web are using static var to share the @ref instantiated 
> by the framework to the object instantiated by  app code. 

If they use static variables then these are terrible examples - if you have the 
URLs then please let me know so that I can try to get them fixed.

> Question: Is there a better way to do this without refactoring the whole code 
> base?

Your DS components are perfectly capable of instantiating other types from 
inside their bundles, or using utility APIs that are exported. It sounds, 
however, like the codebase may be in need of refactoring. This is often the 
case for applications that have been allowed to become monoliths, and becoming 
a monolith is very easy if you don’t have something like OSGi enforcing module 
boundaries. Applications made of small cohesive modules are usually a lot 
simpler to reason about, and tend not to need more than a few components per 
bundle.

> We can enforce this dependent service activation order using MANDATORY refs, 
> however what to do for OPTIONAL refs? Will "immediate" help?

Immediate will not help, and it is important to stop thinking about activation 
order. All immediate means for a component is that it will be activated as soon 
as its mandatory dependencies are satisfied, even if it is otherwise unused. 

The components/services in an OSGi application will come up in whatever order 
makes sense based on the services and configurations available in the runtime. 
The question that you’re trying to ask is “how can I make sure that my optional 
references *eventually* get bound?”. For this to happen either your reference 
must be dynamic (i.e. the optional dependency can be injected into the running 
component) or greedy (i.e. the component will be restarted if a service can be 
bound) or both. Dynamic references are useful, but can be much harder to manage 
as you need to write thread-safe code. Static Greedy references on the other 
hand are simple to write, but can result in a bit of churn if the optional 
services appear and disappear frequently (a relatively unusual occurrence).

Regards,

Tim


> On 25 Jan 2018, at 16:20, Tanvir via osgi-dev <osgi-dev@mail.osgi.org> wrote:
> 
> Hi Tim,
> 
>   Thank you for your reply. Though the example I used is LogService, the 
> issue is for many other services, such as usage, db access etc. Let me be 
> specific on your reply:
> 
> Your comment: "Static variables are a very bad thing for many reasons"
> 
> Agree. However use of static var seems to be inherent in DS. E.g. @Component 
> class is instantiated by the framework, where the class has to be 
> instantiated by app code, e.g. persistence class or any other utility classes 
> used by the service. Many examples in the web are using static var to share 
> the @ref instantiated by the framework to the object instantiated by  app 
> code. 
> 
> Question: Is there a better way to do this without refactoring the whole code 
> base?
> 
> Your comment:  "code to work both with and without a log service, in this 
> case you do need to be able to handle there being no log service to log to."
> 
> Agree. However something optional does not mean that the ref holder code 
> should run without the OPTIONAL  service when the service is available but 
> not activated. With DS, it is recommended to not use bundle ordering to solve 
> dependent service activation issue, rather use options in DS. We can enforce 
> this dependent service activation order using MANDATORY refs, however what to 
> do for OPTIONAL refs? Will "immediate" help?
>     
>  Question: How to enforce service activation order in DS for OPTIONAL  
> services?
> 
> Thanks
> Tanvir
> 
> 
> On 1/22/2018 3:03 AM, Tim Ward wrote:
>> Hi Tanvir,
>> 
>> I would strongly recommend that you do not use solution A. Static variables 
>> are a very bad thing for many reasons, not least (as you have discovered) 
>> because they completely bypass the lifecycle management of your component. 
>> In answer to the question:
>> 
>> "Question: If we set LogService and RefManager as immediate components 
>> (RefManager  is immediate  by default for  being a Component), is it 
>> guaranteed that  they will be activated before EmpService?"
>> 
>> No - this will not help you. You are stepping totally outside the design of 
>> Declarative Services and the result will be an inconsistent mess.
>> 
>> "Another solution for the above problem is to view LogService as OPTIONAL"
>> 
>> This is actually something different, as it’s saying that you want your code 
>> to work both with and without a log service, in this case you do need to be 
>> able to handle there being no log service to log to.
>> 
>> 
>> To go back to your original question:
>> 
>> "Is there a way to solve this proliferation of DS Components and References?"
>> 
>> Having lots of DS components is a good thing! They are lightweight and they 
>> manage your service dependencies. 
>> 
>> You could use field injection to avoid some boilerplate:
>> 
>> @Component
>> public class Emp implements EmpService {
>>   @Reference
>>   LogService log;
>> }
>> 
>> If you really are allergic to using DS for injecting the Log service then an 
>> alternative is to use something like SLF4J instead. This can be configured 
>> to log to the Log Service (by installing the correct SLF4J back end) and 
>> then you can configure the Log service to log somewhere else if you desire.
>> 
>> Regards,
>> 
>> Tim
>> 
>>> On 22 Jan 2018, at 06:06, Tanvir via osgi-dev <osgi-dev@mail.osgi.org 
>>> <mailto:osgi-dev@mail.osgi.org>> wrote:
>>> 
>>> 
>>> In DS, for accessing a service reference, the class has to be a Component. 
>>> That means to access common  services, such as log service, all classes 
>>> becomes Components. In the following example, to access log service all 
>>> classes in Emp bundle became Components.
>>>  
>>> @Component
>>> public class Emp implements EmpService {
>>>   LogService log
>>>   @Reference (cardinality = ReferenceCardinality.MANDATORY)
>>>   void setLogService(LogService log) { this.log = log; } 
>>>   
>>> }
>>> @Component
>>> public class EmpAddress  {
>>>   LogService log
>>>   @Reference (cardinality = ReferenceCardinality.MANDATORY)
>>>   void setLogService(LogService log) { this.log = log; } 
>>> }
>>> @Component
>>> public class EmpPayroll  {
>>>   LogService log
>>>   @Reference (cardinality = ReferenceCardinality.MANDATORY)
>>>   void setLogService(LogService log) { this.log = log; } 
>>> }
>>>  ....
>>> 
>>> Question: Is there a way to solve this proliferation of DS Components and 
>>> References? 
>>> 
>>> Solution A: We can factor out reference code and move them to a RefManager 
>>> Component. Also maintain a shared static variable to LogService for all 
>>> other classes.
>>> 
>>> @Component 
>>> public class RefManager {
>>>   static LogService log
>>>   @Reference (cardinality = ReferenceCardinality.MANDATORY)
>>>   void setLogService(LogService log) { this.log = log; } 
>>>  static LogService  getLogger() { return log;}}
>>> 
>>> @Component
>>> public class Emp implements EmpService {
>>>    ..
>>>    RefManager. getLogger.log();
>>> }
>>> 
>>> public class EmpAddress  {
>>>      .. 
>>>    RefManager. getLogger.log();
>>> }
>>> public class EmpPayroll  { 
>>>    ..
>>>    RefManager. getLogger.log();
>>> }
>>>  
>>> 
>>> Problem: Now we can end up with null LogService reference even though 
>>> LogService ref  is MANDATORY . E.g. if EmpService  is activated before 
>>> RefManager  or LogService, it gets null LogService ref.
>>>  
>>> Question: If we set LogService and RefManager as immediate components 
>>> (RefManager  is immediate  by default for  being a Component), is it 
>>> guaranteed that  they will be activated before EmpService? 
>>> 
>>> Solution B: 
>>> Another solution for the above problem is to view LogService as OPTIONAL. 
>>> However, an optional reference can be null requiring a null check. That 
>>> means each use of Log Service  api require the following null check.
>>> 
>>> If (log!=null) log.log(..);
>>> 
>>> 
>>> Problem:  Considering that log apis are heavily used, this seems tedious 
>>> and error-prone. Is there a better way of using OPTIONAL reference?
>>> 
>>>  
>>> 
>>> -- 
>>> Best,
>>> Tanvir
>>> _______________________________________________
>>> 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>
> 
> -- 
> Best,
> Tanvir
> _______________________________________________
> OSGi Developer Mail List
> osgi-dev@mail.osgi.org
> 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