I want a simple file format to store and retrieve data from disk in Java.
name=value
list=value1,value2,value3
this is mostly going to be used for initial config settings used at startup of the app. I could invision having a watcher on the file to notify the app if it changes so the new settings can be applied potentially but that would be a nice to have. The first part would be pretty easy to write. I just don't want to reinvent the wheel if something is already out there for this and I'd prefer to avoid something as heavy as spring.
Take a look at the java.util.Properties class.
Properties
You can use the Preferences class. It has a notification system, but alas it doesn't notice changes made outside the running JVM or directly to the underlying configuration store (e.g. the config file). It's a really nice class though.
Have a look at OWNER API.
It incorporates most of the feature of java.util.Properties and adds more.
Version 1.0.4 is under development and it will have:
support for arrays and collections (list, set, arrays). It is already implemented on master branch.
"hot reload", when you change the file the config object gets reloaded (it can be synchronous or asynchronous and it does support event notification for reload). Already implemented in master branch.
a lot of features (variable expansion, type conversion). Available since version 1.0.3 and available on maven central repository.
Also for 1.0.4 is planned a validation mechanism that will check the file to be compliant before discarding the old content of the config file during the reload. (not implemented yet)
If you need some particular feature, just ask on github issues or become a contributor.
Related
Background
I'm adding database migrations to an existing project using the open source project mongobee. The actual migrations are all handled by mongobee and its concepts of changelogs and changesets. Part of this enhancement involves checking the current MongoDB database migration version at runtime and comparing it against the version expected by the java application. The reasoning behind this is we'd like to have an installation of our product download code updates (new *.wars) and upon logging in the new version of the application, the admin user would be prompted to update the database if their database version is lower than expected.
We're currently using Maven to package and build our software.
Problem
The one area that's nagging me is how to handle tagging the database version the Java source code expects. I'd like to avoid manually entering this each time we do a build and add a migration.
My proposed solution may not be ideal. My initial thought is to use a convention for the changelog file and class names like "v0001_first_migration" and then at build time, use maybe the maven AntRun plugin to call a separately compiled java file that traverses the migration changelog directory and looks for the latest migration number and then stores that result in a resource file, probably XML. The application can then read that XML file at runtime to get the database version it expects.
1 - Is this feasible?
2 - Is there a way to do something like this in pure Maven without using AntRun?
3 - Is there another option to accomplish this easier?
As an alternative to my proposed solution above, I used a reflection project found here: https://github.com/ronmamo/reflections and iterated through all of the classnames in my migrations directory that follow the aforementioned convention (v0001_first_migration, v0002_second_migration). I parse those using regex to get an Integer and do comparisons to determine the migration version expected by the app. The database side was a lot easier so I won't go over that.
Now, instead of using Ant tasks I'm just popping the expected app migration version into a singleton (gross I know) or alternatively just calling the function that finds the expected app migration depending on where it's used.
WHY a Singleton? The parsing process is expensive and I expect to use this data on each REST call that wants to touch our database. In the REST layer I created the singleton because of some limitations with our current project. The better way here is in the case of Tomcat, create a ServletListener and assign the migration version as an attribute of the ServletContext. Due to the way our REST layer works, I'd be modifying a TON of function signatures to pass in the #Context ServletContext. We don't have Dependency Injection containers either so my options were limited if I didn't want to touch almost every action in the REST layer. The Singleton gets the expected app migration version at startup and that's it so it's still easy to test with mocks and there are no concurrency issues that I can see.
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 have a lot of configuration files that modify how my application behaves. I want to be able to make a change and it gets reflected in the application right away when saving the file. Is there a Java library to help with this?
I could simply keep a list of files with their timestamps and continuously check in a background thread when a timestamp changes. Doesn't seem too difficult, but maybe there's a more efficient way to do this? Custom triggers when certain properties have changed would be nice.
I'm using Spring 3.1, is there a built-in mechanism or solution which works nicely with Spring?
UPDATE: Apparently JDK7 now includes this functionality through its Watch Service API: "Most file system implementations have native support for file change notification. The Watch Service API takes advantage of this support where available. However, when a file system does not support this mechanism, the Watch Service will poll the file system, waiting for events." So this'll be my motivation to migrate to JDK7.
Edited:
http://commons.apache.org/configuration/userguide/howto_filebased.html
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.