worldwind学习笔记-1-Configuration

来源:互联网 发布:达梦数据库有限公司 编辑:程序博客网 时间:2024/05/21 17:20

做的一个小的cs程序中一直嵌套worldwind使用,由于使用的是worldwind的java版,结果cs程序也一直是用java的swing开发的,swing在几年前确实很强大,但是现在给人感觉蛮没落的,几乎很少见到swing开发的软件了,不过还好,我们的用户不考虑我们使用什么系统,也可以吹吹牛逼说,我们的程序可以在mac下,linux下,windows下运行,当然,事实也确实如此。

不过我们使用worldwind一直局限在使用它的功能上,一直没能深入进去研究其架构等,我觉得,ww这款sdk功能真的很强大啊,但是我们只用到了collada下的东西做模型,surfaceImage做贴图,animation做3D云,surface下还用了写东西,用来简单的画画图形,画画path等,当然,我们也使用了OpelGL中的一些功能,画了爆炸,降雨等效果,但是我感觉都不是很理想,显然,OpenGL是基础,这个也得会,才能看懂worldwind中的一些代码。

好了,一些基础信息介绍完毕,我想开始去深入挖掘下ww内的东西,尝试学习他,而不仅仅是使用它。

我选择使用HelloWorldWind.java这个类作为入口,因为它只有一个最基本的球,通过阅读代码去学习,我觉得还是可以有较快的进步的。

先来看下这个类的代码。

[java] view plaincopy
  1. package gov.nasa.worldwindx;  
  2.   
  3. import gov.nasa.worldwind.BasicModel;  
  4. import gov.nasa.worldwind.Configuration;  
  5. import gov.nasa.worldwind.awt.WorldWindowGLCanvas;  
  6.   
  7. public class HelloWorldWind  
  8. {  
  9.     // An inner class is used rather than directly subclassing JFrame in the main class so  
  10.     // that the main can configure system properties prior to invoking Swing. This is  
  11.     // necessary for instance on OS X (Macs) so that the application name can be specified.  
  12.   
  13.     private static class AppFrame extends javax.swing.JFrame  
  14.     {  
  15.         public AppFrame()  
  16.         {  
  17.                
  18.             this.setDefaultCloseOperation(EXIT_ON_CLOSE);  
  19.             WorldWindowGLCanvas wwd = new WorldWindowGLCanvas();  
  20.             wwd.setPreferredSize(new java.awt.Dimension(1000800));  
  21.             this.getContentPane().add(wwd, java.awt.BorderLayout.CENTER);  
  22.                
  23.             wwd.setModel(new BasicModel());  
  24.             this.pack();  
  25.         }  
  26.     }  
  27.   
  28.     public static void main(String[] args)  
  29.     {  
  30.         if (Configuration.isMacOS())  
  31.         {  
  32.             System.setProperty("com.apple.mrj.application.apple.menu.about.name""Hello World Wind");  
  33.         }  
  34.         final AppFrame app=new AppFrame();  
  35.         java.awt.EventQueue.invokeLater(new Runnable()  
  36.         {  
  37.             public void run()  
  38.             {  
  39.                 // Create an AppFrame and immediately make it visible. As per Swing convention, this  
  40.                 // is done within an invokeLater call so that it executes on an AWT thread.  
  41.                   
  42.                 app.setVisible(true);  
  43.             }  
  44.         });  
  45.     }  
  46. }  
代码非常的简单,就是构建了一个JFrame,然后调用awt包中的EventQueue来执行,之所以setvisible是单独执行的,是因为worldwind底层要调用jogl,从而用opengl画图。这个代码我曾尝试将app.setVisible拿出来执行,而不是放在EventQueue里面。这种情况在win32下可以正常,在win64下就不正常,按照EventQueue的解释(awt是单线程的所有awt的组件只能在事件处理线程中访问,从而保证组件状态的可确定性)。。。。。这一块我只想说四个字:不觉明历。。。。貌似是和Java内存模型中的,所谓的无关对象的执行顺序会重排也有一定的关系吧。谁能给点这方面的建议就好了。。

再贴一段别人的解释:使用eventqueue.invokelater()好处是显而易见的,这个方法调用完毕后,它会被销毁,因为匿名内部类是作为临时变量存在的,给它分配的内存在此时会被释放。这个对于只需要在一个地方使用时可以节省内存,而且这个类是不可以被其它的方法或类使用的,只能被EventQueue.invokeLater()来使用。但如果你需要一个在很多地方都能用到的类,而不是只在某一个类里面或者方法里用的话,定义成匿名内部类显然是不可取的。 是,runnable是跟线程相关的类。
swingutilities.invokelater()和eventqueue.invokelater(),后者可以不干扰到事件分发线程.SwingUtilities版只是一个薄薄的封装方法,它直接转而调用 EventQueue.invokeLater。因为Swing框架本身经常调用SwingUtilities,使用SwingUtilities可以减少程序引入的类。

