Eclipse RCP 4 use bundle via declarative service - osgi

I have written an OSGi bundle to use it in my eclipse 4 rcp application. The usage of the service works fine if I add the dependencies, register these service in my activator and inject it in my class.
In activator
IUserService service = new TestUserService();
context.registerService(IUserService.class.getName(), service, null);
In my class
#Inject
IUserService service;
service.getSth();
I read that using bundles via declarative services should be the better way. So changed my implementation.
I created a component definition in my bundle to provide my service:
<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="usermanagement.test">
<implementation class="usermanagement.test.TestUserService"/>
<service>
<provide interface="usermanagement.IUserService"/>
</service>
</scr:component>
Then I removed the service registration from my activator and created an service consumer class:
public class UserServiceConsumer {
private IUserService service;
public synchronized void setQuote(IUserService service) {
this.service = service;
}
public synchronized void unsetQuote(IUserService service) {
if (this.service == service) {
this.service = null;
}
}
}
and another component definition:
<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="UserServiceConsumer">
<implementation class="services.UserServiceConsumer"/>
<reference bind="setService" cardinality="1..1" interface="usermanagement.IUserService" name="IUserService" policy="static" unbind="unsetService"/>
</scr:component>
After these modifications the injection of my serivce does not work anymore. The problem is that the injected service reference is NULL everytime.
Does anyone know why? Did I forgot something?
Thanks a lot!

I can suggest a few things you can do to debug.
Have you actually got an scr implementation in your runtime? SCR (another name for declarative services) isn't included in Equinox core, so you'll need to include it. Most people use the Felix SCR bundle - it will sit very happily on top of Equinox.
Since Declarative Services just use services, you can change one half of your app at a time, to identify whether it's the service consumption or registration which isn't working.
You can also use the Equinox console to inspect your service registration. Use 'ss' to identify your bundle, then 'bundle [no]' to see what services are registered and consumed. If you're using Felix SCR, there are also Equinox console extensions, so you can use 'scr list' to see all services which a bundle attempts to register (and their state), and 'scr info' for more details on a particular service.

