How to have different properties file for different machines? - java

So I am working in a team of people on a small school project, and we're developing java/jsp web app with apache.. I created simple properties.config file so I can store values and use them later and it looks something like this:
home_url = http://localhost:8080/to3/
to3_path = C:/Users/User2/Documents/workspace/TO-3
db_url = jdbc:mysql://localhost:3306/to3?useUnicode=true&characterEncoding=UTF-8
Problem I have is when I commit it and someone do a checkout they have to change values for url-s and paths so it fits their machine.. I heard I can make a custom properties file which will override these default values if it recognizes certain machine, but I don't know how to do it.
Thank you all in advance for your help.

Don't commit project settings. Put them in .gitignore and commit a copy of it (e.g. properties.config.sample). Make sure to keep it up to date with any new keys you add, but each developer should make their own untracked copy.

As Amadan point out you should not commit project properties. My suggestion is to create a file with .properties extension and place your properties inside. To use this file in java you can create a class like that
public class MyProperties{
private String homeUrl = "";
private String to3Path = "";
private String dbPath = "";
private final String configPath = System.getProperty("user.home") + File.separator + "my-props.properties";
public void loadProperties(){
try {
Properties prop = new Properties();
InputStream input = null;
File filePath = new File(configPath);
input = new FileInputStream(filePath);
// load a properties file
prop.load(input);
homeUrl = prop.getProperty("home_url");
to3Path = prop.getPropert("to3_path");
dbPath = prop.getProperty("db_url");
}catch (Exception e) {
e.printStackTrace();
}
}
// getters & setters
}
Then in your app you can do
MyProperties props = new MyProperties();
props.loadProperties();
String homeUrl = props.getHomeUrl();
System.getProperty("user.home") will give home path depending on the OS.
For example in windows this is path is C:\Users\yourName
This way all your co-workers can place their own properties in their personal pc inside their home path and you will be able to work without conflicts.

Related

How to attach file to jar that can be edited inside this jar?

I am making a program that works with MySQL database,for now i store URL, login, password e.t.c as public static String. Now i need to make it possible to work on another computer, so database adress will vary, so i need a way to edit it inside programm and save. I would like to use just external txt file, but i don't know how to point it's location.
I decided to make it using Property file, i put it in src/res folder. It work correct while i'm trying it inside Intellij Idea, but when i build jar (artifact) i get java.io.FileNotFoundException
I tried two ways:
This one was just copied
private String getFile(String fileName) {
StringBuilder result = new StringBuilder("");
//Get file from resources folder
ClassLoader classLoader = getClass().getClassLoader();
File file = new File(classLoader.getResource(fileName).getFile());
System.out.println(file.length());
try (Scanner scanner = new Scanner(file)) {
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
result.append(line).append("\n");
}
scanner.close();
} catch (IOException e) {
e.printStackTrace();
}
return result.toString();
}
System.out.println(obj.getFile("res/cfg.txt"));</code>
And second one using Properties class:
try(FileReader reader = new FileReader("src/res/cfg.txt")) {
Properties properties = new Properties();
properties.load(reader);
System.out.println(properties.get("password"));
}catch (Exception e) {
e.printStackTrace();
System.out.println(e);
}
In both ways i get java.io.FileNotFoundException. What is right way to attach config file like that?
Since the file is inside a .JAR, it can't be accessed via new File(), but you can still read it via the ClassLoader:
Properties properties = new Properties();
try (InputStream stream = getClass().getResourceAsStream("/res/cfg.txt")) {
properties.load(stream);
}
Note that a JAR is read-only. So this approach won't work.
If you want to have editable configuration, you should place your cfg.txt outside the JAR and read it from the filesystem. For example like this:
Properties properties = new Properties();
File appPath = new File(MyClass.class.getProtectionDomain().getCodeSource().getLocation().toURI()).getParentFile();
try (InputStream stream = new FileInputStream(new File(appPath, "cfg.txt"))) {
properties.load(stream);
}
There are multiple places your can place your configuration options, and a robust deployment strategy will utilize some (or all) of the following techniques:
Storing configuration files in a well known location relative to the user's home folder as I mentioned in the comments. This works on Windows (C:\Users\efrisch), Linux (/home/efrisch) and Mac (/Users/efrisch)
File f = new File(System.getProperty("user.home"), "my-settings.txt");
Reading environment variables to control it
File f = new File(System.getenv("DEPLOY_DIR"), "my-settings.txt");
Using a decentralized service such as Apache ZooKeeper to store your database settings
Use Standalone JNDI
(or the JNDI built-in to your deployment target)
Use a Connection Pool

