/*
 * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package java.util.prefs;

import java.util.StringTokenizer;
import java.io.ByteArrayOutputStream;
import java.security.AccessController;
import java.security.PrivilegedAction;

import sun.util.logging.PlatformLogger;

Windows registry based implementation of Preferences. Preferences' systemRoot and userRoot are stored in HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Prefs and HKEY_CURRENT_USER\Software\JavaSoft\Prefs correspondingly.
Author: Konstantin Kladko
See Also:
Since:1.4
/** * Windows registry based implementation of {@code Preferences}. * {@code Preferences}' {@code systemRoot} and {@code userRoot} are stored in * {@code HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Prefs} and * {@code HKEY_CURRENT_USER\Software\JavaSoft\Prefs} correspondingly. * * @author Konstantin Kladko * @see Preferences * @see PreferencesFactory * @since 1.4 */
class WindowsPreferences extends AbstractPreferences { static { PrivilegedAction<Void> load = () -> { System.loadLibrary("prefs"); return null; }; AccessController.doPrivileged(load); }
Logger for error messages
/** * Logger for error messages */
private static PlatformLogger logger;
Windows registry path to Preferences's root nodes.
/** * Windows registry path to {@code Preferences}'s root nodes. */
private static final byte[] WINDOWS_ROOT_PATH = stringToByteArray("Software\\JavaSoft\\Prefs");
Windows handles to HKEY_CURRENT_USER and HKEY_LOCAL_MACHINE hives.
/** * Windows handles to {@code HKEY_CURRENT_USER} and * {@code HKEY_LOCAL_MACHINE} hives. */
private static final int HKEY_CURRENT_USER = 0x80000001; private static final int HKEY_LOCAL_MACHINE = 0x80000002;
Mount point for Preferences' user root.
/** * Mount point for {@code Preferences}' user root. */
private static final int USER_ROOT_NATIVE_HANDLE = HKEY_CURRENT_USER;
Mount point for Preferences' system root.
/** * Mount point for {@code Preferences}' system root. */
private static final int SYSTEM_ROOT_NATIVE_HANDLE = HKEY_LOCAL_MACHINE;
Maximum byte-encoded path length for Windows native functions, ending null character not included.
/** * Maximum byte-encoded path length for Windows native functions, * ending {@code null} character not included. */
private static final int MAX_WINDOWS_PATH_LENGTH = 256;
User root node.
/** * User root node. */
private static volatile Preferences userRoot; static Preferences getUserRoot() { Preferences root = userRoot; if (root == null) { synchronized (WindowsPreferences.class) { root = userRoot; if (root == null) { root = new WindowsPreferences(USER_ROOT_NATIVE_HANDLE, WINDOWS_ROOT_PATH); userRoot = root; } } } return root; }
System root node.
/** * System root node. */
private static volatile Preferences systemRoot; static Preferences getSystemRoot() { Preferences root = systemRoot; if (root == null) { synchronized (WindowsPreferences.class) { root = systemRoot; if (root == null) { root = new WindowsPreferences(SYSTEM_ROOT_NATIVE_HANDLE, WINDOWS_ROOT_PATH); systemRoot = root; } } } return root; } /* Windows error codes. */ private static final int ERROR_SUCCESS = 0; private static final int ERROR_FILE_NOT_FOUND = 2; private static final int ERROR_ACCESS_DENIED = 5; /* Constants used to interpret returns of native functions */ private static final int NATIVE_HANDLE = 0; private static final int ERROR_CODE = 1; private static final int SUBKEYS_NUMBER = 0; private static final int VALUES_NUMBER = 2; private static final int MAX_KEY_LENGTH = 3; private static final int MAX_VALUE_NAME_LENGTH = 4; private static final int DISPOSITION = 2; private static final int REG_CREATED_NEW_KEY = 1; private static final int REG_OPENED_EXISTING_KEY = 2; private static final int NULL_NATIVE_HANDLE = 0; /* Windows security masks */ private static final int DELETE = 0x10000; private static final int KEY_QUERY_VALUE = 1; private static final int KEY_SET_VALUE = 2; private static final int KEY_CREATE_SUB_KEY = 4; private static final int KEY_ENUMERATE_SUB_KEYS = 8; private static final int KEY_READ = 0x20019; private static final int KEY_WRITE = 0x20006; private static final int KEY_ALL_ACCESS = 0xf003f;
Initial time between registry access attempts, in ms. The time is doubled after each failing attempt (except the first).
/** * Initial time between registry access attempts, in ms. The time is doubled * after each failing attempt (except the first). */
private static int INIT_SLEEP_TIME = 50;
Maximum number of registry access attempts.
/** * Maximum number of registry access attempts. */
private static int MAX_ATTEMPTS = 5;
BackingStore availability flag.
/** * BackingStore availability flag. */
private boolean isBackingStoreAvailable = true;
Java wrapper for Windows registry API RegOpenKey()
/** * Java wrapper for Windows registry API RegOpenKey() */
private static native long[] WindowsRegOpenKey(long hKey, byte[] subKey, int securityMask);
Retries RegOpenKey() MAX_ATTEMPTS times before giving up.
/** * Retries RegOpenKey() MAX_ATTEMPTS times before giving up. */
private static long[] WindowsRegOpenKey1(long hKey, byte[] subKey, int securityMask) { long[] result = WindowsRegOpenKey(hKey, subKey, securityMask); if (result[ERROR_CODE] == ERROR_SUCCESS) { return result; } else if (result[ERROR_CODE] == ERROR_FILE_NOT_FOUND) { logger().warning("Trying to recreate Windows registry node " + byteArrayToString(subKey) + " at root 0x" + Long.toHexString(hKey) + "."); // Try recreation long handle = WindowsRegCreateKeyEx(hKey, subKey)[NATIVE_HANDLE]; WindowsRegCloseKey(handle); return WindowsRegOpenKey(hKey, subKey, securityMask); } else if (result[ERROR_CODE] != ERROR_ACCESS_DENIED) { long sleepTime = INIT_SLEEP_TIME; for (int i = 0; i < MAX_ATTEMPTS; i++) { try { Thread.sleep(sleepTime); } catch(InterruptedException e) { return result; } sleepTime *= 2; result = WindowsRegOpenKey(hKey, subKey, securityMask); if (result[ERROR_CODE] == ERROR_SUCCESS) { return result; } } } return result; }
Java wrapper for Windows registry API RegCloseKey()
/** * Java wrapper for Windows registry API RegCloseKey() */
private static native int WindowsRegCloseKey(long hKey);
Java wrapper for Windows registry API RegCreateKeyEx()
/** * Java wrapper for Windows registry API RegCreateKeyEx() */
private static native long[] WindowsRegCreateKeyEx(long hKey, byte[] subKey);
Retries RegCreateKeyEx() MAX_ATTEMPTS times before giving up.
/** * Retries RegCreateKeyEx() MAX_ATTEMPTS times before giving up. */
private static long[] WindowsRegCreateKeyEx1(long hKey, byte[] subKey) { long[] result = WindowsRegCreateKeyEx(hKey, subKey); if (result[ERROR_CODE] == ERROR_SUCCESS) { return result; } else { long sleepTime = INIT_SLEEP_TIME; for (int i = 0; i < MAX_ATTEMPTS; i++) { try { Thread.sleep(sleepTime); } catch(InterruptedException e) { return result; } sleepTime *= 2; result = WindowsRegCreateKeyEx(hKey, subKey); if (result[ERROR_CODE] == ERROR_SUCCESS) { return result; } } } return result; }
Java wrapper for Windows registry API RegDeleteKey()
/** * Java wrapper for Windows registry API RegDeleteKey() */
private static native int WindowsRegDeleteKey(long hKey, byte[] subKey);
Java wrapper for Windows registry API RegFlushKey()
/** * Java wrapper for Windows registry API RegFlushKey() */
private static native int WindowsRegFlushKey(long hKey);
Retries RegFlushKey() MAX_ATTEMPTS times before giving up.
/** * Retries RegFlushKey() MAX_ATTEMPTS times before giving up. */
private static int WindowsRegFlushKey1(long hKey) { int result = WindowsRegFlushKey(hKey); if (result == ERROR_SUCCESS) { return result; } else { long sleepTime = INIT_SLEEP_TIME; for (int i = 0; i < MAX_ATTEMPTS; i++) { try { Thread.sleep(sleepTime); } catch(InterruptedException e) { return result; } sleepTime *= 2; result = WindowsRegFlushKey(hKey); if (result == ERROR_SUCCESS) { return result; } } } return result; }
Java wrapper for Windows registry API RegQueryValueEx()
/** * Java wrapper for Windows registry API RegQueryValueEx() */
private static native byte[] WindowsRegQueryValueEx(long hKey, byte[] valueName);
Java wrapper for Windows registry API RegSetValueEx()
/** * Java wrapper for Windows registry API RegSetValueEx() */
private static native int WindowsRegSetValueEx(long hKey, byte[] valueName, byte[] value);
Retries RegSetValueEx() MAX_ATTEMPTS times before giving up.
/** * Retries RegSetValueEx() MAX_ATTEMPTS times before giving up. */
private static int WindowsRegSetValueEx1(long hKey, byte[] valueName, byte[] value) { int result = WindowsRegSetValueEx(hKey, valueName, value); if (result == ERROR_SUCCESS) { return result; } else { long sleepTime = INIT_SLEEP_TIME; for (int i = 0; i < MAX_ATTEMPTS; i++) { try { Thread.sleep(sleepTime); } catch(InterruptedException e) { return result; } sleepTime *= 2; result = WindowsRegSetValueEx(hKey, valueName, value); if (result == ERROR_SUCCESS) { return result; } } } return result; }
Java wrapper for Windows registry API RegDeleteValue()
/** * Java wrapper for Windows registry API RegDeleteValue() */
private static native int WindowsRegDeleteValue(long hKey, byte[] valueName);
Java wrapper for Windows registry API RegQueryInfoKey()
/** * Java wrapper for Windows registry API RegQueryInfoKey() */
private static native long[] WindowsRegQueryInfoKey(long hKey);
Retries RegQueryInfoKey() MAX_ATTEMPTS times before giving up.
/** * Retries RegQueryInfoKey() MAX_ATTEMPTS times before giving up. */
private static long[] WindowsRegQueryInfoKey1(long hKey) { long[] result = WindowsRegQueryInfoKey(hKey); if (result[ERROR_CODE] == ERROR_SUCCESS) { return result; } else { long sleepTime = INIT_SLEEP_TIME; for (int i = 0; i < MAX_ATTEMPTS; i++) { try { Thread.sleep(sleepTime); } catch(InterruptedException e) { return result; } sleepTime *= 2; result = WindowsRegQueryInfoKey(hKey); if (result[ERROR_CODE] == ERROR_SUCCESS) { return result; } } } return result; }
Java wrapper for Windows registry API RegEnumKeyEx()
/** * Java wrapper for Windows registry API RegEnumKeyEx() */
private static native byte[] WindowsRegEnumKeyEx(long hKey, int subKeyIndex, int maxKeyLength);
Retries RegEnumKeyEx() MAX_ATTEMPTS times before giving up.
/** * Retries RegEnumKeyEx() MAX_ATTEMPTS times before giving up. */
private static byte[] WindowsRegEnumKeyEx1(long hKey, int subKeyIndex, int maxKeyLength) { byte[] result = WindowsRegEnumKeyEx(hKey, subKeyIndex, maxKeyLength); if (result != null) { return result; } else { long sleepTime = INIT_SLEEP_TIME; for (int i = 0; i < MAX_ATTEMPTS; i++) { try { Thread.sleep(sleepTime); } catch(InterruptedException e) { return result; } sleepTime *= 2; result = WindowsRegEnumKeyEx(hKey, subKeyIndex, maxKeyLength); if (result != null) { return result; } } } return result; }
Java wrapper for Windows registry API RegEnumValue()
/** * Java wrapper for Windows registry API RegEnumValue() */
private static native byte[] WindowsRegEnumValue(long hKey, int valueIndex, int maxValueNameLength);
Retries RegEnumValueEx() MAX_ATTEMPTS times before giving up.
/** * Retries RegEnumValueEx() MAX_ATTEMPTS times before giving up. */
private static byte[] WindowsRegEnumValue1(long hKey, int valueIndex, int maxValueNameLength) { byte[] result = WindowsRegEnumValue(hKey, valueIndex, maxValueNameLength); if (result != null) { return result; } else { long sleepTime = INIT_SLEEP_TIME; for (int i = 0; i < MAX_ATTEMPTS; i++) { try { Thread.sleep(sleepTime); } catch(InterruptedException e) { return result; } sleepTime *= 2; result = WindowsRegEnumValue(hKey, valueIndex, maxValueNameLength); if (result != null) { return result; } } } return result; }
Constructs a WindowsPreferences node, creating underlying Windows registry node and all its Windows parents, if they are not yet created. Logs a warning message, if Windows Registry is unavailable.
/** * Constructs a {@code WindowsPreferences} node, creating underlying * Windows registry node and all its Windows parents, if they are not yet * created. * Logs a warning message, if Windows Registry is unavailable. */
private WindowsPreferences(WindowsPreferences parent, String name) { super(parent, name); long parentNativeHandle = parent.openKey(KEY_CREATE_SUB_KEY, KEY_READ); if (parentNativeHandle == NULL_NATIVE_HANDLE) { // if here, openKey failed and logged isBackingStoreAvailable = false; return; } long[] result = WindowsRegCreateKeyEx1(parentNativeHandle, toWindowsName(name)); if (result[ERROR_CODE] != ERROR_SUCCESS) { logger().warning("Could not create windows registry node " + byteArrayToString(windowsAbsolutePath()) + " at root 0x" + Long.toHexString(rootNativeHandle()) + ". Windows RegCreateKeyEx(...) returned error code " + result[ERROR_CODE] + "."); isBackingStoreAvailable = false; return; } newNode = (result[DISPOSITION] == REG_CREATED_NEW_KEY); closeKey(parentNativeHandle); closeKey(result[NATIVE_HANDLE]); }
Constructs a root node creating the underlying Windows registry node and all of its parents, if they have not yet been created. Logs a warning message, if Windows Registry is unavailable.
Params:
  • rootNativeHandle – Native handle to one of Windows top level keys.
  • rootDirectory – Path to root directory, as a byte-encoded string.
/** * Constructs a root node creating the underlying * Windows registry node and all of its parents, if they have not yet been * created. * Logs a warning message, if Windows Registry is unavailable. * @param rootNativeHandle Native handle to one of Windows top level keys. * @param rootDirectory Path to root directory, as a byte-encoded string. */
private WindowsPreferences(long rootNativeHandle, byte[] rootDirectory) { super(null, ""); long[] result = WindowsRegCreateKeyEx1(rootNativeHandle, rootDirectory); if (result[ERROR_CODE] != ERROR_SUCCESS) { logger().warning("Could not open/create prefs root node " + byteArrayToString(windowsAbsolutePath()) + " at root 0x" + Long.toHexString(rootNativeHandle()) + ". Windows RegCreateKeyEx(...) returned error code " + result[ERROR_CODE] + "."); isBackingStoreAvailable = false; return; } // Check if a new node newNode = (result[DISPOSITION] == REG_CREATED_NEW_KEY); closeKey(result[NATIVE_HANDLE]); }
Returns Windows absolute path of the current node as a byte array. Java "/" separator is transformed into Windows "\".
See Also:
  • absolutePath.absolutePath()
/** * Returns Windows absolute path of the current node as a byte array. * Java "/" separator is transformed into Windows "\". * @see Preferences#absolutePath() */
private byte[] windowsAbsolutePath() { ByteArrayOutputStream bstream = new ByteArrayOutputStream(); bstream.write(WINDOWS_ROOT_PATH, 0, WINDOWS_ROOT_PATH.length-1); StringTokenizer tokenizer = new StringTokenizer(absolutePath(), "/"); while (tokenizer.hasMoreTokens()) { bstream.write((byte)'\\'); String nextName = tokenizer.nextToken(); byte[] windowsNextName = toWindowsName(nextName); bstream.write(windowsNextName, 0, windowsNextName.length-1); } bstream.write(0); return bstream.toByteArray(); }
Opens current node's underlying Windows registry key using a given security mask.
Params:
  • securityMask – Windows security mask.
See Also:
Returns:Windows registry key's handle.
/** * Opens current node's underlying Windows registry key using a * given security mask. * @param securityMask Windows security mask. * @return Windows registry key's handle. * @see #openKey(byte[], int) * @see #openKey(int, byte[], int) * @see #closeKey(int) */
private long openKey(int securityMask) { return openKey(securityMask, securityMask); }
Opens current node's underlying Windows registry key using a given security mask.
Params:
  • mask1 – Preferred Windows security mask.
  • mask2 – Alternate Windows security mask.
See Also:
Returns:Windows registry key's handle.
/** * Opens current node's underlying Windows registry key using a * given security mask. * @param mask1 Preferred Windows security mask. * @param mask2 Alternate Windows security mask. * @return Windows registry key's handle. * @see #openKey(byte[], int) * @see #openKey(int, byte[], int) * @see #closeKey(int) */
private long openKey(int mask1, int mask2) { return openKey(windowsAbsolutePath(), mask1, mask2); }
Opens Windows registry key at a given absolute path using a given security mask.
Params:
  • windowsAbsolutePath – Windows absolute path of the key as a byte-encoded string.
  • mask1 – Preferred Windows security mask.
  • mask2 – Alternate Windows security mask.
See Also:
Returns:Windows registry key's handle.
/** * Opens Windows registry key at a given absolute path using a given * security mask. * @param windowsAbsolutePath Windows absolute path of the * key as a byte-encoded string. * @param mask1 Preferred Windows security mask. * @param mask2 Alternate Windows security mask. * @return Windows registry key's handle. * @see #openKey(int) * @see #openKey(int, byte[],int) * @see #closeKey(int) */
private long openKey(byte[] windowsAbsolutePath, int mask1, int mask2) { /* Check if key's path is short enough be opened at once otherwise use a path-splitting procedure */ if (windowsAbsolutePath.length <= MAX_WINDOWS_PATH_LENGTH + 1) { long[] result = WindowsRegOpenKey1(rootNativeHandle(), windowsAbsolutePath, mask1); if (result[ERROR_CODE] == ERROR_ACCESS_DENIED && mask2 != mask1) result = WindowsRegOpenKey1(rootNativeHandle(), windowsAbsolutePath, mask2); if (result[ERROR_CODE] != ERROR_SUCCESS) { logger().warning("Could not open windows registry node " + byteArrayToString(windowsAbsolutePath()) + " at root 0x" + Long.toHexString(rootNativeHandle()) + ". Windows RegOpenKey(...) returned error code " + result[ERROR_CODE] + "."); result[NATIVE_HANDLE] = NULL_NATIVE_HANDLE; if (result[ERROR_CODE] == ERROR_ACCESS_DENIED) { throw new SecurityException( "Could not open windows registry node " + byteArrayToString(windowsAbsolutePath()) + " at root 0x" + Long.toHexString(rootNativeHandle()) + ": Access denied"); } } return result[NATIVE_HANDLE]; } else { return openKey(rootNativeHandle(), windowsAbsolutePath, mask1, mask2); } }
Opens Windows registry key at a given relative path with respect to a given Windows registry key.
Params:
  • windowsAbsolutePath – Windows relative path of the key as a byte-encoded string.
  • nativeHandle – handle to the base Windows key.
  • mask1 – Preferred Windows security mask.
  • mask2 – Alternate Windows security mask.
See Also:
Returns:Windows registry key's handle.
/** * Opens Windows registry key at a given relative path * with respect to a given Windows registry key. * @param windowsAbsolutePath Windows relative path of the * key as a byte-encoded string. * @param nativeHandle handle to the base Windows key. * @param mask1 Preferred Windows security mask. * @param mask2 Alternate Windows security mask. * @return Windows registry key's handle. * @see #openKey(int) * @see #openKey(byte[],int) * @see #closeKey(int) */
private long openKey(long nativeHandle, byte[] windowsRelativePath, int mask1, int mask2) { /* If the path is short enough open at once. Otherwise split the path */ if (windowsRelativePath.length <= MAX_WINDOWS_PATH_LENGTH + 1 ) { long[] result = WindowsRegOpenKey1(nativeHandle, windowsRelativePath, mask1); if (result[ERROR_CODE] == ERROR_ACCESS_DENIED && mask2 != mask1) result = WindowsRegOpenKey1(nativeHandle, windowsRelativePath, mask2); if (result[ERROR_CODE] != ERROR_SUCCESS) { logger().warning("Could not open windows registry node " + byteArrayToString(windowsAbsolutePath()) + " at root 0x" + Long.toHexString(nativeHandle) + ". Windows RegOpenKey(...) returned error code " + result[ERROR_CODE] + "."); result[NATIVE_HANDLE] = NULL_NATIVE_HANDLE; } return result[NATIVE_HANDLE]; } else { int separatorPosition = -1; // Be greedy - open the longest possible path for (int i = MAX_WINDOWS_PATH_LENGTH; i > 0; i--) { if (windowsRelativePath[i] == ((byte)'\\')) { separatorPosition = i; break; } } // Split the path and do the recursion byte[] nextRelativeRoot = new byte[separatorPosition+1]; System.arraycopy(windowsRelativePath, 0, nextRelativeRoot,0, separatorPosition); nextRelativeRoot[separatorPosition] = 0; byte[] nextRelativePath = new byte[windowsRelativePath.length - separatorPosition - 1]; System.arraycopy(windowsRelativePath, separatorPosition+1, nextRelativePath, 0, nextRelativePath.length); long nextNativeHandle = openKey(nativeHandle, nextRelativeRoot, mask1, mask2); if (nextNativeHandle == NULL_NATIVE_HANDLE) { return NULL_NATIVE_HANDLE; } long result = openKey(nextNativeHandle, nextRelativePath, mask1,mask2); closeKey(nextNativeHandle); return result; } }
Closes Windows registry key. Logs a warning if Windows registry is unavailable.
See Also:
@paramkey's Windows registry handle.
/** * Closes Windows registry key. * Logs a warning if Windows registry is unavailable. * @param key's Windows registry handle. * @see #openKey(int) * @see #openKey(byte[],int) * @see #openKey(int, byte[],int) */
private void closeKey(long nativeHandle) { int result = WindowsRegCloseKey(nativeHandle); if (result != ERROR_SUCCESS) { logger().warning("Could not close windows registry node " + byteArrayToString(windowsAbsolutePath()) + " at root 0x" + Long.toHexString(rootNativeHandle()) + ". Windows RegCloseKey(...) returned error code " + result + "."); } }
Implements AbstractPreferences putSpi() method. Puts name-value pair into the underlying Windows registry node. Logs a warning, if Windows registry is unavailable.
See Also:
/** * Implements {@code AbstractPreferences} {@code putSpi()} method. * Puts name-value pair into the underlying Windows registry node. * Logs a warning, if Windows registry is unavailable. * @see #getSpi(String) */
protected void putSpi(String javaName, String value) { long nativeHandle = openKey(KEY_SET_VALUE); if (nativeHandle == NULL_NATIVE_HANDLE) { isBackingStoreAvailable = false; return; } int result = WindowsRegSetValueEx1(nativeHandle, toWindowsName(javaName), toWindowsValueString(value)); if (result != ERROR_SUCCESS) { logger().warning("Could not assign value to key " + byteArrayToString(toWindowsName(javaName)) + " at Windows registry node " + byteArrayToString(windowsAbsolutePath()) + " at root 0x" + Long.toHexString(rootNativeHandle()) + ". Windows RegSetValueEx(...) returned error code " + result + "."); isBackingStoreAvailable = false; } closeKey(nativeHandle); }
Implements AbstractPreferences getSpi() method. Gets a string value from the underlying Windows registry node. Logs a warning, if Windows registry is unavailable.
See Also:
/** * Implements {@code AbstractPreferences} {@code getSpi()} method. * Gets a string value from the underlying Windows registry node. * Logs a warning, if Windows registry is unavailable. * @see #putSpi(String, String) */
protected String getSpi(String javaName) { long nativeHandle = openKey(KEY_QUERY_VALUE); if (nativeHandle == NULL_NATIVE_HANDLE) { return null; } Object resultObject = WindowsRegQueryValueEx(nativeHandle, toWindowsName(javaName)); if (resultObject == null) { closeKey(nativeHandle); return null; } closeKey(nativeHandle); return toJavaValueString((byte[]) resultObject); }
Implements AbstractPreferences removeSpi() method. Deletes a string name-value pair from the underlying Windows registry node, if this value still exists. Logs a warning, if Windows registry is unavailable or key has already been deleted.
/** * Implements {@code AbstractPreferences} {@code removeSpi()} method. * Deletes a string name-value pair from the underlying Windows registry * node, if this value still exists. * Logs a warning, if Windows registry is unavailable or key has already * been deleted. */
protected void removeSpi(String key) { long nativeHandle = openKey(KEY_SET_VALUE); if (nativeHandle == NULL_NATIVE_HANDLE) { return; } int result = WindowsRegDeleteValue(nativeHandle, toWindowsName(key)); if (result != ERROR_SUCCESS && result != ERROR_FILE_NOT_FOUND) { logger().warning("Could not delete windows registry value " + byteArrayToString(windowsAbsolutePath()) + "\\" + toWindowsName(key) + " at root 0x" + Long.toHexString(rootNativeHandle()) + ". Windows RegDeleteValue(...) returned error code " + result + "."); isBackingStoreAvailable = false; } closeKey(nativeHandle); }
Implements AbstractPreferences keysSpi() method. Gets value names from the underlying Windows registry node. Throws a BackingStoreException and logs a warning, if Windows registry is unavailable.
/** * Implements {@code AbstractPreferences} {@code keysSpi()} method. * Gets value names from the underlying Windows registry node. * Throws a BackingStoreException and logs a warning, if * Windows registry is unavailable. */
protected String[] keysSpi() throws BackingStoreException{ // Find out the number of values long nativeHandle = openKey(KEY_QUERY_VALUE); if (nativeHandle == NULL_NATIVE_HANDLE) { throw new BackingStoreException( "Could not open windows registry node " + byteArrayToString(windowsAbsolutePath()) + " at root 0x" + Long.toHexString(rootNativeHandle()) + "."); } long[] result = WindowsRegQueryInfoKey1(nativeHandle); if (result[ERROR_CODE] != ERROR_SUCCESS) { String info = "Could not query windows registry node " + byteArrayToString(windowsAbsolutePath()) + " at root 0x" + Long.toHexString(rootNativeHandle()) + ". Windows RegQueryInfoKeyEx(...) returned error code " + result[ERROR_CODE] + "."; logger().warning(info); throw new BackingStoreException(info); } int maxValueNameLength = (int)result[MAX_VALUE_NAME_LENGTH]; int valuesNumber = (int)result[VALUES_NUMBER]; if (valuesNumber == 0) { closeKey(nativeHandle); return new String[0]; } // Get the values String[] valueNames = new String[valuesNumber]; for (int i = 0; i < valuesNumber; i++) { byte[] windowsName = WindowsRegEnumValue1(nativeHandle, i, maxValueNameLength+1); if (windowsName == null) { String info = "Could not enumerate value #" + i + " of windows node " + byteArrayToString(windowsAbsolutePath()) + " at root 0x" + Long.toHexString(rootNativeHandle()) + "."; logger().warning(info); throw new BackingStoreException(info); } valueNames[i] = toJavaName(windowsName); } closeKey(nativeHandle); return valueNames; }
Implements AbstractPreferences childrenNamesSpi() method. Calls Windows registry to retrive children of this node. Throws a BackingStoreException and logs a warning message, if Windows registry is not available.
/** * Implements {@code AbstractPreferences} {@code childrenNamesSpi()} method. * Calls Windows registry to retrive children of this node. * Throws a BackingStoreException and logs a warning message, * if Windows registry is not available. */
protected String[] childrenNamesSpi() throws BackingStoreException { // Open key long nativeHandle = openKey(KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE); if (nativeHandle == NULL_NATIVE_HANDLE) { throw new BackingStoreException( "Could not open windows registry node " + byteArrayToString(windowsAbsolutePath()) + " at root 0x" + Long.toHexString(rootNativeHandle()) + "."); } // Get number of children long[] result = WindowsRegQueryInfoKey1(nativeHandle); if (result[ERROR_CODE] != ERROR_SUCCESS) { String info = "Could not query windows registry node " + byteArrayToString(windowsAbsolutePath()) + " at root 0x" + Long.toHexString(rootNativeHandle()) + ". Windows RegQueryInfoKeyEx(...) returned error code " + result[ERROR_CODE] + "."; logger().warning(info); throw new BackingStoreException(info); } int maxKeyLength = (int)result[MAX_KEY_LENGTH]; int subKeysNumber = (int)result[SUBKEYS_NUMBER]; if (subKeysNumber == 0) { closeKey(nativeHandle); return new String[0]; } String[] subkeys = new String[subKeysNumber]; String[] children = new String[subKeysNumber]; // Get children for (int i = 0; i < subKeysNumber; i++) { byte[] windowsName = WindowsRegEnumKeyEx1(nativeHandle, i, maxKeyLength+1); if (windowsName == null) { String info = "Could not enumerate key #" + i + " of windows node " + byteArrayToString(windowsAbsolutePath()) + " at root 0x" + Long.toHexString(rootNativeHandle()) + ". "; logger().warning(info); throw new BackingStoreException(info); } String javaName = toJavaName(windowsName); children[i] = javaName; } closeKey(nativeHandle); return children; }
Implements Preferences flush() method. Flushes Windows registry changes to disk. Throws a BackingStoreException and logs a warning message if Windows registry is not available.
/** * Implements {@code Preferences} {@code flush()} method. * Flushes Windows registry changes to disk. * Throws a BackingStoreException and logs a warning message if Windows * registry is not available. */
public void flush() throws BackingStoreException{ if (isRemoved()) { parent.flush(); return; } if (!isBackingStoreAvailable) { throw new BackingStoreException( "flush(): Backing store not available."); } long nativeHandle = openKey(KEY_READ); if (nativeHandle == NULL_NATIVE_HANDLE) { throw new BackingStoreException( "Could not open windows registry node " + byteArrayToString(windowsAbsolutePath()) + " at root 0x" + Long.toHexString(rootNativeHandle()) + "."); } int result = WindowsRegFlushKey1(nativeHandle); if (result != ERROR_SUCCESS) { String info = "Could not flush windows registry node " + byteArrayToString(windowsAbsolutePath()) + " at root 0x" + Long.toHexString(rootNativeHandle()) + ". Windows RegFlushKey(...) returned error code " + result + "."; logger().warning(info); throw new BackingStoreException(info); } closeKey(nativeHandle); }
Implements Preferences sync() method. Flushes Windows registry changes to disk. Equivalent to flush().
See Also:
  • flush()
/** * Implements {@code Preferences} {@code sync()} method. * Flushes Windows registry changes to disk. Equivalent to flush(). * @see flush() */
public void sync() throws BackingStoreException{ if (isRemoved()) throw new IllegalStateException("Node has been removed"); flush(); }
Implements AbstractPreferences childSpi() method. Constructs a child node with a given name and creates its underlying Windows registry node, if it does not exist. Logs a warning message, if Windows Registry is unavailable.
/** * Implements {@code AbstractPreferences} {@code childSpi()} method. * Constructs a child node with a * given name and creates its underlying Windows registry node, * if it does not exist. * Logs a warning message, if Windows Registry is unavailable. */
protected AbstractPreferences childSpi(String name) { return new WindowsPreferences(this, name); }
Implements AbstractPreferences removeNodeSpi() method. Deletes underlying Windows registry node. Throws a BackingStoreException and logs a warning, if Windows registry is not available.
/** * Implements {@code AbstractPreferences} {@code removeNodeSpi()} method. * Deletes underlying Windows registry node. * Throws a BackingStoreException and logs a warning, if Windows registry * is not available. */
public void removeNodeSpi() throws BackingStoreException { long parentNativeHandle = ((WindowsPreferences)parent()).openKey(DELETE); if (parentNativeHandle == NULL_NATIVE_HANDLE) { throw new BackingStoreException( "Could not open parent windows registry node of " + byteArrayToString(windowsAbsolutePath()) + " at root 0x" + Long.toHexString(rootNativeHandle()) + "."); } int result = WindowsRegDeleteKey(parentNativeHandle, toWindowsName(name())); if (result != ERROR_SUCCESS) { String info = "Could not delete windows registry node " + byteArrayToString(windowsAbsolutePath()) + " at root 0x" + Long.toHexString(rootNativeHandle()) + ". Windows RegDeleteKeyEx(...) returned error code " + result + "."; logger().warning(info); throw new BackingStoreException(info); } closeKey(parentNativeHandle); }
Converts value's or node's name from its byte array representation to java string. Two encodings, simple and altBase64 are used. See toWindowsName() for a detailed description of encoding conventions.
Params:
  • windowsNameArray – Null-terminated byte array.
/** * Converts value's or node's name from its byte array representation to * java string. Two encodings, simple and altBase64 are used. See * {@link #toWindowsName(String) toWindowsName()} for a detailed * description of encoding conventions. * @param windowsNameArray Null-terminated byte array. */
private static String toJavaName(byte[] windowsNameArray) { String windowsName = byteArrayToString(windowsNameArray); // check if Alt64 if ((windowsName.length() > 1) && (windowsName.substring(0, 2).equals("/!"))) { return toJavaAlt64Name(windowsName); } StringBuilder javaName = new StringBuilder(); char ch; // Decode from simple encoding for (int i = 0; i < windowsName.length(); i++) { if ((ch = windowsName.charAt(i)) == '/') { char next = ' '; if ((windowsName.length() > i + 1) && ((next = windowsName.charAt(i+1)) >= 'A') && (next <= 'Z')) { ch = next; i++; } else if ((windowsName.length() > i + 1) && (next == '/')) { ch = '\\'; i++; } } else if (ch == '\\') { ch = '/'; } javaName.append(ch); } return javaName.toString(); }
Converts value's or node's name from its Windows representation to java string, using altBase64 encoding. See toWindowsName() for a detailed description of encoding conventions.
/** * Converts value's or node's name from its Windows representation to java * string, using altBase64 encoding. See * {@link #toWindowsName(String) toWindowsName()} for a detailed * description of encoding conventions. */
private static String toJavaAlt64Name(String windowsName) { byte[] byteBuffer = Base64.altBase64ToByteArray(windowsName.substring(2)); StringBuilder result = new StringBuilder(); for (int i = 0; i < byteBuffer.length; i++) { int firstbyte = (byteBuffer[i++] & 0xff); int secondbyte = (byteBuffer[i] & 0xff); result.append((char)((firstbyte << 8) + secondbyte)); } return result.toString(); }
Converts value's or node's name to its Windows representation as a byte-encoded string. Two encodings, simple and altBase64 are used.

Simple encoding is used, if java string does not contain any characters less, than 0x0020, or greater, than 0x007f. Simple encoding adds "/" character to capital letters, i.e. "A" is encoded as "/A". Character '\' is encoded as '//', '/' is encoded as '\'. The constructed string is converted to byte array by truncating the highest byte and adding the terminating null character.

altBase64 encoding is used, if java string does contain at least one character less, than 0x0020, or greater, than 0x007f. This encoding is marked by setting first two bytes of the Windows string to '/!'. The java name is then encoded using byteArrayToAltBase64() method from Base64 class.

/** * Converts value's or node's name to its Windows representation * as a byte-encoded string. * Two encodings, simple and altBase64 are used. * <p> * <i>Simple</i> encoding is used, if java string does not contain * any characters less, than 0x0020, or greater, than 0x007f. * Simple encoding adds "/" character to capital letters, i.e. * "A" is encoded as "/A". Character '\' is encoded as '//', * '/' is encoded as '\'. * The constructed string is converted to byte array by truncating the * highest byte and adding the terminating {@code null} character. * <p> * <i>altBase64</i> encoding is used, if java string does contain at least * one character less, than 0x0020, or greater, than 0x007f. * This encoding is marked by setting first two bytes of the * Windows string to '/!'. The java name is then encoded using * byteArrayToAltBase64() method from * Base64 class. */
private static byte[] toWindowsName(String javaName) { StringBuilder windowsName = new StringBuilder(); for (int i = 0; i < javaName.length(); i++) { char ch = javaName.charAt(i); if ((ch < 0x0020) || (ch > 0x007f)) { // If a non-trivial character encountered, use altBase64 return toWindowsAlt64Name(javaName); } if (ch == '\\') { windowsName.append("//"); } else if (ch == '/') { windowsName.append('\\'); } else if ((ch >= 'A') && (ch <='Z')) { windowsName.append('/').append(ch); } else { windowsName.append(ch); } } return stringToByteArray(windowsName.toString()); }
Converts value's or node's name to its Windows representation as a byte-encoded string, using altBase64 encoding. See toWindowsName() for a detailed description of encoding conventions.
/** * Converts value's or node's name to its Windows representation * as a byte-encoded string, using altBase64 encoding. See * {@link #toWindowsName(String) toWindowsName()} for a detailed * description of encoding conventions. */
private static byte[] toWindowsAlt64Name(String javaName) { byte[] javaNameArray = new byte[2*javaName.length()]; // Convert to byte pairs int counter = 0; for (int i = 0; i < javaName.length();i++) { int ch = javaName.charAt(i); javaNameArray[counter++] = (byte)(ch >>> 8); javaNameArray[counter++] = (byte)ch; } return stringToByteArray("/!" + Base64.byteArrayToAltBase64(javaNameArray)); }
Converts value string from its Windows representation to java string. See toWindowsValueString() for the description of the encoding algorithm.
/** * Converts value string from its Windows representation * to java string. See * {@link #toWindowsValueString(String) toWindowsValueString()} for the * description of the encoding algorithm. */
private static String toJavaValueString(byte[] windowsNameArray) { String windowsName = byteArrayToString(windowsNameArray); StringBuilder javaName = new StringBuilder(); char ch; for (int i = 0; i < windowsName.length(); i++){ if ((ch = windowsName.charAt(i)) == '/') { char next = ' '; if (windowsName.length() > i + 1 && (next = windowsName.charAt(i + 1)) == 'u') { if (windowsName.length() < i + 6) { break; } else { ch = (char)Integer.parseInt( windowsName.substring(i + 2, i + 6), 16); i += 5; } } else if ((windowsName.length() > i + 1) && ((windowsName.charAt(i+1)) >= 'A') && (next <= 'Z')) { ch = next; i++; } else if ((windowsName.length() > i + 1) && (next == '/')) { ch = '\\'; i++; } } else if (ch == '\\') { ch = '/'; } javaName.append(ch); } return javaName.toString(); }
Converts value string to it Windows representation. as a byte-encoded string. Encoding algorithm adds "/" character to capital letters, i.e. "A" is encoded as "/A". Character '\' is encoded as '//', '/' is encoded as '\'. Then convert java string to a byte array of ASCII characters.
/** * Converts value string to it Windows representation. * as a byte-encoded string. * Encoding algorithm adds "/" character to capital letters, i.e. * "A" is encoded as "/A". Character '\' is encoded as '//', * '/' is encoded as '\'. * Then convert java string to a byte array of ASCII characters. */
private static byte[] toWindowsValueString(String javaName) { StringBuilder windowsName = new StringBuilder(); for (int i = 0; i < javaName.length(); i++) { char ch = javaName.charAt(i); if ((ch < 0x0020) || (ch > 0x007f)){ // write \udddd windowsName.append("/u"); String hex = Long.toHexString(javaName.charAt(i)); StringBuilder hex4 = new StringBuilder(hex); hex4.reverse(); int len = 4 - hex4.length(); for (int j = 0; j < len; j++){ hex4.append('0'); } for (int j = 0; j < 4; j++){ windowsName.append(hex4.charAt(3 - j)); } } else if (ch == '\\') { windowsName.append("//"); } else if (ch == '/') { windowsName.append('\\'); } else if ((ch >= 'A') && (ch <='Z')) { windowsName.append('/').append(ch); } else { windowsName.append(ch); } } return stringToByteArray(windowsName.toString()); }
Returns native handle for the top Windows node for this node.
/** * Returns native handle for the top Windows node for this node. */
private long rootNativeHandle() { return (isUserNode() ? USER_ROOT_NATIVE_HANDLE : SYSTEM_ROOT_NATIVE_HANDLE); }
Returns this java string as a null-terminated byte array
/** * Returns this java string as a null-terminated byte array */
private static byte[] stringToByteArray(String str) { byte[] result = new byte[str.length()+1]; for (int i = 0; i < str.length(); i++) { result[i] = (byte) str.charAt(i); } result[str.length()] = 0; return result; }
Converts a null-terminated byte array to java string
/** * Converts a null-terminated byte array to java string */
private static String byteArrayToString(byte[] array) { StringBuilder result = new StringBuilder(); for (int i = 0; i < array.length - 1; i++) { result.append((char)array[i]); } return result.toString(); }
Empty, never used implementation of AbstractPreferences.flushSpi().
/** * Empty, never used implementation of AbstractPreferences.flushSpi(). */
protected void flushSpi() throws BackingStoreException { // assert false; }
Empty, never used implementation of AbstractPreferences.flushSpi().
/** * Empty, never used implementation of AbstractPreferences.flushSpi(). */
protected void syncSpi() throws BackingStoreException { // assert false; } private static synchronized PlatformLogger logger() { if (logger == null) { logger = PlatformLogger.getLogger("java.util.prefs"); } return logger; } }