对于如此多的概念,我感觉好无力,还是看Main里面干嘛了吧。

if (Configuration.isMacOS()) 第一句,判断是不是苹果的操作系统,我不是苹果机,爱我吊事。。。不过,Configuration却是一个非常非常重要的东西,它是不可忽略的。


Configuration的代码如下。

[java] view plaincopy
  1. /* 
  2.  * Copyright (C) 2012 United States Government as represented by the Administrator of the 
  3.  * National Aeronautics and Space Administration. 
  4.  * All Rights Reserved. 
  5.  */  
  6.   
  7. package gov.nasa.worldwind;  
  8.   
  9. import gov.nasa.worldwind.avlist.AVKey;  
  10. import gov.nasa.worldwind.geom.Angle;  
  11. import gov.nasa.worldwind.util.*;  
  12. import org.w3c.dom.*;  
  13.   
  14. import javax.media.opengl.GLProfile;  
  15. import javax.xml.xpath.*;  
  16. import java.io.*;  
  17. import java.util.*;  
  18. import java.util.logging.Level;  
  19.   
  20. /** 
  21.  * This class manages the initial World Wind configuration. It reads World Wind configuration files and registers their 
  22.  * contents. Configurations files contain the names of classes to create at run-time, the initial model definition, 
  23.  * including the globe, elevation model and layers, and various control quantities such as cache sizes and data 
  24.  * retrieval timeouts. 
  25.  * <p/> 
  26.  * The Configuration class is a singleton, but its instance is not exposed publicly. It is addressed only via static 
  27.  * methods of the class. It is constructed upon first use of any of its static methods. 
  28.  * <p/> 
  29.  * When the Configuration class is first instantiated it reads the XML document <code>config/worldwind.xml</code> and 
  30.  * registers all the information there. The information can subsequently be retrieved via the class' various 
  31.  * <code>getValue</code> methods. Many World Wind start-up objects query this information to determine the classes to 
  32.  * create. For example, the first World Wind object created by an application is typically a {@link 
  33.  * gov.nasa.worldwind.awt.WorldWindowGLCanvas}. During construction that class causes World Wind's internal classes to 
  34.  * be constructed, using the names of those classes drawn from the Configuration singleton, this class. 
  35.  * <p/> 
  36.  * The default World Wind configuration document is <code>config/worldwind.xml</code>. This can be changed by setting 
  37.  * the Java property <code>gov.nasa.worldwind.config.file</code> to a different file name or a valid URL prior to 
  38.  * creating any World Wind object or invoking any static methods of World Wind classes, including the Configuration 
  39.  * class. When an application specifies a different configuration location it typically does so in its main method prior 
  40.  * to using World Wind. If a file is specified its location must be on the classpath. (The contents of application and 
  41.  * World Wind jar files are typically on the classpath, in which case the configuration file may be in the jar file.) 
  42.  * <p/> 
  43.  * Additionally, an application may set another Java property, <code>gov.nasa.worldwind.app.config.document</code>, to a 
  44.  * file name or URL whose contents contain configuration values to override those of the primary configuration document. 
  45.  * World Wind overrides only those values in this application document, it leaves all others to the value specified in 
  46.  * the primary document. Applications usually specify an override document in order to specify the initial layers in the 
  47.  * model. 
  48.  * <p/> 
  49.  * See <code>config/worldwind.xml</code> for documentation on setting configuration values. 
  50.  * <p/> 
  51.  * Configuration values can also be set programatically via {@link Configuration#setValue(String, Object)}, but they are 
  52.  * not retroactive so affect only Configuration queries made subsequent to setting the value. 
  53.  * <p/> 
  54.  * <em>Note:</em> Prior to September of 2009, configuration properties were read from the file 
  55.  * <code>config/worldwind.properties</code>. An alternate file could be specified via the 
  56.  * <code>gov.nasa.worldwind.config.file</code> Java property. These mechanisms remain available but are deprecated. 
  57.  * World Wind no longer contains a <code>worldwind.properties</code> file. If <code>worldwind.properties</code> or its 
  58.  * replacement as specified through the Java property exists at run-time and can be found via the classpath, 
  59.  * configuration values specified by that mechanism are given precedence over values specified by the new mechanism. 
  60.  * 
  61.  * @version $Id: Configuration.java 1171 2013-02-11 21:45:02Z dcollins $ 
  62.  * @author Tom Gaskins 
  63.  */  
  64. public class Configuration // Singleton  
  65. {  
  66.     public static final String DEFAULT_LOGGER_NAME = "gov.nasa.worldwind";  
  67.   
  68.     private static final String CONFIG_PROPERTIES_FILE_NAME = "config/worldwind.properties";  
  69.     private static final String CONFIG_FILE_PROPERTY_KEY = "gov.nasa.worldwind.config.file";  
  70.   
  71.     private static final String CONFIG_WW_DOCUMENT_KEY = "gov.nasa.worldwind.config.document";  
  72.     private static final String CONFIG_WW_DOCUMENT_NAME = "config/worldwind.xml";  
  73.   
  74.     private static final String CONFIG_APP_DOCUMENT_KEY = "gov.nasa.worldwind.app.config.document";  
  75.   
  76.     private static Configuration ourInstance = new Configuration();  
  77.   
  78.     private static Configuration getInstance()  
  79.     {  
  80.         return ourInstance;  
  81.     }  
  82.   
  83.     private final Properties properties;  
  84.     private final ArrayList<Document> configDocs = new ArrayList<Document>();  
  85.   
  86.     /** Private constructor invoked only internally. */  
  87.     private Configuration()  
  88.     {  
  89.         this.properties = initializeDefaults();  
  90.   
  91.         // Load the app's configuration if there is one  
  92.         try  
  93.         {  
  94.             String appConfigLocation = System.getProperty(CONFIG_APP_DOCUMENT_KEY);  
  95.             if (appConfigLocation != null)  
  96.                 this.loadConfigDoc(System.getProperty(CONFIG_APP_DOCUMENT_KEY)); // Load app's config first  
  97.         }  
  98.         catch (Exception e)  
  99.         {  
  100.             Logging.logger(DEFAULT_LOGGER_NAME).log(Level.WARNING, "Configuration.ConfigNotFound",  
  101.                 System.getProperty(CONFIG_APP_DOCUMENT_KEY));  
  102.             // Don't stop if the app config file can't be found or parsed  
  103.         }  
  104.   
  105.         try  
  106.         {  
  107.             // Load the default configuration  
  108.             this.loadConfigDoc(System.getProperty(CONFIG_WW_DOCUMENT_KEY, CONFIG_WW_DOCUMENT_NAME));  
  109.   
  110.             // Load config properties, ensuring that the app's config takes precedence over wwj's  
  111.             for (int i = this.configDocs.size() - 1; i >= 0; i--)  
  112.             {  
  113.                 this.loadConfigProperties(this.configDocs.get(i));  
  114.             }  
  115.         }  
  116.         catch (Exception e)  
  117.         {  
  118.             Logging.logger(DEFAULT_LOGGER_NAME).log(Level.WARNING, "Configuration.ConfigNotFound",  
  119.                 System.getProperty(CONFIG_WW_DOCUMENT_KEY));  
  120.         }  
  121.   
  122.         // To support old-style configuration, read an existing config properties file and give the properties  
  123.         // specified there precedence.  
  124.         this.initializeCustom();  
  125.     }  
  126.   
  127.     private void loadConfigDoc(String configLocation)  
  128.     {  
  129.         if (!WWUtil.isEmpty(configLocation))  
  130.         {  
  131.             Document doc = WWXML.openDocument(configLocation);  
  132.             if (doc != null)  
  133.             {  
  134.                 this.configDocs.add(doc);  
  135. //                this.loadConfigProperties(doc);  
  136.             }  
  137.         }  
  138.     }  
  139.   
  140.     private void insertConfigDoc(String configLocation)  
  141.     {  
  142.         if (!WWUtil.isEmpty(configLocation))  
  143.         {  
  144.             Document doc = WWXML.openDocument(configLocation);  
  145.             if (doc != null)  
  146.             {  
  147.                 this.configDocs.add(0, doc);  
  148.                 this.loadConfigProperties(doc);  
  149.             }  
  150.         }  
  151.     }  
  152.   
  153.     private void loadConfigProperties(Document doc)  
  154.     {  
  155.         try  
  156.         {  
  157.             XPath xpath = WWXML.makeXPath();  
  158.   
  159.             NodeList nodes = (NodeList) xpath.evaluate("/WorldWindConfiguration/Property", doc, XPathConstants.NODESET);  
  160.             if (nodes == null || nodes.getLength() == 0)  
  161.                 return;  
  162.   
  163.             for (int i = 0; i < nodes.getLength(); i++)  
  164.             {  
  165.                 Node node = nodes.item(i);  
  166.                 String prop = xpath.evaluate("@name", node);  
  167.                 String value = xpath.evaluate("@value", node);  
  168.                 if (WWUtil.isEmpty(prop))// || WWUtil.isEmpty(value))  
  169.                     continue;  
  170.   
  171.                 this.properties.setProperty(prop, value);  
  172.             }  
  173.         }  
  174.         catch (XPathExpressionException e)  
  175.         {  
  176.             Logging.logger(DEFAULT_LOGGER_NAME).log(Level.WARNING, "XML.ParserConfigurationException");  
  177.         }  
  178.     }  
  179.   
  180.     private Properties initializeDefaults()  
  181.     {  
  182.         Properties defaults = new Properties();  
  183.         java.util.TimeZone tz = java.util.Calendar.getInstance().getTimeZone();  
  184.         if (tz != null)  
  185.             defaults.setProperty(AVKey.INITIAL_LONGITUDE,  
  186.                 Double.toString(  
  187.                     Angle.fromDegrees(180.0 * tz.getOffset(System.currentTimeMillis()) / (12.0 * 3.6e6)).degrees));  
  188.         return defaults;  
  189.     }  
  190.   
  191.     private void initializeCustom()  
  192.     {  
  193.         // IMPORTANT NOTE: Always use the single argument version of Logging.logger in this method because the non-arg  
  194.         // method assumes an instance of Configuration already exists.  
  195.   
  196.         String configFileName = System.getProperty(CONFIG_FILE_PROPERTY_KEY, CONFIG_PROPERTIES_FILE_NAME);  
  197.         try  
  198.         {  
  199.             java.io.InputStream propsStream = null;  
  200.             File file = new File(configFileName);  
  201.             if (file.exists())  
  202.             {  
  203.                 try  
  204.                 {  
  205.                     propsStream = new FileInputStream(file);  
  206.                 }  
  207.                 catch (FileNotFoundException e)  
  208.                 {  
  209.                     Logging.logger(DEFAULT_LOGGER_NAME).log(Level.FINEST, "Configuration.LocalConfigFileNotFound",  
  210.                         configFileName);  
  211.                 }  
  212.             }  
  213.   
  214.             if (propsStream == null)  
  215.             {  
  216.                 propsStream = this.getClass().getResourceAsStream("/" + configFileName);  
  217.             }  
  218.   
  219.             if (propsStream != null)  
  220.                 this.properties.load(propsStream);  
  221.         }  
  222.         // Use a named logger in all the catch statements below to prevent Logger from calling back into  
  223.         // Configuration when this Configuration instance is not yet fully instantiated.  
  224.         catch (IOException e)  
  225.         {  
  226.             Logging.logger(DEFAULT_LOGGER_NAME).log(Level.SEVERE, "Configuration.ExceptionReadingPropsFile", e);  
  227.         }  
  228.     }  
  229.   
  230.     public static void insertConfigurationDocument(String fileName)  
  231.     {  
  232.         getInstance().insertConfigDoc(fileName);  
  233.     }  
  234.   
  235.     /** 
  236.      * Return as a string the value associated with a specified key. 
  237.      * 
  238.      * @param key          the key for the desired value. 
  239.      * @param defaultValue the value to return if the key does not exist. 
  240.      * 
  241.      * @return the value associated with the key, or the specified default value if the key does not exist. 
  242.      */  
  243.     public static synchronized String getStringValue(String key, String defaultValue)  
  244.     {  
  245.         String v = getStringValue(key);  
  246.         return v != null ? v : defaultValue;  
  247.     }  
  248.   
  249.     /** 
  250.      * Return as a string the value associated with a specified key. 
  251.      * 
  252.      * @param key the key for the desired value. 
  253.      * 
  254.      * @return the value associated with the key, or null if the key does not exist. 
  255.      */  
  256.     public static synchronized String getStringValue(String key)  
  257.     {  
  258.         Object o = getInstance().properties.getProperty(key);  
  259.         return o != null ? o.toString() : null;  
  260.     }  
  261.   
  262.     /** 
  263.      * Return as an Integer the value associated with a specified key. 
  264.      * 
  265.      * @param key          the key for the desired value. 
  266.      * @param defaultValue the value to return if the key does not exist. 
  267.      * 
  268.      * @return the value associated with the key, or the specified default value if the key does not exist or is not an 
  269.      *         Integer or string representation of an Integer. 
  270.      */  
  271.     public static synchronized Integer getIntegerValue(String key, Integer defaultValue)  
  272.     {  
  273.         Integer v = getIntegerValue(key);  
  274.         return v != null ? v : defaultValue;  
  275.     }  
  276.   
  277.     /** 
  278.      * Return as an Integer the value associated with a specified key. 
  279.      * 
  280.      * @param key the key for the desired value. 
  281.      * 
  282.      * @return the value associated with the key, or null if the key does not exist or is not an Integer or string 
  283.      *         representation of an Integer. 
  284.      */  
  285.     public static synchronized Integer getIntegerValue(String key)  
  286.     {  
  287.         String v = getStringValue(key);  
  288.         if (v == null)  
  289.             return null;  
  290.   
  291.         try  
  292.         {  
  293.             return Integer.parseInt(v);  
  294.         }  
  295.         catch (NumberFormatException e)  
  296.         {  
  297.             Logging.logger().log(Level.SEVERE, "Configuration.ConversionError", v);  
  298.             return null;  
  299.         }  
  300.     }  
  301.   
  302.     /** 
  303.      * Return as an Long the value associated with a specified key. 
  304.      * 
  305.      * @param key          the key for the desired value. 
  306.      * @param defaultValue the value to return if the key does not exist. 
  307.      * 
  308.      * @return the value associated with the key, or the specified default value if the key does not exist or is not a 
  309.      *         Long or string representation of a Long. 
  310.      */  
  311.     public static synchronized Long getLongValue(String key, Long defaultValue)  
  312.     {  
  313.         Long v = getLongValue(key);  
  314.         return v != null ? v : defaultValue;  
  315.     }  
  316.   
  317.     /** 
  318.      * Return as an Long the value associated with a specified key. 
  319.      * 
  320.      * @param key the key for the desired value. 
  321.      * 
  322.      * @return the value associated with the key, or null if the key does not exist or is not a Long or string 
  323.      *         representation of a Long. 
  324.      */  
  325.     public static synchronized Long getLongValue(String key)  
  326.     {  
  327.         String v = getStringValue(key);  
  328.         if (v == null)  
  329.             return null;  
  330.   
  331.         try  
  332.         {  
  333.             return Long.parseLong(v);  
  334.         }  
  335.         catch (NumberFormatException e)  
  336.         {  
  337.             Logging.logger().log(Level.SEVERE, "Configuration.ConversionError", v);  
  338.             return null;  
  339.         }  
  340.     }  
  341.   
  342.     /** 
  343.      * Return as an Double the value associated with a specified key. 
  344.      * 
  345.      * @param key          the key for the desired value. 
  346.      * @param defaultValue the value to return if the key does not exist. 
  347.      * 
  348.      * @return the value associated with the key, or the specified default value if the key does not exist or is not an 
  349.      *         Double or string representation of an Double. 
  350.      */  
  351.     public static synchronized Double getDoubleValue(String key, Double defaultValue)  
  352.     {  
  353.         Double v = getDoubleValue(key);  
  354.         return v != null ? v : defaultValue;  
  355.     }  
  356.   
  357.     /** 
  358.      * Return as an Double the value associated with a specified key. 
  359.      * 
  360.      * @param key the key for the desired value. 
  361.      * 
  362.      * @return the value associated with the key, or null if the key does not exist or is not an Double or string 
  363.      *         representation of an Double. 
  364.      */  
  365.     public static synchronized Double getDoubleValue(String key)  
  366.     {  
  367.         String v = getStringValue(key);  
  368.         if (v == null)  
  369.             return null;  
  370.   
  371.         try  
  372.         {  
  373.             return Double.parseDouble(v);  
  374.         }  
  375.         catch (NumberFormatException e)  
  376.         {  
  377.             Logging.logger().log(Level.SEVERE, "Configuration.ConversionError", v);  
  378.             return null;  
  379.         }  
  380.     }  
  381.   
  382.     /** 
  383.      * Return as a Boolean the value associated with a specified key. 
  384.      * <p/> 
  385.      * Valid values for true are '1' or anything that starts with 't' or 'T'. ie. 'true', 'True', 't' Valid values for 
  386.      * false are '0' or anything that starts with 'f' or 'F'. ie. 'false', 'False', 'f' 
  387.      * 
  388.      * @param key          the key for the desired value. 
  389.      * @param defaultValue the value to return if the key does not exist. 
  390.      * 
  391.      * @return the value associated with the key, or the specified default value if the key does not exist or is not a 
  392.      *         Boolean or string representation of an Boolean. 
  393.      */  
  394.     public static synchronized Boolean getBooleanValue(String key, Boolean defaultValue)  
  395.     {  
  396.         Boolean v = getBooleanValue(key);  
  397.         return v != null ? v : defaultValue;  
  398.     }  
  399.   
  400.     /** 
  401.      * Return as a Boolean the value associated with a specified key. 
  402.      * <p/> 
  403.      * Valid values for true are '1' or anything that starts with 't' or 'T'. ie. 'true', 'True', 't' Valid values for 
  404.      * false are '0' or anything that starts with 'f' or 'F'. ie. 'false', 'False', 'f' 
  405.      * 
  406.      * @param key the key for the desired value. 
  407.      * 
  408.      * @return the value associated with the key, or null if the key does not exist or is not a Boolean or string 
  409.      *         representation of an Boolean. 
  410.      */  
  411.     public static synchronized Boolean getBooleanValue(String key)  
  412.     {  
  413.         String v = getStringValue(key);  
  414.         if (v == null)  
  415.             return null;  
  416.   
  417.         if (v.trim().toUpperCase().startsWith("T") || v.trim().equals("1"))  
  418.         {  
  419.             return true;  
  420.         }  
  421.         else if (v.trim().toUpperCase().startsWith("F") || v.trim().equals("0"))  
  422.         {  
  423.             return false;  
  424.         }  
  425.         else  
  426.         {  
  427.             Logging.logger().log(Level.SEVERE, "Configuration.ConversionError", v);  
  428.             return null;  
  429.         }  
  430.     }  
  431.   
  432.     /** 
  433.      * Determines whether a key exists in the configuration. 
  434.      * 
  435.      * @param key the key of interest. 
  436.      * 
  437.      * @return true if the key exists, otherwise false. 
  438.      */  
  439.     public static synchronized boolean hasKey(String key)  
  440.     {  
  441.         return getInstance().properties.contains(key);  
  442.     }  
  443.   
  444.     /** 
  445.      * Removes a key and its value from the configuration if the configuration contains the key. 
  446.      * 
  447.      * @param key the key of interest. 
  448.      */  
  449.     public static synchronized void removeKey(String key)  
  450.     {  
  451.         getInstance().properties.remove(key);  
  452.     }  
  453.   
  454.     /** 
  455.      * Adds a key and value to the configuration, or changes the value associated with the key if the key is already in 
  456.      * the configuration. 
  457.      * 
  458.      * @param key   the key to set. 
  459.      * @param value the value to associate with the key. 
  460.      */  
  461.     public static synchronized void setValue(String key, Object value)  
  462.     {  
  463.         getInstance().properties.put(key, value.toString());  
  464.     }  
  465.   
  466.     // OS, user, and run-time specific system properties. //  
  467.   
  468.     /** 
  469.      * Returns the path to the application's current working directory. 
  470.      * 
  471.      * @return the absolute path to the application's current working directory. 
  472.      */  
  473.     public static String getCurrentWorkingDirectory()  
  474.     {  
  475.         String dir = System.getProperty("user.dir");  
  476.         return (dir != null) ? dir : ".";  
  477.     }  
  478.   
  479.     /** 
  480.      * Returns the path to the application user's home directory. 
  481.      * 
  482.      * @return the absolute path to the application user's home directory. 
  483.      */  
  484.     public static String getUserHomeDirectory()  
  485.     {  
  486.         String dir = System.getProperty("user.home");  
  487.         return (dir != null) ? dir : ".";  
  488.     }  
  489.   
  490.     /** 
  491.      * Returns the path to the operating system's temp directory. 
  492.      * 
  493.      * @return the absolute path to the operating system's temporary directory. 
  494.      */  
  495.     public static String getSystemTempDirectory()  
  496.     {  
  497.         String dir = System.getProperty("java.io.tmpdir");  
  498.         return (dir != null) ? dir : ".";  
  499.     }  
  500.   
  501.     /** 
  502.      * Returns the path to the current user's application data directory. The path returned depends on the operating 
  503.      * system on which the Java Virtual Machine is running. The following table provides the path for all supported 
  504.      * operating systems: 
  505.      * <p/> 
  506.      * <table> <tr><th>Operating System</th><th>Path</th></tr> <tr><td>Mac OS X</td><td>~/Library/Application 
  507.      * Support</td></tr> <tr><td>Windows</td><td>~\\Application Data</td></tr> <tr><td>Linux, Unix, 
  508.      * Solaris</td><td>~/</td></tr> </table> 
  509.      * 
  510.      * @return the absolute path to the current user's application data directory. 
  511.      */  
  512.     public static String getCurrentUserAppDataDirectory()  
  513.     {  
  514.         if (isMacOS())  
  515.         {  
  516.             // Return a path that Mac OS X has designated for app-specific data and support files. See the following URL  
  517.             // for details:  
  518.             // http://developer.apple.com/library/mac/#documentation/FileManagement/Conceptual/FileSystemProgrammingGUide/MacOSXDirectories/MacOSXDirectories.html#//apple_ref/doc/uid/TP40010672-CH10-SW1  
  519.             return getUserHomeDirectory() + "/Library/Application Support";  
  520.         }  
  521.         else if (isWindowsOS())  
  522.         {  
  523.             return getUserHomeDirectory() + "\\Application Data";  
  524.         }  
  525.         else if (isLinuxOS() || isUnixOS() || isSolarisOS())  
  526.         {  
  527.             return getUserHomeDirectory();  
  528.         }  
  529.         else  
  530.         {  
  531.             String msg = Logging.getMessage("generic.UnknownOperatingSystem");  
  532.             Logging.logger().fine(msg);  
  533.             return null;  
  534.         }  
  535.     }  
  536.   
  537.     /** 
  538.      * Determines whether the operating system is a Mac operating system. 
  539.      * 
  540.      * @return true if the operating system is a Mac operating system, otherwise false. 
  541.      */  
  542.     public static boolean isMacOS()  
  543.     {  
  544.         String osName = System.getProperty("os.name");  
  545.         return osName != null && osName.toLowerCase().contains("mac");  
  546.     }  
  547.   
  548.     /** 
  549.      * Determines whether the operating system is Windows operating system. 
  550.      * 
  551.      * @return true if the operating system is a Windows operating system, otherwise false. 
  552.      */  
  553.     public static boolean isWindowsOS()  
  554.     {  
  555.         String osName = System.getProperty("os.name");  
  556.         return osName != null && osName.toLowerCase().contains("windows");  
  557.     }  
  558.   
  559.     /** 
  560.      * Determines whether the operating system is Windows XP operating system. 
  561.      * 
  562.      * @return true if the operating system is a Windows XP operating system, otherwise false. 
  563.      */  
  564.     public static boolean isWindowsXPOS()  
  565.     {  
  566.         String osName = System.getProperty("os.name");  
  567.         return osName != null && osName.toLowerCase().contains("windows") && osName.contains("xp");  
  568.     }  
  569.   
  570.     /** 
  571.      * Determines whether the operating system is Windows Vista operating system. 
  572.      * 
  573.      * @return true if the operating system is a Windows Vista operating system, otherwise false. 
  574.      */  
  575.     public static boolean isWindowsVistaOS()  
  576.     {  
  577.         String osName = System.getProperty("os.name");  
  578.         return osName != null && osName.toLowerCase().contains("windows") && osName.contains("vista");  
  579.     }  
  580.   
  581.     /** 
  582.      * Determines whether the operating system is Windows 7 operating system. 
  583.      * 
  584.      * @return true if the operating system is a Windows Vista operating system, otherwise false. 
  585.      */  
  586.     public static boolean isWindows7OS()  
  587.     {  
  588.         String osName = System.getProperty("os.name");  
  589.         return osName != null && osName.toLowerCase().contains("windows") && osName.contains("7");  
  590.     }  
  591.   
  592.     /** 
  593.      * Determines whether the operating system is Linux operating system. 
  594.      * 
  595.      * @return true if the operating system is a Linux operating system, otherwise false. 
  596.      */  
  597.     public static boolean isLinuxOS()  
  598.     {  
  599.         String osName = System.getProperty("os.name");  
  600.         return osName != null && osName.toLowerCase().contains("linux");  
  601.     }  
  602.   
  603.     /** 
  604.      * Determines whether the operating system is Unix operating system. 
  605.      * 
  606.      * @return true if the operating system is a Unix operating system, otherwise false. 
  607.      */  
  608.     public static boolean isUnixOS()  
  609.     {  
  610.         String osName = System.getProperty("os.name");  
  611.         return osName != null && osName.toLowerCase().contains("unix");  
  612.     }  
  613.   
  614.     /** 
  615.      * Determines whether the operating system is Solaris operating system. 
  616.      * 
  617.      * @return true if the operating system is a Solaris operating system, otherwise false. 
  618.      */  
  619.     public static boolean isSolarisOS()  
  620.     {  
  621.         String osName = System.getProperty("os.name");  
  622.         return osName != null && osName.toLowerCase().contains("solaris");  
  623.     }  
  624.   
  625.     /** 
  626.      * Returns the version of the Java virtual machine. 
  627.      * 
  628.      * @return the Java virtual machine version. 
  629.      */  
  630.     public static float getJavaVersion()  
  631.     {  
  632.         float ver = 0f;  
  633.         String s = System.getProperty("java.specification.version");  
  634.         if (null == s || s.length() == 0)  
  635.             s = System.getProperty("java.version");  
  636.         try  
  637.         {  
  638.             ver = Float.parseFloat(s.trim());  
  639.         }  
  640.         catch (NumberFormatException ignore)  
  641.         {  
  642.         }  
  643.         return ver;  
  644.     }  
  645.   
  646.     /** 
  647.      * Returns the highest OpenGL profile available on the current graphics device that is compatible with World Wind. 
  648.      * The returned profile favors hardware acceleration over software acceleration. With JOGL version 2.0-rc11, this 
  649.      * returns the highest available profile from the following list: 
  650.      * <p/> 
  651.      * <ul> <li>OpenGL compatibility profile 4.x</li> <li>OpenGL compatibility profile 3.x</li> <li>OpenGL profile 1.x 
  652.      * up to 3.0</li> </ul> 
  653.      * 
  654.      * @return the highest compatible OpenGL profile. 
  655.      */  
  656.     public static GLProfile getMaxCompatibleGLProfile()  
  657.     {  
  658.         return GLProfile.getMaxFixedFunc(true); // Favor a hardware rasterizer.  
  659.     }  
  660.   
  661.     /** 
  662.      * Returns a specified element of an XML configuration document. 
  663.      * 
  664.      * @param xpathExpression an XPath expression identifying the element of interest. 
  665.      * 
  666.      * @return the element of interest if the XPath expression is valid and the element exists, otherwise null. 
  667.      * 
  668.      * @throws NullPointerException if the XPath expression is null. 
  669.      */  
  670.     public static Element getElement(String xpathExpression)  
  671.     {  
  672.         XPath xpath = WWXML.makeXPath();  
  673.   
  674.         for (Document doc : getInstance().configDocs)  
  675.         {  
  676.             try  
  677.             {  
  678.                 Node node = (Node) xpath.evaluate(xpathExpression, doc.getDocumentElement(), XPathConstants.NODE);  
  679.                 if (node != null)  
  680.                     return (Element) node;  
  681.             }  
  682.             catch (XPathExpressionException e)  
  683.             {  
  684.                 return null;  
  685.             }  
  686.         }  
  687.   
  688.         return null;  
  689.     }  
  690. }  
