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.
Related
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 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.
I'm using JarFile and JarURLConnection to load files out of a jar file. I'm then taking the classes, and loading them via BCEL (ByteCode Engineering Library, apache library). I cant just directly use a class loader because im modifying some classes slightly with the BCEL. I need to load the classes by their bytes into my bcel loader. However, one of the classes I'm loading references a resource. This resource is inside of the jar, so I can get the file (When iterating over the entries in the JarFile, I ignore the regular files, and take the class files for loading later). But just having the file won't do me any good, as the class loads it as a resource. Is there any way I can take that resource from the jar (well I can take it and load it into a byte[], the next part is the issue) and dynamically add it as a resource for my program, so that the classes that I load wont be missing their resources?
Got a lot of stuff here, if anythings confusing, ask in comments, I might've said something wrong, or missed something altogether :) Thanks
I'll show a little of my class loader here (extends ClassLoader):
#Override
public URL getResource(String name) {
System.out.println("LOADING RESOURCE: " + name);
try {
return new URL(null, name, new Handler(files));
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
Now, it is printing out "LOADING RESOURCE: filename", but its then giving me a MalformedURLException (I have no protocol atm, just a file path, that's not a true valid path, but it's just an attempt to give it to my Handler class below).
class Handler extends URLStreamHandler {
#Override
protected URLConnection openConnection(URL u) throws IOException {
return new URLConnection(u) {
#Override
public void connect() throws IOException {
}
#Override
public InputStream getInputStream() throws IOException {
System.out.println("IS: " + url);
return /*method to get input steam*/;
}
};
}
}
The /*method to get input steam*/ is set in my real code, but that's not relevant here. So any further ideas with this?
I am developing an Eclipse plug-in that fits a client-server model. Its a commercial project so we cannot re-distribute the JDBC drivers for the various databases we support with the plug-in.
So I developed a preference page to allow the user locate the jars and have a simple discovery mechanism that iterates through the classes in the jar files, loading each one to verify that it implements the java.sql.Driver interface. This all works great.
But the catch is that I am using Hibernate. And Hibernate uses Class.forName() to instantiate the JDBC driver.
If I try to use the following I get ClassNotFoundException.
public Object execute(final IRepositoryCallback callback)
{
final DatabaseDriverClassLoader loader = new DatabaseDriverClassLoader(
Activator.getDefault().getDatabaseDriverRegistry());
final ClassLoader oldLoader = Thread.currentThread()
.getContextClassLoader();
try
{
Thread.currentThread().setContextClassLoader(loader);
try
{
final SessionFactory sessionFactory = this.configuration
.buildSessionFactory();
if (sessionFactory != null)
{
final Session session = sessionFactory
.openSession();
if (session != null)
{
// CHECKSTYLE:OFF
try
// CHECKSTYLE:ON
{
return callback.doExecute(session);
}
finally
{
session.close();
}
}
}
connection.close();
}
finally
{
}
}
// CHECKSTYLE:OFF
catch (Exception e)
// CHECKSTYLE:ON
{
RepositoryTemplate.LOG.error(e.getMessage(), e);
}
finally
{
Thread.currentThread().setContextClassLoader(oldLoader);
}
return null;
}
And if I try creating the driver myself as follows I get a SecurityException.
public Object execute(final IRepositoryCallback callback)
{
final DatabaseDriverClassLoader loader = new DatabaseDriverClassLoader(
Activator.getDefault().getDatabaseDriverRegistry());
final ClassLoader oldLoader = Thread.currentThread()
.getContextClassLoader();
try
{
Thread.currentThread().setContextClassLoader(loader);
final Class driverClass = loader.loadClass(this.connectionDriverClassName);
final Driver driver = (Driver)driverClass.newInstance();
DriverManager.registerDriver(driver);
try
{
final Connection connection = DriverManager.getConnection(
this.connectionUrl, this.connectionUsername,
this.connectionPassword);
final SessionFactory sessionFactory = this.configuration
.buildSessionFactory();
if (sessionFactory != null)
{
final Session session = sessionFactory
.openSession(connection);
if (session != null)
{
// CHECKSTYLE:OFF
try
// CHECKSTYLE:ON
{
return callback.doExecute(session);
}
finally
{
session.close();
}
}
}
connection.close();
}
finally
{
DriverManager.deregisterDriver(driver);
}
}
// CHECKSTYLE:OFF
catch (Exception e)
// CHECKSTYLE:ON
{
RepositoryTemplate.LOG.error(e.getMessage(), e);
}
finally
{
Thread.currentThread().setContextClassLoader(oldLoader);
}
return null;
}
EDIT: I am not sure it is the best option but I took the approach of implementing my own ConnectionProvider which allowed me instantiate the driver using Class.forName() and I then open the connection using Driver.connect() instead of DriverManager.getConnection(). Its pretty basic but I don't need connection pooling in my specific use case.
The configure() method was as follows:
public void configure(final Properties props)
{
this.url = props.getProperty(Environment.URL);
this.connectionProperties = ConnectionProviderFactory
.getConnectionProperties(props);
final DatabaseDriverClassLoader classLoader = new DatabaseDriverClassLoader(
Activator.getDefault().getDatabaseDriverRegistry());
final String driverClassName = props.getProperty(Environment.DRIVER);
try
{
final Class driverClass = Class.forName(driverClassName, true,
classLoader);
this.driver = (Driver)driverClass.newInstance();
}
catch (ClassNotFoundException e)
{
throw new HibernateException(e);
}
catch (IllegalAccessException e)
{
throw new HibernateException(e);
}
catch (InstantiationException e)
{
throw new HibernateException(e);
}
}
And the getConnection() method is as follows:
public Connection getConnection()
throws SQLException
{
return this.driver.connect(this.url, this.connectionProperties);
}
Class.forName() in OSGi is a major pain. This is not really anyone's fault, just that both use class loaders which do not work the way the other's client is expecting (i.e. OSGi class loader doesn't work in the way that hibernate is expecting).
I think you can go one of a few ways, but the ones I can think of right now are:
the clean way, which is to package the JDBC drivers as OSGi bundles. Contribute the class as a service. You can do this with declarative services (probably better) or write an activator which you'll need to manage starting. When you're ready to get the driver, get the JDBCDriver service, and look for the class that you're interested in.
the less clean way, but will work for less effort than the first - use DynamicImport-Package to add the exported packages from your bundled drivers. This way, the client code can still see the class that it'll use, but it doesn't have to know about it until runtime. You may have to experiment with the package pattern, however, to cover all cases (that's why it's less clean).
the less OSGi way; which is to add your drivers to the eclipse classpath, and add the application parent classloader. You can add this: osgi.parentClassloader=app to your config.ini. This may not fit in with your deployment, especially if you haven't got control of the config.ini file.
the non-OSGi way, instead of using the context class loader, use the URLClassLoader. This will only work if you have a directory full of driver jars, or the user can directly or indirectly specify the location of the driver jar.