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
Related
I'm writing a service to export a bunch of settings to a file. Naturally I want to reuse the already existing labels. We are dealing with a Spring+Wicket-Setup.
The labels are defined in a properties-file.
How can I access the properties?
I tried using StringResourceModels, but MissingResourceException was thrown all the time. I tried loading the properties by hand like
InputStream iStream;
iStream = MySettingsPage.class.getClassLoader().getResourceAsStream("MySettingsPage.properties");
if (iStream != null) {
prop.load(iStream);
}
But the InputStream is null, so no properties are loaded.
I haven't found anything about accessing Wicket properties from a Spring-Service.
Even though I know one should not entangle Spring services with Wicket classes, I'm willing to accept the consequences if there is no other way. Furthermore I'd like to avoid loading the properties by hand because they are already cached.
iStream = MySettingsPage.class.getClassLoader().getResourceAsStream("MySettingsPage.properties");
will try to load the file from the root of the classpath. I have the feeling that this file is next to MySettingsPage.class, i.e. it is in a package like com.example.myproduct. In that case use:
iStream = MySettingsPage.class.getResourceAsStream("MySettingsPage.properties");
I need a configuration file (Properties) for this project I'm working on.
The issue is that the Properties instance fails to load from the file (no exceptions, no visible problems) although it can store properly.
Because I have a defaults HashMap, any property that doesn't exist has it's default value placed in the Properties instance, which then stores everything, so that new properties are seamlessly added when the production server is updated.
I've been tracking this bug for hours, and I can't fix it. I've read dozens of questions here on StackOverflow as well as code examples on other sites. Nothing helped.
The one reason I haven't dropped it already and used the DB instead is that the JDBC driver URL, user and password are stored in that file as well. Notice that the file is being read and written to the hard drive.
Since the defaults system puts stuff in place, even if the file doesn't exist when I try to read, after it's saved it appears, but the next run still won't read anything. I noticed the bug after I changed a setting, and checked the file after a few runs, and to my shock, all values were default.
What's currently happening is the following:
1) No matter if the file is there or not, Properties will not load anything.
2) Since there's nothing in the Properties instance, it is filled with defaults.
3) The instance will now save, overwriting the file with the default values.
Here's all the relevant code:
private static Properties getConfig(){
Properties properties = new Properties();
File cfgFile = new File("data/titallus.properties");
try{
if(cfgFile.createNewFile()){
System.out.println("Config file not found. A default config file will be created automatically.");
}
FileReader reader = new FileReader(cfgFile);
FileWriter writer = new FileWriter(cfgFile);
properties.load(reader);
reader.close();
System.out.println(properties); // Debug, always prints '{}'
for(String k : defaults.keySet()){
if(!properties.containsKey(k)){
properties.setProperty(k, defaults.get(k));
}
}
properties.store(writer, "Titallus Configuration File");
writer.close();
}catch(Exception e){
e.printStackTrace();
System.exit(-1);
}
return properties;
}
I have tried everything I could think of, to no avail.
I also have a Properties subclass for multi-language support, which works just fine.
Does anyone have any idea how to fix this, or at least, another approach to this?
FileWriter writer = new FileWriter(cfgFile);
will be erasing your file before you read from it.
You create a FileWriter for the file before you load the file, which clears the existing data.
I have a tomcat server and i have a controller which writes in to a file, the data coming in the request. SO my doubt is whether multiple threads within the server can write into the same file at the same time and cause issues?
My requirement is that all requests appends data to the same file. I am not using any threading from my end.
My code is as follows:
File file = new File(fileName);
try {
if(!file.exists()) {
file.createNewFile();
}
InputStream inputStream = request.getInputStream();
FileWriter fileWriter = new FileWriter(fileName,true);
BufferedWriter bufferWriter = new BufferedWriter(fileWriter);
bufferWriter.write(IOUtils.toString(inputStream));
bufferWriter.flush();
bufferWriter.close();
}
There is the standard solution for such issue.
You have to create singleton class, which will be shared between all threads.
This singleton will have some BlockingQueue (e.g. LinkedBlockingQueue) in which all threads will put their messages for writing into single file.
This singleton by it self also will be the Thread and inside its run() method it will constantly take values from queue and sequentially write it into needed file.
My requirement is that all requests appends data to the same file
Doing a task for each request (like logging or in your case, appending text to a file) can be best implemented using a filter (javax.servlet.Filter). You don't have to create a singleton manually then and you can turn a filter on or off whenever you need its functionality or not.
However, you still need to synchronize the concurrent access to your file. As Andremoniy pointed out, you can do this using an own Thread, so that your filter does not block the request/response.
EDIT
One thing about the shared object used to write to the file: It is better to store an instance of this object in the javax.servlet.ServletContext rather than creating a singleton object. This is the standard way to go if you need to have an object accessible by all other components in a Java web application using servlets.
We're recently switched over to Log4J from JUL (java.util.Logging) because I wanted to add additional log files for different logging levels.
We have the option in the program to optionally append a value and a date/time stamp to the log file name at the (for all intents and purposes) end of the program's execution.
Because JUL seemed to open and close the file as needed to write to the file, it wasn't locked and we could simply use .renameTo() to change the filename.
Now, using Log4J, that file is left open and is locked, preventing us from renaming the file(s).
I can't decide the name of the file before I configure the logging because the property file containing the options for renaming is some time after the logging is needed (this is why we renamed it at the end of the program).
Do you have any suggestions as to how this can be achieved?
Would Logback and/or SLF4J help or hinder this?
I have sort of worked around the issue by using a system parameter in the log4j properties file, setting the property and then reloading the property file.
This allows me to change the name of the log file to something else at the end of the run, and then rename the old files.
It's inelegant, and very much of a kludge, so I would like to avoid this as it also leaves these temporary files around after the run.
One surefire approach would be to implement your own log4j Appender, perhaps based on the FileAppender ( http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/FileAppender.html ). Add your own specialized API to request the file be renamed.
I haven't tried this yet, but the tact I would take would be to use the underlying API setFile(...): http://www.jdocs.com/log4j/1.2.13/org/apache/log4j/FileAppender.html#M-setFile%28String,boolean,boolean,int%29
For example:
public class RenamingFileAppender extends FileAppender {
...
/** fix concurrency issue in stock implementation **/
public synchronized void setFile(String file) {
super.setFile(file);
}
public synchronized void renameFile(String newName) {
// whole method is synchronized to avoid losing log messages
// implementation can be smarter in having a short term queue
// for any messages that arrive while file is being renamed
File currentFile = new File(this.fileName);
File newFile = new File(newName);
// do checks to ensure current file exists, can be renamed etc.
...
// create a temp file to use while current log gets renamed
File tempFile = File.createTempFile("renaming-appender", ".log");
tempFile.deleteOnExit();
// tell underlying impl to use temporary file, so current file is flushed and closed
super.setFile(tempFile.getAbsolutePath(), false, this.bufferedIO, this.bufferSize);
// rename the recently closed file
currentFile.renameTo(newFile);
// now go back to the original log contents under the new name. Note append=true
super.setFile(newFile.getAbsolutePath(), true, this.bufferedIO, this.bufferSize);
}
Consider using a shutdown hooks, and renaming the file there...
http://onjava.com/pub/a/onjava/2003/03/26/shutdownhook.html
http://www.developerfeed.com/threads/tutorial/understanding-java-shutdown-hook
http://download.oracle.com/javase/1.4.2/docs/guide/lang/hook-design.html
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