Source Code Cross Referenced for FileSystemPreferences.java in  » 6.0-JDK-Platform » solaris » java » util » prefs » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » 6.0 JDK Platform » solaris » java.util.prefs 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Copyright 2000-2006 Sun Microsystems, Inc.  All Rights Reserved.
0003:         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004:         *
0005:         * This code is free software; you can redistribute it and/or modify it
0006:         * under the terms of the GNU General Public License version 2 only, as
0007:         * published by the Free Software Foundation.  Sun designates this
0008:         * particular file as subject to the "Classpath" exception as provided
0009:         * by Sun in the LICENSE file that accompanied this code.
0010:         *
0011:         * This code is distributed in the hope that it will be useful, but WITHOUT
0012:         * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013:         * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
0014:         * version 2 for more details (a copy is included in the LICENSE file that
0015:         * accompanied this code).
0016:         *
0017:         * You should have received a copy of the GNU General Public License version
0018:         * 2 along with this work; if not, write to the Free Software Foundation,
0019:         * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020:         *
0021:         * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022:         * CA 95054 USA or visit www.sun.com if you need additional information or
0023:         * have any questions.
0024:         */
0025:
0026:        package java.util.prefs;
0027:
0028:        import java.util.*;
0029:        import java.io.*;
0030:        import java.util.logging.Logger;
0031:        import java.security.AccessController;
0032:        import java.security.PrivilegedAction;
0033:        import java.security.PrivilegedExceptionAction;
0034:        import java.security.PrivilegedActionException;
0035:
0036:        /**
0037:         * Preferences implementation for Unix.  Preferences are stored in the file
0038:         * system, with one directory per preferences node.  All of the preferences
0039:         * at each node are stored in a single file.  Atomic file system operations
0040:         * (e.g. File.renameTo) are used to ensure integrity.  An in-memory cache of
0041:         * the "explored" portion of the tree is maintained for performance, and 
0042:         * written back to the disk periodically.  File-locking is used to ensure
0043:         * reasonable behavior when multiple VMs are running at the same time.
0044:         * (The file lock is obtained only for sync(), flush() and removeNode().)
0045:         *
0046:         * @author  Josh Bloch
0047:         * @version 1.27, 05/05/07
0048:         * @see     Preferences
0049:         * @since   1.4
0050:         */
0051:        class FileSystemPreferences extends AbstractPreferences {
0052:            /**
0053:             * Sync interval in seconds.
0054:             */
0055:            private static final int SYNC_INTERVAL = Math.max(1, Integer
0056:                    .parseInt((String) AccessController
0057:                            .doPrivileged(new PrivilegedAction() {
0058:                                public Object run() {
0059:                                    return System.getProperty(
0060:                                            "java.util.prefs.syncInterval",
0061:                                            "30");
0062:                                }
0063:                            })));
0064:
0065:            /** 
0066:             * Returns logger for error messages. Backing store exceptions are logged at
0067:             * WARNING level.
0068:             */
0069:            private static Logger getLogger() {
0070:                return Logger.getLogger("java.util.prefs");
0071:            }
0072:
0073:            /**
0074:             * Directory for system preferences.
0075:             */
0076:            private static File systemRootDir;
0077:
0078:            /*
0079:             * Flag, indicating whether systemRoot  directory is writable
0080:             */
0081:            private static boolean isSystemRootWritable;
0082:
0083:            /**
0084:             * Directory for user preferences.
0085:             */
0086:            private static File userRootDir;
0087:
0088:            /*
0089:             * Flag, indicating whether userRoot  directory is writable
0090:             */
0091:            private static boolean isUserRootWritable;
0092:
0093:            /**
0094:             * The user root.
0095:             */
0096:            static Preferences userRoot = null;
0097:
0098:            static synchronized Preferences getUserRoot() {
0099:                if (userRoot == null) {
0100:                    setupUserRoot();
0101:                    userRoot = new FileSystemPreferences(true);
0102:                }
0103:                return userRoot;
0104:            }
0105:
0106:            private static void setupUserRoot() {
0107:                AccessController.doPrivileged(new PrivilegedAction() {
0108:                    public Object run() {
0109:                        userRootDir = new File(System.getProperty(
0110:                                "java.util.prefs.userRoot", System
0111:                                        .getProperty("user.home")),
0112:                                ".java/.userPrefs");
0113:                        // Attempt to create root dir if it does not yet exist.
0114:                        if (!userRootDir.exists()) {
0115:                            if (userRootDir.mkdirs()) {
0116:                                try {
0117:                                    chmod(userRootDir.getCanonicalPath(),
0118:                                            USER_RWX);
0119:                                } catch (IOException e) {
0120:                                    getLogger()
0121:                                            .warning(
0122:                                                    "Could not change permissions"
0123:                                                            + " on userRoot directory. ");
0124:                                }
0125:                                getLogger().info(
0126:                                        "Created user preferences directory.");
0127:                            } else
0128:                                getLogger()
0129:                                        .warning(
0130:                                                "Couldn't create user preferences"
0131:                                                        + " directory. User preferences are unusable.");
0132:                        }
0133:                        isUserRootWritable = userRootDir.canWrite();
0134:                        String USER_NAME = System.getProperty("user.name");
0135:                        userLockFile = new File(userRootDir, ".user.lock."
0136:                                + USER_NAME);
0137:                        userRootModFile = new File(userRootDir,
0138:                                ".userRootModFile." + USER_NAME);
0139:                        if (!userRootModFile.exists())
0140:                            try {
0141:                                // create if does not exist.
0142:                                userRootModFile.createNewFile();
0143:                                // Only user can read/write userRootModFile.
0144:                                int result = chmod(userRootModFile
0145:                                        .getCanonicalPath(), USER_READ_WRITE);
0146:                                if (result != 0)
0147:                                    getLogger()
0148:                                            .warning(
0149:                                                    "Problem creating userRoot "
0150:                                                            + "mod file. Chmod failed on "
0151:                                                            + userRootModFile
0152:                                                                    .getCanonicalPath()
0153:                                                            + " Unix error code "
0154:                                                            + result);
0155:                            } catch (IOException e) {
0156:                                getLogger().warning(e.toString());
0157:                            }
0158:                        userRootModTime = userRootModFile.lastModified();
0159:                        return null;
0160:                    }
0161:                });
0162:            }
0163:
0164:            /**
0165:             * The system root.
0166:             */
0167:            static Preferences systemRoot;
0168:
0169:            static synchronized Preferences getSystemRoot() {
0170:                if (systemRoot == null) {
0171:                    setupSystemRoot();
0172:                    systemRoot = new FileSystemPreferences(false);
0173:                }
0174:                return systemRoot;
0175:            }
0176:
0177:            private static void setupSystemRoot() {
0178:                AccessController.doPrivileged(new PrivilegedAction() {
0179:                    public Object run() {
0180:                        String systemPrefsDirName = (String) System
0181:                                .getProperty("java.util.prefs.systemRoot",
0182:                                        "/etc/.java");
0183:                        systemRootDir = new File(systemPrefsDirName,
0184:                                ".systemPrefs");
0185:                        // Attempt to create root dir if it does not yet exist.
0186:                        if (!systemRootDir.exists()) {
0187:                            // system root does not exist in /etc/.java  
0188:                            // Switching  to java.home
0189:                            systemRootDir = new File(System
0190:                                    .getProperty("java.home"), ".systemPrefs");
0191:                            if (!systemRootDir.exists()) {
0192:                                if (systemRootDir.mkdirs()) {
0193:                                    getLogger().info(
0194:                                            "Created system preferences directory "
0195:                                                    + "in java.home.");
0196:                                    try {
0197:                                        chmod(systemRootDir.getCanonicalPath(),
0198:                                                USER_RWX_ALL_RX);
0199:                                    } catch (IOException e) {
0200:                                    }
0201:                                } else {
0202:                                    getLogger()
0203:                                            .warning(
0204:                                                    "Could not create "
0205:                                                            + "system preferences directory. System "
0206:                                                            + "preferences are unusable.");
0207:                                }
0208:                            }
0209:                        }
0210:                        isSystemRootWritable = systemRootDir.canWrite();
0211:                        systemLockFile = new File(systemRootDir, ".system.lock");
0212:                        systemRootModFile = new File(systemRootDir,
0213:                                ".systemRootModFile");
0214:                        if (!systemRootModFile.exists() && isSystemRootWritable)
0215:                            try {
0216:                                // create if does not exist.
0217:                                systemRootModFile.createNewFile();
0218:                                int result = chmod(systemRootModFile
0219:                                        .getCanonicalPath(), USER_RW_ALL_READ);
0220:                                if (result != 0)
0221:                                    getLogger().warning(
0222:                                            "Chmod failed on "
0223:                                                    + systemRootModFile
0224:                                                            .getCanonicalPath()
0225:                                                    + " Unix error code "
0226:                                                    + result);
0227:                            } catch (IOException e) {
0228:                                getLogger().warning(e.toString());
0229:                            }
0230:                        systemRootModTime = systemRootModFile.lastModified();
0231:                        return null;
0232:                    }
0233:                });
0234:            }
0235:
0236:            /** 
0237:             * Unix user write/read permission
0238:             */
0239:            private static final int USER_READ_WRITE = 0600;
0240:
0241:            private static final int USER_RW_ALL_READ = 0644;
0242:
0243:            private static final int USER_RWX_ALL_RX = 0755;
0244:
0245:            private static final int USER_RWX = 0700;
0246:
0247:            /**
0248:             * The lock file for the user tree.
0249:             */
0250:            static File userLockFile;
0251:
0252:            /**
0253:             * The lock file for the system tree.
0254:             */
0255:            static File systemLockFile;
0256:
0257:            /**
0258:             * Unix lock handle for userRoot.
0259:             * Zero, if unlocked. 
0260:             */
0261:
0262:            private static int userRootLockHandle = 0;
0263:
0264:            /** 
0265:             * Unix lock handle for systemRoot.
0266:             * Zero, if unlocked. 
0267:             */
0268:
0269:            private static int systemRootLockHandle = 0;
0270:
0271:            /**
0272:             * The directory representing this preference node.  There is no guarantee
0273:             * that this directory exits, as another VM can delete it at any time
0274:             * that it (the other VM) holds the file-lock.  While the root node cannot
0275:             * be deleted, it may not yet have been created, or the underlying
0276:             * directory could have been deleted accidentally.
0277:             */
0278:            private final File dir;
0279:
0280:            /**
0281:             * The file representing this preference node's preferences.
0282:             * The file format is undocumented, and subject to change
0283:             * from release to release, but I'm sure that you can figure
0284:             * it out if you try real hard.
0285:             */
0286:            private final File prefsFile;
0287:
0288:            /**
0289:             * A temporary file used for saving changes to preferences.  As part of
0290:             * the sync operation, changes are first saved into this file, and then
0291:             * atomically renamed to prefsFile.  This results in an atomic state
0292:             * change from one valid set of preferences to another.  The
0293:             * the file-lock is held for the duration of this transformation.
0294:             */
0295:            private final File tmpFile;
0296:
0297:            /** 
0298:             * File, which keeps track of global modifications of userRoot.
0299:             */
0300:            private static File userRootModFile;
0301:
0302:            /** 
0303:             * Flag, which indicated whether userRoot was modified by another VM
0304:             */
0305:            private static boolean isUserRootModified = false;
0306:
0307:            /** 
0308:             * Keeps track of userRoot modification time. This time is reset to
0309:             * zero after UNIX reboot, and is increased by 1 second each time 
0310:             * userRoot is modified.
0311:             */
0312:            private static long userRootModTime;
0313:
0314:            /* 
0315:             * File, which keeps track of global modifications of systemRoot
0316:             */
0317:            private static File systemRootModFile;
0318:            /*
0319:             * Flag, which indicates whether systemRoot was modified by another VM
0320:             */
0321:            private static boolean isSystemRootModified = false;
0322:
0323:            /** 
0324:             * Keeps track of systemRoot modification time. This time is reset to
0325:             * zero after system reboot, and is increased by 1 second each time 
0326:             * systemRoot is modified.
0327:             */
0328:            private static long systemRootModTime;
0329:
0330:            /**
0331:             * Locally cached preferences for this node (includes uncommitted
0332:             * changes).  This map is initialized with from disk when the first get or
0333:             * put operation occurs on this node.  It is synchronized with the
0334:             * corresponding disk file (prefsFile) by the sync operation.  The initial
0335:             * value is read *without* acquiring the file-lock.
0336:             */
0337:            private Map prefsCache = null;
0338:
0339:            /**
0340:             * The last modification time of the file backing this node at the time
0341:             * that prefCache was last synchronized (or initially read).  This
0342:             * value is set *before* reading the file, so it's conservative; the 
0343:             * actual timestamp could be (slightly) higher.  A value of zero indicates
0344:             * that we were unable to initialize prefsCache from the disk, or
0345:             * have not yet attempted to do so.  (If prefsCache is non-null, it
0346:             * indicates the former; if it's null, the latter.)
0347:             */
0348:            private long lastSyncTime = 0;
0349:
0350:            /** 
0351:             * Unix error code for locked file.
0352:             */
0353:            private static final int EAGAIN = 11;
0354:
0355:            /** 
0356:             * Unix error code for denied access.
0357:             */
0358:            private static final int EACCES = 13;
0359:
0360:            /* Used to interpret results of native functions */
0361:            private static final int LOCK_HANDLE = 0;
0362:            private static final int ERROR_CODE = 1;
0363:
0364:            /**
0365:             * A list of all uncommitted preference changes.  The elements in this
0366:             * list are of type PrefChange.  If this node is concurrently modified on
0367:             * disk by another VM, the two sets of changes are merged when this node
0368:             * is sync'ed by overwriting our prefsCache with the preference map last
0369:             * written out to disk (by the other VM), and then replaying this change
0370:             * log against that map.  The resulting map is then written back
0371:             * to the disk.
0372:             */
0373:            final List changeLog = new ArrayList();
0374:
0375:            /**
0376:             * Represents a change to a preference.
0377:             */
0378:            private abstract class Change {
0379:                /**
0380:                 * Reapplies the change to prefsCache.
0381:                 */
0382:                abstract void replay();
0383:            };
0384:
0385:            /**
0386:             * Represents a preference put.
0387:             */
0388:            private class Put extends Change {
0389:                String key, value;
0390:
0391:                Put(String key, String value) {
0392:                    this .key = key;
0393:                    this .value = value;
0394:                }
0395:
0396:                void replay() {
0397:                    prefsCache.put(key, value);
0398:                }
0399:            }
0400:
0401:            /**
0402:             * Represents a preference remove.
0403:             */
0404:            private class Remove extends Change {
0405:                String key;
0406:
0407:                Remove(String key) {
0408:                    this .key = key;
0409:                }
0410:
0411:                void replay() {
0412:                    prefsCache.remove(key);
0413:                }
0414:            }
0415:
0416:            /**
0417:             * Represents the creation of this node.
0418:             */
0419:            private class NodeCreate extends Change {
0420:                /**
0421:                 * Performs no action, but the presence of this object in changeLog
0422:                 * will force the node and its ancestors to be made permanent at the
0423:                 * next sync.
0424:                 */
0425:                void replay() {
0426:                }
0427:            }
0428:
0429:            /**
0430:             * NodeCreate object for this node.
0431:             */
0432:            NodeCreate nodeCreate = null;
0433:
0434:            /**
0435:             * Replay changeLog against prefsCache.
0436:             */
0437:            private void replayChanges() {
0438:                for (int i = 0, n = changeLog.size(); i < n; i++)
0439:                    ((Change) changeLog.get(i)).replay();
0440:            }
0441:
0442:            private static Timer syncTimer = new Timer(true); // Daemon Thread
0443:
0444:            static {
0445:                // Add periodic timer task to periodically sync cached prefs
0446:                syncTimer.schedule(new TimerTask() {
0447:                    public void run() {
0448:                        syncWorld();
0449:                    }
0450:                }, SYNC_INTERVAL * 1000, SYNC_INTERVAL * 1000);
0451:
0452:                // Add shutdown hook to flush cached prefs on normal termination
0453:                AccessController.doPrivileged(new PrivilegedAction() {
0454:                    public Object run() {
0455:                        Runtime.getRuntime().addShutdownHook(new Thread() {
0456:                            public void run() {
0457:                                syncTimer.cancel();
0458:                                syncWorld();
0459:                            }
0460:                        });
0461:                        return null;
0462:                    }
0463:                });
0464:            }
0465:
0466:            private static void syncWorld() {
0467:                /*
0468:                 * Synchronization necessary because userRoot and systemRoot are
0469:                 * lazily initialized.
0470:                 */
0471:                Preferences userRt;
0472:                Preferences systemRt;
0473:                synchronized (FileSystemPreferences.class) {
0474:                    userRt = userRoot;
0475:                    systemRt = systemRoot;
0476:                }
0477:
0478:                try {
0479:                    if (userRt != null)
0480:                        userRt.flush();
0481:                } catch (BackingStoreException e) {
0482:                    getLogger().warning("Couldn't flush user prefs: " + e);
0483:                }
0484:
0485:                try {
0486:                    if (systemRt != null)
0487:                        systemRt.flush();
0488:                } catch (BackingStoreException e) {
0489:                    getLogger().warning("Couldn't flush system prefs: " + e);
0490:                }
0491:            }
0492:
0493:            private final boolean isUserNode;
0494:
0495:            /**
0496:             * Special constructor for roots (both user and system).  This constructor
0497:             * will only be called twice, by the static initializer.
0498:             */
0499:            private FileSystemPreferences(boolean user) {
0500:                super (null, "");
0501:                isUserNode = user;
0502:                dir = (user ? userRootDir : systemRootDir);
0503:                prefsFile = new File(dir, "prefs.xml");
0504:                tmpFile = new File(dir, "prefs.tmp");
0505:            }
0506:
0507:            /**
0508:             * Construct a new FileSystemPreferences instance with the specified
0509:             * parent node and name.  This constructor, called from childSpi,
0510:             * is used to make every node except for the two //roots.
0511:             */
0512:            private FileSystemPreferences(FileSystemPreferences parent,
0513:                    String name) {
0514:                super (parent, name);
0515:                isUserNode = parent.isUserNode;
0516:                dir = new File(parent.dir, dirName(name));
0517:                prefsFile = new File(dir, "prefs.xml");
0518:                tmpFile = new File(dir, "prefs.tmp");
0519:                AccessController.doPrivileged(new PrivilegedAction() {
0520:                    public Object run() {
0521:                        newNode = !dir.exists();
0522:                        return null;
0523:                    }
0524:                });
0525:                if (newNode) {
0526:                    // These 2 things guarantee node will get wrtten at next flush/sync
0527:                    prefsCache = new TreeMap();
0528:                    nodeCreate = new NodeCreate();
0529:                    changeLog.add(nodeCreate);
0530:                }
0531:            }
0532:
0533:            public boolean isUserNode() {
0534:                return isUserNode;
0535:            }
0536:
0537:            protected void putSpi(String key, String value) {
0538:                initCacheIfNecessary();
0539:                changeLog.add(new Put(key, value));
0540:                prefsCache.put(key, value);
0541:            }
0542:
0543:            protected String getSpi(String key) {
0544:                initCacheIfNecessary();
0545:                return (String) prefsCache.get(key);
0546:            }
0547:
0548:            protected void removeSpi(String key) {
0549:                initCacheIfNecessary();
0550:                changeLog.add(new Remove(key));
0551:                prefsCache.remove(key);
0552:            }
0553:
0554:            /**
0555:             * Initialize prefsCache if it has yet to be initialized.  When this method
0556:             * returns, prefsCache will be non-null.  If the data was successfully
0557:             * read from the file, lastSyncTime will be updated.  If prefsCache was
0558:             * null, but it was impossible to read the file (because it didn't
0559:             * exist or for any other reason) prefsCache will be initialized to an
0560:             * empty, modifiable Map, and lastSyncTime remain zero.
0561:             */
0562:            private void initCacheIfNecessary() {
0563:                if (prefsCache != null)
0564:                    return;
0565:
0566:                try {
0567:                    loadCache();
0568:                } catch (Exception e) {
0569:                    // assert lastSyncTime == 0;
0570:                    prefsCache = new TreeMap();
0571:                }
0572:            }
0573:
0574:            /**
0575:             * Attempt to load prefsCache from the backing store.  If the attempt
0576:             * succeeds, lastSyncTime will be updated (the new value will typically
0577:             * correspond to the data loaded into the map, but it may be less,
0578:             * if another VM is updating this node concurrently).  If the attempt
0579:             * fails, a BackingStoreException is thrown and both prefsCache and
0580:             * lastSyncTime are unaffected by the call.
0581:             */
0582:            private void loadCache() throws BackingStoreException {
0583:                try {
0584:                    AccessController
0585:                            .doPrivileged(new PrivilegedExceptionAction() {
0586:                                public Object run()
0587:                                        throws BackingStoreException {
0588:                                    Map m = new TreeMap();
0589:                                    long newLastSyncTime = 0;
0590:                                    try {
0591:                                        newLastSyncTime = prefsFile
0592:                                                .lastModified();
0593:                                        FileInputStream fis = new FileInputStream(
0594:                                                prefsFile);
0595:                                        XmlSupport.importMap(fis, m);
0596:                                        fis.close();
0597:                                    } catch (Exception e) {
0598:                                        if (e instanceof  InvalidPreferencesFormatException) {
0599:                                            getLogger().warning(
0600:                                                    "Invalid preferences format in "
0601:                                                            + prefsFile
0602:                                                                    .getPath());
0603:                                            prefsFile
0604:                                                    .renameTo(new File(
0605:                                                            prefsFile
0606:                                                                    .getParentFile(),
0607:                                                            "IncorrectFormatPrefs.xml"));
0608:                                            m = new TreeMap();
0609:                                        } else if (e instanceof  FileNotFoundException) {
0610:                                            getLogger().warning(
0611:                                                    "Prefs file removed in background "
0612:                                                            + prefsFile
0613:                                                                    .getPath());
0614:                                        } else {
0615:                                            throw new BackingStoreException(e);
0616:                                        }
0617:                                    }
0618:                                    // Attempt succeeded; update state
0619:                                    prefsCache = m;
0620:                                    lastSyncTime = newLastSyncTime;
0621:                                    return null;
0622:                                }
0623:                            });
0624:                } catch (PrivilegedActionException e) {
0625:                    throw (BackingStoreException) e.getException();
0626:                }
0627:            }
0628:
0629:            /**
0630:             * Attempt to write back prefsCache to the backing store.  If the attempt
0631:             * succeeds, lastSyncTime will be updated (the new value will correspond
0632:             * exactly to the data thust written back, as we hold the file lock, which
0633:             * prevents a concurrent write.  If the attempt fails, a
0634:             * BackingStoreException is thrown and both the backing store (prefsFile)
0635:             * and lastSyncTime will be unaffected by this call.  This call will
0636:             * NEVER leave prefsFile in a corrupt state.
0637:             */
0638:            private void writeBackCache() throws BackingStoreException {
0639:                try {
0640:                    AccessController
0641:                            .doPrivileged(new PrivilegedExceptionAction() {
0642:                                public Object run()
0643:                                        throws BackingStoreException {
0644:                                    try {
0645:                                        if (!dir.exists() && !dir.mkdirs())
0646:                                            throw new BackingStoreException(dir
0647:                                                    + " create failed.");
0648:                                        FileOutputStream fos = new FileOutputStream(
0649:                                                tmpFile);
0650:                                        XmlSupport.exportMap(fos, prefsCache);
0651:                                        fos.close();
0652:                                        if (!tmpFile.renameTo(prefsFile))
0653:                                            throw new BackingStoreException(
0654:                                                    "Can't rename " + tmpFile
0655:                                                            + " to "
0656:                                                            + prefsFile);
0657:                                    } catch (Exception e) {
0658:                                        if (e instanceof  BackingStoreException)
0659:                                            throw (BackingStoreException) e;
0660:                                        throw new BackingStoreException(e);
0661:                                    }
0662:                                    return null;
0663:                                }
0664:                            });
0665:                } catch (PrivilegedActionException e) {
0666:                    throw (BackingStoreException) e.getException();
0667:                }
0668:            }
0669:
0670:            protected String[] keysSpi() {
0671:                initCacheIfNecessary();
0672:                return (String[]) prefsCache.keySet().toArray(
0673:                        new String[prefsCache.size()]);
0674:            }
0675:
0676:            protected String[] childrenNamesSpi() {
0677:                return (String[]) AccessController
0678:                        .doPrivileged(new PrivilegedAction() {
0679:                            public Object run() {
0680:                                List result = new ArrayList();
0681:                                File[] dirContents = dir.listFiles();
0682:                                if (dirContents != null) {
0683:                                    for (int i = 0; i < dirContents.length; i++)
0684:                                        if (dirContents[i].isDirectory())
0685:                                            result.add(nodeName(dirContents[i]
0686:                                                    .getName()));
0687:                                }
0688:                                return result.toArray(EMPTY_STRING_ARRAY);
0689:                            }
0690:                        });
0691:            }
0692:
0693:            private static final String[] EMPTY_STRING_ARRAY = new String[0];
0694:
0695:            protected AbstractPreferences childSpi(String name) {
0696:                return new FileSystemPreferences(this , name);
0697:            }
0698:
0699:            public void removeNode() throws BackingStoreException {
0700:                synchronized (isUserNode() ? userLockFile : systemLockFile) {
0701:                    // to remove a node we need an exclusive lock
0702:                    if (!lockFile(false))
0703:                        throw (new BackingStoreException(
0704:                                "Couldn't get file lock."));
0705:                    try {
0706:                        super .removeNode();
0707:                    } finally {
0708:                        unlockFile();
0709:                    }
0710:                }
0711:            }
0712:
0713:            /**
0714:             * Called with file lock held (in addition to node locks).
0715:             */
0716:            protected void removeNodeSpi() throws BackingStoreException {
0717:                try {
0718:                    AccessController
0719:                            .doPrivileged(new PrivilegedExceptionAction() {
0720:                                public Object run()
0721:                                        throws BackingStoreException {
0722:                                    if (changeLog.contains(nodeCreate)) {
0723:                                        changeLog.remove(nodeCreate);
0724:                                        nodeCreate = null;
0725:                                        return null;
0726:                                    }
0727:                                    if (!dir.exists())
0728:                                        return null;
0729:                                    prefsFile.delete();
0730:                                    tmpFile.delete();
0731:                                    // dir should be empty now.  If it's not, empty it
0732:                                    File[] junk = dir.listFiles();
0733:                                    if (junk.length != 0) {
0734:                                        getLogger().warning(
0735:                                                "Found extraneous files when removing node: "
0736:                                                        + Arrays.asList(junk));
0737:                                        for (int i = 0; i < junk.length; i++)
0738:                                            junk[i].delete();
0739:                                    }
0740:                                    if (!dir.delete())
0741:                                        throw new BackingStoreException(
0742:                                                "Couldn't delete dir: " + dir);
0743:                                    return null;
0744:                                }
0745:                            });
0746:                } catch (PrivilegedActionException e) {
0747:                    throw (BackingStoreException) e.getException();
0748:                }
0749:            }
0750:
0751:            public synchronized void sync() throws BackingStoreException {
0752:                boolean userNode = isUserNode();
0753:                boolean shared;
0754:
0755:                if (userNode) {
0756:                    shared = false; /* use exclusive lock for user prefs */
0757:                } else {
0758:                    /* if can write to system root, use exclusive lock.
0759:                       otherwise use shared lock. */
0760:                    shared = !isSystemRootWritable;
0761:                }
0762:                synchronized (isUserNode() ? userLockFile : systemLockFile) {
0763:                    if (!lockFile(shared))
0764:                        throw (new BackingStoreException(
0765:                                "Couldn't get file lock."));
0766:                    final Long newModTime = (Long) AccessController
0767:                            .doPrivileged(new PrivilegedAction() {
0768:                                public Object run() {
0769:                                    long nmt;
0770:                                    if (isUserNode()) {
0771:                                        nmt = userRootModFile.lastModified();
0772:                                        isUserRootModified = userRootModTime == nmt;
0773:                                    } else {
0774:                                        nmt = systemRootModFile.lastModified();
0775:                                        isSystemRootModified = systemRootModTime == nmt;
0776:                                    }
0777:                                    return new Long(nmt);
0778:                                }
0779:                            });
0780:                    try {
0781:                        super .sync();
0782:                        AccessController.doPrivileged(new PrivilegedAction() {
0783:                            public Object run() {
0784:                                if (isUserNode()) {
0785:                                    userRootModTime = newModTime.longValue() + 1000;
0786:                                    userRootModFile
0787:                                            .setLastModified(userRootModTime);
0788:                                } else {
0789:                                    systemRootModTime = newModTime.longValue() + 1000;
0790:                                    systemRootModFile
0791:                                            .setLastModified(systemRootModTime);
0792:                                }
0793:                                return null;
0794:                            }
0795:                        });
0796:                    } finally {
0797:                        unlockFile();
0798:                    }
0799:                }
0800:            }
0801:
0802:            protected void syncSpi() throws BackingStoreException {
0803:                try {
0804:                    AccessController
0805:                            .doPrivileged(new PrivilegedExceptionAction() {
0806:                                public Object run()
0807:                                        throws BackingStoreException {
0808:                                    syncSpiPrivileged();
0809:                                    return null;
0810:                                }
0811:                            });
0812:                } catch (PrivilegedActionException e) {
0813:                    throw (BackingStoreException) e.getException();
0814:                }
0815:            }
0816:
0817:            private void syncSpiPrivileged() throws BackingStoreException {
0818:                if (isRemoved())
0819:                    throw new IllegalStateException("Node has been removed");
0820:                if (prefsCache == null)
0821:                    return; // We've never been used, don't bother syncing
0822:                long lastModifiedTime;
0823:                if ((isUserNode() ? isUserRootModified : isSystemRootModified)) {
0824:                    lastModifiedTime = prefsFile.lastModified();
0825:                    if (lastModifiedTime != lastSyncTime) {
0826:                        // Prefs at this node were externally modified; read in node and
0827:                        // playback any local mods since last sync
0828:                        loadCache();
0829:                        replayChanges();
0830:                        lastSyncTime = lastModifiedTime;
0831:                    }
0832:                } else if (lastSyncTime != 0 && !dir.exists()) {
0833:                    // This node was removed in the background.  Playback any changes
0834:                    // against a virgin (empty) Map.
0835:                    prefsCache = new TreeMap();
0836:                    replayChanges();
0837:                }
0838:                if (!changeLog.isEmpty()) {
0839:                    writeBackCache(); // Creates directory & file if necessary
0840:                    /*
0841:                     * Attempt succeeded; it's barely possible that the call to
0842:                     * lastModified might fail (i.e., return 0), but this would not
0843:                     * be a disaster, as lastSyncTime is allowed to lag.
0844:                     */
0845:                    lastModifiedTime = prefsFile.lastModified();
0846:                    /* If lastSyncTime did not change, or went back 
0847:                     * increment by 1 second. Since we hold the lock 
0848:                     * lastSyncTime always monotonically encreases in the
0849:                     * atomic sense.
0850:                     */
0851:                    if (lastSyncTime <= lastModifiedTime) {
0852:                        lastSyncTime = lastModifiedTime + 1000;
0853:                        prefsFile.setLastModified(lastSyncTime);
0854:                    }
0855:                    changeLog.clear();
0856:                }
0857:            }
0858:
0859:            public void flush() throws BackingStoreException {
0860:                if (isRemoved())
0861:                    return;
0862:                sync();
0863:            }
0864:
0865:            protected void flushSpi() throws BackingStoreException {
0866:                // assert false;
0867:            }
0868:
0869:            /**
0870:             * Returns true if the specified character is appropriate for use in
0871:             * Unix directory names.  A character is appropriate if it's a printable
0872:             * ASCII character (> 0x1f && < 0x7f) and unequal to slash ('/', 0x2f),
0873:             * dot ('.', 0x2e), or underscore ('_', 0x5f).
0874:             */
0875:            private static boolean isDirChar(char ch) {
0876:                return ch > 0x1f && ch < 0x7f && ch != '/' && ch != '.'
0877:                        && ch != '_';
0878:            }
0879:
0880:            /**
0881:             * Returns the directory name corresponding to the specified node name.
0882:             * Generally, this is just the node name.  If the node name includes
0883:             * inappropriate characters (as per isDirChar) it is translated to Base64.
0884:             * with the underscore  character ('_', 0x5f) prepended. 
0885:             */
0886:            private static String dirName(String nodeName) {
0887:                for (int i = 0, n = nodeName.length(); i < n; i++)
0888:                    if (!isDirChar(nodeName.charAt(i)))
0889:                        return "_"
0890:                                + Base64
0891:                                        .byteArrayToAltBase64(byteArray(nodeName));
0892:                return nodeName;
0893:            }
0894:
0895:            /**
0896:             * Translate a string into a byte array by translating each character
0897:             * into two bytes, high-byte first ("big-endian").
0898:             */
0899:            private static byte[] byteArray(String s) {
0900:                int len = s.length();
0901:                byte[] result = new byte[2 * len];
0902:                for (int i = 0, j = 0; i < len; i++) {
0903:                    char c = s.charAt(i);
0904:                    result[j++] = (byte) (c >> 8);
0905:                    result[j++] = (byte) c;
0906:                }
0907:                return result;
0908:            }
0909:
0910:            /**
0911:             * Returns the node name corresponding to the specified directory name.
0912:             * (Inverts the transformation of dirName(String).
0913:             */
0914:            private static String nodeName(String dirName) {
0915:                if (dirName.charAt(0) != '_')
0916:                    return dirName;
0917:                byte a[] = Base64.altBase64ToByteArray(dirName.substring(1));
0918:                StringBuffer result = new StringBuffer(a.length / 2);
0919:                for (int i = 0; i < a.length;) {
0920:                    int highByte = a[i++] & 0xff;
0921:                    int lowByte = a[i++] & 0xff;
0922:                    result.append((char) ((highByte << 8) | lowByte));
0923:                }
0924:                return result.toString();
0925:            }
0926:
0927:            /**
0928:             * Try to acquire the appropriate file lock (user or system).  If
0929:             * the initial attempt fails, several more attempts are made using
0930:             * an exponential backoff strategy.  If all attempts fail, this method
0931:             * returns false.
0932:             * @throws SecurityException if file access denied.
0933:             */
0934:            private boolean lockFile(boolean shared) throws SecurityException {
0935:                boolean usernode = isUserNode();
0936:                int[] result;
0937:                int errorCode = 0;
0938:                File lockFile = (usernode ? userLockFile : systemLockFile);
0939:                long sleepTime = INIT_SLEEP_TIME;
0940:                for (int i = 0; i < MAX_ATTEMPTS; i++) {
0941:                    try {
0942:                        int perm = (usernode ? USER_READ_WRITE
0943:                                : USER_RW_ALL_READ);
0944:                        result = lockFile0(lockFile.getCanonicalPath(), perm,
0945:                                shared);
0946:
0947:                        errorCode = result[ERROR_CODE];
0948:                        if (result[LOCK_HANDLE] != 0) {
0949:                            if (usernode) {
0950:                                userRootLockHandle = result[LOCK_HANDLE];
0951:                            } else {
0952:                                systemRootLockHandle = result[LOCK_HANDLE];
0953:                            }
0954:                            return true;
0955:                        }
0956:                    } catch (IOException e) {
0957:                        //                // If at first, you don't succeed...
0958:                    }
0959:
0960:                    try {
0961:                        Thread.sleep(sleepTime);
0962:                    } catch (InterruptedException e) {
0963:                        checkLockFile0ErrorCode(errorCode);
0964:                        return false;
0965:                    }
0966:                    sleepTime *= 2;
0967:                }
0968:                checkLockFile0ErrorCode(errorCode);
0969:                return false;
0970:            }
0971:
0972:            /** 
0973:             * Checks if unlockFile0() returned an error. Throws a SecurityException,
0974:             * if access denied. Logs a warning otherwise.
0975:             */
0976:            private void checkLockFile0ErrorCode(int errorCode)
0977:                    throws SecurityException {
0978:                if (errorCode == EACCES)
0979:                    throw new SecurityException("Could not lock "
0980:                            + (isUserNode() ? "User prefs." : "System prefs.")
0981:                            + " Lock file access denied.");
0982:                if (errorCode != EAGAIN)
0983:                    getLogger().warning(
0984:                            "Could not lock "
0985:                                    + (isUserNode() ? "User prefs. "
0986:                                            : "System prefs.")
0987:                                    + " Unix error code " + errorCode + ".");
0988:            }
0989:
0990:            /**
0991:             * Locks file using UNIX file locking.
0992:             * @param fileName Absolute file name of the lock file.
0993:             * @return Returns a lock handle, used to unlock the file.
0994:             */
0995:            private static native int[] lockFile0(String fileName,
0996:                    int permission, boolean shared);
0997:
0998:            /**
0999:             * Unlocks file previously locked by lockFile0().
1000:             * @param lockHandle Handle to the file lock.
1001:             * @return Returns zero if OK, UNIX error code if failure.
1002:             */
1003:            private static native int unlockFile0(int lockHandle);
1004:
1005:            /**
1006:             * Changes UNIX file permissions.
1007:             */
1008:            private static native int chmod(String fileName, int permission);
1009:
1010:            /**
1011:             * Initial time between lock attempts, in ms.  The time is doubled
1012:             * after each failing attempt (except the first).
1013:             */
1014:            private static int INIT_SLEEP_TIME = 50;
1015:
1016:            /**
1017:             * Maximum number of lock attempts.
1018:             */
1019:            private static int MAX_ATTEMPTS = 5;
1020:
1021:            /**
1022:             * Release the the appropriate file lock (user or system).
1023:             * @throws SecurityException if file access denied.
1024:             */
1025:            private void unlockFile() {
1026:                int result;
1027:                boolean usernode = isUserNode();
1028:                File lockFile = (usernode ? userLockFile : systemLockFile);
1029:                int lockHandle = (usernode ? userRootLockHandle
1030:                        : systemRootLockHandle);
1031:                if (lockHandle == 0) {
1032:                    getLogger().warning(
1033:                            "Unlock: zero lockHandle for "
1034:                                    + (usernode ? "user" : "system")
1035:                                    + " preferences.)");
1036:                    return;
1037:                }
1038:                result = unlockFile0(lockHandle);
1039:                if (result != 0) {
1040:                    getLogger().warning(
1041:                            "Could not drop file-lock on "
1042:                                    + (isUserNode() ? "user" : "system")
1043:                                    + " preferences." + " Unix error code "
1044:                                    + result + ".");
1045:                    if (result == EACCES)
1046:                        throw new SecurityException("Could not unlock"
1047:                                + (isUserNode() ? "User prefs."
1048:                                        : "System prefs.")
1049:                                + " Lock file access denied.");
1050:                }
1051:                if (isUserNode()) {
1052:                    userRootLockHandle = 0;
1053:                } else {
1054:                    systemRootLockHandle = 0;
1055:                }
1056:            }
1057:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.