I have several different projects and all of them currently hardcode server names, DB user and passwords.
I have found all of the places that need to be changed in order to point to a new server, but there are at least 50 instances where the same change is required, which looks like terrible design.
I would like to change this so that this information is centralized so no one else would have to go hunting for this again. I have read about setting environment variables, but preferably I would like to include the information with the projects themselves such as reading from some sort of configuration file.
How should I approach this?
How about properties file? You can use it like this as suggested here :
public class App {
public static void main( String[] args )
{
Properties prop = new Properties();
try {
//load a properties file
prop.load(new FileInputStream("config.properties"));
//get the property value and print it out
System.out.println(prop.getProperty("database"));
System.out.println(prop.getProperty("dbuser"));
System.out.println(prop.getProperty("dbpassword"));
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
Related
I have a java program where I wrote a scheduler, or a timer where once it starts running. It will call the function every N minutes interval indefinitely. For now, I set N to 5 minutes.
I want to sent out this program in a form of jar file along with some sort of properties file where the tester or anyone else can configure N; so it's much more convenient and I do not have to change in the code itself.
This is an example:
public void schedule() throws Exception {
Timer t=new Timer();
t.scheduleAtFixedRate(
new TimerTask() {
#Override
public void run() {
// System.out.println("HELEOELE");
try {
test.index();
} catch (Exception e) {
e.printStackTrace();
}
}
},
0,
300000);
}
In this case, N = 300000.
I am not too familiar with jar file but I do have a properties file with db connection created.
This is how I called the properties:
Properties props=new Properties();
InputStream in = getClass().getResourceAsStream("/config.properties");
props.load(in);
in.close();
int value=Integer.parseInt(props.getProperty("value"));
So I would appreciate is there any way to do this?
You can read the properties file from the classpath in case it is present in your jar only.
Refer this:
Load properties file in JAR?
But, if you wan't to store the properties file out of the jar and be able to make changes in it, then there are multiple options :
store it on the file system at a specified location from where your code reads it.
instead of a properties file, you can also have a system property defined, which stores the required value. But, you would have to restart your container every time you change the value.
you could also consider reading this value directly from the database (optionally loading it into an in-memory cache). But, here, another API would needed to make changes in the database.
Store it outside the jar. Refer the following link
Read properties file outside JAR file
My application is a batch process that pulls environment variables from an application.properties file. The password that I use must be updated every few months. I would like to automate the password update process and save the updated password in the properties file so it can be used in future runs, but any updates I try to make are not propagated to the application.config file.
When I run in Intellij, there are no errors, but the file is not updated. When I run the application as a jar, it gives:
java.io.FileNotFoundException: file:{localpath}\application.jar!\BOOT-INF\classes!\application.properties (The filename, directory name, or volume label syntax is incorrect)
How do I dynamically update the application.properties file within the jar or do I need to create a new properties file outside of the jar when the application first runs??
EXAMPLE CODE SNIPPETS BELOW:
properties.config:
username=user
password=password123
Application.java:
//get properties
prop = new Properties();
InputStream input = null;
try {
input = new FileInputStream(f);
// load a properties file
prop.load(input);
} catch (IOException ex) {
logger.error("Error reading application.properties", ex);
ex.printStackTrace();
} finally {
if (input != null) {
try {
input.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//update properties
prop.setProperty("TESTSTRING", "testvalue");
//write to properties file
OutputStream os = null;
try{
File f = new File(Application.class.getClassLoader().getResource("application.properties").getFile());
os = new FileOutputStream(f);
prop.store(os, comments);
}catch(IOException ex){
logger.error("Error updating application.properties", ex);
ex.printStackTrace();
} finally {
if(os != null){
try{
os.close();
} catch (IOException e){
e.printStackTrace();
}
}
Properties of an application that may change according to the running environment should never be packaged inside the packaged component.
It should be not hard coupled to the component and it should also be modifiable if required without modifying the packaged component.
Besides, properties may contain confidential information (as in your case : username and password).
So it should be preferably stored directly on the target environment.
For example, one of the cloud native application principles from Heroku/twelve factors (that are also good practices in general) is "storing the configuration in the environment".
So updating the properties file inside the packaged component has to be absolutely avoided for the same reasons.
Besides doing it makes the state application more hard to reproduce if an errors occurs.
In your case, simply fill username and password properties in a specific properties file according to the target environment and store this file on the environment.
Then you have just to run the application by specifying this properties file.
For example for windows :
java -jar yourApp-1.0.jar --spring.config.location=file:///D:/application-target-env.properties
Here is the reference documentation about it :
24.2 Accessing command line properties
I have a real quick question. I have a Java program in which I use a properties file. The file is used for keeping track of the program's users. My problem is I cannot figure out how to ADD to the file. I know how to set existing properties to a value, but I don't know how to add more properties without over writing the other ones.
I would like the program to 'register' users, so to speak. Whenever a new users 'signs up', I want the program to add a new property containing the new user's information. I run into this problem though:
Example:
File: numOfUsers=0
One user registers. The username is 'c00lGuy'. The program registers this in the file:
File: numOfUsers=1 user1-username=c00lGuy
Another user registers. She decides to call her username 'theGr8Girl'. The program registers this:
File: numOfUsers=2 user2-username=theGr8Girl
The file after the two users registered:
File: numOfUsers=2 user2-username=theGr8Girl
How do I prevent my program from overwriting existing lines in the file? It seems to erase the file's contents, and then add what I tell it to. I don't want it to erase the file's contents.
The code I am using to register the properties:
Properties prop = new Properties();
OutputStream output = null;
int userCount = getUserCount();
userCount++;
try {
output = new FileOutputStream(fileName);
// set the properties value
prop.setProperty("numOfUsers", String.valueOf(userCount));
prop.setProperty("user" + userCount + "-username", username);
// save properties to project root folder
prop.store(output, null);
} catch (IOException io) {
io.printStackTrace();
} finally {
if (output != null)
try {
output.close();
} catch (IOException e) {
e.printStackTrace();
}
}
Try something like this:
FileOutputStream out = new FileOutputStream(fileName);
props.setProperty("numOfUsers", 2);
...
props.store(out, null);
out.close();
Properties files aren't really intended for this sort of usage, but if you have a small enough data set it'll work.
The step you are missing is that you need to read the properties from disk, make the changes, then save them back to disk.
Properties props = new Properties();
try{
props.load(inputStream);
} finally {
inputStream.close();
}
props.setProperty(....);
try{
props.store(outputStream);
} finally {
outputStream.close();
}
Just bear in mind that this is not at all suitable for any sort of volume processing. Also, there is a race condition if you have two threads trying to make changes to the properties file at the same time.
If you are looking for a lightweight persistent store, I highly recommend mapdb.
You code is creating a new Properties object each time. Make sure to reuse the old instance when adding a user.
The typical format for a line in this file would be
user=hashedPassword
so use the username as the key and the password as a value. The number of users does not need to be stored, it is just the size of the properties map.
I want to take place database.properties outside the project, so when I want to change the content (database configuration) of that when I've build them into jar, I can do it easily without open my project again. So what to do?
First, place the database.properties file in the location you'd like it to be in.
Then, do one of the following:
Add the directory where database.properties is located, to the classpath. Then use Thread.currentThread().getContextClassLoader().getResource() to get a URL to the file, or getResourceAsStream() to get an input stream for the file.
If you don't mind your Java application knowing the exact location of the database.properties file, you can use simple File I/O to obtain a reference to the file (use new File(filename)).
Usually, you'd want to stick with the first option. Place the file anywhere, and add the directory to the classpath. That way, your Java application doesn't have to be aware of the exact location of the file - it will find it as long as the file's directory is added to the runtime classpath.
Example (for the first approach):
public static void main(String []args) throws Exception {
InputStream stream = Thread.currentThread().getContextClassLoader().getResourceAsStream("database.properties");
Properties props = new Properties();
try {
// Read the properties.
props.load(stream);
} finally {
// Don't forget to close the stream, whatever happens.
stream.close();
}
// When reaching this point, 'props' has your database properties.
}
Store properties file in your preferred location. Then do the following:
try {
String myPropertiesFilePath = "D:\\configuration.properties"; // path to your properties file
File myPropFile = new File(myPropertiesFilePath); // open the file
Properties theConfiguration = new Properties();
theConfiguration.load(new FileInputStream(myPropFile)); // load the properties
catch (Exception e) {
}
Now you can easily get properties as String from the file:
String datasourceContext = theConfiguration.getString("demo.datasource.context", "jdbc/demo-DS"); // second one is the default value, in case there is no property defined in the file
Your configuration.properties file might look something like this:
demo.datasource.context=jdbc/demo-DS
demo.datasource.password=123
I am aware of two ways to read a .properties file:
1- System.getProperties.load(Inputstream for .properties file);
2- Creating a new Properties object and then calling load(Inputstream for .properties file);
In first approach, are we going to store values of .properties file in the System object. Is it utilizing more resources?
Would like to know which is the best way to do it or apart from above two ways, if there is any other best way, please let me know.
Thanks.
Depends on what the properties file represents. If it represents system properties which needs to override/supply some default system properties, then go for the first approach. But if it represents application-specific properties (which is more often the usual case), then go for the second approach.
IMO, it is a BAD idea to load application properties into the System properties object. If someone puts bogus property values into the file you are loading, this could cause all sorts of obscure failures. For example, setting "java.home" to a bogus value will cause JavaMail to fail, and setting one of the "*.separator" properties could cause all sorts of things to behave strangely.
If your application really needs to "overlay" the system properties, then it would be better to do this:
Properties props = new Properties(System.getProperties());
props.load(someInputStream);
If it doesn't, then just load the Properties as follows:
Properties props = new Properties();
props.load(someInputStream);
If for some reason you need to override values in the System Properties object itself, then you should do it much more carefully / selectively.
we will read properties files using the URl...
Properties props = new Properties();
try
{
java.net.URL url = Thread.currentThread().getContextClassLoader().getResource(fileName);
java.net.URL url2 = ClassLoader.getSystemResource(fileName);
props.load(url.openStream());
}
catch (FileNotFoundException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
return props;