I am building a Java Application with the intention of packaging it to be a windows executable in the future. My NetBeans project structure can be seen
here.
I am currently reading from config.properties using getResourceAsStream(). I was not aware that this file cannot be written to in a similar manner. Would anyone be able to advise a way to achieve this or is a different approach to my problem required? Thanks.
I think you can use java.util.properties to solve your problem; to write to your properties first create a new Properties object, load them via your InputStream, use methods such as setProperty to add to your configuration and finally use store to write to them.
Example:
File appConfig = new File("a_file");
FileInputStream propsInput = new FileInputStream("a_file");
Properties prop = new Properties();
prop.load(propsInput);
try (Writer inputStream = new FileWriter(appConfig)) {
// Setting the properties.
prop.setProperty("A_PROP", "A_VALUE");
// Storing the properties in the file with a heading comment.
prop.store(inputStream, "INFORMATION!!!");
} catch (IOException ex) {
ex.printStackTrace();
}
There's no straightforward answer to the question how to externalize configuration -- it depends on the application and the environment in which it will be deployed.
The Java preferences API is an attempt to get around this problem by providing a platform-neutral API for preferences. On Linux, the data is actually stored in an XML file in a subdirectory of $HOME/.java but, of course, the programmer isn't supposed to be concerned about this. Using this API is convenient, but doesn't allow complex data to be stored, and doesn't easily allow the programmer to provide the application with a way to read configuration from some specific place.
Rather than use the preferences API you can read/write files explicitly. For simple 'name=value' configuration, you can use a Properties object, which has methods for handling files. This method does allow a specific file location but, of course, controlling the file location does require some adaptation for the various platforms you might support.
If your configuration is more complex than 'name=value', you could read/write it in a format of your choice -- JSON, YAML, XML, etc. All these file formats are well-supported by Java. Using a text-based format allows users to edit the configuration using other tools, if they so wish.
In practice, I nearly always externalize configuration in serialized Java objects, into a file whose location I control. This allows configuration of arbitrary complexity without additional coding, since you're storing Java data directly. It takes a bit of work to structure a program to be serialized, but it's worth it in the long run. Unfortunately, this approach does not allow for easy editing of the configuration outside the program.
If you ever intend to run the application in a container (Docker, etc), then completely different considerations apply. You'll need to use a method of externalizing configuration that is compatible with the container platform -- simply reading and writing files is often inappropriate in such an environment.
If you're unsure how you want to handle configuration, do it in a class that implements an interface you define. Then, if you later change your mind, you can supply a different class that implements the same interface.
Related
This question isn't in regards to how to get/read the properties files, but instead what is the standard or accepted location to keep them. Specifically, I've got two types of properties, one that is sort of a server config file and a couple that are written to and read from to contain information sent to/from a client. So where should these be placed?
What do you see as the options?
Config files should be on the classpath, unless they need to be trivially modifiable. If they do, then they should be in a location external to the app, and the location set by either default, a JNDI string, a system property, or whatever.
Files that are regularly updated as part of system operation must be external, and configured in the same way. Although I'd question whether or not it makes sense to do that kind of persistence with a file.
I am looking for a open-source solutions which allow hosting different properties for different applications and allow changes. On any change of properties it should notify or push the change to the application appropriately.
So, instead every application managing the properties in physical file and deploying physically; these properties can be pushed to a single system. User will have GUI to load and change the properties as per right. Should allow push as mentioned.
If you have already similar open source solutions in mind please advice.
Is this something that Puppet can manage for you?
I don't think what you've described (as nice as it would be) will be likely to exist in an app server. If a program is looking for a file, it's either going to load it with a FileReader (or similar), or it will use ClassLoader.getResourceAsStream(). It might be looking for data that is returned in properties, format, XML properties format, or even something completely different like RDF with which to configure itself. Also many programs read their config on start-up and then hold the values in memory, so you would still need to reboot them to get them to change.
To get something like this to work there would need to be a standard for configuration provisioning and live updates. Once that existed the webapp authors and server vendors would each need to add support for the standard.
If you are the one writing the programs to be managed however, then you can write your programs to request configuration from a service, and have a configuration push feature.... there may be packages out there that can speed up adding that to your code, but I get the impression you are looking to manage programs written by others.
Have you considered to use JMX? I think he could be a good starting point to implement your requirements.
MBeans's attributes can store your application's properties, the MBeanServer will allow you to make them available from remotting, JConsole offers you an GUI to update properties values.
You also can write within the MBean some code that notify the corrrespondig application when a user change any properties using the GUI.
I am working on a project and I need to save user configuration. The configuration is a set of Jchechboxes I need to store their state (true, false). Which do you think is the better way of saving it, in a file and if yes in what (ini, cfg, txt), or it is better to serialize the object with the states?? Or if there is another way, please tell me :)
Cheers
It depends if you need to access the variables many times, and when: at the start of the application or during runtime?
If this configuration is user-related maybe you want to keep separate configuration for each user serialized on a Database so you can load them dynamically when a user loads the form that displays the checkboxes.
If there's just one possible configuration for one user (or such) maybe you should just put everything in a text file (the extension doesn't matter: ini,cfg,txt,lol anything you want) just simplify your life by using standard Java configuration access using the Properties class: http://java.sun.com/j2se/1.4.2/docs/api/java/util/Properties.html
How about a Properties file?
If you decided to store the properties as a serialized object then you will make changing the implementation of the gui much harder and thus less portable. If you save them in a text file then you are free to change the GUI implementation without any disruption to the user, whilst allowing the user to keep their saved properties.
As such, I would always recommend storing preferences in a properties type file. The Properties API, and related commons classes are pretty simple to use.
The best method is to use java.util.prefs to store user preferences
Where do you store user-specific and machine-specific runtime configuration data for J2SE application?
(For example, C:\Users\USERNAME\AppData\Roaming</em> on Windows and /home/username on Unix)
How do you get these locations in the filesystem in platform-independent way?
First on the format:
Java property files are good for key/value pairs (also automatically handle the newline chars). A degree of structure is possible by using 'dot notation'. Drawback is that the structure does not allow you to easily enumerate top-level configuration entities and work in drill-down manner. Best used for a small set of often tweakable environment-specific settings
XML files - quite often used for more complex configuration of various Java frameworks (notably J2EE and Spring). I would advice that you at least learn about Spring - it contains many ideas worth knowing even if you decide not to use it. If you decide to roll your own XML configuration, I'd recommend using XStream with customized serialization options or if you just need to parse some XML, take a look at XOM. BTW Spring also allows you to plug your custom XML configuration language, but it's a relatively complex task. XML configuration is best used for more complex 'internal' configuration that is not seen or tweaked by the end user.
Serialized Java objects - a quick and easy way to persist the state of an object and restore it later. Useful if you write a configuration GUI and you don't care if the configuration is human readable. Beware of compatibility issues when you evolve classes.
Preferences - introduced in Java 1.4, allow you to store typed text, numbers, byte arrays and other primitives in platform-specific storage. On Windows, that is the registry (you can choose between /Software/JavaSoft/Prefs under HKLM or HKCU). Under Unix the same API creates files under the user home or /etc. Each prefs hive can be exported and imported as XML file. You can specify custom implementation of the PreferencesFactory interface by setting the "java.util.prefs.PreferencesFactory" JVM property to your implementation class name.
In general using the prefs API can be a good or a bad thing based on your app scenario.
If you plan to have multiple versions of the same code running on the same machine with different configuration, then using the Preferences API is a bad idea.
If you plan using the application in a restricted environment (Windows domain or tightly managed Unix box) you need to make sure that you have proper access to the necessary registry keys/directories. This has caught me by surprise more than once.
Beware from roaming profiles (replicated home dirs) they make up for some funny scenarios when more than one active machines are involved.
Preferences are not as obvious as a configuration file under the application's directory. most of the desktop support staff doesn't expect and doesn't like them.
Regarding the file layout of the prefs it again depends on your application. A generic suggestion is:
Package most of your XML files inside application's JAR either in the root or under /META-INF directory. These files will be read-only and are considered private for the application.
Put the user modifiable configuration under $APP_HOME/conf . It should consist mainly of properties files and occasionally a simple XML file (XStream serialization). These files are tweaked as part of the installation process and are usually not user serviceable.
Under the user-home, in a dot-directory (i.e. '~/.myapplication') store any user configuration. The user configuration may override the one in the application conf directory. Any changes made from within the application go here (see also next point).
You can also use an $APP_HOME/var directory to store any other mutable data which is specific to this application instance (as opposed to the user). Another advantage of this approach is that you can move and backup the whole application and it's configuration by simple copy of one directory.
This illustrates some standard techniques for managing configuration. You can implement them using different libraries and tools, starting from raw JRE, adding Spring/Guice or going for a full J2EE container (possibly with embedded Spring)
Other approaches for managing configuration are:
Using multiple base directories for running multiple instances of the application using different configurations.
Using lightweight registries for centralized configuration management
A centrally managed Configuration Management Database (CMDB) file, containing the host-specific values for each machine is rsync-ed every night to all production hosts. The application uses a templated configuration and selects from the CMDB during runtime based on the current hostname.
That depends on your kind of J2SE Application:
J2SE executable JAR file (very simple): use user.home System property to find home-dir. Then make a subdir accordingly (like e.g. PGP, SVN, ... do)
Java Web Start provides very nice included methods to safe properties. Always user-specific
Finally Eclipse RCP: There you have the notion of the workspace (also derived from user.home) for users and configuration (not totally sure how to access that tricky in Vista) for computer wide usage
All these approaches are, when used with care -- use correct separatorChar -- OS neutral.
Java has a library specifically for doing this in java.util.prefs.Preferences.
Preferences userPrefs = Preferences.getUserNodeForPackage(MyClass.class); // Gets user preferences node for MyClass
Preferences systemPrefs = Preferences.getSysteNodeForPackage(MyClass.class); // Gets system preferences node for MyClass
Preferences userPrefsRoot = Preferences.getUserRoot(); // Gets user preferences root node
Preferences systemPrefsRoot = Preferences.getSystemRoot(); // Gets system preferences root node
I use this
String pathFile = null;
if(OS.contains("win")){
pathFile = System.getenv("AppData");
}else{
pathFile = System.getProperty("user.home");
}
I save the settings of my application here
C:\Users\USERNAME\AppData\ on windows
user.home (/home/USERNAME) on other platfroms
For user specific config, you could write a config file to the folder pointed to by the "user.home" system property. Would only work on that machine of course.
You might want to look at Resource Bundles.
I used to have a custom preferences class for my applications. For my next hobby project i wanted to switch to the Preferences API. But the put and get functions require a default value and i do not want to spread default values all over the source files. Even though my project is small i can not imagine changing default values all over the source code. How do you guys use the api? I am thinking of wrapping the preferences api in another class but then what is the point of using the API because it only takes away the burden of saving the file to disk, which isn't that hard using serialization? Am i missing the point?
You're mixing a few concepts here. The default given in the code should be specific to the local situation as a 'reasonable default'. If you want to have application-wide defaults, then you need a preference-provider that allows you to hook in both the default preferences and an overlaid user-preferences. Something that may be a worthwhile project in itself.
Oh, and "reasonable defaults" is a great way to avoid configuration when it's not necessary but allow the user or packager to provide better values when needed.
#comment, I think I understand.
By 'local situation' I mean in the context of the code. For your GUI, you need a value for display that represents whatever the thread is using. Therefore I'd use something like Worker.DEFAULT_TIMEOUT. Your worker would use the same value internally as the default. That way you are retrieving the configured value or the worker's default when you are setting the worker's behavior.
then you might want to take full control over how Preferences should follow your desired storage by implementing AbstractPreferences. You can see a linux based implementation here:
http://www.docjar.com/html/api/java/util/prefs/FilePreferencesImpl.java.html
Good luck!
Would it be so hard to stick all your defaults in a single class so that they weren't littering your code?
I've used commons configuration in recent projects. I've looked into the Java Preferences API but I like the flexibility of the Commons project. And you don't have to specify default values!
You can put default values in .preferences file which you bundle in your .jar file (or in specialized class or interface with constants).
I use it for things like window positions/sizes, remembering default folder for choosing files, last opened files and such trivia. I can think of some interesting things you get "for free" with preferences API:
doing things in OS-recommended way; OS might not allow you to write "settings files" in your app folder, and users don't like to be asked where on disk they want to save settings, and you don't want to implement your custom logic for every platform
your data is saved for each OS user separately
a way to keep user data even if your application is uninstalled (or during an upgrade)
don't need database or access to file system
Also, I don't like serialization and don't recommend it for this. Serialization means you have to take care when changing your classes in new versions of your application.