java update properties file run time - java

i am writing standalone java app for production monitoring. once it starts running the api is configured for default values which is set in .properties file. in running state the api's configuration can be changed and the .properties file should be updated accordingly. is there a way to achieve this ? or are there any other approaches to implement this ?
Thanks in advance

The Java Properties class (api here) specifies "load" and "store" methods which should do exactly that. Use FileInputStream and FileOutputStream to specify the file to save it into.

You could use a very simple approach based on the java.util.Properties class which has indeed a load and store methods that you can use in conjunction with a FileInputStream and FileOutputStream:
But actually, I'd recommend to use an existing configuration library like Commons Configuration (amongst others). Check the Properties Howto to see how to load, save and automatically reload a properties file using its API.

I completely agree that Apache Commons Configuration API is really good choice.
This example update properties at runtime
File propertiesFile = new File(getClass().getClassLoader().getResource(fileName).getFile());
PropertiesConfiguration config = new PropertiesConfiguration(propertiesFile);
config.setProperty("hibernate.show_sql", "true");
config.save();
From the post how to update properties file in Java
Hope this help!

java.util.Properties doesn't provide runtime reloading out-of-the-box as far as I know.
Commons Configuration provides support for reloading configuration at runtime. The reload strategy can be configured by setting a ReloadingStrategy on the PropertiesConfiguration object. It also offers various other useful utilities for making your application configurable.

In addition to the load and store method of the Properties class, you can also use the Apache Commons Configuration library, which provides functions to easily manipulate configuration files (and not only .properties files).

Apache common configuration API provided different strategies to reload property files at run time. FileChangedReloadingStrategy is one of them. Refer this link to see an example for property file reloading at run time using FileChangedReloadingStrategy.

Try this:
// Write in property file at runtime
public void setValue(String key, String value) {
Properties props = new Properties();
String path = directoryPath+ "/src/test/resources/runTime.properties";
File f = new File(path);
try {
final FileInputStream configStream = new FileInputStream(f);
props.load(configStream);
configStream.close();
props.setProperty(key, value);
final FileOutputStream output = new FileOutputStream(f);
props.store(output, "");
output.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
// Read same file
public String getValue(String key) {
String value = null;
try {
Properties prop = new Properties();
File f = new File(directoryPath+"/src/test/resources/runTime.properties");
if (f.exists()) {
prop.load(new FileInputStream(f));
value = prop.getProperty(key);
}
} catch (Exception e) {
System.out.println("Failed to read from runTime.properties");
}
return value;
}

Related

Using properties file in Java: copy key value and assign it to another key

is it possible to achieve below scenario using properties file in Java. Thanks a lot for any feedback.
Assume I have a settings.properties file which includes,
my.name=${name}
his.name=hisNameIs${name}
In my code,
InputStream input = new FileInputStream("path/settings.properties");
Properties prop = new Properties();
prop.setProperty("my.name", "John");
prop.load(input);
String output= prop.getProperty(his.name);
System.out.println(output);
Expected Results:
hisNameIsJohn
The Apache Commons Configuration Project has an implementation capable of doing variable interpolation.
Read the section named Variable Interpolation
application.name = Killer App
application.version = 1.6.2
application.title = ${application.name} ${application.version}
You would need this third-party library in your class path, but on the other hand you will not have to worry about writing yet another implementation for this :)
You might like to read the Properties How To as well.
Posting the solution using org.apache.commons.configuration.PropertiesConfiguration
PropertiesConfiguration prop = new PropertiesConfiguration(new File("path/settings.properties"));
prop.addProperty("name", "John");
prop.getProperty(his.name);
In, "settings.properties" file.
his.name=hisNameIs${name}

update config file programmatically during runtime

I have a config.properties file that i want to update during runtime (for example, if the app receives a certain rest call, it updates the config properties).
Is this doable in java? or we can't change the config file on runtime?
thanks
In case you are using Java's Properties class, you can easily do it like this:
final Properties config = new Properties();
You can load a config file to your in-memory config like this:
final File f = new File("config.properties");
if(!f.exists) {
f.createNewFile();
}
final InputStream in = new FileInputStream(in);
config.load(in); //loads the config into the Properties object
in.close();
And if you wish to save the Properties back to a file, you can do:
final OutputStream out = new FileOutputStream(f);
config.save(out, "Some config comments...");
out.close();
You would probably need to wrap this in a try-catch block, but that's basically it.
This is possible, i assume you're using the Properties API? http://docs.oracle.com/javase/7/docs/api/java/util/Properties.html
You can use the store method specifying an OutputStream
logback uses Joran internally, which enabled logback to read configuration files and update them "on the fly" when their content changes. I used this functionality in 2011 and as far as I know Joran still is part of logback.
You could do something like this:
ruleMap = new HashMap<Pattern, Action>();
SetProfileParameterAction profile = new SetProfileParameterAction();
ruleMap.put(new Pattern("*/profile"), new AddProfileAction());
ruleMap.put(new Pattern("*/profile/description"), profile );
ruleMap.put(new Pattern("*/profile/link"), profile);
SimpleConfigurator simpleConfigurator = new SimpleConfigurator(ruleMap);
simpleConfigurator.setContext(context);
try {
simpleConfigurator.doConfigure(cfgFile);
} catch (JoranException e) {
log.error( "failed ...", e);
StatusPrinter.print(context);
}
Please note: this is just a non-complete cut-down version of my code but if Joran works for you this example will give you a hint in which direction to go ...

Java IO for files that are on OR off the classpath

I have an existing method that gets properties from a fixed location. This method also allows me to specify an override to use a different properties file. I want to be able to specify a file that is on the classpath while preserving the current functionality. How would I modify this to achieve this functionality?
protected Properties getProperties(String pathToPropertiesFile) throws IOException {
if (pathToPropertiesFile == null) {
pathToPropertiesFile = "/etc/machineProperties.properties";
}
FileInputStream inputStream = new FileInputStream(pathToPropertiesFile);
Properties props = new Properties();
props.load(inputStream);
return props;
}
All the IO utilities I have found so far work for only files on the classpath or files with absolute paths.
To load a text file that's on your classpath. Taken from here for more context.
InputStream in = this.getClass().getClassLoader()
.getResourceAsStream("SomeTextFile.txt");

Log4j doesn't see .properties file

I use log4j for logging in my app. In every class I need to log something I have the following:
Properties props = new Properties();
try {
props.load(new FileInputStream("/log4j.properties"));
} catch (Exception e){
LOG.error(e);
}
PropertyConfigurator.configure(props);
log4j.properties is placed to the folder /src/main/resources/
the path /log4.properties is given by IDEA as copy reference. When I start my app it it shows the FileNotFoundException
Don't use FileInputStream.
The java.io and its consorts work with the current working directory i.e the directory from which the JVM is executed and not the code workspace.
to illustrate this consider the following piece of code
class ReadFrmFile {
public static void main(String args[]) {
FileInputStream fin = New FileInputStream("intemp.txt");
}
}
If the code is executed from C:\TEMP , the intemp.txt is expected to be in the working directory(C:/TEMP) in this case. If not this will throw the FileNotFoundException. The path of the file names are always absolute and not relative.
To avoid hardcoding the best way would be to place all the required files in the classpath and load them using getResourceAsStream().
Properties props = new Properties();
try {
InputStream inStream = **YOUR_CLASS_NAME**.class.getResourceAsStream("/log4j.properties");
props.load(inStream);
} catch (Exception e){
LOG.error(e);
}
PropertyConfigurator.configure(props);
log4j, by default, looks for the log4j.properties file in the classpath, so you don't need to use the class PropertyConfigurator, ony if the file doesn't exist in the root of the classpath.
In the Spring MVC + Log4j Integration Example, you will see:

Read maven.properties file inside jar/war file

Is there a way to read the content of a file (maven.properties) inside a jar/war file with Java? I need to read the file from disk, when it's not used (in memory). Any advise on how to do this?
Regards,
Johan-Kees
String path = "META-INF/maven/pom.properties";
Properties prop = new Properties();
InputStream in = ClassLoader.getSystemResourceAsStream(path );
try {
prop.load(in);
}
catch (Exception e) {
} finally {
try { in.close(); }
catch (Exception ex){}
}
System.out.println("maven properties " + prop);
One thing first: technically, it's not a file. The JAR / WAR is a file, what you are looking for is an entry within an archive (AKA a resource).
And because it's not a file, you will need to get it as an InputStream
If the JAR / WAR is on the
classpath, you can do SomeClass.class.getResourceAsStream("/path/from/the/jar/to/maven.properties"), where SomeClass is any class inside that JAR / WAR
// these are equivalent:
SomeClass.class.getResourceAsStream("/abc/def");
SomeClass.class.getClassLoader().getResourceAsStream("abc/def");
// note the missing slash in the second version
If not, you will have to read the JAR / WAR like this:
JarFile jarFile = new JarFile(file);
InputStream inputStream =
jarFile.getInputStream(jarFile.getEntry("path/to/maven.properties"));
Now you probably want to load the InputStream into a Properties object:
Properties props = new Properties();
// or: Properties props = System.getProperties();
props.load(inputStream);
Or you can read the InputStream to a String. This is much easier if you use a library like
Apache Commons / IO
String str = IOUtils.toString(inputStream)
Google Guava
String str = CharStreams.toString(new InputStreamReader(inputStream));
This is definitely possible although without knowing your exact situation it's difficult to say specifically.
WAR and JAR files are basically .zip files, so if you have the location of the file containing the .properties file you want you can just open it up using ZipFile and extract the properties.
If it's a JAR file though, there may be an easier way: you could just add it to your classpath and load the properties using something like:
SomeClass.class.getClassLoader().getResourceAsStream("maven.properties");
(assuming the properties file is in the root package)

Categories