Package com.adito.extensions.store

Source Code of com.adito.extensions.store.ExtensionStore

        /*
*  Adito
*
*  Copyright (C) 2003-2006 3SP LTD. All Rights Reserved
*
*  This program is free software; you can redistribute it and/or
*  modify it under the terms of the GNU General Public License
*  as published by the Free Software Foundation; either version 2 of
*  the License, or (at your option) any later version.
*  This program is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*  GNU General Public License for more details.
*
*  You should have received a copy of the GNU General Public
*  License along with this program; if not, write to the Free Software
*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
     
package com.adito.extensions.store;

import java.io.File;
import java.io.FileFilter;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.prefs.BackingStoreException;
import java.util.prefs.Preferences;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.struts.action.ActionForward;
import org.jdom.JDOMException;

import com.adito.boot.Context;
import com.adito.boot.ContextHolder;
import com.adito.boot.PropertyList;
import com.adito.boot.RepositoryFactory;
import com.adito.boot.RepositoryStore;
import com.adito.boot.SystemProperties;
import com.adito.boot.Util;
import com.adito.boot.VersionInfo;
import com.adito.core.BundleActionMessage;
import com.adito.core.CoreAttributeConstants;
import com.adito.core.CoreEvent;
import com.adito.core.CoreEventConstants;
import com.adito.core.CoreMessageResources;
import com.adito.core.CoreServlet;
import com.adito.core.CoreUtil;
import com.adito.core.GlobalWarning;
import com.adito.core.GlobalWarningManager;
import com.adito.core.LicenseAgreement;
import com.adito.core.GlobalWarning.DismissType;
import com.adito.extensions.ExtensionBundle;
import com.adito.extensions.ExtensionDescriptor;
import com.adito.extensions.ExtensionException;
import com.adito.extensions.ExtensionInstaller;
import com.adito.extensions.ExtensionType;
import com.adito.extensions.ExtensionBundle.ExtensionBundleStatus;
import com.adito.setup.LicenseAgreementCallback;
import com.adito.tasks.Task;
import com.adito.tasks.TaskHttpServletRequest;
import com.adito.tasks.TaskInputStream;
import com.adito.tasks.TaskProgressBar;
import com.adito.util.ZipExtract;

/**
* Manages all aspects of <i>Extensions</i> including loading, starting,
* activating, disabling, installing, remove and updating.
* <p>
* This class also manages the interaction with the <i>Adito Extension Store</i>,
* including update checking and installing from the store.
*/
public class ExtensionStore {

    public static final String HTTP_3SP_COM_APPSTORE = "http://www.aditoproject.org/appstore/";
    private static final Log log = LogFactory.getLog(ExtensionStore.class);
  private static final String DIRS_TO_REMOVE = "dirsToRemove";
  private static String currentEdition = "Community Edition";

    public static final String UPDATEABLE = "Updateable";

  /**
   * Name of store in repository for extension bundle archives
   */
  public static final String ARCHIVE_STORE = "archives";

  /**
   * 'Installed' category in extension manager
   */
  public static final String INSTALLED_CATEGORY = "Installed";

  /**
   * The extension bundle id for the Agent.
   */
  public static final String AGENT_EXTENSION_BUNDLE_ID = "adito-agent";

  /**
   * Preferences node for storing current extension version and other
   * extension related details
   */
  public static final Preferences PREFS = ContextHolder.getContext().getPreferences().node("extensions");

  /**
   * Preferences node with the extensions node for storing extension store
   * related details.
   */
  public static final Preferences STORE_PREF = PREFS.node("store");

  /**
   * Preferences node with the extensions node for storing extension version
   * details.
   */
  public static final Preferences VERSION_PREFS = PREFS.node("versions");

  /**
   * Extension store connect timeout
   */
  public static final int CONNECT_TIMEOUT = 30000;

  /**
   * Extension store read timeout
   */
  public static final int READ_TIMEOUT = 30000;

  // Private instance variables

  private File basedir;
  private Map<String, ExtensionBundle> extensionBundles;
  private List<ExtensionBundle> extensionBundlesList;
  private List<ExtensionInstaller> extensionBundleInstallList;
  private ExtensionStoreDescriptor downloadableExtensions;
  private Calendar downloadableExtensionsLastUpdated;
  private boolean repositoryBacked;
  private static ExtensionStore instance;
    //private UpdateChecker updateChecker;

  /**
   * Get an instance of the extension store.
   *
   * @return instance
   */
  public static ExtensionStore getInstance() {
    if (instance == null) {
      instance = new ExtensionStore();
    }
    return instance;
  }

  /**
   * Get the update checker that checks for update to the core, extensions and
   * loads the RSS feeds
   *
   * @return update checker
   */
    //public UpdateChecker getUpdateChecker() {
    //   return updateChecker;
    //}

  /**
   * Get the directory where expanded extensions are stored.
   *
   * @return the extension store directory
   */
  public File getExtensionStoreDirectory() {
    return basedir;
  }

  /**
   * Get if the extension store is 'Repository Backed'. See class description
   * for details.
   *
   * @return true if it is repository backed
   */
  public boolean isRepositoryBacked() {
    return repositoryBacked;
  }

  /**
   * Initialise the extension store.
   *
   * @param basedir
   * @throws IOException
   */
  public void init(File basedir) throws IOException {

        //updateChecker = new UpdateChecker();

    // Get if the application store comes from the repository
    repositoryBacked = "true".equals(SystemProperties.get("adito.extensions.repositoryBacked", "true"));

    this.basedir = basedir;

    extensionBundles = new HashMap<String, ExtensionBundle>();
    extensionBundlesList = new ArrayList<ExtensionBundle>();
    extensionBundleInstallList = new ArrayList<ExtensionInstaller>();

    if (isRepositoryBacked()) {
      initialiseRepository();
    }

    try {
      loadAll();
      // TODO display errors to use somehow
    } catch (Exception e) {
      log.error("Failed extract extension bundles from repository.", e);
    }

    /*
     * A lot of plugins were made incompatible at 0.2.10. Here we make sure
     * any incompatible extensions are disabled
     */
    VersionInfo.Version sslxVersion = ContextHolder.getContext().getVersion();
    if (sslxVersion.getMajor() == 0 && sslxVersion.getMinor() == 2 && sslxVersion.getBuild() == 10) {
      StringBuffer buf = new StringBuffer();
      for (ExtensionBundle bundle : extensionBundlesList) {
        if (bundle.getRequiredHostVersion() == null || bundle.getRequiredHostVersion().compareTo(sslxVersion) < 0) {
          log.warn("Extension " + bundle.getId()
            + " has a required host version of "
            + bundle.getRequiredHostVersion()
            + " where as "
            + "this version is "
            + sslxVersion
            + ". This plugin will be disabled.");
          ExtensionStoreStatusManager.systemDisableExtension(bundle.getId());
          if (buf.length() > 0) {
            buf.append(",");
          }
          buf.append(bundle.getName());
        }
      }
      if (buf.length() > 0) {
                GlobalWarningManager.getInstance().addMultipleGlobalWarning(
                    new GlobalWarning(GlobalWarning.MANAGEMENT_USERS, new BundleActionMessage("extensions",
                                    "startup.disabledExtensions", buf.toString()), DismissType.DISMISS_FOR_USER));
            }
    }

    /*
     * First remove any plugins whose uninstallation may have been deferred
     * until restart
     */
    if (!isRepositoryBacked()) {

      String dirsToRemove = STORE_PREF.get(DIRS_TO_REMOVE, "");
      if (!dirsToRemove.equals("")) {
        StringTokenizer t = new StringTokenizer(dirsToRemove, ",");
        while (t.hasMoreTokens()) {
          File dir = new File(t.nextToken());
          if (dir.exists()) {
            if (log.isInfoEnabled())
              log.info("Removing extension " + dir.getAbsolutePath());
            Util.delTree(dir);
          }
        }
        STORE_PREF.remove(DIRS_TO_REMOVE);
      }

      /*
       * Check for extension updates
       */
      File updatedExtensionsDir = getUpdatedExtensionsDirectory();
      File[] extensions = updatedExtensionsDir.listFiles();
      if (extensions != null) {
        for (int i = 0; i < extensions.length; i++) {
          File destDir = new File(ContextHolder.getContext().getApplicationDirectory(), extensions[i].getName());
          if (destDir.exists()) {
            if (log.isInfoEnabled())
              log.info("Removing extension " + destDir.getAbsolutePath());
            if (!Util.delTree(destDir)) {
              throw new IOException("Failed to remove old extension " + destDir.getAbsolutePath());
            }
          }
          if (log.isInfoEnabled())
            log.info("Moving " + extensions[i].getAbsolutePath() + " to " + destDir.getAbsolutePath());
          if (!extensions[i].renameTo(destDir)) {
            throw new IOException("Failed to rename extension " + extensions[i].getAbsolutePath()
              + " to "
              + destDir.getAbsolutePath());
          }
        }
      }
    }

    // Add any additional class path elements
    addAdditionalClasspath();
    addAdditionalWebResource();

    // Check for any mandatory updates
        //try {
        //    updateChecker.initialise();
        //} catch (Exception e) {
      /*
       * There is no need to prevent start up if we fail to get the
       * available versions.
       */
        //    log.error("Failed to check for any extension updates.", e);
        //}
  }

  /**
   * @return the available extension bundles
   */
  @SuppressWarnings("unchecked")
  public List<ExtensionBundle> getAllAvailableExtensionBundles() {
    List<ExtensionBundle> all = new ArrayList<ExtensionBundle>(extensionBundlesList);
    try {
      ExtensionStoreDescriptor descriptor = getDownloadableExtensionStoreDescriptor(downloadableExtensions != null, getWorkingVersion());
      if (descriptor != null && descriptor.getExtensionBundles() != null) {
        for (Iterator itr = descriptor.getExtensionBundles().iterator(); itr.hasNext();) {
          ExtensionBundle bundle = (ExtensionBundle) itr.next();
          // If the app is already installed, remove dont include it
          // in the list
          if (!extensionBundles.containsKey(bundle.getId())) {
            all.add(bundle);
          }
        }
      }
    } catch (Exception e) {
      log.error("Failed to get downloadable extensions.", e);
    }
    Collections.sort(all);
    return all;
  }

  /**
     * Get all the available extension bundles fro a given category.
     *
   * @param category
   * @return the available extension bundles
   */
  @SuppressWarnings("unchecked")
  public List<ExtensionBundle> getAllAvailableExtensionBundles(String category) {
        // just get the installed ones.
        if (category.equals(INSTALLED_CATEGORY)){
            return extensionBundlesList;
        }
       
        List<ExtensionBundle> all = new ArrayList<ExtensionBundle>();
        if (category.equals(UPDATEABLE)){
            for (ExtensionBundle bundle : extensionBundles.values()) {
                // add all the updateable extensions
                if (bundle.isUpdateable()){
                    all.add(bundle);
                }
            }
        }
       
      try {
          ExtensionStoreDescriptor descriptor = getDownloadableExtensionStoreDescriptor(downloadableExtensions != null, getWorkingVersion());
          if (descriptor != null && descriptor.getExtensionBundles() != null) {
              for (Iterator itr = descriptor.getExtensionBundles().iterator(); itr.hasNext();) {
                  ExtensionBundle bundle = (ExtensionBundle) itr.next();
                  // If the app is already installed, remove dont include it
                  // in the list
                  if (!extensionBundles.containsKey(bundle.getId()) && bundle.getCategory().equals(category)) {
                      all.add(bundle);
                  }
              }
          }
      } catch (Exception e) {
          log.error("Failed to get downloadable extensions.", e);
      }
      Collections.sort(all);
      return all;
  }
 
  /**
   * @param id
   * @param version
   * @return URLConnection
   * @throws IOException
   */
  public URLConnection downloadExtension(String id, String version) throws IOException {
    URL downloadURL = getDownloadURL(id, version);
    if (downloadURL != null) {
      if (log.isInfoEnabled())
        log.info("Downloading extension from " + downloadURL.toExternalForm());
      URLConnection con = downloadURL.openConnection();
      con.setConnectTimeout(CONNECT_TIMEOUT);
      con.setReadTimeout(READ_TIMEOUT);
      con.connect();
      return con;
    } else {
      throw new IOException("No valid download location for " + id);
    }
  }

  /**
   * Start all extensions bundles
   *
   * @throws ExtensionException any error starting a bundle. If multiple
   *         extensions are started then only the first exception thrown by
   *         the bundle will be thrown from this method, an attempt will be
   *         made to start all other extensions bundles.
   */
  public void start() throws ExtensionException {
    if (log.isInfoEnabled())
      log.info("Starting extension store. Extensions will start in the following order .. ");
    Collections.sort(extensionBundlesList, new BundleComparator());
    for (ExtensionBundle bundle : extensionBundlesList) {
      log.info("    " + bundle.getId() + " (" + bundle.getOrder() + ")");
    }

    for (ExtensionBundle bundle : extensionBundlesList) {
        boolean setupMode = ContextHolder.getContext().isSetupMode();
            if (!setupMode || (setupMode && bundle.isStartOnSetupMode())) {
          ContextHolder.getContext().getBootProgressMonitor().updateMessage("Starting " + bundle.getName());
          ContextHolder.getContext()
                  .getBootProgressMonitor()
                  .updateProgress((int) (30 + (10 * ((float) extensionBundlesList.indexOf(bundle) / extensionBundlesList.size()))));
   
          // Start the bundle
          try {
              if (bundle.getStatus() == ExtensionBundleStatus.ENABLED) {
                  bundle.start();
              }
          } catch (Throwable t) {
            /*
             * Catch throwable to prevent bad extensions from interferring
             * with the core (e.g. NoClassDefFoundError,
             * ClassNotFoundException)
             */
            log.error("Failed to start extension bundle.", t);
          }
        }
    }

    /*
     * First check which extensions should have their installers run
     */
    checkExtensionsForInstallation();

    /*
     * Now run the installer for the start phase
     */
    performInstalls(ExtensionInstaller.ON_START);

  }

  /**
   * Stop all extensions bundles
   *
   * @throws ExtensionException any error stopping a bundle. If multiple
   *         extensions are started then only the first exception thrown by
   *         the bundle will be thrown from this method, an attempt will be
   *         made to start all other extensions bundles.
   */
  public void stop() throws ExtensionException {
    if (log.isInfoEnabled())
      log.info("Stopping extensions");

    // ensure all threads are finished.
        //updateChecker.end();

    // Stop extensions in the reverse order they were started
    if(extensionBundlesList != null) {
        Collections.reverse(extensionBundlesList);
   
        ExtensionException ee = null;
        for (ExtensionBundle bundle : extensionBundlesList) {
          try {
            bundle.stop();
          } catch (ExtensionException e) {
            if (ee == null) {
              ee = e;
            }
            log.error("Failed to stop extension bundle.", ee);
          }
        }
        if (ee != null) {
          throw ee;
        }
    }
  }

