Avoiding hardcoding of Property File path specification - java

I'm having a small problem decoupling the path specification for properties files that my JAVA program uses , from the implementation itself.
The program may be deployed at multiple locations with different directory structures and I don't want the path specification to be hard coded into the Program code.
Here is the situation as it exists now.
I have one folder server/
Inside which there are 2 packages core/ & support/ (both of which have many subpackages underneath)
What I had done earlier was that , wherever the path for a properties file needed to be specified , I just gave a relative path i.e. properties/
In this scenario, the properties file needs to be wherever you're launching the program from. This worked during testing , when i was manually starting the program up using
"java ". and i would put the properties folder wherever I was starting the program from.
But in a real scenario, this program will be autostarted by a script (ksh) which is executed at scheduled intervals by a job.
In this case , giving the relative path doesn't work. I tried putting the properties files in the folder where the scripts are located , but that doesn't work either.
Right now , I am having to manually specify the path for each environment recompile the code and deploy a separate copy for each environment.
Is there any way to remove this coupling and just have one location for the properties file regardless of where it needs to be deployed?

use a System.Properties entry to specify the path, then on command line add it via
java -DmyProp=somepath -cp yourclasspath YourClass
In your app, you can retrieve it with System.getProperty("myProp"), just be sure to add proper testing and handle the Property Not Found scenario.
Another practice is to leave props in a jar and then load 'em with the LoadResource, in this way you just need to deploy different config jars in each deployment, but I think that the System.setProperty way is the fastest.

Generally some clients may not prefer to use -D= while starting your application. In fact you should also provide a .sh/.bat script file along with your jar file so that client can just double click on the script to run your application.
In this script you can have variable declared which you can ask the client to be configure accordingly. Client can just open the script file in text editor and type in the path of the configuration file.
Other way to use this script file would be to do following :
1) Check if YOUR_APP_NAME_CONFIG variable is set in system environment. If yes then go to step 3 or got to step 2
2) Ask the user on command line for the location of configuration file. Check if the location is correct. If correct then set the environment variable YOUR_APP_NAME_CONFIG with value of location of configuration file.
3)Start your application
Having a script file for your application gives you lots of liberty to do many stuff around automating the environment configuration for your application.
In your application get the config file path by System.getProperty("YOUR_APP_NAME_CONFIG").
This all may look like lot of pain but think from client perspective. Its cake walk for client that he just double click a script to start your application and for the first launch of application the script asks for some inputs if needed and then your application is good to go :)

What I did was pass another classpath parameter with the jar invocation..
java -cp classpath1;folder-where-propertiesfile-located Application.jar
and in the application use getClass().getClassLoader().getResourcesAsStream("properties-file");
This will automatically fetch the properties file form the appropriate classpath folder..
With this setup, I could change the properties file inside the folder and use the same jar file without re-archiving the jar..

Related

Data driven framework jar export

I have created a data driven framework in Selenium by using Java, Eclipse and an Excel file. I have exported the runnable jar file which executes perfectly in my system but it is not executing on others due to path problems. I wanted to know whether there is any specific way to use a data driven jar file in different systems by solving it's path problems? Or, do I have to do all installations and ensure all related resources are in the system on which I want to execute?
Use user.dir key for get project location using java.
Code:
System.out.println("Present Project Directory : "+ System.getProperty("user.dir"));
Use System.getProperty("user.dir") which require path and append the folder as per required in your project folder.
This is how you dynamically add the path. what ever the system it is. it will take the path of project directory dynamically
Hope it will help you :)

Jenkins & Java : How to specify input file location

I have a java project which compares data in two excel files and displays the output. IN my eclipse project i created a folder data and in the code I wrote code read from root/data and it works fine as well. But my manager asked me to move this job to Jenkins. So my question is how do i specify the input folder path in Jenkins , Should it be the same server where Jenkins is installed or Jenkins can read data from another location in another server ?
By default, Jenkins will work on the Job's workspace location, if you provide a path in the job (be it via Parameter or Env. variable etc), it will be relative to that location.
However, you can specify an absolute path for anywhere on the Jenkins Server, which will also work.
If you wish to read data from another server, you will need to make it available to the job's runtime/access level.
One example would be to put this file on IIS or Network Share or other form of sharing, and download it during your chef job into the workspace.
Powershell example for downloading a file from IIS site:
$source = "http://my-web-server-ip/download/mycsvfile.csv"
$destination = "c:\my-jenkins-job-workspace\mycsvfile.csv"
Invoke-WebRequest $source -OutFile $destination
Please consider the above is just a basic implementation of this, and this can be accomplish in a number of ways - which some may be better than others.

