com.asprise.imaging.core.prefs.FileSystemPreferences Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of java-scanner-access-twain Show documentation
Show all versions of java-scanner-access-twain Show documentation
Acquire images from and have total control on almost all kinds of scanners on both Windows 32bit and 64bit.
/**********************************************************************************************
*
* Asprise Scanning and Imaging API - http://asprise.com/document-scanner-image-pdf/java-scanning-api-overview.html
* Copyright (C) 1998-2018. Asprise Inc.
*
* This file is licensed under the GNU Affero General Public License version 3 as published by
* the Free Software Foundation.
*
* Unless required by applicable law or agreed to in writing, software distributed under the
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions
* and limitations under the License.
*
* You should have received a copy of the GNU Affero General Public License. If not, please
* visit .
*
**********************************************************************************************/
package com.asprise.imaging.core.prefs;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.TreeMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.prefs.AbstractPreferences;
import java.util.prefs.BackingStoreException;
import java.util.prefs.InvalidPreferencesFormatException;
import java.util.prefs.Preferences;
class FileSystemPreferences extends AbstractPreferences {
private static final int SYNC_INTERVAL = Math.max(1,
Integer.parseInt(String.valueOf(
AccessController.doPrivileged(
new sun.security.action.GetPropertyAction(
"java.util.prefs.syncInterval", "30")))));
private static Logger _logger;
private static Logger getLogger() {
if(_logger == null) {
_logger = Logger.getLogger("asprise.FileSystemPreferences");
_logger.setLevel(Level.SEVERE);
}
return _logger;
}
private static File systemRootDir;
private static boolean isSystemRootWritable;
private static File userRootDir;
private static boolean isUserRootWritable;
static Preferences userRoot = null;
static synchronized Preferences getUserRoot() {
if (userRoot == null) {
setupUserRoot();
userRoot = new FileSystemPreferences(true);
}
return userRoot;
}
private static void setupUserRoot() {
AccessController.doPrivileged(new PrivilegedAction() {
public Void run() {
userRootDir =
new File(System.getProperty("java.util.prefs.userRoot",
System.getProperty("user.home")), ".java/.userPrefs");
if (!userRootDir.exists()) {
if (userRootDir.mkdirs()) {
try {
chmod(userRootDir.getCanonicalPath(), USER_RWX);
} catch (IOException e) {
getLogger().warning("Could not change permissions" +
" on userRoot directory. ");
}
getLogger().info("Created user preferences directory.");
}
else
getLogger().warning("Couldn't create user preferences" +
" directory. User preferences are unusable.");
}
isUserRootWritable = userRootDir.canWrite();
String USER_NAME = System.getProperty("user.name");
userLockFile = new File (userRootDir,".user.lock." + USER_NAME);
userRootModFile = new File (userRootDir,
".userRootModFile." + USER_NAME);
if (!userRootModFile.exists())
try {
userRootModFile.createNewFile();
int result = chmod(userRootModFile.getCanonicalPath(),
USER_READ_WRITE);
if (result !=0)
getLogger().warning("Problem creating userRoot " +
"mod file. Chmod failed on " +
userRootModFile.getCanonicalPath() +
" Unix error code " + result);
} catch (IOException e) {
getLogger().warning(e.toString());
}
userRootModTime = userRootModFile.lastModified();
return null;
}
});
}
static Preferences systemRoot;
static synchronized Preferences getSystemRoot() {
if (systemRoot == null) {
setupSystemRoot();
systemRoot = new FileSystemPreferences(false);
}
return systemRoot;
}
private static void setupSystemRoot() {
AccessController.doPrivileged(new PrivilegedAction() {
public Void run() {
String systemPrefsDirName =
System.getProperty("java.util.prefs.systemRoot","/etc/.java");
systemRootDir =
new File(systemPrefsDirName, ".systemPrefs");
if (!systemRootDir.exists()) {
systemRootDir =
new File(System.getProperty("java.home"),
".systemPrefs");
if (!systemRootDir.exists()) {
if (systemRootDir.mkdirs()) {
getLogger().info(
"Created system preferences directory "
+ "in java.home.");
try {
chmod(systemRootDir.getCanonicalPath(),
USER_RWX_ALL_RX);
} catch (IOException e) {
}
} else {
getLogger().warning("Could not create "
+ "system preferences directory. System "
+ "preferences are unusable.");
}
}
}
isSystemRootWritable = systemRootDir.canWrite();
systemLockFile = new File(systemRootDir, ".system.lock");
systemRootModFile =
new File (systemRootDir,".systemRootModFile");
if (!systemRootModFile.exists() && isSystemRootWritable)
try {
systemRootModFile.createNewFile();
int result = chmod(systemRootModFile.getCanonicalPath(),
USER_RW_ALL_READ);
if (result !=0)
getLogger().warning("Chmod failed on " +
systemRootModFile.getCanonicalPath() +
" Unix error code " + result);
} catch (IOException e) { getLogger().warning(e.toString());
}
systemRootModTime = systemRootModFile.lastModified();
return null;
}
});
}
private static final int USER_READ_WRITE = 0600;
private static final int USER_RW_ALL_READ = 0644;
private static final int USER_RWX_ALL_RX = 0755;
private static final int USER_RWX = 0700;
static File userLockFile;
static File systemLockFile;
private static int userRootLockHandle = 0;
private static int systemRootLockHandle = 0;
private final File dir;
private final File prefsFile;
private final File tmpFile;
private static File userRootModFile;
private static boolean isUserRootModified = false;
private static long userRootModTime;
private static File systemRootModFile;
private static boolean isSystemRootModified = false;
private static long systemRootModTime;
private Map prefsCache = null;
private long lastSyncTime = 0;
private static final int EAGAIN = 11;
private static final int EACCES = 13;
private static final int LOCK_HANDLE = 0;
private static final int ERROR_CODE = 1;
final List changeLog = new ArrayList();
private abstract class Change {
abstract void replay();
};
private class Put extends Change {
String key, value;
Put(String key, String value) {
this.key = key;
this.value = value;
}
void replay() {
prefsCache.put(key, value);
}
}
private class Remove extends Change {
String key;
Remove(String key) {
this.key = key;
}
void replay() {
prefsCache.remove(key);
}
}
private class NodeCreate extends Change {
void replay() {
}
}
NodeCreate nodeCreate = null;
private void replayChanges() {
for (int i = 0, n = changeLog.size(); i() {
public Void run() {
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
syncTimer.cancel();
syncWorld();
}
});
return null;
}
});
}
private static void syncWorld() {
Preferences userRt;
Preferences systemRt;
synchronized(FileSystemPreferences.class) {
userRt = userRoot;
systemRt = systemRoot;
}
try {
if (userRt != null)
userRt.flush();
} catch(BackingStoreException e) {
getLogger().warning("Couldn't flush user prefs: " + e);
}
try {
if (systemRt != null)
systemRt.flush();
} catch(BackingStoreException e) {
getLogger().warning("Couldn't flush system prefs: " + e);
}
}
private final boolean isUserNode;
private FileSystemPreferences(boolean user) {
super(null, "");
isUserNode = user;
dir = (user ? userRootDir: systemRootDir);
prefsFile = new File(dir, "prefs.xml");
tmpFile = new File(dir, "prefs.tmp");
}
private FileSystemPreferences(FileSystemPreferences parent, String name) {
super(parent, name);
isUserNode = parent.isUserNode;
dir = new File(parent.dir, dirName(name));
prefsFile = new File(dir, "prefs.xml");
tmpFile = new File(dir, "prefs.tmp");
AccessController.doPrivileged(new PrivilegedAction() {
public Void run() {
newNode = !dir.exists();
return null;
}
});
if (newNode) {
prefsCache = new TreeMap();
nodeCreate = new NodeCreate();
changeLog.add(nodeCreate);
}
}
public boolean isUserNode() {
return isUserNode;
}
protected void putSpi(String key, String value) {
initCacheIfNecessary();
changeLog.add(new Put(key, value));
prefsCache.put(key, value);
}
protected String getSpi(String key) {
initCacheIfNecessary();
return prefsCache.get(key);
}
protected void removeSpi(String key) {
initCacheIfNecessary();
changeLog.add(new Remove(key));
prefsCache.remove(key);
}
private void initCacheIfNecessary() {
if (prefsCache != null)
return;
try {
loadCache();
} catch(Exception e) {
prefsCache = new TreeMap();
}
}
private void loadCache() throws BackingStoreException {
try {
AccessController.doPrivileged(
new PrivilegedExceptionAction() {
public Void run() throws BackingStoreException {
Map m = new TreeMap();
long newLastSyncTime = 0;
try {
newLastSyncTime = prefsFile.lastModified();
FileInputStream fis = new FileInputStream(prefsFile);
XmlSupport.importMap(fis, m);
} catch(Exception e) {
if (e instanceof InvalidPreferencesFormatException) {
getLogger().warning("Invalid preferences format in "
+ prefsFile.getPath());
renameFile(prefsFile, new File(prefsFile.getParentFile(), "IncorrectFormatPrefs.xml"));
m = new TreeMap();
} else if (e instanceof FileNotFoundException) {
} else {
throw new BackingStoreException(e);
}
}
prefsCache = m;
lastSyncTime = newLastSyncTime;
return null;
}
});
} catch (PrivilegedActionException e) {
throw (BackingStoreException) e.getException();
}
}
private void writeBackCache() throws BackingStoreException {
try {
AccessController.doPrivileged(
new PrivilegedExceptionAction() {
public Void run() throws BackingStoreException {
try {
if (!dir.exists() && !dir.mkdirs())
throw new BackingStoreException(dir +
" create failed.");
FileOutputStream fos = new FileOutputStream(tmpFile);
XmlSupport.exportMap(fos, prefsCache);
if (!renameFile(tmpFile, prefsFile))
throw new BackingStoreException("Can't rename " +
tmpFile + " to " + prefsFile);
} catch(Exception e) {
if (e instanceof BackingStoreException)
throw (BackingStoreException)e;
throw new BackingStoreException(e);
}
return null;
}
});
} catch (PrivilegedActionException e) {
throw (BackingStoreException) e.getException();
}
}
protected String[] keysSpi() {
initCacheIfNecessary();
return prefsCache.keySet().toArray(new String[prefsCache.size()]);
}
protected String[] childrenNamesSpi() {
return AccessController.doPrivileged(
new PrivilegedAction() {
public String[] run() {
List result = new ArrayList();
File[] dirContents = dir.listFiles();
if (dirContents != null) {
for (int i = 0; i < dirContents.length; i++)
if (dirContents[i].isDirectory())
result.add(nodeName(dirContents[i].getName()));
}
return result.toArray(EMPTY_STRING_ARRAY);
}
});
}
private static final String[] EMPTY_STRING_ARRAY = new String[0];
protected AbstractPreferences childSpi(String name) {
return new FileSystemPreferences(this, name);
}
public void removeNode() throws BackingStoreException {
synchronized (isUserNode()? userLockFile: systemLockFile) {
if (!lockFile(false))
throw(new BackingStoreException("Couldn't get file lock."));
try {
super.removeNode();
} finally {
unlockFile();
}
}
}
protected void removeNodeSpi() throws BackingStoreException {
try {
AccessController.doPrivileged(
new PrivilegedExceptionAction() {
public Void run() throws BackingStoreException {
if (changeLog.contains(nodeCreate)) {
changeLog.remove(nodeCreate);
nodeCreate = null;
return null;
}
if (!dir.exists())
return null;
prefsFile.delete();
tmpFile.delete();
File[] junk = dir.listFiles();
if (junk.length != 0) {
getLogger().warning(
"Found extraneous files when removing node: "
+ Arrays.asList(junk));
for (int i=0; i() {
public Long run() {
long nmt;
if (isUserNode()) {
nmt = userRootModFile.lastModified();
isUserRootModified = userRootModTime == nmt;
} else {
nmt = systemRootModFile.lastModified();
isSystemRootModified = systemRootModTime == nmt;
}
return new Long(nmt);
}
});
try {
super.sync();
AccessController.doPrivileged(new PrivilegedAction() {
public Void run() {
if (isUserNode()) {
userRootModTime = newModTime.longValue() + 1000;
userRootModFile.setLastModified(userRootModTime);
} else {
systemRootModTime = newModTime.longValue() + 1000;
systemRootModFile.setLastModified(systemRootModTime);
}
return null;
}
});
} finally {
unlockFile();
}
}
}
protected void syncSpi() throws BackingStoreException {
try {
AccessController.doPrivileged(
new PrivilegedExceptionAction() {
public Void run() throws BackingStoreException {
syncSpiPrivileged();
return null;
}
});
} catch (PrivilegedActionException e) {
throw (BackingStoreException) e.getException();
}
}
private void syncSpiPrivileged() throws BackingStoreException {
if (isRemoved())
throw new IllegalStateException("Node has been removed");
if (prefsCache == null)
return;
long lastModifiedTime;
if ((isUserNode() ? isUserRootModified : isSystemRootModified)) {
lastModifiedTime = prefsFile.lastModified();
if (lastModifiedTime != lastSyncTime) {
loadCache();
replayChanges();
lastSyncTime = lastModifiedTime;
}
} else if (lastSyncTime != 0 && !dir.exists()) {
prefsCache = new TreeMap();
replayChanges();
}
if (!changeLog.isEmpty()) {
writeBackCache();
lastModifiedTime = prefsFile.lastModified();
if (lastSyncTime <= lastModifiedTime) {
lastSyncTime = lastModifiedTime + 1000;
prefsFile.setLastModified(lastSyncTime);
}
changeLog.clear();
}
}
public void flush() throws BackingStoreException {
if (isRemoved())
return;
sync();
}
protected void flushSpi() throws BackingStoreException {
}
private static boolean isDirChar(char ch) {
return ch > 0x1f && ch < 0x7f && ch != '/' && ch != '.' && ch != '_';
}
private static String dirName(String nodeName) {
StringBuilder sb = new StringBuilder(nodeName);
for(int i = 0; i < sb.length(); i++) {
char c = sb.charAt(i);
if( (c >= 0 && c <= 9)
|| (c >= 'a' && c <= 'z')
|| (c >= 'A' && c <= 'Z')
|| (c == '-' || c == '_' )
) {
} else {
sb.setCharAt(i, '_');
}
}
return sb.toString();
}
private static byte[] byteArray(String s) {
int len = s.length();
byte[] result = new byte[2*len];
for (int i=0, j=0; i>8);
result[j++] = (byte) c;
}
return result;
}
private static String nodeName(String dirName) {
if (dirName.charAt(0) != '_')
return dirName;
byte a[] = Base64.altBase64ToByteArray(dirName.substring(1));
StringBuffer result = new StringBuffer(a.length/2);
for (int i = 0; i < a.length; ) {
int highByte = a[i++] & 0xff;
int lowByte = a[i++] & 0xff;
result.append((char) ((highByte << 8) | lowByte));
}
return result.toString();
}
private boolean lockFile(boolean shared) throws SecurityException{
boolean usernode = isUserNode();
int[] result;
int errorCode = 0;
File lockFile = (usernode ? userLockFile : systemLockFile);
long sleepTime = INIT_SLEEP_TIME;
for (int i = 0; i < MAX_ATTEMPTS; i++) {
try {
int perm = (usernode? USER_READ_WRITE: USER_RW_ALL_READ);
result = lockFile0(lockFile.getCanonicalPath(), perm, shared);
errorCode = result[ERROR_CODE];
if (result[LOCK_HANDLE] != 0) {
if (usernode) {
userRootLockHandle = result[LOCK_HANDLE];
} else {
systemRootLockHandle = result[LOCK_HANDLE];
}
return true;
}
} catch(IOException e) {
}
try {
Thread.sleep(sleepTime);
} catch(InterruptedException e) {
checkLockFile0ErrorCode(errorCode);
return false;
}
sleepTime *= 2;
}
checkLockFile0ErrorCode(errorCode);
return false;
}
private void checkLockFile0ErrorCode (int errorCode)
throws SecurityException {
if (errorCode == EACCES)
throw new SecurityException("Could not lock " +
(isUserNode()? "User prefs." : "System prefs.") +
" Lock file access denied.");
if (errorCode != EAGAIN)
getLogger().warning("Could not lock " +
(isUserNode()? "User prefs. " : "System prefs.") +
" Unix error code " + errorCode + ".");
}
private static int[] lockFile0(String fileName, int permission, boolean shared) {
return new int[] {1, 0};
}
private static int unlockFile0(int lockHandle) {
return 0;
}
private static int chmod(String fileName, int permission) {
return 0;
}
private static int INIT_SLEEP_TIME = 50;
private static int MAX_ATTEMPTS = 5;
private void unlockFile() {
int result;
boolean usernode = isUserNode();
File lockFile = (usernode ? userLockFile : systemLockFile);
int lockHandle = ( usernode ? userRootLockHandle:systemRootLockHandle);
if (lockHandle == 0) {
getLogger().warning("Unlock: zero lockHandle for " +
(usernode ? "user":"system") + " preferences.)");
return;
}
result = unlockFile0(lockHandle);
if (result != 0) {
getLogger().warning("Could not drop file-lock on " +
(isUserNode() ? "user" : "system") + " preferences." +
" Unix error code " + result + ".");
if (result == EACCES)
throw new SecurityException("Could not unlock" +
(isUserNode()? "User prefs." : "System prefs.") +
" Lock file access denied.");
}
if (isUserNode()) {
userRootLockHandle = 0;
} else {
systemRootLockHandle = 0;
}
}
@Override
public boolean isRemoved() {
return super.isRemoved();
}
public Object getLock() {
return lock;
}
static boolean renameFile(File source, File target) {
if(System.getProperty("os.name").toLowerCase().contains("windows")) {
if(copyFile(source, target)) {
source.delete();
return true;
} else {
return false;
}
} else {
return source.renameTo(target);
}
}
static boolean copyFile(File source, File target) {
InputStream inputStream = null;
OutputStream outputStream = null;
try {
inputStream = new FileInputStream(source);
if(inputStream == null) {
return false;
}
outputStream = new FileOutputStream(target);
byte[] buffer = new byte[1024];
int len = inputStream.read(buffer);
while (len != -1) {
outputStream.write(buffer, 0, len);
len = inputStream.read(buffer);
}
return true;
} catch (Throwable t) {
return false;
} finally {
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
}
}
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
}
}
}
}
}