request.getServletContext().getRealPath(); is returning my target directory instead of src?

I am trying to implement a feature on my site that saves files to a project directory. Here is the method that is doing it.
#RequestMapping(value = "/upload", method = RequestMethod.POST)
public String Upload(#RequestParam("file") MultipartFile file, Principal principal, HttpServletRequest request) throws IOException {
if (!file.isEmpty()) {
String uploadsDir = "/uploads/";
String realPathtoUploads = request.getServletContext().getRealPath(uploadsDir);
if(! new File(realPathtoUploads).exists())
{
new File(realPathtoUploads).mkdir();
}
String orgName = file.getOriginalFilename();
String filePath = realPathtoUploads + orgName;
File dest = new File(filePath);
file.transferTo(dest);
return "user";
}
return "user";
}
It is saving the file but it is saving in the target directory. Shouldn't I be saving files to my src directory and not my target? How can I change it so its going to the src direct? Thanks!
I am using netbeans btw if that makes any difference.
All path related methods actually calculate the path based on the folder the container launched your app from. So if you launched your Tomcat or Jetty or another container using probably maven, your application was launched from the target folder which is where maven places the war and all other resources.
Hence, getRealPath actually takes the application location and concatenates the relative "/uploads" to it.
Of course your container behaves as it should.
Your requirement is achievable, however if you choose to manipulate the path yourself than any change to the folder location would force to change it manually.
You could do for example :
String rootPath = "/home/user/";
String downlods = "downloads";
String realPathtoUploads = rootPath + downlods ;
if(! new File(realPathtoUploads).exists()) {
new File(realPathtoUploads).mkdir();
}
HTH,
Gal

How to get jar path in runtime

