apache PropertiesConfiguration doesn't resolve placeholders - java

Say that I have the following two configuration files:
File 1:
key1 = ${common.key1}
key2 = ${common.key2}
File 2:
common.key1 = value1
common.key2 = value2
And I have the following code:
import org.apache.commons.configuration.PropertiesConfiguration;
...
PropertiesConfiguration newConfig = new PropertiesConfiguration();
File configFile1 = new File("...paht to file 1");
File configFile2 = new File("...path to file 2");
newConfig.setDelimiterParsingDisabled(true);
newConfig.load(configFile2);
newConfig.load(configFile1);
Iterator<String> props = newConfig.getKeys();
while (props.hasNext()) {
String propName = props.next();
String propValue = newConfig.getProperty(propName).toString();
System.out.println(propName + " = " + propValue);
}
I have the following output:
common.key1 = value1
common.key2 = value2
key1 = ${common.key1}
key2 = ${common.key2}
Why the placeholders are not resolved ?

See this page in the documentation, which says:
Below is some more information related to variable interpolation users should be aware of:
...
Variable interpolation is done by all property access methods. One exception is the generic getProperty() method which returns the raw property value.
And that's exactly what you are using in your code.
The API docs of getProperty() mentions this as well:
Gets a property from the configuration. ... On this level variable substitution is not yet performed.
Use other methods available in PropertiesConfiguration to get the actual, interpolated value. For example, call getProperties() on the PropertiesConfiguration to convert it to a java.util.Properties object and iterate on that instead.

It is also possible to use it in generic way with placeholders substitution like below:
config.get(Object.class, propName);
Unlike getProperty method the get method with Object.class parameter will return value of original class with variables interpolated.

Related

How to use org.apache.commons.configuration with Coldfusion

I am trying to utilize PropertiesConfiguration to manipulate property files in coldfusion. Using org.apache.commons.configuration version 1.10.
propertyFile = "usergui.properties";
config = createObject("java","org.apache.commons.configuration.PropertiesConfiguration").init(propertyFile);
I am getting to matching function init that takes a string. I have tried doing java.io.file.
I figured it out problem was that I didn't include all the dependencies. DUH!
function updatePropFile(string propFile, struct propStruct, struct removeStruct){
propertyFile = propFile;
javaFile = createObject("java", "java.io.File").init(propertyFile);
fileStream = createObject("java", "java.io.FileInputStream").init(javaFile);
config = createObject("java","org.apache.commons.configuration.PropertiesConfiguration").init(javaFile);
configLayout = config.getLayout();
for(key in propStruct){
if(config.containsKey(key)){
config.setProperty(key, propStruct[key]);
}else{
config.addProperty(key, propStruct[key]);
}
}
for(key in removeStruct){
if(config.containsKey(key)){
/* clear prop and add as comment */
value = config.getProperty(key).toString();
config.clearProperty(key);
config.addProperty('##'&key, key & "=" & value);
}
}
configLayout.save(createObject("java", "java.io.FileWriter").init(propFile, false));
}

Parsing Properties file

