Is there a way to use place holders in Apache PropertiesConfiguration - java

I have the following configuration setup using Apache Configuration:
import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.PropertiesConfiguration;
Configuration config = new PropertiesConfiguration("config.properties");
I want to know if there is some way to use place holders in the properties file? For example, I want to have this:
some.message = You got a message: {0}
And be able to pass in the value for the {0} place holder. Typically, you can usually do something like config.getString("some.message", String[] of values) but don't see anything like that.

As far as I know, Configuration class doesn't provide any formatters. So, for your task
You can use MessageFormat as it was suggested by Bilguun. Please
note, that format method is static.
You can use String.format function.
Examples is bellow:
config.properties
enter some.message.printf=%1$s\, you've got a message from %2$s \n
some.message.point.numbers =Hey {0}\, you got message: {1}!
Example class
import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.PropertiesConfiguration;
import java.text.MessageFormat;
public class ConfigurationTest {
public static void main(String[] args) throws ConfigurationException {
Configuration config = new PropertiesConfiguration("config.properties");
String stringFormat = String.format(config.getString("some.message.printf"), "Thomas", "Andrew");
// 1 String format
System.out.println(stringFormat);
// 2 Message Format
System.out.println(MessageFormat.format(config.getString("some.message.point.numbers"), "Thomas", "Hello"));
}
}

I believe you could get property value with placeholder from a property file and then use MessageFormat to formatting the message to what you desired. Let's say you got following property in your property file:
some.message = "Hey {0}, you got message: {1}!"
So that you get and format this property like:
message will be "Hey {0}, you got message: {1}!"
String message = config.getString("some.message");
MessageFormat mf = new MessageFormat("");
//it will print: "Hey Thomas, you got message: 1"
System.out.println(mf.format(message, "Thomas", 1));
Also, if you could use system variables or environmental variables if it is not changed on the fly

Related

Common configuration 2 - commented properties

i'm developing a java desktop application to use as a tool to manipulate properties files.
So my application need to to load a TXT file containing several keys (or properties), and be able to changes there values.
I use Apache commons configurations 2 project to do this work.
Everything was going well until a face this situation..
there is a txt file contating several properties but, one properties (or key) has a # before his name (look at config.txt file below), so apache commons do not recognize this propertie.
When i set a value to this propertie (look at last two lines on main method), apache commons configurator creates a new line on config.txt
This is not good to me, because i need to preserve the original config.txt format, so if i need to set a value to fileDb propertie, my expected behavior is to remove the # from fileDb name and do not create a new fileDb propertie on config.txt.
the program that uses this configuration file (config.txt) understands that if the property is commented (if it has "#" in its name), it means that it should not be used, but if it is uncommented (without "#" in the name) means that it should be used and that its value should be read.
So what can i do to add or remove "#" from the propertie name using common configuration? if is not possible to do it with commons configurator, how to do it?
On the ConfigTest class i show how the problem ocours.
Before run the code, the file config.txt has a commented propertie named fileDB
#fileDb = C:/test/test.db
the maind method try to change the filedb value to "C://aa//bb//cc"
but after the executions end wil appears a new propetie with the same name "fileDb" but uncomented (without "#"). At the end, config.txt wil have two fileDb propertie, one with "#" and other without "#"
#fileDb = C:/test/test.db
fileDb = C://aa//bb//cc
My expectd behavior after the code execution is to has only one fileDb propetie
fileDb = C://aa//bb//cc
After be able to uncoment this propertie i expect to be able to comment again if necessery (if user wish to do it on my app).
ConfigTest class
import org.apache.commons.configuration2.Configuration;
import org.apache.commons.configuration2.FileBasedConfiguration;
import org.apache.commons.configuration2.PropertiesConfiguration;
import org.apache.commons.configuration2.builder.FileBasedConfigurationBuilder;
import org.apache.commons.configuration2.builder.fluent.FileBasedBuilderParameters;
import org.apache.commons.configuration2.builder.fluent.Parameters;
import org.apache.commons.configuration2.ex.ConfigurationException;
import java.io.File;
public class ConfigTest {
private Configuration localConfiguration;
private FileBasedConfigurationBuilder<FileBasedConfiguration> fileBuilder;
private ConfigTest() throws ConfigurationException {
this.loadPropertiesFile();
}
private void loadPropertiesFile() throws ConfigurationException {
File file = new File("config.txt");
FileBasedBuilderParameters fb = new Parameters().fileBased();
fb.setFile(file);
fileBuilder = new FileBasedConfigurationBuilder<FileBasedConfiguration>(PropertiesConfiguration.class);
fileBuilder.configure(fb);
localConfiguration = fileBuilder.getConfiguration();
}
public boolean saveModifications(){
try {
fileBuilder.save();
return true;
} catch (ConfigurationException e) {
e.printStackTrace();
return false;
}
}
public void setProperty(String key, String value){
localConfiguration.setProperty(key,value);
}
public static void main(String[] args) throws ConfigurationException {
ConfigTest test = new ConfigTest();
//change outputOnSSD propertie value to false
test.setProperty("outputOnSSD", "false");
//here when i set a new value to fileDb propertie, a new line on config.txt with a new fileDb propertie name is created
//the question is: how to remove # from fileDb propetie name on config.txt to commons config recognize it as a existent propertie?
test.setProperty("fileDb", "C://aa//bb//cc");
test.saveModifications();
}
}
File "config.txt" used by ConfigTest class to change his value
########################################################################
# Local environment configuration
########################################################################
# Defines program localization/language
locale = pt-BR
# Temporary directory for processing: "default" uses the system temporary folder.
indexTemp = /home/downloads
# Enable if is on a SSD disk.
indexTempOnSSD = true
# Enable if output/case folder is on SSD. If enabled, index is created directly in case folder,
outputOnSSD = false
# Number of processing threads/workers: "default" uses the number of CPU logical cores.
numThreads = 14
# Full path for hash index database.
#fileDb = C:/test/test.db