很轻松的在前几行就可以看到,这是单列的,整个程序就此一家,别无他处,所有的方法几乎都是static声明的,外部可以直接调用。
[java] view plaincopy
  1. private static Configuration getInstance()  
  2. {  
  3.     return ourInstance;  
  4. }  

其所返回的ourInstance在这个方法的上面声明的,也是static的,并且调用了私有的构造参数初始化。

构造函数中首先就是先给Properties初始化,这个对象是util包中的,用于存储一些属性变量。

[java] view plaincopy
  1. private Properties initializeDefaults()  
  2.     {  
  3.         Properties defaults = new Properties();  
  4.         java.util.TimeZone tz = java.util.Calendar.getInstance().getTimeZone();  
  5.         if (tz != null)  
  6.             defaults.setProperty(AVKey.INITIAL_LONGITUDE,  
  7.                 Double.toString(  
  8.                     Angle.fromDegrees(180.0 * tz.getOffset(System.currentTimeMillis()) / (12.0 * 3.6e6)).degrees));  
  9.         return defaults;  
  10.     }  

这段代码,给defaults增加了一个开始的经纬度,这个经纬度,是根据当前程序所运行的国家的时区以及当前时间,以及180分成12个时区,每个时区所分的时间等信息计算得到的,我的结果是120°。

