I would like to modify a properties file of a Portlet during runtime. The portlet is deployed in a Tomcat 7.0.23 and the properties file sits in "/WEB-INF/classes/content" from where I can access it via the code shown below. In fact, the code is executed without any exceptions but the newly added Property is not saved to the properties file.
String fileName = "MyProps.properties";
String relativePath = "/WEB-INF/classes/content/";
String fullPath = "c:/tomcat-7.0.23/webapps/my-portlet/WEB-INF/classes/content/";
try {
String path = relativePath + fileName;
InputStream in = getPortletContext().getResourceAsStream(path);
Properties props = new Properties();
props.load(in);
props.setProperty("test", "test");
File file = new File(fullPath + fileName));
FileOutputStream out = new FileOutputStream(file);
props.store(out, "");
} catch(Exception ex) { // error handling here}
After adding the new Property, I could verify with
props.list(System.out);
that it was added indeed. The context.xml file contains the following entries:
antiJARLocking="true"
antiResourceLocking="true"
Is this the right way to add/change Properties in a running Tomcat instance or should I take a different approach? If the latter, how could it be achieved best?
Many thanks for your answers!
You should definitely not rely on ever being able to change a file contained in a deployed web app. Control has been handed over to the container at that point and the file may be overwritten, or it may not even be writable. It also puts a burden on the application deployer, because now they cannot simply blow away the exploded WAR folder (if one exists) and redeploy the archive.
As an alternative to your approach, consider placing the properties file in a location external to the web app. One approach I've seen used successfully is this:
Determine a 'well-known' location where runtime property files will
be hosted, or allow the deployer to specify this location via a well
known property.
Attempt to read your property file from this location. If it does
not exist, create and initialize it from a template stored within
your application.
Save all changes made during the applications execution to this
external property file.
With this setup you never have to worry about not being able to write the file, or of it getting overwritten by the container.
Related
I am trying to generate a XML file and save it in /WEB-INF/pages/.
Below is my code which uses a relative path:
File folder = new File("src/main/webapp/WEB-INF/pages/");
StreamResult result = new StreamResult(new File(folder, fileName));
It's working fine when running as an application on my local machine (C:\Users\userName\Desktop\Source\MyProject\src\main\webapp\WEB-INF\pages\myFile.xml).
But when deploying and running on server machine, it throws the below exception:
javax.xml.transform.TransformerException:
java.io.FileNotFoundException
C:\project\eclipse-jee-luna-R-win32-x86_64\eclipse\src\main\webapp\WEB INF\pages\myFile.xml
I tried getServletContext().getRealPath() as well, but it's returning null on my server. Can someone help?
Never use relative local disk file system paths in a Java EE web application such as new File("filename.xml"). For an in depth explanation, see also getResourceAsStream() vs FileInputStream.
Never use getRealPath() with the purpose to obtain a location to write files. For an in depth explanation, see also What does servletcontext.getRealPath("/") mean and when should I use it.
Never write files to deploy folder anyway. For an in depth explanation, see also Recommended way to save uploaded files in a servlet application.
Always write them to an external folder on a predefined absolute path.
Either hardcoded:
File folder = new File("/absolute/path/to/web/files");
File result = new File(folder, "filename.xml");
// ...
Or configured in one of many ways:
File folder = new File(System.getProperty("xml.location"));
File result = new File(folder, "filename.xml");
// ...
Or making use of container-managed temp folder:
File folder = (File) getServletContext().getAttribute(ServletContext.TEMPDIR);
File result = new File(folder, "filename.xml");
// ...
Or making use of OS-managed temp folder:
File result = File.createTempFile("filename-", ".xml");
// ...
The alternative is to use a (embedded) database or a CDN host (e.g. S3).
See also:
Recommended way to save uploaded files in a servlet application
Where to place and how to read configuration resource files in servlet based application?
Simple ways to keep data on redeployment of Java EE 7 web application
Store PDF for a limited time on app server and make it available for download
What does servletcontext.getRealPath("/") mean and when should I use it
getResourceAsStream() vs FileInputStream
just use
File relpath = new File(".\pages\");
as application cursor in default stay into web-inf folder.
My Java EE application includes many sub-projects, which should use a single one configuration file to connect to the database. I intend to write a Java class and make it an independent jar to read the database connection parameters from datasource.xml, which will be put on the path of the independent jar.
The questions I want to ask:
How to dynamic get the absolute path of the datasource.xml?
Can the solution of the first question work in all operating systems like UNIX, etc?
The first subject you have to deal with is where you store that file.
According to your question, you are going to be storing the file somewhere on the file system, externally to the actual application package. Therefore, you absolutely must know where the file is really located on the file system in order to access it; you can't conclude it in advance, unless you use environment variables that will instruct your code where the file is located.
A better approach is to package your XML file with the JAR. Then, you need not worry about absolute paths anymore. Simply use Thread.currentThread().getContextClassLoader().getResource(), providing the package-style path to the resource and you'll get a reference to it wherever it may be found.
If you can't package your file along with the JAR, you might be able to store it in a directory on the file system and add that directory to your server's classpath lookup sequence; some application servers support that. Then, you can still use the classloader to look up the resource, without requiring to know its absolute location.
What about this? Converting a relative path to absolute during runtime.. I guess that should work on all enviroments...
File a = new File("/some/abs/path");
File parentFolder = new File(a.getParent());
File b = new File(parentFolder, "../some/relative/path");
String absolute = b.getCanonicalPath(); // may throw IOException
regards
You can make use of Environment Variables
String path = System.getEnv("MYVARIABLE");
File datasource = path + "/datasource.xml";
Or read in the location from a properties file available in a constant location
Properties props = new Properties();
try {
props.load("MyFixed.properties");
} catch(Exception e) {
e.printStackTrace(); // Can do better
}
String path = props.getProperty("datasource.path");
File datasource = path + "/datasource.xml";
Or pass in a VM argument when starting the Jar with -D
String path = System.getProperty("datasource.path");
File datasource = path + "/datasource.xml";
and call with
java -jar -Ddatasource.path=/my/path/to/datasource.xml my.jar
Please tell me where exactly do i put my .properties file in my eclipse project. Do I make a separate folder for it ?
I want to put it in such a way that I will be able to distribute my project easily in JAR form.
Thanks.
EDIT:
I want to put the properties file in such a way that it can be easily edited later, on any OS.
The approach I use in order to be able to easily change configuration without redeployment.
One version of the property file (with the defaults) in the root of your project, I always let it in the application package (foo.bar.myapp). I load the default one with getResourceAsStream("/foo/bar/myapp/config.properties") or like in the sample relative to the class package.
And additionally I ready a system property:
String configFileLocation = System.getProperty("config");
And just override the default with the properties read from the config file passed as property.
For instance:
Properties props = new Properties();
props.load(Main.class.getResourceAsStream("mydefault.properties"));
System.out.println("default loaded: " + props);
String configFile = System.getProperty("config");
if (configFile != null) {
props.load(new FileInputStream(configFile));
System.out.println("custom config loaded from " + configFile);
}
System.out.println("custom override: " + props);
This would load first your resource stored under your project in foo.bar package named mydefault.properties, and after it if system property config is configured it will load override the loaded properties with the one the the referred path.
The system property can be set using -D parameter, in this case would be something like: java -Dconfig=/home/user/custom.properties foo.bar.Main. Or if you are in a web application (Tomcat for instance) you can set this property using CATALINA_OPTS.
src/main/resource would be an ideal choice.
Users can upload images on my website. My servlet needs to write the uploads into directory images of my webapp. For writing it onto the disk I need to create a File() object.
One way is that I can hardcode the complete path to something like
new File("/usr/tomcat/webapps/ROOT/images/file.jpg")
Is there a way so that I can specify something like new File("images/file.jpg").. Can I do it using new File (URI uri ) so that I do not have to hardcode the complete path. My servlet is located inside /usr/tomcat/webapps/ROOT/WEB-INF/classes/
The images folder is not a directory. It is actually a symbolic link which is pointing to another directory on the filesystem outside tomcat
Don't store images under your webapp deployment directory: next time you'll redeploy the app, you will lose all your images. And moreover, there is not always a directory for a webapp, since it's typically deployed as a war file.
Store your images in an external location, at an absolute path, and configure Tomcat or another web server to serve images from this location, or implement a servlet which serves images from this location.
See Image Upload and Display in JSP for additional pointers.
EDIT:
If your problem is the hard-coded absolute path in the Java code, use a System property that you set when starting Tomcat, or a context param in the web.xml, or use a properties file to store the path, or your database.
You can get the web app path from the ServletContext object. You get the ServletContext from the HttpServletRequest object (http://docs.oracle.com/javaee/6/api/javax/servlet/ServletRequest.html#getServletContext%28%29).
See http://docs.oracle.com/javaee/6/api/javax/servlet/ServletContext.html#getRealPath%28java.lang.String%29
Concatenate the "real path" to the desired image file path and provide this as the parameter to the File constructor.
try{
String directory = //Store it in your Property file and pick it
String filename= //Generate Dynamic name or any specific format
// Create file
FileWriter fstream = new FileWriter(directory+filename);
BufferedWriter out = new BufferedWriter(fstream);
out.write("your content"); }
catch (Exception e){
System.err.println("Error: " + e.getMessage()); }
finally {
//Close the output stream
out.close();
}
You Can keep the directory path in you property file if it is not changing frequently.
Directory name can be absolute path which may be a hardrive path or you can save it in your webapp also but it always advisable any input file keep it outside the webapp.
File naming is always up to you if you want to keep the same file name then need to handle duplicate check other wise specify some dynamic format and named it.
I have created a dynamic web project within Eclipse. I created a properties file inside the src directory:
<project-root>/src/props.properties
I'm starting Tomcat via Eclipse in debug mode. Now I want to read the properties file from one of my POJOs, but I get a FileNotFoundException. The current path seems to be the Eclipse path.
I had a look into the web for solution, but none of them worked for me. Maybe I did something wrong. The code is like this:
File file = new File("props.properties");
FileReader reader = new FileReader(file);
properties.load(reader);
How should I acces the properties file?
Where should it be located?
Thanks in advance.
If its a web application then the properties will get deployed to WEB-INF/classes and can be loaded using the class loader
InputStream in = {NameOfClassWhereThisisInvoked}.class.getResourceAsStream("/props.properties");
properties.load(in);
in.close();
Actully that should work regardless of whether it is a webapp or not.
I'm assuming src is defined as a source folder
There is another way of doing this as follows:
File file = new File(session.getServletContext().getRealPath("/") + "props.properties");
Instead of "props.properties" you could give any path relative to the "WebContent" folder of your eclipse web-application project.
here is the correct way to load properties file from anywhere in the classpath
private Properties getPropertiesFromClasspath(String propFileName)
throws IOException
{
Properties props = new Properties();
InputStream inputStream =
this.getClass().getClassLoader().getResourceAsStream(propFileName);
if (inputStream == null)
{
throw new FileNotFoundException("property file '" + propFileName
+ "' not found in the classpath");
}
props.load(inputStream);
return props;
}
You can create a singleton class to load properties in memory on first time access and later use them via a static method. A complete example of this is available at
http://bharatonjava.wordpress.com/2012/09/12/using-properties-file-in-java-application/
Kepp ur Properties file in src folder and the following code is enough to read the properties file
**File file = new File("./src/config.properties");
FileReader reader = new FileReader(file);
prop.load(reader);
System.out.println(prop.getProperty("directorypath"));**
Is your project set to build automatically? If so (or you're building manually), check whetherprops.properties appears in your project's output folder (in Eclipse this is usually "bin" but may be WebRoot or something else, depending on how your project is set up).
When a project builds, it should copy over config files as well as your compiled classes, JSPs etc. However, I believe that file readers, by default, use the JVM's home directory for their source. In Eclipse's case, this means that your props.properties file would have to be in the project root, i.e. not the "src" folder.