Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/macosx/classes/java/util/prefs/MacOSXPreferencesFile.java
38918 views
1
/*
2
* Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
package java.util.prefs;
27
28
import java.util.HashMap;
29
import java.util.HashSet;
30
import java.util.Iterator;
31
import java.util.Timer;
32
import java.util.TimerTask;
33
import java.lang.ref.WeakReference;
34
35
36
/*
37
MacOSXPreferencesFile synchronization:
38
39
Everything is synchronized on MacOSXPreferencesFile.class. This prevents:
40
* simultaneous updates to cachedFiles or changedFiles
41
* simultaneous creation of two objects for the same name+user+host triplet
42
* simultaneous modifications to the same file
43
* modifications during syncWorld/flushWorld
44
* (in MacOSXPreferences.removeNodeSpi()) modification or sync during
45
multi-step node removal process
46
... among other things.
47
*/
48
/*
49
Timers. There are two timers that control synchronization of prefs data to
50
and from disk.
51
52
* Sync timer periodically calls syncWorld() to force external disk changes
53
(e.g. from another VM) into the memory cache. The sync timer runs even
54
if there are no outstanding local changes. The sync timer syncs all live
55
MacOSXPreferencesFile objects (the cachedFiles list).
56
The sync timer period is controlled by the java.util.prefs.syncInterval
57
property (same as FileSystemPreferences). By default there is *no*
58
sync timer (unlike FileSystemPreferences); it is only enabled if the
59
syncInterval property is set. The minimum interval is 5 seconds.
60
61
* Flush timer calls flushWorld() to force local changes to disk.
62
The flush timer is scheduled to fire some time after each pref change,
63
unless it's already scheduled to fire before that. syncWorld and
64
flushWorld will cancel any outstanding flush timer as unnecessary.
65
The flush timer flushes all changed files (the changedFiles list).
66
The time between pref write and flush timer call is controlled by the
67
java.util.prefs.flushDelay property (unlike FileSystemPreferences).
68
The default is 60 seconds and the minimum is 5 seconds.
69
70
The flush timer's behavior is required by the Java Preferences spec
71
("changes will eventually propagate to the persistent backing store with
72
an implementation-dependent delay"). The sync timer is not required by
73
the spec (multiple VMs are only required to not corrupt the prefs), but
74
the periodic sync is implemented by FileSystemPreferences and may be
75
useful to some programs. The sync timer is disabled by default because
76
it's expensive and is usually not necessary.
77
*/
78
79
class MacOSXPreferencesFile {
80
81
static {
82
java.security.AccessController.doPrivileged(
83
new java.security.PrivilegedAction<Void>() {
84
public Void run() {
85
System.loadLibrary("osx");
86
return null;
87
}
88
});
89
}
90
91
private class FlushTask extends TimerTask {
92
public void run() {
93
MacOSXPreferencesFile.flushWorld();
94
}
95
}
96
97
private class SyncTask extends TimerTask {
98
public void run() {
99
MacOSXPreferencesFile.syncWorld();
100
}
101
}
102
103
// Maps string -> weak reference to MacOSXPreferencesFile
104
private static HashMap<String, WeakReference<MacOSXPreferencesFile>>
105
cachedFiles;
106
// Files that may have unflushed changes
107
private static HashSet<MacOSXPreferencesFile> changedFiles;
108
109
110
// Timer and pending sync and flush tasks (which are both scheduled
111
// on the same timer)
112
private static Timer timer = null;
113
private static FlushTask flushTimerTask = null;
114
private static long flushDelay = -1; // in seconds (min 5, default 60)
115
private static long syncInterval = -1; // (min 5, default negative == off)
116
117
private String appName;
118
private long user;
119
private long host;
120
121
String name() { return appName; }
122
long user() { return user; }
123
long host() { return host; }
124
125
// private constructor - use factory method getFile() instead
126
private MacOSXPreferencesFile(String newName, long newUser, long newHost)
127
{
128
appName = newName;
129
user = newUser;
130
host = newHost;
131
}
132
133
// Factory method
134
// Always returns the same object for the given name+user+host
135
static synchronized MacOSXPreferencesFile
136
getFile(String newName, boolean isUser)
137
{
138
MacOSXPreferencesFile result = null;
139
140
if (cachedFiles == null)
141
cachedFiles = new HashMap<>();
142
143
String hashkey =
144
newName + String.valueOf(isUser);
145
WeakReference<MacOSXPreferencesFile> hashvalue = cachedFiles.get(hashkey);
146
if (hashvalue != null) {
147
result = hashvalue.get();
148
}
149
if (result == null) {
150
// Java user node == CF current user, any host
151
// Java system node == CF any user, current host
152
result = new MacOSXPreferencesFile(newName,
153
isUser ? cfCurrentUser : cfAnyUser,
154
isUser ? cfAnyHost : cfCurrentHost);
155
cachedFiles.put(hashkey, new WeakReference<MacOSXPreferencesFile>(result));
156
}
157
158
// Don't schedule this file for flushing until some nodes or
159
// keys are added to it.
160
161
// Do set up the sync timer if requested; sync timer affects reads
162
// as well as writes.
163
initSyncTimerIfNeeded();
164
165
return result;
166
}
167
168
169
// Write all prefs changes to disk and clear all cached prefs values
170
// (so the next read will read from disk).
171
static synchronized boolean syncWorld()
172
{
173
boolean ok = true;
174
175
if (cachedFiles != null && !cachedFiles.isEmpty()) {
176
Iterator<WeakReference<MacOSXPreferencesFile>> iter =
177
cachedFiles.values().iterator();
178
while (iter.hasNext()) {
179
WeakReference<MacOSXPreferencesFile> ref = iter.next();
180
MacOSXPreferencesFile f = ref.get();
181
if (f != null) {
182
if (!f.synchronize()) ok = false;
183
} else {
184
iter.remove();
185
}
186
}
187
}
188
189
// Kill any pending flush
190
if (flushTimerTask != null) {
191
flushTimerTask.cancel();
192
flushTimerTask = null;
193
}
194
195
// Clear changed file list. The changed files were guaranteed to
196
// have been in the cached file list (because there was a strong
197
// reference from changedFiles.
198
if (changedFiles != null) changedFiles.clear();
199
200
return ok;
201
}
202
203
204
// Sync only current user preferences
205
static synchronized boolean syncUser() {
206
boolean ok = true;
207
if (cachedFiles != null && !cachedFiles.isEmpty()) {
208
Iterator<WeakReference<MacOSXPreferencesFile>> iter =
209
cachedFiles.values().iterator();
210
while (iter.hasNext()) {
211
WeakReference<MacOSXPreferencesFile> ref = iter.next();
212
MacOSXPreferencesFile f = ref.get();
213
if (f != null && f.user == cfCurrentUser) {
214
if (!f.synchronize()) {
215
ok = false;
216
}
217
} else {
218
iter.remove();
219
}
220
}
221
}
222
// Remove synchronized file from changed file list. The changed files were
223
// guaranteed to have been in the cached file list (because there was a strong
224
// reference from changedFiles.
225
if (changedFiles != null) {
226
Iterator<MacOSXPreferencesFile> iterChanged = changedFiles.iterator();
227
while (iterChanged.hasNext()) {
228
MacOSXPreferencesFile f = iterChanged.next();
229
if (f != null && f.user == cfCurrentUser)
230
iterChanged.remove();
231
}
232
}
233
return ok;
234
}
235
236
//Flush only current user preferences
237
static synchronized boolean flushUser() {
238
boolean ok = true;
239
if (changedFiles != null && !changedFiles.isEmpty()) {
240
Iterator<MacOSXPreferencesFile> iterator = changedFiles.iterator();
241
while(iterator.hasNext()) {
242
MacOSXPreferencesFile f = iterator.next();
243
if (f.user == cfCurrentUser) {
244
if (!f.synchronize())
245
ok = false;
246
else
247
iterator.remove();
248
}
249
}
250
}
251
return ok;
252
}
253
254
// Write all prefs changes to disk, but do not clear all cached prefs
255
// values. Also kills any scheduled flush task.
256
// There's no CFPreferencesFlush() (<rdar://problem/3049129>), so lots of cached prefs
257
// are cleared anyway.
258
static synchronized boolean flushWorld()
259
{
260
boolean ok = true;
261
262
if (changedFiles != null && !changedFiles.isEmpty()) {
263
for (MacOSXPreferencesFile f : changedFiles) {
264
if (!f.synchronize())
265
ok = false;
266
}
267
changedFiles.clear();
268
}
269
270
if (flushTimerTask != null) {
271
flushTimerTask.cancel();
272
flushTimerTask = null;
273
}
274
275
return ok;
276
}
277
278
// Mark this prefs file as changed. The changes will be flushed in
279
// at most flushDelay() seconds.
280
// Must be called when synchronized on MacOSXPreferencesFile.class
281
private void markChanged()
282
{
283
// Add this file to the changed file list
284
if (changedFiles == null)
285
changedFiles = new HashSet<>();
286
changedFiles.add(this);
287
288
// Schedule a new flush and a shutdown hook, if necessary
289
if (flushTimerTask == null) {
290
flushTimerTask = new FlushTask();
291
timer().schedule(flushTimerTask, flushDelay() * 1000);
292
}
293
}
294
295
// Return the flush delay, initializing from a property if necessary.
296
private static synchronized long flushDelay()
297
{
298
if (flushDelay == -1) {
299
try {
300
// flush delay >= 5, default 60
301
flushDelay = Math.max(5, Integer.parseInt(System.getProperty("java.util.prefs.flushDelay", "60")));
302
} catch (NumberFormatException e) {
303
flushDelay = 60;
304
}
305
}
306
return flushDelay;
307
}
308
309
// Initialize and run the sync timer, if the sync timer property is set
310
// and the sync timer hasn't already been started.
311
private static synchronized void initSyncTimerIfNeeded()
312
{
313
// syncInterval: -1 is uninitialized, other negative is off,
314
// positive is seconds between syncs (min 5).
315
316
if (syncInterval == -1) {
317
try {
318
syncInterval = Integer.parseInt(System.getProperty("java.util.prefs.syncInterval", "-2"));
319
if (syncInterval >= 0) {
320
// minimum of 5 seconds
321
syncInterval = Math.max(5, syncInterval);
322
} else {
323
syncInterval = -2; // default off
324
}
325
} catch (NumberFormatException e) {
326
syncInterval = -2; // bad property value - default off
327
}
328
329
if (syncInterval > 0) {
330
timer().schedule(new TimerTask() {
331
@Override
332
public void run() {
333
MacOSXPreferencesFile.syncWorld();}
334
}, syncInterval * 1000, syncInterval * 1000);
335
} else {
336
// syncInterval property not set. No sync timer ever.
337
}
338
}
339
}
340
341
// Return the timer used for flush and sync, creating it if necessary.
342
private static synchronized Timer timer()
343
{
344
if (timer == null) {
345
timer = new Timer(true); // daemon
346
Thread flushThread = new Thread() {
347
@Override
348
public void run() {
349
flushWorld();
350
}
351
};
352
/* Set context class loader to null in order to avoid
353
* keeping a strong reference to an application classloader.
354
*/
355
flushThread.setContextClassLoader(null);
356
Runtime.getRuntime().addShutdownHook(flushThread);
357
}
358
return timer;
359
}
360
361
362
// Node manipulation
363
boolean addNode(String path)
364
{
365
synchronized(MacOSXPreferencesFile.class) {
366
markChanged();
367
return addNode(path, appName, user, host);
368
}
369
}
370
371
void removeNode(String path)
372
{
373
synchronized(MacOSXPreferencesFile.class) {
374
markChanged();
375
removeNode(path, appName, user, host);
376
}
377
}
378
379
boolean addChildToNode(String path, String child)
380
{
381
synchronized(MacOSXPreferencesFile.class) {
382
markChanged();
383
return addChildToNode(path, child+"/", appName, user, host);
384
}
385
}
386
387
void removeChildFromNode(String path, String child)
388
{
389
synchronized(MacOSXPreferencesFile.class) {
390
markChanged();
391
removeChildFromNode(path, child+"/", appName, user, host);
392
}
393
}
394
395
396
// Key manipulation
397
void addKeyToNode(String path, String key, String value)
398
{
399
synchronized(MacOSXPreferencesFile.class) {
400
markChanged();
401
addKeyToNode(path, key, value, appName, user, host);
402
}
403
}
404
405
void removeKeyFromNode(String path, String key)
406
{
407
synchronized(MacOSXPreferencesFile.class) {
408
markChanged();
409
removeKeyFromNode(path, key, appName, user, host);
410
}
411
}
412
413
String getKeyFromNode(String path, String key)
414
{
415
synchronized(MacOSXPreferencesFile.class) {
416
return getKeyFromNode(path, key, appName, user, host);
417
}
418
}
419
420
421
// Enumerators
422
String[] getChildrenForNode(String path)
423
{
424
synchronized(MacOSXPreferencesFile.class) {
425
return getChildrenForNode(path, appName, user, host);
426
}
427
}
428
429
String[] getKeysForNode(String path)
430
{
431
synchronized(MacOSXPreferencesFile.class) {
432
return getKeysForNode(path, appName, user, host);
433
}
434
}
435
436
437
// Synchronization
438
boolean synchronize()
439
{
440
synchronized(MacOSXPreferencesFile.class) {
441
return synchronize(appName, user, host);
442
}
443
}
444
445
446
// CF functions
447
// Must be called when synchronized on MacOSXPreferencesFile.class
448
private static final native boolean
449
addNode(String path, String name, long user, long host);
450
private static final native void
451
removeNode(String path, String name, long user, long host);
452
private static final native boolean
453
addChildToNode(String path, String child,
454
String name, long user, long host);
455
private static final native void
456
removeChildFromNode(String path, String child,
457
String name, long user, long host);
458
private static final native void
459
addKeyToNode(String path, String key, String value,
460
String name, long user, long host);
461
private static final native void
462
removeKeyFromNode(String path, String key,
463
String name, long user, long host);
464
private static final native String
465
getKeyFromNode(String path, String key,
466
String name, long user, long host);
467
private static final native String[]
468
getChildrenForNode(String path, String name, long user, long host);
469
private static final native String[]
470
getKeysForNode(String path, String name, long user, long host);
471
private static final native boolean
472
synchronize(String name, long user, long host);
473
474
// CFPreferences host and user values (CFStringRefs)
475
private static long cfCurrentUser = currentUser();
476
private static long cfAnyUser = anyUser();
477
private static long cfCurrentHost = currentHost();
478
private static long cfAnyHost = anyHost();
479
480
// CFPreferences constant accessors
481
private static final native long currentUser();
482
private static final native long anyUser();
483
private static final native long currentHost();
484
private static final native long anyHost();
485
}
486
487
488