How to read a local properties file from an executable jar?

I developed and tested my program on Eclipse Indigo. No problem finding the properties file when run.
I created a runnable jar using Eclipse export.
The program cannot find the properties file when the program is run from the jar.
The properties file is not in the jar, it is in a subdirectory of the directory where the jar is deployed.
As noted above, this directory is on the classpath in the Eclipse run configuration.
C:/myApp/myApp.jar C:/myApp/properties/myApp.properties
props.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("myApp.properties"));
Do I just need to edit the Jar manifest to put the config directory on the classpath?
properties.load(this.getClass().getResourceAsStream(configFileSrc));
This should work.
In my case, configFileSrc = "/apiconfig/appconfig.properties"
I had to add staticresources dir in the build path.
Thanks
Yes. Make sure you specify the path of the config directory relative to the directory where the jar is located. Since you said above that the config directory is a sub directory of the jar location, this will probably just be
<configDir>
where <configDir> is your configuration directory name.
You will also need to use an absolute resource name for the lookup, by adding a slash to the properties file name:
props.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("/myApp.properties"));
This is because the relative name your specify will have the package path of the class appended to it, which you don't want.
Is there any specific reason you need to use the contextClassLoader? A simpler invocation would be to use the classLoader of the class containing the lookup. And, since the class can delegate to it's classLoader, you can simply say:
props.load(getClass().getResourceAsStream("/myApp.properties"));
Finally - have you considered putting the properties file in the jar itself? If it's not going to change at all, this would be a better option. You wouldn't need to specify the classPath in that case. Note that if you want, you could put it in a sub-directory in the jar , but you would have to change the resource path you looked for, and again use an absolute resource name
Here is some info on absolute and relative resource names:
http://docs.oracle.com/javase/1.5.0/docs/guide/lang/resources.html
Hope this helps!
The real problem here is that you need to make up your mind where your application is going to load the properties from when the application is deployed.
(How it works in Eclipse is kind of irrelevant ... unless you expect your users to install Eclipse to run your app!)
If you want it to load the properties from the JAR file, they need to be in the JAR file.
If you want it to load the properties from the file system, they need to be in the file system. That means you have two subsidiary issues:
Where in the file system will your application look? Bear in mind that this has to work for all of the OS platforms you support, and that different OSes have different conventions for where "configuration settings* should be stored.
Is there a default version of the properties file, and how will you install it?
If you want to load it from the CLASSPATH and not the JAR file, that means you cannot make your application an executable JAR. (Running as java -jar ... will ignore all attempts to set an external classpath.)
If you opt for a non-executable JAR file AND loading the properties from the classpath, you have more problems:
How do you set the classpath?
How do you install the properties file "alongside" the JAR file?
Are there security concerns with a (potentially) user writable directory on the application's classpath?
This is probably the worst option.
Once you have decided how (from where) your application needs to load its properties when deployed, the code for implementing your scheme is relatively straightforward. (Modulo the problems mentioned above.)
You could even combine a couple of options; e.g. look for the properties file in the file system and then fall back to a "default" properties file in the JAR file. Or you could make the file system location of the properties file a command line option or supply it via an environment variable or via -D and the system properties.

Dependency issues in deploying using Java Webstart

