Source Code Cross Referenced for ConfigContainer.java in  » 6.0-JDK-Modules » java-3d » com » sun » j3d » utils » universe » 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 Modules » java 3d » com.sun.j3d.utils.universe 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * $RCSfile: ConfigContainer.java,v $
0003:         *
0004:         * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
0005:         *
0006:         * Redistribution and use in source and binary forms, with or without
0007:         * modification, are permitted provided that the following conditions
0008:         * are met:
0009:         *
0010:         * - Redistribution of source code must retain the above copyright
0011:         *   notice, this list of conditions and the following disclaimer.
0012:         *
0013:         * - Redistribution in binary form must reproduce the above copyright
0014:         *   notice, this list of conditions and the following disclaimer in
0015:         *   the documentation and/or other materials provided with the
0016:         *   distribution.
0017:         *
0018:         * Neither the name of Sun Microsystems, Inc. or the names of
0019:         * contributors may be used to endorse or promote products derived
0020:         * from this software without specific prior written permission.
0021:         *
0022:         * This software is provided "AS IS," without a warranty of any
0023:         * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
0024:         * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
0025:         * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
0026:         * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
0027:         * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
0028:         * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
0029:         * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
0030:         * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
0031:         * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
0032:         * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
0033:         * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
0034:         * POSSIBILITY OF SUCH DAMAGES.
0035:         *
0036:         * You acknowledge that this software is not designed, licensed or
0037:         * intended for use in the design, construction, operation or
0038:         * maintenance of any nuclear facility.
0039:         *
0040:         * $Revision: 1.6 $
0041:         * $Date: 2007/02/09 17:20:43 $
0042:         * $State: Exp $
0043:         */
0044:
0045:        package com.sun.j3d.utils.universe;
0046:
0047:        import java.io.*;
0048:        import java.util.*;
0049:        import java.net.URL;
0050:        import java.net.MalformedURLException;
0051:        import javax.media.j3d.*;
0052:        import com.sun.j3d.utils.behaviors.vp.ViewPlatformBehavior;
0053:
0054:        /**
0055:         * Loads a Java 3D configuration file and creates a container of named objects
0056:         * that will effect the viewing configuration specified in the file.  These
0057:         * can include Viewers, ViewingPlatforms, ViewPlatformBehaviors, InputDevices,
0058:         * Sensors, and other objects.<p>
0059:         * 
0060:         * Clients can construct the view side of a scene graph by retrieving these
0061:         * objects using the accessor methods provided by this class.  This could
0062:         * involve as little as just attaching ViewingPlatforms to a Locale, depending
0063:         * upon how completely the viewing configuration is specified in the file.
0064:         * The ConfiguredUniverse class is an example of a ConfigContainer client and
0065:         * how it can be used.<p>
0066:         *
0067:         * ConfigContainer can be useful for clients other than ConfiguredUniverse.
0068:         * InputDevice and ViewPlatformBehavior configuration is fully supported, so a
0069:         * given Java 3D installation can provide configuration files to an
0070:         * application that will allow it to fully utilize whatever site-specific
0071:         * devices and behaviors are available.  The configuration mechanism can be
0072:         * extended for any target object through the use of the
0073:         * <code>NewObject</code> and <code>ObjectProperty</code> configuration
0074:         * commands.
0075:         *
0076:         * @see ConfiguredUniverse
0077:         * @see <a href="doc-files/config-syntax.html">
0078:         *      The Java 3D Configuration File</a>
0079:         * @see <a href="doc-files/config-examples.html">
0080:         *      Example Configuration Files</a>
0081:         *
0082:         * @since Java 3D 1.3.1
0083:         */
0084:        public class ConfigContainer {
0085:            //
0086:            // The configuration object database is implemented with a HashMap which
0087:            // maps their class names to ArrayList objects which contain the actual
0088:            // instances.  The latter are used since the instances of a given class
0089:            // must be evaluated in the order in which they were created.
0090:            // LinkedHashMap is available in JDK 1.4 but currently this code must run
0091:            // under JDK 1.3.1 as well.
0092:            // 
0093:            private Map baseNameMap = new HashMap();
0094:
0095:            // Map containing named canvases for each view.
0096:            private Map viewCanvasMap = new HashMap();
0097:
0098:            // Read-only Maps for the public interface to the configuration database.
0099:            private ReadOnlyMap bodyMap = null;
0100:            private ReadOnlyMap environmentMap = null;
0101:            private ReadOnlyMap viewerMap = null;
0102:            private ReadOnlyMap deviceMap = null;
0103:            private ReadOnlyMap sensorMap = null;
0104:            private ReadOnlyMap behaviorMap = null;
0105:            private ReadOnlyMap platformMap = null;
0106:            private ReadOnlyMap genericObjectMap = null;
0107:
0108:            // Read-only Sets for the public interface to the configuration database.
0109:            private ReadOnlySet bodies = null;
0110:            private ReadOnlySet environments = null;
0111:            private ReadOnlySet viewers = null;
0112:            private ReadOnlySet devices = null;
0113:            private ReadOnlySet sensors = null;
0114:            private ReadOnlySet behaviors = null;
0115:            private ReadOnlySet platforms = null;
0116:            private ReadOnlySet genericObjects = null;
0117:
0118:            // The number of TransformGroups to include in ViewingPlatforms.
0119:            private int transformCount = 1;
0120:
0121:            // The visibility status of Viewer AWT components.
0122:            private boolean setVisible = false;
0123:
0124:            private ClassLoader classLoader = ClassLoader
0125:                    .getSystemClassLoader();
0126:
0127:            /**
0128:             * The name of the file this ConfigContainer is currently loading.
0129:             */
0130:            String currentFileName = null;
0131:
0132:            /**
0133:             * Creates a new ConfigContainer and loads the configuration file at the
0134:             * specified URL.  All ViewingPlatform instances are created with a single
0135:             * TransformGroup and all Viewer components are initially invisible.
0136:             *
0137:             * @param userConfig URL of the configuration file to load
0138:             */
0139:            public ConfigContainer(URL userConfig) {
0140:                this (userConfig, false, 1, true);
0141:            }
0142:
0143:            /**
0144:             * Creates a new ConfigContainer and loads the configuration file at the
0145:             * specified URL.  All ViewingPlatform instances are created with a single
0146:             * TransformGroup and all Viewer components are initially invisible.
0147:             *
0148:             * @param userConfig URL of the configuration file to load
0149:             * @param classLoader the class loader to use to load classes specified
0150:             * in the config file.
0151:             */
0152:            public ConfigContainer(URL userConfig, ClassLoader classLoader) {
0153:                this (userConfig, false, 1, true, classLoader);
0154:            }
0155:
0156:            /**
0157:             * Creates a new ConfigContainer and loads the configuration file at the
0158:             * specified URL.  Any ViewingPlatform instantiated by the configuration
0159:             * file will be created with the specified number of transforms.  Viewer
0160:             * components may be set initially visible or invisible with the
0161:             * <code>setVisible</code> flag.
0162:             *
0163:             * @param userConfig URL of the configuration file to load
0164:             * @param setVisible if true, <code>setVisible(true)</code> is called on
0165:             *  all Viewers
0166:             * @param transformCount number of transforms to be included in any
0167:             *  ViewingPlatform created; must be greater than 0
0168:             */
0169:            public ConfigContainer(URL userConfig, boolean setVisible,
0170:                    int transformCount) {
0171:
0172:                this (userConfig, setVisible, transformCount, true);
0173:            }
0174:
0175:            /**
0176:             * Creates a new ConfigContainer and loads the configuration file at the
0177:             * specified URL.  Any ViewingPlatform instantiated by the configuration
0178:             * file will be created with the specified number of transforms.  Viewer
0179:             * components may be set initially visible or invisible with the
0180:             * <code>setVisible</code> flag.
0181:             *
0182:             * @param userConfig URL of the configuration file to load
0183:             * @param setVisible if true, <code>setVisible(true)</code> is called on
0184:             *  all Viewers
0185:             * @param transformCount number of transforms to be included in any
0186:             *  ViewingPlatform created; must be greater than 0
0187:             * @param classLoader the class loader to use to load classes specified
0188:             * in the config file.
0189:             */
0190:            public ConfigContainer(URL userConfig, boolean setVisible,
0191:                    int transformCount, ClassLoader classLoader) {
0192:
0193:                this (userConfig, setVisible, transformCount, true, classLoader);
0194:            }
0195:
0196:            /**
0197:             * Package-scoped constructor for ConfigContainer.  This provides an
0198:             * additional flag, <code>attachBehaviors</code>, which indicates whether
0199:             * or not ViewPlatformBehaviors should be attached to the ViewingPlatforms
0200:             * specified for them.<p>
0201:             *
0202:             * Normally the flag should be true.  However, when instantiated by
0203:             * ConfiguredUniverse, this flag is set false so that ConfiguredUniverse
0204:             * can set a reference to itself in the ViewingPlatform before attaching
0205:             * the behavior.  This provides backwards compatibility to behaviors that
0206:             * access the ConfiguredUniverse instance from a call to
0207:             * <code>setViewingPlatform</code> in order to look up the actual Sensor,
0208:             * Viewer, Behavior, etc., instances associated with the names provided
0209:             * them from the configuration file.<p>
0210:             * 
0211:             * The preferred methods to retrieve instances of specific objects defined
0212:             * in the configuration file are to either 1) get the ConfiguredUniverse
0213:             * instance when the behavior's <code>initialize</code> method is called,
0214:             * or to 2) define properties that accept object instances directly, and
0215:             * then use the newer Device, Sensor, ViewPlatform, etc., built-in
0216:             * commands in the configuration file.  These built-ins will return an
0217:             * object instance from a name.
0218:             *
0219:             * @param userConfig URL of the configuration file to load
0220:             * @param setVisible if true, <code>setVisible(true)</code> is called on
0221:             *  all Viewers
0222:             * @param transformCount number of transforms to be included in any
0223:             *  ViewingPlatform created; must be greater than 0
0224:             * @param attachBehaviors if true, attach ViewPlatformBehaviors to the
0225:             *  appropriate ViewingPlatforms
0226:             */
0227:            ConfigContainer(URL userConfig, boolean setVisible,
0228:                    int transformCount, boolean attachBehaviors) {
0229:
0230:                if (transformCount < 1)
0231:                    throw new IllegalArgumentException(
0232:                            "transformCount must be greater than 0");
0233:
0234:                loadConfig(userConfig);
0235:                processConfig(setVisible, transformCount, attachBehaviors);
0236:            }
0237:
0238:            /**
0239:             * Package scoped constructor that adds the ability to set the ClassLoader
0240:             * which will be used to load any app specific classes specified in the
0241:             * configuration file. By default SystemClassLoader is used.
0242:             */
0243:            ConfigContainer(URL userConfig, boolean setVisible,
0244:                    int transformCount, boolean attachBehaviors,
0245:                    ClassLoader classLoader) {
0246:                this (userConfig, setVisible, transformCount, attachBehaviors);
0247:                this .classLoader = classLoader;
0248:            }
0249:
0250:            /**
0251:             * Open, parse, and load the contents of a configuration file.
0252:             * 
0253:             * @param userConfig location of the configuration file
0254:             */
0255:            private void loadConfig(URL userConfig) {
0256:                InputStream inputStream = null;
0257:                StreamTokenizer streamTokenizer = null;
0258:                String lastFileName = currentFileName;
0259:
0260:                currentFileName = userConfig.toString();
0261:                try {
0262:                    inputStream = userConfig.openStream();
0263:                    Reader r = new BufferedReader(new InputStreamReader(
0264:                            inputStream));
0265:                    streamTokenizer = new StreamTokenizer(r);
0266:                } catch (IOException e) {
0267:                    throw new IllegalArgumentException(e + "\nUnable to open "
0268:                            + currentFileName);
0269:                }
0270:
0271:                //
0272:                // Set up syntax tables for the tokenizer.
0273:                // 
0274:                // It would be nice to allow '/' as a word constituent for URL strings
0275:                // and Unix paths, but then the scanner won't ignore "//" and "/* */"
0276:                // comment style syntax.  Treating '/' as an ordinary character will
0277:                // allow comments to work, but then '/' becomes a single token which
0278:                // has to be concatenated with subsequent tokens to reconstruct the
0279:                // original word string.
0280:                //
0281:                // It is cleaner to just require quoting for forward slashes.  '/'
0282:                // should still be treated as an ordinary character however, so that a
0283:                // non-quoted URL string or Unix path will be treated as a syntax
0284:                // error instead of a comment.
0285:                // 
0286:                streamTokenizer.ordinaryChar('/');
0287:                streamTokenizer.wordChars('_', '_');
0288:                streamTokenizer.wordChars('$', '$'); // for ${...} Java property
0289:                streamTokenizer.wordChars('{', '}'); // substitution in word tokens
0290:                streamTokenizer.slashSlashComments(true);
0291:                streamTokenizer.slashStarComments(true);
0292:
0293:                // Create an s-expression parser to use for all top-level (0) commands.
0294:                ConfigSexpression sexp = new ConfigSexpression();
0295:
0296:                // Loop through all top-level commands.  Boolean.FALSE is returned
0297:                // after the last one is evaluated.
0298:                while (sexp.parseAndEval(this , streamTokenizer, 0) != Boolean.FALSE)
0299:                    ;
0300:
0301:                // Close the input stream.
0302:                try {
0303:                    inputStream.close();
0304:                } catch (IOException e) {
0305:                    throw new IllegalArgumentException(e + "\nUnable to close "
0306:                            + currentFileName);
0307:                }
0308:
0309:                // Restore current file name.
0310:                currentFileName = lastFileName;
0311:            }
0312:
0313:            /**
0314:             * This method gets called from the s-expression parser to process a
0315:             * configuration command.
0316:             *
0317:             * @param elements tokenized list of sexp elements
0318:             * @param lineNumber command line number
0319:             */
0320:            void evaluateCommand(ArrayList elements, int lineNumber) {
0321:                ConfigObject co;
0322:                ConfigCommand cmd;
0323:
0324:                // Create a command object.
0325:                cmd = new ConfigCommand(elements, currentFileName, lineNumber);
0326:
0327:                // Process the command according to its type.
0328:                switch (cmd.type) {
0329:                case ConfigCommand.CREATE:
0330:                    co = createConfigObject(cmd);
0331:                    addConfigObject(co);
0332:                    break;
0333:                case ConfigCommand.ALIAS:
0334:                    co = createConfigAlias(cmd);
0335:                    addConfigObject(co);
0336:                    break;
0337:                case ConfigCommand.PROPERTY:
0338:                    co = findConfigObject(cmd.baseName, cmd.instanceName);
0339:                    co.setProperty(cmd);
0340:                    break;
0341:                case ConfigCommand.INCLUDE:
0342:                    if (!(cmd.argv[1] instanceof  String)) {
0343:                        throw new IllegalArgumentException(
0344:                                "Include file must be a URL string");
0345:                    }
0346:                    URL url = null;
0347:                    String urlString = (String) cmd.argv[1];
0348:                    try {
0349:                        url = new URL(urlString);
0350:                    } catch (MalformedURLException e) {
0351:                        throw new IllegalArgumentException(e.toString());
0352:                    }
0353:                    loadConfig(url);
0354:                    break;
0355:                case ConfigCommand.IGNORE:
0356:                    break;
0357:                default:
0358:                    throw new IllegalArgumentException("Unknown command \""
0359:                            + cmd.commandName + "\"");
0360:                }
0361:            }
0362:
0363:            /**
0364:             * Instantiates and initializes an object that extends the ConfigObject
0365:             * base class.  The class name of the object is derived from the
0366:             * command, which is of the following form:<p>
0367:             *
0368:             * (New{baseName} {instanceName} ... [Alias {aliasName}])<p>
0369:             *
0370:             * The first two command elements and the optional trailing Alias syntax
0371:             * are processed here, at which point the subclass implementation of
0372:             * initialize() is called.  Subclasses must override initialize() if they
0373:             * need to process more than what is processed by default here.
0374:             * 
0375:             * @param cmd configuration command that creates a new ConfigObject
0376:             */
0377:            private ConfigObject createConfigObject(ConfigCommand cmd) {
0378:                Class objectClass = null;
0379:                ConfigObject configObject = null;
0380:
0381:                // Instantatiate the ConfigObject if possible.  This is not the target
0382:                // object, but an object that will gather configuration properties,
0383:                // instantiate the target object, and then apply the configuration
0384:                // properties to it.
0385:                try {
0386:                    objectClass = Class
0387:                            .forName("com.sun.j3d.utils.universe.Config"
0388:                                    + cmd.baseName);
0389:                } catch (ClassNotFoundException e) {
0390:                    throw new IllegalArgumentException("\"" + cmd.baseName
0391:                            + "\""
0392:                            + " is not a configurable object; ignoring command");
0393:                }
0394:                try {
0395:                    configObject = (ConfigObject) (objectClass.newInstance());
0396:                } catch (IllegalAccessException e) {
0397:                    System.out.println(e);
0398:                    throw new IllegalArgumentException("Ignoring command");
0399:                } catch (InstantiationException e) {
0400:                    System.out.println(e);
0401:                    throw new IllegalArgumentException("Ignoring command");
0402:                }
0403:
0404:                // Process an Alias keyword if present.  This option is available for
0405:                // all New commands so it is processed here.  The Alias keyword must
0406:                // be the penultimate command element, followed by a String.
0407:                for (int i = 2; i < cmd.argc; i++) {
0408:                    if (cmd.argv[i] instanceof  String
0409:                            && ((String) cmd.argv[i]).equals("Alias")) {
0410:                        if (i == (cmd.argc - 2)
0411:                                && cmd.argv[i + 1] instanceof  String) {
0412:                            addConfigObject(new ConfigAlias(cmd.baseName,
0413:                                    (String) cmd.argv[i + 1], configObject));
0414:                            cmd.argc -= 2;
0415:                        } else {
0416:                            throw new IllegalArgumentException(
0417:                                    "The alias name must be a string and "
0418:                                            + "must be the last command argument");
0419:                        }
0420:                    }
0421:                }
0422:
0423:                // Initialize common fields.
0424:                configObject.baseName = cmd.baseName;
0425:                configObject.instanceName = cmd.instanceName;
0426:                configObject.creatingCommand = cmd;
0427:                configObject.configContainer = this ;
0428:
0429:                // Initialize specific fields and return the ConfigObject.
0430:                configObject.setClassLoader(classLoader);
0431:                configObject.initialize(cmd);
0432:                return configObject;
0433:            }
0434:
0435:            /**
0436:             * Instantiate and initialize a ConfigObject base class containing alias
0437:             * information.  The command is of the form:<p>
0438:             *
0439:             * ({baseName}Alias {aliasName} {originalName})
0440:             * 
0441:             * @param cmd configuration command that creates a new alias
0442:             * @return the new ConfigObject with alias information
0443:             */
0444:            private ConfigObject createConfigAlias(ConfigCommand cmd) {
0445:                ConfigObject original;
0446:
0447:                if (cmd.argc != 3 || !(cmd.argv[2] instanceof  String))
0448:                    throw new IllegalArgumentException("Command \""
0449:                            + cmd.commandName
0450:                            + "\" requires an instance name as second argument");
0451:
0452:                original = findConfigObject(cmd.baseName, (String) cmd.argv[2]);
0453:                return new ConfigAlias(cmd.baseName, cmd.instanceName, original);
0454:            }
0455:
0456:            /**
0457:             * A class that does nothing but reference another ConfigObject.  Once
0458:             * created, the alias name can be used in all commands that would accept
0459:             * the original name.  A lookup of the alias name will always return the
0460:             * original instance.
0461:             */
0462:            private static class ConfigAlias extends ConfigObject {
0463:                ConfigAlias(String baseName, String instanceName,
0464:                        ConfigObject targ) {
0465:                    this .baseName = baseName;
0466:                    this .instanceName = instanceName;
0467:                    this .isAlias = true;
0468:                    this .original = targ;
0469:                    targ.aliases.add(instanceName);
0470:                }
0471:            }
0472:
0473:            /**
0474:             * Adds the specified ConfigObject instance into this container using the
0475:             * given ConfigCommand's base name and instance name.
0476:             * 
0477:             * @param object the ConfigObject instance to add into the database
0478:             */
0479:            private void addConfigObject(ConfigObject object) {
0480:                ArrayList instances;
0481:
0482:                instances = (ArrayList) baseNameMap.get(object.baseName);
0483:                if (instances == null) {
0484:                    instances = new ArrayList();
0485:                    baseNameMap.put(object.baseName, instances);
0486:                }
0487:
0488:                // Disallow duplicate instance names.
0489:                for (int i = 0; i < instances.size(); i++) {
0490:                    ConfigObject co = (ConfigObject) instances.get(i);
0491:                    if (co.instanceName.equals(object.instanceName)) {
0492:                        // Don't confuse anybody using Window.
0493:                        String base = object.baseName;
0494:                        if (base.equals("Screen"))
0495:                            base = "Screen or Window";
0496:                        throw new IllegalArgumentException("Duplicate " + base
0497:                                + " instance name \"" + object.instanceName
0498:                                + "\" ignored");
0499:                    }
0500:                }
0501:
0502:                instances.add(object);
0503:            }
0504:
0505:            /**
0506:             * Finds a config object matching the given base name and the instance
0507:             * name.  If an alias is found, then its original is returned. If the
0508:             * object is not found, an IllegalArgumentException is thrown.<p>
0509:             *
0510:             * @param basename base name of the config object
0511:             * @param instanceName name associated with this config object instance
0512:             * @return the found ConfigObject
0513:             */
0514:            ConfigObject findConfigObject(String baseName, String instanceName) {
0515:                ArrayList instances;
0516:                ConfigObject configObject;
0517:
0518:                instances = (ArrayList) baseNameMap.get(baseName);
0519:                if (instances != null) {
0520:                    for (int i = 0; i < instances.size(); i++) {
0521:                        configObject = (ConfigObject) instances.get(i);
0522:
0523:                        if (configObject.instanceName.equals(instanceName)) {
0524:                            if (configObject.isAlias)
0525:                                return configObject.original;
0526:                            else
0527:                                return configObject;
0528:                        }
0529:                    }
0530:                }
0531:
0532:                // Throw an error, but don't confuse anybody using Window.
0533:                if (baseName.equals("Screen"))
0534:                    baseName = "Screen or Window";
0535:                throw new IllegalArgumentException(baseName + " \""
0536:                        + instanceName + "\" not found");
0537:            }
0538:
0539:            /**
0540:             * Find instances of config objects with the given base name.
0541:             * This is the same as <code>findConfigObjects(baseName, true)</code>.
0542:             * Aliases are filtered out so that all returned instances are unique.
0543:             *
0544:             * @param baseName base name of desired config object class
0545:             * @return ArrayList of config object instances of the desired base
0546:             *  class, or null if instances of the base class don't exist
0547:             */
0548:            Collection findConfigObjects(String baseName) {
0549:                return findConfigObjects(baseName, true);
0550:            }
0551:
0552:            /**
0553:             * Find instances of config objects with the given base name.
0554:             *
0555:             * @param baseName base name of desired config object class
0556:             * @param filterAlias if true, aliases are filtered out so that all
0557:             *  returned instances are unique
0558:             * @return ArrayList of config object instances of the desired base
0559:             *  class, or null if instances of the base class don't exist
0560:             */
0561:            Collection findConfigObjects(String baseName, boolean filterAlias) {
0562:                ArrayList instances;
0563:
0564:                instances = (ArrayList) baseNameMap.get(baseName);
0565:                if (instances == null || instances.size() == 0) {
0566:                    return null; // This is not an error.
0567:                }
0568:
0569:                if (filterAlias) {
0570:                    ArrayList output = new ArrayList();
0571:                    for (int i = 0; i < instances.size(); i++) {
0572:                        ConfigObject configObject = (ConfigObject) instances
0573:                                .get(i);
0574:
0575:                        if (!configObject.isAlias) {
0576:                            output.add(configObject);
0577:                        }
0578:                    }
0579:                    return output;
0580:                } else {
0581:                    return instances;
0582:                }
0583:            }
0584:
0585:            /**
0586:             * Returns the ConfigObject associated with the name in the given
0587:             * ConfigCommand.  This is used for evaluating retained built-in commands
0588:             * after the config file has already been parsed.  The parser won't catch
0589:             * any of the exceptions generated by this method, so the error messages
0590:             * are wrapped accordingly.
0591:             * 
0592:             * @param basename base name of the config object
0593:             * @param cmd command containing the name in argv[1]
0594:             * @return the found ConfigObject
0595:             */
0596:            private ConfigObject findConfigObject(String baseName,
0597:                    ConfigCommand cmd) {
0598:                if (cmd.argc != 2 || !(cmd.argv[1] instanceof  String))
0599:                    throw new IllegalArgumentException(ConfigObject
0600:                            .errorMessage(cmd,
0601:                                    "Parameter must be a single string"));
0602:                try {
0603:                    return findConfigObject(baseName, (String) cmd.argv[1]);
0604:                } catch (IllegalArgumentException e) {
0605:                    throw new IllegalArgumentException(ConfigObject
0606:                            .errorMessage(cmd, e.getMessage()));
0607:                }
0608:            }
0609:
0610:            /**
0611:             * This method gets called from a ConfigObject to evaluate a retained
0612:             * built-in command nested within a property command.  These are commands
0613:             * that can't be evaluated until the entire config file is parsed.
0614:             * 
0615:             * @param cmd the built-in command
0616:             * @return object representing result of evaluation
0617:             */
0618:            Object evaluateBuiltIn(ConfigCommand cmd) {
0619:                int argc = cmd.argc;
0620:                Object[] argv = cmd.argv;
0621:
0622:                if (cmd.commandName.equals("ConfigContainer")) {
0623:                    // return a reference to this ConfigContainer
0624:                    return this ;
0625:                } else if (cmd.commandName.equals("Canvas3D")) {
0626:                    // Look for canvases in the screen database.
0627:                    return ((ConfigScreen) findConfigObject("Screen", cmd)).j3dCanvas;
0628:                } else if (baseNameMap.get(cmd.commandName) != null) {
0629:                    // Handle commands of the form ({objectType} name) that return the
0630:                    // object associated with the name.
0631:                    return findConfigObject(cmd.commandName, cmd).targetObject;
0632:                } else {
0633:                    // So far no other retained built-in commands.
0634:                    throw new IllegalArgumentException(ConfigObject
0635:                            .errorMessage(cmd, "Unknown built-in command \""
0636:                                    + cmd.commandName + "\""));
0637:                }
0638:            }
0639:
0640:            /**
0641:             * Process the configuration after parsing the configuration file.
0642:             * Note: the processing order of the various config objects is
0643:             * significant.
0644:             *
0645:             * @param setVisible true if Viewer components should be visible
0646:             * @param transformCount number of TransformGroups with which
0647:             *  ViewingPlatforms should be created
0648:             * @param attachBehaviors true if behaviors should be attached to
0649:             *  ViewingPlatforms
0650:             */
0651:            private void processConfig(boolean setVisible, int transformCount,
0652:                    boolean attachBehaviors) {
0653:
0654:                Collection c, s, pe, vp;
0655:                this .setVisible = setVisible;
0656:                this .transformCount = transformCount;
0657:
0658:                c = findConfigObjects("PhysicalBody");
0659:                if (c != null) {
0660:                    processPhysicalBodies(c);
0661:                }
0662:
0663:                pe = findConfigObjects("PhysicalEnvironment");
0664:                if (pe != null) {
0665:                    processPhysicalEnvironments(pe);
0666:                }
0667:
0668:                c = findConfigObjects("View");
0669:                if (c != null) {
0670:                    processViews(c, setVisible);
0671:                }
0672:
0673:                c = findConfigObjects("Device");
0674:                s = findConfigObjects("Sensor");
0675:                if (c != null) {
0676:                    processDevices(c, s, pe);
0677:                }
0678:
0679:                vp = findConfigObjects("ViewPlatform");
0680:                if (vp != null) {
0681:                    processViewPlatforms(vp, transformCount);
0682:                }
0683:
0684:                c = findConfigObjects("ViewPlatformBehavior");
0685:                if (c != null) {
0686:                    processViewPlatformBehaviors(c, vp, attachBehaviors);
0687:                }
0688:
0689:                c = findConfigObjects("Object");
0690:                if (c != null) {
0691:                    processGenericObjects(c);
0692:                }
0693:            }
0694:
0695:            // Process config physical environments into Java 3D physical
0696:            // environments.  
0697:            private void processPhysicalEnvironments(Collection c) {
0698:                Iterator i = c.iterator();
0699:                while (i.hasNext()) {
0700:                    ConfigPhysicalEnvironment e = (ConfigPhysicalEnvironment) i
0701:                            .next();
0702:                    e.targetObject = e.createJ3dPhysicalEnvironment();
0703:                }
0704:            }
0705:
0706:            // Process config physical bodys into Java 3D physical bodies.
0707:            private void processPhysicalBodies(Collection c) {
0708:                Iterator i = c.iterator();
0709:                while (i.hasNext()) {
0710:                    ConfigPhysicalBody b = (ConfigPhysicalBody) i.next();
0711:                    b.targetObject = b.createJ3dPhysicalBody();
0712:                }
0713:            }
0714:
0715:            // Process config views into Java 3D Views and then create Viewer objects
0716:            // for them.  This should only be called after all physical bodies and
0717:            // physical environments have been processed.
0718:            private void processViews(Collection c, boolean setVisible) {
0719:                Iterator i = c.iterator();
0720:                while (i.hasNext()) {
0721:                    ConfigView v = (ConfigView) i.next();
0722:                    v.targetObject = v.createViewer(setVisible);
0723:                }
0724:            }
0725:
0726:            // Process config devices into Java 3D input devices.  This should be done
0727:            // only after all views have been processed, as some InputDevice
0728:            // implementations require the AWT components associated with a view.
0729:            private void processDevices(Collection c, Collection s, Collection p) {
0730:                ConfigDevice cd = null;
0731:                Iterator i = c.iterator();
0732:                while (i.hasNext()) {
0733:                    cd = (ConfigDevice) i.next();
0734:                    cd.targetObject = cd.createInputDevice();
0735:                }
0736:
0737:                // Process device properties only after all InputDevices have been
0738:                // instantiated.  Some InputDevice properties require references
0739:                // to other InputDevice implementations.
0740:                i = c.iterator();
0741:                while (i.hasNext())
0742:                    ((ConfigDevice) i.next()).processProperties();
0743:
0744:                // Initialize the devices only after all have been instantiated, as
0745:                // some InputDevices implementations are slaved to the first one
0746:                // created and will not initialize otherwise (e.g. LogitechTracker).
0747:                i = c.iterator();
0748:                while (i.hasNext()) {
0749:                    cd = (ConfigDevice) i.next();
0750:                    if (!cd.j3dInputDevice.initialize())
0751:                        throw new RuntimeException(cd.errorMessage(
0752:                                cd.creatingCommand,
0753:                                "could not initialize device \""
0754:                                        + cd.instanceName + "\""));
0755:                }
0756:
0757:                // An InputDevice implementation will have created all its Sensors by
0758:                // the time initialize() returns.  Retrieve and configure them here.
0759:                if (s != null) {
0760:                    i = s.iterator();
0761:                    while (i.hasNext()) {
0762:                        ConfigSensor cs = (ConfigSensor) i.next();
0763:                        cs.configureSensor();
0764:                        cs.targetObject = cs.j3dSensor;
0765:                    }
0766:                }
0767:
0768:                // Iterate through the PhysicalEnvironments and process the devices.
0769:                if (p != null) {
0770:                    i = p.iterator();
0771:                    while (i.hasNext())
0772:                        ((ConfigPhysicalEnvironment) i.next()).processDevices();
0773:                }
0774:            }
0775:
0776:            // Process config view platforms into Java 3D viewing platforms.
0777:            private void processViewPlatforms(Collection c, int numTransforms) {
0778:                Iterator i = c.iterator();
0779:                while (i.hasNext()) {
0780:                    ConfigViewPlatform cvp = (ConfigViewPlatform) i.next();
0781:                    cvp.targetObject = cvp.createViewingPlatform(numTransforms);
0782:                }
0783:            }
0784:
0785:            // Process the configured view platform behaviors.
0786:            private void processViewPlatformBehaviors(Collection behaviors,
0787:                    Collection viewPlatforms, boolean attach) {
0788:                Iterator i = behaviors.iterator();
0789:                while (i.hasNext()) {
0790:                    ConfigViewPlatformBehavior b = (ConfigViewPlatformBehavior) i
0791:                            .next();
0792:                    b.targetObject = b.createViewPlatformBehavior();
0793:                }
0794:
0795:                // Process properties only after all behaviors are instantiated.
0796:                i = behaviors.iterator();
0797:                while (i.hasNext())
0798:                    ((ConfigViewPlatformBehavior) i.next()).processProperties();
0799:
0800:                // Attach behaviors to platforms after properties processed.
0801:                if (attach && viewPlatforms != null) {
0802:                    i = viewPlatforms.iterator();
0803:                    while (i.hasNext())
0804:                        ((ConfigViewPlatform) i.next()).processBehavior();
0805:                }
0806:            }
0807:
0808:            // Process generic objects. 
0809:            private void processGenericObjects(Collection objects) {
0810:                Iterator i = objects.iterator();
0811:                while (i.hasNext()) {
0812:                    ConfigObject o = (ConfigObject) i.next();
0813:                    o.targetObject = o.createTargetObject();
0814:                }
0815:
0816:                // Process properties only after all target objects are instantiated.
0817:                i = objects.iterator();
0818:                while (i.hasNext())
0819:                    ((ConfigObject) i.next()).processProperties();
0820:            }
0821:
0822:            // Returns a read-only Set containing all unique Java 3D objects of the
0823:            // specified base class.
0824:            private ReadOnlySet createSet(String baseName) {
0825:                Collection c = findConfigObjects(baseName, true);
0826:                if (c == null || c.size() == 0)
0827:                    return null;
0828:
0829:                Iterator i = c.iterator();
0830:                ArrayList l = new ArrayList();
0831:                while (i.hasNext())
0832:                    l.add(((ConfigObject) i.next()).targetObject);
0833:
0834:                return new ReadOnlySet(l);
0835:            }
0836:
0837:            // Returns a read-only Map that maps all names in the specified base
0838:            // class, including aliases, to their corresponding Java 3D objects.
0839:            private ReadOnlyMap createMap(String baseName) {
0840:                Collection c = findConfigObjects(baseName, false);
0841:                if (c == null || c.size() == 0)
0842:                    return null;
0843:
0844:                Iterator i = c.iterator();
0845:                HashMap m = new HashMap();
0846:                while (i.hasNext()) {
0847:                    ConfigObject co = (ConfigObject) i.next();
0848:                    if (co.isAlias)
0849:                        m.put(co.instanceName, co.original.targetObject);
0850:                    else
0851:                        m.put(co.instanceName, co.targetObject);
0852:                }
0853:
0854:                return new ReadOnlyMap(m);
0855:            }
0856:
0857:            /**
0858:             * Returns a read-only Set of all configured PhysicalBody instances in the
0859:             * order they were defined in the configuration file.
0860:             *
0861:             * PhysicalBody instances are created with the following command:<p>
0862:             * <blockquote>
0863:             * (NewPhysicalBody <i>&lt;instance name&gt;</i>
0864:             * [Alias <i>&lt;alias name&gt;</i>])
0865:             * </blockquote>
0866:             * 
0867:             * The PhysicalBody is configured through the following command:<p>
0868:             * <blockquote>
0869:             * (PhysicalBodyProperty <i>&lt;instance name&gt;
0870:             * &lt;property name&gt; &lt;property value&gt;</i>)
0871:             * </blockquote>
0872:             * 
0873:             * @return read-only Set of all unique instances, or null
0874:             */
0875:            public Set getPhysicalBodies() {
0876:                if (bodies != null)
0877:                    return bodies;
0878:                bodies = createSet("PhysicalBody");
0879:                return bodies;
0880:            }
0881:
0882:            /**
0883:             * Returns a read-only Map that maps PhysicalBody names to instances.
0884:             * Names may be aliases and if so will map to the original instances.
0885:             * 
0886:             * @return read-only Map from names to PhysicalBody instances, or null if
0887:             *  no instances
0888:             */
0889:            public Map getNamedPhysicalBodies() {
0890:                if (bodyMap != null)
0891:                    return bodyMap;
0892:                bodyMap = createMap("PhysicalBody");
0893:                return bodyMap;
0894:            }
0895:
0896:            /**
0897:             * Returns a read-only Set of all configured PhysicalEnvironment instances
0898:             * in the order they were defined in the configuration file.<p>
0899:             * 
0900:             * PhysicalEnvironment instances are created with the following command:<p>
0901:             * <blockquote>
0902:             * (NewPhysicalEnvironment <i>&lt;instance name&gt;</i>
0903:             * [Alias <i>&lt;alias name&gt;</i>])
0904:             * </blockquote>
0905:             * 
0906:             * The PhysicalEnvironment is configured through the following command:<p>
0907:             * <blockquote>
0908:             * (PhysicalEnvironmentProperty <i>&lt;instance name&gt;
0909:             * &lt;property name&gt; &lt;property value&gt;</i>)
0910:             * </blockquote>
0911:             * 
0912:             * @return read-only Set of all unique instances, or null
0913:             */
0914:            public Set getPhysicalEnvironments() {
0915:                if (environments != null)
0916:                    return environments;
0917:                environments = createSet("PhysicalEnvironment");
0918:                return environments;
0919:            }
0920:
0921:            /**
0922:             * Returns a read-only Map that maps PhysicalEnvironment names to
0923:             * instances.  Names may be aliases and if so will map to the original
0924:             * instances.
0925:             * 
0926:             * @return read-only Map from names to PhysicalEnvironment instances, or
0927:             *  null if no instances
0928:             */
0929:            public Map getNamedPhysicalEnvironments() {
0930:                if (environmentMap != null)
0931:                    return environmentMap;
0932:                environmentMap = createMap("PhysicalEnvironment");
0933:                return environmentMap;
0934:            }
0935:
0936:            /**
0937:             * Returns a read-only Set of all configured Viewer instances in the order
0938:             * they were defined in the configuration file.  The Viewers will have
0939:             * incorporated any PhysicalEnvironment and PhysicalBody objects specfied
0940:             * for them in the configuration file, and will be attached to any
0941:             * ViewingPlatforms specified for them.<p>
0942:             * 
0943:             * Viewer instances are created with the following command:<p>
0944:             * <blockquote>
0945:             * (NewView <i>&lt;instance name&gt;</i> [Alias <i>&lt;alias name&gt;</i>])
0946:             * </blockquote>
0947:             * 
0948:             * The Viewer is configured through the following command:<p>
0949:             * <blockquote>
0950:             * (ViewProperty <i>&lt;instance name&gt;
0951:             * &lt;property name&gt; &lt;property value&gt;</i>)
0952:             * </blockquote>
0953:             *
0954:             * @return read-only Set of all unique instances, or null
0955:             */
0956:            public Set getViewers() {
0957:                if (viewers != null)
0958:                    return viewers;
0959:                viewers = createSet("View");
0960:                return viewers;
0961:            }
0962:
0963:            /**
0964:             * Returns a read-only Map that maps Viewer names to instances.
0965:             * Names may be aliases and if so will map to the original instances.
0966:             * The Viewers will have incorporated any PhysicalEnvironment and
0967:             * PhysicalBody objects specfied for them in the configuration file, and
0968:             * will be attached to any ViewingPlatforms specified for them.<p>
0969:             * 
0970:             * @return read-only Map from names to Viewer instances, or
0971:             *  null if no instances
0972:             */
0973:            public Map getNamedViewers() {
0974:                if (viewerMap != null)
0975:                    return viewerMap;
0976:                viewerMap = createMap("View");
0977:                return viewerMap;
0978:            }
0979:
0980:            /**
0981:             * Returns a read-only Set of all configured InputDevice instances in the
0982:             * order they were defined in the configuration file.  All InputDevice
0983:             * instances in the set are initialized and registered with any
0984:             * PhysicalEnvironments that reference them.<p>
0985:             *
0986:             * InputDevice instances are created with the following command:<p>
0987:             * <blockquote>
0988:             * (NewDevice <i>&lt;instanceName&gt; &lt;className&gt;</i>
0989:             * [Alias <i>&lt;alias name&gt;</i>])
0990:             * </blockquote>
0991:             * 
0992:             * <i>className</i> must be the fully-qualified name of a class that
0993:             * implements the InputDevice interface.  The implementation
0994:             * must provide a parameterless constructor.<p>
0995:             *
0996:             * The InputDevice is configured through the DeviceProperty command:<p>
0997:             * <blockquote>
0998:             * (DeviceProperty <i>&lt;instanceName&gt; &lt;propertyName&gt;
0999:             *  &lt;arg0&gt; ... &lt;argn&gt;</i>)
1000:             * </blockquote>
1001:             * 
1002:             * <i>propertyName</i> must be the name of a input device method that
1003:             * takes an array of Objects as its only parameter; the array is populated
1004:             * with the values of <i>arg0</i> through <i>argn</i> when the method is
1005:             * invoked to set the property.  These additional requirements for
1006:             * configurable input devices can usually be fulfilled by extending or
1007:             * wrapping available InputDevice implementations.
1008:             * 
1009:             * @return read-only Set of all unique instances, or null
1010:             */
1011:            public Set getInputDevices() {
1012:                if (devices != null)
1013:                    return devices;
1014:                devices = createSet("Device");
1015:                return devices;
1016:            }
1017:
1018:            /**
1019:             * Returns a read-only Map that maps InputDevice names to instances.
1020:             * Names may be aliases and if so will map to the original instances.  All
1021:             * InputDevice instances in the map are initialized and registered with
1022:             * any PhysicalEnvironments that reference them.
1023:             * 
1024:             * @return read-only Map from names to InputDevice instances, or
1025:             *  null if no instances
1026:             * @see #getInputDevices
1027:             */
1028:            public Map getNamedInputDevices() {
1029:                if (deviceMap != null)
1030:                    return deviceMap;
1031:                deviceMap = createMap("Device");
1032:                return deviceMap;
1033:            }
1034:
1035:            /**
1036:             * Returns a read-only Set of all configured Sensor instances in the order
1037:             * they were defined in the configuration file.  The associated
1038:             * InputDevices are all initialized and registered with any
1039:             * PhysicalEnvironments that reference them.<p>
1040:             * 
1041:             * Sensor instances are named with the following command:<p>
1042:             * <blockquote>
1043:             * (NewSensor <i>&lt;instance name&gt; &lt;device name&gt; 
1044:             * &lt;sensor index&gt;</i> [Alias <i>&lt;alias name&gt;</i>])
1045:             * </blockquote>
1046:             * 
1047:             * <i>device name</i> is the instance name of a previously defined
1048:             * InputDevice, and <i>sensor index</i> is the index of the Sensor to be
1049:             * bound to <i>instance name</i>.  The InputDevice implementation is
1050:             * responsible for creating its own Sensor objects, so this command does
1051:             * not create any new instances.<p>
1052:             *
1053:             * The Sensor is configured through the SensorProperty command:<p>
1054:             * <blockquote>
1055:             * (SensorProperty <i>&lt;instance name&gt; &lt;property name&gt; 
1056:             * &lt;property value&gt;</i>)
1057:             * </blockquote>
1058:             * 
1059:             * With the sole exception of the Sensor assigned to the head tracker,
1060:             * none of the Sensors defined in the configuration file are placed into
1061:             * the Sensor array maintained by a PhysicalEnvironment.  
1062:             *
1063:             * @return read-only Set of all unique instances, or null
1064:             */
1065:            public Set getSensors() {
1066:                if (sensors != null)
1067:                    return sensors;
1068:                sensors = createSet("Sensor");
1069:                return sensors;
1070:            }
1071:
1072:            /**
1073:             * Returns a read-only Map that maps Sensor names to instances.  Names may
1074:             * be aliases and if so will map to the original instances.  The
1075:             * associated InputDevices are all initialized and registered with any
1076:             * PhysicalEnvironments that reference them.<p>
1077:             * 
1078:             * With the sole exception of the Sensor assigned to the head tracker,
1079:             * none of the Sensors defined in the configuration file are placed into
1080:             * the Sensor array maintained by a PhysicalEnvironment.  
1081:             * 
1082:             * @return read-only Map from names to Sensor instances, or
1083:             *  null if no instances
1084:             */
1085:            public Map getNamedSensors() {
1086:                if (sensorMap != null)
1087:                    return sensorMap;
1088:                sensorMap = createMap("Sensor");
1089:                return sensorMap;
1090:            }
1091:
1092:            /**
1093:             * Returns a read-only Set of all configured ViewingPlatform instances in
1094:             * the order they were defined in the configuration file.  The
1095:             * ConfigContainer class itself does not attach the ViewingPlatform
1096:             * instances to any scengraph components or universe Locales; they are not
1097:             * "live" until made so by a separate client such as ConfiguredUniverse.
1098:             *
1099:             * ViewingPlatform instances are created with the following command:<p>
1100:             * <blockquote>
1101:             * (NewViewPlatform <i>&lt;instance name&gt;</i>
1102:             * [Alias <i>&lt;alias name&gt;</i>])
1103:             * </blockquote>
1104:             * 
1105:             * The ViewingPlatform is configured through the following command:<p>
1106:             * <blockquote>
1107:             * (ViewPlatformProperty <i>&lt;instance name&gt; &lt;property name&gt;
1108:             * &lt;property value&gt;</i>)
1109:             * </blockquote>
1110:             *
1111:             * @return read-only Set of all unique instances, or null
1112:             */
1113:            public Set getViewingPlatforms() {
1114:                if (platforms != null)
1115:                    return platforms;
1116:                platforms = createSet("ViewPlatform");
1117:                return platforms;
1118:            }
1119:
1120:            /**
1121:             * Returns a read-only Map that maps ViewingPlatform names to instances.
1122:             * Names may be aliases and if so will map to the original instances.  The
1123:             * ConfigContainer class itself does not attach the ViewingPlatform
1124:             * instances to any scengraph components or universe Locales; they are not
1125:             * "live" until made so by a separate client such as ConfiguredUniverse.
1126:             * 
1127:             * @return read-only Map from names to ViewingPlatform instances, or
1128:             *  null if no instances
1129:             */
1130:            public Map getNamedViewingPlatforms() {
1131:                if (platformMap != null)
1132:                    return platformMap;
1133:                platformMap = createMap("ViewPlatform");
1134:                return platformMap;
1135:            }
1136:
1137:            /**
1138:             * Returns a read-only Set of all configured ViewPlatformBehavior
1139:             * instances in the order they were defined in the configuration file.<p>
1140:             * 
1141:             * The behaviors are attached to any ViewingPlatforms that specified them;
1142:             * that is, the <code>setViewPlatformBehavior</code> and
1143:             * <code>setViewingPlatform</code> methods of ViewingPlatform and
1144:             * ViewPlatformBehavior have been called if appropriate.  However, a
1145:             * behavior's <code>initialize</code> method is not called until the
1146:             * ViewingPlatform to which it is attached is made live.<p>
1147:             *
1148:             * ViewPlatformBehavior instances are created by the following command:<p>
1149:             * <blockquote>
1150:             * (NewViewPlatformBehavior <i>&lt;instanceName&gt; &lt;className&gt;</i>)
1151:             * </blockquote>
1152:             * 
1153:             * <i>className</i> must be the fully qualified name of a concrete class
1154:             * that extends the abstract ViewPlatformBehavior class.  The
1155:             * implementation must provide a parameterless constructor.<p>
1156:             *
1157:             * The behavior is configured using ViewPlatformBehaviorProperty:<p>
1158:             * <blockquote>
1159:             * (ViewPlatformBehaviorProperty <i>&lt;instanceName&gt;
1160:             *  &lt;propertyName&gt; &lt;arg0&gt; ... &lt;argn&gt;</i>)
1161:             * </blockquote>
1162:             * 
1163:             * ViewPlatformBehavior subclasses inherit a number of pre-defined
1164:             * properties that can be directly specified with the <i>propertyName</i>
1165:             * string; see the configuration file documentation for details.<p>
1166:             *
1167:             * Concrete ViewPlatformBehavior instances can also define their own
1168:             * unique properties.  In those cases, <i>propertyName</i> must be the
1169:             * name of a behavior method that takes an array of Objects as its only
1170:             * parameter; the array is populated with the values of <i>arg0</i>
1171:             * through <i>argn</i> when the method is invoked to set the property.
1172:             * These additional requirements for configurable behaviors can usually be
1173:             * fulfilled by extending or wrapping available ViewPlatformBehavior
1174:             * subclasses.
1175:             *
1176:             * @return read-only Set of all unique instances, or null
1177:             */
1178:            public Set getViewPlatformBehaviors() {
1179:                if (behaviors != null)
1180:                    return behaviors;
1181:                behaviors = createSet("ViewPlatformBehavior");
1182:                return behaviors;
1183:            }
1184:
1185:            /**
1186:             * Returns a read-only Map that maps ViewPlatformBehavior names to
1187:             * instances.  Names may be aliases and if so will map to the original
1188:             * instances.<p>
1189:             * 
1190:             * The behaviors are attached to any ViewingPlatforms that specified them;
1191:             * that is, the <code>setViewPlatformBehavior</code> and
1192:             * <code>setViewingPlatform</code> methods of ViewingPlatform and
1193:             * ViewPlatformBehavior have been called if appropriate.  However, a
1194:             * behavior's <code>initialize</code> method is not called until the
1195:             * ViewingPlatform to which it is attached is made live.<p>
1196:             * 
1197:             * @return read-only Map from names to ViewPlatformBehavior instances, or
1198:             *  null if no instances
1199:             * @see #getViewPlatformBehaviors
1200:             */
1201:            public Map getNamedViewPlatformBehaviors() {
1202:                if (behaviorMap != null)
1203:                    return behaviorMap;
1204:                behaviorMap = createMap("ViewPlatformBehavior");
1205:                return behaviorMap;
1206:            }
1207:
1208:            /**
1209:             * Returns a read-only Map containing the named Canvas3D instances used by
1210:             * the specified Viewer.  Names may be aliases and if so will map to the
1211:             * original instances.  The set of unique Canvas3D instances used by a
1212:             * Viewer may be obtained by calling the Viewer's accessor methods
1213:             * directly.<p>
1214:             * 
1215:             * A named Canvas3D is created and added to a Viewer whenever any of the
1216:             * following configuration commands are used:<p>
1217:             * <blockquote>
1218:             * (ViewProperty <i>&lt;view&gt;</i> Screen <i>&lt;screenName&gt;</i>)<br>
1219:             * (ViewProperty <i>&lt;view&gt;</i> Window <i>&lt;windowName&gt;</i>)
1220:             * </blockquote>
1221:             * 
1222:             * <i>view</i> is the name of a Viewer created with the NewView command.
1223:             * The <i>screenName</i> and <i>windowName</i> parameters of the above
1224:             * commands are the keys to use when looking up the associated Canvas3D
1225:             * instances in the Map returned by this method.  <b>Note:</b> the
1226:             * NewScreen and NewWindow commands do <i>not</i> create Canvas3D
1227:             * instances themselves; they are created only by the above configuration
1228:             * commands.
1229:             *
1230:             * @param viewName the name of the Viewer
1231:             * @return read-only Map containing the Viewer's named Canvas3D instances
1232:             */
1233:            public Map getNamedCanvases(String viewName) {
1234:                Map m = (Map) viewCanvasMap.get(viewName);
1235:                if (m != null)
1236:                    return m;
1237:
1238:                m = new HashMap();
1239:                ConfigView cv = (ConfigView) findConfigObject("View", viewName);
1240:                Iterator i = cv.screens.iterator();
1241:                while (i.hasNext()) {
1242:                    ConfigScreen cs = (ConfigScreen) i.next();
1243:                    m.put(cs.instanceName, cs.j3dCanvas);
1244:
1245:                    // The aliases list contains all alias strings for the canvas. 
1246:                    Iterator j = cs.aliases.iterator();
1247:                    while (j.hasNext())
1248:                        m.put(j.next(), cs.j3dCanvas);
1249:                }
1250:                m = new ReadOnlyMap(m);
1251:                viewCanvasMap.put(viewName, m);
1252:                return m;
1253:            }
1254:
1255:            /**
1256:             * Returns a read-only Set of all generic configuration object
1257:             * instances in the order they were defined in the configuration file.<p>
1258:             *
1259:             * Generic object instances are created with the following command:<p>
1260:             * <blockquote>
1261:             * (NewObject <i>&lt;instanceName&gt; &lt;className&gt;</i>)
1262:             * </blockquote>
1263:             * 
1264:             * <i>className</i> must be the fully-qualified name of a class that
1265:             * provides a parameterless constructor.<p>
1266:             *
1267:             * The object is configured through the ObjectProperty command:<p>
1268:             * <blockquote>
1269:             * (ObjectProperty <i>&lt;instanceName&gt; &lt;propertyName&gt;
1270:             *  &lt;arg0&gt; ... &lt;argn&gt;</i>)
1271:             * </blockquote>
1272:             * 
1273:             * <i>propertyName</i> must be the name of a method provided by object
1274:             * <i>instanceName</i>.  It must take an array of Objects as its only
1275:             * parameter; the array is populated with the values of <i>arg0</i>
1276:             * through <i>argn</i> when the method is invoked to set the property.
1277:             * These additional requirements for configurable objects can usually be
1278:             * fulfilled by extending or wrapping available object classes.
1279:             *
1280:             * @return read-only Set of all unique instances, or null
1281:             */
1282:            public Set getGenericObjects() {
1283:                if (genericObjects != null)
1284:                    return genericObjects;
1285:                genericObjects = createSet("Object");
1286:                return genericObjects;
1287:            }
1288:
1289:            /**
1290:             * Returns a read-only Map that maps generic object names to
1291:             * instances.  Names may be aliases and if so will map to the original
1292:             * instances.
1293:             * 
1294:             * @return read-only Map from names to generic object instances, or
1295:             *  null if no instances
1296:             * @see #getGenericObjects
1297:             */
1298:            public Map getNamedGenericObjects() {
1299:                if (genericObjectMap != null)
1300:                    return genericObjectMap;
1301:                genericObjectMap = createMap("Object");
1302:                return genericObjectMap;
1303:            }
1304:
1305:            /**
1306:             * Returns the number of TransformGroups with which ViewingPlatforms
1307:             * should be created.  This is useful for clients that wish to provide a
1308:             * default ViewingPlatform if the configuration file doesn't specify one.
1309:             *
1310:             * @return the number of TransformGroups
1311:             */
1312:            public int getViewPlatformTransformCount() {
1313:                return transformCount;
1314:            }
1315:
1316:            /**
1317:             * Returns whether Viewers should be created with their AWT components
1318:             * initially visible or invisible.  This is useful for clients that wish
1319:             * to provide a default Viewer if the configuration file doesn't specify
1320:             * one. 
1321:             *
1322:             * @return true if Viewer components should be initially visible; false
1323:             *  otherwise 
1324:             */
1325:            public boolean getViewerVisibility() {
1326:                return setVisible;
1327:            }
1328:
1329:            /**
1330:             * Release memory references used by this ConfigContainer.  All Sets and
1331:             * Maps obtained from this ConfigContainer are cleared.
1332:             */
1333:            public void clear() {
1334:                // Clear baseNameList.
1335:                Iterator i = baseNameMap.values().iterator();
1336:                while (i.hasNext())
1337:                    ((Collection) i.next()).clear();
1338:                baseNameMap.clear();
1339:
1340:                // Clear viewCanvasMap.
1341:                i = viewCanvasMap.values().iterator();
1342:                while (i.hasNext())
1343:                    ((ReadOnlyMap) i.next()).map.clear();
1344:                viewCanvasMap.clear();
1345:
1346:                // Release reference to file name.
1347:                currentFileName = null;
1348:
1349:                // Clear and release sets.
1350:                if (bodies != null) {
1351:                    bodies.collection.clear();
1352:                    bodies = null;
1353:                }
1354:                if (environments != null) {
1355:                    environments.collection.clear();
1356:                    environments = null;
1357:                }
1358:                if (devices != null) {
1359:                    devices.collection.clear();
1360:                    devices = null;
1361:                }
1362:                if (sensors != null) {
1363:                    sensors.collection.clear();
1364:                    sensors = null;
1365:                }
1366:                if (behaviors != null) {
1367:                    behaviors.collection.clear();
1368:                    behaviors = null;
1369:                }
1370:                if (platforms != null) {
1371:                    platforms.collection.clear();
1372:                    platforms = null;
1373:                }
1374:                if (viewers != null) {
1375:                    viewers.collection.clear();
1376:                    viewers = null;
1377:                }
1378:                if (genericObjects != null) {
1379:                    genericObjects.collection.clear();
1380:                    genericObjects = null;
1381:                }
1382:
1383:                // Clear and release maps.
1384:                if (bodyMap != null) {
1385:                    bodyMap.map.clear();
1386:                    bodyMap = null;
1387:                }
1388:                if (environmentMap != null) {
1389:                    environmentMap.map.clear();
1390:                    environmentMap = null;
1391:                }
1392:                if (deviceMap != null) {
1393:                    deviceMap.map.clear();
1394:                    deviceMap = null;
1395:                }
1396:                if (sensorMap != null) {
1397:                    sensorMap.map.clear();
1398:                    sensorMap = null;
1399:                }
1400:                if (behaviorMap != null) {
1401:                    behaviorMap.map.clear();
1402:                    behaviorMap = null;
1403:                }
1404:                if (platformMap != null) {
1405:                    platformMap.map.clear();
1406:                    platformMap = null;
1407:                }
1408:                if (viewerMap != null) {
1409:                    viewerMap.map.clear();
1410:                    viewerMap = null;
1411:                }
1412:                if (genericObjectMap != null) {
1413:                    genericObjectMap.map.clear();
1414:                    genericObjectMap = null;
1415:                }
1416:
1417:            }
1418:
1419:            /**
1420:             * Returns the config file URL based on system properties.  The current
1421:             * implementation of this method parses the j3d.configURL property as a
1422:             * URL string.  For example, the following command line would specify that
1423:             * the config file is taken from the file "j3dconfig" in the current
1424:             * directory:
1425:             * <ul>
1426:             * <code>java -Dj3d.configURL=file:j3dconfig ...</code>
1427:             * </ul>
1428:             *
1429:             * @return the URL of the config file; null is returned if no valid
1430:             *  URL is defined by the system properties
1431:             */
1432:            public static URL getConfigURL() {
1433:                return getConfigURL(null);
1434:            }
1435:
1436:            /**
1437:             * Returns the config file URL based on system properties.  The current
1438:             * implementation of this method parses the j3d.configURL property as a
1439:             * URL string.  For example, the following command line would specify that
1440:             * the config file is taken from the file "j3dconfig" in the current
1441:             * directory:
1442:             * <ul>
1443:             * <code>java -Dj3d.configURL=file:j3dconfig ...</code>
1444:             * </ul>
1445:             *
1446:             * @param defaultURLString the default string used to construct
1447:             *  the URL if the appropriate system properties are not defined
1448:             * @return the URL of the config file; null is returned if no
1449:             *  valid URL is defined either by the system properties or the
1450:             *  default URL string
1451:             */
1452:            public static URL getConfigURL(String defaultURLString) {
1453:                URL url = null;
1454:                String urlString = null;
1455:                final String defProp = defaultURLString;
1456:
1457:                urlString = (String) java.security.AccessController
1458:                        .doPrivileged(new java.security.PrivilegedAction() {
1459:                            public Object run() {
1460:                                return System.getProperty("j3d.configURL",
1461:                                        defProp);
1462:                            }
1463:                        });
1464:
1465:                if (urlString == null) {
1466:                    return null;
1467:                }
1468:                try {
1469:                    url = new URL(urlString);
1470:                } catch (MalformedURLException e) {
1471:                    System.out.println(e);
1472:                    return null;
1473:                }
1474:                return url;
1475:            }
1476:
1477:            // A general purpose read-only Map backed by a HashMap.
1478:            private static class ReadOnlyMap extends AbstractMap {
1479:                HashMap map;
1480:                private Set entrySet = null;
1481:
1482:                ReadOnlyMap(Map map) {
1483:                    this .map = new HashMap(map);
1484:                }
1485:
1486:                // overridden for efficiency
1487:                public Object get(Object key) {
1488:                    return map.get(key);
1489:                }
1490:
1491:                // overridden for efficiency
1492:                public boolean containsKey(Object key) {
1493:                    return map.containsKey(key);
1494:                }
1495:
1496:                // overridden for efficiency
1497:                public boolean containsValue(Object value) {
1498:                    return map.containsValue(value);
1499:                }
1500:
1501:                public Set entrySet() {
1502:                    if (entrySet == null)
1503:                        entrySet = new ReadOnlySet(map.entrySet());
1504:
1505:                    return entrySet;
1506:                }
1507:            }
1508:
1509:            // A general purpose read-only Set backed by a Collection containing
1510:            // unique objects.
1511:            private static class ReadOnlySet extends AbstractSet {
1512:                Collection collection = null;
1513:
1514:                ReadOnlySet(Collection c) {
1515:                    this .collection = c;
1516:                }
1517:
1518:                public int size() {
1519:                    return collection.size();
1520:                }
1521:
1522:                public Iterator iterator() {
1523:                    return new ReadOnlyIterator(collection.iterator());
1524:                }
1525:            }
1526:
1527:            // A general purpose read-only Iterator backed by another Iterator.
1528:            private static class ReadOnlyIterator implements  Iterator {
1529:                private Iterator i;
1530:
1531:                ReadOnlyIterator(Iterator i) {
1532:                    this .i = i;
1533:                }
1534:
1535:                public boolean hasNext() {
1536:                    return i.hasNext();
1537:                }
1538:
1539:                public Object next() {
1540:                    return i.next();
1541:                }
1542:
1543:                public void remove() {
1544:                    throw new UnsupportedOperationException();
1545:                }
1546:            }
1547:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.