OSGi: passing parameters to a specific bundle - java

I have a custom jar with a custom Main class, which starts the OSGi Framework and installs/starts the bundles. This main jar also includes a properties file.
Goal: I have a bundle A which should pick up the properties of this properties file of the main jar somehow.
My first attempt was to define a component in bundle A (using Apache Felix SCR/ Declarative Services) and retrieve the properties in its activate-method. This works so far that I'm getting the default value specified in the #Property-annotation.
But how can I now pass the properties of the properties file to this component?
Passing arguments to OSGi application
mentions to use the Config Admin, but how can I use this in the Main class?
The Config Admin is in a bundle, not in the main jar, and the bundles are not installed in any specific order
The Main class doesn't know anything about the bundles it installs, let alone a specific service.pid.
Update:
I'm trying now an approach suggested by #vizier (which doesn't use Config Admin and thus doesn't have the mentioned issues):
define a service interface in the main jar (system bundle)
provide an implementation, which reads the property file (the properties file is in the same jar)
export the package X containing this service interface
bundle A then can import the package X and e.g. reference the service using Declarative Services
But in my bundle A I'm getting:
org.osgi.framework.BundleException: Unresolved constraint in bundle <bundle A> [14]: Unable to resolve 14.0: missing requirement [14.0] osgi.wiring.package; (&(osgi.wiring.package=<package X>)(version>=0.1.0)(!(version>=1.0.0)))
at org.apache.felix.framework.Felix.resolveBundleRevision(Felix.java:3826)
at org.apache.felix.framework.Felix.startBundle(Felix.java:1868)
at org.apache.felix.framework.Felix.setActiveStartLevel(Felix.java:1191)
at org.apache.felix.framework.FrameworkStartLevelImpl.run(FrameworkStartLevelImpl.java:295)
at java.lang.Thread.run(Thread.java:722)
Does the system bundle only export osgi packages even if some custom packages were added to Export-Package in the Manifest file? Or what is going wrong?

As always, register a service ... The receive bundle (and any other bundle) can search for the service and read the properties. Since you're the framework launcher you can register any service you want through the Framework object you get from the Launching API.
In bnd(tools) I have a launcher. It uses the OSGi Launcher API to create the bundle, similar to what you describe. I pass the command line arguments as properties on a Launcher service. Look at https://github.com/bndtools/bnd/blob/master/biz.aQute.launcher/src/aQute/launcher/Launcher.java for an example.
You can of course also just get the Configuration Admin service through the Framework object and use it to register Configurations. It is quite easy (just actually done it) to define the configurations in JSON (or, dare I say it, XML) file and then read it and update Configuration Admin.

You can make the jar containing the main class an OSGi bundle as well, and during startup you install this bundle together with the other bundles. Then you can let other bundles access the properties contained in your jar using a number of techniques, such as the followings:
provide a class for accessing the properties and integrate using module dependancy (Export-package/Import-package)
provide as service for accessing the properties
use Config Admin

The simplest may be to make the jar with the properties file a fragment, with bundle A as the host.
Then the properties will be on the classpath of the bundle and can be easily read.

We have a similar case in Apache Karaf. There we simply set the properties as java System properties and also give them to the framework. These are then available as properties in the OSGi bundle context. So this is nice for properties that are for the whole platform. See the project of the karaf starter: http://svn.apache.org/viewvc/karaf/trunk/main/
If you need properties in user bundles then using the config admin service is much nicer. It decouples the user bundle form the mechanism of retrieving the properties and also allows updates at runtime. There is a also the metatype service which allows to define the structure and meaning of the properties which allows nice forms for editing the properties.
I describe in two tutorials on my website how to use the config admin service:
Config Admin Service: http://www.liquid-reality.de/x/G4Be
Metatype Service: http://www.liquid-reality.de/x/KoBe

Related

Can i create separate properties file for Virgo OSGi bundle?

