Read Properties File in Karaf From Another Bundle - osgi

In Karaf, is there a way for a bundle to read a properties file from another bundle?
I have bundle1, which contains some classes that bundle2 uses (bundle1 exports the package containing those classes in its maven pom via maven-bundle-plugin and bundle2 imports it). But bundle2 also needs to use a properties file from bundle1. Is there a way that in addition to classes, bundle2 can access a file from bundle1?
From what I've read, one option is to deploy the properties to the karaf etc folder via the features file and then it can be accessed from bundle2 via blueprint. I would like to avoid that if possible, as bundle1 is currently not deployed as a feature. So hoping for an alternate approach.

The nicest way is to wrap the access through a class of bundle1. Assume bundle1 contains a class named MyClass. Inside this class you can do this.getClass().getResourceAsStream(path). The path is relative to the package of the class.
So a method of this class could return an Inputstream for the properties file or allow access to the actual properties.
In fact you can also access the properties file from bundle2. Simply use MyClass.getResourceAsStream(path) from a class in bundle2. This works as each class is by default loaded by the classloader of the bundle it resides in.

Related

Spring can't find properties file

I tried all ways to find a file and always got this exception:
java.io.FileNotFoundException: class path resource [src/main/resources/sport.properties] cannot be opened because it does not exist
This is my folder structure:
What path in this String is correct? #PropertySource("classpath:/src/main/resources/sport.properties")
What path in this String is correct? #PropertySource("classpath:/src/main/resources/sport.properties")
That is incorrect because you are mixing up two "name spaces".
The string "classpath:/src/main/resources/sport.properties" is a URI.
The "classpath" means you are telling Spring to look on the application's runtime classpath.
But "/src/main/resources/sport.properties" is not a name on the runtime classpath. Rather it is a pathname in the file system relative to the Eclipse project directory.
Since you are using Maven with Eclipse, you need to understand that the resources tree(s) get added to your classpath; i.e. "${MAVEN_PROJECT}/src/main/resources/a/b" becomes "/a/b" on the runtime classpath.
The "${MAVEN_PROJECT}/src/main/resources" directories for all Maven projects that make up your app are added to the classpath in this way.
When unit testing, "${MAVEN_PROJECT}/src/test/resources" directories get added ro the classpath as well.
In short, you should probably use #PropertySource("classpath:/sport.properties")
I would suggest using TestPropertySource as mentioned below for integration tests.
#RunWith(SpringRunner.class)
#ContextConfiguration(locations = "/applicationContext.xml")
#TestPropertySource(locations = "/sport.properties")
#TestPropertySource is a class-level annotation that is used to
configure the locations() of properties files and inlined properties()
to be added to the Environment's set of PropertySources for an
ApplicationContext for integration tests.
Precedence:- Test property sources have higher precedence than those
loaded from the operating system's environment or Java system
properties as well as property sources added by the application
declaratively via #PropertySource or programmatically (e.g., via an
ApplicationContextInitializer or some other means). Thus, test
property sources can be used to selectively override properties
defined in system and application property sources. Furthermore,
inlined properties() have higher precedence than properties loaded
from resource locations().

Deploying BEAN in OSGi plugin

I am currently deploying my custom controls as OSGi plugins and I wanted to do the same thing with my beans. I have tried putting them into the OSGi plugin and it works fine but the only problem I have is the faces-config.
It seems it has to be called faces-config in the OSGi plugin to work but that means i can't use beans in the NSF anymore because it seems to ignore the local faces-config.
Is there a way to change the name of the faces-config in the OSGi plugin?
Something like FEATURE-faces-config.xml?
In the class in your plugin that extends AbstractXspLibrary, you can override "getFacesConfigFiles", which should return an array of strings representing paths within the plugin to additional files of any name to load as faces-config additions. For example:
#Override
public String[] getFacesConfigFiles() {
return new String[] {
"com/example/config/beans.xml"
};
}
Then you can put the config file in that path within your Java source folder (or another folder that is included in build.properties) and it will be loaded in addition to your app's normal faces-config, beans and all.
The NSFs are running as separate, distinct Java applications. The OSGi plugin is running in the OSGi layer, above all those distinct Java applications, as a single code base. Consequently, the faces-config is only at that level.
It's possible to load them dynamically, by using an ImplicitObjectFactory, loaded from an XspContributor. That's what is done in OpenNTF Domino API for e.g. userScope (which is a bean stored in applicationScope of an NSF). See org.openntf.domino.xsp.helpers.OpenntfDominoImplicitObjectFactory, which is referenced in OpenntfDominoXspContributor, loaded via the extension point of type "com.ibm.xsp.library.Contributor".
A few caveats:
You have no control over what happens if you try to register your bean with a name the developer also uses for a different variable in that scope.
Unless you add code to check if the library is enabled, as we do, you'll be adding the bean to every database on the server.
You still need to add the library to the NSF. Unless you also provide a component that those databases will all use, there's no way you can programmatically add it, as far as I know.
It might be easier to skip the bean approach and just add an instance of the Java class in beforePageLoad, page controller class, or however you're managing the backing to the relevant XPage (if viewScope) or application (if sessionScope / applicationScope).

