Saving user settings/database/cache... in Java (On every OS) - java

My Java application is saving stuff in 'user.home' but on windows this does not seem to be the correct path to save application information (as a friend told me). An other option is using the preferences api but it's not possible to set up the hsqldb location using the preferences api. Also, I want all files to be available in the same folder (local database, config, cache, ...).
I'm looking for some example code or a framework that takes care of os-specific stuff.

On my WinXP Pro SP3 system, user.home points to C:\Documents and settings\<username>
Lot of applications just store their data there (instead of this path + Application data, but some others go down to there), creating a directory in Unix style, ie. dot + application name (examples: .antexplorer, .sqlworkbench, .squirrel-sql, .SunDownloadManager, .p4qt, .gimp-2.4, etc.).
Looks like a decent, common practice...

It's unusual for a window app to save data in user.home but not "wrong". Windows applications love to spread their data all over the place (a bit in the registry, a bit in the application's install directory, a bit in the Windows directory, a bit in System32, a bit here and a bit there). In the end, this makes it impossible to cleanly backup or remove something which results in the famous "Windows rot" (i.e. you have to reinstall every few months).
Anyway. If you really don't want to use user.home (and I see no reason not to), use code like this from Apache commons-lang to figure out if you're running on Windows. If this yields true, pop up a directory selection dialog where the user can specify where they want to save their data.
Save this information in Preferences and use this path the next time when your app is started. This way, users can specify where they want their data and you only have to leave one bit of information in the prefs.

For an application "foo" I'd create a directory named ".foo" inside user.home. For Windows it will look slightly strange, but almost noone ever looks in that directory (and it's filled with obscure directories anyway) and on Linux/Solaris/... it will result in a hidden directory that doesn't clutter the users home directory visually.

dynamically read (from your code) the value of APPDATA environment variable, and store your config files in %APPDATA%\\.myapp\config
==> value is platform dependent, do not use any hard-coded paths, always read the env. var.

The problem is not Wiindows but the standard java setup.
Long Discussion
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4787931>Here
I would advise picking this up on a '-D MYLOC=%USERPROFILE%' property on the command line.
Note that you will only get a "USERPROFILE" if the user did a desktop login, this does not get set if the user logged in remotly with citrix or similar or via ssh, also, coprporate desktops mess around with this setting and may set it to something unusable.

Related

Java Best Practices for Config File Locations

In UNIX and its derivatives, application config files live under /etc/, whereas they live elsewhere on Windows and other systems. The philosophy behind java is "Write once, run everywhere" and an app ideally shouldn't have to care what OS it's on. But I want my application to load a config file on startup and I need to provide a path. Right now, I'm loading different file locations switching off of the OS name, but this doesn't feel like it's best practices for Java. How do I reconcile this?
When I am making a game/app I just put a resources folder in the same path as the app. For example in the code, the directory would be "res/config.yml". In the same folder as the jar you put the resource folder named "res". you then put the file in the res file. So the app should get the file.
I usually put configuration files in a directory .<appName> (note the leading dot) in the user home, which is read at runtime via System.getProperty("user.home"). This is the expected location for Linux users, while on Windows it feels a bit exotic (compared with profile directories like AppData/Local or AppData/Roaming) even if it's an extremely popular choice for cross-platform tools. Using the current user's home means you won't usually have troubles with filesystem access rights, and using user.home is preferred instead of a custom property because it's provided out of the box by the system (and still it can be overridden)
Another approach is using the installation directory, but then you have to use an environment variable that points to that, like $APP_HOME, because it can't generally be inferred while the application is running (actually you can get the installation directory pretty easily for typical JAR deployments by playing with URLs returned by the main ClassLoader, but I consider it a hack and think it shouldn't be used). Your application can read the variable with System.getenv("APP_HOME"), and this variable must be set by the platform-dependent scripts you provide to start your application. This strategy has the downside that the current user may not have the rights to read/write to the named directory.
In our application we use different locations for configuration on each OS.
On Linux
/etc/applicationname
On Windows
[Use Selected Install Dir]/conf
We control where the application looks via a system property
-Dconf.dir=path
I don't necessarily think there is a correct answer in this case.

Change working dir in Java Webstart

Is there a way to change working dir for JVM when running Java Webstart?
When i use system.setProperties("user.dir", newDir) it sets it(system.getProperties() shows it does) but ignores it.
Is this a limitation in Java Webstart to always use the working dir where i started the jnlp file?
I am using all permissions in the jnlp file.
Please help!
EDIT: Whatever i do now, my webstart always uses user.dir to save files. Frustrating!
I've had this question in the past myself, but I've always found that, in the end, I didn't need it. Why do I say this?
Because your java web start app is not like an executable run from Program Files. It doesn't even exist on your computer like most programs (it is broken up into a bunch of different files and reassembled by the JVM). Therefore, you cannot say that the program has its own directory to do what it needs.
But it doesn't need to. Here's why:
Java has the Preferences API to help when you need to store data. The under-workings of the Preferences API is as mysterious as JWS, thus they are really a perfect fit. Either way, if you need to write things to a file, you should check this API to see if it can meet your needs.
If you need to write files for the user, then prompting them and allowing them to choose the location obviously means you won't use your current working directory to read/write files.
If you need to serialize objects, you should just create a program directory using the user.home resource as #AndrewThompson suggested. This will be "your" directory and is as good (in fact, better) than a directory in Program Files (if you're running on Windows, as an example).
In conclusion, in all cases (that I've come across), there's no need to change your current working directory. If you need your own folder, create one in user.home (because you won't run into file permissions issues there).
..all my settings file i use is created in the user.dir.
There is the mistake. Put them in a sub-directory of user.home & the problem is solved.
In the hypothesis you really really need to divert user.dir property for Java WebStart execution, here is the only option I have found: set this system environment variable (so system wide):
_JAVA_OPTIONS="-Duser.dir=C:\Temp"
But care about it, this option is read and applied to any JVM executions.
Why was it required in my context ? Because Java WebStart ClassLoader was looking for any single resource (class, properties...) in user profile before getting it from jar files in cache. As the user profile has been moved to a network storage, application start up became terribly slow. I am still investigating Java sources to understand (and avoid) this behavior. So my applications work perfectly without setting user.dir but that was the only work-around for the performance issue we got at the moment.
The recommended way to pass runtime parameters or user specific setting is through the jnlp argument
<application-desc main-class=".....">
<argument>user.home</argument>
..............

set up database directory

I am working on a Java Desktop program which upon its installation will designate a default database directory and working directory. Where should I save such information so that the next time the user open the program, the program knows where to look for database and working directory?
Things that come to mind:
store everything in the registry (well, did that in MATLAB version and if there is another way, definitely will not go there).
set up another database attached in the jar file to store everything
Is this a so called persistence problem? What are Java Persistence or Java Data Object? Do they have the way to make it working?
any other suggestions?
Take a look at the Java Preferences API. It is a standard Java SE mechanism for storing preferences that does so in a platform specific, but application neutral way. Uses the Registry on Windows, Preferences files on OS X, and I believe ~/.files on Unix.
The Preferences class was created to store things like... preferences in an OS-neutral fashion.
You could also just specify a directory location manually, through a launcher script, or create a default directory in the user's home, and keep both configuration and DB files there.
Your persistent memory is your hard drive, of course, so you need to store data there if you want it to persist from execution to execution. Really, anything goes. You could store the configuration in an XML file -- makes it user-readable outside of the application, which is really nice for debugging, and Java comes with libraries for XML parsing and generation. It would be OS-independent, unlike a registry solution, which is Windows specific. And you could use the XML approach to share information between apps, if that matters. Something to consider.
Update: Preferences are cool! Never saw that one before.

Windows Mobile: automatically copy files on reboot

I have a Java app that runs on a Windows mobile device. At startup the app talks to our server to see if any files need updating and downloads them if they do. If any of the files are dlls they need to be stored in a temp directory and the device is rebooted because they might be currently in use. When the app starts it reads an xml file that lists all of the temp files and where they need to go and copies them into place.
A new requirement has come up that involves also updating the JVM files as part of this process. Since the code that does the copying is run on the JVM there is no way to do it since the files will always be in use. So we are looking at writing something in native code to do this copying process.
Before we start, I was just wondering if anyone knew of an already existing application or technique that does this (someone suggested a registry entry that tells the device to copy files on startup for example). Basically the requirement is to read some sort of configuration file that details the location of the source file and the destination then performs the copy. Any ideas before I reinvent the wheel by writing an app myself?
If your target handsets are handheld barcode scanners (Symbol, Intermec, etc.) they already have a framework in place for this. I don't have all the details, but I know from previous projects that they have a "protected" memory location that allows application to essentially re-configure / copy themselves from hard boots and similar problems. It might be worth seeing if any of that would work on your existing targets.
The scanners use either Windows CE or Windows Mobile.
In the absence of another answer, I have written a simple app to do it and put it in the startup directory. Was pretty easy, just didn't want to reinvent the wheel.
You can also rename your running executable file by the running-application itself. After this you can copy the file into the directory and simply restart your application.

Cross-platform way to ask for the user's documents folder?

I'm writing a cross-platform program in Java and want to stick the configuration files in the user's documents folder ("My Documents" under Windows, "Documents" under appropriate Linux, and whatever the folder's called under Mac OS), but I'm not sure how to ask Java for that.
I'd like to stay away from hard-coding things (do X if we're on Windows, Y if we're on Linux, or Z if we're on OS X), as this puts the burden of support on my shoulders rather than the Oracle development team.
I've checked the system properties list, but it doesn't seem to include the user's documents folder.
Sadly there is no easy cross-platform way. You will have to take advantage of native functionality on each OS platform
Here is some info on how to do it in osx
Here is some info on how to do it in windows
For Linux I don't have a convenient link, but given that there isn't necessarily the concept of a Documents folder in Linux, I don't know of a good solution. The system property user.home should at least be valid in Linux.
Partial solution:
boolean isMac = System.getProperty("os.name").equals("Mac OS X");
Or use http://commons.apache.org/vfs/ to get the operating system:
http://commons.apache.org/vfs/apidocs/org/apache/commons/vfs2/util/Os.html
// the folder name is the same whatever the language of Mac OSX.
Mac: System.getProperty("user.home")+File.separator+"Documents");
/Users/david/Documents
Win: System.getenv("APPDATA"));
C:\Documents and Settings\david\Application Data
This is usually not possible in a generic way. You will have to use platform dependent apstractions. I do it like this for AppData e.g., on Windows I detect the AppData/Roaming or AppData/Local, depending on the data I need to store, on other Platforms I create a folder ".myappname" in the userhome, and use this.
For the documents folder, you will have to read the registry. Before Windows Vista using the user.home propery + "/Documents" is not enought, because in other languages it might be "/Dokumente" (german) or something else. Just the registry has the real path to this folder.
On linux platforms it depends on the Desktop environment. You will just have to try it out. Gnome and KDE use different places to store the Documents folder, IMHO. And if you just use FVWM there, there is no predefined place for docs except the user.home property, what is a good fallback.
Assuming this is an application which requires installation, Why not ask the user to specify the location during installation. Generate a run script using this information which would set the appropriate environment variables. As a norm the user is not expected to run the java command!
When the user starts the application using this run script, the application can read the environment variables.
Alternatively, create a jar file with configuration files. Read the config files using Classloader's getResourceAsStream. As long as the configuration jar is under the classpath you can access the files. This also has the added advantage of hiding the configuration from accidental modification. This should work for folders as well (if the config needs to be modified by the user).
Ask the user, somehow, where they want to save data to, or use the current directory (simple relative paths) and provide appropriate instructions for set up. One means of "asking" is having a property that can be set via the command line.
Don't just pollute the user's home directory with your application's stuff - how do you know how they like their document tree organized?
I am absolutely fed up with *nix oriented programs dropping their little config files and data folders into the root of my documents folder.
What is wrong with hardcoding a way to get the path depending on the users operating system?
There can be large variances and OS's work differently with different names.
Simply on launch find the path of the documents folder based on their OS and continue to reference that path wherever it is needed.

Categories