Multiple config block in java properties file - java

I need to define multiple configuration blocks in a single .properties file in Spring. Currently I am having multiple .properties file like below:
one.properties:
publishing.channel=ftp
ftp.user=user1
ftp.password=pass1
ftp.host=abc.xyz.com
ftp.port=21
two.properties
publishing.channel=ftp
ftp.user=user2
ftp.password=pass2
ftp.host=def.xyz.com
ftp.port=21
What I now require is defining only one .properties file and add all the configuration blocks in it like so:
publishing.channel=ftp
ftp.user=user1
ftp.password=pass1
ftp.host=abc.xyz.com
ftp.port=21
then another one
publishing.channel=ftp
ftp.user=user2
ftp.password=pass2
ftp.host=cdf.xyz.com
ftp.port=21
it could be http too
publishing.channel=http
http.user=user2
http.password=pass2
http.host=cdf.xyz.com
Problem is when I put multiple property blocks like this, I cannot differentiate in code as my bean methods (e.g. getHost()) will only fetch the last declared one in the properties file. I do not want to create many variables like host1, host2, host3 and so on as it would need to be modified in case there is another block of properties added. How can I make it generic?
Thanks in advance.

You can use PropertiesConfiguration from Apache Commons Configuration and then access all the values of same key and add your logic to get the required value.
Use getStringArray(key) method or getList(key) method to access all values.

Related

Changing single parameters in XML file wrapped as Java Object