How do I access Spring properties in a logback configuration

Is there a way to access Spring properties within a logback.xml file?
I know one can import a properties file if you know its location, but I'm using Spring profiles to control where the properties file should be loaded or not.
Is there done kind of connector that asked me to feed Spring data into logback? This would only be at startup; I don't need to be able to do this on the fly.
I'm guessing you do have to import a property file (common property file, non-environment specific one) that will contain the name of the property that you are going to use in the logback.xml, and that you want to optionally override the value of the property for some environment (you need at least one property file containing the name of the property, because you will be using that property in the logback.xml, and you need it to be available to be able to use it).
For the optional environment-override, how about including an additional property file? For example, we use both application.properties and application-${spring.profiles.active}.properties files. Then if we don't need to override the property for some environment, we simply don't include it in the environment specific property file (application-dev.properties, etc.)

Look up a dynamic property at run-time in Spring from PropertySourcesPlaceholderConfigurer?

Not sure of the best approach to this. We've created a jar that could be used by different projects. The other projects relying on this jar need to provide certain properties defined in one of their spring properties files. (Our jar shouldn't care what they name those property files.)
Using #Value("${some.prop}") works great for most properties, however we now have the requirement that the name of the property to look up is dynamic. For example:
int val = getSomeVal();
String propNeeded = foo.getProperty("foo."+val+".dynamic.prop");
Not sure what "foo" should be to get my access. I looked into injecting Environment, however from all my googling it looks like that will not load from an xml property-placeholder definition (even if defined as a bean def for PropertySourcesPlaceholderConfigurer.) You seem to have to use #PropertySource, yet my main config is an XML file so not sure how to get Environment to work. (I can't really go 'old skool' and look up the property file as a class path Resource either since I'm not aware of the name of the file the users defined.)
I don't mind making this particular Service class ApplicationContextAware, but if I did that how could I get access to the underlying PropertySourcesPlaceholderConfigurer ? which I would 'seem?' to need in order to get access to a property dynamically?
The other option is that I force users of the jar to declare a bean by a name that I can look up
<util:properties id="appProps" location="classpath:application.properties" />
And I then inject appProps as Properties and look up from there. I don't like this approach though since it forces the users of the library to name an file by a common id. I would think the best solution is to just get a handle in some way to the underlying PropertySourcesPlaceholderConfigurer in my service class... I'm just not sure how to do it?
Why doesn't Spring simply allow PropertySource to be defined some how via your XML config and then I could just inject Environment?
Thanks for any suggestions how to accomplish what I want.
You could have a ReloadableResourceBundleMessageSource declared to read from the same source as the PropertySourcesPlaceholderConfigurer. This way you could just #Autowire MessageSource (or make your bean implement MessageSourceAware) and use that to retrieve your properties.
Main reason for using ReloadableResourceBundleMessageSource is to retrieve I18N messages, so that would kind of hacky...

Accessing properties file from another module context

I use maven. My web application contains two modules and each has it's own spring context. First is packed to jar, the second one to war. The second one uses first module's jar and calls it's methods.
I need to add property file, which will be used by first module (via spring context). The main issue is that I should be able to access/edit this property file after war deployment.
How can I provide such a property file, that will be used in first jar module and can be changed after war module deployment?
Thanks.
Sorry, don't see the problem, you need to describe that better. From what I understood this is the way to go:
place a.properties in src/main/resources in the JAR module
use a PropertyPlaceholderConfigurer to make the properties available in the Spring context
it'll be packed in root of the JAR
the JAR ends up in WEB-INF/lib of the WAR which again is "root of the classpath" so to speak
Update, 2013-06-09
(question was updated based on comments to initial answer above)
Essentially what you seem to be looking for (still not quite sure) is how to load properties from a properties file that is not packaged with your WAR/JAR.
In this case you can skip all of the above steps except 2.
Use a PropertyPlaceholderConfigurer and specify the location of the file as classpath*:a.properties (see below)
Place a.properties anywhere on the classpath outside the WAR file.
Warning! Of course you can now edit the properties independently from releasing the WAR file but since Spring initializes the beans on application start and since all beans are singletons by default changes to the properties file won't become effective until you restart the app.
XML example
<bean class="....PropertyPlaceholderConfigurer">
<property name="location" value="classpath*:a.properties" />

Resources