I seem to be having trouble storing Java preferences using a Jython script. If in Jython 2.5 beta I use:
clazz = Class.forName('mypackage.myclass')
prefs = Preferences.userNodeForPackage(clazz);
# or Preferences.userRoot()
prefs.put('propertyname', 'yes')
The preferences are not stored. If I then add:
prefs.flush()
I get
java.util.prefs.BackingStoreException: Couldn't get file lock.
I am currently running this on Linux and Unix using Java 1.6. I'm hoping that I'm missing something obvious, since my Java applications can successfully use java.util.prefs.Preferences on the same system.
Any help would be greatly appreciated.
In the comments on your question and the answer you state that it tries to write /etc/.java/.systemPrefs. I don't think that's actually right.
clazz = Class.forName('mypackage.myclass')
prefs = Preferences.userNodeForPackage(clazz);
# or Preferences.userRoot()
prefs.put('propertyname', 'yes')
You are using Preferences.userNodeForPackage, so you will get the .userPrefs.
These are located at /home/[user]/.java and should be writable.
With the systemPrefs you can get permission problems on linux. The preferences are stored in /etc/.java/.systemPrefs by default. If this directory isn't available(if you just copied the jre onto your system for example), the FileSystemPreferences class used to write
the preferences falls back to [java.home]/.systemPrefs.
To call prefs.flush() shouldn't be necessary, since the preferences are saved in a predefined interval and when your program terminates.
This seemed relevant.
Could it simply be that a file is not created or the owner on the file has insufficient permissions? Or something like that?
Related
I have a Java application that reads from the Preferences by using:
Preferences prefs = Preferences.userNodeForPackage(MyClass.class);
prefs.get((String)key, "");
On a fresh Windows 8 machine this fails with:
WARNING: Could not open/create prefs root node Software\JavaSoft\Prefs
at root 0x80000002. Windows RegCreateKeyEx(...) returned error code 5.
Error code 5 is access denied.
I can't find anything I'm doing wrong. Google and SO searches give old results relating only to Windows Vista/7 where one was wrongly using systemRoot (How can I write System preferences with Java? Can I invoke UAC?).
The error can be "cured" by creating HKLM/Software/JavaSoft/Prefs and setting permissions to HKLM/Software/JavaSoft as mentioned here Java: java.util.Preferences Failing. But this is not something I can require my users to do when they install the program.
So I'm looking for a better solution. My last ditch effort is to simply write to file but I'd like to avoid that. This also seems related I'm trying to use Java Prefences from XML WITHOUT using Windows registry, but I see a Registry-related message but it was down voted without an answer.
At current I suspect a Win8 JVM bug...
Questions
Does any one know of a solution that doesn't involve writing files?
Why does the same code work perfectly fine in Windows 7 but fails miserably in Windows 8?
I recently started noticing a same warning and thought it means that registry cannot be written. But upon closer inspection I noticed that all preferences where successfully updated in HKEY_CURRENT_USER anyways. So I got curious why I'm seeing this warning.
It turned out that the culprit is this static member variable: WindowsPreferences.systemRoot
Looks like Java tries to initialize WindowsPreferences.systemRoot just in case it is used later on by the program, and that initialization obviously fails if the program is not ran as administrator.
Since you're using Preferences.userNodeForPackage(), you will never need the systemRoot, therefore you can safely ignore that warning.
Of course, this is a horrible practice that Java tries to initialize systemRoot when it's not requested.
Update: I tested this problem in various Java versions and concluded that this bug was introduced in Java 1.7.0_21. It worked fine in Java 1.7.0_17 simply because the installer of that version would create the "Pref" folder in registry! Of course even in that version if you were to delete "Pref" from registry then it would stop working, so it was a silly solution on the part of Oracle to begin with. I will fill a bug report.
Update 2: The warning message is not a bug. It seem to be the intended behavior: http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6809488
I need to create a persistent storage in my Java app so all users can access it. So I was studying about java.util.prefs.Preferences and using systemRoot() works fine to me on Windows, saving data at Register.
But I'm really facing some problems on Linux (Ubuntu). I want to use a directory that other of our apps already uses: /usr/share/.
So, I'm trying to redirect systemRoot default directory to /usr/share at runtime. Here's my code:
System.setProperty("java -Djava.util.prefs.systemRoot", "/usr/share/myfolder");
Preferences pref = Preferences.systemRoot().node("/usr/share/myfolder");
According to this site, I have to create .systemPrefs folder before execute this command line and its implicit that systemRoot() will use it.
When I execute my program, I get the following WARNING:
java.util.prefs.FileSystemPreferences syncWorld
WARNING Couldn't flush system prefs: java.util.prefs.BackingStoreException: /etc/.java/.systemPrefs/usr create failed.
So I'm assuming that System.setProperty isn't working. Any suggestion?
Thanks in advance!
This is a really pesky issue Java running on *nix based servers.
I was able to solve it by using the following vm args:
-Djava.util.prefs.userRoot=/opt/apache-tomcat-7.0.50/uprefs -Djava.util.prefs.systemRoot=/opt/apache-tomcat-7.0.50/sprefs
One important note though on the systemRoot path is to create a sub-folder within it named .systemPrefs or it will not work.
Also, don't forget to chown -R these directories to the user running the java application (in my case it was tomcat).
Bimalesh suggested that instead of
System.setProperty("java -Djava.util.prefs.systemRoot", "/usr/share/myfolder"), that you say
System.setProperty("-Djava.util.prefs.systemRoot", "/usr/share/myfolder").
But the name of the property that you are trying to set is java.util.prefs.systemRoot, and not -Djava.util.prefs.systemRoot, so you should do
System.setProperty("java.util.prefs.systemRoot", "/usr/share/myfolder");
If that doesn't work, try adding the "-D" switch to the command line that starts your program. That is where
java -D... should go. The command would start with
java -Djava.util.prefs.systemRoot=/usr/share/myfolder
In a Linux system, the System root preference node will be under /etc. This is due to history, and is a standard that is regulated by the Linux Standard Base. Any non-system preferences can go in other locations, but it is a violation of the design of the operating system to have system preference go elsewhere.
Odds are your define is ineffective in a Linux system because it fails to start at /etc. Apparently something in the Java code defers to the specification of the operating system over your decision to re-base the preference root.
Typically such files are protected against modification by not being world (or even most user) writeable. This means that for users to have access to Preferences, they should go under
Preferences.userRoot()
Which will place them in hidden directories just off their home directory (where they will have modification privileges).
If your want any user to read any other user's preferences (the description sounds like you might) then you will need to have an installer that runs as a sufficiently authorized user (typically root) to make the required directory under /etc and change it's permissions to be world writeable.
Typically files under /etc are not world writable as users changing other's user's setting is then possible, and considered a type of security breach of the user's expected environment. For example, a careless employee (or a disgruntled one) could wipe out all other user's preferences in one stroke.
In Linux, I'll usually put user configuration files in $HOME/.myapp and in Windows I'll use APPDATA. So far so good.
What about non-user specific configuration? In linux, I'd put it into /etc. Is there an equivalent in Windows? Please note I would like to have the service running before any user logs in. Also, in case it plays a role, I'm developing in Java.
Alternatively: I approaching this the wrong way?
You could use ALLUSERPROFILES as a base directory. This environment variable resolves to the C:\PROGRAMDATA folder in Windows7. Of course you need to add a specific folder for your applications
In summary, you should use the known folder: ProgramData.
To avoid hard coding of paths (and hence why I'm not providing them here) you should always retrieve the value via one of the following methods:
The %PROGRAMDATA% environment variable (you can also use %ALLUSERSPROFILE% but I consider %PROGRAMDATA% more meaningful)
For unmanaged code use SHGetKnownFolderPath, passing the FOLDERID_ProgramData.
For managed code use System.Environment.GetFolderPath, passing CommonApplicationData.
This folder is not writeable by non-admins, so depending on your requirements you'll want to create a directory for your program and set the ACLs you need at install time.
Some good information on this topic is provided in the blog post: "Where Should I Write Program Data Instead of Program Files".
For those interested in using other Known Folders, MSDN provides extensive documentation.
In Windows most "program files" for an app go in C:\Program Files\MyApp. The environment variable would be %ProgramFiles%\MyApp.
I have a program, written in Java, which originally used its directory in Program Files to write files accessible to all users of this program. This required our users to run as administrator all the time. In an effort to alleviate that, we decided to move files which needed to be written during regular usage to the ProgramData folder using the %ALLUSERSPROFILE% environment variable. Using a subfolder in this directory for our application works great if it is designated as writable during the installation process, which works fine using NSIS.
The problem comes with upgrading existing users. The Java File API provides setWritable but this does not appear to work after testing on development machines. It looks as though the new file API with Java 7 would solve this problem, but with no release date on the horizon I would rather not wait.
It seems the simplest solution would be to use JNA to call the appropriate Windows API call to set this directory writable. Since upgrading the software necessitates admin rights, similar to installing, it should let this change go through fine. However, I'm unsure where to start, having never used JNA before or the Windows API. Suggestions as to which Windows library to load and what functions to call would be appreciated, especially if someone has encountered a similar problem before.
Well, I'm glad you gave some background...You could use JNA, but the easier way would be to execute a call to the command-line utility cacls. It's included by default in Windows XP installations, I believe, so it should do the trick for you. Try Runtime.getRuntime().exec("C:\\Windows\\System32\\cacls.exe"+options)
Check out the documentation here -> http://technet.microsoft.com/en-us/library/bb490872.aspx
I use the follow line:
Runtime.getRuntime().exec( "C:\\Windows\\System32\\icacls.exe \"%ProgramData%\my application" /grant *S-1-5-32-545:(OI)(CI)(W,M)" );
S-1-5-32-545 is the SID for BUILTIN\Users because the name work only on English systems. https://support.microsoft.com/de-de/kb/163846
This give the BUILTIN\Users write access to all files in the given directory independent which user has create it.
when running a Java application as service with the user 'LocalService', the temp directory ("java.io.tmpdir") points to 'c:/windows/temp' (for example).
Running a Java application normally gives 'c:/documents and settings/user/local settings/temp' instead.
How can I determine the user independent temp folder 'c:/windows/temp' when my application runs normally?
Thanks and greetings,
GHad
You could:
as suggested by St Shadow, rely on some environment variable such as %WINDIR% or %SYSTEMROOT%, append "\temp" on the end, and use this.
or pass in this value to your app as a variable using a commandline argument to the JVM, e.g.
-Dmytempdir=%WINDIR%\temp
As you mention, the user could change the values of either of these
variables using System -> Environment Variables, but I don't think they'd have any affect on the system until a reboot anyway (...?).
Or...
try and read the value from the registry using some nasty use of java.util.prefs.Preferences or something -- On my machine it looks like the value you're after is held in HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment\TEMP.
This would likely have to be quite messy and I don't know if the Preferences class will get you access to the key you'd need to read. Again, there's not much you could do about the user changing the registry value either, if they really wanted to, but again I doubt it would have any affect until after a reboot, and would probably have an impact on more than just your app.
Cheers,
--J
I'm not sure there is a 'clean' way of doing this.
In this situation, I would probably create a directory specifically for the Java app and refer to it in a properties file.
Java system property java.io.tmpdir just point to system variable %TMP%.
For normal user %TMP% points to %HOMEPATH%\temp, for other account - can be another path.
You can try to use %SYSTEMROOT%\temp instead of java.io.tmpdir - %SYSTEMROOT% points to directory, where windows is installed.
You can simply create your own temporary folder, add use the deleteOnExit() method to ensure this folder will be removed at the exit of your application.