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");
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
All,
I have decided to adopt the java.util.Properties class within my servlets to facilitate easier maintenance of configs.
I am using the poperties class function loadFromXML to fetch an XML file that contains denatured (XML compliant ) SQL queries that my servlet will then execute.
Using this code which works fine in normal CLI Java application:
// retrieve all queries from xml from classpath
queries = new Properties();
try
{
String path = getServletContext().getRealPath("/WEB-INF");
System.out.println(path + "/queries.xml");
queries.loadFromXML(MyServlet.class.getResourceAsStream(path + "/queries.xml"));
}
catch (IOException io)
{
io.printStackTrace();
}
The output is a NULL Pointer Exception thrown by the loadFromXML method
java.lang.NullPointerException
at java.util.Properties.loadFromXML(Properties.java:851)
The file exists as produced by the system out message in the web server logs.
CORE3282: stdout: /u02/SunONE61060/testserver/myservlet/WEB-INF/queries.xml
I tried moving the XML file to the base directory where the Servlet class exists and call it from there but still the same NPE.
Any ideas?
Your problem is here:
MyServlet.class.getResourceAsStream(path + "/queries.xml")
This will return null. .getResourceAsStream() can only load from the classpath (for instance, /com/foo/myclass/MyResource.xml).
Since you have the absolute path of your resource, just use a standard FileInputStream, for instance.
Also: close your stream after you are done with it. Right now you don't: you have a resource leak. See the javadoc for Closeable.
You are attempting to load the resources from your classpath but are providing a real path. These two are not the same.
When you are using
MyServlet.class.getResourceAsStream("queries.xml")
Then the classloader will attempt to load the class from whereever your MyServlet.class file is, so if the package is my.pkg, it will attempt to load it from WEB-INF/classes/my/pkg/queries.xml.
You can also put the queries into the root of your class hierarchy (WEB-INF/classes/queries.xml) and load it like so:
MyServlet.class.getResourceAsStream("/queries.xml")
Then it will expect the file in WEB-INF/classes/queries.xml.
Alternatively, if you want to leave the file where it is, just use the servlet context to get the input stream:
getServletContext().getResourceAsStream("/WEB-INF/queries.xml")
It isn't valid to get a real path and then treat that as part of a resource path. It isn't. Make up your mind. Just do
getResourceAsStream("/WEB-INF/classes/.../queries.xml")
where the ... is the package of MyServlet, and put the resource file there.
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 noticed that when I try to load a resource (an image, data, sound file, ect.) it is not possible to put it in the same file as the source code and just type "soundfiles/sound.wav". What is the best way to get this url?
Specifically here:
// load wave data from buffer
WaveData wavefile = WaveData.create("spaceinvaders/" + path);
I have done this before in many different ways, just wondering what the best way is.
If you ship your application in jar it's common way to package resources also in jar and access them using classloader:
//jar structure
your.jar
|--com
| `--... //classes here
`--resources
`--spaceinvaders
`--sound.wav
And code to access:
InputStream resource = getClass().getClassLoader().getResourceAsStream("resources/spaceinvaders/sound.wav");
Background
Developing a simple web application (Eclipse + JBoss + Apache Tomcat) to generate XML files.
Problem
The "Business Area" list queries against the database, and the "Column Cluster" list queries the database using the selected "Business Area" items. Both of these are unique queries that are stored external text files.
The files are currently stored in the following locations:
WebContent/META-INF/business-areas.sql
WebContent/META-INF/column-clusters.sql
These are then used to seed PreparedStatements.
Source Code
The method to read the SQL code might resemble:
private String getSQL() {
String result = "";
try {
BufferedReader br = open( "business-areas.sql" );
String line = null;
while( (line = br.readLine()) != null ) {
result += line;
}
br.close();
}
catch( Exception e ) {
e.printStackTrace();
}
return result;
}
Questions
I would like to know:
What are the best practices for storing such assets for deployment as part of a web app? (That is, is META-INF a good location, or is META-INF/resources preferred?)
What APIs would you recommend for reading the file content? (That is, how do I write the open method so that it finds the files to open?)
I already have JNDI in place to establish the database connection, but would rather not use JNDI to obtain handles to the files, if possible.
Related Sites
http://blogs.oracle.com/alexismp/entry/web_inf_lib_jar_meta
http://www.avajava.com/tutorials/lessons/where-do-i-put-resources-in-my-maven-project.html
http://docs.jboss.org/jbossweb/3.0.x/config/context.html
http://tomcat.apache.org/tomcat-4.0-doc/catalina/docs/api/org/apache/naming/resources/FileDirContext.html
Thank you!
The right location (and also the common practice) is to place them under your source directory, which will then gets compiled into WEB-INF/classes directory. I'm not sure what you meant by "classes directory is volatile" in your response to #Dave, but this is how most (if not all) Java web apps store things. WEB-INF/classes is not just for Java classes. It's common to see logging properties file (like log4j), Hibernate and Spring XML files stored under source directory and you can safely access the files using something like this:-
// in this case, the business-areas.sql is located right under "source/sql" directory
InputStream is = getClass().getClassLoader().getResourceAsStream("sql/business-areas.sql");
BufferedReader br = new BufferedReader(new InputStreamReader(is));
Some useful information about the use of META-INF: What's the purpose of META-INF?
I had similar concerns as Dave Jarvis about mixing resources with classes and lib, so I did some fiddling and found this solution:
I placed my resource files in WEB-INF/resources. Then, to load them, I used this:
getClass().getClassLoader().getResourceAsStream("../resources/main.xml");
I don't know that using a .. is a much cleaner solution, but my files are at least not mixed with classes or jars.
I'd put them in WEB-INF/classes, or bundle them inside your application.jar which will go inside WEB-INF/lib. Then you can load them from the classpath as explained here and here
Even better, if you use maven, the best practice is to put these type of files inside src/main/resources and then maven will take care of this for you.