001    package org.hackystat.projectbrowser;
002    
003    import java.io.FileInputStream;
004    import java.io.IOException;
005    import java.util.Map;
006    import java.util.Properties;
007    
008    /**
009     * Provides access to the values stored in the sensorbase.properties file. 
010     * @author Philip Johnson
011     */
012    public class ProjectBrowserProperties {
013      
014      /** The sensorbase host.  */
015      public static final String SENSORBASE_HOST_KEY =  "projectbrowser.sensorbase.host";
016      /** The dpd host.  */
017      public static final String DAILYPROJECTDATA_HOST_KEY =  "projectbrowser.dailyprojectdata.host";
018      /** The telemetry host.  */
019      public static final String TELEMETRY_HOST_KEY =  "projectbrowser.telemetry.host";
020      /** The logging level.  */
021      public static final String LOGGING_LEVEL_KEY =  "projectbrowser.logging.level";
022      /** The admin email key. */
023      public static final String ADMIN_EMAIL_KEY =  "projectbrowser.admin.email";
024      /** How to control wicket development vs. deployment mode. */
025      public static final String WICKET_CONFIGURATION_KEY =  "projectbrowser.wicket.configuration";
026      /** Application logo URL. */
027      public static final String APPLICATION_LOGO_KEY =  "projectbrowser.application.logo";
028      /** Optional name. */
029      public static final String APPLICATION_NAME_KEY =  "projectbrowser.application.name";
030      /** Optional items per page. */
031      public static final String SENSORDATA_ITEMSPERPAGE_KEY = "projectbrowser.sensordata.itemsperpage";
032      /** Optional max height of text area in Projects Page. */
033      public static final String PROJECTS_TEXTMAXHEIGHT_KEY = "projectbrowser.projects.maxtextheight";
034      /** Key for tabs of pages. */
035      public static final String AVAILABLEPAGE_KEY = "projectbrowser.availablepage";
036      /** If background process enable for pages. */
037      public static final String BACKGROUND_PROCESS_KEY = "projectbrowser.backgroundprocess.enable";
038      /** Directory of portfolio definitions. */
039      public static final String PORTFOLIO_DEFINITION_DIR = "projectbrowser.portfolio.definitions.dir";
040      /** Directory of portfolio definitions. */
041      public static final String LOG_USAGE_KEY = "projectbrowser.usagelogging";
042      /** Available pages. */
043      public static final String[] PAGE_NAMES = {"projects", "dailyprojectdata", 
044                                                 "telemetry", "trajectory", "projectportfolio", "crap"};
045      /** The default number of items per page. */
046      private int defaultItemsPerPage = 50;
047      /** The default port as an int. */
048      private int defaultPort = 9879;
049      /** The default text max height in the projects page.  */
050      private int defaultTextMaxHeight = 5;
051      
052      // Not sure yet if we need the following.
053      /** The projectbrowser hostname key. */
054      public static final String HOSTNAME_KEY = "projectbrowser.hostname";
055      /** The projectbrowser context root. */
056      public static final String CONTEXT_ROOT_KEY = "projectbrowser.context.root";
057      /** The projectbrowser port key. */
058      public static final String PORT_KEY = "projectbrowser.port";
059      /** The SMTP host key. */
060      //public static final String SMTP_HOST_KEY =  "projectbrowser.smtp.host";
061      /** The test install host key. */
062      //public static final String TEST_INSTALL_KEY =  "projectbrowser.test.install";
063      /** True as a string.*/
064      private static final String TRUE = "true";
065      /** False as a string.*/
066      private static final String FALSE = "false";
067      
068      
069      /** Where we store the properties. */
070      private Properties properties; 
071      
072      /**
073       * Creates a new ProjectBrowserProperties instance. 
074       * Prints an error to the console if problems occur on loading.
075       * @param properties A properties instance containing values that override those in the 
076       * properties file. Can be null if no properties are to be overridden.  
077       */
078      public ProjectBrowserProperties(Properties properties) {
079        try {
080          initializeProperties(properties);
081        }
082        catch (Exception e) {
083          System.out.println("Error initializing projectbrowser properties.");
084        }
085      }
086      
087      /**
088       * The default public constructor, which gets all properties from projectbrowser.properties. 
089       */
090      public ProjectBrowserProperties() {
091        this(null);
092      }
093     
094    
095      /**
096       * Reads in the properties in ~/.hackystat/projectbrowser/projectbrowser.properties
097       * if this file exists, 
098       * and provides default values for all properties not mentioned in this file.
099       * @param testProperties A properties instance containing values that override those in the 
100       * @throws Exception if errors occur.
101       */
102      private void initializeProperties (Properties testProperties) throws Exception {
103        String userHome = System.getProperty("user.home");
104        String propFile = userHome + "/.hackystat/projectbrowser/projectbrowser.properties";
105        this.properties = new Properties();
106        // Set defaults.
107        properties.setProperty(SENSORBASE_HOST_KEY, "http://localhost:9876/sensorbase");
108        properties.setProperty(DAILYPROJECTDATA_HOST_KEY, "http://localhost:9877/dailyprojectdata");
109        properties.setProperty(TELEMETRY_HOST_KEY, "http://localhost:9878/telemetry");
110        properties.setProperty(LOGGING_LEVEL_KEY, "INFO");
111        properties.setProperty(HOSTNAME_KEY, "localhost");
112        properties.setProperty(CONTEXT_ROOT_KEY, "projectbrowser");
113        properties.setProperty(PORT_KEY, String.valueOf(defaultPort));
114        properties.setProperty(ADMIN_EMAIL_KEY, "johnson@hackystat.org");
115        properties.setProperty(APPLICATION_LOGO_KEY, 
116            "http://xenia.ics.hawaii.edu/hackyDevSite/images/hackystat.gif");
117        properties.setProperty(WICKET_CONFIGURATION_KEY, "deployment");
118        properties.setProperty(APPLICATION_NAME_KEY, "Hackystat ProjectBrowser");
119        properties.setProperty(SENSORDATA_ITEMSPERPAGE_KEY, String.valueOf(defaultItemsPerPage));
120        properties.setProperty(PROJECTS_TEXTMAXHEIGHT_KEY, String.valueOf(defaultTextMaxHeight));
121        properties.setProperty(AVAILABLEPAGE_KEY + ".sensordata", TRUE);
122        properties.setProperty(AVAILABLEPAGE_KEY + ".dailyprojectdata", TRUE);
123        properties.setProperty(AVAILABLEPAGE_KEY + ".telemetry", TRUE);
124        properties.setProperty(AVAILABLEPAGE_KEY + ".trajectory", FALSE);
125        properties.setProperty(AVAILABLEPAGE_KEY + ".projects", TRUE);
126        properties.setProperty(AVAILABLEPAGE_KEY + ".projectportfolio", TRUE);
127        properties.setProperty(BACKGROUND_PROCESS_KEY + ".telemetry", TRUE);
128        properties.setProperty(BACKGROUND_PROCESS_KEY + ".trajectory", TRUE);
129        properties.setProperty(BACKGROUND_PROCESS_KEY + ".projectportfolio", TRUE);
130        properties.setProperty(BACKGROUND_PROCESS_KEY + ".todate", TRUE);
131        properties.setProperty(PORTFOLIO_DEFINITION_DIR, userHome + "/.hackystat/projectbrowser/");
132        properties.setProperty(LOG_USAGE_KEY, "false");
133    
134        // Now read in the properties file, and override the defaults if supplied. 
135        FileInputStream stream = null;
136        try {
137          stream = new FileInputStream(propFile);
138          properties.load(stream);
139          System.out.println("Loading ProjectBrowser properties from: " + propFile);
140        }
141        catch (IOException e) {
142          System.out.println(propFile + " not found. Using default properties.");
143        }
144        finally {
145          if (stream != null) {
146            stream.close();
147          }
148        }
149        // If we have supplied some properties as an argument, use these to override whatever we've 
150        // done so far. 
151        if (testProperties != null) {
152          this.properties.putAll(testProperties);
153        }
154        trimProperties(properties);
155        String wicketConfig = properties.getProperty(WICKET_CONFIGURATION_KEY);
156        if (wicketConfig != null) {
157          System.setProperty("wicket.configuration", wicketConfig);
158        }
159        
160        // I don't think we need to do the following for ProjectBrowser, since we aren't using Mailer. 
161        // Now add to System properties. Since the Mailer class expects to find this stuff on the 
162        // System Properties, we will add everything to it.  In general, however, clients should not
163        // use the System Properties to get at these values, since that precludes running several
164        // SensorBases in a single JVM.   And just is generally bogus. 
165        //Properties systemProperties = System.getProperties();
166        //systemProperties.putAll(properties);
167        //System.setProperties(systemProperties);
168      }
169      
170      /**
171       * Returns a string containing the current properties.
172       * @return A string with the properties.  
173       */
174      public String echoProperties() {
175        String cr = System.getProperty("line.separator"); 
176        String eq = " = ";
177        String pad = "                ";
178        return "ProjectBrowser Properties:" + cr +
179          pad + SENSORBASE_HOST_KEY      + eq + get(SENSORBASE_HOST_KEY) + cr +
180          pad + DAILYPROJECTDATA_HOST_KEY  + eq + get(DAILYPROJECTDATA_HOST_KEY) + cr +
181          pad + TELEMETRY_HOST_KEY          + eq + get(TELEMETRY_HOST_KEY) + cr +
182          pad + LOGGING_LEVEL_KEY   + eq + get(LOGGING_LEVEL_KEY) + cr +
183          pad + WICKET_CONFIGURATION_KEY   + eq + get(WICKET_CONFIGURATION_KEY) + cr +
184          pad + APPLICATION_LOGO_KEY   + eq + get(APPLICATION_LOGO_KEY) + cr +
185          pad + APPLICATION_NAME_KEY   + eq + get(APPLICATION_NAME_KEY) + cr +
186          pad + HOSTNAME_KEY   + eq + get(HOSTNAME_KEY) + cr +
187          pad + CONTEXT_ROOT_KEY   + eq + get(CONTEXT_ROOT_KEY) + cr +
188          pad + PORT_KEY   + eq + get(PORT_KEY) + cr +
189          pad + SENSORDATA_ITEMSPERPAGE_KEY   + eq + get(SENSORDATA_ITEMSPERPAGE_KEY) + cr +
190          pad + PROJECTS_TEXTMAXHEIGHT_KEY + eq + get(PROJECTS_TEXTMAXHEIGHT_KEY) + cr +
191          pad + ADMIN_EMAIL_KEY   + eq + get(ADMIN_EMAIL_KEY);
192      }
193      
194      /**
195       * Returns the value of the ProjectBrowser Property specified by the key.
196       * @param key Should be one of the public static final strings in this class.
197       * @return The value of the key, or null if not found.
198       */
199      public String get(String key) {
200        return this.properties.getProperty(key);
201      }
202      
203      /**
204       * Ensures that the there is no leading or trailing whitespace in the property values.
205       * The fact that we need to do this indicates a bug in Java's Properties implementation to me. 
206       * @param properties The properties. 
207       */
208      private void trimProperties(Properties properties) {
209        // Have to do this iteration in a Java 5 compatible manner. no stringPropertyNames().
210        for (Map.Entry<Object, Object> entry : properties.entrySet()) {
211          String propName = (String)entry.getKey();
212          properties.setProperty(propName, properties.getProperty(propName).trim());
213        }
214      }
215      
216      /**
217       * Returns true if the user has supplied an application logo URL. 
218       * @return True if the application logo URL was supplied. 
219       */
220      public boolean hasApplicationLogo() {
221        return !"".equals(get(APPLICATION_LOGO_KEY));
222      }
223      
224      /**
225       * @param pageName name of the page.
226       * @return true if the user set the page as available.
227       */
228      public boolean isPageAvailable (String pageName) {
229        String pageKey = AVAILABLEPAGE_KEY + "." + pageName;
230        return TRUE.equals(get(pageKey));
231      }
232    
233      /**
234       * @param pageName name of the page.
235       * @return true if the user set the background process of the page enable.
236       */
237      public boolean isBackgroundProcessEnable (String pageName) {
238        String pageKey = BACKGROUND_PROCESS_KEY + "." + pageName;
239        return TRUE.equals(get(pageKey));
240      }
241      
242      /**
243       * @return true if the user set to enable usage logging
244       */
245      public boolean isLoggingUserUsage() {
246        return TRUE.equals(get(LOG_USAGE_KEY));
247      }
248      
249      /**
250       * Returns an integer indicating the number of SensorData instances to display per page.
251       * Defaults to the default number of items per page, currently 50.
252       * @return An int with the number of sensor data items per page. 
253       */
254      public int getSensorDataItemsPerPage() {
255        int itemsperpage = defaultItemsPerPage;
256        try {
257          itemsperpage = Integer.parseInt(get(SENSORDATA_ITEMSPERPAGE_KEY));
258        }
259        catch (Exception e) {
260          itemsperpage = defaultItemsPerPage;
261        }
262        return itemsperpage;
263      }
264      
265      /**
266       * Returns the port to be used for this application.
267       * Defaults to 8080. 
268       * @return The port as an integer. 
269       */
270      public int getPort() {
271        int port = defaultPort;
272        try {
273          port = Integer.parseInt(get(PORT_KEY));
274        }
275        catch (Exception e) {
276          port = defaultPort;
277        }
278        return port;
279      }
280      
281      /**
282       * Returns the context root for this application. Defaults to "projectbrowser".
283       * @return The context root. 
284       */
285      public String getContextRoot() {
286        return get(CONTEXT_ROOT_KEY);
287      }
288      
289      /**
290       * Returns the URL to this system as defined by the project properties. 
291       * @return The URL to this system. 
292       */
293      public String getHost() {
294        return "http://" + get(HOSTNAME_KEY) + ":" + getPort() + "/" + getContextRoot(); 
295      }
296    
297      /**
298       * Return the directroy of portfolio definition xmls.
299       * @return the file path.
300       */
301      public String getPortfolioDefinitionDir() {
302        return get(PORTFOLIO_DEFINITION_DIR);
303      }
304    }