I am doing a self updating application using Apache Felix and I can't seem to forcibly restart Felix after update. I did some tricks to simulate the restart process by using some kind of application State.
public class LauncherActivator implements BundleActivator {
public static LauncherState State;
#Override
public void start(BundleContext context) throws Exception {
...
LauncherApplication.State = LauncherState.READY;
Platform.runLater(() -> {
try {
new LauncherApplication().start();
} catch (Exception ex) {
Logger.getLogger(LauncherActivator.class.getName()).log(Level.SEVERE, null, ex);
}
});
}
}
If there are updates detected I would just change the global state to LauncherAppliation.State = LauncherState.RESTART; if the application detects the change in State I will just simply call BUNDLE_MAP.get('application.activator').update();, BUNDLE_MAP is some kind of a HashMap that stores all running bundles on start.
I tested it and it worked, I can see in the logs that the activator bundle is being updated and the simple restart mechanism reruns the activator bundle but there are times that it doesn't rerun the activator bundle and the bundle state is already ACTIVE.
So what would be the right way to restart Apache Felix using the activator bundle or any bundle in general?
It is all in the documentation all this time!
Starting the Framework Instance
The start() method is used to start the framework instance. If the init() method was not invoked prior to calling start(), then it is invoked by start(). The two methods result in two different framework state transitions:
init() results in the framework instance in the Bundle.STARTING state.
start() results in the framework instance in the Bundle.ACTIVE state.
The init() method is necessary since the framework does not have a BundleContext when it is first created, so a transition to the Bundle.STARTING state is required to acquire its context (via Bundle.getBundleContext()) for performing various tasks, such as installing bundles. Note that the Felix framework also provides the felix.systembundle.activators property that serves a similar purpose, but is not standard. After the init() method completes, the follow actions have been performed:
Event handling is enabled.
The security manager is installed if it is enabled.
The framework is set to start level 0.
All bundles in the bundle caches are reified and their state is set to Bundle.INSTALLED.
The framework gets a valid BundleContext.
All framework-provided services are made available (e.g., PackageAdmin, StartLevel, etc.).
The framework enters the Bundle.STARTING state.
A call to start() is necessary to start the framework instance, if the init() method is invoked manually. Invoking init() or start() on an already started framework as no effect.
Stopping the Framework Instance
To stop the framework instance, invoke the stop() method, which will asynchronously stop the framework. To know when the framework has finished its shutdown sequence, use the waitForStop() method to wait until it is complete. A stopped framework will be in the Bundle.RESOLVED state. It is possible to restart the framework, using the normal combination of init()/start() methods as previously described.
Launching a Framework
Launching a framework is fairly simple and involves only four steps:
Define some configuration properties.
Obtain framework factory.
Use factory to create framework with the configuration properties.
Invoke the Framework.start() method.
In reality, the first step is optional, since all properties will have reasonable defaults, but if you are creating a launcher you will generally want to more than that, such as automatically installing and starting bundles when you start the framework instance. The default Felix launcher defines reusable functionality to automatically install and/or start bundles upon framework startup.
Related
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.
}
}
I have a JAX-RS (Jersey) server with which I register and bind my stuff.
I want to print a banner when the server starts up. I want to do this using the JAX-RS framework not the web server's platform (i.e., no Jetty, Netty, Thorntail, etc hooks).
I saw the following which mentions the tried and true Servlet way of doing things:
Jax rs: How can I run a method automatically everytime my server restarts? , but that does not work because I am not running a servlet container in my server so that lifecycle call is never made.
I figured there must be a JCA-ish type object that I can register with Application/ResourceConfig that has such a lifecycle call, but I am unable to even find any kind of list of the things you can actually register.
Not to complain (but I will), but I cannot decide if this is so difficult because when they moved the project to eclipse, they broke every hyperlink to the old official documentation or that it is simply so implicit, like Spring, that it only works by github'ing other people's code and realizing, 'oh, I did not know you could do that'.
Jersey has Event Listeners. You'll want to use the ApplicationEventListener and the ApplicationEvent.Type you'll probably want to listen for to print the banner is the INITIALIZATION_FINISHED
public class MyApplicationEventListener
implements ApplicationEventListener {
#Override
public void onEvent(ApplicationEvent event) {
switch (event.getType()) {
case INITIALIZATION_FINISHED:
printBanner();
break;
}
}
#Override
public RequestEventListener onRequest(RequestEvent requestEvent) {
return null;
}
}
If I use ODataQueryBuilder in a servlet, I can call the servlet without any problem.
If I incorporated the code in a method and call this method within a ServletContextListener, I got first the following error.
2018 02 27 13:17:09#+00#ERROR#org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/]##anonymous#fs-watcher#na#afc186d33#firstapp#web##na#na#na#na#Exception sending context initialized event to listener instance of class com.sap.cloud.sdk.frameworks.hystrix.ScpNeoHystrixBootstrapListenerjava.lang.IllegalStateException: Another strategy was already registered.
at com.netflix.hystrix.strategy.HystrixPlugins.registerConcurrencyStrategy(HystrixPlugins.java:190)
at com.sap.cloud.sdk.frameworks.hystrix.ScpNeoHystrixBootstrapListener.bootstrap(ScpNeoHystrixBootstrapListener.java:43)
at com.sap.cloud.sdk.frameworks.hystrix.ScpNeoHystrixBootstrapListener.contextInitialized(ScpNeoHystrixBootstrapListener.java:74)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:5110)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5633)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:145)
at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:1015)
at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:991)
at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:652)
at org.eclipse.gemini.web.tomcat.internal.TomcatServletContainer.startWebApplication(TomcatServletContainer.java:125)
at org.eclipse.gemini.web.internal.StandardWebApplication.start(StandardWebApplication.java:109)
at org.eclipse.gemini.web.extender.WebContainerBundleCustomizer.addingBundle(WebContainerBundleCustomizer.java:49)
at org.osgi.util.tracker.BundleTracker$Tracked.customizerAdding(BundleTracker.java:467)
at org.osgi.util.tracker.BundleTracker$Tracked.customizerAdding(BundleTracker.java:1)
at org.osgi.util.tracker.AbstractTracked.trackAdding(AbstractTracked.java:256)
at org.osgi.util.tracker.AbstractTracked.track(AbstractTracked.java:229)
at org.osgi.util.tracker.BundleTracker$Tracked.bundleChanged(BundleTracker.java:443)
at org.eclipse.osgi.framework.internal.core.BundleContextImpl.dispatchEvent(BundleContextImpl.java:847)
at org.eclipse.osgi.framework.eventmgr.EventManager.dispatchEvent(EventManager.java:230)
at org.eclipse.osgi.framework.eventmgr.ListenerQueue.dispatchEventSynchronous(ListenerQueue.java:148)
at org.eclipse.osgi.framework.internal.core.Framework.publishBundleEventPrivileged(Framework.java:1568)
at org.eclipse.osgi.framework.internal.core.Framework.publishBundleEvent(Framework.java:1504)
at org.eclipse.osgi.framework.internal.core.Framework.publishBundleEvent(Framework.java:1499)
at org.eclipse.osgi.framework.internal.core.BundleHost.startWorker(BundleHost.java:391)
at org.eclipse.osgi.framework.internal.core.AbstractBundle.start(AbstractBundle.java:300)
at org.eclipse.osgi.framework.internal.core.AbstractBundle.start(AbstractBundle.java:292)
at org.eclipse.virgo.web.war.deployer.WARDeployer.start(WARDeployer.java:780)
at org.eclipse.virgo.nano.deployer.internal.StandardApplicationDeployer.startDeployables(StandardApplicationDeployer.java:325)
at org.eclipse.virgo.nano.deployer.internal.StandardApplicationDeployer.bulkDeploy(StandardApplicationDeployer.java:116)
at org.eclipse.virgo.nano.deployer.hot.HotDeploymentFileSystemListener.bulkDeployIfNotDeployed(HotDeployerFileSystemListener.java:143)
at org.eclipse.virgo.nano.deployer.hot.HotDeploymentFileSystemListener.onInitialEvent(HotDeployerFileSystemListener.java:105)
at org.eclipse.virgo.util.io.FileSystemChecker.notifyListenersOnInitialEvent(FileSystemChecker.java:207)
at org.eclipse.virgo.util.io.FileSystemChecker.handleInitialFiles(FileSystemChecker.java:177)
at org.eclipse.virgo.util.io.FileSystemChecker.check(FileSystemChecker.java:261)
at org.eclipse.virgo.nano.deployer.hot.WatchTask.run(WatchTask.java:49)
at java.lang.Thread.run(Thread.java:807)
Followed by:
One or more listeners failed to start. Full details will be found in
the appropriate container log file
Context [] startup failed due to previous errors
This will destroy my Servlet Context Listener and then failed to start web application in NEO.
It is strange because the method is called well and in the log I can see that the method is called without an error.
If I don't call the method in code, the application is starting up well.
Please let me know, how I can solve this issue, because I need to call the S/4 Hana system.
Update:
Version 2.0.0 of the SAP S/4HANA Cloud SDK changed the way how RequestContextListeners are initialized. It is now be possible to use the following code without additional effort:
new RequestContextExecutor().execute(...);
Original answer:
I guess that you want to run logic in some background task that is not triggered by a user request.
Can you try to wrap the logic calling the S/4HANA system in a Callable which is passed to the execute method of a RequestContextExecutor?
For example:
List<SomeData> result = new RequestContextExecutor()
.execute(new Callable<List<SomeData>>() {
#Override
public List<SomeData> call() {
return new GetSomeDataCommand().execute();
}
});
Note that this will require a technical user with Basic credentials in the destination configuration; principal propagation is not available in this case.
Also note that if you want to run the background task calling the external system in a ServletContextListener during application startup, you have to
either explicitly register the relevant RequestContextListener classes which are also subclasses of ServletContextListener (including, if you are using the SAP Cloud Platform Neo environment, initializing the ScpNeoHystrixBootstrapListener),
or specify the order of the ServletContextListener classes explicitly in the web.xml file.
You can register these listeners explictly as follows:
// ensure that the correct HystrixConcurrencyStrategy is used
new ScpNeoHystrixBootstrapListener().bootstrap();
// explicitly register RequestContextListeners
new RequestContextExecutor().withListeners(
new DestinationsRequestContextListener(),
new ScpNeoDestinationsRequestContextListener(),
new TenantRequestContextListener(),
new UserRequestContextListener()
).execute( /* callable */ );
I have a modular application which uses OSGi framework. Here I'm using org.eclipse.equinox.common_3.4.0 OSGi container. So now the application is already running with all the osgi bundles installed and active and I am displaying all the active OSGi bundles on the UI, by looping though a hash map, based on some action.
Now the requirement is, while the application is already running, I want to instal a new OSGi bundle, from a file system, by giving this new bundle to the application's OSGi container so that it will start this bundle.
How do I achieve this ?
I have tried reading the OSGi bundle as a JarInputstream and read the bundle activator fully qualified class path and tried to instantiate this using Class.forName("") and type casted to BundleActivator interface. But while starting it, it is taking bundle context as a argument to start method.
Is there way where I can just give the OSGi bundle to the container pragmatically so that it will take care of installing and starting the bundle and then my UI will automatically picks up this new bundle name in the display.
Assuming you have the file to load, you can install the bundle like:
void install( BundleContext context, File file) throws Exception {
Bundle b = context.installBundle( file.toURI().toString() );
b.start();
}
And you can uninstall it (if the file is gone):
void uninstall( BundleContext context, File file) throws Exception {
Bundle b = context.getBundle( file.toURI().toString() );
b.uninstall();
}
You get the BundleContext from your activate or Declarative services component's activate method. These are the recommended methods but in dire cases you can also use:
BundleContext context = FrameworkUtil.getBundle( this.getClass() ).getBundleContext();
Though handy it bypasses some mechanism that you might want to use in the future so getting the context in the recommended way is much better
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.