001/* $Source: /cvsroot2/open/projects/WebARTS/ca/bc/webarts/tools/AutoUpdateApp.java,v $
002 *  $Revision: 1295 $  $Date: 2019-04-18 18:05:01 -0700 (Thu, 18 Apr 2019) $  $Locker:  $
003 *  Copyright 2001-2002 (C) WebARTS Design.   All rights reserved.
004 *
005 *  This program is free software; you can redistribute it and/or
006 *  modify it under the terms of the GNU General Public License
007 *  as published by the Free Software Foundation; either version 2
008 *  of the License, or any later version.
009 *
010 *  This program is distributed in the hope that it will be useful,
011 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
012 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
013 *  GNU General Public License for more details.
014 *
015 *  You should have received a copy of the GNU General Public License
016 *  along with this program; if not, write to the Free Software
017 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
018*/
019/*
020Here is the revision log
021------------------------
022$Log: AutoUpdateApp.java,v $
023Revision 1.4  2002/10/22 08:59:36  tgutwin
024Many JavaDoc Comments changes.
025Removed the StreamGobbler class... it now lives on its own in tools.
026small change to the exec call.
027
028Revision 1.3  2001/08/04 18:54:49  tgutwin
029
030Added the ability to read properties file from a file in the current dir.
031There are 3 places this app now looks for the prop file
0321) in the jar in the curr dir
0332) in the jar that is found in the classpath
0343) in the prop file in the curr dir.
035
036
037*/
038
039package ca.bc.webarts.tools;
040
041
042
043import java.io.BufferedReader;
044import java.io.File;
045import java.io.FileInputStream;
046import java.io.FileOutputStream;
047import java.io.FileNotFoundException;
048import java.io.IOException;
049import java.io.InputStream;
050import java.io.InputStreamReader;
051import java.io.ObjectOutputStream;
052import java.io.PrintStream;
053import java.lang.Runtime;
054import java.lang.Process;
055import java.lang.SecurityException;
056import java.lang.String;
057import java.util.jar.JarFile;
058import java.util.jar.JarEntry;
059import java.util.jar.JarInputStream;
060import java.net.HttpURLConnection;
061import java.net.MalformedURLException;
062import java.net.URL;
063import java.net.URLConnection;
064import java.util.Enumeration;
065import java.util.Properties;
066import java.util.StringTokenizer;
067import java.util.Vector;
068
069// not necessary but saves headaches later if classes move
070import ca.bc.webarts.tools.StreamGobbler;
071
072import ca.bc.webarts.widgets.Util;
073
074/**
075 * This is a self standing Java application that acts as a middleware
076 * application executor that lets you put this class and a properties file on a
077 * client and be able to execute anything you want and have it update the app
078 * automatically from a specified URL.
079 * A <A HREF="#runApp(java.util.Properties)">static method</A> is also
080 * available to access the functionality from within existing code.
081 * <P>It executes applications... both native or Java as
082 * specified in a Properties file that gets passed to it (via a filename on the
083 * commandline). All system output from the executed app is echoed to the
084 * System.out (both regular and error output).
085 * <P> Its main purpose is to provide a single entrypoint to
086 * execute applications that can be dynamically specified at runtime. This
087 * allows a single deployment of this class onto a client and then tell this
088 * class what to run and where to download an update from if needed.
089 * <p>If you want this class to have a the name of your app; just extend this
090 * class and name it what you want... like the JOggPlayeAutoUpdate.java file.
091 * <P><B><U>Features:</U></B><UL><LI>executes Java<SUP><SMALL>TM</SMALL></SUP>
092 * Class files
093 * <LI>executes Java<SUP><SMALL>TM</SMALL></SUP> Jar files
094 * <LI>executes native executable files
095 * <LI>automatically retrieves the required files at a specified URL
096 * <LI>automatically checks for newer updated files at a specified URL
097 * <LI>automatically downmloads/updates any required files
098 * <LI>can run as an application or from existing code via the
099 * <A HREF="#runApp(java.util.Properties)">static runApp method</A></UL>
100 * <P><B><U>Usage:</U></B><BR><code>java AutoUpdateApp</code> &lt;
101 * <code>propertiesFilename</code>&gt; OR<BR>
102 * <code>java -jar AutoUpdateApp.jar</code>
103 * &lt;<code>propertiesFilename</code>&gt;<P>
104 * The <B>properties file</B> describes the app to
105 * execute. It has both required and optional entries as follows:
106 * <UL>
107 * <LI><B>Required Entries</B></LI>
108 * <UL>
109 * <LI><I><U>appType</U></I> - a String specifying the type of app that will
110 * be executed
111 * <BR>(NATIVE_APP = native; JAVA_APP = java;
112*  APPLET_APP = applet; HTTPURL_APP = httpUrl)
113 * </LI>
114 * <LI><I><U>remoteAppURL</U></I> - a string specifying URL for the application
115 * to launch<BR>
116 * (for example: file://usr/bin/telnet.sh or file:/c:/winnt/wordpad.exe)
117 * </LI>
118 * </UL><BR>
119 * <LI><B>Optional Entries</B></LI>
120 * <UL><LI><I><U>remoteAppAutoDownload</U></I> - a string specifying
121 * the flag (boolean string value) that specifies if this app should query the
122 * download server (see property below) for updated app files.</LI>
123 * <LI><I><U>remoteAppDownloadURL</U></I> - a string specifying
124 * the URL of the download for the Remote Launch APP.  If the filename portion
125 * of this URL does not match the filename portion of the remoteAppURL this app
126 * will assume it is an archive file (ie Jar file) that will be downloaded and
127 * will save it as a separate file.  In addition, if the appType is JAVA_APP,
128 * this archive name will be added to the front of the classpath so the new
129 * files in the archive will be used first.</LI>
130 * <LI><I><U>remoteAppJvmParameters</U></I> - a string specifying any parameters
131 * that should go directly to the JVM when executing a Java App. For Example:
132 * -Xmx64m -Xms8m</LI>
133 * <LI><I><U>remoteAppJvmClasspath</U></I> - a string specifying any additional
134 * paths to add to the <I>front</I> of the classpath when executing a Java App.
135 * The path entries in this string <B>must</B> be delimited by ";" because a
136 * ":" might have to used in a DOS drive specification.</LI>
137 * </UL><BR>
138 * <LI><B>All extra entries</B> in the properties file will be passed directly
139 * to the application as commandline parameters.</LI>
140 * </UL><HR>
141 * <P>An Example Properties file might look like:<BR>
142 * <PRE>
143 * # NATIVE Remote Application Description property file
144 * appType=0
145 * remoteAppURL=file:/c:/progra~1/tn.bat
146 * #remoteAppURL=c:\\progra~1\\tn.bat
147 * remoteAppDownloadURL=
148 * remoteAppAutoDownload=false
149 * telnetHost=10.0.0.22 2020
150 * </PRE><P>
151 * OR<BR>
152 * <PRE>
153 * # Java Remote Application Description property file
154 * appType=1
155 * remoteAppURL=SimpleExample
156 * remoteAppDownloadURL=http://somesite.com/updates/MySimpleExample.jar
157 * remoteAppAutoDownload=false
158 * remoteAppJvmParameters=-Xmx64m
159 * extraParm=myParm1
160 * anotherExtraParm=myParm2
161 * </PRE>
162 * OR<BR>
163 * <PRE>
164 * # Java Remote Application Description property file
165 * appType=1
166 * remoteAppURL=TelnetApp.jar
167 * remoteAppDownloadURL=http://somesite.com/updates/TelnetApp.jar
168 * remoteAppAutoDownload=true
169 * remoteAppJvmClasspath=/usr/local/extraclasses.jar;/usr/moreextraclasses.jar
170 * telnetHost=10.0.0.22 2020
171 * </PRE>
172 *
173 * <p>Author: <a href="mailto:tgutwin@webarts.bc.ca">Tom Gutwin P.Eng.</a>
174 * <br>Copyright (C) 2002-2003 <a href="http://www.webarts.bc.ca">Web<i>ARTS</i>
175 * Design</a>, North Vancouver Canada. All Rights Reserved.</p>
176 * @author     <a href="mailto:tgutwin@webarts.bc.ca">Tom Gutwin P.Eng.</a>
177 **/
178public class AutoUpdateApp
179{
180  /** This var should be defined by an extending class (not required)**/
181   protected static String appName_ = "";
182
183  /** The default property filename to use. **/
184   protected static String appPropertyFilename_ = appName_ + ".prop";
185
186
187  /** this VM classpath **/
188  static final String CLASSPATH = System.getProperty("java.class.path");
189
190  /** Class Constant specifying that the app to run is a native application **/
191  static public final String NATIVE_APP = "native";
192
193  /** Class Constant specifying that the app to run is a Java application **/
194  static public final String JAVA_APP = "java";
195
196  /** Class Constant specifying that the app to run is a Java Applet **/
197  static public final String APPLET_APP = "applet";
198
199  /**
200   * Class Constant specifying that the app to run is a URL Locationto view
201   * using the native webbrowser.
202   **/
203  public static final String HTTPURL_APP = "httpUrl";
204
205  /**
206   * Remote Launch Property Key specifying the remote lauch app type.<P>This
207   * is a required property in the supplied properties file.
208   **/
209  public static final String RMT_APP_TYPE         = "appType";
210
211  /**
212   * Remote Launch Property Key specifying the remote lauch
213   * URL for the RemoteLaunchOperation.HTTPURL_APP app type.<P>This
214   * is a required property in the supplied properties file.
215   **/
216  public static final String RMT_APP_URL          = "remoteAppURL";
217
218  /**
219   * Remote Launch Property Key specifying the URL of the download for the
220   * Remote Launch APP.<P>This is an optional property in the supplied
221   * properties file.
222   **/
223  public static final String RMT_APP_DOWNLOADURL  = "remoteAppDownloadURL";
224
225  /**
226   * Remote Launch Property Key specifying the flag (boolean string value) that
227   * specifies if the RemoteLaunchOperation Operation should query the
228   * download server for updated app files.<P>This is an optional property in
229   * the supplied properties file. (default=true)
230   **/
231  public static final String RMT_APP_AUTODOWNLOAD = "remoteAppAutoDownload";
232
233  /**
234   * Remote Launch Property Key  specifying any parameters that should go to the
235   * JVM when executing a Java App.<P>This is an optional property in
236   * the supplied properties file. (default="")
237   **/
238  public static final String RMT_APP_JVM_PARAMETERS = "remoteAppJvmParameters";
239
240  /**
241   * Remote Launch Property Key specifying any parameters that should be added
242   * to the <B>FRONT</B> of the classpath when executing a Java App.<P>This is
243   * an optional property in the supplied properties file. (default="")<P>A
244   * StringTokenizer is used to parse this property value and usessemi colons or
245   * colons as delimiters. <B>Note</B> that spaces are NOT used as delimeters so
246   * they can be used in the paths.
247   **/
248  public static final String RMT_APP_JVM_CLASSPATH = "remoteAppJvmClasspath";
249
250  /**
251    *  A helper Vector that keeps a table of the Defined Properties.
252    **/
253  private static Vector definedPropertyKeys = new Vector();
254
255  /** A holder for the NA Clients System File Separator. **/
256  private static final String SYSTEM_FILE_SEPERATOR = File.separator;
257
258  /**
259   * A holder for the directory location to save downloaded apps.<P>
260   * Default = <code>./RemoteApps/</code> (or the DOS Equiv.
261   * <code>.\RemoteApps\</code>).
262   **/
263  private static final String DEFAULT_SAVE_LOCATION = "." +
264    SYSTEM_FILE_SEPERATOR + "RemoteApps" + SYSTEM_FILE_SEPERATOR;
265
266  /**
267   * Remote Launch Parm specifying the remote lauch app type (required).
268   **/
269  private static String appType_ = JAVA_APP;
270
271  /**
272   * Remote Launch Parm specifying the remote lauched application in the form of
273   * a URL.<P>It gets assigned from the required property RMT_APP_URL in the
274   * supplied properties file.
275   **/
276  private static URL remoteAppURL_ = null;
277
278  /** The system dependant file path to execute. **/
279  private static String filePath_ = "";
280
281  /** The system dependant file path for the downloaded archive file.**/
282  private static String archiveFilePath_ = "";
283
284  /**
285   * Remote Launch Parm specifying the URL of the download for the Remote Launch
286   * APP.
287   **/
288  private static URL remoteAppDownloadURL_ = null;
289
290  /**
291   * Remote Launch Parm specifying the flag (boolean string val) that specifies
292   * if the RemoteLaunchOperation Operation should query the
293   * download server for updated app files.<P>(default=true)
294   **/
295  private static boolean remoteAppAutoDownload_ = true;
296
297  /**
298   * Remote Launch Parm specifying the any extra commandline parms to send
299   * directly to the jvm.<P>(default="")
300   **/
301  private static String jvmParameters_ = "";
302
303  /**
304   * Remote Launch Parm specifying the any extra classpath parms to put at the
305   * front of the classpath when the calling the jvm.<P>(default="")<P>A
306   * StringTokenizer is used to parse this property value. So commas or a space
307   * delimited list of entries will work.
308   **/
309  private static String jvmClasspath_ = "";
310
311  /**
312   * A class var to track the progress of the various validation checks that
313   * are performed.
314   **/
315  private static boolean soFarSoGood_ = true;
316
317  /**
318   * A class var to indicate if the download URL is pointing to an archive file
319   * (ie jar file) instead of the actual executable file.<p>This field gets
320   * used by the updateAppFromServer method to determine where to save the file.
321   * </p>
322   *
323   * @see #updateAppFromServer
324   **/
325  private static boolean archiveDownload_ = false;
326
327  /**
328   * A class var to record and error message to print out if any of the
329   * validation checks on the properties fail.
330   **/
331  private static String errorMsg_ = "";
332
333  /**
334   * A table of strings holding any extra parameter properties that were passed
335   * in the properties file. Extra means anything that do not match any of the
336   * Keys specified above.
337   **/
338   private static Vector cmdLineParms_ = new Vector();
339
340
341   /**
342   * Basic constructor for the application.  It is empty. The entry for this
343   * app is the <A HREF="#main(java.lang.String[])">main( String[] )</A> or
344   * <A HREF="#runApp(java.util.Properties)">runApp(Properties)</A>methods.
345   *
346   * @see #main
347   * @see #runApp
348   **/
349  protected AutoUpdateApp()
350  {
351    // not implemented
352  }
353
354
355  /**
356   * The entry point for running an app defined by the passed in properties.
357   * <P><b>This method blocks until the Executed app is complete</b></p>
358   *
359   * @param props the Properties defining the app to run as defined in the main
360   * class description.
361   *
362   * @return the return code from the exec'd application, -1 if the app did not
363   * get executed or the app returned a -1.
364   *
365   * @see #main
366   **/
367  public static int runApp(Properties props)
368  {
369    int retVal = -1;
370     System.out.println("++ Initializing AutoUpdateApp");
371    // init the class vars from the Properties file
372    soFarSoGood_ = initialize(props);
373
374    // required parameters are all set up??
375    if (soFarSoGood_)
376    {
377      // required parms are supplied ... carry on the validation
378      System.out.println("++ Ensuring the Remote app Is Available");
379
380      // validate that the app is available
381      soFarSoGood_ = ensureTheAppIsAvailable(filePath_);
382    }
383
384    // check for updates
385    if (soFarSoGood_ && remoteAppAutoDownload_ && remoteAppDownloadURL_ != null)
386    {
387      // the return from this DOES not affect soFarSoGood_ because we already
388      // confirmed that the app is available.
389      System.out.println("++ Checking for an update.");
390      checkAndUpdateApp(remoteAppDownloadURL_);
391    }
392
393    // execute
394    if (soFarSoGood_)
395    {
396      // This call blocks until the Executed app is complete
397      System.out.println("++ Executing the app");
398      retVal = execute();
399      System.out.println("++ Application Completed: Return code = " + retVal);
400    }
401
402    if (!soFarSoGood_)
403      System.out.println(errorMsg_);
404
405    return retVal;
406  }
407
408
409  /**
410   * The main entry for this app. It performs all the calls to validate,
411   * download and then execute the executable requested in the Properties file
412   * that is passed in as this apps single commandline parameter.
413   *
414   * @param args are the commandline parameters.This app expects ONLY 1
415   *             parameter... the absolute file path to the properties file
416   *             containing all the info for the Remote App to execute.
417   *
418   * @see #runApp
419   **/
420  public static void main (String [] args)
421  {
422    if (args.length < 1)
423      runApp(loadPropertiesFile(appPropertyFilename_));
424    else
425      System.out.println("AutoUpdateApp ERROR - incorrect number of" +
426                         "commandline args:\nUSAGE: java -jar " + appName_ +
427                         ".jar ");
428
429    //System.exit(0);
430  }
431
432
433  /**
434   * Initializes the apps vars (based on the passed in properties file)
435   * and gets ready to start.
436   *
437   * @return true if everything went okay and we can now start
438   **/
439  private static boolean initialize(Properties props)
440  {
441    boolean retVal = true;
442    // Validate that we got a properties file args.length ==1
443    if (props == null)
444      retVal = false;
445    else
446    {
447      // set up our helper vector to save us time on compares later on
448      definedPropertyKeys.add(RMT_APP_TYPE);
449      definedPropertyKeys.add(RMT_APP_URL);
450      definedPropertyKeys.add(RMT_APP_DOWNLOADURL);
451      definedPropertyKeys.add(RMT_APP_AUTODOWNLOAD);
452      definedPropertyKeys.add(RMT_APP_JVM_PARAMETERS);
453      definedPropertyKeys.add(RMT_APP_JVM_CLASSPATH);
454      // parse out the needed properties into the class variables
455      retVal = parseProperties(props);
456    }
457    return retVal;
458  }
459
460
461  /**
462   * This helper method checks that the specified file exists, if not it
463   * downloads it from the download URL.
464   *
465   * @return true if everything went okay and we have the file in place.
466   **/
467  private static boolean ensureTheAppIsAvailable(String filePath)
468  {
469    boolean retVal = true;
470    File executableFile = null;
471
472    if (filePath == null)
473      filePath = "";
474
475    try
476    {
477      System.out.println("We have the Parms: Remote App URL = "
478        + filePath);
479      if (appType_ == JAVA_APP &&
480        !(filePath.trim().toLowerCase().endsWith(".jar")) &&
481        !(filePath.trim().toLowerCase().endsWith(".class")))
482        executableFile = new File(filePath + ".class");
483      else
484        executableFile = new File(filePath);
485
486      // now get the downloadUrl filename (if it exists)
487      String downloadFilename = "";
488      if (remoteAppDownloadURL_ != null)
489      {
490        downloadFilename = remoteAppDownloadURL_.getFile();
491        downloadFilename = DEFAULT_SAVE_LOCATION +
492          downloadFilename.substring(downloadFilename.lastIndexOf("/")+1);
493      }
494
495      if (executableFile.exists())
496      {
497        if (!executableFile.canRead())
498        {
499          errorMsg_ = "ERROR: Cannot read " + executableFile.getAbsolutePath();
500          retVal = false;
501        }
502        else
503          System.out.println("Executable Exists");
504      }
505      else
506      {
507        // do the initial download/install
508        if (!(new File(downloadFilename)).exists())
509        {
510          System.out.println("Remote Launch Executable Does NOT Exist, " +
511                             "attempting retrieval");
512          retVal = updateAppFromServer(remoteAppDownloadURL_);
513        }
514      }
515    }
516    catch (SecurityException securityEx)
517    {
518      errorMsg_ = "ERROR: A Java Security Manager is in use and is " +
519        "restricting execution of the " + filePath +
520        " application.";
521      retVal = false;
522    }
523    // catch anything else here
524    catch (Exception otherEx)
525    {
526      errorMsg_ = "ERROR: An unforseen " + otherEx.getMessage() + "exception " +
527                  "occured while asserting the " + filePath +
528                  " application was available.\nIt will NOT execute.";
529      retVal = false;
530    }
531
532    return retVal;
533  }
534
535
536  /**
537   * Searches the classpath for the specified filename and then returns the full
538   * path that is used for it.
539   *
540   * @return the path description of the passed filename as found in the
541   *         classpath.
542   **/
543  private static String getFilePathFromClasspath(String filename)
544  {
545    String retVal = "";
546    String pathSep = System.getProperty("path.separator");
547
548    int fileIndex = CLASSPATH.indexOf(filename);
549    //System.out.println("Searching the Classpath for " + filename + " " +fileIndex);
550    if (fileIndex>=0)
551    {
552      int startSpot = 0;
553      int nextSpot = CLASSPATH.indexOf(pathSep);
554      // the fileName is in the classpath
555      // System.out.print("Start Looking at ("+startSpot+","+nextSpot+")");
556      while ((nextSpot < fileIndex) && nextSpot != -1)
557      {
558        startSpot = nextSpot;
559        nextSpot = CLASSPATH.indexOf(pathSep,startSpot+1);
560        //System.out.print(", ("+startSpot+","+nextSpot+")");
561      }
562      if (startSpot <= 0) startSpot = -1;
563      if (nextSpot <= 0) nextSpot = CLASSPATH.length() ;
564      retVal = CLASSPATH.substring(startSpot+1, nextSpot);
565    }
566
567    return retVal;
568  }
569
570
571  /**
572   * Converts the path component of a URL to the native relative file path.
573   *
574   * @param url the url to use to convert.
575   *
576   * @return the converted path string. It will return a "" if the URL does not
577   *         include a filepath portion.
578   **/
579  public static String convertSystemDependantPath(URL url)
580  {
581    String retVal = "";
582
583    // First check if we need to do the '/' conversion
584    if (url != null && SYSTEM_FILE_SEPERATOR.equals("\\"))
585    {
586      // yup... we have to switch 'em
587      // gotta use getFile instead of getPath which is a jdk 1.3 method
588      String tempPath = url.getFile();
589      for ( int i = 0; i < tempPath.length();i++)
590      {
591        if (tempPath.charAt(i) != '/' )
592        {
593          retVal += tempPath.substring(i,i+1);
594        }
595        else
596        {
597          if (i != 0)
598            retVal += "\\";
599        }
600      }
601    }
602    else if (url != null)
603      // It is a Un*x path (no conversion needed)
604      retVal = url.getFile().substring(1);
605
606    return retVal;
607  }
608
609
610  /**
611   * Determines the app type that has been assigned to the class variables and
612   * calls the correct helper method that Executes the class defined remote app.
613   * It Expects that all the class vars that desribe the app are in place and
614   * valid.
615   *
616   **/
617  private static int execute()
618  {
619    int retVal = -1;
620
621    if(appType_.equals(NATIVE_APP))
622    {
623      retVal = executeNativeApp(filePath_,
624                                cmdLineParms_);
625    }
626    else if(appType_.equals(JAVA_APP))
627    {
628        // first we have to build the JVM parameters Vector
629        Vector jvmParmVector = null;
630        if (!"".equals(jvmParameters_))
631        {
632          jvmParmVector = new Vector();
633          StringTokenizer s = new StringTokenizer(jvmParameters_);
634          while (s.hasMoreTokens())
635          {
636            jvmParmVector.add(s.nextToken());
637          }
638        }
639        retVal = executeJavaApp(filePath_,
640                                jvmParmVector,
641                                cmdLineParms_);
642    }
643    else if(appType_.equals(APPLET_APP))
644    {
645      // not implemented
646      errorMsg_ = "Applet type remote apps not yet supported";
647      soFarSoGood_ = false;
648    }
649    else if(appType_.equals(HTTPURL_APP))
650    {
651      // not implemented
652      errorMsg_ = "HTTP URL type remote apps not yet supported";
653      soFarSoGood_ = false;
654    }
655
656    return retVal;
657  }
658
659
660  /**
661   * Parses a String representation of a URL or absolute file path and converts
662   * it into a URL.<P>This method is a bit forgiving... if the string is not
663   * a correctlty formatted http, ftp, or file URL it will assume it is a file
664   * URL and create the returned URL as such.
665   *
666   * @param value is the String to convert into a URL.
667   *
668   * @return the Valid URL for the Executable or null if this method failed to
669   *         convert the passed in string.
670   *
671   * @throws MalformedURLException if the passed in String is not a URL
672   **/
673  private static URL parseAppExecutableUrl(String value)
674     throws MalformedURLException
675  {
676    URL retVal = null;
677    if (value.toLowerCase().startsWith("http:/") ||
678        value.toLowerCase().startsWith("ftp:/")  ||
679        value.toLowerCase().startsWith("file:/"))
680    {
681      // the following throws a MalformedURLException if value is bad
682      retVal = new URL(value);
683    }
684    else // assume it is a file path
685    {
686      try
687      {
688        String tempPath = value; // Assume Un*x ... no replacement needed
689        if (SYSTEM_FILE_SEPERATOR.equals("\\"))
690        {
691          /* Replace the file separators with the forward slash */
692          tempPath = ""; // start from scratch
693          for ( int i = 0; i < value.length(); i++)
694          {
695            if (value.charAt(i) != SYSTEM_FILE_SEPERATOR.charAt(0) )
696            {
697              tempPath += value.substring(i,i+1);
698            }
699            else
700            {
701              tempPath += "/";
702            }
703          }
704        }
705        retVal = new URL("file:/" + tempPath);
706      }
707      catch (NullPointerException badUrl)
708      {
709        throw new MalformedURLException(
710          "Can't parse the location URL from the file path provided.");
711      }
712    }
713    return retVal;
714  }
715
716
717  /**
718   * Checks the specified remoteAppDownloadURL_ to see if there is a newer
719   * version of the remoteAppURL_ <B>AND </B>then goes out and updates the app
720   * if a newer one is available.
721   *
722   * @param urlToGet is the place to go to get the updated app.
723   *
724   * @return true if there is a newer version available and it was download
725   *              successfully.
726   *
727   * @see #remoteAppDownloadURL_
728   * @see #remoteAppURL_
729   **/
730  private static boolean checkAndUpdateApp(URL urlToGet)
731  {
732    boolean retVal = false;
733    if (checkForUpdatedApp())
734      retVal = updateAppFromServer(urlToGet);
735
736    return retVal;
737  }
738
739
740  /**
741   * Checks the specified remoteAppDownloadURL_ to see if there is a newer
742   * version of the remoteAppURL_.
743   *
744   * @return true if there is a newer version available
745   *
746   * @see #checkAndUpdateApp
747   * @see #remoteAppDownloadURL_
748   * @see #remoteAppURL_
749   **/
750  private static boolean checkForUpdatedApp()
751  {
752    boolean retVal = false;
753    if (filePath_ == null)
754      filePath_ = "";
755
756    try
757    {
758      File executableFile = null;
759
760      if (appType_ == JAVA_APP &&
761        !(filePath_.trim().toLowerCase().endsWith(".jar")) &&
762        !(filePath_.trim().toLowerCase().endsWith(".class")))
763        executableFile = new File(filePath_ + ".class");
764      else
765        executableFile = new File(filePath_);
766
767      if (executableFile.exists())
768      {
769        if (executableFile.canRead())
770        {
771          long localModTime = executableFile.lastModified();
772          URLConnection remoteConn =
773            (URLConnection) remoteAppDownloadURL_.openConnection();
774          if (remoteConn.getLastModified() > localModTime)
775            retVal = true;
776        }
777      }
778      else
779        // check the download file
780      {
781        if (remoteAppDownloadURL_ != null)
782        {
783          // Parse out the filename portion of the download url
784          String downloadFilename = remoteAppDownloadURL_.getFile();
785          downloadFilename = DEFAULT_SAVE_LOCATION +
786            downloadFilename.substring(downloadFilename.lastIndexOf("/")+1);
787
788          // now create a file Object based on the above info so we can check
789          // dates
790          File localDownloadFile = new File(downloadFilename);
791          if (localDownloadFile.exists())
792          {
793            if (localDownloadFile.canRead())
794            {
795              long localModTime = localDownloadFile.lastModified();
796              URLConnection remoteConn =
797                (URLConnection) remoteAppDownloadURL_.openConnection();
798              if (remoteConn.getLastModified() > localModTime)
799              {
800                retVal = true;
801              }
802            }
803          }
804        }
805      }
806    }
807    catch (IOException ioEx)
808    {
809      System.out.println("Cannot check for updates at this time: " +
810        "The remote download URL specified " + remoteAppDownloadURL_ +
811        "is not permitting a connection.\nUsing current local file.");
812    }
813    return retVal;
814  }
815
816
817  /**
818   * Downloads the requested URL and replaces any existing version.<P>The place
819   * for saving this downloaded file is determined based on the archiveDownload_
820   * flag.  If archiveDownload_is true then dowloaded file is saved as a new
821   * /updated file with its own filename. This is done when an archive file is
822   * used as the download that is not the same as the executable name found in
823   * the remoteAppURL_ field. For example: if remoteAppURL_ points to
824   * ca.bc.webarts.SomeClass and the remoteAppDownloadURL_ points to
825   * SomeClass.jar we need to save the downloaded file to SomeClass.jar and then
826   * assume the commandline parameters will take care of the running/classpath
827   * issues.
828   *
829   * @param urlToGet is the place to go to get the updated app.
830   *
831   * @return true if successfully updated
832   *
833   * @see #archiveDownload_
834   **/
835  private static boolean updateAppFromServer(URL urlToGet)
836  {
837    boolean retVal = false;
838
839    if (urlToGet != null)
840    {
841      String filename = urlToGet.getFile();
842
843      // get the filename of the download
844      String remoteAppName = filename.substring(filename.lastIndexOf("/")+1);
845
846      // check if the remote download filename is the same as our Executable
847      // file name (we need this if the exe/class file is in an Jar archive etc
848      if (archiveDownload_)
849      {
850        // write to a new file
851        filename = DEFAULT_SAVE_LOCATION + remoteAppName;
852        archiveFilePath_ = filename;
853      }
854      else
855        // if so just overwrite the exe/class file
856        filename = filePath_;
857
858      //go get it
859      try
860      {
861        System.out.print("Downloading an update for: " +
862                           filename + " <");
863        URLConnection connection =
864          (URLConnection) urlToGet.openConnection();
865        System.out.println(connection.getContentType() + "> ("+
866                           connection.getContentLength() + ")");
867        System.out.println("  FROM: " + urlToGet);
868
869        // Store the file locally
870        InputStream inUrl = null;
871        if (urlToGet.getProtocol().equals("http"))
872          inUrl = ((HttpURLConnection) connection).getInputStream();
873        else
874          inUrl = connection.getInputStream();
875        new File(DEFAULT_SAVE_LOCATION).mkdir(); // ensures the dir exests
876        FileOutputStream ostream = new FileOutputStream(filename);
877
878        // start transfering
879        byte [] bytesRead= new byte[1024];
880        int numBytes = inUrl.read(bytesRead);
881        int status = 0;
882        System.out.print("..");
883        while (numBytes != -1)
884        {
885          // write what we read
886          ostream.write(bytesRead, 0, numBytes);
887
888          // update our status indicator
889          status += numBytes;
890          if (status % 1024 == 0)
891            System.out.print(".");
892
893          // go back for more
894          numBytes = inUrl.read(bytesRead);
895        }
896        System.out.println(".");
897        ostream.close();
898        retVal = true;
899      }
900      catch (NullPointerException nullEx)
901      {
902        System.out.println("Cannot update" + filename + " at this time: ");
903        System.out.println("Reason: Cannot get the content from " +
904                           urlToGet.toString());
905         System.out.println("Using current local file.");
906      }
907      catch (MalformedURLException badUrlEx)
908      {
909        System.out.println("Cannot update" + filename + " at this time: ");
910        System.out.println("Reason: Cannot get the URL for " +
911                           filename);
912        System.out.println("Using current local file.");
913      }
914      catch (SecurityException secEx)
915      {
916        System.out.println("Cannot update" + filename + " at this time: ");
917        System.out.println("Reason: Cannot create the file due to security " +
918                           "reasons.");
919        System.out.println("Using current local file.");
920      }
921      catch (FileNotFoundException fnfEx)
922      {
923        System.out.println("Cannot update" + filename + " at this time: ");
924        System.out.println("Reason: Cannot write the File.");
925        System.out.println("Using current local file.");
926      }
927      catch (IOException ioEx)
928      {
929        System.out.println("Cannot update" + filename + " at this time: ");
930        System.out.println("Reason: The remote download URL specified " +
931                           urlToGet + "is not permitting a connection.");
932        System.out.println("Using current local file.");
933      }
934    }
935
936    return retVal;
937  }
938
939
940  /**
941   * Executes the Specified Native OS application with the provided commandline
942   * parameters. This method blocks until the Executed app is complete. It also
943   * cleans up its sub-process and garbage collects.
944   * <br><b><u>
945   * NOTE:</b></u> This method uses a vector for the appParams and DOES NOT guaranty
946   * parameter order.  Please use the
947   * <a href="#executeNativeApp(java.lang.String, java.lang.String[])">
948   * executeNativeApp(String executableLocation, String [] cmdParms)</a> method\
949   * which uses an array for storage/retreival of the app parms.
950   *
951   * @param executableLocation is the path to the executable to run
952   *
953   * @param appParms and extra commandline parameters to tag onto the end of the
954   *                 commandline that gets executed.
955   *
956   * @return returns the return code from the executed app/process
957   *
958   * @see #executeNativeApp(java.lang.String, java.lang.String[])
959   * @see StreamGobbler
960   * @see java.lang.Runtime#getRuntime
961   **/
962  protected static int executeNativeApp(String executableLocation,
963                                      Vector appParms)
964  {
965    int cmdParms = 0;
966    if (appParms != null)
967      cmdParms = appParms.size();
968    String [] cmds = new String [cmdParms+1];
969
970    for (int i=1; i <= cmdParms; i++)
971    {
972      cmds[i] = (String) appParms.elementAt(i-1);
973    }
974    return executeNativeApp(executableLocation, cmds);
975  }
976
977
978  /**
979   * Executes the Specified Native OS application with the provided commandline
980   * parameters. This method blocks until the Executed app is complete. It also
981   * cleans up its sub-process and garbage collects. This method sends app
982   * output to std out.
983   *
984   * @param executableLocation is the path to the executable to run
985   *
986   * @param cmdParms and extra commandline parameters to tag onto the end of the
987   *                 commandline that gets executed.
988   *
989   * @return returns the return code from the executed app/process
990   *
991   * @see StreamGobbler
992   * @see java.lang.Runtime#getRuntime
993   **/
994  public static int executeNativeApp(String executableLocation,
995                                      String [] cmdParms)
996  {
997    return executeNativeApp(executableLocation, cmdParms, null);
998  }
999
1000
1001  /**
1002   * Executes the Specified Native OS application with the provided commandline
1003   * parameters. This method blocks until the Executed app is complete. It also
1004   * cleans up its sub-process and garbage collects.
1005   *
1006   * @param executableLocation is the path to the executable to run
1007   *
1008   * @param cmdParms and extra commandline parameters to tag onto the end of the
1009   *                 commandline that gets executed.
1010   *
1011   * @param outputFilename a filename to send the output to.
1012   *
1013   * @return returns the return code from the executed app/process
1014   *
1015   * @see StreamGobbler
1016   * @see java.lang.Runtime#getRuntime
1017   **/
1018  public static int executeNativeApp(String executableLocation,
1019                                      String [] cmdParms,
1020                                      String outputFilename)
1021  {
1022    int retVal = -1;
1023    //int cmdParms = 0;
1024    //if (appParms != null)
1025    //  cmdParms = appParms.size();
1026    String [] cmds = new String [cmdParms.length+1];
1027    cmds[0] = executableLocation;
1028
1029    System.out.print("\nParms: ");
1030    for (int i=1; i <= cmdParms.length; i++)
1031    {
1032      cmds[i] = (String) cmdParms[i-1];
1033      System.out.print(" " + cmds[i]);
1034    }
1035    System.out.println("");
1036
1037    // Start the app... This starts a new process
1038    try
1039    {
1040      File appDirfile = Util.getFileDir(executableLocation);
1041      System.out.println("Executable Dir : "+ appDirfile.getAbsolutePath());
1042      Runtime runtime = Runtime.getRuntime();
1043      System.out.println("Executing: "+ cmds[0]);
1044      Process p = runtime.exec(cmds, null, appDirfile);
1045
1046      // capture any output we get
1047      // any error message?
1048      StreamGobbler errorGobbler = new StreamGobbler(p.getErrorStream(), "APP ERR:");
1049
1050      // redirect any output?
1051      FileOutputStream pumpedOutputFile = null;
1052      PrintStream printStream = null;
1053      if (outputFilename != null && !outputFilename.equals(""))
1054      {
1055        pumpedOutputFile = new FileOutputStream(outputFilename);
1056        printStream =new PrintStream(pumpedOutputFile);
1057        System.out.println("Output Redirected to file: "+ outputFilename);
1058      }
1059      StreamGobbler outputGobbler = new
1060        StreamGobbler(p.getInputStream(), "", printStream);
1061      outputGobbler.setCapture(true);
1062
1063        // kick them off
1064      errorGobbler.start();
1065      outputGobbler.start();
1066      //Util.sleep(1000); // give the gobbler time to get all the output
1067
1068      // now wait for the process to end
1069      try
1070      {
1071        p.waitFor();
1072      }
1073      catch (InterruptedException intEx)
1074      {
1075        // no biggie
1076        System.out.print("Process "+ cmds[0] +" Interupted?");
1077      }
1078      retVal = p.exitValue();
1079      Util.sleep(1000); // give the gobbler time to get all the output
1080      errorGobbler.finishedGobbling_ = true;
1081      outputGobbler.finishedGobbling_ = true;
1082      p.destroy();
1083      p = null;
1084      runtime.gc();
1085    }
1086    catch (IOException ioEx)
1087    {
1088      errorMsg_ = "ERROR: An IO exception occured while attempting " +
1089        "execution of the " + executableLocation + " application.";
1090      soFarSoGood_ = false;
1091    }
1092    catch (SecurityException securityEx)
1093    {
1094      errorMsg_ = "ERROR: A Java Security Manager is in use and is " +
1095        "restricting execution of the " + executableLocation + " application.";
1096      soFarSoGood_ = false;
1097    }
1098    catch (Exception ex)
1099    {
1100      errorMsg_ = "ERROR: A Java Exception Occured" +
1101        "restricting execution of the " + executableLocation + " application.";
1102      soFarSoGood_ = false;
1103    }
1104
1105    return retVal;
1106  }
1107
1108
1109  /**
1110   * Executes the Specified Java appilcation with the provided commandline
1111   * parameters.
1112   *
1113   * @param classLocation is the path to the executable to run
1114   *
1115   * @param appParms and extra commandline parameters to tag onto the end of the
1116   *                 commandline that gets executed.
1117   * @return returns the return code from the executed app/process
1118   **/
1119  protected static int executeJavaApp(String classLocation, Vector appParms)
1120  {
1121    return executeJavaApp(classLocation, null, appParms);
1122  }
1123
1124
1125  /**
1126   * Executes the Specified Java appilcation with the provided JVM parameters
1127   * and executableApp commandline parameters.
1128   *
1129   * @param classLocation is the path to the executable to run
1130   *
1131   * @param jvmParms holds any cmdline parms to send directly to the jvm
1132   *
1133   * @param appParms and extra commandline parameters to tag onto the end of the
1134   *                 commandline that gets executed.
1135   * @return returns the return code from the executed app/process
1136   **/
1137  protected static int executeJavaApp(String classLocation,
1138                                    Vector jvmParms,
1139                                    Vector appParms)
1140  {
1141    int retVal = -1;
1142    int cmdParms = 0;
1143    if (appParms != null)
1144      cmdParms = appParms.size();
1145    Vector v = new Vector();
1146    int vCounter = 0;
1147
1148    // add the JVM parms first
1149    if (jvmParms != null)
1150    {
1151      int jvmParmSize = jvmParms.size();
1152      // add all the JVM parameters
1153      for (int i=0; i< jvmParmSize; i++)
1154      {
1155        v.add(vCounter++,(String)jvmParms.elementAt(i));
1156      }
1157    }
1158
1159    // Add the classpath parm (if it is not empty)
1160    if (archiveDownload_)
1161      jvmClasspath_ = archiveFilePath_+ File.pathSeparator + jvmClasspath_;
1162
1163    if (!"".equals(jvmClasspath_))
1164    {
1165      v.add(vCounter++,"-cp");
1166      v.add(vCounter++,jvmClasspath_);
1167    }
1168
1169    // verify if the java app is a class or jar file
1170    // if it is a jar we have to provide the extra -jar item on the cmdline
1171    // this assumes the jar is set up to be autoexecuting jar
1172    if (classLocation.trim().toLowerCase().endsWith("jar"))
1173      v.add(vCounter++,"-jar");
1174    v.add(vCounter++,classLocation);
1175
1176    // add all the extra parameters following the class/jar file
1177    for (int i=0; i < cmdParms; i++)
1178    {
1179      v.add(vCounter++,(String)appParms.elementAt(i));
1180    }
1181
1182    /*
1183    cmdParms = v.size();
1184    System.out.print("Parms: ");
1185    for (int i=1; i <= cmdParms; i++)
1186    {
1187      System.out.print(" " + (String) v.elementAt(i-1));
1188    }
1189    System.out.println("");
1190    */
1191
1192    String javaHome = System.getProperty("java.home");
1193    appParms.add(classLocation);
1194    retVal = executeNativeApp(javaHome + SYSTEM_FILE_SEPERATOR +"bin" +
1195                              SYSTEM_FILE_SEPERATOR + "java", v);
1196    return retVal;
1197  }
1198
1199
1200  /**
1201   * Parses the passed in Properties and pulls out all the name/value pairs
1202   * and assigns them to the class vars as needed.
1203   *
1204   * @param props the Properties to parse
1205   *
1206   * @return true if the method was able to successfully assign all class vars
1207   *
1208   **/
1209  private static boolean parseProperties(Properties props)
1210  {
1211    boolean retVal = true;
1212
1213    // grab out the name/value pairs
1214    // app type
1215    if (props.containsKey(RMT_APP_TYPE))
1216    {
1217      appType_ = props.getProperty(RMT_APP_TYPE);
1218    }
1219    else
1220    {
1221      errorMsg_ = "Can't parse the required parameter: application type.";
1222      retVal = false;
1223    }
1224
1225    // app locator
1226    if (retVal && props.containsKey(RMT_APP_URL))
1227    {
1228      try
1229      {
1230        remoteAppURL_ = parseAppExecutableUrl(props.getProperty(RMT_APP_URL));
1231        filePath_ = convertSystemDependantPath(remoteAppURL_);
1232      }
1233      catch (MalformedURLException badUrl)
1234      {
1235        errorMsg_ = "Can't parse the location URL for the application " +
1236          "to execute";
1237        retVal = false;
1238      }
1239    }
1240    else
1241    {
1242      errorMsg_ = "Can't parse the required parameter: application location.";
1243      retVal = false;
1244    }
1245
1246    String tempVal = null;
1247    // optional autodownload flag
1248    if (retVal && props.containsKey(RMT_APP_AUTODOWNLOAD))
1249    {
1250      tempVal = (String) props.get(RMT_APP_AUTODOWNLOAD);
1251      if (tempVal != null)
1252        remoteAppAutoDownload_ = (
1253          "false".equals(tempVal.trim().toLowerCase())?
1254          false:
1255          true);
1256    }
1257
1258    // optional download url
1259    if (retVal &&
1260        props.containsKey(RMT_APP_DOWNLOADURL))
1261    {
1262      try
1263      {
1264        remoteAppDownloadURL_ =
1265          new URL((String) props.get(RMT_APP_DOWNLOADURL));
1266
1267        // check and set the archiveDownload_ indicator
1268        String remoteFilename = remoteAppDownloadURL_.getFile();
1269
1270        // get our path for saving set up
1271        String remoteAppName =
1272          remoteFilename.substring(remoteFilename.lastIndexOf("/")+1);
1273        String localAppName =
1274          filePath_.substring(filePath_.lastIndexOf(SYSTEM_FILE_SEPERATOR)+1);
1275
1276        // check if the remote download filename is the same as our Executable
1277        // file name. Set archiveDownload_if the exe/class file is in
1278        // an archive (ie Jar or maybe a zip)
1279        // this gets used be the Auto Download feature (updateAppFromServer)
1280        if (remoteAppName != null && !remoteAppName.equals(localAppName))
1281        {
1282          // if so just overwrite the exe/class file
1283          archiveDownload_ = true;
1284          archiveFilePath_ = DEFAULT_SAVE_LOCATION + remoteAppName;
1285        }
1286        else
1287          filePath_ = DEFAULT_SAVE_LOCATION + remoteAppName;
1288      }
1289      catch (MalformedURLException badUrl)
1290      {
1291        // This is Okay because this Property is an optional one.
1292        // so just inform the user
1293        System.out.println("WARNING: Can't parse the supplied location URL " +
1294                           "to download the application to execute.");
1295        System.out.println("Using current local file.");
1296      }
1297    }
1298
1299    // optional jvm parms string
1300    if (retVal && props.containsKey(RMT_APP_JVM_PARAMETERS))
1301    {
1302      jvmParameters_ = props.getProperty(RMT_APP_JVM_PARAMETERS);
1303    }
1304
1305    // optional jvm classpath string
1306    if (retVal && props.containsKey(RMT_APP_JVM_CLASSPATH))
1307    {
1308      StringTokenizer st = new StringTokenizer(
1309        props.getProperty(RMT_APP_JVM_CLASSPATH), ";");
1310      while (st.hasMoreTokens())
1311      {
1312        // add them to the FRONT of any existing jvmClasspath_
1313        jvmClasspath_ = st.nextToken() +
1314          (jvmClasspath_==""?"":File.pathSeparator + jvmClasspath_);
1315      }
1316    }
1317
1318    // grab out all the rest
1319    for (Enumeration myEnum = props.keys(); myEnum.hasMoreElements();)
1320    {
1321      String currentPropKey = (String) myEnum.nextElement();
1322      if (currentPropKey != null &&
1323          !definedPropertyKeys.contains(currentPropKey))
1324      {
1325        // tokenize any extra parms if it can
1326        tempVal = props.getProperty(currentPropKey);
1327        StringTokenizer st = new StringTokenizer(tempVal);
1328        while (st.hasMoreTokens())
1329        {
1330          cmdLineParms_.add(st.nextToken());
1331        }
1332      }
1333    }
1334
1335    return retVal;
1336  }
1337
1338
1339  /**
1340   * Loads the AutoDownload app information from the properties file so this
1341   * wrapped app can execute. The properties file is encased in the root dir of
1342   * this apps jar file.
1343   *
1344   * @return the parsed Properties contained in the file specified by the passed
1345   *         in appPropertyFilename_, null if unable to get the contained
1346   *         Properties
1347   **/
1348  protected static Properties loadAutoAppPropertiesFile()
1349  {
1350    Properties props = null;
1351    boolean errorOccured = true;
1352    InputStream in = null;
1353    JarEntry autoAppPropsJarEntry = null;
1354    String currDir = System.getProperty("user.dir");
1355    String thisJarFile = currDir + SYSTEM_FILE_SEPERATOR + appName_+".jar";
1356    String jarInClasspath = getFilePathFromClasspath(appName_+".jar");
1357    String fileInCurrDir = currDir + SYSTEM_FILE_SEPERATOR +
1358                           appPropertyFilename_;
1359
1360    try
1361    {
1362      // first check the current directory for a jar file with this appsname.jar
1363      File tempFile = new File(thisJarFile);
1364      if (tempFile == null || !tempFile.exists() || !tempFile.canRead())
1365      {
1366        // if no jar in the current dir then going looking in the classpath
1367        tempFile = new File(jarInClasspath);
1368        if (tempFile == null || !tempFile.exists() || !tempFile.canRead())
1369        {
1370          // Last resort look for an unzipped set of files
1371          tempFile = new File(fileInCurrDir);
1372          if (tempFile == null || !tempFile.exists() || !tempFile.canRead())
1373          {
1374            // Not Found Anywhere
1375            thisJarFile = null;
1376          }
1377          else
1378          {
1379            // Its an Unzipped Archive
1380            // So load the props right here (leave errorOccured = true
1381            try
1382            {
1383              in = new FileInputStream(tempFile);
1384              props = new Properties();
1385              props.load(in);
1386              errorOccured = false;
1387            }
1388            catch (FileNotFoundException fEx)
1389            {
1390              System.out.println("No Application Properties File " +
1391                                 "FileNotFoundException " + appPropertyFilename_);
1392            }
1393            catch (IOException ioEx)
1394            {
1395              System.out.println("IO Error Reading Properties File " +
1396                                 "FileNotFoundException " + appPropertyFilename_);
1397            }
1398          }
1399        }
1400        else
1401        {
1402          // Its in The Classpath
1403          thisJarFile = jarInClasspath;
1404          errorOccured = false;
1405        }
1406      }
1407      else
1408        // Its in the Jar
1409        errorOccured = false;
1410    }
1411    catch (NullPointerException fEx)
1412    {
1413      thisJarFile = null;
1414    }
1415
1416    try
1417    {
1418      if (!errorOccured) // if in jar or jar in classpath
1419      {
1420        System.out.println(" +++ Looking for Jar File \n" + thisJarFile);
1421        JarFile jar = new JarFile(thisJarFile, false);
1422        autoAppPropsJarEntry = jar.getJarEntry(appPropertyFilename_);
1423        System.out.println("appPropertyFilename_="+appPropertyFilename_);
1424        System.out.println("autoAppPropsJarEntry="+
1425                           (autoAppPropsJarEntry==null?"null":"valid"));
1426        in = jar.getInputStream(autoAppPropsJarEntry);
1427        props = new Properties();
1428        props.load(in);
1429        errorOccured = false;
1430      }
1431    }
1432    catch (NullPointerException fEx)
1433    {
1434      System.out.println("No Application Properties JarEntry " +
1435                         "NullPointerException " + appPropertyFilename_);
1436    }
1437    catch (FileNotFoundException fEx)
1438    {
1439      System.out.println("No Application Properties JarEntry " +
1440                         "FileNotFoundException " + appPropertyFilename_);
1441    }
1442    catch (IOException ioEx)
1443    {
1444      System.out.println("IO Error Reading Properties JarEntry " +
1445                         "FileNotFoundException " + appPropertyFilename_);
1446    }
1447    catch (SecurityException secEx)
1448    {
1449      System.out.println("Jar SecurityException " + thisJarFile);
1450    }
1451
1452    return props;
1453  }
1454
1455
1456  /**
1457   * Loads the passed Properties file and returns a Properties object.
1458   *
1459   * @param propFilename the filename for the Properties file to parse
1460   *
1461   * @return the parsed Properties contained in the file specified by the passed
1462   *         in propFilename, null if unable to get the contained Properties
1463   *
1464   **/
1465  protected static Properties loadPropertiesFile(String propFilename)
1466  {
1467    Properties props = new Properties();
1468    try
1469    {
1470      // validate that the properties file exists
1471      FileInputStream propFileIn = new FileInputStream(propFilename);
1472
1473      // Load the Properties File
1474      props.load(propFileIn);
1475
1476    }
1477    catch (FileNotFoundException fnfEx)
1478    {
1479      // the path is null
1480      props = null;
1481      errorMsg_ = "Cannot obtain the application path (File Not Found).";
1482    }
1483    catch (IOException ioEx)
1484    {
1485      // the path is null
1486      props = null;
1487      errorMsg_ = "Cannot obtain the application path (I/O Error).";
1488    }
1489    return props;
1490  }
1491}