I have Tomcat Virgo Server. I am deploying couple of OSGi bundles. I want to expose settings through properties, so the service within bundle can read it though Java System.getProperty(String) API. Is it possible ?
You should use OSGis ConfigurationAdmin for doing this. You can deploy your properties files into [VIRGO_HOME]/pickup and then consume the properties from ConfigurationAdmin Service over the configurations pid. Virgo recognizes your properties files in its pickup folder and automatically exposes them over the ConfigurationAdmin Service. You could also list your properties files in a plan file if you use plans to deploy your bundles as an application.
Please refer to the official documentation on the Virgo Documentation Page [1] for further details.
And if you are using Spring/Blueprint you can stick to the property placeholder as you are used to. Just use the osgix namespace handlers and do something like this:
<osgix:cm-properties id="cmProps" persistent-id="com.xyz.myapp">
<prop key="host">localhost</prop>
</osgix:cm-properties>
As by default the persistent-id or pid is the name of your properties file. For further reference have a look at Gemini Blueprint Documentation as well [2].
[1] http://www.eclipse.org/virgo/documentation/virgo-documentation-3.6.4.RELEASE/docs/virgo-programmer-guide/htmlsingle/virgo-programmer-guide.html#developing-applications-configuration-artifacts
[2] http://www.eclipse.org/gemini/blueprint/documentation/reference/1.0.2.RELEASE/html/compendium.html#compendium:cm

How do I edit the property file that my osgi managed service implementation uses?

I am using Apache Felix as my OSGi framework implementation. I have a class that is implementing ManagedService in order to get properties from a file using the ConfigAdmin service. I am able to manually edit the properties file and receive updates in my managed service. How do I edit the properties in this file from my managed service? Editing the Dictionary that I get from the update method has no effect.
The ConfigurationAdmin service has two parts:
The ManagedService, a component that receives a configuration.
The ConfigurationAdmin service, which can be used to set, update or delete a configuration.
In other words, if you want to change your own configuration, you need to talk to the ConfigurationAdmin service to do that.
By the way, nowhere in the spec does it say that there is a "file" holding the configuration. It is up to ConfigurationAdmin to decide how to persist (in a file, database, whatever). All management of configurations goes through the ConfigurationAdmin service.

How to migrate from Spring DI to OSGi DI in a nice manner?

I have a Swing project using Spring for DI and now I am trying to migrate to Eclipse 4 and OSGi.
Using the configuration files of Spring the user could comment/uncomment beans in order to add/remove functionality (offered by these back-end beans).
Now in Eclipse and OSGi I am looking for the best way to do this based on OSGi.
I know that I can make the beans as services and define start levels in OSGi but this does not solve my use case, which is:
The application starts without these beans/modules running and if the user updates the configuration from the running UI these beans/modules start and they are also started on the next start-up of the application.
Is there a nice/clean approach for my problem?
You probably want to use Eclipse Gemini Blueprint to do the management of how everything is integrated between Spring and OSGi (Gemini Blueprint is the successor to Spring Dynamic Modules). In particular, it can handle virtually all the complexity relating to dynamic service registration for you; your beans can remain virtually identical.
Another approach would be to use Declarative Services together with Configuration Admin to let configuration data determine which services to activate. In more detail here.
Like you already found out services are a good aproach to this. Simply install all your modules but do not start them. Then your UI can start and stop modules as the user selects the functionality he wants. THe OSGi framework then remembers the installed and started modules on a restart.
The absolute best approach for this is Declarative Services (DS). DS is integrated with OSGi's Configuration Admin, making it trivial to control the number of service instances as well as their configuration and service properties. For example, the following component (with the bnd annotations [which will resemble similar functionality in the OSGi specs soon]):
#Component(designateFactory=Config.class)
public MyComp implements MyService {
interface Config {
int port();
String host();
}
Config config;
#Activate
void activate(Map<String,Object> map) {
config = Configurable.createConfigurable(Config.class,map);
start();
}
void foo() { ... do the MyService stuff ... }
#Reference
void setDataSource( DataSource ds ) { ... }
}
This component requires a Configuration Admin factory configuration. The best way to see how powerful this is, is to setup a framework with Apache Felix Webconsole. The designateFactory=Config.class tells bnd to create a metatype XML file in the bundle. This is used by the Webconsole to create a pretty nice looking form for the configuration data, derived from the interface and its methods. This form is type aware, i.e. you cannot enter a non-nummeric value for the port number. Through the webconsole you can now instantiate multiple components by creating multiple factory configurations. Deleting these factory configurations, removes the service. In your application, you can manipulate Configuration Admin yourself under the control of the user.
Another advantage is that through Configuration Admin you can control the binding of the component's dependencies. In the aforementioned example, you can set the dataSource.target property to a filter like (db=accounting) to select the accounting database. All configuration properties are added as service properties so you can easily set the 'db' service property on the configuration that creates the Data Source (if it was implemented this way).
This is one of the least understood advantages of DS, and I can tell you it is HUGE. To get started with this this, just create a DS project in bndtools and then a new Run Descriptor and select the Webconsole template.
Another advantage of DS is that it is small and it is not try to hide the dynamics, which in Blueprint can be painful.

