All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.scijava.java3d.utils.universe.ConfigContainer Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistribution of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 *
 * - Redistribution in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in
 *   the documentation and/or other materials provided with the
 *   distribution.
 *
 * Neither the name of Sun Microsystems, Inc. or the names of
 * contributors may be used to endorse or promote products derived
 * from this software without specific prior written permission.
 *
 * This software is provided "AS IS," without a warranty of any
 * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
 * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
 * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
 * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
 * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
 * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
 * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
 * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
 * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
 * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGES.
 *
 * You acknowledge that this software is not designed, licensed or
 * intended for use in the design, construction, operation or
 * maintenance of any nuclear facility.
 *
 */

package org.scijava.java3d.utils.universe ;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StreamTokenizer;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.AbstractMap;
import java.util.AbstractSet;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

/**
 * Loads a Java 3D configuration file and creates a container of named objects
 * that will effect the viewing configuration specified in the file.  These
 * can include Viewers, ViewingPlatforms, ViewPlatformBehaviors, InputDevices,
 * Sensors, and other objects.

* * Clients can construct the view side of a scene graph by retrieving these * objects using the accessor methods provided by this class. This could * involve as little as just attaching ViewingPlatforms to a Locale, depending * upon how completely the viewing configuration is specified in the file. * The ConfiguredUniverse class is an example of a ConfigContainer client and * how it can be used.

* * ConfigContainer can be useful for clients other than ConfiguredUniverse. * InputDevice and ViewPlatformBehavior configuration is fully supported, so a * given Java 3D installation can provide configuration files to an * application that will allow it to fully utilize whatever site-specific * devices and behaviors are available. The configuration mechanism can be * extended for any target object through the use of the * NewObject and ObjectProperty configuration * commands. * * @see ConfiguredUniverse * @see * The Java 3D Configuration File * @see * Example Configuration Files * * @since Java 3D 1.3.1 */ public class ConfigContainer { // // The configuration object database is implemented with a HashMap which // maps their class names to ArrayList objects which contain the actual // instances. The latter are used since the instances of a given class // must be evaluated in the order in which they were created. // LinkedHashMap is available in JDK 1.4 but currently this code must run // under JDK 1.3.1 as well. // private Map baseNameMap = new HashMap() ; // Map containing named canvases for each view. private Map viewCanvasMap = new HashMap() ; // Read-only Maps for the public interface to the configuration database. private ReadOnlyMap bodyMap = null ; private ReadOnlyMap environmentMap = null ; private ReadOnlyMap viewerMap = null ; private ReadOnlyMap deviceMap = null ; private ReadOnlyMap sensorMap = null ; private ReadOnlyMap behaviorMap = null ; private ReadOnlyMap platformMap = null ; private ReadOnlyMap genericObjectMap = null ; // Read-only Sets for the public interface to the configuration database. private ReadOnlySet bodies = null ; private ReadOnlySet environments = null ; private ReadOnlySet viewers = null ; private ReadOnlySet devices = null ; private ReadOnlySet sensors = null ; private ReadOnlySet behaviors = null ; private ReadOnlySet platforms = null ; private ReadOnlySet genericObjects = null ; // The number of TransformGroups to include in ViewingPlatforms. private int transformCount = 1 ; // The visibility status of Viewer AWT components. private boolean setVisible = false ; private ClassLoader classLoader = ClassLoader.getSystemClassLoader(); /** * The name of the file this ConfigContainer is currently loading. */ String currentFileName = null ; /** * Creates a new ConfigContainer and loads the configuration file at the * specified URL. All ViewingPlatform instances are created with a single * TransformGroup and all Viewer components are initially invisible. * * @param userConfig URL of the configuration file to load */ public ConfigContainer(URL userConfig) { this(userConfig, false, 1, true) ; } /** * Creates a new ConfigContainer and loads the configuration file at the * specified URL. All ViewingPlatform instances are created with a single * TransformGroup and all Viewer components are initially invisible. * * @param userConfig URL of the configuration file to load * @param classLoader the class loader to use to load classes specified * in the config file. */ public ConfigContainer(URL userConfig, ClassLoader classLoader) { this(userConfig, false, 1, true, classLoader) ; } /** * Creates a new ConfigContainer and loads the configuration file at the * specified URL. Any ViewingPlatform instantiated by the configuration * file will be created with the specified number of transforms. Viewer * components may be set initially visible or invisible with the * setVisible flag. * * @param userConfig URL of the configuration file to load * @param setVisible if true, setVisible(true) is called on * all Viewers * @param transformCount number of transforms to be included in any * ViewingPlatform created; must be greater than 0 */ public ConfigContainer(URL userConfig, boolean setVisible, int transformCount) { this(userConfig, setVisible, transformCount, true) ; } /** * Creates a new ConfigContainer and loads the configuration file at the * specified URL. Any ViewingPlatform instantiated by the configuration * file will be created with the specified number of transforms. Viewer * components may be set initially visible or invisible with the * setVisible flag. * * @param userConfig URL of the configuration file to load * @param setVisible if true, setVisible(true) is called on * all Viewers * @param transformCount number of transforms to be included in any * ViewingPlatform created; must be greater than 0 * @param classLoader the class loader to use to load classes specified * in the config file. */ public ConfigContainer(URL userConfig, boolean setVisible, int transformCount, ClassLoader classLoader) { this(userConfig, setVisible, transformCount, true, classLoader) ; } /** * Package-scoped constructor for ConfigContainer. This provides an * additional flag, attachBehaviors, which indicates whether * or not ViewPlatformBehaviors should be attached to the ViewingPlatforms * specified for them.

* * Normally the flag should be true. However, when instantiated by * ConfiguredUniverse, this flag is set false so that ConfiguredUniverse * can set a reference to itself in the ViewingPlatform before attaching * the behavior. This provides backwards compatibility to behaviors that * access the ConfiguredUniverse instance from a call to * setViewingPlatform in order to look up the actual Sensor, * Viewer, Behavior, etc., instances associated with the names provided * them from the configuration file.

* * The preferred methods to retrieve instances of specific objects defined * in the configuration file are to either 1) get the ConfiguredUniverse * instance when the behavior's initialize method is called, * or to 2) define properties that accept object instances directly, and * then use the newer Device, Sensor, ViewPlatform, etc., built-in * commands in the configuration file. These built-ins will return an * object instance from a name. * * @param userConfig URL of the configuration file to load * @param setVisible if true, setVisible(true) is called on * all Viewers * @param transformCount number of transforms to be included in any * ViewingPlatform created; must be greater than 0 * @param attachBehaviors if true, attach ViewPlatformBehaviors to the * appropriate ViewingPlatforms */ ConfigContainer(URL userConfig, boolean setVisible, int transformCount, boolean attachBehaviors) { if (transformCount < 1) throw new IllegalArgumentException ("transformCount must be greater than 0") ; loadConfig(userConfig) ; processConfig(setVisible, transformCount, attachBehaviors) ; } /** * Package scoped constructor that adds the ability to set the ClassLoader * which will be used to load any app specific classes specified in the * configuration file. By default SystemClassLoader is used. */ ConfigContainer(URL userConfig, boolean setVisible, int transformCount, boolean attachBehaviors, ClassLoader classLoader) { this(userConfig, setVisible, transformCount, attachBehaviors); this.classLoader = classLoader; } /** * Open, parse, and load the contents of a configuration file. * * @param userConfig location of the configuration file */ private void loadConfig(URL userConfig) { InputStream inputStream = null ; StreamTokenizer streamTokenizer = null ; String lastFileName = currentFileName ; currentFileName = userConfig.toString() ; try { inputStream = userConfig.openStream() ; Reader r = new BufferedReader(new InputStreamReader(inputStream)) ; streamTokenizer = new StreamTokenizer(r) ; } catch (IOException e) { throw new IllegalArgumentException( e + "\nUnable to open " + currentFileName) ; } // // Set up syntax tables for the tokenizer. // // It would be nice to allow '/' as a word constituent for URL strings // and Unix paths, but then the scanner won't ignore "//" and "/* */" // comment style syntax. Treating '/' as an ordinary character will // allow comments to work, but then '/' becomes a single token which // has to be concatenated with subsequent tokens to reconstruct the // original word string. // // It is cleaner to just require quoting for forward slashes. '/' // should still be treated as an ordinary character however, so that a // non-quoted URL string or Unix path will be treated as a syntax // error instead of a comment. // streamTokenizer.ordinaryChar('/') ; streamTokenizer.wordChars('_', '_') ; streamTokenizer.wordChars('$', '$') ; // for ${...} Java property streamTokenizer.wordChars('{', '}') ; // substitution in word tokens streamTokenizer.slashSlashComments(true) ; streamTokenizer.slashStarComments(true) ; // Create an s-expression parser to use for all top-level (0) commands. ConfigSexpression sexp = new ConfigSexpression() ; // Loop through all top-level commands. Boolean.FALSE is returned // after the last one is evaluated. while (sexp.parseAndEval(this, streamTokenizer, 0) != Boolean.FALSE) ; // Close the input stream. try { inputStream.close() ; } catch (IOException e) { throw new IllegalArgumentException( e + "\nUnable to close " + currentFileName) ; } // Restore current file name. currentFileName = lastFileName ; } /** * This method gets called from the s-expression parser to process a * configuration command. * * @param elements tokenized list of sexp elements * @param lineNumber command line number */ void evaluateCommand(ArrayList elements, int lineNumber) { ConfigObject co ; ConfigCommand cmd ; // Create a command object. cmd = new ConfigCommand(elements, currentFileName, lineNumber) ; // Process the command according to its type. switch (cmd.type) { case ConfigCommand.CREATE: co = createConfigObject(cmd) ; addConfigObject(co) ; break ; case ConfigCommand.ALIAS: co = createConfigAlias(cmd) ; addConfigObject(co) ; break ; case ConfigCommand.PROPERTY: co = findConfigObject(cmd.baseName, cmd.instanceName) ; co.setProperty(cmd) ; break ; case ConfigCommand.INCLUDE: if (! (cmd.argv[1] instanceof String)) { throw new IllegalArgumentException ("Include file must be a URL string") ; } URL url = null ; String urlString = (String)cmd.argv[1] ; try { url = new URL(urlString) ; } catch (MalformedURLException e) { throw new IllegalArgumentException(e.toString()) ; } loadConfig(url) ; break ; case ConfigCommand.IGNORE: break ; default: throw new IllegalArgumentException ("Unknown command \"" + cmd.commandName + "\"") ; } } /** * Instantiates and initializes an object that extends the ConfigObject * base class. The class name of the object is derived from the * command, which is of the following form:

