/**
  * Allows user to target several browsers. The names of potential browsers can be accessed via the
  * {@link #getBrowserList() getBrowserList} method.
  *
  * <p>The browsers from the list will be tried in order (first to last) until one of the calls
  * succeeds. If all the calls to the requested browsers fail, the code will fail over to the
  * default browser.
  *
  * @param browsers List
  * @param urlString String
  * @throws UnsupportedOperatingSystemException
  * @throws BrowserLaunchingExecutionException
  * @throws BrowserLaunchingInitializingException
  */
 public void openUrl(List browsers, String urlString)
     throws UnsupportedOperatingSystemException, BrowserLaunchingExecutionException,
         BrowserLaunchingInitializingException {
   if (browsers == null || browsers.isEmpty()) {
     logger.debug("falling through to non-targetted openUrl");
     openUrl(urlString);
   } else {
     String protocol = null;
     try {
       protocol = getProtocol(urlString);
     } catch (MalformedURLException malrulex) {
       throw new BrowserLaunchingExecutionException(malrulex);
     }
     Map browserMap = getBrowserMap();
     boolean success = false;
     Iterator iter = browsers.iterator();
     while (iter.hasNext() && !success) {
       WindowsBrowser winBrowser = (WindowsBrowser) browserMap.get(iter.next());
       if (winBrowser != null) {
         success = openUrlWithBrowser(winBrowser, protocol, urlString);
       }
     }
     if (!success) {
       logger.debug("none of listed browsers succeeded; falling through to non-targetted openUrl");
       openUrl(urlString);
     }
   }
 }
 /**
  * Attempts to open a url with the specified browser. This is a utility method called by the
  * openUrl methods.
  *
  * @param winBrowser WindowsBrowser
  * @param protocol String
  * @param urlString String
  * @return boolean
  * @throws BrowserLaunchingExecutionException
  */
 private boolean openUrlWithBrowser(WindowsBrowser winBrowser, String protocol, String urlString)
     throws BrowserLaunchingExecutionException {
   boolean success = false;
   try {
     logger.info(winBrowser.getBrowserDisplayName());
     logger.info(urlString);
     logger.info(protocol);
     String args = getCommandArgs(protocol, winBrowser, urlString, forceNewWindow);
     if (logger.isDebugEnabled()) {
       logger.debug(args);
     }
     Process process = Runtime.getRuntime().exec(args);
     // This avoids a memory leak on some versions of Java on Windows.
     // That's hinted at in <http://developer.java.sun.com/developer/qow/archive/68/>.
     process.waitFor();
     // some browsers (mozilla, firefox) return 1 if you attempt to
     // open a url and an instance of that browser is already running
     // not clear why because the call is succeeding, ie the browser
     // opens the url.
     // If we don't say 1 is also a success, we get two browser
     // windows or tabs opened to the url.
     //
     // We could make this check smarter in the future if we run
     // into problems. the winBrowser object could handle the
     // check to make it browser specific.
     int exitValue = process.exitValue();
     success = exitValue == 0 || exitValue == 1;
   }
   // Runtimes may throw InterruptedException
   // want to catch every possible exception and wrap it
   catch (Exception e) {
     throw new BrowserLaunchingExecutionException(e);
   }
   return success;
 }
 /**
  * Opens a url using a specific browser.
  *
  * <p>If the specified browser is not available, the method will fall through to calling the
  * default openUrl method.
  *
  * @param browser String
  * @param urlString String
  * @throws UnsupportedOperatingSystemException
  * @throws BrowserLaunchingExecutionException
  * @throws BrowserLaunchingInitializingException
  */
 public void openUrl(String browser, String urlString)
     throws UnsupportedOperatingSystemException, BrowserLaunchingExecutionException,
         BrowserLaunchingInitializingException {
   if (IBrowserLaunching.BROWSER_DEFAULT.equals(browser) || browser == null) {
     logger.info("default or null browser target; falling through to non-targetted openUrl");
     openUrl(urlString);
   } else {
     Map browserMap = getBrowserMap();
     WindowsBrowser winBrowser = (WindowsBrowser) browserMap.get(browser);
     if (winBrowser == null) {
       logger.info("the available browsers list does not contain: " + browser);
       logger.info("falling through to non-targetted openUrl");
       openUrl(urlString);
     } else {
       String protocol = null;
       try {
         protocol = getProtocol(urlString);
       } catch (MalformedURLException malrulex) {
         throw new BrowserLaunchingExecutionException(malrulex);
       }
       boolean successfullLaunch = openUrlWithBrowser(winBrowser, protocol, urlString);
       if (!successfullLaunch) {
         logger.debug("falling through to non-targetted openUrl");
         openUrl(urlString);
       }
     }
   }
 }
 /**
  * Initializes the browser launcher from the windows config file. It initializes the browsers to
  * check list and the command line args to use for version of windows referenced by the
  * windowsKey.
  *
  * @see windowsKey
  * @throws BrowserLaunchingInitializingException
  */
 public void initialize() throws BrowserLaunchingInitializingException {
   try {
     URL configUrl = getClass().getResource(CONFIGFILE_WINDOWS);
     if (configUrl == null) {
       throw new BrowserLaunchingInitializingException(
           "unable to find config file: " + CONFIGFILE_WINDOWS);
     }
     Properties configProps = new Properties();
     configProps.load(configUrl.openStream());
     // get sep char
     String sepChar = configProps.getProperty(PROP_KEY_DELIMITER);
     // load different types of browsers
     Iterator keysIter = configProps.keySet().iterator();
     while (keysIter.hasNext()) {
       String key = (String) keysIter.next();
       if (key.startsWith(PROP_KEY_BROWSER_PREFIX)) {
         WindowsBrowser winBrowser = new WindowsBrowser(sepChar, configProps.getProperty(key));
         browsersToCheck.add(winBrowser);
       }
     }
     // load the type of windows based on the windows key
     String windowsConfigStr = configProps.getProperty(windowsKey, null);
     if (windowsConfigStr == null) {
       throw new BrowserLaunchingInitializingException(windowsKey + " is not a valid property");
     }
     String[] winConfigItems = windowsConfigStr.split(sepChar);
     commandsDefaultBrowser = winConfigItems[0];
     commandsTargettedBrowser = winConfigItems[1];
     Boolean boolVal = new Boolean(winConfigItems[2]);
     useRegistry = boolVal.booleanValue();
     // check for override of useRegistry from system prop
     // need to explicitly check BOTH values to filter out
     // invalid prop values
     String propValue =
         System.getProperty(IBrowserLaunching.WINDOWS_BROWSER_DISC_POLICY_PROPERTY, null);
     if (IBrowserLaunching.WINDOWS_BROWSER_DISC_POLICY_DISK.equals(propValue)) {
       useRegistry = false;
     } else if (IBrowserLaunching.WINDOWS_BROWSER_DISC_POLICY_REGISTRY.equals(propValue)) {
       useRegistry = true;
     }
     if (logger.isDebugEnabled()) {
       logger.debug(
           "Browser discovery policy property value=" + (propValue == null ? "null" : propValue));
       logger.debug("useRegistry=" + Boolean.toString(useRegistry));
     }
     // get info for checking Program Files folder
     programFilesFolderTemplate = configProps.getProperty("program.files.template", null);
     driveLetters = configProps.getProperty("drive.letters", null);
     // set brwosersToCheck to a non-modifiable list
     browsersToCheck = Collections.unmodifiableList(browsersToCheck);
   } catch (IOException ioex) {
     throw new BrowserLaunchingInitializingException(ioex);
   }
 }
 /**
  * Use program files folder template from properties file and the list of drive letters from that
  * properties file
  *
  * @return File
  */
 private File getProgramFilesPath() {
   File progFilesPath = null;
   if (driveLetters != null && programFilesFolderTemplate != null) {
     String[] drives = driveLetters.split(";");
     for (int idx = 0; idx < drives.length && progFilesPath == null; idx++) {
       String path = MessageFormat.format(programFilesFolderTemplate, new Object[] {drives[idx]});
       File pfPath = new File(path);
       logger.debug(path);
       logger.debug(pfPath.getPath());
       if (pfPath.exists()) {
         progFilesPath = pfPath;
       }
     }
   }
   return progFilesPath;
 }
 /**
  * Accesses the Windows registry to look for browser exes. The browsers search for are in the
  * browsersToCheck list. The returned map will use display names and exe names as keys to the
  * {@link WindowsBrowser WindowsBrowser} objects.
  *
  * @param browsersToCheck List
  * @return Map
  */
 private Map getAvailableBrowsers(List tempBrowsersToCheck) {
   logger.debug("finding available browsers using registry");
   logger.debug("browsers to check: " + tempBrowsersToCheck);
   Map browsersAvailable = new TreeMap(String.CASE_INSENSITIVE_ORDER);
   try {
     // create map of exe names to win browser objects
     Map exesToBrowserObjs = getExeNamesToBrowsers(tempBrowsersToCheck);
     // access and look in registry
     Regor regor = new Regor();
     String subKeyName = "Software\\Microsoft\\Windows\\CurrentVersion\\App Paths";
     int key = regor.openKey(Regor.HKEY_LOCAL_MACHINE, subKeyName);
     if (key > -1) {
       List keys = regor.listKeys(key);
       Collections.sort(keys, String.CASE_INSENSITIVE_ORDER);
       Iterator keysIter = exesToBrowserObjs.keySet().iterator();
       while (keysIter.hasNext()) {
         String exeKey = (String) keysIter.next();
         int index = Collections.binarySearch(keys, exeKey, String.CASE_INSENSITIVE_ORDER);
         if (index >= 0) {
           WindowsBrowser winBrowser =
               getBrowserFromRegistryEntry(
                   regor, key, (String) keys.get(index), exeKey, exesToBrowserObjs);
           if (winBrowser != null) {
             if (logger.isDebugEnabled()) {
               logger.debug(
                   "Adding browser " + winBrowser.getBrowserDisplayName() + " to available list.");
               logger.debug(winBrowser.getPathToExe());
             }
             // adding display and exe for backward compatibility and
             // ease of use if someone passes in the name of an exe
             browsersAvailable.put(winBrowser.getBrowserDisplayName(), winBrowser);
             browsersAvailable.put(winBrowser.getBrowserApplicationName(), winBrowser);
             tempBrowsersToCheck.remove(winBrowser);
           }
         }
       }
     }
   } catch (RegistryErrorException ex) {
     logger.error("problem accessing registry", ex);
   }
   return browsersAvailable;
 }
 /**
  * Checks that the windows key is valid.
  *
  * @param logger AbstractLogger
  * @param windowsKey String
  */
 public WindowsBrowserLaunching(AbstractLogger logger, String windowsKey) {
   if (windowsKey == null) {
     throw new IllegalArgumentException("windowsKey cannot be null");
   }
   if (Arrays.binarySearch(WIN_KEYS, windowsKey) < 0) {
     throw new IllegalArgumentException(windowsKey + " is invalid");
   }
   this.logger = logger;
   this.windowsKey = windowsKey;
   logger.info(windowsKey);
 }
 /**
  * Opens a url using the default browser.
  *
  * @param urlString String
  * @throws UnsupportedOperatingSystemException
  * @throws BrowserLaunchingExecutionException
  * @throws BrowserLaunchingInitializingException
  */
 public void openUrl(String urlString)
     throws UnsupportedOperatingSystemException, BrowserLaunchingExecutionException,
         BrowserLaunchingInitializingException {
   try {
     logger.info(urlString);
     String protocol = getProtocol(urlString);
     logger.info(protocol);
     // try the system prop first
     boolean successfullSystemPropLaunch = false;
     String browserName = System.getProperty(IBrowserLaunching.BROWSER_SYSTEM_PROPERTY, null);
     if (browserName != null) {
       Map browserMap = getBrowserMap();
       WindowsBrowser winBrowser = (WindowsBrowser) browserMap.get(browserName);
       if (winBrowser != null) {
         logger.debug("using browser from system property");
         successfullSystemPropLaunch = openUrlWithBrowser(winBrowser, protocol, urlString);
       }
     }
     if (!successfullSystemPropLaunch) {
       String[] args = getCommandArgs(protocol, urlString);
       if (logger.isDebugEnabled()) {
         logger.debug(getArrayAsString(args));
       }
       Process process = Runtime.getRuntime().exec(args);
       // This avoids a memory leak on some versions of Java on Windows.
       // That's hinted at in <http://developer.java.sun.com/developer/qow/archive/68/>.
       process.waitFor();
       process.exitValue();
     }
   } catch (Exception e) {
     logger.error("fatal exception", e);
     throw new BrowserLaunchingExecutionException(e);
   }
 }
 /**
  * Secondary method for browser discovery.
  *
  * <p>Uses IE to get the path to the Program Files directory; then gets a list of the sub dirs and
  * checks them against the remaining browsers.
  *
  * @param iePath String
  * @param browsersAvailable Map
  * @param tmpBrowsersToCheck List
  */
 private Map processFilePathsForBrowsers(List tmpBrowsersToCheck) {
   logger.debug("finding available browsers in program files path");
   logger.debug("browsers to check: " + tmpBrowsersToCheck);
   Map browsersAvailable = new HashMap();
   File progFilesPath = getProgramFilesPath();
   if (progFilesPath != null) {
     logger.debug("program files path: " + progFilesPath.getPath());
     File[] subDirs = progFilesPath.listFiles(new DirFileFilter());
     int subDirsCnt = subDirs != null ? subDirs.length : 0;
     // create and populate map of dir names to win browser objects
     Iterator iter = tmpBrowsersToCheck.iterator();
     Map dirNameToBrowser = new HashMap();
     while (iter.hasNext()) {
       WindowsBrowser wBrowser = (WindowsBrowser) iter.next();
       dirNameToBrowser.put(wBrowser.getSubDirName(), wBrowser);
     }
     // iterate over subdirs and compare to map entries
     for (int idx = 0; idx < subDirsCnt && !tmpBrowsersToCheck.isEmpty(); idx++) {
       if (dirNameToBrowser.containsKey(subDirs[idx].getName())) {
         WindowsBrowser wBrowser = (WindowsBrowser) dirNameToBrowser.get(subDirs[idx].getName());
         // need to search folder and sub-folders for exe to find
         // the full path
         String exeName = wBrowser.getBrowserApplicationName() + ".exe";
         File fullPathToExe = findExeFilePath(subDirs[idx], exeName);
         if (fullPathToExe != null) {
           logger.debug(
               "Adding browser " + wBrowser.getBrowserDisplayName() + " to available list.");
           wBrowser.setPathToExe(fullPathToExe.getPath());
           logger.debug(wBrowser.getPathToExe());
           // adding display and exe for backward compatibility and
           // ease of use if someone passes in the name of an exe
           browsersAvailable.put(wBrowser.getBrowserDisplayName(), wBrowser);
           browsersAvailable.put(wBrowser.getBrowserApplicationName(), wBrowser);
           tmpBrowsersToCheck.remove(wBrowser);
         }
       }
     }
   }
   return browsersAvailable;
 }
  /**
   * Returns true if the browser is available, ie mdfind command finds it.
   *
   * @param logger AbstractLogger
   * @return boolean
   */
  public boolean isBrowserAvailable(StandardUnixBrowser browser, AbstractLogger logger) {
    boolean isAvailable = false;
    try {
      Process process =
          Runtime.getRuntime().exec(new String[] {"mdfind", browser.getBrowserApplicationName()});
      InputStream errStream = process.getErrorStream();
      InputStream inStream = process.getInputStream();
      BufferedReader errIn = new BufferedReader(new InputStreamReader(errStream));
      BufferedReader in = new BufferedReader(new InputStreamReader(inStream));

      String temp;
      StringBuffer whichOutput = new StringBuffer();
      while ((temp = in.readLine()) != null) {
        // Searching with spotlight (mdfind) will find more than just the app sometimes
        if (temp.indexOf(browser.getBrowserApplicationName()) > -1) {
          whichOutput.append(temp);
        }
      }

      StringBuffer whichErrOutput = new StringBuffer();
      while ((temp = errIn.readLine()) != null) {
        whichErrOutput.append(temp);
      }

      in.close();
      errIn.close();
      if (whichOutput.length() > 0) {
        logger.debug(whichOutput.toString());
        // very weak test but should be enough since the Open -a applicationname works very well
        isAvailable = true;
      }
      if (whichErrOutput.length() > 0) {
        logger.debug(whichErrOutput.toString());
      }
    } catch (IOException ex) {
      logger.error("io error executing which command", ex);
    }
    return isAvailable;
  }