How to externalize the configuration of bundles?

I am developing a OSGi program composed of several bundles that I run sometimes on my local windows dev computer, sometimes on a classic linux.
Currently, several bundles dedicated to resource connection have their own configuration file (properties file) containing some informations like the path to access some important files (present on both environments).
However, since the paths are different on the two execution-environments, I have to manually change the configuration before compilation, depending on which environment I am going to run my program in.
Is there a way for bundles to refer to an external configuration file? A solution could be to create a fragment for each environment that I generate only once, but I won't be able to change the configuration file easily since it will be in the jar of the fragment.
Are there some "best practices" that I should know to solve my "simple" problem ?
Take a look at OSGi's ConfigurationAdmin [1],[2] - this will suit your needs exactly (and is yet another example of OSGi's elegance).
Basically you'll implement a ManagedService or ManagedServiceFactory and the ConfigurationAdmin service take care of the rest.
The default setup for the Felix implementation used in concert with File Install (see Angelo's comment) will scan a directory of configuration files (filename is the service ID and file suffix .cfg). But ConfigurationAdmin is pluggable, so the backend for config could be a database etc.
The great thing about externalizing your config in this way is that you can keep it with the app/environment - so your bundles become agnostic of their environment.
Expanding on #earcam's excellent suggestion, I recommend binding your configuration via Declarative Services and Metatype. It makes it REALLY easy, particularly with the Felix annotations. Below is a simplified example of a service that uses JAAS for authentication, and it has a configurable JAAS realm name. The "ConfigurationPolicy.OPTIONAL" is the awesome part. If you set it to REQUIRE then the service will not be registered until its configured.
#Component(
name = "com.example.authprovider",
label = "Example authentication interceptor",
description = "Blocks unauthenticated access to REST endpoints",
specVersion = "1.1",
metatype = true,
policy = ConfigurationPolicy.OPTIONAL
)
#Service
#References({
...
})
#Properties({
#Property(name="jaasRealm", value = "default", label="JAAS Realm",
description = "the JAAS realm to use to find LoginModules to authenticate this login"),
...
})
public class Foo implements ... {
...
}
If you take this approach and use a Metatype-friendly container like Apache Karaf, then you'll get an auto-generated configuration UI for free in the admin web console.

Put authentication/login configuration inside PROJECT

I implemented a custom login module I want to use with the JBoss AS 6. I followed some tutorial guidelines on the internet, namely http://x-techteam.blogspot.com/2007/04/jboss-custom-login-module-simple.html.
They write about configuring ${JBOSS_HOME}/server/default/conf/login-config.xml and deploy a JAR with the custom login module, but I don't like the idea of changing a configuration within the JBoss folder.
I really would like to have ALL configurations within my WAR file. The EE application I write will be sent to some customers and they should not have to worry about configuring some security contexts or roles via XML.
So my question is:
Can I have a local login-config.xml within my war that will be picked up by JBoss?
Can the custom login module class remain within my war, without having to deploy it to some JBoss folder?
Thank you in advance.
Use dynamic security domains:
link

Categories

Resources