* * (New{baseName} {instanceName} ... [Alias {aliasName}])

* * The first two command elements and the optional trailing Alias syntax * are processed here, at which point the subclass implementation of * initialize() is called. Subclasses must override initialize() if they * need to process more than what is processed by default here. * * @param cmd configuration command that creates a new ConfigObject */ private ConfigObject createConfigObject(ConfigCommand cmd) { Class objectClass = null ; ConfigObject configObject = null ; // Instantatiate the ConfigObject if possible. This is not the target // object, but an object that will gather configuration properties, // instantiate the target object, and then apply the configuration // properties to it. try { objectClass = Class.forName("org.scijava.java3d.utils.universe.Config" + cmd.baseName) ; } catch (ClassNotFoundException e) { throw new IllegalArgumentException ("\"" + cmd.baseName + "\"" + " is not a configurable object; ignoring command") ; } try { configObject = (ConfigObject)(objectClass.newInstance()) ; } catch (IllegalAccessException e) { System.out.println(e) ; throw new IllegalArgumentException("Ignoring command") ; } catch (InstantiationException e) { System.out.println(e) ; throw new IllegalArgumentException("Ignoring command") ; } // Process an Alias keyword if present. This option is available for // all New commands so it is processed here. The Alias keyword must // be the penultimate command element, followed by a String. for (int i = 2 ; i < cmd.argc ; i++) { if (cmd.argv[i] instanceof String && ((String)cmd.argv[i]).equals("Alias")) { if (i == (cmd.argc - 2) && cmd.argv[i+1] instanceof String) { addConfigObject(new ConfigAlias(cmd.baseName, (String)cmd.argv[i+1], configObject)) ; cmd.argc -= 2 ; } else { throw new IllegalArgumentException ("The alias name must be a string and " + "must be the last command argument") ; } } } // Initialize common fields. configObject.baseName = cmd.baseName ; configObject.instanceName = cmd.instanceName ; configObject.creatingCommand = cmd ; configObject.configContainer = this ; // Initialize specific fields and return the ConfigObject. configObject.setClassLoader(classLoader); configObject.initialize(cmd) ; return configObject ; } /** * Instantiate and initialize a ConfigObject base class containing alias * information. The command is of the form:

* * ({baseName}Alias {aliasName} {originalName}) * * @param cmd configuration command that creates a new alias * @return the new ConfigObject with alias information */ private ConfigObject createConfigAlias(ConfigCommand cmd) { ConfigObject original ; if (cmd.argc != 3 || ! (cmd.argv[2] instanceof String)) throw new IllegalArgumentException ("Command \"" + cmd.commandName + "\" requires an instance name as second argument") ; original = findConfigObject(cmd.baseName, (String)cmd.argv[2]) ; return new ConfigAlias(cmd.baseName, cmd.instanceName, original) ; } /** * A class that does nothing but reference another ConfigObject. Once * created, the alias name can be used in all commands that would accept * the original name. A lookup of the alias name will always return the * original instance. */ private static class ConfigAlias extends ConfigObject { ConfigAlias(String baseName, String instanceName, ConfigObject targ) { this.baseName = baseName ; this.instanceName = instanceName ; this.isAlias = true ; this.original = targ ; targ.aliases.add(instanceName) ; } } /** * Adds the specified ConfigObject instance into this container using the * given ConfigCommand's base name and instance name. * * @param object the ConfigObject instance to add into the database */ private void addConfigObject(ConfigObject object) { ArrayList instances ; instances = (ArrayList)baseNameMap.get(object.baseName) ; if (instances == null) { instances = new ArrayList() ; baseNameMap.put(object.baseName, instances) ; } // Disallow duplicate instance names. for (int i = 0 ; i < instances.size() ; i++) { ConfigObject co = (ConfigObject)instances.get(i) ; if (co.instanceName.equals(object.instanceName)) { // Don't confuse anybody using Window. String base = object.baseName ; if (base.equals("Screen")) base = "Screen or Window" ; throw new IllegalArgumentException ("Duplicate " + base + " instance name \"" + object.instanceName + "\" ignored") ; } } instances.add(object) ; } /** * Finds a config object matching the given base name and the instance * name. If an alias is found, then its original is returned. If the * object is not found, an IllegalArgumentException is thrown.

* * @param basename base name of the config object * @param instanceName name associated with this config object instance * @return the found ConfigObject */ ConfigObject findConfigObject(String baseName, String instanceName) { ArrayList instances ; ConfigObject configObject ; instances = (ArrayList)baseNameMap.get(baseName) ; if (instances != null) { for (int i = 0 ; i < instances.size() ; i++) { configObject = (ConfigObject)instances.get(i) ; if (configObject.instanceName.equals(instanceName)) { if (configObject.isAlias) return configObject.original ; else return configObject ; } } } // Throw an error, but don't confuse anybody using Window. if (baseName.equals("Screen")) baseName = "Screen or Window" ; throw new IllegalArgumentException (baseName + " \"" + instanceName + "\" not found") ; } /** * Find instances of config objects with the given base name. * This is the same as findConfigObjects(baseName, true). * Aliases are filtered out so that all returned instances are unique. * * @param baseName base name of desired config object class * @return ArrayList of config object instances of the desired base * class, or null if instances of the base class don't exist */ Collection findConfigObjects(String baseName) { return findConfigObjects(baseName, true) ; } /** * Find instances of config objects with the given base name. * * @param baseName base name of desired config object class * @param filterAlias if true, aliases are filtered out so that all * returned instances are unique * @return ArrayList of config object instances of the desired base * class, or null if instances of the base class don't exist */ Collection findConfigObjects(String baseName, boolean filterAlias) { ArrayList instances ; instances = (ArrayList)baseNameMap.get(baseName) ; if (instances == null || instances.size() == 0) { return null ; // This is not an error. } if (filterAlias) { ArrayList output = new ArrayList() ; for (int i = 0 ; i < instances.size() ; i++) { ConfigObject configObject = (ConfigObject)instances.get(i) ; if (! configObject.isAlias) { output.add(configObject) ; } } return output ; } else { return instances ; } } /** * Returns the ConfigObject associated with the name in the given * ConfigCommand. This is used for evaluating retained built-in commands * after the config file has already been parsed. The parser won't catch * any of the exceptions generated by this method, so the error messages * are wrapped accordingly. * * @param basename base name of the config object * @param cmd command containing the name in argv[1] * @return the found ConfigObject */ private ConfigObject findConfigObject(String baseName, ConfigCommand cmd) { if (cmd.argc != 2 || !(cmd.argv[1] instanceof String)) throw new IllegalArgumentException (ConfigObject.errorMessage (cmd, "Parameter must be a single string")) ; try { return findConfigObject(baseName, (String)cmd.argv[1]) ; } catch (IllegalArgumentException e) { throw new IllegalArgumentException (ConfigObject.errorMessage(cmd, e.getMessage())) ; } } /** * This method gets called from a ConfigObject to evaluate a retained * built-in command nested within a property command. These are commands * that can't be evaluated until the entire config file is parsed. * * @param cmd the built-in command * @return object representing result of evaluation */ Object evaluateBuiltIn(ConfigCommand cmd) { int argc = cmd.argc ; Object[] argv = cmd.argv ; if (cmd.commandName.equals("ConfigContainer")) { // return a reference to this ConfigContainer return this ; } else if (cmd.commandName.equals("Canvas3D")) { // Look for canvases in the screen database. return ((ConfigScreen)findConfigObject("Screen", cmd)).j3dCanvas ; } else if (baseNameMap.get(cmd.commandName) != null) { // Handle commands of the form ({objectType} name) that return the // object associated with the name. return findConfigObject(cmd.commandName, cmd).targetObject ; } else { // So far no other retained built-in commands. throw new IllegalArgumentException (ConfigObject.errorMessage(cmd, "Unknown built-in command \"" + cmd.commandName + "\"")) ; } } /** * Process the configuration after parsing the configuration file. * Note: the processing order of the various config objects is * significant. * * @param setVisible true if Viewer components should be visible * @param transformCount number of TransformGroups with which * ViewingPlatforms should be created * @param attachBehaviors true if behaviors should be attached to * ViewingPlatforms */ private void processConfig(boolean setVisible, int transformCount, boolean attachBehaviors) { Collection c, s, pe, vp ; this.setVisible = setVisible ; this.transformCount = transformCount ; c = findConfigObjects("PhysicalBody") ; if (c != null) { processPhysicalBodies(c) ; } pe = findConfigObjects("PhysicalEnvironment") ; if (pe != null) { processPhysicalEnvironments(pe) ; } c = findConfigObjects("View") ; if (c != null) { processViews(c, setVisible) ; } c = findConfigObjects("Device") ; s = findConfigObjects("Sensor") ; if (c != null) { processDevices(c, s, pe) ; } vp = findConfigObjects("ViewPlatform") ; if (vp != null) { processViewPlatforms(vp, transformCount) ; } c = findConfigObjects("ViewPlatformBehavior") ; if (c != null) { processViewPlatformBehaviors(c, vp, attachBehaviors) ; } c = findConfigObjects("Object") ; if (c != null) { processGenericObjects(c) ; } } // Process config physical environments into Java 3D physical // environments. private void processPhysicalEnvironments(Collection c) { Iterator i = c.iterator() ; while (i.hasNext()) { ConfigPhysicalEnvironment e = (ConfigPhysicalEnvironment)i.next() ; e.targetObject = e.createJ3dPhysicalEnvironment() ; } } // Process config physical bodys into Java 3D physical bodies. private void processPhysicalBodies(Collection c) { Iterator i = c.iterator() ; while (i.hasNext()) { ConfigPhysicalBody b = (ConfigPhysicalBody)i.next() ; b.targetObject = b.createJ3dPhysicalBody() ; } } // Process config views into Java 3D Views and then create Viewer objects // for them. This should only be called after all physical bodies and // physical environments have been processed. private void processViews(Collection c, boolean setVisible) { Iterator i = c.iterator() ; while (i.hasNext()) { ConfigView v = (ConfigView)i.next() ; v.targetObject = v.createViewer(setVisible) ; } } // Process config devices into Java 3D input devices. This should be done // only after all views have been processed, as some InputDevice // implementations require the AWT components associated with a view. private void processDevices(Collection c, Collection s, Collection p) { ConfigDevice cd = null ; Iterator i = c.iterator() ; while (i.hasNext()) { cd = (ConfigDevice)i.next() ; cd.targetObject = cd.createInputDevice() ; } // Process device properties only after all InputDevices have been // instantiated. Some InputDevice properties require references // to other InputDevice implementations. i = c.iterator() ; while (i.hasNext()) ((ConfigDevice)i.next()).processProperties() ; // Initialize the devices only after all have been instantiated, as // some InputDevices implementations are slaved to the first one // created and will not initialize otherwise (e.g. LogitechTracker). i = c.iterator() ; while (i.hasNext()) { cd = (ConfigDevice)i.next() ; if (! cd.j3dInputDevice.initialize()) throw new RuntimeException (cd.errorMessage(cd.creatingCommand, "could not initialize device \"" + cd.instanceName + "\"")) ; } // An InputDevice implementation will have created all its Sensors by // the time initialize() returns. Retrieve and configure them here. if (s != null) { i = s.iterator() ; while (i.hasNext()) { ConfigSensor cs = (ConfigSensor)i.next() ; cs.configureSensor() ; cs.targetObject = cs.j3dSensor ; } } // Iterate through the PhysicalEnvironments and process the devices. if (p != null) { i = p.iterator() ; while (i.hasNext()) ((ConfigPhysicalEnvironment)i.next()).processDevices() ; } } // Process config view platforms into Java 3D viewing platforms. private void processViewPlatforms(Collection c, int numTransforms) { Iterator i = c.iterator() ; while (i.hasNext()) { ConfigViewPlatform cvp = (ConfigViewPlatform)i.next() ; cvp.targetObject = cvp.createViewingPlatform(numTransforms) ; } } // Process the configured view platform behaviors. private void processViewPlatformBehaviors(Collection behaviors, Collection viewPlatforms, boolean attach) { Iterator i = behaviors.iterator() ; while (i.hasNext()) { ConfigViewPlatformBehavior b = (ConfigViewPlatformBehavior)i.next() ; b.targetObject = b.createViewPlatformBehavior() ; } // Process properties only after all behaviors are instantiated. i = behaviors.iterator() ; while (i.hasNext()) ((ConfigViewPlatformBehavior)i.next()).processProperties() ; // Attach behaviors to platforms after properties processed. if (attach && viewPlatforms != null) { i = viewPlatforms.iterator() ; while (i.hasNext()) ((ConfigViewPlatform)i.next()).processBehavior() ; } } // Process generic objects. private void processGenericObjects(Collection objects) { Iterator i = objects.iterator() ; while (i.hasNext()) { ConfigObject o = (ConfigObject)i.next() ; o.targetObject = o.createTargetObject() ; } // Process properties only after all target objects are instantiated. i = objects.iterator() ; while (i.hasNext()) ((ConfigObject)i.next()).processProperties() ; } // Returns a read-only Set containing all unique Java 3D objects of the // specified base class. private ReadOnlySet createSet(String baseName) { Collection c = findConfigObjects(baseName, true) ; if (c == null || c.size() == 0) return null ; Iterator i = c.iterator() ; ArrayList l = new ArrayList() ; while (i.hasNext()) l.add(((ConfigObject)i.next()).targetObject) ; return new ReadOnlySet(l) ; } // Returns a read-only Map that maps all names in the specified base // class, including aliases, to their corresponding Java 3D objects. private ReadOnlyMap createMap(String baseName) { Collection c = findConfigObjects(baseName, false) ; if (c == null || c.size() == 0) return null ; Iterator i = c.iterator() ; HashMap m = new HashMap() ; while (i.hasNext()) { ConfigObject co = (ConfigObject)i.next() ; if (co.isAlias) m.put(co.instanceName, co.original.targetObject) ; else m.put(co.instanceName, co.targetObject) ; } return new ReadOnlyMap(m) ; } /** * Returns a read-only Set of all configured PhysicalBody instances in the * order they were defined in the configuration file. * * PhysicalBody instances are created with the following command:

*

* (NewPhysicalBody <instance name> * [Alias <alias name>]) *
* * The PhysicalBody is configured through the following command:

*

* (PhysicalBodyProperty <instance name> * <property name> <property value>) *
* * @return read-only Set of all unique instances, or null */ public Set getPhysicalBodies() { if (bodies != null) return bodies ; bodies = createSet("PhysicalBody") ; return bodies ; } /** * Returns a read-only Map that maps PhysicalBody names to instances. * Names may be aliases and if so will map to the original instances. * * @return read-only Map from names to PhysicalBody instances, or null if * no instances */ public Map getNamedPhysicalBodies() { if (bodyMap != null) return bodyMap ; bodyMap = createMap("PhysicalBody") ; return bodyMap ; } /** * Returns a read-only Set of all configured PhysicalEnvironment instances * in the order they were defined in the configuration file.

* * PhysicalEnvironment instances are created with the following command:

*

* (NewPhysicalEnvironment <instance name> * [Alias <alias name>]) *
* * The PhysicalEnvironment is configured through the following command:

*

* (PhysicalEnvironmentProperty <instance name> * <property name> <property value>) *
* * @return read-only Set of all unique instances, or null */ public Set getPhysicalEnvironments() { if (environments != null) return environments ; environments = createSet("PhysicalEnvironment") ; return environments ; } /** * Returns a read-only Map that maps PhysicalEnvironment names to * instances. Names may be aliases and if so will map to the original * instances. * * @return read-only Map from names to PhysicalEnvironment instances, or * null if no instances */ public Map getNamedPhysicalEnvironments() { if (environmentMap != null) return environmentMap ; environmentMap = createMap("PhysicalEnvironment") ; return environmentMap ; } /** * Returns a read-only Set of all configured Viewer instances in the order * they were defined in the configuration file. The Viewers will have * incorporated any PhysicalEnvironment and PhysicalBody objects specfied * for them in the configuration file, and will be attached to any * ViewingPlatforms specified for them.

* * Viewer instances are created with the following command:

*

* (NewView <instance name> [Alias <alias name>]) *
* * The Viewer is configured through the following command:

*

* (ViewProperty <instance name> * <property name> <property value>) *
* * @return read-only Set of all unique instances, or null */ public Set getViewers() { if (viewers != null) return viewers ; viewers = createSet("View") ; return viewers ; } /** * Returns a read-only Map that maps Viewer names to instances. * Names may be aliases and if so will map to the original instances. * The Viewers will have incorporated any PhysicalEnvironment and * PhysicalBody objects specfied for them in the configuration file, and * will be attached to any ViewingPlatforms specified for them.

* * @return read-only Map from names to Viewer instances, or * null if no instances */ public Map getNamedViewers() { if (viewerMap != null) return viewerMap ; viewerMap = createMap("View") ; return viewerMap ; } /** * Returns a read-only Set of all configured InputDevice instances in the * order they were defined in the configuration file. All InputDevice * instances in the set are initialized and registered with any * PhysicalEnvironments that reference them.

* * InputDevice instances are created with the following command:

*

* (NewDevice <instanceName> <className> * [Alias <alias name>]) *
* * className must be the fully-qualified name of a class that * implements the InputDevice interface. The implementation * must provide a parameterless constructor.

* * The InputDevice is configured through the DeviceProperty command:

*

* (DeviceProperty <instanceName> <propertyName> * <arg0> ... <argn>) *
* * propertyName must be the name of a input device method that * takes an array of Objects as its only parameter; the array is populated * with the values of arg0 through argn when the method is * invoked to set the property. These additional requirements for * configurable input devices can usually be fulfilled by extending or * wrapping available InputDevice implementations. * * @return read-only Set of all unique instances, or null */ public Set getInputDevices() { if (devices != null) return devices ; devices = createSet("Device") ; return devices ; } /** * Returns a read-only Map that maps InputDevice names to instances. * Names may be aliases and if so will map to the original instances. All * InputDevice instances in the map are initialized and registered with * any PhysicalEnvironments that reference them. * * @return read-only Map from names to InputDevice instances, or * null if no instances * @see #getInputDevices */ public Map getNamedInputDevices() { if (deviceMap != null) return deviceMap ; deviceMap = createMap("Device") ; return deviceMap ; } /** * Returns a read-only Set of all configured Sensor instances in the order * they were defined in the configuration file. The associated * InputDevices are all initialized and registered with any * PhysicalEnvironments that reference them.

* * Sensor instances are named with the following command:

*

* (NewSensor <instance name> <device name> * <sensor index> [Alias <alias name>]) *
* * device name is the instance name of a previously defined * InputDevice, and sensor index is the index of the Sensor to be * bound to instance name. The InputDevice implementation is * responsible for creating its own Sensor objects, so this command does * not create any new instances.

* * The Sensor is configured through the SensorProperty command:

*

* (SensorProperty <instance name> <property name> * <property value>) *
* * With the sole exception of the Sensor assigned to the head tracker, * none of the Sensors defined in the configuration file are placed into * the Sensor array maintained by a PhysicalEnvironment. * * @return read-only Set of all unique instances, or null */ public Set getSensors() { if (sensors != null) return sensors ; sensors = createSet("Sensor") ; return sensors ; } /** * Returns a read-only Map that maps Sensor names to instances. Names may * be aliases and if so will map to the original instances. The * associated InputDevices are all initialized and registered with any * PhysicalEnvironments that reference them.

* * With the sole exception of the Sensor assigned to the head tracker, * none of the Sensors defined in the configuration file are placed into * the Sensor array maintained by a PhysicalEnvironment. * * @return read-only Map from names to Sensor instances, or * null if no instances */ public Map getNamedSensors() { if (sensorMap != null) return sensorMap ; sensorMap = createMap("Sensor") ; return sensorMap ; } /** * Returns a read-only Set of all configured ViewingPlatform instances in * the order they were defined in the configuration file. The * ConfigContainer class itself does not attach the ViewingPlatform * instances to any scengraph components or universe Locales; they are not * "live" until made so by a separate client such as ConfiguredUniverse. * * ViewingPlatform instances are created with the following command:

*

* (NewViewPlatform <instance name> * [Alias <alias name>]) *
* * The ViewingPlatform is configured through the following command:

*

* (ViewPlatformProperty <instance name> <property name> * <property value>) *
* * @return read-only Set of all unique instances, or null */ public Set getViewingPlatforms() { if (platforms != null) return platforms ; platforms = createSet("ViewPlatform") ; return platforms ; } /** * Returns a read-only Map that maps ViewingPlatform names to instances. * Names may be aliases and if so will map to the original instances. The * ConfigContainer class itself does not attach the ViewingPlatform * instances to any scengraph components or universe Locales; they are not * "live" until made so by a separate client such as ConfiguredUniverse. * * @return read-only Map from names to ViewingPlatform instances, or * null if no instances */ public Map getNamedViewingPlatforms() { if (platformMap != null) return platformMap ; platformMap = createMap("ViewPlatform") ; return platformMap ; } /** * Returns a read-only Set of all configured ViewPlatformBehavior * instances in the order they were defined in the configuration file.

* * The behaviors are attached to any ViewingPlatforms that specified them; * that is, the setViewPlatformBehavior and * setViewingPlatform methods of ViewingPlatform and * ViewPlatformBehavior have been called if appropriate. However, a * behavior's initialize method is not called until the * ViewingPlatform to which it is attached is made live.

* * ViewPlatformBehavior instances are created by the following command:

*

* (NewViewPlatformBehavior <instanceName> <className>) *
* * className must be the fully qualified name of a concrete class * that extends the abstract ViewPlatformBehavior class. The * implementation must provide a parameterless constructor.

* * The behavior is configured using ViewPlatformBehaviorProperty:

*

* (ViewPlatformBehaviorProperty <instanceName> * <propertyName> <arg0> ... <argn>) *
* * ViewPlatformBehavior subclasses inherit a number of pre-defined * properties that can be directly specified with the propertyName * string; see the configuration file documentation for details.

* * Concrete ViewPlatformBehavior instances can also define their own * unique properties. In those cases, propertyName must be the * name of a behavior method that takes an array of Objects as its only * parameter; the array is populated with the values of arg0 * through argn when the method is invoked to set the property. * These additional requirements for configurable behaviors can usually be * fulfilled by extending or wrapping available ViewPlatformBehavior * subclasses. * * @return read-only Set of all unique instances, or null */ public Set getViewPlatformBehaviors() { if (behaviors != null) return behaviors ; behaviors = createSet("ViewPlatformBehavior") ; return behaviors ; } /** * Returns a read-only Map that maps ViewPlatformBehavior names to * instances. Names may be aliases and if so will map to the original * instances.

* * The behaviors are attached to any ViewingPlatforms that specified them; * that is, the setViewPlatformBehavior and * setViewingPlatform methods of ViewingPlatform and * ViewPlatformBehavior have been called if appropriate. However, a * behavior's initialize method is not called until the * ViewingPlatform to which it is attached is made live.

* * @return read-only Map from names to ViewPlatformBehavior instances, or * null if no instances * @see #getViewPlatformBehaviors */ public Map getNamedViewPlatformBehaviors() { if (behaviorMap != null) return behaviorMap ; behaviorMap = createMap("ViewPlatformBehavior") ; return behaviorMap ; } /** * Returns a read-only Map containing the named Canvas3D instances used by * the specified Viewer. Names may be aliases and if so will map to the * original instances. The set of unique Canvas3D instances used by a * Viewer may be obtained by calling the Viewer's accessor methods * directly.

* * A named Canvas3D is created and added to a Viewer whenever any of the * following configuration commands are used:

*

* (ViewProperty <view> Screen <screenName>)
* (ViewProperty <view> Window <windowName>) *
* * view is the name of a Viewer created with the NewView command. * The screenName and windowName parameters of the above * commands are the keys to use when looking up the associated Canvas3D * instances in the Map returned by this method. Note: the * NewScreen and NewWindow commands do not create Canvas3D * instances themselves; they are created only by the above configuration * commands. * * @param viewName the name of the Viewer * @return read-only Map containing the Viewer's named Canvas3D instances */ public Map getNamedCanvases(String viewName) { Map m = (Map)viewCanvasMap.get(viewName) ; if (m != null) return m ; m = new HashMap() ; ConfigView cv = (ConfigView)findConfigObject("View", viewName) ; Iterator i = cv.screens.iterator() ; while (i.hasNext()) { ConfigScreen cs = (ConfigScreen)i.next() ; m.put(cs.instanceName, cs.j3dCanvas) ; // The aliases list contains all alias strings for the canvas. Iterator j = cs.aliases.iterator() ; while (j.hasNext()) m.put(j.next(), cs.j3dCanvas) ; } m = new ReadOnlyMap(m) ; viewCanvasMap.put(viewName, m) ; return m ; } /** * Returns a read-only Set of all generic configuration object * instances in the order they were defined in the configuration file.

* * Generic object instances are created with the following command:

*

* (NewObject <instanceName> <className>) *
* * className must be the fully-qualified name of a class that * provides a parameterless constructor.

* * The object is configured through the ObjectProperty command:

*

* (ObjectProperty <instanceName> <propertyName> * <arg0> ... <argn>) *
* * propertyName must be the name of a method provided by object * instanceName. It must take an array of Objects as its only * parameter; the array is populated with the values of arg0 * through argn when the method is invoked to set the property. * These additional requirements for configurable objects can usually be * fulfilled by extending or wrapping available object classes. * * @return read-only Set of all unique instances, or null */ public Set getGenericObjects() { if (genericObjects != null) return genericObjects ; genericObjects = createSet("Object") ; return genericObjects ; } /** * Returns a read-only Map that maps generic object names to * instances. Names may be aliases and if so will map to the original * instances. * * @return read-only Map from names to generic object instances, or * null if no instances * @see #getGenericObjects */ public Map getNamedGenericObjects() { if (genericObjectMap != null) return genericObjectMap ; genericObjectMap = createMap("Object") ; return genericObjectMap ; } /** * Returns the number of TransformGroups with which ViewingPlatforms * should be created. This is useful for clients that wish to provide a * default ViewingPlatform if the configuration file doesn't specify one. * * @return the number of TransformGroups */ public int getViewPlatformTransformCount() { return transformCount ; } /** * Returns whether Viewers should be created with their AWT components * initially visible or invisible. This is useful for clients that wish * to provide a default Viewer if the configuration file doesn't specify * one. * * @return true if Viewer components should be initially visible; false * otherwise */ public boolean getViewerVisibility() { return setVisible ; } /** * Release memory references used by this ConfigContainer. All Sets and * Maps obtained from this ConfigContainer are cleared. */ public void clear() { // Clear baseNameList. Iterator i = baseNameMap.values().iterator() ; while (i.hasNext()) ((Collection)i.next()).clear() ; baseNameMap.clear() ; // Clear viewCanvasMap. i = viewCanvasMap.values().iterator() ; while (i.hasNext()) ((ReadOnlyMap)i.next()).map.clear() ; viewCanvasMap.clear() ; // Release reference to file name. currentFileName = null ; // Clear and release sets. if (bodies != null) { bodies.collection.clear() ; bodies = null ; } if (environments != null) { environments.collection.clear() ; environments = null ; } if (devices != null) { devices.collection.clear() ; devices = null ; } if (sensors != null) { sensors.collection.clear() ; sensors = null ; } if (behaviors != null) { behaviors.collection.clear() ; behaviors = null ; } if (platforms != null) { platforms.collection.clear() ; platforms = null ; } if (viewers != null) { viewers.collection.clear() ; viewers = null ; } if (genericObjects != null) { genericObjects.collection.clear() ; genericObjects = null ; } // Clear and release maps. if (bodyMap != null) { bodyMap.map.clear() ; bodyMap = null ; } if (environmentMap != null) { environmentMap.map.clear() ; environmentMap = null ; } if (deviceMap != null) { deviceMap.map.clear() ; deviceMap = null ; } if (sensorMap != null) { sensorMap.map.clear() ; sensorMap = null ; } if (behaviorMap != null) { behaviorMap.map.clear() ; behaviorMap = null ; } if (platformMap != null) { platformMap.map.clear() ; platformMap = null ; } if (viewerMap != null) { viewerMap.map.clear() ; viewerMap = null ; } if (genericObjectMap != null) { genericObjectMap.map.clear() ; genericObjectMap = null ; } } /** * Returns the config file URL based on system properties. The current * implementation of this method parses the j3d.configURL property as a * URL string. For example, the following command line would specify that * the config file is taken from the file "j3dconfig" in the current * directory: *
    * java -Dj3d.configURL=file:j3dconfig ... *
* * @return the URL of the config file; null is returned if no valid * URL is defined by the system properties */ public static URL getConfigURL() { return getConfigURL(null) ; } /** * Returns the config file URL based on system properties. The current * implementation of this method parses the j3d.configURL property as a * URL string. For example, the following command line would specify that * the config file is taken from the file "j3dconfig" in the current * directory: *
    * java -Dj3d.configURL=file:j3dconfig ... *
* * @param defaultURLString the default string used to construct * the URL if the appropriate system properties are not defined * @return the URL of the config file; null is returned if no * valid URL is defined either by the system properties or the * default URL string */ public static URL getConfigURL(String defaultURLString) { URL url = null ; String urlString = null ; final String defProp = defaultURLString ; urlString = (String)java.security.AccessController.doPrivileged (new java.security.PrivilegedAction() { @Override public Object run() { return System.getProperty("j3d.configURL", defProp) ; } }) ; if (urlString == null) { return null ; } try { url = new URL(urlString) ; } catch(MalformedURLException e) { System.out.println(e) ; return null ; } return url ; } // A general purpose read-only Map backed by a HashMap. private static class ReadOnlyMap extends AbstractMap { HashMap map ; private Set entrySet = null ; ReadOnlyMap(Map map) { this.map = new HashMap(map) ; } // overridden for efficiency @Override public Object get(Object key) { return map.get(key) ; } // overridden for efficiency @Override public boolean containsKey(Object key) { return map.containsKey(key) ; } // overridden for efficiency @Override public boolean containsValue(Object value) { return map.containsValue(value) ; } @Override public Set entrySet() { if (entrySet == null) entrySet = new ReadOnlySet(map.entrySet()) ; return entrySet ; } } // A general purpose read-only Set backed by a Collection containing // unique objects. private static class ReadOnlySet extends AbstractSet { Collection collection = null ; ReadOnlySet(Collection c) { this.collection = c ; } @Override public int size() { return collection.size() ; } @Override public Iterator iterator() { return new ReadOnlyIterator(collection.iterator()) ; } } // A general purpose read-only Iterator backed by another Iterator. private static class ReadOnlyIterator implements Iterator { private Iterator i ; ReadOnlyIterator(Iterator i) { this.i = i ; } @Override public boolean hasNext() { return i.hasNext() ; } @Override public Object next() { return i.next() ; } @Override public void remove() { throw new UnsupportedOperationException() ; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy