/**
  * Helper method for downloading a plugin with a verbode progress bar
  *
  * @param name the plugin name
  * @param url the URL
  * @return true is plugin zip could be downloaded and unpacked
  */
 public boolean downloadAndUnpackPlugin(String name, URL url) throws IOException {
   final String pluginGroupId = settings.get("apps.plugingroup", PluginApp.GROUP_ID);
   String version = "0"; // dummy version
   PluginApp app = new PluginApp(pluginGroupId, name, version, url);
   File appFile = app.getInstallPath(environment);
   if (appFile.exists()) {
     return false;
   } else {
     appFile.mkdirs();
     // only zip supported
     File zipFile = new File(environment.pluginsFile(), name + ".zip");
     downloadHelper.download(url, zipFile, new HttpDownloadHelper.VerboseProgress(System.out));
     // extract zip
     unzip(environment, new ZipFile(zipFile), app.getInstallPath(environment), app.getPathName());
     zipFile.delete();
     return true;
   }
 }
 /**
  * Helper method for refreshing all plugin apps
  *
  * @return a map of plugin apps that are present after refreshing
  */
 private Map<String, PluginApp> refreshPluginApps() {
   final Map<String, PluginApp> loadedApps = newHashMap();
   final String pluginGroupId = settings.get("apps.plugingroup", PluginApp.GROUP_ID);
   final Map<String, Settings> pluginSettings = settings.getGroups("apps.plugins");
   // download all declared plugins if not already present
   for (Map.Entry<String, Settings> entry : pluginSettings.entrySet()) {
     try {
       String name = entry.getKey();
       boolean enabled = entry.getValue().getAsBoolean("enabled", Boolean.TRUE);
       if (enabled) {
         URL url = new URL(entry.getValue().get("url"));
         String version = entry.getValue().get("version", "0");
         PluginApp app = new PluginApp(pluginGroupId, name, version, url);
         File appFile = app.getInstallPath(environment);
         if (appFile.exists()) {
           loadedApps.put(app.getCanonicalForm(), app);
         } else {
           appFile.mkdirs();
           logger.info("retrieving plugin from URL {}", url);
           // only zip supported
           File zipFile = new File(environment.pluginsFile(), name + ".zip");
           downloadHelper.download(url, zipFile, null);
           // extract zip
           unzip(
               environment,
               new ZipFile(zipFile),
               app.getInstallPath(environment),
               app.getPathName());
           zipFile.delete();
         }
       }
     } catch (IOException e) {
       logger.error(e.getMessage(), e);
     }
   }
   return loadPlugins(environment.pluginsFile());
 }
 /**
  * Helper for loading all plugins into the class path and building a plugin app map.
  *
  * @param pluginsFile the base folder for the plugins
  * @return
  */
 private Map<String, PluginApp> loadPlugins(File pluginsFile) {
   Map<String, PluginApp> map = newHashMap();
   // traverse all legacy plugins in the plugins folder
   File[] pluginsFiles = pluginsFile.listFiles();
   if (pluginsFiles == null) {
     logger.warn("no files exist in {}", pluginsFile.getAbsolutePath());
     return map;
   }
   for (File pluginFile : pluginsFiles) {
     if (pluginFile.isDirectory()) {
       try {
         // add the root
         classLoader.addUri(pluginFile.toURI());
         // gather files to add
         List<File> libFiles = Lists.newArrayList();
         if (pluginFile.listFiles() != null) {
           libFiles.addAll(Arrays.asList(pluginFile.listFiles()));
         }
         File libLocation = new File(pluginFile, "lib");
         if (libLocation.exists()
             && libLocation.isDirectory()
             && libLocation.listFiles() != null) {
           libFiles.addAll(Arrays.asList(libLocation.listFiles()));
         }
         // if there are jars in it, add it as well
         for (File libFile : libFiles) {
           if (!(libFile.getName().endsWith(".jar") || libFile.getName().endsWith(".zip"))) {
             continue;
           }
           classLoader.addUri(libFile.toURI());
         }
       } catch (Exception e) {
         logger.warn("failed to add plugin [{}]", pluginFile, e);
       }
     }
   }
   // now, everything is on the class path, build the plugin app map
   Enumeration<URL> propUrls = null;
   try {
     propUrls = classLoader.getResources(DEFAULT_RESOURCE);
   } catch (IOException e1) {
     logger.warn("failed to find resources on classpath", e1);
     return map;
   }
   while (propUrls.hasMoreElements()) {
     URL propUrl = propUrls.nextElement();
     Properties appProps = new Properties();
     InputStream is = null;
     try {
       // skip jar URLs, they are artifact apps
       is = propUrl.openStream();
       appProps.load(is);
       String appClassName = appProps.getProperty("plugin");
       Plugin plugin = instantiatePluginClass(appClassName);
       if (isArtifactPlugin(plugin)) {
         logger.debug("plugin at [{}] is already present as artifact app, skipping", propUrl);
       } else {
         PluginApp app = new PluginApp(PluginApp.GROUP_ID, propUrl, plugin);
         map.put(app.getCanonicalForm(), app);
       }
     } catch (Exception e) {
       logger.warn(
           "failed to load plugin from [{}], reason: {}", propUrl, ExceptionFormatter.format(e));
     } finally {
       if (is != null) {
         try {
           is.close();
         } catch (IOException e) {
           // ignore
         }
       }
     }
   }
   return map;
 }