  /**
   * Activate all extensions bundles
   *
   * @throws ExtensionException any error activating a bundle. If multiple
   *         extensions are started then only the first exception thrown by
   *         the bundle will be thrown from this method, an attempt will be
   *         made to start all other extensions bundles.
   */
  public void activate() throws ExtensionException {
    if (log.isInfoEnabled())
      log.info("Activating extension store.");

    StringBuffer buf = new StringBuffer();
    for (ExtensionBundle bundle : extensionBundlesList) {
      try {
        if (bundle.getStatus() == ExtensionBundleStatus.STARTED) {

          ContextHolder.getContext().getBootProgressMonitor().updateMessage("Activating " + bundle.getName());
          ContextHolder.getContext()
                  .getBootProgressMonitor()
                  .updateProgress((int) (65 + (10 * ((float) extensionBundlesList.indexOf(bundle) / extensionBundlesList.size()))));

          bundle.activate();
         
          if(buf.length() != 0)
            buf.append(",");
          buf.append(bundle.getId());
        }
      } catch (Throwable t) {
        /*
         * Catch throwable to prevent bad extensions from interferring
         * with the core (e.g. NoClassDefFoundError,
         * ClassNotFoundException)
         */
        log.error("Failed to activate extension bundle.", t);
      }
    }

    /*
     * Remove the versions of any extensions that no longer exist
     */
    String[] k;
    try {
      k = VERSION_PREFS.keys();
      for (int i = 0; i < k.length; i++) {
        if (!isExtensionBundleLoaded(k[i])) {
          VERSION_PREFS.remove(k[i]);
        }
      }
    } catch (BackingStoreException e) {
      log.warn("Could not clean up extension versions preferences node.", e);
    }

    // Start watching for version updates and RSS updates (if enabled)
        //updateChecker.start();

    /*
     * Now run the installer for the start phase
     */
    performInstalls(ExtensionInstaller.ON_ACTIVATE);
   
    /**
     * If activat plugins has changed since the last full activation
     * then clear out the compiled JSP files
     */
    if(!buf.toString().equals(PREFS.get("lastActivatedPlugins", ""))) {
      Util.delTree(new File(ContextHolder.getContext().getTempDirectory(), "org"));
    }
    PREFS.put("lastActivatedPlugins", buf.toString());

    /* Flush these preferences now incase the server is terminated before
     * it gets a chance to write the preferences. When running in a development,
     * its possible for the server to get confused about when it should
     * clear out the temporary temporary directory.
     */
    try {
      PREFS.flush();
    }
    catch(BackingStoreException bse) {     
    }
  }

  /**
   * reset
   */
  public void resetExtensionStoreUpdate() {
    downloadableExtensions = null;
  }

  /**
   * @param connect
   * @return ExtensionStoreDescriptor
   * @throws IOException
   * @throws JDOMException
   */
  public ExtensionStoreDescriptor getDownloadableExtensionStoreDescriptor(boolean connect) throws IOException, JDOMException {
    return getDownloadableExtensionStoreDescriptor(connect, getWorkingVersion());
  }
 
  /**
   * @param connect
   * @param version
   * @return ExtensionStoreDescriptor
   * @throws IOException
   * @throws JDOMException
   */
  public ExtensionStoreDescriptor getDownloadableExtensionStoreDescriptor(boolean connect, VersionInfo.Version version) throws IOException, JDOMException {
    if (downloadableExtensions != null && downloadableExtensionsLastUpdated != null) {
      Calendar calendar = ((Calendar) downloadableExtensionsLastUpdated.clone());
      calendar.add(Calendar.DAY_OF_MONTH, 1);
      if (new GregorianCalendar().after(calendar)) {
        if (log.isInfoEnabled())
          log.info("Downloadable extensions are out of date, will contact the update site again.");
        downloadableExtensions = null;
      }
    }

    if (downloadableExtensions == null && connect) {
      URL storeURL = getStoreDownloadURL(ExtensionStore.HTTP_3SP_COM_APPSTORE, version);
      if (storeURL != null) {
        if (log.isInfoEnabled())
          log.info("Loading extension store descriptor from " + storeURL.getHost());

        downloadableExtensions = new ExtensionStoreDescriptor(storeURL);
        downloadableExtensionsLastUpdated = new GregorianCalendar();

        for (ExtensionBundle extensionBundle : downloadableExtensions.getExtensionBundles()) {
          try {
            ExtensionBundle installedApp = getExtensionBundle(extensionBundle.getId());
            if (!installedApp.isDevExtension() && installedApp.getVersion().compareTo(extensionBundle.getVersion()) < 0) {
              if (log.isInfoEnabled())
                log.info("Update found for extenions " + extensionBundle.getId());
              installedApp.setType(ExtensionBundle.TYPE_UPDATEABLE);
              installedApp.setUpdateVersion(extensionBundle.getVersion());
              installedApp.setChanges(extensionBundle.getChanges());
            }
          } catch (Exception e) {
                    if (log.isInfoEnabled())
                        log.info("Extension " + extensionBundle.getId() + " is not installed.");
          }
        }

        if (log.isInfoEnabled())
          log.info("Extension store descriptor loaded from " + storeURL.getHost());
      }
    }
    return downloadableExtensions;
  }

  void performInstalls(String phase) {
    for (ExtensionInstaller installer : extensionBundleInstallList) {
      try {
        if (log.isInfoEnabled()) {
          log.info("Performing installer for " + installer.getBundle().getName() + " phase " + phase);
        }
        installer.doInstall(phase);
      } catch (Exception e) {
        log.warn("Installer for " + installer.getBundle().getName() + " phase " + phase + " failed.", e);
      }
    }
  }

  void checkExtensionsForInstallation() {
    extensionBundleInstallList.clear();
    PropertyList forceInstalls = new PropertyList(SystemProperties.get("adito.forceInstallers", ""));
    for (ExtensionBundle bundle : extensionBundlesList) {
      if (bundle.getInstaller().getOpCount() > 0 && bundle.getStatus().isStartedOrActivated()) {
        String ver = VERSION_PREFS.get(bundle.getId(), "");
        boolean force = forceInstalls.contains(bundle.getId());
        if (force || ver.equals("") || !ver.equals(bundle.getVersion().toString())) {
            if(force) {
                        log.info("Will run installer for " + bundle.getId() + " because it has been forced by the adito.foreceInstallers property.");
            }
            else if (ver.equals("")) {
            log.info("Will run installer for " + bundle.getId() + " because this is its first install");
          } else {
            log.info("Will run installer for " + bundle.getId()
              + " because the last installed version "
              + ver
              + " has been upgraded to "
              + bundle.getVersion().toString());
          }
          extensionBundleInstallList.add(bundle.getInstaller());
        }
      }
    }
  }

  private static URL getDownloadURL(String id, String version) {
    try {
            String location = SystemProperties.get("adito.downloadableApplicationStore.location", ExtensionStore.HTTP_3SP_COM_APPSTORE);
            location += Util.urlEncode(id) + "/" + Util.urlEncode(version) + "/" + Util.urlEncode(id) + ".zip";
      return new URL(location);
    } catch (MalformedURLException murle) {
      try {
        String path = SystemProperties.get("adito.downloadableApplications.location");
        path = path.replaceAll("\\$\\{id\\}", id);
                path = path.replaceAll("\\$\\{version\\}", version);
        return new File(path).toURL();
      } catch (MalformedURLException e) {
        log.error("Invalid downloadable extension location specified in system property adito.downloadableApplicationStore.location, '" + SystemProperties.get("adito.downloadableApplicationStore.location")
          + "'. Must be either a URL or the file path of the store descriptor file.");
      }
    }
    return null;
  }

  public static URL getStoreDownloadURL(String appStoreLocation, VersionInfo.Version version) {
    try {
      String location = SystemProperties.get("adito.downloadableApplicationStore.location", appStoreLocation);
            location += "core/" + Util.urlEncode(version.toString()) + "/store.xml";
      return new URL(location);
    } catch (MalformedURLException murle) {
      try {
        return new File(SystemProperties.get("adito.downloadableApplicationStore.location")).toURL();
      } catch (MalformedURLException e) {
        log.error("Invalid downloadable extension store location specified in system property adito.downloadableApplicationStore.location, '" + SystemProperties.get("adito.downloadableApplicationStore.location")
          + "'. Must be either a URL or the file path of the store descriptor file.");
      }
    }
    return null;
  }
 
  /**
   *
   */
  public void deregisterApplicationPermissions() {
    Util.toDo("Deregister application permissions");
  }

  private synchronized void reloadAll() throws Exception {
    CoreMessageResources resources = CoreServlet.getServlet().getExtensionStoreResources();
    for (ExtensionBundle extensionBundle : extensionBundles.values()) {
      for (ExtensionDescriptor descriptor : extensionBundle) {
        Collection<String> toRemove = new ArrayList<String>();

        for (Iterator itr = resources.keys(); itr.hasNext();) {
          String key = (String) itr.next();
          if (key.startsWith("application." + descriptor.getId() + ".")) {
            toRemove.add(key);
          }
        }

        for (Iterator itr = toRemove.iterator(); itr.hasNext();) {
          resources.removeKey((String) itr.next());
        }
      }
    }

    extensionBundles.clear();
    extensionBundlesList.clear();

    loadAll();
  }

  @SuppressWarnings("unchecked")
  private void loadAll() throws Exception {

    if (log.isInfoEnabled())
      log.info("Loading applications");

    if (!basedir.exists()) {
      basedir.mkdirs();
    }

    // Load dev extensions first
    loadDevExtensions();

    File[] files = basedir.listFiles();
    for (int index = 0; index < files.length; index++) {
      try {
        loadDir(files[index]);
      } catch (Exception e) {
        log.error("Failed to load " + files[index].getName(), e);
      }
    }

    String descriptors = SystemProperties.get("adito.additionalDescriptors", "");
    // Load any additional descriptors
    for (StringTokenizer tokenizer = new StringTokenizer(descriptors, ","); tokenizer.hasMoreTokens();) {
      File file = new File(tokenizer.nextToken());
      if (file.exists()) {
        try {
          loadBundle(file, false);
        } catch (Exception e) {
          log.error("Failed to load " + file.getAbsolutePath(), e);
        }
      }
    }

    Collections.sort(extensionBundlesList);
  }

  private void loadDir(File dir) throws ExtensionException {
    if (dir.isDirectory()) {
      File[] descriptors = dir.listFiles(new FilenameFilter() {
        public boolean accept(File f, String filename) {
          return filename.equals("application.xml") || filename.equals("extension.xml");
        }
      });

      if (descriptors.length == 0) {
        log.warn("Extension folder " + dir.getName() + " found with no extension.xml (or the deprecated application.xml)");
        return;
      } else if (descriptors.length > 1) {
        // Should never happen if its case sensitive
        log.warn("Extension folder " + dir.getName()
          + " found with too many extension.xml (or deprecated application.xml) files. Please remove one. This extensions will be ignored.");
        return;
      }
      if (log.isInfoEnabled())
        log.info("Found application bundle " + dir.getName());

      if (descriptors[0].getName().equals("application.xml")) {
        log.warn("DEPRECATED. Application descriptor file " + descriptors[0]
          + "  is no longer used, please use extension.xml instead.");
      }
      loadBundle(descriptors[0], false);
    }
  }

  private void loadBundle(File descriptor, boolean devExtension) throws ExtensionException {
    ExtensionBundle bundle = new ExtensionBundle(descriptor, devExtension);
    loadBundle(bundle);
  }

  private void loadBundle(ExtensionBundle bundle) throws ExtensionException {

    bundle.load();
    ExtensionBundle oldBundle = (ExtensionBundle) extensionBundles.get(bundle.getId());

    if (oldBundle != null && oldBundle.isDevExtension()) {
      throw new ExtensionException(ExtensionException.CANNOT_REPLACE_DEV_EXTENSION, bundle.getId());
    }

    bundle.setCategory(ExtensionStore.INSTALLED_CATEGORY);
    try {
      ExtensionBundleStatus extensionStatus = ExtensionStoreStatusManager.getExtensionStatus(bundle.getId());
      bundle.setStatus(extensionStatus);
    } catch (IOException ioe) {
      throw new ExtensionException(ExtensionException.INTERNAL_ERROR, ioe, "Failed to add bundle.");
    }

    for (ExtensionDescriptor descriptor : bundle) {
      if (log.isInfoEnabled())
        log.info("Extension " + descriptor.getName() + " has been loaded");
    }
    extensionBundlesList.remove(oldBundle);
    extensionBundles.put(bundle.getId(), bundle);
    extensionBundlesList.add(bundle);
  }

  /**
   * @param bundleId
   * @throws ExtensionException
   * @throws IOException
   */
  public void systemDisableExtension(String bundleId) throws ExtensionException, IOException {
    ExtensionBundle extensionBundle = getExtensionBundle(bundleId);
    extensionBundle.setStatus(ExtensionBundle.ExtensionBundleStatus.SYSTEM_DISABLED);
    ExtensionStoreStatusManager.systemDisableExtension(bundleId);
  }

  /**
   * @param bundleId
   * @throws Exception
   */
  public void disableExtension(String bundleId) throws Exception {
    ExtensionBundle extensionBundle = getExtensionBundle(bundleId);
    extensionBundle.setStatus(ExtensionBundle.ExtensionBundleStatus.DISABLED);
    ExtensionStoreStatusManager.disableExtension(bundleId);
    if(extensionBundle.isContainsPlugin()) {
      extensionBundle.setType(ExtensionBundle.TYPE_PENDING_STATE_CHANGE);
    }
  }

  /**
   * @param bundleId
   * @throws Exception
   */
  public void enableExtension(String bundleId) throws Exception {
    ExtensionBundle extensionBundle = getExtensionBundle(bundleId);
    extensionBundle.setStatus(ExtensionBundle.ExtensionBundleStatus.ENABLED);
    ExtensionStoreStatusManager.enableExtension(bundleId);
    if(extensionBundle.isContainsPlugin()) {
      extensionBundle.setType(ExtensionBundle.TYPE_PENDING_STATE_CHANGE);
    }
  }

