I am trying to read and write a properties file with all my server and database connections in my JSF web application project in eclipse. Am using log4j to write to console. My config.properties file is:
dbserver=localhost
dbname=mydatabase;instance=myinstance
dbuser=myuser
dbpassword=mypassword
I placed my config.properties file in webapp/WEB-INF/classes folder (this is the classpath right?). I have verified that it is reading the file correctly in this specific location because if I delete the file, it breaks.
In my managed bean, I have functions to read and write to the config.properties file.
public void getSettings() {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
InputStream input = classLoader.getResourceAsStream("config.properties");
Properties properties = new Properties();
try {
properties.load(input);
this.server = properties.getProperty("dbserver");
this.db = properties.getProperty("dbname");
this.user = properties.getProperty("dbuser");
this.pass = properties.getProperty("dbpassword");
logger.info("Config file successfully loaded!");
} catch (IOException e) {
logger.error("Loading Database Settings Error with " + e);
} finally {
if (input != null) {
try {
input.close();
logger.info("Closing config file...");
} catch (IOException e) {
logger.error("Error closing config file with " + e);
}
}
}
}
public void saveSettings() {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
Properties props = new Properties();
OutputStream out = null;
try {
props.setProperty("dbserver", this.server);
props.setProperty("dbname", this.db);
props.setProperty("dbuser", this.user);
props.setProperty("dbpassword", this.pass);
URL url = classLoader.getResource("config.properties");
File file = null;
try {
file = new File(url.toURI().getPath());
} catch (URISyntaxException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// File f = new File("config.properties");
out = new FileOutputStream(file);
props.store(out, "This is an optional header comment string");
logger.info("Config file successfully saved!");
} catch (IOException io) {
logger.error("Saving configuration properties failed error with : " + io.getMessage());
} finally {
if (out != null) {
try {
logger.info("Closing config file...");
out.close();
} catch (IOException e) {
logger.error("Failed closing configuration properties file error with : " + e);
}
}
}
}
I never had an issue reading from the properties file but had a hard time writing to the file. This issue seemed to have been solved by specifying
URL url = classLoader.getResource("config.properties");
Now, if I change the server name from "localhost" to "192.168.1.1", I can see that the new information persists even though I refresh the page or restart the server. HOWEVER... when I open the config.properties file, I still see
dbserver=localhost
when I am expecting to see
dbserver=192.168.1.1
The information seems to persist somewhere else even though the file still remains the same? How and where can I access the contents of my properties fie to see the changes that are being made to it?
Modifying the WAR file is a bad idea (for example, some web servers may notice the file modification an redeploy your app, there may be problems when the server explodes the war on deployment etc.)
I would suggest applying an alternative approach - some possibilities are:
Place the properties in a database table, so they can be easily modified
Use an external properties file for overriding your "Property.prop" file settings. You can pull this off for example as follows. Assume that the default property values are bundled in your WAR and the modified values are saved to some other path, which is defined using a system property - let say it's called CONFIG_LOCATION. Now after loading your properties from the bundle you read them also from this external "overrides.prop" file - this overrides your defaults from "Property.prop":
PropertiesConfiguration pc1=new PropertiesConfiguration(a);
try(
FileReader propReader = new FileReader(System.getenv().get("CONFIG_FILES") +"/overrides.prop"){ pc1.load(propReader);
}
When you need to save changes, you do that to "overrides.prop" - this will save all the properties, not only the changed ones, but that should have no negative effects.
Related
First of, my sincere apologies for bringing up an oft repeated question in this forum; but I cannot figure out my mistake(s).
I have two .properties files that I am trying to load unsuccessfully. Here's the folder structure I have - unless there is a compelling reason otherwise or it is contrary to the best practice, I like to keep this structure:
As you notice my DAO code is under zencs.dbutils package and my .properties files are respectively under zencs.resources.properties.db* packages.
The reason I do it this way because eventually this will connect to and manage multiple data sources - my DAO code will evolve to handle them dynamically (not yet so). I want to set up all data source properties in one place
My Project properties are set as follows:
Now in my DAO class I have a method initProperties(), called by getConnection(), that is trying to reference these properties files through getResourceAsStream(). Please see below code that I tried:
public class DAO {
Connection conn = null;
public Properties properties = new Properties();
public Properties dbConnect = new Properties();
private void initProperties() {
InputStream inputDBdrivers = getClass().getResourceAsStream("snowflakeConnect.properties");
if (inputDBdrivers != null) {
try{
dbConnect.load(inputDBdrivers);
inputDBdrivers.close();
} catch(IOException ioex) {
System.err.println(ioex.getStackTrace().toString());
}
} else {
System.out.println("snowflakeConnect.properties file not found! Terminating Application normally...");
System.exit(0);
}
InputStream inputDBprops = getClass().getResourceAsStream("snowflake.properties");
if (inputDBprops != null) {
try{
properties.load(inputDBprops);
inputDBprops.close();
} catch(IOException ioex) {
System.err.println(ioex.getStackTrace().toString());
}
} else {
System.out.println("snowflake.properties file not found! Terminating Application normally...");
System.exit(0);
}
}
Connection getConnection() throws SQLException {
// build connection properties
initProperties();
try {
Class.forName(dbConnect.getProperty("driver"));
} catch (ClassNotFoundException cnfex) {
System.err.println("ERROR: getConnection() :: Snowflake Class not found: " + cnfex.getMessage());
}
return DriverManager.getConnection(dbConnect.getProperty("connectStr"), properties);
}
public DAO() {
try {
this.conn = getConnection();
} catch (SQLException sqlex) {
Logger.getLogger(DAO.class.getName()).log(Level.SEVERE, null, sqlex);
}
}
}
When I am executing it, the error says "snowflakeConnect.properties file not found! Terminating Application normally..."
My evaluation is that the code in the above form resolving the files to be in zencs/dbutils/ and the ClassLoader cannot find them there obviously.
I tried full absolute path (out of desperation though it expects relative); I tried relative path with "../resources/properties/{dbdrivers | dbutils}/filename.properties" with no success. With the relative path it is resolving to "zencs/dbutils/../resources/properties/dbdrivers/snowflakeConnect.properties" for ClassLoader...
Am I NOT setting the resources folder and everything underneath it correctly?
Obviously my comprehension of how it should resolve is flawed. Can you please help with what I might have not understood and how should I go about this issue?
Thanks a bunch!
You could try to use getResourceAsStream() including your package name like this:
InputStream inputDBdrivers = getClass().getResourceAsStream("/zencs/resources/properties/dbdrivers/snowflakeConnect.properties");
InputStream inputDBprops = getClass().getResourceAsStream("/zencs/resources/properties/dbutils/snowflake.properties");
The leading slash is usually the key part here. It could help to remove that as well but you said you've tried that already so I guess that's not what you're looking for.
I'm using FileSystem to modify a properties file inside a zip file
public boolean processZip()
{
boolean wasModified = false;
Path zipFilePath = Paths.get(this.getZipFileName());
try (FileSystem fs = FileSystems.newFileSystem(zipFilePath, null))
{
Logger.info("Processing zip: #0",
this.getZipFileName());
Path source = fs.getPath(
"/some/path/some.properties");
// Delete old properties file.
Files.delete(source);
this.createPropertiesFile(source);
wasModified = true;
}
catch (NoSuchFileException e)
{
Logger.info("Properties file not found.");
}
catch (Exception e)
{
Logger.error("There was an error updating the properties in zip: " +
this.getZipFileName(),
e);
}
return wasModified;
}
protected void createPropertiesFile(Path dst) throws IOException
{
try (BufferedWriter bw = new BufferedWriter(
new OutputStreamWriter(Files.newOutputStream(dst))))
{
bw.write(this.getProperties().getValues());
}
catch (Exception e)
{
Logger.error("There was an error creating the properties in zip: " +
this.getInputJarFileName(),
e);
}
}
But every now and then it fails on windows with the following stacktrace:
ERROR: There was an error updating the properties in zip: C:\Apps\Test\some.zip
java.nio.file.FileSystemException: C:\Apps\Test\some.zip: The process cannot access the file because it is being used by another process.
at sun.nio.fs.WindowsException.translateToIOException(WindowsException.java:86)
at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:97)
at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:102)
at sun.nio.fs.WindowsFileSystemProvider.implDelete(WindowsFileSystemProvider.java:269)
at sun.nio.fs.AbstractFileSystemProvider.delete(AbstractFileSystemProvider.java:103)
at java.nio.file.Files.delete(Files.java:1126)
at com.sun.nio.zipfs.ZipFileSystem.sync(ZipFileSystem.java:1294)
at com.sun.nio.zipfs.ZipFileSystem.close(ZipFileSystem.java:277)
The thing is, that file gets copied by an earlier process (the process has ended when the zip file is modified). So I don't know what can be using that file in windows. At first I thought maybe the antivirus but it happens even with the antivirus off.
I'm not sure if there is something else that I can do to prevent this. It is not as frequent but every now and then it happens.
It has admin rights, I have tried exploding the zip, modify the file and zip it back. That only made the issue more frequent. I have tried also Apache commons FileUtils.forceDelete(file).
Is there something I'm missing?
Please let me know if this question has been asked before.
The Goal
In my android application when a user launches the App it loads the Login.class first. This class checks to see if a local file (in the included file path of the App) called app_prefs.prop exists (which it does) and then it checks the following fields structured like so:
username=
user_hash=
saved_email=
email_hash=
Those fields are blank by default just like so. I am reading them using the following code:
public static String getConfigValue(Context context, String name) {
Resources resources = context.getResources();
String TAG = "Retrieve";
try {
InputStream rawResource = resources.openRawResource(R.raw.app_prefs);
Properties properties = new Properties();
properties.load(rawResource);
return properties.getProperty(name);
} catch (Resources.NotFoundException e) {
Log.e(TAG, "Unable to find the config file: " + e.getMessage());
} catch (IOException e) {
Log.e(TAG, "Failed to open config file.");
}
return null;
}
If they return empty values, which by default they will, then the login screen is showed. If they do not, the login is attempted by default and if successful it will continue to the App, if not, login is shown again of course.
The Issue
When they sign in, I want to write the data into those fields. Currently its being sent to and from the server using JSON and works awesome. I am able to extract this data as well to a string variable which I am then passing to my save to config file after logging the user in but before continuing to the next App screen. This is where the problem lies, I have enabled the permission
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
I have also passed all the values to it, but they are not being written to the lines I want them too. Here is the code I am using to write the file with:
private void commitUserInfotoFile(Context context, String username, String passhash, String rmemail, String rmemailhash) {
Resources resources = context.getResources();
String TAG = "Store";
try {
InputStream rawResource = resources.openRawResource(R.raw.app_prefs);
Properties properties = new Properties();
properties.load(rawResource);
//tried using setProperty as well as put but neither works
properties.setProperty("username", username);
properties.put("username", username);
properties.setProperty("user_hash", passhash);
properties.setProperty("saved_email", rmemail);
properties.setProperty("email_hash", rmemailhash);
Log.e(TAG, "Wrote the values to the stored file");
} catch (Resources.NotFoundException e) {
Log.e(TAG, "Unable to find the config file: " + e.getMessage());
} catch (IOException e) {
Log.e(TAG, "IO Exception loading file.");
}
}
Yet its not storing those values to the file even tho I get the message Wrote the values to the stored file in my console. I am a little confused as to the writing of properties using this method so any help would be appreciated. Thanks
You never store the result of your edits back into the resource. setProperty() just updates some internal key-value pair in the Properties object, it does not update it's source. You need to call Properties.store(OutputStream, String) when you are done with your edits. See here:
https://developer.android.com/reference/java/util/Properties.html#store(java.io.OutputStream, java.lang.String)
I try to load a property file in Java running on JBossFuse/karaf.
The file is located at $[karaf.home]/etc/bean.properties
The Code is able to load properties inside the bundle fine, but now I try to exclude the properties from the project itself and the code throws a Nullpointer-Exception.
The Path is properly resolved on my development machine as
C:\Users\someone\devstudio\runtimes\jboss-fuse-6.3.0.redhat-135\etc\bean.properties
The property-File can be loaded in the blueprint-XML to configure beans, but to access the bean my code needs the CamelContext. As I have some static codeblocks that are accessed without an exchange/context/registry, I also wanted to be able to load the properties in Java.
Both the functions throw the NullPointerException and I guess, it is because the code runs in Fuse.
public static Properties getProperties(String location) {
Properties prop = new Properties();
InputStream input = null;
try {
input = PropertyLoader.class.getClassLoader().getResourceAsStream(location);
prop.load(input);
} catch (IOException ex) {
log.error("Error loading properties file from: " + location, ex);
return null;
} finally {
if (input != null) {
try {
input.close();
} catch (IOException e) {
log.error(e);
}
}
}
return prop;
}
public static Properties getPropertiesFromFilesystem(String location) {
Properties prop = new Properties();
InputStream input = null;
try {
input = new FileInputStream(location);
prop.load(input);
} catch (IOException ex) {
log.error("Error loading properties file from: " + location, ex);
return null;
} finally {
if (input != null) {
try {
input.close();
} catch (IOException e) {
log.error(e);
}
}
}
return prop;
}
The Exception:
java.lang.NullPointerException
at java.util.Properties$LineReader.readLine(Properties.java:434)[:1.8.0_91]
at java.util.Properties.load0(Properties.java:353)[:1.8.0_91]
at java.util.Properties.load(Properties.java:341)[:1.8.0_91]
at com.mycompany.util.PropertyLoader.getProperties(PropertyLoader.java:19)[319:camel-archetype-blueprint:0.0.14]
at com.mycompany.camel.blueprint.MyProcessor.process(MyProcessor.java:21)[319:camel-archetype-blueprint:0.0.14]
at org.apache.camel.processor.DelegateSyncProcessor.process(DelegateSyncProcessor.java:63)[231:org.apache.camel.camel-core:2.17.0.redhat-630135]
at org.apache.camel.management.InstrumentationProcessor.process(InstrumentationProcessor.java:77)[231:org.apache.camel.camel-core:2.17.0.redhat-630135]
at org.apache.camel.processor.RedeliveryErrorHandler.process(RedeliveryErrorHandler.java:468)[231:org.apache.camel.camel-core:2.17.0.redhat-630135]
at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:196)[231:org.apache.camel.camel-core:2.17.0.redhat-630135]
at org.apache.camel.processor.Pipeline.process(Pipeline.java:121)[231:org.apache.camel.camel-core:2.17.0.redhat-630135]
at org.apache.camel.processor.Pipeline.process(Pipeline.java:83)[231:org.apache.camel.camel-core:2.17.0.redhat-630135]
at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:196)[231:org.apache.camel.camel-core:2.17.0.redhat-630135]
at org.apache.camel.component.timer.TimerConsumer.sendTimerExchange(TimerConsumer.java:192)[231:org.apache.camel.camel-core:2.17.0.redhat-630135]
at org.apache.camel.component.timer.TimerConsumer$1.run(TimerConsumer.java:76)[231:org.apache.camel.camel-core:2.17.0.redhat-630135]
at java.util.TimerThread.mainLoop(Timer.java:555)[:1.8.0_91]
at java.util.TimerThread.run(Timer.java:505)[:1.8.0_91]
Any help would be highly appreciated.
Do not do that. You are looking for trouble.
Load properties the OSGi way (use .cfg as extension and a blueprint property-placeholder bean)
You have the added benefit of getting notified if the file changes (if you wish)
Inject them in a bean EVEN IF you are using only static methods.
Don't mix managed beans with unmanaged static code unless you know very well what you are doing.
If some "static" code requires properties means that it is stateful, and this class deserves to be instantiated to a bean.
Not sure why you are getting an NPE without a more complete example. If you need to use properties without a route, you should be using Camel's property placeholder facilities:
https://access.redhat.com/documentation/en-us/red_hat_jboss_fuse/6.3/html/apache_camel_development_guide/basicprinciples#BasicPrinciples-PropPlaceholders
I am loading properties on an Wildfly application server like this:
public String getPropertyValue(String propertyName) throws IOException {
InputStream inputStream;
Properties properties = new Properties();
inputStream = getClass().getClassLoader().getResourceAsStream(propertyFileName);
if (inputStream != null) {
properties.load(inputStream);
} else {
throw new FileNotFoundException("property file '" + propertyFileName + "' not found in the classpath");
}
inputStream.close();
String property = properties.getProperty(propertyName);
LOG.debug("Property {} with value {} loaded.", propertyName, property);
return property;
}
Now I want to write to that very same file. How do I do that correctly? I tried around with new File(configurationFileName), but that creates a new File in a different directory, and I tried around with URL/URI of file from classloader, but that doesn't seem to work either. What is the correct way to do this?
Thx for help!
You can't and you shouldn't. I would use a database table to store and load properties. Or if it shall be a properties-file, then store it somewhere external via a file path, but not via the class path.
try (FileOutputStream out = new FileOutputStream(new File( getClass().getClassLoader().getResource(propertyName).toURI()))){
properties.store(out,"My Comments);
}
Raoul Duke is actually right, doing the properties via file raises a lot of problems. I will soon switch to DB for keeping those. In the mean time I did this: When I write properties, they are written to a newly created file. When I read properties, I load the "old" ones, and then create a new properties object with the old ones as defaults, in which I then load the new file.
private Properties loadProperties() throws IOException {
InputStream inputStream;
Properties defaultProperties = new Properties();
inputStream = getClass().getClassLoader().getResourceAsStream(defaultPropertyFileName);
if (inputStream != null) {
defaultProperties.load(inputStream);
} else {
throw new FileNotFoundException("Property file '" + defaultPropertyFileName + "' not found in the classpath");
}
inputStream.close();
Properties allProps = new Properties(defaultProperties);
try {
allProps.load(new FileInputStream(new File(updatedPropertyFileName)));
} catch (IOException ex) {
LOG.error("Error loading properties: {}", ex.toString());
return defaultProperties;
}
return allProps;
}
I marked his answer right, since I am technically not writing to the file I wanted to, plus this is only a workaround and his solution is way better and cleaner.