Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/macosx/classes/java/util/prefs/MacOSXPreferences.java
38918 views
/*1* Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package java.util.prefs;2627import java.util.Objects;2829class MacOSXPreferences extends AbstractPreferences {30// fixme need security checks?3132// CF preferences file name for Java nodes with short names33// This value is also in MacOSXPreferencesFile.c34private static final String defaultAppName = "com.apple.java.util.prefs";3536// true if this node is a child of userRoot or is userRoot37private final boolean isUser;3839// true if this node is userRoot or systemRoot40private final boolean isRoot;4142// CF's storage location for this node and its keys43private final MacOSXPreferencesFile file;4445// absolutePath() + "/"46private final String path;4748// User root and system root nodes49private static volatile MacOSXPreferences userRoot;50private static volatile MacOSXPreferences systemRoot;515253// Returns user root node, creating it if necessary.54// Called by MacOSXPreferencesFactory55static Preferences getUserRoot() {56MacOSXPreferences root = userRoot;57if (root == null) {58synchronized (MacOSXPreferences.class) {59root = userRoot;60if (root == null) {61userRoot = root = new MacOSXPreferences(true);62}63}64}65return root;66}676869// Returns system root node, creating it if necessary.70// Called by MacOSXPreferencesFactory71static Preferences getSystemRoot() {72MacOSXPreferences root = systemRoot;73if (root == null) {74synchronized (MacOSXPreferences.class) {75root = systemRoot;76if (root == null) {77systemRoot = root = new MacOSXPreferences(false);78}79}80}81return root;82}838485// Create a new root node. Called by getUserRoot() and getSystemRoot()86// Synchronization is provided by the caller.87private MacOSXPreferences(boolean newIsUser) {88this(null, "", false, true, newIsUser);89}909192// Create a new non-root node with the given parent.93// Called by childSpi().94private MacOSXPreferences(MacOSXPreferences parent, String name) {95this(parent, name, false, false, false);96}9798private MacOSXPreferences(MacOSXPreferences parent, String name,99boolean isNew)100{101this(parent, name, isNew, false, false);102}103104private MacOSXPreferences(MacOSXPreferences parent, String name,105boolean isNew, boolean isRoot, boolean isUser)106{107super(parent, name);108this.isRoot = isRoot;109if (isRoot)110this.isUser = isUser;111else112this.isUser = isUserNode();113path = isRoot ? absolutePath() : absolutePath() + "/";114file = cfFileForNode(this.isUser);115if (isNew)116newNode = isNew;117else118newNode = file.addNode(path);119}120121// Create and return the MacOSXPreferencesFile for this node.122// Does not write anything to the file.123private MacOSXPreferencesFile cfFileForNode(boolean isUser)124{125String name = path;126// /one/two/three/four/five/127// The fourth slash is the end of the first three components.128// If there is no fourth slash, the name has fewer than 3 components129int componentCount = 0;130int pos = -1;131for (int i = 0; i < 4; i++) {132pos = name.indexOf('/', pos+1);133if (pos == -1) break;134}135136if (pos == -1) {137// fewer than three components - use default name138name = defaultAppName;139} else {140// truncate to three components, no leading or trailing '/'141// replace '/' with '.' to make filesystem happy142// convert to all lowercase to survive on HFS+143name = name.substring(1, pos);144name = name.replace('/', '.');145name = name.toLowerCase();146}147148return MacOSXPreferencesFile.getFile(name, isUser);149}150151152// AbstractPreferences implementation153@Override154protected void putSpi(String key, String value)155{156file.addKeyToNode(path, key, value);157}158159// AbstractPreferences implementation160@Override161protected String getSpi(String key)162{163return file.getKeyFromNode(path, key);164}165166// AbstractPreferences implementation167@Override168protected void removeSpi(String key)169{170Objects.requireNonNull(key, "Specified key cannot be null");171file.removeKeyFromNode(path, key);172}173174175// AbstractPreferences implementation176@Override177protected void removeNodeSpi()178throws BackingStoreException179{180// Disallow flush or sync between these two operations181// (they may be manipulating two different files)182synchronized(MacOSXPreferencesFile.class) {183((MacOSXPreferences)parent()).removeChild(name());184file.removeNode(path);185}186}187188// Erase knowledge about a child of this node. Called by removeNodeSpi.189private void removeChild(String child)190{191file.removeChildFromNode(path, child);192}193194195// AbstractPreferences implementation196@Override197protected String[] childrenNamesSpi()198throws BackingStoreException199{200String[] result = file.getChildrenForNode(path);201if (result == null) throw new BackingStoreException("Couldn't get list of children for node '" + path + "'");202return result;203}204205// AbstractPreferences implementation206@Override207protected String[] keysSpi()208throws BackingStoreException209{210String[] result = file.getKeysForNode(path);211if (result == null) throw new BackingStoreException("Couldn't get list of keys for node '" + path + "'");212return result;213}214215// AbstractPreferences implementation216@Override217protected AbstractPreferences childSpi(String name)218{219// Add to parent's child list here and disallow sync220// because parent and child might be in different files.221synchronized(MacOSXPreferencesFile.class) {222boolean isNew = file.addChildToNode(path, name);223return new MacOSXPreferences(this, name, isNew);224}225}226227// AbstractPreferences override228@Override229public void flush()230throws BackingStoreException231{232// Flush should *not* check for removal, unlike sync, but should233// prevent simultaneous removal.234synchronized(lock) {235if (isUser) {236if (!MacOSXPreferencesFile.flushUser()) {237throw new BackingStoreException("Synchronization failed for node '" + path + "'");238}239} else {240if (!MacOSXPreferencesFile.flushWorld()) {241throw new BackingStoreException("Synchronization failed for node '" + path + "'");242}243}244}245}246247// AbstractPreferences implementation248@Override249protected void flushSpi()250throws BackingStoreException251{252// nothing here - overridden flush() doesn't call this253}254255// AbstractPreferences override256@Override257public void sync()258throws BackingStoreException259{260synchronized(lock) {261if (isRemoved())262throw new IllegalStateException("Node has been removed");263// fixme! overkill264if (isUser) {265if (!MacOSXPreferencesFile.syncUser()) {266throw new BackingStoreException("Synchronization failed for node '" + path + "'");267}268} else {269if (!MacOSXPreferencesFile.syncWorld()) {270throw new BackingStoreException("Synchronization failed for node '" + path + "'");271}272}273}274}275276// AbstractPreferences implementation277@Override278protected void syncSpi()279throws BackingStoreException280{281// nothing here - overridden sync() doesn't call this282}283}284285286287