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.
Related
Locker Apps is a Folder Lock application, how can I lock files or folders on Windows using Java?
Here is what I tried:
File file = new File(file path);
file.setExecutable(false);
file.setWritable(false);
file.setReadable(false);
But only file.setwritable(false); works - I can't rewrite the file. Other methods do nothing to the file.
These methods are simply setting the file system access permissions for the file. In order to understand them, you need to understand the OS / file system access control rules.
For example, on Linux file.setWriteable(false) is equivalent to running chmod u-w file to clear the "owner write" access bit:
Note:
chmod can only change any permissions on the file if you are the owner of the file, or if you are running as root.
The owner write permission means that owner (or root) can execute the file, or not. If you are neither, then that permission does not affect you.
So there are at least two possible reasons why setWriteable may not be "working".
You are not executing your Java program as the file owner or root. In that case, setWriteable will return false. But note that you don't check the result!
You are not trying to write the file as the file's owner. In that case, the access but you just removed (in Java) does not affect you.
Solutions:
There is a newer / better API for setting file permissions in Java in the java.nio.file.Files class:
public static Path setPosixFilePermissions(
Path path,
Set<PosixFilePermission> perms)
throws IOException
This allows you to set / clear all avail POSIX file permissions in one call, and it with throw an exception if it can't for any reason.
Many file systems also support more sophisticated ACL mechanisms ....
HOWEVER
None of this is equivalent to the functionality provided by a File Locker app. Why? Because any attempt to block file access via file permissions or ACLs can trivially be reversed by someone with root access. Provided you know what it is doing at a technical level.
What the Windows "Folder Lock" app can apparently encrypt files or hide them. Files can be marked as hidden natively in Java 7 and later by setting the "dos:hidden" attribute; see https://stackoverflow.com/a/42816082/139985. It is probably also using permissions and ACLs to restrict access, that can be doing on Java too. It may also be doing other things. The documentation says (unhelpfully!):
Once the files are locked, it becomes protected in every possible way and can only be accessed through the Folder Lock security application.
That sounds like marketing rather than truth, and is almost certainly untrue. However figuring out what the app is actually doing, would require me to get a Windows machine, download and install the software, and then violate the license by attempting to reverse engineer it.
But note that the above method for "hiding" is Windows specific. On Linux / Mac OS you "hide" a file from some commands by making the first character of the file name a dot (".") character.
Is there a platform-independent way to get a path to store program data in Java?
This is surely a very basic question but I can't seem to find the answer anywhere. I am looking for a path to store user data such as user preferences or historical data input. On Windows we would normally store it in C:\Program Files\APPNAME, C:\Program Files (x86)\APPNAME or C:\ProgramData\APPNAME depending on the OS and architecture. On Unix we could store preferences in /etc/APPNAME or /opt/APPNAME depending on the context. On Mac we have a special cabinet to store program's data. In java, how do we get a location like this in a platform-independent way?
The system property user.home should be pretty standard across most desktop systems.
System.out.println(System.getProperty("user.home"));
Note that this is the user the Java process runs under - so in case of server-side Java process, you would need to store information for the users of your app in your own data structure, as your app's users are not known to the OS.
Regarding a system-wide storage location, you may need to detect the OS version and compute the path. Another problem is that you would most likely need to escalate privileges to write to a system-wide location.
Look to store settings in a (sub-)directory of user.home. Not only is it a place to which the app. would reasonably be expected to have read-write privileges, but is cross-platform.
The sub-directory might be based on the Fully Qualified name or package name of the class to prevent clashes. I.E.
package our.com.main;
Would be written to sub-directory our/com/main.
I am developing a java web application that needs to pass shell scripts to putty after user authentication. putty.exe should launch only if authentication is successful and if the script has begun running successfully.
Also, since different users might have installed putty in different locations on their systems. Is there any way to launch putty.exe without requiring the user to manually configure the path. Or is it possible to programmatically find the path and launch putty?
I will start by saying not having the user add putty to the path is most easily solved by creating a configuration file for each user, where one of the parameters will be the location of the putty executable. Properly handling this with default values and a dialogue box if putty can't be opened would be simple and familiar to most users.
Two simple situations could completely mess with how you do a search for the executable: the user renames the putty executable or the user has multiple versions of putty.
To avoid getting stumped by the first situation you are going to have to ask for the new name and somehow save it in a config.
To avoid getting stumped by the second you are going to have to ask for the version of putty they want, store that version, and somehow do version checking if all you want to do is look for putty.exe (maybe you have a file of the checksum for each version).
This is just as, if not more annoying to the user (and definitely more annoying to you) than just asking them to point to the executable. There are more ways that things could go wrong, as well.
Basically, it is possible to search for the executable but it would not save anyone any trouble and would only make more for you. Having the user configure the path is not very tricky, but if you want to avoid it then the easiest thing is to have per-user configuration files with the putty path saved in it by your program.
One way is by editing the PATH system variable of the user machines and add the full path of the Putty.exe location.
Another solution is to create a link that points to Putty.exe in a default folder in every user machine, so Java could access to this link w/o problems.
A third solution could be to ship the Putty.exe with your application installer. Putty.exe doesn't need custom DLLs to work (at least I haven't needed one yet).
Theoritically it is possible if you search through every directory on user's computer to find putty.exe. But practically, you should required the file to be put in some familiar directories or use an environment variable.
I agree with people above. Also in your application you can provide ability to user set putty.exe full path and store them in cookies.
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 SWT Java app that runs on Windows XP / Vista / 7 and Mac OS X. I'm currently saving a config file to:
System.getProperty("user.home") + filename
With the changes in security in Windows Vista and Windows 7 this doesn't seem to be the best place to save it anymore.
This file saves information such as registration key info and it is annoying for my users if the file can't be saved or is deleted.
Is there a better path I should use?
Also, what's the preferred path for per user application data on Mac OS X?
macos path for application data to be kept is "~/Library/Application Support" as per Apple documentation
What changes in security? I understand they prohibited writing in Program Files, I didn't know they forbid to write in user home.
It would be a serious compatibility break, I have a number of applications writing there, either directly a file, or in a folder ("hidden" at the Unix mode, ie. prefixed with a dot).
Now, it seems to be more "friendly" to write in Application Data folder as do a number of other applications (but rarely cross-platform applications which seem to use the previous solution...) but the exact location seems hard to find in Java, and would need a platform detection to do something else on other platforms.
An alternative seems to be to use the Preferences API, ie. java.util.prefs.Preferences.
Sun itself, with its java control panel, had the very same problem (bug 6487334): their control panel, running at different integrity level, could not both read/write to their deployment directories.
They moved it to c:\users\<username>\appdata\local, but had to not rely on System.getProperty("user.home") because to this day, it uses a registry KEY that can be set to incorrect value if windows is "tweaked": bug 6519127
So the question How to get local application data folder in Java?, using HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders\* is the right place to start looking for read/write access for your settings.
You can read it with, for instance, SWT Win32 Extension project.
The interest to keep your data within the user's homedir is that they will be part of the user's profile which can be a roaming profile, saved at logoff and restored at logon (used quite often on corporation's workstations)