GROOVY I am getting random backslashes when creating JSON file in Folder

I am having trouble compiling the JSON file. This is my method (the main method just has the name of the method I am writing this code in it so I did not include the main method in here.)
static void buildJSONFiles() {
String commandJson = "C:/Users/Name/Desktop/docfiles/command_config.json"
def data = [
commands:
JsonOutput.toJson([new Commands(name:"upload", path:"\${BUILTIN_EXE(command)}", includeCommandName: true),
new Commands(name:"file_info", path:"\${BUILTIN_EXE(command)}", includeCommandName: true)])
]
println(data)
def json_str = JsonOutput.toJson(data)
def json_beauty = JsonOutput.prettyPrint(json_str)
File file = new File(commandJson)
file.write(json_beauty)
println(json_str)
}
static class Commands {
String name
String path
boolean includeCommandName
}
my output in the console does come out right like this
[commands:[{"includeCommandName":true,"path":"${BUILTIN_EXE(command)}","name":"upload"},{"includeCommandName":true,"path":"${BUILTIN_EXE(command)}","name":"file_info"}]]
but sending it to the JSON file it comes out like this
{"commands":"[{\"includeCommandName\":true,\"path\":\"${BUILTIN_EXE(command)}\",\"name\":\"upload\"},{\"includeCommandName\":true,\"path\":\"${BUILTIN_EXE(command)}\",\"name\":\"file_info\"}]"}
I understand that JSON backslash is a special character so I expected it to be only around the :"${BUILTIN_EXE(command)} but it is showing up everywhere where I did not even have a backslash.
You don't have "random backslashes", you have double-quoted JSON, since you're using JsonOutput twice. json_str is a string with JSON in it, and then you're wrapping that as a JSON value inside more JSON.

How Google protobuf format reduces size of the object after it encoded

package sample;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang.SerializationUtils;
import sample.ProtoObj.Attachment;
public class Main {
public static void main(String args[]){
POJO pojo = new POJO();
pojo.setContent("content");
List<sample.POJO.Attachment> att = new ArrayList<POJO.Attachment>();
sample.POJO.Attachment attach = pojo.new Attachment();
attach.setName("Attachment Name");
attach.setId("0e068652dbd9");
attach.setSize(1913558);
att.add(attach);
pojo.setAttach(att);
byte[] byyy = SerializationUtils.serialize(pojo);
System.out.println("Size of the POJO ::: "+byyy.length);
ProtoObj tc = new ProtoObj();
List<Attachment> attachList = new ArrayList<ProtoObj.Attachment>();
Attachment attach1 = tc.new Attachment();
attach1.setName("Attachment Name");
attach1.setId("0e068652dbd9");
attach1.setSize(1913558);
attachList.add(attach1);
tc.setContent("content");
tc.setAttach(attachList);
byte[] bhh = tc.getProto(tc);
System.out.println("Size of the PROTO ::: "+bhh.length);
}
}
I have used above program to compute the size of the encoded/Serialized Object using Protobuf and POJO. Both the objects handle same set of the data. But the output shows drastic difference in the size of the object.
Output:
Size of the POJO ::: 336
Size of the PROTO ::: 82
Also I have read the below link to know how google protobuf formats affect the size of the encoded object.
https://developers.google.com/protocol-buffers/docs/encoding
But I'm unable to understand it. Please explain me to understand simply.
Protobuf doesn't send the schema alongside with the data. So both sides need to have the schema in order to deserialise passed data.
Because of that you can optimise and put each field right after another. Something like this:
AttachmentName0e068652dbd91913558
And all this in binary format. This in JSON would look like:
{"name": "AttachmentName", "id": "0e068652dbd9", "size": "1913558"}
As you can see the schema is encoded in the serialised message itself.
I'm not completely aware of Java SerialisationUtils, but I think they pass or encode the schema also and that's why you see this size difference.

