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.
Related
I'm trying to add authorization to several microservices. Given all the services share similar authorization process, I want to extract the logic to a shared library.
I managed to create library, but I realise all the configurations need to be set in the application.yml file in the microservice which calls the library. I don't want to expose some of the configurations at service layer though.
After some searches, I found I could set #PropertySource("library.properties") in my library's configuration class to force reading properties from the specified .properties file within the library.
The problem now is I want to set different values for different environments, e.g. authorization URL for test and production would be different. How can I configure the file so that the configuration class would read same property value based on active profile (e.g. environment = test/staging/production)?
You can have multiple property files such as "application-environment.yml” in your resource folder. Spring framework picks the right one based on the active profile.
For example, if you define a “staging” environment and have a staging profile and then your property file should be named as application-staging.yml.
We are using spring with a tomcat 7 cluster for our web application.
In order to do an load testing our staging server we need to have some sort of a "special controller".
This controller is providing some really risky operations that must not reach the production server!
What is the best way to do this? how can we create this code, add it to our svn, and still make it unavailable to production deployment?
Thanks
I'd suggest using Spring profile. You can set a bean to load only when a specific profile is active. This way this controller would load only when profile staging is active.
For example you can define:
#Controller
#Profile("staging")
public class SpecialController {
...
}
You need to pass in the JVM options the profile -Dactive.profiles=staging
Spring has special feature for this named "profiles". You can define staging profile, create as many beans as you need marked for this profile. Then, when you are running application you just have to supply JVM option -Dspring.profiles.active=staging and all staging targeted beans will run. Otherwise they will be ignored.
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.
What's the norm / best practices for saving/retrieving application settings in a EJB3 app?
I'm using maven as a build tool, and I have a multi module project.
I was thinking of putting some properties file on some common module that would be available application-wise as a jar but I'm not sure if an EJB is more suited for this.
Edit: The application properties should be configurable per environment.
My main issue is how to expose the properties to the rest of the container, my secondary issue is how to save them in a environment-dependent way
If the settings are to be changed on a regular basis then locking them in a properties file within a jar is going to make life difficult.
If the settings pertain to resources such as database or JMS connection urls, then those are best defined to the container and accessed via a JNDI lookup.
You could use context-param or servlet init-params in the web.xml, there must be something similar in the application.xml - I haven't looked at them in a while.
You could define them in an LDAP, and then extend the JNDI tree to include that branch.
Although I would probably just use a properties file located in a directory on the classpath outside of the ear/war/jar deployment structure.
What's the norm / best practices for saving/retrieving application settings in a EJB3 app?
EJB3 app is very vague... But I would say that things like an endpoint URLs for external services would typically go in JNDI as environment entries (that you could then inject with the #Resource annotation) if you want to maximize portability.
OSGi employs a service-oriented architecture: Bundles register service objects, that other bundles consume. Service publishing and binding is managed by the framework. This decouples service providers from service users completely (except for the need to agree on a service interface).
Is there a way to limit (by configuration) what services are visible to what bundles ?
For example, if I have an HttpService, all bundles that feel like doing so can install servlets into it. I would like to make the HttpService not visible to selective bundles.
For extra credits: In addition to just filtering service registrations, the ability to modify registration properties. So that even if a bundle registers a Servlet with alias=/admin, I can change that to alias=/somethingelse for consumption by Pax Web Extender Whiteboard.
Is there a way to limit (by configuration) what services are visible to what bundles?
As you are aware, it is possible to filter on service properties, though this probably doesn't give the sort of control you are asking for: the services are still visible to other bundles deployed in the framework.
In SpringSource's dm Server (an open-source, modular, OSGi-based Java application server) an application can be Scoped when it is deployed. This allows you to deploy multiple applications (in separate scopes) that might include inconsistent versions of dependent bundles, while still allowing common bundles to be shared (by deploying them outside of a scope—in the so-called global scope).
If a scoped application/bundle registers an OSGi service it is only available to the bundles in the same scope. (The services are 'scoped' as well.)
This is not magic: the server wraps the OSGi services interfaces and uses service properties 'under the covers' to perform the filtering required on-the-fly.
I think this would give you the sort of separation you are looking for.
For information about dm Server (not to be confused with Spring DM) go to the SpringSource.org dmServer page.
Steve Powell
SpringSource; dm Server Development
The upcoming R4.2 of the OSGi specification define a component called Find Hook that allows exactly to:
"inspect the returned set of service references and optionally shrink the set of returned services"
See
http://www.osgi.org/download/r4-v4.2-core-draft-20090310.pdf section 12.5
Please note that R4.2 is not final yet, still I believe the major OSGi implementations (Felix and Equinox) already have the code for this additional functionality in their trunk
Is there a way to limit (by configuration) what services are visible to what bundles ?
There is no way to do that using service properties. You could define your own service property that specifies which bundles should consume the service you are exporting, but there is no way to prevent other bundles from consuming it as well.
For extra credits: In addition to just filtering service registrations, the ability to >modify registration properties. So that even if a bundle registers a Servlet with >alias=/admin, I can change that to alias=/somethingelse for consumption by Pax Web >Extender Whiteboard.
Well... that's a tough one. You could define your own Servlet interface "MyServlet" and export your Servlets using that interface. Then, another bundle could consume those MyServlets and re-export them as Servlets with modified service properties.
Other than that ... no idea.
I haven't tried this, but seems like it may help you...
In the OSGi R4 Component Spec describes the "Configuration Admin Service" which, from a 5 minutes inspection, appears to be able to alter services dynamically.
Ultimately I think it will be up to you to control access to the services based on some agreed upon configuration values
For extra credits: In addition to just filtering service registrations, the ability to modify registration properties. So that even if a bundle registers a Servlet with alias=/admin, I can change that to alias=/somethingelse for consumption by Pax Web Extender Whiteboard.
using iPOJO you can change properties of the exposed services pretty simple. It has bunch of other features, which could be interessting to someone using OSGi a lot.
If you want to limit the visibility of services, your best bet is to enable OSGi security. It is designed to limit what services, packages and other things are visible to what bundles. You can for example only make a certain service available to a bundle that is signed by you (or use various other criteria).
The other option, already mentioned, it to use the 4.2 service hooks, which allow a sort of "do it yourself" security mechanism.
The second question, changing properties like the endpoint under which a service is registered, is something you can do via the ServiceRegistration that you get back when registering your service. Changes can be triggered by becoming a ManagedService and use ConfigurationAdmin to configure yourself.