I am getting a config.xml file via a REST API which has a specific structure. I am adapting this config.xml via Java and pushing it again via PUT command to the REST endpoint to update it.
This XML structure contains the same amount of properties (let's say 'name' and 'description') but might be enhanced by some more properties (e.g. 'category'), which I am not aware of.
<config>
<name>myName</name>
<description>myDescription<description>
<category>myCategory<category>
</config>
My goal is to adapt this config file via Java Code while wrapping it into an Object. So I built a Class 'Config' containing 'String name' and 'String description'.
I can easily parse the config.xml to my Config object with JAXB and adapt name and description, but when marshalling it to XML the category would be missing, although it was returned by the REST API. Is there a way (maybe ValueChangeListener?) to adapt only the changed values in an existing xml file?
public class Config { String name; String description; }
So I don't event want to be able to change 'category' at all, I just don't want to lose the data.
Info: In my scenario the Config class is very complex and has alot of subclasses (it's a representing a Jenkins Job). So the example above is very simplified.
I got the idea to create a second config file, only having the changed parameters. Afterwards merging the to config files. But I had no idea how to be aware what exactly has changed and how to implement it.
Example:
I want to change description to "newDescription", so my expected XML would be:
<config>
<name>myName</name>
<description>newDescription<description>
<category>myCategory<category>
</config>
unfortuntately it is:
<config>
<name>myName</name>
<description>newDescription<description>
</config>
Means category parameter is lost, as I am not aware of it and therefore didnt add it to the Config class. Summarized, there might be parameters in the XML file which I am not aware, which I also do not want to change - but don't want to lose when pushing an updated config.

Can you override a library's Spring property placeholders?

We are working on moving our application to use only Spring-Boot application.properties files. The old way we were doing was that each library/dependency would have their properties stored in a dedicated properties file like res/environment/some-library-override.properties. The values would then be retrieved in the library using #Value("$some-library-{PROPERTY_NAME}").
However, since moving all of these override properties to dedicated application.properties files, it is no longer resolving the properties and we get errors like java.lang.NumberFormatException: For input string: "$some-library-{PROPERTY_NAME}".
I assume this is because it is still expecting the property to be in that dedicated properties file.
Is there a solution to this that doesn't involve modifying the library/dependency? Is it possible to have it ignore the prefix and only look for the PROPERTY_NAME in the application.properties files?
if you have declared propertie var likeproperty.name=XXXX or added environment var like PROPERTY_NAME=XXXX.
you need to use this way
#Value("some-library-${property.name}")
// will inject value "some-library" + "XXXX"

merging multiple levels of configuration using typesafe/akka config

I'm looking at:
https://github.com/typesafehub/config
Let's say I want to have a default configuration, e.g. reference.conf, and then I want to have dev/prod overrides (two different application.conf's), and then I also wanted to have host-specific overrides that inherited from both the application.conf and ultimately the default reference.conf. How would I do this?
e.g., I'm imagining a directory structure something like:
resources/reference.conf
resources/prod/application.conf
resources/prod/master.conf
resources/prod/slave.conf
resources/dev/application.conf
resources/dev/master.conf
resources/dev/slave.conf
Or maybe it would be resources/dev/master/application.conf?
Somewhere I would specify an environment, i.e. maybe extracted from the hostname the application was started on.
If the application was master.dev.example.com, I'm expecting I should be able to do something like:
getConfigurations("dev/master.conf").withDefaultsFrom(
getConfigurations("dev/application.conf").withDefaultsFrom(
getConfigurations("resource.conf"))
But I'm having a hard time understanding what exactly that would look like using the given library.
I see I could set a config.resource system property, but it looks like that would only allow for one level of overrides, dev-application.conf -> resources.conf, not something like master-node.conf -> dev-application.conf -> resources.conf.
I see a .withFallback method, but that seems to be if I wanted to mix two kinds of configuration in a single file, not to chain resources/files together.
Use multiple withFallback with the configs that have the highest priority first. For example:
Config finalConfig =
ConfigFactory.systemProperties().
withFallback(masterConfig).
withFallback(applicationConfig).
withFallback(referenceConfig)
Each of the configs like masterConfig would have been loaded with Config.parseFile. You can also use ConfigFactor.load as a convenience, but the parseXXX methods give you more control over your hierarchy.

xstream: only parsing child element

I have following xml
<root>
<child-1>
</child-1>
<child-2>
<subchild-21>
</subchild-22>
</child-2>
</root>
My requirement is such that I only want to parse child-2. I am unaware of root and child-1.
Is it possible with xstream because I couldn't find a way to ignore root.
There are several ways to go, depending on your requirements.
If you know the name of the class to parse (child-2 here), you could look for the <child-2> and </child-2> entry in the XML, copy them along with the content in-between to a new temporary XML file (you can create temporary files using createTempFile() from the standard File class). This is the way I would suggest.
If you want to take out the child-2 instance without knowing its name, but you know the names of the surrounding classes, you could mock their classes, that is create classes of the same name, but without their specific content. In your example there is no content (might have been ignored at export time), but it's important to have the same member data in the mock classes for the import to succeed. (unless you use ignoreUnknownElements() as stated by Philipi Willemann)
Of course, if you're the one creating the XML, you should be able to export only the child-2 instance in the first place.
If you know the root name you can create a simple class has an attribute of the class you have mapped to child-2:
#XStreamAlias("root")
class Root {
#XStreamAlias("child-2")
private Child2 child;
//get and set
}
Then when you are processing the XML you can set XStream to ignore unknown elements with xstream.ignoreUnknownElements();

How to Change init-parameters at Runtime?

If I modify the XML to change the value of init parameter
I see the changes only when web-app is redeployed.
My question is cant I get around this by setting the values at run time.Is there any API that allow me to change the values dynamically.
It's called init-parameter for a reason. So, you can't.
But you can change values at runtime, that's no problem.
After reading the init parameters put them as attributes of the ServletContext (ctx.setAttribute("name", value))
Create a small (password-protected) page that lists all attributes of the ServletContext and gives the ability to change them.
Maybe you could use apache commons configuration, specifically have a look at Automatic Reloading...
Make use of properties files instead and write code so that it 1) reads the value from it everytime, or 2) can reload the value on command, or 3) reloads the file automatically at certain intervals.
If you put the properties file somewhere in the webapp's runtime classpath or add its path to the webapp's runtime classpath, then you can easily access/load it as follows:
Properties properties = new Properties();
properties.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("filename.properties"));
String value = properties.get("key");

Categories