dynamically read/add value to the parameter of conf file with Properties

I have a message like below in my conf file.
text.message = Richard has to go to School in 01/06/2012 / 1days.
All highlighted field will be variable.
I want to read this text.me string and insert the value from my java using Properties.
I know how to read the whole string using Prop, but don't know how to read like above String which will be like.
text.message = #name# has to go to #place# in #date# / #days#.
how can I read the above string from the conf using Properties and insert data dynamically?
It can be either date or days in the string. How I can turn on and off between those parameters?
Thanks ahead.
You can use the MessageFormat API for this.
Kickoff example:
text.message = {0} has to go to {1} in {2,date,dd/MM/yyyy} / {3}
with
String message = properties.getProperty("text.message");
String formattedMessage = MessageFormat.format(message, "Richard", "School", new Date(), "1days");
System.out.println(formattedMessage); // Richard has to go to School in 31/05/2012 / 1days
You can use the MessageFormat class, which replaces dynamic placeholders in a string with the desired values.
For example, the following code...
String pattern = "{0} has to go to {1} in {2,date} / {3,number,integer} days.";
String result = MessageFormat.format(pattern, "Richard", "school", new Date(), 5);
System.out.println(result);
...will produce the following output:
Richard has to go to school in 31-May-2012 / 5 days.
You can simply get the pattern from your Properties object, then apply the MessageFormat translation.

Regex to fetch only Key Value pairs and omit some charaters

I have this data
ReferenceDataLocation = as
##############################################################################
#
# LicenseKey
# Address Doctor License
#
##############################################################################
LicenseKey = al
which I'd like to capture only key value pairs eg: ReferenceDataLocation = as and LicenseKey = al
I wrote (?xms)(^[\w]+.*?)(?=^[\w]+|\z) regex which is perfect except the fact that it also captures ##### part, which is not key value pair.
Please help me modify the same regex (?xms)(^[\w]+.*?)(?=^[\w]+|\z) to only get ReferenceDataLocation = as and LicenseKey = al
Note: Here you can try out
Update
I tried (?xms)(^[\w]+.*?)(?=^[\w^#]+|\z) it works in the site but gives me an error in java
Exception in thread "main" java.util.regex.PatternSyntaxException: Unclosed character class near index 31
(?xms)(^[\w]+.*?)(?=^[\w^#]+|\Z)
^
Updat Regex that works for me
(?xms)(^[\w]+.*?)(?=^[\w^\s]+|\z)
You can't do that with a simple regex-match. You can't account for occurrences like these:
# some words here LicenseKey = al
The regex engine cannot look behind from LicenseKey to the end of the line. This is not supported in Java's regex engine (unbounded look-behinds).
But what you posted looks like it's just a properties file. Try this:
import java.io.FileInputStream;
import java.util.Properties;
public class Main {
public static void main(String[] args) throws Exception {
Properties properties = new Properties();
properties.load(new FileInputStream("test.properties"));
System.out.println(properties.getProperty("ReferenceDataLocation"));
System.out.println(properties.getProperty("LicenseKey"));
System.out.println(properties.getProperty("foo"));
}
}
which will print:
as
al
null
Note that your input file needn't be called test.properties, you can give it any name you like.
And if you don't know the keys up front, you can simply iterate over all entries in your properties file like this:
for(Map.Entry<Object, Object> entry : properties.entrySet()) {
System.out.println(entry.getKey() + " :: " + entry.getValue());
}
which prints:
LicenseKey :: al
ReferenceDataLocation :: as
And there's also Properties#stringPropertyNames() which returns a Set<String> that represents all keys in the properties file (see the API docs for more info).
See:
Tutorial: http://download.oracle.com/javase/tutorial/essential/environment/properties.html
API docs: http://download.oracle.com/javase/7/docs/api/java/util/Properties.html

Categories