Source Code Cross Referenced for Registry.java in  » Scripting » oscript-2.10.4 » ti » chimera » 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 » Scripting » oscript 2.10.4 » ti.chimera 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*=============================================================================
002:         *     Copyright Texas Instruments, Inc., 2001.  All Rights Reserved.
003:         * 
004:         *  This program is free software; you can redistribute it and/or modify
005:         *  it under the terms of the GNU General Public License as published by
006:         *  the Free Software Foundation; either version 2 of the License, or
007:         *  (at your option) any later version.
008:         * 
009:         *  This program is distributed in the hope that it will be useful,
010:         *  but WITHOUT ANY WARRANTY; without even the implied warranty of
011:         *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
012:         *  GNU General Public License for more details.
013:         * 
014:         *  You should have received a copy of the GNU General Public License
015:         *  along with this program; if not, write to the Free Software
016:         *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
017:         */
018:
019:        package ti.chimera;
020:
021:        import ti.chimera.registry.*;
022:        import ti.exceptions.ProgrammingErrorException;
023:
024:        import java.util.*;
025:
026:        /**
027:         * The registry is a mechanism that allows different parts of the system
028:         * share data.  It is traditionally used to store registered plugins and
029:         * services, but other parts of the system can use the registry to store
030:         * or share data.  The registry uses a publish-subscribe model, where in
031:         * order to track the value of a node, the user subscribes to the node,
032:         * and whenever the value of the node changes the most recent value is
033:         * published to the subscriber's callback function.  The registry will
034:         * ensure that changes are published in the order they occur, and that
035:         * all changes will be published, even if they've already been super-
036:         * ceded by subsequent changes.
037:         * <p>
038:         * The registry is organized as a hierarchical tree, where "nodes" are
039:         * either parent nodes (directories) or data nodes.  Directory nodes
040:         * are just data nodes whose data is a table mapping child names to
041:         * nodes.  A <code>path</code> is a <code>/</code> delimited string that
042:         * specifies how to find a node from the root of the tree.  Paths can
043:         * contain <code>..</code> to refer to one level up in the tree, or
044:         * <code>.</code> to refer to the current level in the tree.
045:         * <p>
046:         * The registry can be accessed via {@link ti.chimera.Main#getRegistry}
047:         * or from the script environment variable <code>registry</code>.
048:         * 
049:         * @author Rob Clark
050:         * @version 0.1
051:         * @see ti.chimera.Main#getRegistry
052:         */
053:        public class Registry extends RegistryCore {
054:            /*=======================================================================*/
055:            /**
056:             * Class Constructor.
057:             */
058:            Registry(Main main) {
059:                super (main);
060:            }
061:
062:            /* 
063:             * Convenience API:
064:             */
065:
066:            /*=======================================================================*/
067:            /**
068:             * Subscribe to receive notification of changes to the value of the node
069:             * at the specified path.  This subscription is relative to the specified
070:             * <code>path</code>, and not the node that is currently located at that
071:             * path.  If there is currently a node at this path, then the subscriber
072:             * will be immediately called with the current value, otherwise the
073:             * subscriber will be called once the node is created.  If the node at
074:             * this path is removed, and then at some later time another node is
075:             * {@link #link}ed in to this path, then the subscriber will subscribed
076:             * to that node (and immediately called with it's value), and so on.
077:             * <p>
078:             * If <code>contract</code> is not <code>null</code>, then only subscribe
079:             * to the node if it has a compatible contract.
080:             * 
081:             * @param path         the path to the node to subscribe to
082:             * @param contract     the optional contract, or <code>null</code>
083:             * @param subscriber   the subscriber
084:             */
085:            public void subscribeToValue(String path,
086:                    final NodeContract contract, final NodeSubscriber subscriber) {
087:                if (subscriber == null)
088:                    throw new ProgrammingErrorException(
089:                            "illegal argument: subscriber is null");
090:                else if (path == null)
091:                    throw new ProgrammingErrorException(
092:                            "illegal argument: path is null");
093:
094:                NodeSeeker ns;
095:
096:                subscribeToValueSubscriberMap.put(subscriber,
097:                        ns = new NodeSeeker(path) {
098:
099:                            void publishFromSoughtNode(Node node, Object value) {
100:                                if (((contract == null) ? NodeContract.NULL_CONTRACT
101:                                        : contract).accepts(value))
102:                                    subscriber.publish(node, value);
103:                            }
104:
105:                        });
106:
107:                ns.start();
108:            }
109:
110:            private Map subscribeToValueSubscriberMap = new Hashtable();
111:
112:            /**
113:             * Unsubscribe from specified path.  If not subscribed, do nothing.
114:             * 
115:             * @param subscriber   the subscriber
116:             */
117:            public void unsubscribeFromValue(NodeSubscriber subscriber) {
118:                NodeSeeker ns = (NodeSeeker) (subscribeToValueSubscriberMap
119:                        .remove(subscriber));
120:
121:                if (ns != null)
122:                    ns.dispose();
123:            }
124:
125:            /*=======================================================================*/
126:            /**
127:             * Subscribe to the creation of a node.  The subscriber will be called
128:             * whenever a node is {@link #link}ed in to the specified path.  If the
129:             * node already exists, the subscriber will be called (pretty much)
130:             * immediately.
131:             * 
132:             * @param path         the path to the node to subscribe to
133:             * @param subscriber   the subscriber
134:             */
135:            public void subscribeToCreation(String path,
136:                    final NodeCreationSubscriber subscriber) {
137:                if (subscriber == null)
138:                    throw new ProgrammingErrorException(
139:                            "illegal argument: subscriber is null");
140:                else if (path == null)
141:                    throw new ProgrammingErrorException(
142:                            "illegal argument: path is null");
143:
144:                final String basename = basename(path);
145:                NodeSeeker ns;
146:
147:                subscribeToCreationSubscriberMap.put(subscriber,
148:                        ns = new NodeSeeker(dirname(path)) {
149:
150:                            private DirectoryTable lastDt;
151:
152:                            void publishFromSoughtNode(Node node, Object value) {
153:                                DirectoryTable newDt = (DirectoryTable) value;
154:
155:                                for (Iterator added = newDt.notIn(lastDt); added
156:                                        .hasNext();) {
157:                                    if (added.next().equals(basename)) {
158:                                        subscriber.nodeCreated(newDt
159:                                                .get(basename));
160:                                        break;
161:                                    }
162:                                }
163:
164:                                lastDt = newDt;
165:                            }
166:
167:                        });
168:
169:                ns.start();
170:            }
171:
172:            private Map subscribeToCreationSubscriberMap = new Hashtable();
173:
174:            /**
175:             * Unsubscribe to the creation of a node.  If not subscribed, do nothing.
176:             * 
177:             * @param subscriber   the subscriber
178:             */
179:            public void unsubscribeFromCreation(
180:                    NodeCreationSubscriber subscriber) {
181:                NodeSeeker ns = (NodeSeeker) (subscribeToCreationSubscriberMap
182:                        .remove(subscriber));
183:
184:                if (ns != null)
185:                    ns.dispose();
186:            }
187:
188:            /*=======================================================================*/
189:            /**
190:             * Subscribe to the deletion of a node.  The subscriber will be called
191:             * whenever a node is {@link #unlink}ed from the specified path.
192:             * 
193:             * @param path         the path to the node to subscribe to
194:             * @param subscriber   the subscriber
195:             */
196:            public void subscribeToDeletion(String path,
197:                    final NodeDeletionSubscriber subscriber) {
198:                if (subscriber == null)
199:                    throw new ProgrammingErrorException(
200:                            "illegal argument: subscriber is null");
201:                else if (path == null)
202:                    throw new ProgrammingErrorException(
203:                            "illegal argument: path is null");
204:
205:                final String basename = basename(path);
206:                NodeSeeker ns;
207:
208:                subscribeToDeletionSubscriberMap.put(subscriber,
209:                        ns = new NodeSeeker(dirname(path)) {
210:
211:                            private DirectoryTable lastDt;
212:
213:                            void publishFromSoughtNode(Node node, Object value) {
214:                                DirectoryTable newDt = (DirectoryTable) value;
215:                                DirectoryTable lastDt = this .lastDt;
216:                                this .lastDt = newDt;
217:
218:                                if (lastDt != null) {
219:                                    for (Iterator removed = lastDt.notIn(newDt); removed
220:                                            .hasNext();) {
221:                                        if (removed.next().equals(basename)) {
222:                                            subscriber.nodeDeleted(lastDt
223:                                                    .get(basename));
224:                                            break;
225:                                        }
226:                                    }
227:                                }
228:                            }
229:
230:                        });
231:
232:                ns.start();
233:            }
234:
235:            private Map subscribeToDeletionSubscriberMap = new Hashtable();
236:
237:            /**
238:             * Unsubscribe to the deletion of a node.  If not subscribed, do nothing.
239:             * 
240:             * @param subscriber   the subscriber
241:             */
242:            public void unsubscribeFromDeletion(
243:                    NodeDeletionSubscriber subscriber) {
244:                NodeSeeker ns = (NodeSeeker) (subscribeToDeletionSubscriberMap
245:                        .remove(subscriber));
246:
247:                if (ns != null)
248:                    ns.dispose();
249:            }
250:
251:            /* 
252:             * Plugin/Service API:
253:             */
254:
255:            /*=======================================================================*/
256:            /**
257:             * Register a plugin.  This is how a plugin is added to the system.  Once
258:             * a plugin is added, the plugin can be resolved by {@link #getPlugin} and
259:             * a service provided by a plugin can be resolved by {@link #getService}.
260:             * The registry will handle starting a plugin if needed.
261:             * 
262:             * @param plugin       the plugin to register
263:             * @see #getPlugin
264:             * @see #getService
265:             */
266:            public void register(Plugin plugin) {
267:                checkName(plugin.getName());
268:                main.debug(1, "registering plugin: \"" + plugin.getName()
269:                        + "\"");
270:
271:                String path = "/Plugins/" + plugin.getName();
272:
273:                // remove old node at same path, if there is one:
274:                try {
275:                    unlink(path, true);
276:                } catch (RegistryException e) {
277:                }
278:
279:                // create plugin directory:
280:                mkdir(path);
281:                mkdir(path + "/Services");
282:
283:                // link in plugin instance:
284:                try {
285:                    link(new Node(plugin, new TypeNodeContract(Plugin.class),
286:                            "The \"" + plugin.getName() + "\" instance"), path
287:                            + "/instance");
288:                } catch (RegistryException e) {
289:                    throw new ProgrammingErrorException(e);
290:                }
291:
292:                // populate directory node with services:
293:                for (Iterator itr = plugin.getServiceFactories(); itr.hasNext();) {
294:                    Plugin.ServiceFactory f = ((Plugin.ServiceFactory) (itr
295:                            .next()));
296:                    main.debug(1, "registering service: \"" + f.getName()
297:                            + "\" provided by \"" + plugin.getName() + "\"");
298:
299:                    Node node = new Node(f, new TypeNodeContract(
300:                            Plugin.ServiceFactory.class),
301:                            "The service-factory for the \"" + f.getName()
302:                                    + "\" service");
303:
304:                    // remove old service node at same path, if there is one:
305:                    try {
306:                        if (exists("/Services/" + f.getName()))
307:                            unlink("/Services/" + f.getName());
308:                    } catch (RegistryException e) {
309:                        throw new ProgrammingErrorException(e);
310:                    }
311:
312:                    try {
313:                        link(node, path + "/Services/" + f.getName());
314:                        link(node, "/Services/" + f.getName());
315:                    } catch (RegistryException e) {
316:                        throw new ProgrammingErrorException(e);
317:                    }
318:                }
319:            }
320:
321:            /*=======================================================================*/
322:            /**
323:             * Get service provided by a plugin by name.  This will automatically
324:             * start the plugin providing the service if it has not already been
325:             * started.
326:             * 
327:             * @param name         the name of the plugin to find
328:             * @see #getServiceNames
329:             */
330:            public Service getService(String name) {
331:                checkName(name);
332:                try {
333:                    return ((Plugin.ServiceFactory) (resolve("/Services/"
334:                            + name).getValue())).getService();
335:                } catch (RegistryException e) {
336:                    return null;
337:                }
338:            }
339:
340:            private static void checkName(String name) {
341:                if (name.indexOf('/') != -1)
342:                    throw new ProgrammingErrorException(
343:                            "invalid service name: \"" + name + "\"");
344:            }
345:
346:            /*=========================================================================*/
347:            /**
348:             * The convenience API uses NodeSubscribers to "find" a particular node,
349:             * even if it doesn't currently exist.  In the case of the creation/
350:             * deletion subscriber API, the node-seeker is looking for the parent
351:             * directory of the node of interest to the user.  In the case of the
352:             * value subscriber, the node-seeker is seeking the actual node that the 
353:             * user is interested in.  Whatever the case, all of these node-seekers 
354:             * share the same node-seeking algorithm, and only differ in what they 
355:             * do once they've found their node of interest.
356:             */
357:            abstract class NodeSeeker {
358:                /**
359:                 * The path we are trying to subscribe to.
360:                 */
361:                private String soughtPath;
362:
363:                /**
364:                 * The root of the chain of subscribers to each parent directory leading
365:                 * up to the node at the sought-path
366:                 */
367:                private NodeSeekerSubscriber root;
368:
369:                /**
370:                 * Class Constructor.
371:                 * 
372:                 * @param soughtPath   the path to the node this seeker is seeking
373:                 */
374:                public NodeSeeker(String soughtPath) {
375:                    this .soughtPath = normalize(soughtPath);
376:                }
377:
378:                /**
379:                 * We have to create the root *after* the parent class constructor is 
380:                 * completed, to work around some "quirks" about how inner classes
381:                 * work (ie. by copying final vars in to instance of innser class)
382:                 */
383:                void start() {
384:                    root = new NodeSeekerSubscriber(Registry.this .root, "/");
385:                }
386:
387:                /**
388:                 * Called when the user unsubscribes, and this NodeSeeker 
389:                 * should clean up all it's subscribers.
390:                 */
391:                void dispose() {
392:                    root.dispose();
393:                }
394:
395:                /**
396:                 * When a <code>publish</code> happens from the node at the path of
397:                 * interest (ie. the sought node), we call this method which should
398:                 * be implemented by the derived class to do whatever is necessary.
399:                 */
400:                abstract void publishFromSoughtNode(Node node, Object value);
401:
402:                /**
403:                 * An instance of this subscriber is created for each parent directory
404:                 * leading up to and including the node at the sought path.  When any of 
405:                 * these subscribers detect that their next in the chain is removed, it 
406:                 * messages the next in chain by calling {@link #dispose}.  Conversely
407:                 * when a node detects that a child has been added that is the next in
408:                 * the chain, it creates a new subscriber for that child.
409:                 */
410:                class NodeSeekerSubscriber implements  NodeSubscriber {
411:                    private Node node;
412:                    private String path;
413:                    private String childName; // the name of the child we are watching for
414:
415:                    private NodeSeekerSubscriber next; // node corresponding to childName
416:                    private DirectoryTable lastDt;
417:
418:                    NodeSeekerSubscriber(Node node, String path) {
419:                        this .node = node;
420:                        this .path = path;
421:
422:                        if (!path.equals(soughtPath)) {
423:                            int idx = soughtPath
424:                                    .indexOf('/', path.length() + 1);
425:                            if (idx == -1)
426:                                idx = soughtPath.length();
427:                            childName = basename(soughtPath.substring(path
428:                                    .length(), idx));
429:                        }
430:
431:                        node.subscribe(this );
432:                    }
433:
434:                    public void publish(Node node, Object value) {
435:                        if (childName == null) {
436:                            publishFromSoughtNode(node, value);
437:                        } else {
438:                            DirectoryTable newDt = (DirectoryTable) value;
439:
440:                            if (lastDt != null) {
441:                                for (Iterator removed = lastDt.notIn(newDt); removed
442:                                        .hasNext();) {
443:                                    if (removed.next().equals(childName)) {
444:                                        next.dispose();
445:                                        next = null;
446:                                    }
447:                                }
448:                            }
449:
450:                            for (Iterator added = newDt.notIn(lastDt); added
451:                                    .hasNext();) {
452:                                String name = (String) (added.next());
453:
454:                                if (name.equals(childName)) {
455:                                    if (next != null)
456:                                        throw new ProgrammingErrorException(
457:                                                "shouldn't be possible!");
458:
459:                                    next = new NodeSeekerSubscriber(newDt
460:                                            .get(name), normalize(path + "/"
461:                                            + childName));
462:                                }
463:                            }
464:
465:                            lastDt = newDt;
466:                        }
467:                    }
468:
469:                    void dispose() {
470:                        if (next != null)
471:                            next.dispose();
472:                        node.unsubscribe(this );
473:                    }
474:                }
475:            }
476:        }
477:
478:        /*
479:         *   Local Variables:
480:         *   tab-width: 2
481:         *   indent-tabs-mode: nil
482:         *   mode: java
483:         *   c-indentation-style: java
484:         *   c-basic-offset: 2
485:         *   eval: (c-set-offset 'substatement-open '0)
486:         *   eval: (c-set-offset 'case-label '+)
487:         *   eval: (c-set-offset 'inclass '+)
488:         *   eval: (c-set-offset 'inline-open '0)
489:         *   End:
490:         */
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.