I am working on a project in Java which has a directory structure something like this:
MainFolder
/ | \
Folder1 Folder2 Folder3...
|
Program.jar|Run.sh
In Folder1 I have main jar file along with the shell script to run the program.
In Folder2 I'm having configuration files in xml which may later be modified by the program
and In Folder3 I'm having jar files that the main program depends on.
Now I want to deploy this program using Java web-start.My current understanding is that web start allows us to deploy programs using 1 or more jar files.My problem is that I need the directory structure also.Can anyone suggest a solution for this.
As mentioned by others, the shell script raises problems. What does it do specifically to 'run the program'?
For the configuration files - 'Folder 2', webstart provides the PersistenceService. I have a small demo. (1)
As far as the Jars in 'Folder 3' go. Move them, as well as the Jar's in folders 2 & 1 to a single directory named 'lib'. The main Jar and the configuration files will be required eagerly, which is the default for JWS. If any of the other Jars (ex. '3') might not be needed immediately or at all, they should be deployed as download='lazy'.
To access the local file system - for reading input supplied by the user or writing a new file they created - a JWS app. normally needs to be digitally signed and trusted. But JWS also provides the much more limited form of access through the FileContents object. For more details, see the demo. of the File Service in the page linked below. (1)
1) Demos of the JNLP API, including the PersistenceService & FileContents object.
I think you will have to make some changes to the structure for webstart deployment (possibly package it as a jar or set of jars), also the launching will be done via JNLP, by webstart and not Run.sh.
Additionally you will have to sign your deployment if you need permissions to write to the disk.
See the FAQ for webstart here
Also check out the developer guide on how to deploy using webstart
Java WebStart does not provide any help in making the filsystem as you need it - it only provides the program components for memory.
If you need this structure, you will need to maintain it yourself (and then, where?)
If the only thing you need is a shell script to run, you can keep the contents of that file as a resource inside your jar, create a temporary file at each run, put the desired contents inside, and execute it, and then delete the temporary file when you are done. Note that this brings you into the wonderful world of code signing which is rather tedious.

How do you get file path for file when user directory changes?

I have a java app, and the log4j.properties file is in src/com/my/path/props. On compile, it's copied into classes/com/my/path/props
The file is loaded via PropertyConfigurator.configureAndWatch(user.dir + "/classes/com/my/path/props/log4j.properties").
This all works fine normally, though it's not ideal because of using user.dir (but I do not know another way to reference a file relative to the "application's start directory"). The problem manifests when trying to run this application using an NT Service wrapper. When done this way, the user.dir changes from the application's root dir to wherever the NTService wrapper's exe file is.
My question is: What's the appropriate way to get a the String file path representation of the log4j.properties file in my classes/com/my/path/props/ directory? I realize this would completely break down if the props file were in a jar; but in this case, it's not and is simply a file on the file system.
I've tried new File(this.getClass().getClassLoader().getResource("com/my/path/props/log4j.properties").getURI()).getAbsolutePath(), but that fails because on production, the path to the file is actually a UNC path and consequently throws a "URI has an authority component" exception.
How do other people deal with this problem?
Thanks.
OK. So... you asked how other people deal with this problem. First, they do not leave it up to Eclipse for where files get placed. They choose where they want them, how they want to access them, and then have their build tool (which unless they are just playing around, should not be an IDE like Eclipse, but rather a dedicated build tool like Maven or Ant) where to place it.
The choice of where you want the file depends on what you want to do with it. If its simply a config file that will never be edited at runtime, you typically place it inside your JAR (which is another practice - applications are placed in one or more JARs, WARs, or EARs, not a classes directory). If the file is to be edited at runtime, which from your "watching" it appears to be the case, you typically put it in a config directory outside your JAR.
How you access it (from the filepath or the classpath) is another choice. Where possible, I favor accessing files from the classpath because it is more portable - and when in a JAR, pretty much required. If that doesn't make sense in your case, then choose a path other than "user.dir" if that is changing when you deploy. You can hard-code it, use an environment variable, a property, a config file, a command line argument, etc. to set the actual path.
Always choose where things go and how you access them. Don't let your tools choose for you. It will make your life easier :-)
I took singleshot's advice and kept the properties files out of src and instead in a separate directory which I added to the classpath. In retrospect, this was indeed boneheaded to have configured it the way I did originally.
From there, my problem was getting a File from a URL. I ended up finding what I needed in Commons IO FileUtils, with its toFile(URL) method.
The code ended up looking like this:
private URL maintenanceConfigPath = this.getClass().getClassLoader().getResource("MaintenanceConfig.properties");
....
File f = FileUtils.toFile(maintenanceConfigPath);
....
Again, thanks to all for your feedback and for pointing me down a path that got me towards an answer

Categories

Resources