src/macosx/classes/java/util/prefs/MacOSXPreferencesFile.java

Print this page




  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 cachedFiles = null;

 105     // Files that may have unflushed changes
 106     private static HashSet changedFiles = null;
 107 
 108 
 109     // Timer and pending sync and flush tasks (which are both scheduled
 110     // on the same timer)
 111     private static Timer timer = null;
 112     private static FlushTask flushTimerTask = null;
 113     private static long flushDelay = -1; // in seconds (min 5, default 60)
 114     private static long syncInterval = -1; // (min 5, default negative == off)
 115 
 116     private String appName;
 117     private long user;
 118     private long host;
 119 
 120     String name() { return appName; }
 121     long user() { return user; }
 122     long host() { return host; }
 123 
 124     // private contructor - use factory method getFile() instead
 125     private MacOSXPreferencesFile(String newName, long newUser, long newHost)
 126     {
 127         appName = newName;
 128         user = newUser;
 129         host = newHost;
 130     }
 131 
 132     // Factory method
 133     // Always returns the same object for the given name+user+host
 134     static synchronized MacOSXPreferencesFile
 135         getFile(String newName, boolean isUser)
 136     {
 137         MacOSXPreferencesFile result = null;
 138 
 139         if (cachedFiles == null) cachedFiles = new HashMap();

 140 
 141         String hashkey =
 142             newName + String.valueOf(isUser);
 143         WeakReference hashvalue = (WeakReference)cachedFiles.get(hashkey);
 144         if (hashvalue != null) {
 145             result = (MacOSXPreferencesFile)hashvalue.get();
 146         }
 147         if (result == null) {
 148             // Java user node == CF current user, any host
 149             // Java system node == CF any user, current host
 150             result = new MacOSXPreferencesFile(newName,
 151                                          isUser ? cfCurrentUser : cfAnyUser,
 152                                          isUser ? cfAnyHost : cfCurrentHost);
 153             cachedFiles.put(hashkey, new WeakReference(result));
 154         }
 155 
 156         // Don't schedule this file for flushing until some nodes or
 157         // keys are added to it.
 158 
 159         // Do set up the sync timer if requested; sync timer affects reads
 160         // as well as writes.
 161         initSyncTimerIfNeeded();
 162 
 163         return result;
 164     }
 165 
 166 
 167     // Write all prefs changes to disk and clear all cached prefs values
 168     // (so the next read will read from disk).
 169     static synchronized boolean syncWorld()
 170     {
 171         boolean ok = true;
 172 
 173         if (cachedFiles != null  &&  !cachedFiles.isEmpty()) {
 174             Iterator iter = cachedFiles.values().iterator();

 175             while (iter.hasNext()) {
 176                 WeakReference ref = (WeakReference)iter.next();
 177                 MacOSXPreferencesFile f = (MacOSXPreferencesFile)ref.get();
 178                 if (f != null) {
 179                     if (!f.synchronize()) ok = false;
 180                 } else {
 181                     iter.remove();
 182                 }
 183             }
 184         }
 185 
 186         // Kill any pending flush
 187         if (flushTimerTask != null) {
 188             flushTimerTask.cancel();
 189             flushTimerTask = null;
 190         }
 191 
 192         // Clear changed file list. The changed files were guaranteed to
 193         // have been in the cached file list (because there was a strong
 194         // reference from changedFiles.
 195         if (changedFiles != null) changedFiles.clear();
 196 
 197         return ok;
 198     }
 199 
 200 
 201     // Sync only current user preferences
 202     static synchronized boolean syncUser() {
 203         boolean ok = true;
 204         if (cachedFiles != null  &&  !cachedFiles.isEmpty()) {
 205             Iterator<WeakReference> iter = cachedFiles.values().iterator();

 206             while (iter.hasNext()) {
 207                 WeakReference ref = iter.next();
 208                 MacOSXPreferencesFile f = (MacOSXPreferencesFile)ref.get();
 209                 if (f != null && f.user == cfCurrentUser) {
 210                     if (!f.synchronize()) {
 211                         ok = false;
 212                     }
 213                 } else {
 214                     iter.remove();
 215                 }
 216             }
 217         }
 218         // Remove synchronized file from changed file list. The changed files were
 219         // guaranteed to have been in the cached file list (because there was a strong
 220         // reference from changedFiles.
 221         if (changedFiles != null) {
 222             Iterator<MacOSXPreferencesFile> iterChanged = changedFiles.iterator();
 223             while (iterChanged.hasNext()) {
 224                 MacOSXPreferencesFile f = iterChanged.next();
 225                 if (f != null && f.user == cfCurrentUser)
 226                     iterChanged.remove();
 227              }
 228         }
 229         return ok;
 230     }
 231 
 232 
 233 
 234     // Write all prefs changes to disk, but do not clear all cached prefs
 235     // values. Also kills any scheduled flush task.
 236     // There's no CFPreferencesFlush() (<rdar://problem/3049129>), so lots of cached prefs
 237     // are cleared anyway.
 238     static synchronized boolean flushWorld()
 239     {
 240         boolean ok = true;
 241 
 242         if (changedFiles != null  &&  !changedFiles.isEmpty()) {
 243             Iterator iter = changedFiles.iterator();
 244             while (iter.hasNext()) {
 245                 MacOSXPreferencesFile f = (MacOSXPreferencesFile)iter.next();
 246                 if (!f.synchronize()) ok = false;
 247             }
 248 
 249             changedFiles.clear();
 250         }
 251 
 252         if (flushTimerTask != null) {
 253             flushTimerTask.cancel();
 254             flushTimerTask = null;
 255         }
 256 
 257         return ok;
 258     }
 259 
 260     // Mark this prefs file as changed. The changes will be flushed in
 261     // at most flushDelay() seconds.
 262     // Must be called when synchronized on MacOSXPreferencesFile.class
 263     private void markChanged()
 264     {
 265         // Add this file to the changed file list
 266         if (changedFiles == null) changedFiles = new HashSet();

 267         changedFiles.add(this);
 268 
 269         // Schedule a new flush and a shutdown hook, if necessary
 270         if (flushTimerTask == null) {
 271             flushTimerTask = new FlushTask();
 272             timer().schedule(flushTimerTask, flushDelay() * 1000);
 273         }
 274     }
 275 
 276     // Return the flush delay, initializing from a property if necessary.
 277     private static synchronized long flushDelay()
 278     {
 279         if (flushDelay == -1) {
 280             try {
 281                 // flush delay >= 5, default 60
 282                 flushDelay = Math.max(5, Integer.parseInt(System.getProperty("java.util.prefs.flushDelay", "60")));
 283             } catch (NumberFormatException e) {
 284                 flushDelay = 60;
 285             }
 286         }


 292     private static synchronized void initSyncTimerIfNeeded()
 293     {
 294         // syncInterval: -1 is uninitialized, other negative is off,
 295         // positive is seconds between syncs (min 5).
 296 
 297         if (syncInterval == -1) {
 298             try {
 299                 syncInterval = Integer.parseInt(System.getProperty("java.util.prefs.syncInterval", "-2"));
 300                 if (syncInterval >= 0) {
 301                     // minimum of 5 seconds
 302                     syncInterval = Math.max(5, syncInterval);
 303                 } else {
 304                     syncInterval = -2; // default off
 305                 }
 306             } catch (NumberFormatException e) {
 307                 syncInterval = -2; // bad property value - default off
 308             }
 309 
 310             if (syncInterval > 0) {
 311                 timer().schedule(new TimerTask() {
 312                         public void run() { MacOSXPreferencesFile.syncWorld();}


 313                     }, syncInterval * 1000, syncInterval * 1000);
 314             } else {
 315                 // syncInterval property not set. No sync timer ever.
 316             }
 317         }
 318     }
 319 
 320     // Return the timer used for flush and sync, creating it if necessary.
 321     private static synchronized Timer timer()
 322     {
 323         if (timer == null) {
 324             timer = new Timer(true); // daemon
 325             Thread flushThread = new Thread() {

 326                 public void run() {
 327                     flushWorld();
 328                 }
 329             };
 330             /* Set context class loader to null in order to avoid
 331              * keeping a strong reference to an application classloader.
 332              */
 333             flushThread.setContextClassLoader(null);
 334             Runtime.getRuntime().addShutdownHook(flushThread);
 335         }
 336         return timer;
 337     }
 338 
 339 
 340     // Node manipulation
 341     boolean addNode(String path)
 342     {
 343         synchronized(MacOSXPreferencesFile.class) {
 344             markChanged();
 345             return addNode(path, appName, user, host);




  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 = null;
 106     // Files that may have unflushed changes
 107     private static HashSet<MacOSXPreferencesFile> changedFiles = null;
 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 contructor - 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 
 237 
 238     // Write all prefs changes to disk, but do not clear all cached prefs
 239     // values. Also kills any scheduled flush task.
 240     // There's no CFPreferencesFlush() (<rdar://problem/3049129>), so lots of cached prefs
 241     // are cleared anyway.
 242     static synchronized boolean flushWorld()
 243     {
 244         boolean ok = true;
 245 
 246         if (changedFiles != null  &&  !changedFiles.isEmpty()) {
 247             for (MacOSXPreferencesFile f : changedFiles) {
 248                 if (!f.synchronize()) 
 249                     ok = false;

 250             }

 251             changedFiles.clear();
 252         }
 253 
 254         if (flushTimerTask != null) {
 255             flushTimerTask.cancel();
 256             flushTimerTask = null;
 257         }
 258 
 259         return ok;
 260     }
 261 
 262     // Mark this prefs file as changed. The changes will be flushed in
 263     // at most flushDelay() seconds.
 264     // Must be called when synchronized on MacOSXPreferencesFile.class
 265     private void markChanged()
 266     {
 267         // Add this file to the changed file list
 268         if (changedFiles == null) 
 269             changedFiles = new HashSet<>();
 270         changedFiles.add(this);
 271 
 272         // Schedule a new flush and a shutdown hook, if necessary
 273         if (flushTimerTask == null) {
 274             flushTimerTask = new FlushTask();
 275             timer().schedule(flushTimerTask, flushDelay() * 1000);
 276         }
 277     }
 278 
 279     // Return the flush delay, initializing from a property if necessary.
 280     private static synchronized long flushDelay()
 281     {
 282         if (flushDelay == -1) {
 283             try {
 284                 // flush delay >= 5, default 60
 285                 flushDelay = Math.max(5, Integer.parseInt(System.getProperty("java.util.prefs.flushDelay", "60")));
 286             } catch (NumberFormatException e) {
 287                 flushDelay = 60;
 288             }
 289         }


 295     private static synchronized void initSyncTimerIfNeeded()
 296     {
 297         // syncInterval: -1 is uninitialized, other negative is off,
 298         // positive is seconds between syncs (min 5).
 299 
 300         if (syncInterval == -1) {
 301             try {
 302                 syncInterval = Integer.parseInt(System.getProperty("java.util.prefs.syncInterval", "-2"));
 303                 if (syncInterval >= 0) {
 304                     // minimum of 5 seconds
 305                     syncInterval = Math.max(5, syncInterval);
 306                 } else {
 307                     syncInterval = -2; // default off
 308                 }
 309             } catch (NumberFormatException e) {
 310                 syncInterval = -2; // bad property value - default off
 311             }
 312 
 313             if (syncInterval > 0) {
 314                 timer().schedule(new TimerTask() {
 315                     @Override
 316                     public void run() {
 317                         MacOSXPreferencesFile.syncWorld();}
 318                     }, syncInterval * 1000, syncInterval * 1000);
 319             } else {
 320                 // syncInterval property not set. No sync timer ever.
 321             }
 322         }
 323     }
 324 
 325     // Return the timer used for flush and sync, creating it if necessary.
 326     private static synchronized Timer timer()
 327     {
 328         if (timer == null) {
 329             timer = new Timer(true); // daemon
 330             Thread flushThread = new Thread() {
 331                 @Override
 332                 public void run() {
 333                     flushWorld();
 334                 }
 335             };
 336             /* Set context class loader to null in order to avoid
 337              * keeping a strong reference to an application classloader.
 338              */
 339             flushThread.setContextClassLoader(null);
 340             Runtime.getRuntime().addShutdownHook(flushThread);
 341         }
 342         return timer;
 343     }
 344 
 345 
 346     // Node manipulation
 347     boolean addNode(String path)
 348     {
 349         synchronized(MacOSXPreferencesFile.class) {
 350             markChanged();
 351             return addNode(path, appName, user, host);