I've written a class that loads external properties for use in my program, it is modeled off of this link: Load Properties File in Singleton Class. I've read here (FileNotFoundException with properties file) and here (Java Properties File not loading) of how to load an external property file, however I continue to get a FileNotFoundException. My properties file is external and is located in the same directory as my executable jar.
public class ExternalProperties extends Properties{
private static ExternalProperties instance = null;
private Properties properties;
private static String location;
protected ExternalProperties() throws IOException {
properties = new Properties();
properties.load(getClass().getResourceAsStream("test.properties"));
}
public static ExternalProperties getInstance(){
if(instance == null){
try{
instance = new ExternalProperties();
} catch (IOException e) {
e.printStackTrace();
}
}
return instance;
}
public static void setLocation(String path){
location = path;
}
}
I am passing the location of the property file through the command line such as:
java -jar chef-deploy-tests-0.0.0009-SNAPSHOT-jar-with-dependencies.jar test.properties
Any suggestions on what I am doing wrong?
It depends on your location of the test.properties file.
* <li> If the name begins with a {#code '/'}
* then the absolute name of the resource is the
* portion of the name following the {#code '/'}.
*
* <li> Otherwise, the absolute name is of the following form:
*
* <blockquote>
* {#code modified_package_name/name}
* </blockquote>
*
* <p> Where the {#code modified_package_name} is the package name of this
* object with {#code '/'} substituted for {#code '.'}.
I think your problem is that test.properties is NOT on your classpath. The way you are running it now is simply passing the file as an argument to the application. I think what you mean to do is add it to the application's classpath:
java -jar chef-deploy-tests-0.0.0009-SNAPSHOT-jar-with-dependencies.jar -classpath .
This will include all the files in the the current directory in the java classpath. Another option may be to put that test.properties file into a separate directory and specify that one instead of the '.'
Related
When my application starts it reads a configuration properties file using the following code:
Properties properties = new Properties();
// parse the config resource
try (InputStream input = getClass().getClassLoader().getResourceAsStream(filename))
{
if (input == null)
{
// throw exception
}
// read the property list (key-value pairs) from the input byte stream
properties.load(input);
}
I am able to read and set individual properties.
The properties file is located in src/main/resources and after I build the application using maven, a copy of it is placed in target/classes. The jar file that is created also has a copy of it in the root directory when I open it up.
I would also like to be able to overwrite the properties file so that next time the application starts up, then it will read the new updated file. How do I achieve this? Is it even possible?
I found this question but no answers.
I've tried this:
try (OutputStream output = new FileOutputStream(filename))
{
properties.store(output, null);
}
which works if I just want to create a new file altogether. I would then have to modify the application so that it reads from a given folder rather than what originated from the resources folder. Is this what I should be doing?
I'm fairly new to Java so please go easy.
Storing the initial, default properties in the jar file, as resources is fine.
But if you want them to be writable, then you need to really store them as a file somewhere on the disk. Typically, under a .yourapp directory (or in a .yourapp file) inside the user's home directory.
So, try finding the file, and if not present, fallback to the resources. When writing, always write to the file.
This is an example code you can use for this. You create a config folder in the project root directory, an inside it you place your app.properties file
package com.yourparckage;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
public class Config {
/* Create basic object */
private ClassLoader objClassLoader = null;
private Properties commonProperties = new Properties();
public static final String CONFIG_FILE = "config/app.properties";
/**
* This method loads config data from properties file
*
*/
public Config() {
objClassLoader = getClass().getClassLoader();
}
public String readKey(String propertiesFilename, String key)
{
/* Simple validation */
if (propertiesFilename != null && !propertiesFilename.trim().isEmpty() && key != null
&& !key.trim().isEmpty()) {
/* Create an object of FileInputStream */
InputStream objFileInputStream = null;
/**
* Following try-catch is used to support upto 1.6. Use try-with-resource in JDK
* 1.7 or above
*/
try {
/* Read file from resources folder */
objFileInputStream = new FileInputStream(propertiesFilename);
/* Load file into commonProperties */
commonProperties.load(objFileInputStream);
/* Get the value of key */
return String.valueOf(commonProperties.get(key));
} catch (FileNotFoundException ex) {
ex.printStackTrace();
} catch (IOException ex) {
ex.printStackTrace();
} finally {
/* Close the resource */
if (objFileInputStream != null) {
try {
objFileInputStream.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
return null;
}
}
I need to write a simple configuration file using apache-commons-configuration but no matter what I try, it's not writing anything to the file.
This is how the file should look like
<config>
<foo>bar</foo>
</config>
This is what I'm doing to write the foo configuration:
private static final String USER_CONFIGURATION_FILE_NAME = "config.xml";
private final Path configFilePath = Paths.get(System.getProperty("user.home"), ".myapp",
USER_CONFIGURATION_FILE_NAME);
private final FileBasedConfigurationBuilder<XMLConfiguration> configBuilder=
new FileBasedConfigurationBuilder<>(XMLConfiguration.class)
.configure(new Parameters().xml().setFile(configFilePath.toFile()));
/**
* Sets the foo configuration to the given {#link String}
*
* #param foo The configuration to be set up
* #throws ConfigurationException If any error occur while setting the property on the
* configuration file
*/
public void setfoo(final String bar) throws ConfigurationException {
checkNotNull(bar);
final Configuration config = configBuilder.getConfiguration();
config.setProperty("foo", bar);
configBuilder.save();
}
/**
* Retrieves the foo set up on the configuration file
*
* #return The foo set up on the configuration file
* #throws ConfigurationException If any error occur while setting the property on the
* configuration file
* #throws NoSuchElementException If there is no foo set up
*/
public String getFoo() throws ConfigurationException {
return configBuilder.getConfiguration().getString("foo");
}
Am I missing something? In Apache Commons Configuration - File-based Configurations I can't see any other information needed to set up the file, so I really don't know what I'm missing here.
For some reason the FileBasedConfiguration is not setting up the xml file by itself, so I had to create it manually and set up the root element, like this:
configFilePath.toFile().createNewFile();
final Writer writer = Files.newBufferedWriter(configFilePath);
writer.write("<config></config>"); //sets the root element of the configuration file
writer.flush();
Shouldn't FileBasedConfiguration take care of this for me, or this is a step that's not documented on apache-commons?
I have maven project in Java in which I have a property file (quartz.properties) under this directory:
/src/main/resources
Now I can use this property file in two ways from this class as shown below:
/**
* Create a StdSchedulerFactory that has been initialized via
* <code>{#link #initialize(Properties)}</code>.
*
* #see #initialize(Properties)
*/
public StdSchedulerFactory(Properties props) throws SchedulerException {
initialize(props);
}
/**
* Create a StdSchedulerFactory that has been initialized via
* <code>{#link #initialize(String)}</code>.
*
* #see #initialize(String)
*/
public StdSchedulerFactory(String fileName) throws SchedulerException {
initialize(fileName);
}
I am not sure how can I use StdSchedulerFactory class to provide the path of my quartz.properties file.
As of now I am providing hardcoded path like this but this is not the right way to provide the path since if anyone else is running this code in their desktop or laptop then it will not work. I will be running this application from my desktop and also I will be making a runnable jar as well so I want that my program should load my properties file dynamically without any hardcoded path.
public class TestingQuartz {
public static void main(String[] args) throws SchedulerException {
SchedulerFactory factory = new StdSchedulerFactory(
"C:\\workspace\\tester_quartz\\quartzmain\\src\\main\\resources\\quartz.properties");
Scheduler scheduler = factory.getScheduler();
scheduler.start();
}
}
As your configuration file is in src/main/resources of a mavenized project, it will be embedded in the resulting artifact (jar, war...) you build with maven. Thus you should load the file "from the classpath" like this :
StdSchedulerFactory factory = new StdSchedulerFactory();
factory.initialize(this.getClass().getClassLoader().getResourceAsStream("quartz.properties"));
Since it appears to be on your class path you could do this:
getClass().getClassLoader().getResource("quartz.properties").toExternalForm()
I'm working on a Java EE project that provide a servlet that store a lot of images (or common files) into glassfish server for specific users.
I'm wondering if there are standard directories to save the files into standard web programming.
For example, I have three users that want upload their files, where I can save them into server?
There are'nt any standard directories. I suggest you to create directory on a server to each user. For example: The user registers, some data goes to the database and also a directory for this user is created. Than this user can upload any file to his own directory.
P.S you can create directories anywhere on the server, then configure the path of directory in server's JNDI resources for look in your application.
You have to create PropertiesObjectFactory class to handle JNDI properties of java.util.Porperties (if you are using glassfish 2). Or yuo can write your custom ObjectFactory also. Glassfish 3 already have this function. It is set into: org.glassfish.resources.custom.factory.PropertiesFactory.
Create directory somewhere on the server. For e.g: /server/glassfish/users
Open glassfish admin console and navigate to: Resources -> JNDI -> Custom Resources, click "New". Provide a JNDI name, for e.g: jndi/users_directories, choose a resource type "java.util.Properties", specify Factory class: org.glassfish.resources.custom.factory.PropertiesFactory, then click "Add property", specify name for e.g: users.directories and in value column copy your directory path. In this case: /server/glassfish/users. Click OK and thats all.
Restart application server.
Make a look up in your application:
public Properties getProperties(String jndiName) {
Properties properties = null;
try {
InitialContext context = new InitialContext();
properties = (Properties) context.lookup(jndiName);
context.close();
} catch (NamingException e) {
LOGGER.error("Naming error occurred while initializing properties from JNDI.", e);
return null;
}
return properties;
}
When you call this method in your application provide a JNDI name you configured in your application server: jndi/users_directories. If you have mapped resources in deploymet descriptor you have to use: java:comp/env/jndi/users_directories.
If you whant to do the same using spring:
<jee:jndi-lookup id="usersDirectories"
jndi-name="jndi/users_directories"/>
Or if you are using glassfish 2, then create a custom PropertiesObjectFactory class:
public class PropertiesObjectFactory implements Serializable, ObjectFactory {
/**
* File property name.
*/
public static final String FILE_PROPERTY_NAME = "org.glassfish.resources.custom.factory.PropertiesFactory.fileName";
/**
* Implemented method from object factory interface.
*
* #param obj object
* #param name name
* #param nameCtx context name
* #param environment environment
* #return file properties
* #throws Exception if error occurs
*/
public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment)
throws Exception {
Reference ref = (Reference) obj;
Enumeration<RefAddr> refAddrs = ref.getAll();
String fileName = null;
Properties fileProperties = new Properties();
Properties properties = new Properties();
while (refAddrs.hasMoreElements()) {
RefAddr addr = refAddrs.nextElement();
String type = addr.getType();
String value = (String) addr.getContent();
if (type.equalsIgnoreCase(FILE_PROPERTY_NAME)) {
fileName = value;
} else {
properties.put(type, value);
}
}
if (fileName != null) {
File file = new File(fileName);
if (!file.isAbsolute()) {
file = new File(System.getProperty("com.sun.aas.installRoot") + File.separator + fileName);
}
try {
if (file.exists()) {
try {
FileInputStream fis = new FileInputStream(file);
if (fileName.toUpperCase().endsWith("XML")) {
fileProperties.loadFromXML(fis);
} else {
fileProperties.load(fis);
}
} catch (IOException ioe) {
throw new IOException("IO Exception during properties load : " + file.getAbsolutePath());
}
} else {
throw new FileNotFoundException("File not found : " + file.getAbsolutePath());
}
} catch (FileNotFoundException fnfe) {
throw new FileNotFoundException("File not found : " + file.getAbsolutePath());
}
}
fileProperties.putAll(properties);
return fileProperties;
}
}
Make a .jar file of this class and put it to server global library directory. Provide this factory class for your JNDI resources, restart the server and you are good to use the same look up, covered above.
I have an exe process that is running with a shortcut.
In the "Start in" property of the shortcut I set it to the folder where all app resources are. The process still looks for files at the location of the exe and not the location written in the shortcut.
I can also see it in Process Explorer - the "current directory" is the location of the exe.
Is there a way to change it?
(If I wasn't clear enough -
I want to put my app in a central network location and not in each user folder - but I want it to run - above each user folder by putting a shortcut in each user folder.)
BTW : Why don't I solve it with code writing? Because of third party jars I have in my exe (I am using exe4j to make an exe)
From exe4-j documentation.., it seems this can be configured in exe4j project.
Working directory
For some applications (especially GUI applications) you might want to change the working directory
to a specific directory relative to the executable, for example to read config files that are in a fixed
location. To do so, please select the Change working directory to: checkbox and enter a
directory relative to the executable in the adjacent text field. To change the current directory to the
same directory where the executable is located, please enter a single dot.
One alternative is to use a System Property. Just create a shortcut like this:
java -Dmyproperty="\\myserver\myfolder" -jar yourjar.jar
And get this property on your program:
System.getProperty("myproperty");
You can also set multiple System Properties.
I would start the java application via a cmd or bat file, then change to the work dir before you call javaw. If you don't do any thing special in your java application code all the paths in it will be relative to the place where you started java.
Jess
You can hack the classpath programatically which would allow you to specify a specific folder or series of folders to access the data.
import java.io.IOException;
import java.io.File;
import java.net.URLClassLoader;
import java.net.URL;
import java.lang.reflect.Method;
public class ClassPathHacker {
private static final Class[] parameters = new Class[]{URL.class};
public static void addFile(String s) throws IOException {
File f = new File(s);
addFile(f);
}//end method
public static void addFile(File f) throws IOException {
addURL(f.toURI().toURL());
}//end method
public static void addURL(URL u) throws IOException {
URLClassLoader sysloader = (URLClassLoader) ClassLoader.getSystemClassLoader();
Class sysclass = URLClassLoader.class;
try {
Method method = sysclass.getDeclaredMethod("addURL", parameters);
method.setAccessible(true);
method.invoke(sysloader, new Object[]{u});
} catch (Throwable t) {
t.printStackTrace();
throw new IOException("Error, could not add URL to system classloader");
}//end try catch
}//end method
}//end class
with the property loader file of
import java.io.InputStream;
import java.util.Enumeration;
import java.util.Locale;
import java.util.Properties;
import java.util.ResourceBundle;
public abstract class PropertyLoader
{
/**
* Looks up a resource named 'name' in the classpath. The resource must map
* to a file with .properties extention. The name is assumed to be absolute
* and can use either "/" or "." for package segment separation with an
* optional leading "/" and optional ".properties" suffix. Thus, the
* following names refer to the same resource:
* <pre>
* some.pkg.Resource
* some.pkg.Resource.properties
* some/pkg/Resource
* some/pkg/Resource.properties
* /some/pkg/Resource
* /some/pkg/Resource.properties
* </pre>
*
* #param name classpath resource name [may not be null]
* #param loader classloader through which to load the resource [null
* is equivalent to the application loader]
*
* #return resource converted to java.util.Properties [may be null if the
* resource was not found and THROW_ON_LOAD_FAILURE is false]
* #throws IllegalArgumentException if the resource was not found and
* THROW_ON_LOAD_FAILURE is true
*/
public static Properties loadProperties (String name, ClassLoader loader)
{
if (name == null)
throw new IllegalArgumentException ("null input: name");
if (name.startsWith ("/"))
name = name.substring (1);
if (name.endsWith (SUFFIX))
name = name.substring (0, name.length () - SUFFIX.length ());
Properties result = null;
InputStream in = null;
try
{
if (loader == null) loader = ClassLoader.getSystemClassLoader ();
if (LOAD_AS_RESOURCE_BUNDLE)
{
name = name.replace ('/', '.');
// Throws MissingResourceException on lookup failures:
final ResourceBundle rb = ResourceBundle.getBundle (name,
Locale.getDefault (), loader);
result = new Properties ();
for (Enumeration keys = rb.getKeys (); keys.hasMoreElements ();)
{
final String key = (String) keys.nextElement ();
final String value = rb.getString (key);
result.put (key, value);
}
}
else
{
name = name.replace ('.', '/');
if (! name.endsWith (SUFFIX))
name = name.concat (SUFFIX);
// Returns null on lookup failures:
in = loader.getResourceAsStream(name);
if (in != null)
{
result = new Properties ();
result.load (in); // Can throw IOException
}
}
}
catch (Exception e)
{
result = null;
}
finally
{
if (in != null) try { in.close (); } catch (Throwable ignore) {}
}
if (THROW_ON_LOAD_FAILURE && (result == null))
{
throw new IllegalArgumentException ("could not load [" + name + "]"+
" as " + (LOAD_AS_RESOURCE_BUNDLE
? "a resource bundle"
: "a classloader resource"));
}
return result;
}
/**
* A convenience overload of {#link #loadProperties(String, ClassLoader)}
* that uses the current thread's context classloader.
*/
public static Properties loadProperties (final String name)
{
return loadProperties (name,
Thread.currentThread ().getContextClassLoader ());
}
private static final boolean THROW_ON_LOAD_FAILURE = true;
private static final boolean LOAD_AS_RESOURCE_BUNDLE = false;
private static final String SUFFIX = ".properties";
} // End of class
then you can add a path as follows
try {
//First Load up the properties and populate the config
ClassPathHacker.addFile("/pathtomyapp");
} catch (IOException ex) {
ex.printStackTrace();
}
properties = PropertyLoader.loadProperties("myapp");
or you can also use getResourceBundle to get your resources, this is just one example of hacking the classpath to allow files to be available, you can always just add the classpath programatically and let the jar files you need to be available to reside there, so if you always ensure that the app network path is Q: you can add Q:\ to the classpath.