I want java to look for .properties file in same folder with jar which is running. How can I do it and how can I determine if app is running in IDE or as explicit jar file
you can access this file (if it is in your classpath) via:
Paths.get(this.getClass().getResource("file.properties").toURI());
Firstly I have to say that this is inherently a bad practice, though life often is not perfect and sometimes we have to roll with the bad design punches.
This is the class I mustered up for a pet project of mine that required such functionality:
public class ArbitraryPath {
private static Logger logger = LogManager.getLogger("utility");
private static boolean isRunFromJar = false;
public static String resolveResourceFilePath(String fileName, String folderName, Class<?> requestingClass) throws URISyntaxException{
// ARGUMENT NULL CHECK SAFETY HERE
String fullPath = requestingClass.getResource("").toURI().toString();
isRunFromJar = isRunFromJar(fullPath);
String result = "";
if(!isRunFromJar){
result = trimPathDownToProject(requestingClass.getResource("").toURI());
}
result = result+folderName+"/"+fileName+".properties";
return result;
}
private static String trimPathDownToProject(URI previousPath){
String result = null;
while(!isClassFolderReached(previousPath)){
previousPath = previousPath.resolve("..");
}
previousPath = previousPath.resolve("..");
result = previousPath.getPath();
return result;
}
private static boolean isClassFolderReached(URI currentPath){
String checkableString = currentPath.toString();
checkableString = checkableString.substring(0,checkableString.length()-1);
checkableString = checkableString.substring(checkableString.lastIndexOf("/")+1,checkableString.length());
if(checkableString.equalsIgnoreCase("bin")){
return true;
} else {
return false;
}
}
private static boolean isRunFromJar(String fullPath) throws URISyntaxException{
String solidClassFolder = "/bin/";
String solidJarContainer = ".jar!";
if(!fullPath.contains(solidClassFolder)){
if(fullPath.contains(solidJarContainer)){
return true;
} else {
logger.error("Requesting class is not located within a supported project structure!");
throw new IllegalArgumentException("Requesting class must be within a bin folder!");
}
} else {
return false;
}
}
}
I guess a little explaining is in order...
Overall this will try to resolve a filepath for a properties file located in an arbitrary project. This means that the ArbitraryPath class does not need to be located in the same project as the properties file, this comes in handy when you want to separate for example the JUnit tests in a separate project. It will identify the project based on the class you give it, the class should be in the same project as the properties file you are trying to find.
So first of all it gets the path of the class you gave it in this line:
String fullPath = requestingClass.getResource("").toURI().toString();
Then it checks whether or not this class is within a JAR file or if it is executed from the IDE. This is done by checking whether the path contains "/bin/" which would normally mean that it is executed from an IDE or ".jar!" which would normally mean that it is executed from a JAR. You can modify the method if you have a different project structure.
If it is determined that it is NOT run from JAR then we trim the path down to the project folder, going backwards down the path until we reach the BIN folder. Again, change this if your project structure deviates from the standard.
(If we determine that it IS run from a JAR file then we don't trim anything since we have already got the path to the base folder.)
After that, we have retrieved a path to the project folder so we add the name of the folder (if there is one) where the properties file is located, and add the filename and extension of the properties file which we want to locate.
We then return this path. We can then use this path in an InputStream like such:
FileInputStream in = new FileInputStream(ArbitraryPath.resolveResourceFilePath("myPropertiesFile", "configFolder", UserConfiguration.class));
Which will retrieve the myPropertiesFile.properties in the myConfiguration folder in the project folder where UserConfiguration.class is located.
Please note that this class assumes you have a standard project configuration.
Feel free to adapt it to your needs etc.
Also this is a really hackish and crude way to do this.
String absolutePath = null;
try {
absolutePath = (new File(Utils.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath())).getCanonicalPath();
absolutePath = absolutePath.substring(0, absolutePath.lastIndexOf(File.separator))+File.separator;
} catch (URISyntaxException ex) {
Logger.getLogger(Utils.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(Utils.class.getName()).log(Level.SEVERE, null, ex);
}

Text input and output java

I am trying to read 2 files after i read the files i want to get their contents and manipulate the contents of the two files then update a new file which is the output. The files are in the same folder as the program but the program always throws a FileNotFoundException.
Below is my code:-
import java.io.*;
import java.util.Scanner;
public class UpdateMaster {
public static void main(String[] args)
{
String master = "Customer.dat";
String trans = "Transactns.dat";
String newMaster = "Temp.txt";
Scanner inputStreamMaster = null;
Scanner inputStreamTrans = null;
PrintWriter inputStreamNewMaster = null;
try
{
inputStreamMaster = new Scanner(new File(master));
inputStreamTrans = new Scanner(new File(trans));
inputStreamNewMaster = new PrintWriter(newMaster);
}
catch(FileNotFoundException e)
{
System.out.println("Error: you opend a file that does not exist.");
System.exit(0);
}
catch(IOException e)
{
System.out.println("Error.");
System.exit(0);
}
do
{
String transLine = inputStreamTrans.nextLine();
String masterLine = inputStreamMaster.nextLine();
String[] transLineArr = transLine.split(",");
String[] masterLineArr = masterLine.split(",");
int trAccNo = Integer.parseInt(transLineArr[0]);
int sales = Integer.parseInt(transLineArr[1]);
int masterAccNo = Integer.parseInt(masterLineArr[0]);
int balance = Integer.parseInt(masterLineArr[1]);
while(masterAccNo== trAccNo){
inputStreamNewMaster.println(trAccNo+ " , "+masterAccNo);
masterLine = inputStreamMaster.nextLine();
masterLineArr = masterLine.split(",");
masterAccNo = Integer.parseInt(masterLineArr[0]);
balance = Integer.parseInt(masterLineArr[1]);
}
balance = balance + sales;
inputStreamNewMaster.println(masterAccNo+ " , "+balance);
}while(inputStreamTrans.hasNextLine());
inputStreamMaster.close();
inputStreamTrans.close();
inputStreamNewMaster.close();
//System.out.println(" the line were written to "+ newMaster);
}
}
Like #Ankit Rustagi said in the comments, you need the full path of the files if you want to keep the current implementation.
However, there is a solution where you only need the file names: use BufferedReader / BufferedWriter. See here an example on how to use these classes (in the example it uses the full path but it works without it too).
Use absolute path
String master = "C:/Data/Customer.dat";
String trans = "C:/Data/Transactns.dat";
String newMaster = "C:/Data/Temp.txt";
The code works for me, i guess you misspelled some filename(s) or your files are in the wrong folder. I created your files on the same level as the src or the project. Also this is the folder where the files are exspected.
There's nothing wrong with using relative paths like tihis. What's happening is that your program is looking for the files in the directory where you execute the program, which doesn't have to be the folder of the program. You can confirm this by logging the absolute path of the files before you try to read them. For example:
File masterFile = new File(master);
System.out.printf("Using master file '%s'%n", masterFile.getAbsolutePath());
inputStreamMaster = new Scanner(masterFile);
In general you should not hardcode file paths but allow the user to specify them in someway, for example using command line arguments, a configuration file with a well known path, or an interactive user interface.
There is a way to locate the program's class file but it's a little tricky because Java allows classes to be loaded from compressed archives that may be located in remote systems. It's better to solve this problem in some other manner.
Try this:
String current = new java.io.File( "." ).getCanonicalPath();
System.out.println("I look for files in:"+current);
To see what directory your program expects to find its input files. If it shows the correct directory, check spelling of filenames. Otherwise, you have a clue as to what's gone wrong.

How to load files on multiple platforms properly using Java? [duplicate]

This question already has answers here:
Platform independent paths in Java
(8 answers)
Closed 3 years ago.
I have a java swing database application which needs to be run on Windows and Linux. My database connection details are stored in a XML file and I load them.
This application can load this properties on Linux properly but it is not working on Windows.
How do I load files on multiple platforms properly using Java?
This is the code:
PropertyHandler propertyWriter = new PropertyHandler();
List keys = new ArrayList();
keys.add("ip");
keys.add("database");
Map localProps = propertyWriter.read(keys, "conf" + File.separatorChar + "properties.xml", true);//if false load from the local properties
//get properties from the xml in the internal package
List seKeys = new ArrayList();
seKeys.add("driver");
seKeys.add("username");
seKeys.add("password");
Map seProps = propertyWriter.read(seKeys, "conf" + File.separatorChar + "properties.xml", true);
String dsn = "jdbc:mysql://" + (String) localProps.get("ip") + ":3306/" + (String) localProps.get("database");
jDBCConnectionPool = new JDBCConnectionPool((String) seProps.get("driver"), dsn, (String) seProps.get("username"), (String) seProps.get("password"));
File reader method:
public Map read(List properties, String path, boolean isConfFromClassPath)
{
Properties prop = new Properties();
Map props = new HashMap();
try {
if (isConfFromClassPath) {
InputStream in = this.getClass().getClassLoader().getResourceAsStream(path);
prop.loadFromXML(in);
for (Iterator i = properties.iterator(); i.hasNext();) {
String key = (String) i.next();
props.put(key, prop.getProperty(key));
}
in.close();
} else {
FileInputStream in = new FileInputStream(path);
prop.loadFromXML(in);
for (Iterator i = properties.iterator(); i.hasNext();) {
String key = (String) i.next();
props.put(key, prop.getProperty(key));
}
in.close();
}
} catch (Exception ex) {
ex.printStackTrace();
}
return props;
}
If the file is in a jar file and accessed by the classpath then you should always use /.
The JavaDocs for the ClassLoader.getResource say that "The name of a resource is a '/'-separated path name that identifies the resource."
http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/ClassLoader.html#getResource(java.lang.String)
I'm not sure if there is the proper way, but one way is:
File confDir = new File("conf");
File propFile = new File(confDir, "properties.xml");
But in a scenario as simple as yours, I would just use /
If it's a resource located in classpath, we can load it with following snippet:
getClass().getClassLoader().getResourceAsStream(
"/META-INF/SqlQueryFile.sql")));
You can load all files on multiple platforms without any trouble.
Kindly use Matcher.quoteReplacement(File.separator) for replacing the slash.
It will works for every platform.
String fileLocation = "/src/service/files";
fileLocation = fileLocation.replaceAll("/",Matcher.quoteReplacement(File.separator));
assuming that your file is in conf/properties.xml on Linux and conf\properties.xml on Windows,
use File.pathSeparator instead of File.separator

Categories

Resources