  private static void installExtension(ExtensionBundle extensionBundle) throws IOException {
    if (ExtensionBundle.ExtensionBundleStatus.SYSTEM_DISABLED.equals(extensionBundle.getStatus())) {
      ExtensionStoreStatusManager.installExtension(extensionBundle.getId());
      extensionBundle.setStatus(ExtensionBundle.ExtensionBundleStatus.ENABLED);
    }
  }

  /**
   * @return List
   */
  public List<ExtensionBundle> getExtensionBundles() {
    return extensionBundlesList;
  }

  /**
   * @param name
   * @return true if the extension bundle has been loaded
   */
  public boolean isExtensionBundleLoaded(String name) {
    return extensionBundles.containsKey(name);
  }

  /**
   * @return ExtensionDescriptor
   */
  public ExtensionDescriptor getAgentApplication() {
    try {
      ExtensionBundle bundle = getExtensionBundle(AGENT_EXTENSION_BUNDLE_ID);
      return bundle != null ? (ExtensionDescriptor) bundle.getApplicationDescriptor(AGENT_EXTENSION_BUNDLE_ID) : null;
    } catch (Exception e) {
      log.error("Failed to get agent descriptor. Loaded?", e);
      return null;
    }
  }

  /**
   * @param id
   * @return ExtensionDescriptor
   */
  public ExtensionDescriptor getExtensionDescriptor(String id) {
    for (ExtensionBundle bundle : extensionBundlesList) {
      ExtensionDescriptor descriptor = bundle.getApplicationDescriptor(id);
      if (descriptor != null && descriptor instanceof ExtensionDescriptor) {
        return (ExtensionDescriptor) descriptor;
      }
    }
    return null;
  }

  /**
   * Get an extension bundle given its ID.
   *
   * @param id extension bundle id
   * @return extension bundle
   * @throws ExtensionException if bundle could not be located ({@link ExtensionException#INVALID_EXTENSION}).
   */
  public ExtensionBundle getExtensionBundle(String id) throws ExtensionException {
    if (!extensionBundles.containsKey(id)) {
      throw new ExtensionException(ExtensionException.INVALID_EXTENSION, id);
    }
    return (ExtensionBundle) extensionBundles.get(id);
  }

  /**
   * Reload all
   *
   * @throws Exception
   */
  public void reload() throws Exception {
    if (log.isInfoEnabled())
      log.info("Reloading all application bundles");
    boolean reconnect = downloadableExtensions != null;
    downloadableExtensions = null;
    downloadableExtensionsLastUpdated = null;
    deregisterApplicationPermissions();

    reloadAll();
    if (reconnect) {
            getDownloadableExtensionStoreDescriptor(true);
    }
  }

    public static VersionInfo.Version getWorkingVersion() {
        VersionInfo.Version version = new VersionInfo.Version(SystemProperties.get("adito.forceVersion", ContextHolder.getContext().getVersion().toString()));
        return version;
    }

  /**
   * @param id
   * @throws ExtensionException
   */
  @SuppressWarnings("unchecked")
  public void reload(String id) throws ExtensionException {
    if (log.isInfoEnabled())
      log.info("Reloading application bundle " + id);
    if (isExtensionLoaded(id)) {
      ExtensionBundle bundle = getExtensionBundle(id);
      try {
        bundle.load();
      } catch (ExtensionException ee) {
        log.warn("Failed to reload extension descriptor.", ee);
        extensionBundles.remove(id);
        extensionBundlesList.remove(bundle);
        throw ee;
      }
    } else {
      loadDir(new File(basedir, id));
    }
    Collections.sort(extensionBundlesList);
  }

  /**
   * @return File
   * @throws IOException
   */
  public File getUpdatedExtensionsDirectory() throws IOException {
    File updatedExtensionsDir = new File(ContextHolder.getContext().getConfDirectory(), "updated-extensions");
    if (!updatedExtensionsDir.exists() && !updatedExtensionsDir.mkdirs()) {
      throw new IOException("The extension update directory " + updatedExtensionsDir.getAbsolutePath()
        + " could not be created.");
    }
    return updatedExtensionsDir;
  }

  /**
   * Remove an extension bundle. The bundle will be stopped if it is started
   * and events will be fired. Global warnings will also be created if the
   * bundle contains any plugins informing the administrator the server must
   * be restarted.
   *
   * @param bundle bundle to remove
   * @throws Exception on any error
   */
  @SuppressWarnings("unchecked")
  public void removeExtensionBundle(ExtensionBundle bundle) throws Exception {
    if (log.isInfoEnabled())
      log.info("Removing extension bundle " + bundle.getId());
    boolean containsPlugin = bundle.isContainsPlugin();
    try {
      CoreServlet.getServlet()
              .fireCoreEvent(new CoreEvent(this,
                      CoreEventConstants.REMOVING_EXTENSION,
                      bundle,
                      null,
                      CoreEvent.STATE_SUCCESSFUL).addAttribute(CoreAttributeConstants.EVENT_ATTR_EXTENSION_ID,
                bundle.getId())
                      .addAttribute(CoreAttributeConstants.EVENT_ATTR_EXTENSION_NAME, bundle.getName()));
      bundle.removeBundle();
      VERSION_PREFS.remove(bundle.getId());
      CoreServlet.getServlet()
              .fireCoreEvent(new CoreEvent(this,
                      CoreEventConstants.REMOVE_EXTENSION,
                      bundle,
                      null,
                      CoreEvent.STATE_SUCCESSFUL).addAttribute(CoreAttributeConstants.EVENT_ATTR_EXTENSION_ID,
                bundle.getId())
                      .addAttribute(CoreAttributeConstants.EVENT_ATTR_EXTENSION_NAME, bundle.getName()));
      if (containsPlugin) {
        if (!ExtensionStore.getInstance().isRepositoryBacked()) {
          if (log.isInfoEnabled())
            log.info("Extension " + bundle.getId() + " contains plugins, deferring removal until restart.");
          StringBuffer toRemove = new StringBuffer(STORE_PREF.get(DIRS_TO_REMOVE, ""));
          if (toRemove.length() > 0) {
            toRemove.append(",");
          }
          toRemove.append(bundle.getBaseDir());
          STORE_PREF.put(DIRS_TO_REMOVE, toRemove.toString());
        }
      }
      ExtensionStoreStatusManager.removeExtension(bundle.getId());
    } catch (Exception e) {
      CoreServlet.getServlet()
              .fireCoreEvent(new CoreEvent(this, CoreEventConstants.REMOVE_EXTENSION, null, null, e).addAttribute(CoreAttributeConstants.EVENT_ATTR_EXTENSION_ID,
                bundle.getId())
                      .addAttribute(CoreAttributeConstants.EVENT_ATTR_EXTENSION_NAME, bundle.getName()));

      throw e;
    } finally {
      if (!containsPlugin) {
        extensionBundles.remove(bundle.getId());
        extensionBundlesList.remove(bundle);
        if (log.isInfoEnabled())
          log.info("Extension Zip file " + bundle.getId() + ".zip" + " has been deleted.");
      }
      if (ExtensionStore.getInstance().isRepositoryBacked()) {
        RepositoryFactory.getRepository().getStore(ExtensionStore.ARCHIVE_STORE).removeEntry(bundle.getId() + ".zip");
      }
      Collections.sort(extensionBundlesList);
    }
  }

