Get absolute path of a property file - java

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

Related

Sharing a Java Object Stream

I've got a project to do with 2 other classmates.
We used Dropbox to share the project so we can write from our houses (Isn't a very good choice, but it worked and was easier than using GitHub)
My question is now about sharing the object stream.
I want to put the file of the stream in same dropbox shared directory of the code.
BUT, when i initialize the file
File f = new File(PATH);
i must use the path of my computer (C:\User**Alessandro**\Dropbox)
As you can see it is linked to Alessandro, and so to my computer.
This clearly won't work on another PC.
How can tell the compiler to just look in the same directory of the source code/.class files?
You can use Class#getResource(java.lang.String) to obtain a URL corresponding to the location of the file relative to the classpath of the Java program:
URL url = getClass().getResource("/path/to/the/file");
File file = new File(url.getPath());
Note here that / is the root of your classpath, which is the top of the directory containing your class files. So your resource should be placed inside the classpath somewhere in order for it to work on your friend's computer.
Don't use absolute paths. Use relative paths like ./myfile.txt. Start the program with the project directory as the current dir. (This is the default in Eclipse.) But then you have to ensure that this both works for development and for production use.
As an alternative you can create a properties file and define the path there. Your code then only refers to a property name and each developer can adjust the configuration file. See Properties documentation.

Dynamically finding the destination of the project

I can use:
getClass().getClassLoader().getResource("").getPath());
To dynamically get the path of the Class files in my project.
But I need to get the path dynamically for the home directory of the project. I can't do this statically, like this:
File file = new File("C:\Users\etc...");
Because the destination of the project can change from one computer to the next. I need to call a file in the project's home directory. How do I do that dynamically. It would be similar to how I did it in the beginning of this question, but it can not be just for Classes.
Any idea?
There's no such thing as a "java project" in Java. If you know where your class files are in relationship to whatever directory you're trying to locate, you can use the path you obtained in your first example:
Url classUrl = ...
File resourcePath = new File(classUrl.toUri());
File rootDir = resourcePath.getParentFile().getParentFile().getParentFile();
or
File rootDir = new File(resourcePath.getPath() +
"/../../../".replace("/", File.separatorChar));
Of course, this will only work as long as the files are actually on the file system; if they're in a jar, you'd need to locate the jar file instead.
But this is usually not something you want to do. It's a better practice to configure a sandbox for your application by passing them to your application as command-line arguments or environment variables. In some cases, it's also useful to use the pre-defined System properties such as user.home, user.dir, and java.io.tmpdir.

How to read file with different canonical paths

I am making an java application which reads a file from a particular location. The location of the file is in the folder retrived from
getCanonicalPath().
The problem i am facing is that when i am running my application in Eclipse the canonical path is different from the one which Dr Java sees. So, what should i do before delivering my application to the client to make sure that it sees the file no matter which ide/command prompt is used to run the application. Obviously it would not be a good idea to copy the same file across all possible folders to cover different possibilities of getCanonicalPath.
Thanks
One of the solution is to have this file in your classpath and load it from your classpath, with a code like
URL url = getClass().getClassLoader().getResource(path);
if(url != null) {
try {
return new File(url.toURI().getPath());
} catch (URISyntaxException e) {
return null;
}
}
This is standard if this file is a configuration file. Usually in a standard java project layout you put this in the folder src/main/resources.
If this is more of a data file, you should put in a configuration file its path, and have different configurations, one for your station and one for production on the client machine. Of course in this case the configuration file is in the class path ;).
A common solution is to place the file in a directory which is in the class path. If you use getResource or getResourceAsInputStream you can find the file regardless of where it is provided its in the class path. if you use maven you can be sure how the classpath is setup regardless of the IDE used.
You should always load file ClassLoader using API like Test.class.getClassLoader().getResource(name),Test.class.getClassLoader().getResourceAsStream(name) More Information available here

modify properties file in Tomcat during runtime

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.

Loading application properties in a Java desktop application

What is the best way to store and load application level properties in Java.
Is there anything simulare to .net where I would just put something in the app.config
<appSettings>
<add key="emailAddress" value="me#example.com" />
</appSettings>
And then retrieve it like this:
string AdminEmail = ConfigurationManager.AppSettings["emailAddress"];
Do I have to load properties files into file streams and such? seems like unnecessary work.
I have tried this:
Properties props = new Properties();
FileInputStream fis = new FileInputStream("myProps.properties");
props.load(fis);
fis.close();
But this is give me a java.io.FileNotFoundException exception. Where does the properties file need to go to in relation to the class?
The Preferences API provides this functionality. It has many warts, but if you are looking to do this in an OS-agnostic fashion, this is the only way to accomplish this using the standard Java runtime libraries. You can of course always write your own OS-specific code to meet your needs. Yes, you can write simple code to load a properties file, but the location of that file can become a problem across multiple operating systems. I assume since you are writing a desktop app in Java, you care about OS portability. Otherwise Java might not be the best choice for a desktop app.
If you use a FileInputStream like that, your path is relative to the current directory of the OS, which usually is the startup directory.
If you instead use the Java built in resources mechanism (as described in the API, getResourceAsStream() et al), the path will be relative to the location of your class. With this approach you can also load resources from within jars and even over networks (for Applets for instance). The concept which is used is a sort of virtual filesystem, which is called the 'classpath' in Java jargon. There is a devx article covering it a litte more in detail.
In short, this sort of code works well:
Properties prop = new Properties();
//with properties in the same dir as current class
prop.load(getClass().getResourceAsStream("my.properties"));
//with properties in the root dir of your jar, or in base of classpath
prop.load(getClass().getResourceAsStream("/my.properties"));
You will need to add error handling...
Typically it will attempt to load from the application's current directory, which can vary depending on how you run it. You should be able to determine this at runtime by doing:
String currentFolder = System.getProperty("user.dir");
The file path it would be looking for in that case is relative to where you started your java application from. This is not where the main class is or the jar file but where you called Java from. If you are starting your application with a script that calls Java, then it is that directory.
Say for example, you application is bundled in a jar file 'app.jar'. Put 'myProps.properties' in the same directory and run 'java -jar app.jar' from that directory. It should find your properties file that way.
You can use Properties with a ResourceBundle. I use this in a application to store labels, buttons and messages in different languages
First you create a properties file, like test.properties. It´s a text file and inside it you put your information like this:
propertyname=value
In your case
emailAddress=me#example.com
email2=blablabla#example.com
and so on...
To get this properties in the code, create a ResourceBundle object with the name of your property file to call the properties.
ResourceBundle rb = ResourceBundle.getBundle("test");
To get an specific value from a properties file, just call the ResourceBundle
String value = rb.getString("emailAddress");
This way, the String named value contains the value of the property named "emailAddress", located in the test.properties file
String value2 = rb.getString("email2");
Likewise, the String named value2 contains the value of the property named "email2", located in the test.properties file
When you do not specify an absolute path, the one chosen is the current one.
It's not exactly what you asked, but if you want to use XML files as configuration, you could have a look at Apache Commons Configuration

Categories

Resources