Source Code Cross Referenced for AbstractPreferences.java in  » Apache-Harmony-Java-SE » java-package » 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 » Apache Harmony Java SE » java package » java.util.prefs 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         *  Licensed to the Apache Software Foundation (ASF) under one or more
003:         *  contributor license agreements.  See the NOTICE file distributed with
004:         *  this work for additional information regarding copyright ownership.
005:         *  The ASF licenses this file to You under the Apache License, Version 2.0
006:         *  (the "License"); you may not use this file except in compliance with
007:         *  the License.  You may obtain a copy of the License at
008:         *
009:         *     http://www.apache.org/licenses/LICENSE-2.0
010:         *
011:         *  Unless required by applicable law or agreed to in writing, software
012:         *  distributed under the License is distributed on an "AS IS" BASIS,
013:         *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014:         *  See the License for the specific language governing permissions and
015:         *  limitations under the License.
016:         */
017:
018:        package java.util.prefs;
019:
020:        import java.io.IOException;
021:        import java.io.OutputStream;
022:        import java.io.UnsupportedEncodingException;
023:        import java.util.EventListener;
024:        import java.util.EventObject;
025:        import java.util.HashMap;
026:        import java.util.Iterator;
027:        import java.util.LinkedList;
028:        import java.util.List;
029:        import java.util.Map;
030:        import java.util.StringTokenizer;
031:        import java.util.TreeSet;
032:
033:        import org.apache.harmony.luni.util.Base64;
034:        import org.apache.harmony.prefs.internal.nls.Messages;
035:
036:        /**
037:         * This class is partly implementation of <code>Preferences</code>, which can be 
038:         * used to simplify <code>Preferences</code> provider's implementation. 
039:         * <p>
040:         * This class define nine abstract SPI methods, which must be implemented by 
041:         * preference provider. And provider can also override other methods of this 
042:         * class. Some SPI methods will throw <code>BackingStoreException</code>, 
043:         * including <code>childrenNamesSpi()</code>, <code>flushSpi()</code>, 
044:         * <code>keysSpi()</code>, <code>removeNodeSpi()</code>, 
045:         * <code>syncSpi()</code>; <code>getSpi(String, String)</code> never throws any 
046:         * exceptions; the last SPI methods, <code>putSpi(String)</code>, 
047:         * <code>removeSpi(String)</code> and <code>childSpi(String)</code> won't throw 
048:         * <code>BackingStoreException</code>, but in some implementations, they may 
049:         * throw <code>SecurityException</code> due to lacking the permission to access 
050:         * backing end storage.</p>
051:         * 
052:         * @since 1.4
053:         * @see Preferences
054:         */
055:        public abstract class AbstractPreferences extends Preferences {
056:            /*
057:             * -----------------------------------------------------------
058:             * Class fields
059:             * -----------------------------------------------------------
060:             */
061:            /** the unhandled events collection */
062:            private static final List<EventObject> events = new LinkedList<EventObject>();
063:            /** the event dispatcher thread */
064:            private static final EventDispatcher dispatcher = new EventDispatcher(
065:                    "Preference Event Dispatcher"); //$NON-NLS-1$
066:
067:            /*
068:             * -----------------------------------------------------------
069:             * Class initializer
070:             * -----------------------------------------------------------
071:             */
072:            static {
073:                dispatcher.setDaemon(true);
074:                dispatcher.start();
075:                Runtime.getRuntime().addShutdownHook(new Thread() {
076:                    @Override
077:                    public void run() {
078:                        Preferences uroot = Preferences.userRoot();
079:                        Preferences sroot = Preferences.systemRoot();
080:                        try {
081:                            uroot.flush();
082:                        } catch (BackingStoreException e) {//ignore
083:                        }
084:                        try {
085:                            sroot.flush();
086:                        } catch (BackingStoreException e) {//ignore
087:                        }
088:                    }
089:                });
090:            }
091:
092:            /*
093:             * -----------------------------------------------------------
094:             * Instance fields (package-private)
095:             * -----------------------------------------------------------
096:             */
097:            /** true if this node is in user preference hierarchy */
098:            boolean userNode;
099:
100:            /*
101:             * -----------------------------------------------------------
102:             * Instance fields (private)
103:             * -----------------------------------------------------------
104:             */
105:            /** Marker class for 'lock' field. */
106:            private static class Lock {
107:            }
108:
109:            /** The object used to lock this node. */
110:            protected final Object lock;
111:
112:            /**
113:             * This field is true if this node is created while it doesn't exist in the 
114:             * backing store. This field's default value is false, and it is checked when 
115:             * the node creation is completed, and if it is true, the node change event 
116:             * will be fired for this node's parent.
117:             */
118:            protected boolean newNode;
119:
120:            /** cached child nodes */
121:            private Map<String, AbstractPreferences> cachedNode;
122:
123:            //the collections of listeners
124:            private List<EventListener> nodeChangeListeners;
125:            private List<EventListener> preferenceChangeListeners;
126:
127:            //this node's name
128:            private String nodeName;
129:
130:            //handler to this node's parent
131:            private AbstractPreferences parentPref;
132:
133:            //true if this node has been removed
134:            private boolean isRemoved;
135:
136:            //handler to this node's root node
137:            private AbstractPreferences root;
138:
139:            /*
140:             * -----------------------------------------------------------
141:             * Constructors
142:             * -----------------------------------------------------------
143:             */
144:            /**
145:             * Construct a new <code>AbstractPreferences</code> instance using given 
146:             * parent node and node name. 
147:             *
148:             * @param parent
149:             * 				the parent node of this node, can be null, which means this 
150:             * 				node is root
151:             * @param name
152:             * 				the name of this node, can be empty(""), which means this 
153:             * 				node is root
154:             * @throws IllegalArgumentException
155:             * 				if name contains slash, or be empty if parent is not null
156:             */
157:            protected AbstractPreferences(AbstractPreferences parent,
158:                    String name) {
159:                if ((null == parent ^ name.length() == 0)
160:                        || name.indexOf("/") >= 0) { //$NON-NLS-1$
161:                    throw new IllegalArgumentException();
162:                }
163:                root = null == parent ? this  : parent.root;
164:                nodeChangeListeners = new LinkedList<EventListener>();
165:                preferenceChangeListeners = new LinkedList<EventListener>();
166:                isRemoved = false;
167:                cachedNode = new HashMap<String, AbstractPreferences>();
168:                nodeName = name;
169:                parentPref = parent;
170:                lock = new Lock();
171:                userNode = root.userNode;
172:            }
173:
174:            /*
175:             * -----------------------------------------------------------
176:             * Methods
177:             * -----------------------------------------------------------
178:             */
179:            /**
180:             * Return arrays of all cached children node.
181:             * 
182:             * @return arrays of all cached children node.
183:             */
184:            protected final AbstractPreferences[] cachedChildren() {
185:                return cachedNode.values().toArray(
186:                        new AbstractPreferences[cachedNode.size()]);
187:            }
188:
189:            /**
190:             * Return the child node with given name, or null if it doesn't exist. The 
191:             * given name must be valid and this node cannot be removed. Invocation of 
192:             * this method implies that the node with given name is not cached(or, has 
193:             * been removed.)
194:             * 
195:             * @param name	the given child name to be got 
196:             * @return		the child node with given name, or null if it doesn't exist 
197:             * @throws BackingStoreException
198:             * 				if backing store is unavailable or causes operation failure
199:             */
200:            protected AbstractPreferences getChild(String name)
201:                    throws BackingStoreException {
202:                synchronized (lock) {
203:                    checkState();
204:                    AbstractPreferences result = null;
205:                    String[] childrenNames = childrenNames();
206:                    for (int i = 0; i < childrenNames.length; i++) {
207:                        if (childrenNames[i].equals(name)) {
208:                            result = childSpi(name);
209:                            break;
210:                        }
211:                    }
212:                    return result;
213:                }
214:
215:            }
216:
217:            /**
218:             * Return true if and only if this node has been removed by invoking 
219:             * {@link #removeNode() removeNode}. 
220:             *
221:             * @return true if and only if this node has been removed by invoking 
222:             * 			{@link #removeNode() removeNode}
223:             */
224:            protected boolean isRemoved() {
225:                synchronized (lock) {
226:                    return isRemoved;
227:                }
228:            }
229:
230:            /**
231:             * Flush changes of this node to the backing store. This method should only 
232:             * flush this node, and should not include the descendant nodes. The 
233:             * implementation which want to flush all nodes at once should override 
234:             * {@link #flush() flush()} method. 
235:             *
236:             * @throws BackingStoreException
237:             * 				if backing store is unavailable or causes operation failure
238:             */
239:            protected abstract void flushSpi() throws BackingStoreException;
240:
241:            /**
242:             * Return names of this node's all children , or empty array if this node has 
243:             * no child. Cached children name is not required to be returned.
244:             *
245:             * @return names of this node's all children
246:             * @throws BackingStoreException
247:             * 				if backing store is unavailable or causes operation failure
248:             */
249:            protected abstract String[] childrenNamesSpi()
250:                    throws BackingStoreException;
251:
252:            /**
253:             * Return the child preference node with the given name, and create new one if 
254:             * it does not exist. Invoker of this method should assure that the given name 
255:             * are valid as well as this node is not removed. Invocation of this method 
256:             * implies that the node with given name is not cached(or, has been removed.)
257:             * If the named node has just been removed, implementation of this method must 
258:             * create a new one instead of reactivated the removed one. 
259:             * <p>
260:             * The new creation is not required to be persisted immediately until the flush 
261:             * method is invoked.</p>
262:             * 
263:             * @param name
264:             * @return AbstractPreferences
265:             */
266:            protected abstract AbstractPreferences childSpi(String name);
267:
268:            /**
269:             * Put the given key-value pair into this node. Invoker of this method should
270:             * assure that both the given values are valid as well as this node 
271:             * is not removed.
272:             *
273:             * @param name	the given preference key
274:             * @param value the given preference value
275:             */
276:            protected abstract void putSpi(String name, String value);
277:
278:            /**
279:             * Get the preference value mapped to the given key. Invoker of this method 
280:             * should assure that given key are valid as well as this node is not removed. 
281:             * This method should not throw exceptions, but if it does, the invoker should 
282:             * catch it and deal with it as null return value.
283:             *
284:             * @param key	the given key to be searched for
285:             * @return the preference value mapped to the given key
286:             */
287:            protected abstract String getSpi(String key);
288:
289:            /**
290:             * Return all keys of this node's preferences, or empty array if no preference 
291:             * found on this node. Invoker of this method should assure that this node is 
292:             * not removed.
293:             *
294:             * @return all keys of this node's preferences
295:             * @throws BackingStoreException
296:             * 				if backing store is unavailable or causes operation failure
297:             */
298:            protected abstract String[] keysSpi() throws BackingStoreException;
299:
300:            /**
301:             * Remove this node from the preference hierarchy tree. The invoker of this 
302:             * method should assure that this node has no child node, which means the 
303:             * {@link Preferences#removeNode() Preferences.removeNode()} should invoke 
304:             * this method multi-times in bottom-up pattern. The removal is not required 
305:             * to be persisted at once until the it is flushed.  
306:             *
307:             * @throws BackingStoreException
308:             * 				if backing store is unavailable or causes operation failure
309:             */
310:            protected abstract void removeNodeSpi()
311:                    throws BackingStoreException;
312:
313:            /**
314:             * Remove the preference with the given key. Invoker of this method 
315:             * should assure that given key are valid as well as this node is not removed. 
316:             * 
317:             * @param key	the given key to removed
318:             */
319:            protected abstract void removeSpi(String key);
320:
321:            /**
322:             * Synchronize this node with the backing store. This method should only 
323:             * synchronize this node, and should not include the descendant nodes. The 
324:             * implementation which want to synchronize all nodes at once should override 
325:             * {@link #sync() sync()} method. 
326:             * 
327:             * @throws BackingStoreException
328:             * 				if backing store is unavailable or causes operation failure
329:             */
330:            protected abstract void syncSpi() throws BackingStoreException;
331:
332:            /*
333:             * -----------------------------------------------------------
334:             * Methods inherited from Preferences
335:             * -----------------------------------------------------------
336:             */
337:            @Override
338:            public String absolutePath() {
339:                if (parentPref == null) {
340:                    return "/"; //$NON-NLS-1$
341:                } else if (parentPref == root) {
342:                    return "/" + nodeName; //$NON-NLS-1$
343:                }
344:                return parentPref.absolutePath() + "/" + nodeName; //$NON-NLS-1$
345:            }
346:
347:            @Override
348:            public String[] childrenNames() throws BackingStoreException {
349:                synchronized (lock) {
350:                    checkState();
351:                    TreeSet<String> result = new TreeSet<String>(cachedNode
352:                            .keySet());
353:                    String[] names = childrenNamesSpi();
354:                    for (int i = 0; i < names.length; i++) {
355:                        result.add(names[i]);
356:                    }
357:                    return result.toArray(new String[0]);
358:                }
359:            }
360:
361:            @Override
362:            public void clear() throws BackingStoreException {
363:                synchronized (lock) {
364:                    String[] keyList = keys();
365:                    for (int i = 0; i < keyList.length; i++) {
366:                        remove(keyList[i]);
367:                    }
368:                }
369:            }
370:
371:            @Override
372:            public void exportNode(OutputStream ostream) throws IOException,
373:                    BackingStoreException {
374:                if (ostream == null) {
375:                    // prefs.5=Stream is null
376:                    throw new NullPointerException(Messages
377:                            .getString("prefs.5")); //$NON-NLS-1$
378:                }
379:                checkState();
380:                XMLParser.exportPrefs(this , ostream, false);
381:
382:            }
383:
384:            @Override
385:            public void exportSubtree(OutputStream ostream) throws IOException,
386:                    BackingStoreException {
387:                if (ostream == null) {
388:                    // prefs.5=Stream is null
389:                    throw new NullPointerException(Messages
390:                            .getString("prefs.5")); //$NON-NLS-1$
391:                }
392:                checkState();
393:                XMLParser.exportPrefs(this , ostream, true);
394:            }
395:
396:            @Override
397:            public void flush() throws BackingStoreException {
398:                synchronized (lock) {
399:                    flushSpi();
400:                }
401:                AbstractPreferences[] cc = cachedChildren();
402:                int i;
403:                for (i = 0; i < cc.length; i++) {
404:                    cc[i].flush();
405:                }
406:            }
407:
408:            @Override
409:            public String get(String key, String deflt) {
410:                if (key == null) {
411:                    throw new NullPointerException();
412:                }
413:                String result;
414:                synchronized (lock) {
415:                    checkState();
416:                    try {
417:                        result = getSpi(key);
418:                    } catch (Exception e) {
419:                        result = null;
420:                    }
421:                }
422:                return (result == null ? deflt : result);
423:            }
424:
425:            @Override
426:            public boolean getBoolean(String key, boolean deflt) {
427:                String result = get(key, null);
428:                if (result == null) {
429:                    return deflt;
430:                } else if (result.equalsIgnoreCase("true")) { //$NON-NLS-1$
431:                    return true;
432:                } else if (result.equalsIgnoreCase("false")) { //$NON-NLS-1$
433:                    return false;
434:                } else {
435:                    return deflt;
436:                }
437:            }
438:
439:            @Override
440:            public byte[] getByteArray(String key, byte[] deflt) {
441:                String svalue = get(key, null);
442:                if (svalue == null) {
443:                    return deflt;
444:                }
445:                if (svalue.length() == 0) {
446:                    return new byte[0];
447:                }
448:                byte[] dres;
449:                try {
450:                    byte[] bavalue = svalue.getBytes("US-ASCII"); //$NON-NLS-1$
451:                    if (bavalue.length % 4 != 0) {
452:                        return deflt;
453:                    }
454:                    dres = Base64.decode(bavalue);
455:                } catch (Exception e) {
456:                    dres = deflt;
457:                }
458:                return dres;
459:            }
460:
461:            @Override
462:            public double getDouble(String key, double deflt) {
463:                String result = get(key, null);
464:                if (result == null) {
465:                    return deflt;
466:                }
467:                double dres;
468:                try {
469:                    dres = Double.parseDouble(result);
470:                } catch (NumberFormatException e) {
471:                    dres = deflt;
472:                }
473:                return dres;
474:            }
475:
476:            @Override
477:            public float getFloat(String key, float deflt) {
478:                String result = get(key, null);
479:                if (result == null) {
480:                    return deflt;
481:                }
482:                float fres;
483:                try {
484:                    fres = Float.parseFloat(result);
485:                } catch (NumberFormatException e) {
486:                    fres = deflt;
487:                }
488:                return fres;
489:            }
490:
491:            @Override
492:            public int getInt(String key, int deflt) {
493:                String result = get(key, null);
494:                if (result == null) {
495:                    return deflt;
496:                }
497:                int ires;
498:                try {
499:                    ires = Integer.parseInt(result);
500:                } catch (NumberFormatException e) {
501:                    ires = deflt;
502:                }
503:                return ires;
504:            }
505:
506:            @Override
507:            public long getLong(String key, long deflt) {
508:                String result = get(key, null);
509:                if (result == null) {
510:                    return deflt;
511:                }
512:                long lres;
513:                try {
514:                    lres = Long.parseLong(result);
515:                } catch (NumberFormatException e) {
516:                    lres = deflt;
517:                }
518:                return lres;
519:            }
520:
521:            @Override
522:            public boolean isUserNode() {
523:                return root == Preferences.userRoot();
524:            }
525:
526:            @Override
527:            public String[] keys() throws BackingStoreException {
528:                synchronized (lock) {
529:                    checkState();
530:                    return keysSpi();
531:                }
532:            }
533:
534:            @Override
535:            public String name() {
536:                return nodeName;
537:            }
538:
539:            @Override
540:            public Preferences node(String name) {
541:                AbstractPreferences startNode = null;
542:                synchronized (lock) {
543:                    checkState();
544:                    validateName(name);
545:                    if ("".equals(name)) { //$NON-NLS-1$
546:                        return this ;
547:                    } else if ("/".equals(name)) { //$NON-NLS-1$
548:                        return root;
549:                    }
550:                    if (name.startsWith("/")) { //$NON-NLS-1$
551:                        startNode = root;
552:                        name = name.substring(1);
553:                    } else {
554:                        startNode = this ;
555:                    }
556:                }
557:                Preferences result = null;
558:                try {
559:                    result = startNode.nodeImpl(name, true);
560:                } catch (BackingStoreException e) {
561:                    //should not happen
562:                }
563:                return result;
564:            }
565:
566:            private void validateName(String name) {
567:                if (name.endsWith("/") && name.length() > 1) { //$NON-NLS-1$
568:                    // prefs.6=Name cannot end with '/'\!
569:                    throw new IllegalArgumentException(Messages
570:                            .getString("prefs.6")); //$NON-NLS-1$
571:                }
572:                if (name.indexOf("//") >= 0) { //$NON-NLS-1$
573:                    // prefs.7=Name cannot contains consecutive '/'\!
574:                    throw new IllegalArgumentException(Messages
575:                            .getString("prefs.7")); //$NON-NLS-1$
576:                }
577:            }
578:
579:            private AbstractPreferences nodeImpl(String path, boolean createNew)
580:                    throws BackingStoreException {
581:                StringTokenizer st = new StringTokenizer(path, "/"); //$NON-NLS-1$
582:                AbstractPreferences currentNode = this ;
583:                AbstractPreferences temp = null;
584:                while (st.hasMoreTokens() && null != currentNode) {
585:                    String name = st.nextToken();
586:                    synchronized (currentNode.lock) {
587:                        temp = currentNode.cachedNode.get(name);
588:                        if (temp == null) {
589:                            temp = getNodeFromBackend(createNew, currentNode,
590:                                    name);
591:                        }
592:                    }
593:
594:                    currentNode = temp;
595:                }
596:                return currentNode;
597:            }
598:
599:            private AbstractPreferences getNodeFromBackend(boolean createNew,
600:                    AbstractPreferences currentNode, String name)
601:                    throws BackingStoreException {
602:                AbstractPreferences temp;
603:                if (name.length() > MAX_NAME_LENGTH) {
604:                    // prefs.8=Name length is too long: {0}
605:                    throw new IllegalArgumentException(Messages.getString(
606:                            "prefs.8", //$NON-NLS-1$
607:                            name));
608:                }
609:                if (createNew) {
610:                    temp = currentNode.childSpi(name);
611:                    currentNode.cachedNode.put(name, temp);
612:                    if (temp.newNode
613:                            && currentNode.nodeChangeListeners.size() > 0) {
614:                        currentNode.notifyChildAdded(temp);
615:                    }
616:                } else {
617:                    temp = currentNode.getChild(name);
618:                }
619:                return temp;
620:            }
621:
622:            @Override
623:            public boolean nodeExists(String name) throws BackingStoreException {
624:                AbstractPreferences startNode = null;
625:                synchronized (lock) {
626:                    if (isRemoved()) {
627:                        if ("".equals(name)) { //$NON-NLS-1$
628:                            return false;
629:                        }
630:                        // prefs.9=This node has been removed\!
631:                        throw new IllegalStateException(Messages
632:                                .getString("prefs.9")); //$NON-NLS-1$
633:                    }
634:                    validateName(name);
635:                    if ("".equals(name) || "/".equals(name)) { //$NON-NLS-1$ //$NON-NLS-2$
636:                        return true;
637:                    }
638:                    if (name.startsWith("/")) { //$NON-NLS-1$
639:                        startNode = root;
640:                        name = name.substring(1);
641:                    } else {
642:                        startNode = this ;
643:                    }
644:                }
645:                try {
646:                    Preferences result = startNode.nodeImpl(name, false);
647:                    return null == result ? false : true;
648:                } catch (IllegalArgumentException e) {
649:                    return false;
650:                }
651:            }
652:
653:            @Override
654:            public Preferences parent() {
655:                checkState();
656:                return parentPref;
657:            }
658:
659:            private void checkState() {
660:                if (isRemoved()) {
661:                    // prefs.9=This node has been removed\!
662:                    throw new IllegalStateException(Messages
663:                            .getString("prefs.9")); //$NON-NLS-1$
664:                }
665:            }
666:
667:            @Override
668:            public void put(String key, String value) {
669:                if (null == key || null == value) {
670:                    throw new NullPointerException();
671:                }
672:                if (key.length() > MAX_KEY_LENGTH
673:                        || value.length() > MAX_VALUE_LENGTH) {
674:                    throw new IllegalArgumentException();
675:                }
676:                synchronized (lock) {
677:                    checkState();
678:                    putSpi(key, value);
679:                }
680:                notifyPreferenceChange(key, value);
681:            }
682:
683:            @Override
684:            public void putBoolean(String key, boolean value) {
685:                String sval = String.valueOf(value);
686:                put(key, sval);
687:            }
688:
689:            @Override
690:            public void putByteArray(String key, byte[] value) {
691:                try {
692:                    put(key, Base64.encode(value, "US-ASCII")); //$NON-NLS-1$
693:                } catch (UnsupportedEncodingException e) {
694:                    throw new AssertionError(e);
695:                }
696:            }
697:
698:            @Override
699:            public void putDouble(String key, double value) {
700:                String sval = Double.toString(value);
701:                put(key, sval);
702:            }
703:
704:            @Override
705:            public void putFloat(String key, float value) {
706:                String sval = Float.toString(value);
707:                put(key, sval);
708:            }
709:
710:            @Override
711:            public void putInt(String key, int value) {
712:                String sval = Integer.toString(value);
713:                put(key, sval);
714:            }
715:
716:            @Override
717:            public void putLong(String key, long value) {
718:                String sval = Long.toString(value);
719:                put(key, sval);
720:            }
721:
722:            @Override
723:            public void remove(String key) {
724:                synchronized (lock) {
725:                    checkState();
726:                    removeSpi(key);
727:                }
728:                notifyPreferenceChange(key, null);
729:            }
730:
731:            @Override
732:            public void removeNode() throws BackingStoreException {
733:                if (root == this ) {
734:                    // prefs.A=Cannot remove root node\!
735:                    throw new UnsupportedOperationException(Messages
736:                            .getString("prefs.A")); //$NON-NLS-1$
737:                }
738:                synchronized (parentPref.lock) {
739:                    removeNodeImpl();
740:                }
741:            }
742:
743:            private void removeNodeImpl() throws BackingStoreException {
744:                synchronized (lock) {
745:                    checkState();
746:                    String[] childrenNames = childrenNamesSpi();
747:                    for (int i = 0; i < childrenNames.length; i++) {
748:                        if (null == cachedNode.get(childrenNames[i])) {
749:                            AbstractPreferences child = childSpi(childrenNames[i]);
750:                            cachedNode.put(childrenNames[i], child);
751:                        }
752:                    }
753:                    AbstractPreferences[] children = cachedNode.values()
754:                            .toArray(new AbstractPreferences[0]);
755:                    for (int i = 0; i < children.length; i++) {
756:                        children[i].removeNodeImpl();
757:                    }
758:                    removeNodeSpi();
759:                    isRemoved = true;
760:                    parentPref.cachedNode.remove(nodeName);
761:                }
762:                if (parentPref.nodeChangeListeners.size() > 0) {
763:                    parentPref.notifyChildRemoved(this );
764:                }
765:            }
766:
767:            @Override
768:            public void addNodeChangeListener(NodeChangeListener ncl) {
769:                if (null == ncl) {
770:                    throw new NullPointerException();
771:                }
772:                checkState();
773:                synchronized (nodeChangeListeners) {
774:                    nodeChangeListeners.add(ncl);
775:                }
776:            }
777:
778:            @Override
779:            public void addPreferenceChangeListener(PreferenceChangeListener pcl) {
780:                if (null == pcl) {
781:                    throw new NullPointerException();
782:                }
783:                checkState();
784:                synchronized (preferenceChangeListeners) {
785:                    preferenceChangeListeners.add(pcl);
786:                }
787:            }
788:
789:            @Override
790:            public void removeNodeChangeListener(NodeChangeListener ncl) {
791:                checkState();
792:                synchronized (nodeChangeListeners) {
793:                    int pos;
794:                    if ((pos = nodeChangeListeners.indexOf(ncl)) == -1) {
795:                        throw new IllegalArgumentException();
796:                    }
797:                    nodeChangeListeners.remove(pos);
798:                }
799:            }
800:
801:            @Override
802:            public void removePreferenceChangeListener(
803:                    PreferenceChangeListener pcl) {
804:                checkState();
805:                synchronized (preferenceChangeListeners) {
806:                    int pos;
807:                    if ((pos = preferenceChangeListeners.indexOf(pcl)) == -1) {
808:                        throw new IllegalArgumentException();
809:                    }
810:                    preferenceChangeListeners.remove(pos);
811:                }
812:            }
813:
814:            @Override
815:            public void sync() throws BackingStoreException {
816:                synchronized (lock) {
817:                    checkState();
818:                    syncSpi();
819:                }
820:                AbstractPreferences[] cc = cachedChildren();
821:                int i;
822:                for (i = 0; i < cc.length; i++) {
823:                    cc[i].sync();
824:                }
825:            }
826:
827:            @Override
828:            public String toString() {
829:                StringBuffer sb = new StringBuffer();
830:                sb.append(isUserNode() ? "User" : "System"); //$NON-NLS-1$ //$NON-NLS-2$
831:                sb.append(" Preference Node: "); //$NON-NLS-1$
832:                sb.append(absolutePath());
833:                return sb.toString();
834:            }
835:
836:            private void notifyChildAdded(Preferences child) {
837:                NodeChangeEvent nce = new NodeAddEvent(this , child);
838:                synchronized (events) {
839:                    events.add(nce);
840:                    events.notifyAll();
841:                }
842:            }
843:
844:            private void notifyChildRemoved(Preferences child) {
845:                NodeChangeEvent nce = new NodeRemoveEvent(this , child);
846:                synchronized (events) {
847:                    events.add(nce);
848:                    events.notifyAll();
849:                }
850:            }
851:
852:            private void notifyPreferenceChange(String key, String newValue) {
853:                PreferenceChangeEvent pce = new PreferenceChangeEvent(this ,
854:                        key, newValue);
855:                synchronized (events) {
856:                    events.add(pce);
857:                    events.notifyAll();
858:                }
859:            }
860:
861:            private static class EventDispatcher extends Thread {
862:                EventDispatcher(String name) {
863:                    super (name);
864:                }
865:
866:                @Override
867:                public void run() {
868:                    while (true) {
869:                        EventObject event = null;
870:                        try {
871:                            event = getEventObject();
872:                        } catch (InterruptedException e) {
873:                            e.printStackTrace();
874:                            continue;
875:                        }
876:                        AbstractPreferences pref = (AbstractPreferences) event
877:                                .getSource();
878:                        if (event instanceof  NodeAddEvent) {
879:                            dispatchNodeAdd((NodeChangeEvent) event,
880:                                    pref.nodeChangeListeners);
881:                        } else if (event instanceof  NodeRemoveEvent) {
882:                            dispatchNodeRemove((NodeChangeEvent) event,
883:                                    pref.nodeChangeListeners);
884:                        } else if (event instanceof  PreferenceChangeEvent) {
885:                            dispatchPrefChange((PreferenceChangeEvent) event,
886:                                    pref.preferenceChangeListeners);
887:                        }
888:                    }
889:                }
890:
891:                private EventObject getEventObject()
892:                        throws InterruptedException {
893:                    synchronized (events) {
894:                        if (events.isEmpty()) {
895:                            events.wait();
896:                        }
897:                        EventObject event = events.get(0);
898:                        events.remove(0);
899:                        return event;
900:                    }
901:                }
902:
903:                private void dispatchPrefChange(PreferenceChangeEvent event,
904:                        List<EventListener> preferenceChangeListeners) {
905:                    synchronized (preferenceChangeListeners) {
906:                        Iterator<EventListener> i = preferenceChangeListeners
907:                                .iterator();
908:                        while (i.hasNext()) {
909:                            PreferenceChangeListener pcl = (PreferenceChangeListener) i
910:                                    .next();
911:                            pcl.preferenceChange(event);
912:                        }
913:                    }
914:                }
915:
916:                private void dispatchNodeRemove(NodeChangeEvent event,
917:                        List<EventListener> nodeChangeListeners) {
918:                    synchronized (nodeChangeListeners) {
919:                        Iterator<EventListener> i = nodeChangeListeners
920:                                .iterator();
921:                        while (i.hasNext()) {
922:                            NodeChangeListener ncl = (NodeChangeListener) i
923:                                    .next();
924:                            ncl.childRemoved(event);
925:                        }
926:                    }
927:                }
928:
929:                private void dispatchNodeAdd(NodeChangeEvent event,
930:                        List<EventListener> nodeChangeListeners) {
931:                    synchronized (nodeChangeListeners) {
932:                        Iterator<EventListener> i = nodeChangeListeners
933:                                .iterator();
934:                        while (i.hasNext()) {
935:                            NodeChangeListener ncl = (NodeChangeListener) i
936:                                    .next();
937:                            ncl.childAdded(event);
938:                        }
939:                    }
940:                }
941:            }
942:
943:            private static class NodeAddEvent extends NodeChangeEvent {
944:                //The base class is NOT serializable, so this class isn't either.
945:                private static final long serialVersionUID = 1L;
946:
947:                public NodeAddEvent(Preferences p, Preferences c) {
948:                    super (p, c);
949:                }
950:            }
951:
952:            private static class NodeRemoveEvent extends NodeChangeEvent {
953:                //The base class is NOT serializable, so this class isn't either.
954:                private static final long serialVersionUID = 1L;
955:
956:                public NodeRemoveEvent(Preferences p, Preferences c) {
957:                    super(p, c);
958:                }
959:            }
960:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.