I am trying to parse a Properties file that has the following format:
CarModel=Prius
CarMake=Toyota
Option1=Transmission
OptionValue1a=Manual
OptionValue1b=Automatic
Option2=Brakes
OptionValue2a=Regular
OptionValue2b=ABS
My question is, what if there are various forms of the Properties file? For instance, what if a Properties file has 3 options for Option 1, and another Properties file has 2 options for Option 1? Right now my code looks like this:
Properties props = new Properties();
FileInputStream x = new FileInputStream(filename);
props.load(x);
String carModel = props.getProperty("CarModel");
if(!carModel.equals(null)){
String carMake = props.getProperty("CarMake");
String option1 = props.getProperty("Option1");
String option1a = props.getProperty("OptionValue1a");
String option1b = props.getProperty("OptionValue1b");
etc. I'm thinking I need a lot of 'if' statements, but I'm unsure how to implement them. Any ideas?
Are you sure you want to use a properties file? I suggest using YAML.
I am trying to parse a Properties file that has the following format:
CarModel: Prius
CarMake: Toyota
Transmission:
- Manual
- Automatic
Brakes:
- Regular
- ABS
Using SnakeYAML you can do
Map<String, Object> car = (Map) new Yaml().load(new FileReader(filename));
Note the lines starting with - are turned into a list.
If you must stick with Properties, I suggest putting the list in a property.
CarModel=Prius
CarMake=Toyota
Options=Transmission Manual|Automatic,\
Brakes Regular|ABS
This way you can read the options like
String options = prop.getProperty("Options");
for(String option : options.split("\\s*,\\s*")) {
String[] parts = option.split("\\s+");
String optionType = parts[0];
String[] optionChoices = parts[1].split("[|]");
}
This way you can have any number of options with any number of choices.

How to get values custom metadata properties

I'm trying to get the metadata for an asset in the DAM. However, it seems that the metadata comes back as empty for properties that don't have "dc:" in front of them.
Resource rs = getResourceResolver().getResource(fileReference);
Asset asset = rs.adaptTo(Asset.class);
//this works
title = asset.getMetadataValue("dc:title").toString();
//this does not work.
//I have ensured that "mine.title" is a property and has string value assigned to it.
customTitle = asset.getMetadataValue("mine.title").toString():
//this does not work either
customTitle = asset.getMetadata("mine.title").toString():
Is there a way to get the value from a custom metadata property?
Assets at the end are simple nodes, so to get some property you can do something like this (depending on actual path of variable fileReference):
Resource metadataResource = rs.getChild("jcr:content/metadata");
ValueMap properties = ResourceUtil.getValueMap(metadataResource);
customTitle = properties.get("mine.title", "defaultValue")
"dc:title" comes with a registered namespace "dc" (Dublin Core) whereas "mine.title" does not.
That's the reason of title = asset.getMetadataValue("dc:title").toString(); giving you proper value than customTitle = asset.getMetadataValue("mine.title").toString()
You can attack this problem in many ways.
Change the property name to "dc:myTitle" and retrieve it in the same way you are retrieving "dc:title" [0]
You can retrieve the value of "mine.title" in the way Alex has described.
Resource rs = getResourceResolver().getResource(fileReference + "/jcr:content/metadata");
ValueMap damAssetValueMap = damResource.adaptTo(ValueMap.class);
String shortName = damAssetValueMap.get("shortName", String.class);
Register a new namespace and define options (in your case , its "mine").
A look at "/libs/dam/nodetypes" and "/libs/dam/options/metadata" might be helpful.
[0] Check "/libs/dam/options/metadata"

How to append values to a key using ini4j?

I want to append a value to following Key like this:
[Section]
Key=value1,value2
I tried Wini and Section getAll() and putAll() functions but it always replaces value1 with value2 instead of appending value2. And I did' t find any tutorial about this online. How can I do this using ini4j? Or another jni writinig and parsing library?
I finally treated it as a single Key-value pair and appended to the string after "Key=".
This topic is a little old, but I'm faced exact the same problem, so...
To read all:
//open the file
Ini ini = new Ini(new File(iniFileName));
//load all values at once
Ini.Section names = ini.get("mySectionX");
myStr[] = names.getAll("myKey1", String[].class);
To put all (with the same ini and names):
//if myStr[] have changes
names.putAll("myKey1", myStr);
At final you gonna have the ini file like this ("myKey1" is ALWAYS the same):
[mySectionX]
myKey1 = value1
myKey1 = value2
myKey1 = value3
Adding more information,
if you want o create a new file:
Ini ini = new Ini();
ini.setComment(" Main comment "); //comment about the file
//add a section comment, a section and a value
ini.putComment("mySectionX", " Comment about the section");
ini.put("mySectionX", "myKey1", "value1");
//adding many parameters at one in a section
String[] keyList = {value1, value2, value3};
ini.add("mySectionY");
Ini.Section names = ini.get("mySectionY");
names.putAll("myKey1", keyList); //put all new elements at once
...
ini.store(new File(iniFileName));

Java properties containing dollar delimited variables

I'm storing my app settings in properties file that I use in Ant and in the Java app. Maybe it's not good pratice, but I find it very handy to avoid duplications. The file contains variables such as:
usefulstuff.dir = ${user.home}/usefulstuff
So that other people can run the program on *nix systems, provided that they have the usefulstuff folder in their home directory.
Now, the fascinating thing is that this properties file works fine in Ant (the variable gets resolved to /home/username), while when I load the same file directly in the Java app, I get a string containing ${user.home}/usefulstuff, which is not very useful indeed.
I load the props with this code in Ant:
<loadproperties srcFile="myProps.properties"/>
And in the Java app:
FileInputStream ins = new FileInputStream(propFilePath);
myProps.load(ins);
ins.close();
Am I missing anything? Maybe is there a better way to load properties in a Java app than load()?
I don't think it's particularly "fascinating" that this works in Ant - Ant is deliberately written to do so:
Properties are key-value-pairs where Apache Ant tries to expand ${key} to value at runtime.
and
Ant provides access to all system properties as if they had been defined using a <property> task. For example, ${os.name} expands to the name of the operating system.
If you want the same behaviour, you'll need to implement the same sort of logic. It's possible that you could use the classes from Ant directly, if they do what you want - and if you're happy to ship the relevant binaries (and abide by the licence).
Otherwise, you might want to use a regular expression to find all the matches - or (probably simpler) iterate over all of the system properties and do a simple replacement on them.
As Jon said, it should be straighforward to write the property handling yourself. For eg:
import java.util.*;
public class PropertiesTest
{
public static void main(String[] args)
{
Properties props = new Properties();
props.setProperty("foo", "foo/${os.name}/baz/${os.version}");
props.setProperty("bar", "bar/${user.country}/baz/${user.country}");
System.out.println("BEFORE:");
printProperties(props);
resolveSystemProperties(props);
System.out.println("\n\nAFTER:");
printProperties(props);
}
static void resolveSystemProperties(Properties props)
{
Map<String, String> sysProps = readSystemProperties();
Set<String> sysPropRefs = sysProps.keySet();
Enumeration names = props.propertyNames();
while (names.hasMoreElements())
{
String name = (String) names.nextElement();
String value = props.getProperty(name);
for (String ref : sysPropRefs)
{
if (value.contains(ref))
{
value = value.replace(ref, sysProps.get(ref));
}
}
props.setProperty(name, value);
}
}
static Map<String, String> readSystemProperties()
{
Properties props = System.getProperties();
Map<String, String> propsMap =
new HashMap<String, String>(props.size());
Enumeration names = props.propertyNames();
while (names.hasMoreElements())
{
String name = (String) names.nextElement();
propsMap.put("${" + name + "}", props.getProperty(name));
}
return propsMap;
}
static void printProperties(Properties props)
{
Enumeration names = props.propertyNames();
while (names.hasMoreElements())
{
String name = (String) names.nextElement();
String value = props.getProperty(name);
System.out.println(name + " => " + value);
}
}
}

Categories