  /**
   * Determine if an extension is installed given its extension bundle id.
   *
   * @param id extension bundle id
   * @return true if the extension has been loaded
   */
  public boolean isExtensionLoaded(String id) {
    for (Iterator i = extensionBundlesList.iterator(); i.hasNext();) {
      ExtensionBundle bundle = (ExtensionBundle) i.next();
      if (bundle.containsApplication(id)) {
        return true;
      }
    }
    return false;
  }

  /**
   * Install an extension directly from the Adito Extension Store given its id
   * and an input stream providing the extension bundle archive in zip format.
   * This method will also attempt to install all of the bundles dependencies.
   *
   * @param id extension bundle id
   * @param in input stream of extension bundle archive (Zip format)
   * @param request request object
     * @param contentLength size of extension bundle if known (-1 when unavailable - used for progress bar)
   * @return ExtensionBundle installed extension bundle
   * @throws ExtensionException on any error
   */
  public ExtensionBundle installExtensionFromStore(final String id, InputStream in, HttpServletRequest request, long contentLength)
          throws ExtensionException {
    ExtensionStoreDescriptor store;
    try {
      // Get the application store descriptor
      store = getDownloadableExtensionStoreDescriptor(true);
      if (store == null) {
        throw new ExtensionException(ExtensionException.INTERNAL_ERROR, "No downloadable applications.");
      }

      ExtensionBundle bundle = store.getApplicationBundle(id);
      if (bundle == null) {
        throw new ExtensionException(ExtensionException.INVALID_EXTENSION, id);
      }

      // Check host version
      Context context = ContextHolder.getContext();
      if (bundle.getRequiredHostVersion() != null && bundle.getRequiredHostVersion().compareTo(context.getVersion()) > 0) {
        throw new ExtensionException(ExtensionException.INSUFFICIENT_ADITO_HOST_VERSION,
                bundle.getId(),
                bundle.getRequiredHostVersion().toString());
     

      // Install all dependencies
      if (bundle.getDependencies() != null) {
        for (String dep : bundle.getDependencies()) {
          if (isExtensionBundleLoaded(dep)) {
            ExtensionBundle current = getExtensionBundle(dep);
            ExtensionBundle available = store.getApplicationBundle(dep);
            if(available != null) {
              if (!current.isDevExtension() && isNewerVersionAvailable(available, current)) {
                if (log.isInfoEnabled())
                  log.info("Found a dependency (" + dep + "), that needs upgrading. " + current.getVersion().toString() + " is the current version, " +  available.getVersion().toString() + " is available. Installing now");
                installExtensionFromStore(current.getId(), available.getVersion().toString(), request);
              }
            }
          } else {
            try {
              if (log.isInfoEnabled())
                log.info("Found a dependency (" + dep + "), that is not installed. Installing now");
              installExtensionFromStore(dep, store.getApplicationBundle(dep).getVersion().toString(), request);
            } catch (Exception e) {
              throw new ExtensionException(ExtensionException.INTERNAL_ERROR, "Failed to install dependency " + dep);
            }
          }
        }
      }

            // This action may be wrapped in a task progress monitor
            Task task = (Task)request.getAttribute(TaskHttpServletRequest.ATTR_TASK);
            if(task != null && request.getAttribute(TaskHttpServletRequest.ATTR_TASK_PROGRESS_HANDLED_EXTERNALLY) == null) {
                TaskProgressBar bar = new TaskProgressBar("installExtension", 0, (int)contentLength, 0); // TODO should accept longs
                task.clearProgressBars();
                task.addProgressBar(bar);
                in = new TaskInputStream(bar, in);
                ((TaskInputStream)in).getProgressBar().setNote(new BundleActionMessage("extensions", "taskProgress.downloadExtension.note", id));
                if(!task.isConfigured())
                    task.configured();
            }         

      return installExtension(id, in);
    } catch (IOException jde) {
      throw new ExtensionException(ExtensionException.INTERNAL_ERROR, "Failed to load descriptor.");
    } catch (JDOMException jde) {
      throw new ExtensionException(ExtensionException.FAILED_TO_PARSE_DESCRIPTOR);
    }
  }

  /**
   * Install an extension directly from the Adito Extension Store given its id.
   * This method will also attempt to install all of the bundles dependencies.
   *
   * @param id extension bundle ID
   * @param version
   * @param request request object
   * @throws ExtensionException extension errors
   * @throws IOException io errors
   */
  public void installExtensionFromStore(String id, String version, HttpServletRequest request) throws IOException, ExtensionException {
    URLConnection connection = downloadExtension(id, version);
    InputStream inputStream = connection.getInputStream();
    installExtensionFromStore(id, inputStream, request, connection.getContentLength());
  }

  /**
   * Install an extension givens its bundle and an input stream providing the
   * extension bundle archive in zip format.
   *
   * @param id extension bundle ID
   * @param in input stream provided the extension bundle archive (in Zip
   *        format)
   * @return ExtensionBundle
   * @throws IOException io errors
   * @throws ExtensionException extension errors
   */
  public ExtensionBundle installExtension(final String id, InputStream in) throws IOException, ExtensionException {
    streamToRepositoryStore(in, id);

    try {
      RepositoryStore repStore = RepositoryFactory.getRepository().getStore(ARCHIVE_STORE);
      ZipExtract.extractZipFile(getExtensionStoreDirectory(), repStore.getEntryInputStream(id + ".zip"));
      reload(id);
      ExtensionBundle newBundle = getExtensionBundle(id);
      installExtension(newBundle);
      fireBundleEvent(CoreEventConstants.INSTALL_EXTENSION, newBundle);
    } catch (IOException e) {
      CoreServlet.getServlet().fireCoreEvent(new CoreEvent(this,
              CoreEventConstants.INSTALL_EXTENSION,
              null,
              null,
              CoreEvent.STATE_UNSUCCESSFUL).addAttribute(CoreAttributeConstants.EVENT_ATTR_EXTENSION_ID, id));
      throw e;
    } catch (ExtensionException e) {
      CoreServlet.getServlet().fireCoreEvent(new CoreEvent(this,
              CoreEventConstants.INSTALL_EXTENSION,
              null,
              null,
              CoreEvent.STATE_UNSUCCESSFUL).addAttribute(CoreAttributeConstants.EVENT_ATTR_EXTENSION_ID, id));
      throw e;
    }
    return getExtensionBundle(id);
  }

  /**
   * Check the license for a given bundle, adding a page redirect to ask the
   * user to accept a license agreement if required.
   * <p>
   * This should be called just after an extenion is installed either from the
   * Adito Application Store or manually.
   *
   * @param newBundle newly installed bundle
   * @param request request object
   * @param installedForward the forward to redirect to after license
   *        agreement has been show
   * @throws Exception on any error
   */
  public void licenseCheck(final ExtensionBundle newBundle, HttpServletRequest request, final ActionForward installedForward)
          throws Exception {

    final RepositoryStore repStore = RepositoryFactory.getRepository().getStore(ARCHIVE_STORE);
    // If installing, there may be a license agreement to handle
    File licenseFile = newBundle.getLicenseFile();
    if (licenseFile != null && licenseFile.exists()) {
      LicenseAgreement licenseAgreement = getLicenseAgreement(newBundle, repStore, licenseFile, installedForward);
      CoreUtil.requestLicenseAgreement(request.getSession(), licenseAgreement);
    }
  }

  /**
   * Invoked after an extension has been installed, this method adds a global
   * warning if the bundle contains any plugins indicating a restart is neeed.
   * Also, if the bundle doesn't contain any plugins it will immediately run
   * the 'installer'.
   *
   * @param newBundle newly installed extension bundle
   * @param request request
   * @throws Exception on any error
   */
  public void postInstallExtension(final ExtensionBundle newBundle, HttpServletRequest request) throws Exception {
    boolean containsPlugin = newBundle.isContainsPlugin();

    if (containsPlugin) {
        GlobalWarningManager.getInstance().addMultipleGlobalWarning(new GlobalWarning(GlobalWarning.MANAGEMENT_USERS, new BundleActionMessage("extensions",
            "extensionStore.message.pluginInstalledRestartRequired"), DismissType.DISMISS_FOR_USER));
      newBundle.setType(ExtensionBundle.TYPE_PENDING_INSTALLATION);
    } else {
      newBundle.start();

      // Installer must be run after start as it may have custom tasks
      if (newBundle.getInstaller() != null) {
        newBundle.getInstaller().doInstall(null);
      }

      newBundle.activate();
    }
  }

  /**
   * Update an extension givens its bundle and an input stream providing the
   * extension bundle archive in zip format.
   *
   * @param id extension bundle id
   * @param in input stream of extension bundle archive (Zip format)
   * @param request reuqest object
     * @param contentLength content length
   * @return ExtensionBundle newly loaded extension bundle
   * @throws Exception on any error
   */
  public ExtensionBundle updateExtension(String id, InputStream in, HttpServletRequest request, long contentLength) throws Exception {
    ExtensionStoreDescriptor store;
    // Get the application store descriptor
    /**
     * LDP - Why does this require the extension store descriptor? Extensions should be
     * updatable even if the extension store is not available!!!!!!!!
     */
//    store = getDownloadableExtensionStoreDescriptor(true);
//    if (store == null) {
//      throw new ExtensionException(ExtensionException.INTERNAL_ERROR, "No downloadable applications.");
//    }


        // This action may be wrapped in a task progress monitor
        Task task = (Task)request.getAttribute(TaskHttpServletRequest.ATTR_TASK);
        if(task != null && request.getAttribute(TaskHttpServletRequest.ATTR_TASK_PROGRESS_HANDLED_EXTERNALLY) == null) {
            TaskProgressBar bar = new TaskProgressBar("updateExtension", 0, (int)contentLength, 0);
            task.addProgressBar(bar);
            in = new TaskInputStream(bar, in);
            ((TaskInputStream)in).getProgressBar().setNote(new BundleActionMessage("extensions", "taskProgress.downloadExtension.note", id));
            task.configured();
        }           

    ExtensionBundle currentBundle = getExtensionBundle(id);
    if (currentBundle == null) {
      throw new ExtensionException(ExtensionException.INVALID_EXTENSION, id);
    }

    try {
      return updateExtension(currentBundle, in, request);
    } catch (ExtensionException ee) {
      CoreServlet.getServlet()
              .fireCoreEvent(new CoreEvent(this,
                      CoreEventConstants.UPDATE_EXTENSION,
                      null,
                      null,
                      CoreEvent.STATE_SUCCESSFUL).addAttribute(CoreAttributeConstants.EVENT_ATTR_EXTENSION_ID,
                                                currentBundle.getId())
                      .addAttribute(CoreAttributeConstants.EVENT_ATTR_EXTENSION_NAME, currentBundle.getName())
                      .addAttribute(CoreAttributeConstants.EVENT_ATTR_EXTENSION_VERSION,
                                                currentBundle.getVersion().toString()));
      throw ee;
    }
  }

  private ExtensionBundle updateExtension(ExtensionBundle currentBundle, InputStream in,
                      HttpServletRequest request) throws Exception {

    // Check host version
    Context context = ContextHolder.getContext();
    if (currentBundle.getRequiredHostVersion() != null && currentBundle.getRequiredHostVersion().compareTo(context.getVersion()) > 0) {
      throw new ExtensionException(ExtensionException.INSUFFICIENT_ADITO_HOST_VERSION,
                currentBundle.getId(),
                currentBundle.getRequiredHostVersion().toString());
    }

    boolean containsPlugin = currentBundle.isContainsPlugin();

    // Remove Extension Bundle;
    try {
      currentBundle.removeBundle();
      VERSION_PREFS.remove(currentBundle.getId());
    } catch (Exception e) {
      throw e;
    } finally {
      if (!containsPlugin) {
        extensionBundles.remove(currentBundle.getId());
        extensionBundlesList.remove(currentBundle);
        if (log.isInfoEnabled())
          log.info("Extension Zip file " + currentBundle.getId() + ".zip" + " has been deleted.");
      }
    }

    // Install Extension;
    streamToRepositoryStore(in, currentBundle.getId());
    RepositoryStore repStore = RepositoryFactory.getRepository().getStore(ARCHIVE_STORE);
    ZipExtract.extractZipFile(getExtensionStoreDirectory(), repStore.getEntryInputStream(currentBundle.getId() + ".zip"));

    if (containsPlugin) {
      currentBundle.setType(ExtensionBundle.TYPE_PENDING_UPDATE);
      fireBundleEvent(CoreEventConstants.UPDATE_EXTENSION, currentBundle);
      return currentBundle;
    } else {
      reload(currentBundle.getId());
      ExtensionBundle newBundle = getExtensionBundle(currentBundle.getId());
      installExtension(newBundle);
      postInstallExtension(newBundle, request);
      if (newBundle.getStatus().isStartedOrActivated()) {
        newBundle.stop();
        newBundle.start();
        newBundle.activate();
      }
      fireBundleEvent(CoreEventConstants.UPDATE_EXTENSION, newBundle);
      return newBundle;
    }
  }

  /**
   * Set the <i>Edition</i>, i.e. GPL, Community or Enterprise.
   *
   * @param currentEdition edition
   */
  public static void setCurrentEdition(String currentEdition) {
    ExtensionStore.currentEdition = currentEdition;
  }

  private LicenseAgreement getLicenseAgreement(final ExtensionBundle newBundle, final RepositoryStore repStore,
                          final File licenseFile, final ActionForward installedForward) {
    return new LicenseAgreement(newBundle.getName(), licenseFile, new LicenseAgreementCallback() {
      public void licenseAccepted(HttpServletRequest request) {
        // Dont care
      }

      public void licenseRejected(HttpServletRequest request) {
        // Remove the repository entry if it is in
        // use
        if (isRepositoryBacked()) {
          try {
            repStore.removeEntry(newBundle.getId() + ".zip");
          } catch (IOException ex) {
          }
        }

        // Remove the expanded bundle
        if (newBundle.getBaseDir().exists()) {
          Util.delTree(newBundle.getBaseDir());
        }

        // Reload the extension store
        try {
          reload(newBundle.getId());
        } catch (Exception e) {
          log.error("Failed to reload extension store.");
        }
      }
    }, installedForward);
  }

  private static boolean isNewerVersionAvailable(ExtensionBundle available, ExtensionBundle current) {
    VersionInfo.Version v1 = new VersionInfo.Version(available.getVersion().toString());
    VersionInfo.Version v2 = new VersionInfo.Version(current.getVersion().toString());
    return v1.compareTo(v2) > 0;
  }

  private static void streamToRepositoryStore(InputStream in, String bundleId) throws IOException {
    RepositoryStore repStore = RepositoryFactory.getRepository().getStore(ARCHIVE_STORE);
    OutputStream out = null;
    try {
      out = repStore.getEntryOutputStream(bundleId + ".zip");
      Util.copy(in, out);
    } finally {
      Util.closeStream(in);
      Util.closeStream(out);
    }
  }

  private void fireBundleEvent(int eventType, ExtensionBundle bundle) {
    String extensionType = getExtensionType(bundle);
    CoreServlet.getServlet()
            .fireCoreEvent(new CoreEvent(this, eventType, null, null, CoreEvent.STATE_SUCCESSFUL).addAttribute(CoreAttributeConstants.EVENT_ATTR_EXTENSION_ID,
              bundle.getId())
                    .addAttribute(CoreAttributeConstants.EVENT_ATTR_EXTENSION_NAME, bundle.getName())
                    .addAttribute(CoreAttributeConstants.EVENT_ATTR_EXTENSION_VERSION,
                      bundle.getVersion().toString())
                    .addAttribute(CoreAttributeConstants.EVENT_ATTR_EXTENSION_TYPE, extensionType));
  }

  private static String getExtensionType(ExtensionBundle bundle) {
    for (Iterator itr = bundle.iterator(); itr.hasNext();) {
      ExtensionDescriptor descriptor = (ExtensionDescriptor) itr.next();
      if (descriptor.getExtensionType() instanceof ExtensionType) {
        return descriptor.getExtensionType().getType();
      }
    }
    return null;
  }

  private void addAdditionalWebResource() {
    //
    String additionalWebResources = SystemProperties.get("adito.additionalWebResourceDirectories", "");
    if (additionalWebResources != null) {
      StringTokenizer t = new StringTokenizer(additionalWebResources, ",");
      while (t.hasMoreTokens()) {
        try {
          URL u = null;
          String dir = t.nextToken();
          if (dir.endsWith("]")) {
            int idx = dir.indexOf('[');
            if (idx != -1) {
              dir = dir.substring(0, idx);
              u = new File(dir).getCanonicalFile().toURL();
              log.warn("Associating additional web resource directories with plugins is no longer supported.");
            }
          }
          if (u == null) {
            u = new File(dir).getCanonicalFile().toURL();
          }
          ContextHolder.getContext().addResourceBase(u);
        } catch (Exception e) {
          log.error("Failed to add additional web resources directory.", e);
        }
      }
    }
  }

  private void addAdditionalClasspath() {

    // Add any additional class path elements
    StringTokenizer t = new StringTokenizer(SystemProperties.get("adito.additionalClasspath", ""), ",");
    while (t.hasMoreTokens()) {
      try {
        String sf = t.nextToken();
        File[] f = null;
        if (sf.endsWith("/*.jar")) {
          f = new File(sf.substring(0, sf.length() - 6)).listFiles(new FileFilter() {
            public boolean accept(File pathname) {
              return pathname.getName().toLowerCase().endsWith(".jar");
            }
          });
        } else {
          f = new File[1];
          f[0] = new File(sf);
        }
        for (int j = 0; f != null && j < f.length; j++) {
          if (f[j].exists() && (f[j].isDirectory() || f[j].getName().toLowerCase().endsWith(".jar"))) {
            URL u = f[j].toURL();
            ContextHolder.getContext().addContextLoaderURL(u);
          }
        }
      } catch (MalformedURLException murle) {
        log.warn("Invalid element in additional classpaths");
      }

    }
  }

  private void initialiseRepository() {
    RepositoryStore store = RepositoryFactory.getRepository().getStore("archives");
    // Remove the existing extensions
    if (basedir.exists()) {
      Util.delTree(basedir);
    }

    // Now recreate all extensions from the repository
    basedir.mkdirs();
    String[] archives = store.listEntries();
    for (int i = 0; i < archives.length; i++) {
      if (log.isInfoEnabled()) {
        log.info("Extracting archive " + archives[i]);
      }
      try {
        ZipExtract.extractZipFile(basedir, store.getEntryInputStream(archives[i]));
        if (log.isInfoEnabled()) {
          log.info("Completed archive extraction for extension " + archives[i]);
        }
      } catch (IOException ex) {
        log.error("Error extracting archive for extension " + archives[i], ex);
        Util.delTree(new File(basedir, archives[i]));
      }
    }
  }

  private void loadDevExtensions() {
    List<String> devExtensions = new ArrayList<String>();
    String extensionList = SystemProperties.get("adito.devExtensions", "");
    StringTokenizer t = new StringTokenizer(extensionList, ",");
    while (t.hasMoreTokens()) {
      String ext = t.nextToken();
      if (ext.equalsIgnoreCase("all")) {
        File f = new File(SystemProperties.get("user.dir")).getParentFile();
        File[] dirs = f.listFiles(new FileFilter() {
          public boolean accept(File pathname) {
            File f = new File(pathname, "extensions");
            return f.exists() && f.isDirectory();
          }
        });
        for (int i = 0; dirs != null && i < dirs.length; i++) {
          devExtensions.add(dirs[i].getName());
        }
      } else if (ext.equalsIgnoreCase("enterprise")) {
        File f = new File(SystemProperties.get("user.dir")).getParentFile();
        File[] dirs = f.listFiles(new FileFilter() {
          public boolean accept(File pathname) {
            File f = new File(pathname, "extensions");
            return f.exists() && f.isDirectory() && pathname.getName().indexOf("adito-enterprise-") != -1;
          }
        });
        for (int i = 0; dirs != null && i < dirs.length; i++) {
          devExtensions.add(dirs[i].getName());
        }
      } else if (ext.equalsIgnoreCase("community")) {
        File f = new File(SystemProperties.get("user.dir")).getParentFile();
        File[] dirs = f.listFiles(new FileFilter() {
          public boolean accept(File pathname) {
            File f = new File(pathname, "extensions");
            return f.exists() && f.isDirectory() && pathname.getName().indexOf("adito-community-") != -1;
          }
        });
        for (int i = 0; dirs != null && i < dirs.length; i++) {
          devExtensions.add(dirs[i].getName());
        }
      } else {
        if (ext.startsWith("!")) {
          devExtensions.remove(ext.substring(1));
        } else {
          devExtensions.add(ext);
        }
      }
    }

    for (Iterator it = devExtensions.iterator(); it.hasNext();) {
      String ext = (String) it.next();
      File d = new File(new File(SystemProperties.get("user.dir")).getParentFile(), ext);
      File extensionDir = new File(new File(d, "extensions"), d.getName());
      File extensionDescriptor = new File(extensionDir, "extension.xml");
      if (extensionDescriptor.exists()) {
        try {
          loadBundle(extensionDescriptor, true);
        } catch (Exception e) {
          log.error("Failed to load dev extension " + extensionDescriptor.getAbsolutePath(), e);
        }
      }
    }
  }

  class BundleComparator implements Comparator<ExtensionBundle> {
    public int compare(ExtensionBundle o1, ExtensionBundle o2) {
      int i = new Integer(o1.getOrder()).compareTo(new Integer(o2.getOrder()));
      return i == 0 ? o1.getId().compareTo(o2.getId()) : i;
    }
  }

}
TOP

Related Classes of com.adito.extensions.store.ExtensionStore

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.