I have found a solution.
In the manifest file of my service I have added the following line:
Bundle-ActivationPolicy: lazy
After that the userServiceConsumer and component definition in my application are unneeded.
In a view class I can do the following now:
public class MyPart {
private IUserService uServ;
#Inject
public MyPart(IUserService uServ) {
this.uServ = uServ;
if (uServ != null)
System.out.println("UserService available");
else
System.out.println("UserService == null");
}
Via DI my service is injected in constructor of the view. That works for me!

I think declarative services will not work in your UI class as it will not be created by the SCR but by Eclipse.
So what you can try is to leave the UI as it was with #Inject and only change the bundle providing the service to use DS.
Basically I would not even try to change the UI side. The #Inject notations is much less overhead than the declarative services.

Related

Are services in AEM really singleton?

I have an interface which I have implemented. I have annoted the impl with #Component and #Service of the package org.apache.felix.scr.annotations.
I wrote a simple constructor for my impl
public MyImpl(){
LOG.info("New instance created!!");
}
I also added loggers in #activate and #deactivate method.
I expected to see "New instance created!!" only once BUT I can see activate and deactivate method being called per request I make on a page(This service is invoked by A Sling Model which is used in that page)
What I saw was "New instance created!!" logged several times.
This means the OSGi container create multiple instances of my Service and called the activate and deactivate method every time.
This shows that this is not a Singleton.
The Object should be discarded only when I uninstall my bundle.
Please help me understand what is going on here.
I WANT TO IMPLEMENT A TRUE SINGLETON IN AEM
I have implemented this in AEM 6.5 instance which uses Apache Felix.
Edit:
Adding Service properties:
aemRootUrl http://localhost:8080
api.http.connections_manager.timeout 60000
api.http.cookie_max.age 18000
api.http.max_connections 200
api.http.max_connections_per_host 20
api.http.timeout.connection 300000
api.http.timeout.socket 300000
api.server.ssl.trust_all_certs true
api.server.url https://10asdasdsad
api.server.username admin
component.id 3925
component.name com.example.foundation.core.connection.impl.HybrisConnectionImpl
non_akamai.api.server.url hadasdadasd
service.bundleid 585
Service PID com.example.foundation.core.connection.impl.HybrisConnectionImpl
service.scope bundle
Using Bundles com.example.dumb-foundation.core (585)
Values altered to hide client specific information
EDIT::
I've removed the SCR annotations and replaced them with OSGI annotations here I've explictly specified
#Component(service =HybrisConnection.class, immediate=true,scope = ServiceScope.SINGLETON)
But still is shows as scope=bundle.
Should I enforce Singleton and OSGi annotations on it's dependencies as well for this to be a proper Singleton?
In declarative services (which is what you use behind the scenes) there are some cases when a component (and its service) is unpublished.
By default a simple component with immediate=true will come up when the bundle starts and go down when it stops.
If your component has any mandatory service dependencies (#Reference) then it will only be active while all dependencies are present. So if at least one dependent service goes away the component will be deactivated.
In addition the component might get restarted when config is not present at start but added later. If you want to avoid this make the config required.
Every thing #Christian Schneider said is true.
They AEM services are Singletons but are deactivated/unpublished at times. This might be for various reasons.
I faced a horrible issue because of ConfigurationAdmin service. Using this services caused our OSGi config files to be bound to the wrong bundle i.e. SlingModels. bundle within AEM.
the only way to access this is by getting the service using configAdmin.getConfig(PID).setBundleLocation(null);
BUT Doing this causes the service that is linked to this configuration to restart.
So every time I did config.setBundleLocation(null) the service restarted.
The best and most awesome way to resolve this is use OCD to define configuration for OSGi Services linked to OSGi config.xmls
AND NEVER EVER EVER use configuration Admin
If you want to access properties of another service Say ServiceA want to read ServiceB's title property set in com.example.serivce.impl.ServiceB.xml
Then in ServiceB in the #activate method read the props from OCD config and set it in instance level and have ServiceA inject ServiceB as it's dependency and use the property needed.
eg.
class ServiceA{
#Reference
private ServiceB serviceB;
public void someMethod(){
serviceB.getTitle(); // Successfully read property of another service i.e.
ServiceB without using ConfigurationAdmin.
}
}

Dropwizard: dropwizard-guicey sub-resource locators

I'm migrating my application from Jersey2/HK2 to Dropwizard. I'm using dropwizard-guicey to integrate Guice into my application while maintaining some of my HK2 bindings/features.
Dropwizard-guicey binds all resources in singleton scope by default, which leaves me wondering -- what is the suggested way to bind sub-resources in this situation? In Jersey, I can do something as simple as
#Path("{pathParamId}/sub-resource")
public Class<MySubResource> mySubResource() {
return MySubResource.class;
}
But my subresource class then looks like this
public class MySubResource {
private String id;
public MySubResource(#PathParam("pathParamId") id) {
this.id = id;
}
}
It doesn't seem that Dropwizard is able to pick up on the dependencies that Guice binds in MySubResource, since the resources are all managed by Jersey.
What I'm ultimately looking for is the per-request bindings that Jersey gives by default for resources and Guice to do the injection beneath that level.
In your example, root resource will be managed by guice (installed by resource installer) and sub resource will be created by HK (per request).
To use guice services in sub resource you need to enable hk guice bridge:
Add org.glassfish.hk2:guice-bridge:2.5.0-b32 dependency
enable bridge option with .option(GuiceyOptions.UseHkBridge, true).
I add complete demo to the samples repo. It also shows how your case could be implemented with pure guice.

Axis2(aar) + spring, without a servletContext

Greetings dear Stackoverflow users, I have been lately in lots of pain with one specific problem with axis2 web services with Spring framework. I have read lots of different guides and read different forums but found people with the same problems but with no solutions. Basically ended up holding the monitor with both of my hands and yelling "What did you find out BudapestHacker938?". Anyway my axis2 web service class needs Spring beans and therefore they are autowired inside the web service class. Everything works so well inside the jetty server where I have servletContext. Just define needed listeners in web.xml and it works. Such a bliss. But unfortunately all good things come to the end in some point, for me, the devil is CICS environment inside of mainframe. There is no servletcontext like in Jetty/Tomcat, luckily it still has axis2 support. So according to the different user-guides I decided to archive my web-service into .aar and added it under the services folder. Axis2 folder structure is the following:
repository/
modules
services
When I am building this .aar archive then I am also generating my own wsdl, not using axis2 inbuilt wsdl generator which according to services.xml generates the services out of the given class (when I am running the axis2server, not using because doesn't like JAX-WS annotations as far as I know). To initialize Spring framework, I needed to write little SpringInit class which initializes Spring beans. Unfortunately it also for some reason initializes my web-service class according to its annotations and then occupies the main port(suspect that SpringInit intializes by its own the web service class since it is also defined as a Spring bean and SpringInit extends Axis2 class ServiceLifeCycle) and I get JVM BIND exception where it is stating that address is already in use. I would like to have the service built up according to the wsdl which is stored inside of the WSDL rather than generate new one, because I have various environments: 1) local machine - Jetty 2) mainframe. Anyway I give an insight to my services.xml:
<service name="Absence" class="org.services.SpringInit">
<description>
random description
</description>
<parameter name="ServiceTCCL">composite</parameter>
<parameter name="useOriginalwsdl" locked="false">true</parameter>
<parameter name="ServiceObjectSupplier">org.apache.axis2.extensions.spring.receivers.SpringAppContextAwareObjectSupplier</parameter>
<parameter name="ServiceClass">org.services.Absence</parameter>
<parameter name="SpringBeanName">absence</parameter>
<parameter name="SpringContextLocation">META-INF/applicationContextAar.xml</parameter>
</service>
Spring applicationContextAar.xml, little bit refactored it for dear Stack community:
<beans>
<bean id="applicationContext" class="org.apache.axis2.extensions.spring.receivers.ApplicationContextHolder" />
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>
<bean id="ds" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.h2.Driver" />
<property name="url" value="jdbc:h2:tcp://localhost/~/devDb" />
<property name="username" value="sa" />
<property name="password" value="" />
</bean>
<bean id="absence" class="org.services.Absence"></bean>
<bean id="jtemplate" class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate">
<constructor-arg ref="ds"></constructor-arg>
</bean>
<bean id="datasetFactory" class="org.vsam.DataSetFactory"></bean>
<bean id="dataManagerFactory" class="org.datamanager.DataManagerFactory"></bean>
<bean id="absenceFactory" class="org.services.AbsenceFactory"></bean>
<bean id="h2Database" class="org.dataset.H2Database"><constructor-arg ref="jtemplate"></constructor-arg>
</bean>
<bean class="org.springframework.remoting.jaxws.SimpleJaxWsServiceExporter"></bean>
</beans>
My SpringInit class looks something like that:
public class SpringInit implements ServiceLifeCycle {
public void startUp(ConfigurationContext ignore, AxisService service) {
try {
ClassLoader classLoader = service.getClassLoader();
ClassPathXmlApplicationContext appCtx = new
ClassPathXmlApplicationContext(new String[] {"applicationContextAar.xml"}, false);
appCtx.setClassLoader(classLoader);
appCtx.refresh();
} catch (Exception ex) {
ex.printStackTrace();
}
}
public void shutDown(ConfigurationContext ctxIgnore, AxisService ignore) {}
}
Now we are moving to org.services.Absence.class, it is an ordinary JAX-WS web-service class with following header (contains JAX-WS annotations):
#WebService(name = "AbsenceService", serviceName = "Absence", portName = "Absence",
targetNamespace = "http://www.something.org/Absence")
public class Absence extends ServiceHandlerBase {
#Autowired
private AbsenceFactory absenceFactory;
#Autowired
private DataManagerFactory dataManagerFactory;
#Autowired
private DataSetFactory dataSetFactory;
...
}
Containing methods like that:
#WebMethod
#WebResult(name = "AbsenceResponse")
public SearchAbsenceRecordsResponse invokeSearchAbsenceRecords(
#WebParam ServiceRequest request,
#WebParam SearchAbsenceRecordsRequest absenceRequest) {...}
One alternative is to add "servicejars" folder into "repository" folder and populate it with absence.jar which has all its dependencies in the sub-folder "lib". Axis2 then automatically runs absense.jar since it has JAX-WS annotation. But in there when I call out the web-service for example with SOAP-UI, it doesn't have Spring initialized since I don't know how to initialize Spring in that solution. Maybe someone has any expertise about that.
TL;DR
How do I get my Spring beans initialized in manner that it doesn't start the services in the web service class according to the annotation and would rather build up services according to the wsdl?
You are welcome to ask questions.
How I initialized Spring inside of CICS without servletcontext?
Basically until today the SOAP web services have been published through servicejars which means into the repository folder has been created "servicejars" folder which cointains jars which have been built from the web service classes. "servicejars" subfolder "lib" contains all the dependencies which web service jars need.
At first I learnt from the web(Axis2 homepage, there was an instruction about axis2 and spring integration) for initializing Spring in Axis2 web service I need .aar archive and SpringInit service defined in services.xml. But this brought lots of problems since having old architecture built on jaxws and jaxb there was a huge need for refactoring the web services layer. Axis2 tolerated jaxws annotations only with "servicejars" solution. Initing Spring with SpringInit class meant that it initializes Spring beans according to the application context. This now runs web service bean(absence bean in previous post) as a separate web service and occupied 8080 port, when time came for the web service creation according to WSDL I got an error "JVM bind address already in use". So after that I figured I should create the service according to the absence Spring bean and let axis2server generate the WSDL, but axis2server didn't like jaxws annotation and even without them it didn't like my jaxb DTOs.
Therefore, I decided to drop .aar architecture and went back to the "servicejars" architecture. Unfortunately in there I didn't have services.xml support, to define the potential SpringInit service.
Since jaxws web services are the only entrypoints then I decided do the following (initialize Spring beans in the web service layer):
#WebService(name = "AbsenceService", serviceName = "Absence", portName = "Absence",
targetNamespace = "http://www.something.org/Absence")
public class Absence extends ServiceHandlerBase {
private static AbsenceFactory absenceFactory;
private static DataManagerFactory dataManagerFactory;
private static DataSetFactory dataSetFactory;
static {
try {
ClassPathXmlApplicationContext appCtx = new
ClassPathXmlApplicationContext(new String[] {"applicationContext.xml"}, false);
appCtx.refresh();
absenceFactory = (AbsenceFactory) appCtx.getBean("absenceFactory", AbsenceFactory.class);
dataManagerFactory = (DataManagerFactory) appCtx.getBean("dataManagerFactory", DataManagerFactory.class);
dataSetFactory = (DataSetFactory) appCtx.getBean("datasetFactory", DataSetFactory.class);
} catch (Exception ex) {
ex.printStackTrace();
}
}
...
}
As you can see when this class is being called out, it will initialize applicationcontext and since it is static, all the spring beans will stay in the memory until the end(when service is closed). In other classes autowiring works perfectly, no need to get these beans wired manually.
In the end, I didn't find the possiblity to initialize Spring in the matter as I hoped through .aar architecture, but I found a work around with the guidance of a senior programmer. Huge thanks to him! And now the possible solution is visible for all StackOverFlow users.
EDIT:
In applicationContext.xml I had:
<bean class="org.springframework.remoting.jaxws.SimpleJaxWsServiceExporter"/>
Tries to create web services with Absence.class(absence bean). Removed it since I can in local machine as well use pre-generated WSDL with Jetty (originally was used for creating web service in the local machine, like I said before, I have local development environment and it should be also compatible with CICS, now it is solved).

Setting properties in Adobe CQ5

I'm working on CQ5 based app, which is a whole new area for me as I was mainly working on Spring based web-apps before.
The app is maven project based on Blue-prints archetype(http://www.cqblueprints.com/xwiki/bin/view/Blue+Prints/The+CQ+Project+Maven+Archetype).
Now I have a question, what is a standard approach to add some properties, that would normally go to config.properties (or alike) file in standard web-app. Properties that contain things like hostNames, accountNumbers and alike.
Cheers.
I'm not familiar with blueprints, but as I understand that's just a way to generate your CQ project structure, so I assume it doesn't have any real impact on how you manage configuration parameters.
CQ5 is based on Apache Sling, which uses the OSGi ConfigAdmin service for configurable parameters, and provides a few tools to make this easier.
You can see an example of that in the PathBasedDecorator Sling component, which uses the #Component annotation to declare itself as an OSGi component:
#Component(metatype=true, ...)
and later uses an #Property annotation to declare a multi-value configurable parameter, with default values:
#Property(value={"/content:2", "/sling-test-pbrt:2"}, unbounded=PropertyUnbounded.ARRAY)
private static final String PROP_PATH_MAPPING = "path.mapping";
That value is then read in the component's activate() method:
final Dictionary<?, ?> properties = componentContext.getProperties();
final String[] mappingList = (String[]) properties.get(PROP_PATH_MAPPING);
and the OSGi bundle that contains that component provides a metatype.properties file to define the name and label of the configurable parameter.
That's it - with this, Sling and the OSGi framework generate a basic config UI for the component, that you can access from /system/console/config, and manage your component's activation and reactivation automatically if configuration parameters change.
Those configurations can also come from the JCR repository, thanks to the Sling installer which picks them up there, you can find a number of those in folders named "config" under /libs and /apps in your CQ5 repository.
Another option is to use JCR content directly, depending on how your configurable parameters are used. You could tell your component that its config is under /apps/foo/myparameters in the repository (and make just that value configurable), and add JCR properties and child nodes under that node as needed, that your component can read. The disadvantage is that your #Component won't be restarted automatically when parameters change, as happens when using OSGi configurations directly.
Long explanation...hope this helps ;-)
Thanks a lot to Bertrand, your answer really pointed me in the right direction.
What I did was I created .ConfigService.xml for each of my ran modes, which looks like that:
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0"
jcr:primaryType="sling:OsgiConfig"
myconfig.config="{String}My Value"/>
Then in my ConfigService looked like that:
#Component(immediate = true, metatype = true)
#Service(ConfigService.class)
public class ConfigService {
private Dictionary<String, String> properties;
#SuppressWarnings("unchecked")
protected void activate(ComponentContext context) {
properties = context.getProperties();
}
protected void deactivate(ComponentContext context) {
properties = null;
}
public String getProperty(String key) {
return properties.get(key);
}
}
Than I just use ConfigService if I need to get a config property accessing it using #Reference.
I hope that can help someone!
ConfigService example may not be the best approach since the ComponentContext should only be depended upon during component activation and deactivation.

OSGi: Is it valid to register services within a declarative service component activation method?

This is a duplicate of another question, but copying from the other one:
I've run into an issue with Felix SCR where I get the message:
ServiceFactory.getService() resulted in a cycle
The reason this appers to be occuring is because within an activation method, call it ServiceAImpl (which provides ServiceA), the service registers another service, call it ServiceB.
I have another service component, call it ServiceCImpl, which depends on both ServiceA and ServiceB. By ServiceAImpl registering ServiceB, ServiceCImpl has become satisfied and within the same call to activate ServiceAImpl, the ServiceCImpl binding methods are called. When the binding method for ServiceA is called, the cycle is detected and the component fails to initialize.
Maybe there is a way to allow the SCR to wait to bind the ServiceCImpl or maybe I need to be registering ServiceB differently?
I guess what doesn't make sense is why the Felix SCR will activate ServiceCImpl within the activation method of ServiceAImpl. I wouldn't think that ServiceCImpl would be considered satisfied until after the activation method has exited. Perhaps this is an issue of using declarative services while still registering services directly with the framework?
Haven't tried other SCR implementations, like Equinox's version, but I might try that to see if there is a difference, but maybe somebody knows if this is a OSGi thing or a Felix thing?
Additional Info: As to why ServiceB is not a service component...ServiceA actually has a service reference of 0..n for another service, call it ServiceD. Everytime a ServiceD interface is provided by a component, a ServiceB is registered using the same service object. Normally the same provider of ServiceD could provide ServiceB, but the idea is to make the overall interface for developers more simplistic so they don't have to provide multiple service interfaces (also, ServiceB has some properties that are set automatically that would have to be done manually and possibly could be done incorrectly).
The reason this appears to be happening is that ServiceAImpl is a delayed component that has already been loaded so ServiceA is in fact already resgistered before the component is activated. However, when another component comes along that needs ServiceA, this causes ServiceAImpl to be activated. Part of the activation process of ServiceAImpl is to register ServiceB which immediately causes ServiceCImpl to be activated. A change was made in FELIX-2368 to immediately activate a component by making most SCR operations synchronous.
A workaround is to make ServiceAImpl an immediate component which isn't desired as it shouldn't be activated if nothing needs the service. In this case, the activation method is completed when the component is loaded and by the time it is needed and bound to another component there is no problem.
I've tried to recreate this scenario with a small set of test bundles and the ProSyst OSGi FW.
However, if I register a service with DS, I am not able to register an other service from within the activate() method. If I just use DS to obtain services, I can register services as usual. So there is probably really a problem with DS/SCR...
Example:
public class ServiceAImpl implements ServiceA, ServiceB, ManagedService {
public void activate(ComponentContext _context) {
_context.getBundleContext().registerService(
ManagedService.class.getName(),
this,
null);
_context.getBundleContext().registerService(
ServiceB.class.getName(),
this,
null);
}
#Override
public void doA() {
System.out.println("Doing A Stuff");
}
#Override
public void doB() {
System.out.println("Doing B Stuff");
}
#Override
public void updated(Dictionary arg0) throws ConfigurationException {
}
}
This class will register 2 Services (ServiceB, ManagedService) with this bnd. file:
Private-Package: org.test.impl
Service-Component: org.test.impl.ServiceAImpl
Bundle-Category: test
but only 1 service (ServiceA) with this sample:#
Private-Package: org.test.impl
Service-Component: org.test.impl.ServiceAImpl;provide:=org.test.ServiceA
Bundle-Category: test
So probably you should/have to try to register the services either via DS/SCR or the "classic way" via bundle context.

Resources