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 forbeing 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 commonservices, 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
--
Best,
Tanvir
_______________________________________________
OSGi Developer Mail List
osgi-dev@mail.osgi.org
https://mail.osgi.org/mailman/listinfo/osgi-dev