之后它在try中开始载入配置文件:

String appConfigLocation = System.getProperty(CONFIG_APP_DOCUMENT_KEY);
            if (appConfigLocation != null)
                this.loadConfigDoc(System.getProperty(CONFIG_APP_DOCUMENT_KEY));

appConfiguration的结果是null,所以不执行哈。

再然后有一个 this.loadConfigDoc(System.getProperty(CONFIG_WW_DOCUMENT_KEY, CONFIG_WW_DOCUMENT_NAME));

追一下System的源代码,里面还有一层,最终找到这样的代码

public String getProperty(String key, String defaultValue) {
        String val = getProperty(key);
        return (val == null) ? defaultValue : val;
    }

loadConfigDoc这个方法,是读取xml文件的,这个里面深入下,可以看到有趣的东西,就是

[java] view plaincopy
  1. public static Document openDocument(Object docSource)  
  2.     {  
  3.         if (docSource == null || WWUtil.isEmpty(docSource))  
  4.         {  
  5.             String message = Logging.getMessage("nullValue.DocumentSourceIsNull");  
  6.             throw new IllegalArgumentException(message);  
  7.         }  
  8.   
  9.         if (docSource instanceof URL)  
  10.         {  
  11.             return openDocumentURL((URL) docSource);  
  12.         }  
  13.         else if (docSource instanceof InputStream)  
  14.         {  
  15.             return openDocumentStream((InputStream) docSource);  
  16.         }  
  17.         else if (docSource instanceof File)  
  18.         {  
  19.             return openDocumentFile(((File) docSource).getPath(), null);  
  20.         }  
  21.         else if (!(docSource instanceof String))  
  22.         {  
  23.             String message = Logging.getMessage("generic.UnrecognizedSourceType", docSource.toString());  
  24.             throw new IllegalArgumentException(message);  
  25.         }  
  26.   
  27.         String sourceName = (String) docSource;  
  28.   
  29.         URL url = WWIO.makeURL(sourceName);  
  30.         if (url != null)  
  31.             return openDocumentURL(url);  
  32.   
  33.         return openDocumentFile(sourceName, null);  
  34.     }  

比较牛的代码啊,是吧?!类似于工厂模式,按照传过来的不同的对象,用不同的方式去打开,都返回Document的实例,而且通过最后一句if判断是不是String,如果是String,就用URL的方式打开。读取XML文件是个老生长谈的问题,这里他用的JAXP读取的,不过百度说:由于问题太多,从JDK1.7开始删除该功能。

之后呢,要把刚读到的Document对象用loadConfigProperties方法,把里面的内容放入property对象中,就实现了系统的初始化。

注意,构造函数中最后一句的this.initializeCustom();没有啥意思了,是老版本中读取配置文件的,也可以用来自定义一些内容。

0 0
原创粉丝点击