What is a best practice for storing user messages in a configuration file and then retrieving them for certain events throughout an application?
I was thinking of having 1 single configuration file with entries such as
REQUIRED_FIELD = {0} is a required field
INVALID_FORMAT = The format for {0} is {1}
etc. and then calling them from a class that would be something like this
public class UIMessages {
public static final String REQUIRED_FIELD = "REQUIRED_FIELD";
public static final String INVALID_FORMAT = "INVALID_FORMAT";
static {
// load configuration file into a "Properties" object
}
public static String getMessage(String messageKey) {
//
return properties.getProperty(messageKey);
}
}
Is this the right way to approach this problem or is there some de-facto standard already in place?
You're on the right track with putting the messages into a property file. Java makes this pretty easy if you use ResourceBundle. You basically create a property file containing your message strings for each locale you want to support (messages_en.properties, messages_ja.properties) and bundle those property files into your jar. Then, in your code, you extract the message:
ResourceBundle bundle = ResourceBundle.getBundle("messages");
String text = MessageFormat.format(bundle.getString("ERROR_MESSAGE"), args);
When you load the bundle, Java will determine what locale you're running in and load the correct message. Then, you pass in your args along with the message string and create the localized message.
Reference for ResourceBundle.
Your approach is almost correct. I want to add one more thing. If you are talking about configuration file, it is always better to have two .properties file.
One for default configuration of the application. (let's say defaultProperties.properties)
Second for user-specific configuration (let's say appProperties.properties)
. . .
// create and load default properties
Properties defaultProps = new Properties();
FileInputStream in = new FileInputStream("defaultProperties");
defaultProps.load(in);
in.close();
// create application properties with default
Properties applicationProps = new Properties(defaultProps);
// now load properties from last invocation
in = new FileInputStream("appProperties");
applicationProps.load(in);
in.close();
. . .
Spring already has support for doing this kind of thing. http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/beans.html#context-functionality-messagesource would be a good starting point
Related
I have a java web applilication. This application loads its configuration file with singleton according source file below.
public class Configuration {
private static Configuration config;
private static Properties prop = null;
private static InputStream input = null;
private Configuration() {
input = this.getClass().getResourceAsStream("/config.properties");
prop = new Properties();
prop.load(input);
input = new FileInputStream(prop.getProperty("soap.config"));
prop = new Properties(prop);
prop.load(new InputStreamReader(input, StandardCharsets.UTF_8));
}
public static Configuration getInstance() {
if (config == null) {
config = new Configuration();
}
return config;
}
}
config.properties (located into resources folder of java project)
soap.config=/home/wildfly/soap.propeties
Content of soap.properties file:
server=192.168.1.1
user=John
pass=thepass
Server features:
Total memory: 8GBram. 30% ram used
1 core, 40gb hard disk
Widfly Server
linux virtual machine
If I want to change some value in config file, it's necessary to restart the aplication by Wildfly admin console also. I think it's more useful to change config file values without restarting the application.
Additionally, the application receives more than thousands request a day and I see server status is fine.
Questions:
Is it beneficial or worth to use singleton to load a configuration file?
The instruction this.getClass().getResourceAsStream("/config.properties") will read the config file and after that it will close it inmediatelly. Is it correct?
Let's break this into two pieces: is a singleton ok for a config file? Kind of. Singletons have some major flaws when it comes to testability. It's better in general to use injection, and to pass an instance of the class to every place that needs it. A singleton will work, but it will make your testing far harder.
Is there a better way to handle config files so they handle changes? Yes. Use a WatchService to watch for when the file is changed (https://docs.oracle.com/javase/tutorial/essential/io/notification.html). The Configuration class should handle this. Then when it does change, it should parse the new file and update itself. This does provide a gap for race conditions though where part of the data is fetched from the old file, and part from the new. There's techniques you can use to avoid that however (providing all the data atomically, or allowing a client to lock the configuration file and only updating when its unlocked, etc).
The best solution I can think of:
simply give the config another field: lastFileEditedTime that stores the timestamp of the file that was loaded last.
create a static variable: lastFileUpdateCheckedTime. this stores the last check time in ms (System.getCurrentMilis) and if the last check has been made more than x seconds ago, check that file again
use both in the getInstance() method. First check against lastFileUpdateCheckedTime, and if that triggers, check against lastFileEditedTime
(you could also make both static or add both to the config, however you like)
This way the system keeps loading updated files, but will not reload too many times per second or do the filesystem timestamp check too often.
And to answer your questions:
yes, singleton is beneficial, because it prevents loading each time, and all parts of your code that use it are (more or less) on the same config
no, getResourceAsStream will give you an open stream, you should close it. Activate compiler warnings, they will clearly show you. Best use try-resource-catch for closing
I have a class of which I need a different instance if one of its attributes changes. These changes are read at runtime from a property file.
I would like to have a single file detailing the properties of all the single instances:
------------
name=Milan
surface=....
------------
name=Naples
surface=....
How can I load each set of properties in a different Property class (maybe creating a Properties[])? Is there a Java built in method to do so?
Should I manually parse it, how could create an InputStream anytime I find the division String among the sets?
ArrayList<Properties> properties = new ArrayList<>();
if( whateverItIs.nextLine() == "----" ){
InputStream limitedInputStream = next-5-lines ;
properties.add(new Properties().load(limitedInputStream));
}
Something like above. And, by the way, any constructor method which directly creates the class from a file?
EDIT: any pointing in the right direction to look it for myself would be fine too.
First of all, read the whole file as a single string. Then use split and StringReader.
String propertiesFile = FileUtils.readFileToString(file, "utf-8");
String[] propertyDivs = propertiesFile.split("----");
ArrayList<Properties> properties = new ArrayList<Properties>();
for (String propertyDiv : propertyDivs) {
properties.add(new Properties().load(new StringReader(propertyDiv)));
}
The example above uses apache commons-io library for file to String one-liner, because Java does not have such a built-in method. However, reading file can be easily implemented using standard Java libraries, see Whole text file to a String in Java
background:
I need to load test a process on a server that I am working with. What I am doing is I am creating a bunch of files on client side and will upload them to server. The server is monitoring for new files (in input dir, file names are unique) and once there is a new file it processes it, once done, it creates a response file with same name but different extension to output dir. If the processing fails, it puts the incoming file to error dir. I am using the inotifywait to monitor the changes on server, which outputs:
10:48:47 /path/to/in/ CREATE ABCD.infile1
10:48:55 /path/to/out/ CREATE ABCD.outfile1
or
10:49:11 /path/to/in/ CREATE ASDF.infile1
10:49:19 /path/to/err/ CREATE ASDF.infile1
problem:
I need to parse the list of all results (planning to implement in java) like so, that I take the infile and match it with the same file name (either found in ERR or OUT), calculate the time taken and indicate weather it was success or not. The idea I am having is to create 3 lists (in, out, err) and try to parse, something like (in pseudo-code)
inList
outList
errList
for item : inList
if outlist.contains(item) parse;
else if errList.contains(item) parse;
else error;
question:
Is this efficient? Or is there a better way to approach this situation? Anyway, you might think that it is a code you are executing just once, why the struggle, but I really would like to know how do handle this properly.
The solution with lists is problematic, as you will have to keep them synchronized properly with the state of drive and always load them. What is more you will reach at some point capacity limit for file stored in single location.
Alternatives what you have are that you use i/o API to check path existence, or introduce a between database where you will store your values.
Another approach is database where you will store the information about keys and physical paths that file really has.
If I was you i would start with the I/O API and design a simple interface that could be replaced in future if the solution would appear to be inefficient.
You can use the "UserDefinedfileAttributeView" concept.
Create your own File attribute, say, "Result" and set its value accordingly for the files in IN dir. If the file is moved to OUT dir, "Result"="Success" and if the file is moved to ERR dir, "Result"="Error"
I tried the below code, hope it helps.
public static void main(String[] args) {
try{
Path file = Paths.get("C:\\Users\\rohit\\Desktop\\imp docs\\Steps.txt");
UserDefinedFileAttributeView userView = Files.getFileAttributeView(file, UserDefinedFileAttributeView.class);
String attribName = "RESULT";
String attribValue = "SUCCESS";
userView.write(attribName, Charset.defaultCharset().encode(attribValue));
List<String> attribList = userView.list();
for (String s : attribList) {
ByteBuffer buf = ByteBuffer.allocate(userView.size(s));
userView.read(s, buf);
buf.flip();
String value = Charset.defaultCharset().decode(buf).toString();
if("SUCCESS".equals(value)){
System.out.print(String.format("User defined attribute: %s", s));
System.out.println(String.format("; value: %s", value));
}
}
}
catch(Exception e){
}
You can do this for every file placed in IN dir.
I am creating some REST APIs. For this I have some application level common name value pairs. To configure those name value pairs , I just created an xml file in WebContent and accessed values from the xml in a static block of a class and initialized with static variables. So all values which are given for each name in xml will be assigned to respective static variable from a class's static block.
I am able to access those variables and get values in each classes other than from a REST API client. The problem comes, when I'm creating a REST API client for consuming API's created in the same project, FileNotFoundException is throwing for the path I have given for my xml file(WebContent/myxml.xml).
I can see that, its searching for the same xml file in my eclipse path(/home/aneesh/eclipse/WebContent/myxml.xml). And FileNotFoundException throwing.
How can I resolve this issue?
1. class which accessing xml file
class Constants {
public static String name;
static {
initializeConstants();
}
public static void initializeConstants() {
try {
//initializing Constants
//"Reading file"
File xmlFile = new File("WebContent/myxml.xml");
.......
//file is getting read perfectly and "name" is initialized
}
}
2. class accepting static variable Constants.name
// accepting value of 'name' using Constants.name successfully
// writing a method which is accepting some parameters and using Constants.name.
// writing a "main" method and calling this class's methods will work perfectly.
// value of Constants.name will be accessible here.
3. REST API created which will call methods of second class with parameters.
4. Webscript client created for consuming above created API.
// Here the exception is coming.
// Eception is throwing from the class Constants
//Exception from Constants : FileNotFoundException
java.io.FileNotFoundException: /home/aneesh/eclipse/eclipse/WebContent/myxml.xml (No such file or directory)
So, why in this case its looking for the file in eclipse's path? How to resolve it?
Tried by putting into src folder also, but not working.
Try giving the path as WebContent//myxml.xml
(Note the double forward slashes //)
You will have to find the path of the XML file dynamically.
You can use ServletContext object's getRealPath() - you can use it like : getRealPath("/"), which returns you the path of the application deployed. Then from there you can navigate to the XML file required inside your application.
ServletContext context = session.getServletContext();
String path = context.getRealPath("/");
Use the variable path and navigate to your XML.
As I my class is not a Servlet class; I followed;
public String getAppPath() {
java.net.URL r = this.getClass().getClassLoader().getResource("myxml.xml");
String filePath = r.getFile();
String result = new File(new File(new File(filePath).getParent()).getParent()).getParent();
if (!filePath.contains("WEB-INF")) {
// Assume we need to add the "WebContent" folder if using Jetty.
result = FilenameUtils.concat(result, "WebContent");
}
return result;
}
I want to take place database.properties outside the project, so when I want to change the content (database configuration) of that when I've build them into jar, I can do it easily without open my project again. So what to do?
First, place the database.properties file in the location you'd like it to be in.
Then, do one of the following:
Add the directory where database.properties is located, to the classpath. Then use Thread.currentThread().getContextClassLoader().getResource() to get a URL to the file, or getResourceAsStream() to get an input stream for the file.
If you don't mind your Java application knowing the exact location of the database.properties file, you can use simple File I/O to obtain a reference to the file (use new File(filename)).
Usually, you'd want to stick with the first option. Place the file anywhere, and add the directory to the classpath. That way, your Java application doesn't have to be aware of the exact location of the file - it will find it as long as the file's directory is added to the runtime classpath.
Example (for the first approach):
public static void main(String []args) throws Exception {
InputStream stream = Thread.currentThread().getContextClassLoader().getResourceAsStream("database.properties");
Properties props = new Properties();
try {
// Read the properties.
props.load(stream);
} finally {
// Don't forget to close the stream, whatever happens.
stream.close();
}
// When reaching this point, 'props' has your database properties.
}
Store properties file in your preferred location. Then do the following:
try {
String myPropertiesFilePath = "D:\\configuration.properties"; // path to your properties file
File myPropFile = new File(myPropertiesFilePath); // open the file
Properties theConfiguration = new Properties();
theConfiguration.load(new FileInputStream(myPropFile)); // load the properties
catch (Exception e) {
}
Now you can easily get properties as String from the file:
String datasourceContext = theConfiguration.getString("demo.datasource.context", "jdbc/demo-DS"); // second one is the default value, in case there is no property defined in the file
Your configuration.properties file might look something like this:
demo.datasource.context=jdbc/demo-DS
demo.datasource.password=123