Package net.rim.tumbler.config

Source Code of net.rim.tumbler.config.FeatureManager$ExtensionInfo

/*
* Copyright 2010-2011 Research In Motion Limited.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.rim.tumbler.config;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Set;
import java.util.Vector;
import java.util.Map.Entry;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

import net.rim.tumbler.exception.PackageException;
import net.rim.tumbler.file.ExtensionDependencyManager;
import net.rim.tumbler.file.FileManager;
import net.rim.tumbler.file.Library;
import net.rim.tumbler.file.Library.Configuration;
import net.rim.tumbler.file.Library.Extension;
import net.rim.tumbler.file.Library.Jar;
import net.rim.tumbler.file.Library.Platform;
import net.rim.tumbler.file.Library.Src;
import net.rim.tumbler.file.Library.Target;
import net.rim.tumbler.log.LogType;
import net.rim.tumbler.log.Logger;
import net.rim.tumbler.session.BBWPProperties;
import net.rim.tumbler.session.SessionManager;
import net.rim.tumbler.xml.LibraryXMLParser;

public class FeatureManager {
    // TODO Hardcode platform="JAVA"
    private String                                _platform           = "JAVA";
    // TODO Hardcode target="default" until target becomes one of the command
    // line params in bbwp.exe
    private String                                _targetVersion      = "default";
    private HashSet< String >                     _requiredFeatures;
    // {featureId, paths & root library.xml info}
    private Hashtable< String, ExtensionInfo >    _repositoryFeatures;
    // {extensionId, paths & root library.xml info}
    private Hashtable< String, ExtensionInfo >    _extensionLookupTable;
    private HashSet< String >                     _resolvedPaths;    
    // By default, "ext" under Tumbler's home, configurable in bbwp.properties
    private String                                _repositoryDir;
    // Common folder contains shared common APIs, folder under _repositoryDir
    // for storing common API
    private String                                _commonAPIDir       = "common";
    private HashSet< String >                     _extensionClasses;
   
    private HashSet< String >                     _sharedGlobalJSFiles;
    private HashSet< String >                     _extensionJSFiles;
 
  // List of compiled JARs that the extensions might depend on
    private HashSet< String >                     _compiledJARDependencies;
   
    private HashSet< String >                     _curPaths           = new HashSet< String >();
    private HashSet< String >                     _commonAPIPaths     = new HashSet< String >();
    private File                                  _temporaryDirectory;
  // TODO Hardcode features that are not found in extension repository,
  // temporary workaround until widgetcache extension is moved out of
  // framework
  private static HashSet< String >              FRAMEWORK_FEATURES  = new HashSet< String >();

    private static final String                   TEMPORARY_DIRECTORY = "~temporaryextensionsource";
    private static final String                   EXTENSION_DIRECTORY = "extension";
    private static final String                   JS_DIRECTORY        = "WebWorksApplicationSharedJsRepository0";
    private static final String                   COMMON_JS_DIRECTORY = "sharedglobal";
    private static final String                   LIBRARY_XML         = "library.xml";
   
  /**
   * Stores the extension's library.xml information and the paths to source
   * code in repository.
   */
  public static class ExtensionInfo {
    private Library _lib;
    private HashSet<String> _javaPaths;
    private HashSet<String> _jarPaths;
    private HashSet<String> _jsPaths;
   
    private File _extensionFolder;

    public ExtensionInfo(Library lib, HashSet<String> javaPaths, HashSet<String> jsPaths) {
      _lib = lib;
      _javaPaths = javaPaths;
      _jsPaths = jsPaths;
    }

    public Library getLibrary() {
      return _lib;
    }
   
    /**
     * @return the extension id found in library.xml, or null if it is not
     *         defined
     */
    public String getExtensionId() {
      if (_lib != null && _lib.getExtension() != null) {
        return _lib.getExtension().getId();
      }

      return null;
    }

    public HashSet<String> getRepositoryJavaPaths() {
      return _javaPaths;
    }
   
    public HashSet<String> getRepositoryJavaScriptPaths() {
      return _jsPaths;
    }
   
    public HashSet<String> getCompiledJARPaths() {
      return _jarPaths;
    }
   
    public void addCompiledJARPath(String path) {
      if (_jarPaths == null) {
        _jarPaths = new HashSet<String>();
      }
     
      _jarPaths.add(path);
    }
   
    public void setExtensionFolder(File extFolder) {
      _extensionFolder = extFolder;
    }
   
    public File getExtensionFolder() {
      return _extensionFolder;
    }

    @Override
    public String toString() {
      StringBuffer buf = new StringBuffer();
      buf.append("{lib: ");
      buf.append(_lib);
      buf.append(", javaPaths: ");
      buf.append(_javaPaths);
      buf.append(", jsPaths: ");
      buf.append(_jsPaths);     
      buf.append("}");
      return buf.toString();
    }       
  }

  public FeatureManager(BBWPProperties bbwpProperties,
      Hashtable<WidgetAccess, Vector<WidgetFeature>> accessTable) {
    _repositoryFeatures = new Hashtable<String, ExtensionInfo>();
    _extensionLookupTable = new Hashtable<String, ExtensionInfo>();
    _resolvedPaths = new HashSet<String>();
    _repositoryDir = bbwpProperties.getRepositoryDir();
    _requiredFeatures = getRequiredFeatures(accessTable);
    _extensionClasses = new HashSet<String>();
    _compiledJARDependencies = new HashSet<String>();
    _sharedGlobalJSFiles = new HashSet<String>();
    _extensionJSFiles = new HashSet<String>();
   
    // TODO temp workaround, treat widgetcache features as exceptions
    // will not throw error when the code fails to find them in extension
    // repository   
    if (FRAMEWORK_FEATURES.isEmpty()) {
      FRAMEWORK_FEATURES.add("blackberry.widgetcache");
      FRAMEWORK_FEATURES.add("blackberry.widgetcache.CacheInformation");
    }
  }

  private static HashSet<String> getRequiredFeatures(
      Hashtable<WidgetAccess, Vector<WidgetFeature>> accessTable) {
    Set<WidgetAccess> keys = accessTable.keySet();
    HashSet<String> requiredFeatures = new HashSet<String>();

    for (Object accessKey : keys) {
      Vector<WidgetFeature> features = (Vector<WidgetFeature>) accessTable
          .get(accessKey);

      for (Object featureObject : features) {
        WidgetFeature feature = (WidgetFeature) featureObject;
        requiredFeatures.add(feature.getID());
      }
    }

    return requiredFeatures;
 
 
  /**
   * Given a WebWorks application archive, look at the features specified in
   * the white list and figure out all the extensions that need to be built.
   *
   * @param widgetArchive
   *            WebWorks application archive
   * @param extJars
   *            zip entries of JAR files found in the archive's "ext" folder
   * @return a set of file paths of the source code of all extensions that
   *         need to be built
   * @throws Exception
   *             if problems encountered while resolving extension
   *             dependencies
   */
  public HashSet<String> resolveFeatures(ZipFile widgetArchive,
      HashSet<ZipEntry> extJars) throws Exception {
    // step 1: resolve features from widget archive ext folder
    // if JAR files contribute to features from core API, JAR wins
    if (extJars != null && !extJars.isEmpty()) {
      resolveFeaturesFromExtJars(widgetArchive, extJars);
    }

    // step 2: resolve features from repository folder
    resolveFeaturesFromRepository();

    // step 3: copy common API files to extension folder for code to compile
    copyCommonAPI();

    return _resolvedPaths;
  }

  public HashSet<String> getExtensionClasses() {
    return _extensionClasses;
  }
 
  public HashSet<String> getExtensionJSFiles() {
    return _extensionJSFiles;
  }

  public HashSet<String> getSharedGlobalJSFiles() {
    return _sharedGlobalJSFiles;
  }
 
  /**
   * @return folders that need to be copied for common APIs
   */
  public HashSet<String> getCommonAPIPaths() {
    return _commonAPIPaths;
  }
 
  /**
   * @return
   */
  public HashSet<String> getCompiledJARDependencies() {
    return _compiledJARDependencies;
  }

  /**
   * Check JARs in widget archive's ext folder <br>
   * If required features are found in JARs, extract them to source folder <br>
   * Add paths in HashSet when done
   */
  private void resolveFeaturesFromExtJars(ZipFile widgetArchive,
      HashSet<ZipEntry> extJars) {
    if (_temporaryDirectory != null) {
            if (_temporaryDirectory.delete() == false) {
                Logger.logMessage(LogType.WARNING, "EXCEPTION_DELETING_DIRECTORY",
                        _temporaryDirectory.toString());
            }
    }
    _temporaryDirectory = new File(getTempExtensionPath());

    for (ZipEntry jarFile : extJars) {
      try {
        // uncompress the jar into folders
        File sourceExtension = unzipJarToTempDir(widgetArchive, jarFile);

        if (sourceExtension == null) {
                    Logger.logMessage(LogType.WARNING,
                            "EXCEPTION_FAILING_DECOMPRESS_JAR", jarFile.getName());
          return;
        }

        // parse features offered from ext JARs
        Hashtable<String, ExtensionInfo> eligibleFeatures = getEligibleFeatures(sourceExtension);

        // if any eligible ids exists, move the content of the temp dir
        // into a permanent location
        finalizeEligibleIDs(eligibleFeatures);
      } catch (Exception e) {
        e.printStackTrace();
      } finally {
        File[] tempExten = _temporaryDirectory.listFiles();

        for (File f : tempExten) {
          FileManager.deleteDirectory(f);
        }
      }
    }
   
    FileManager.deleteDirectory(_temporaryDirectory);
  }

  /*
   * Takes the jar, uncompress it to temp folder, then return its handle in
   * the temp folder
   */
  private File unzipJarToTempDir(ZipFile widgetArchive, ZipEntry jarFile)
      throws IOException {

    String extensionName = getExtensionName(jarFile.getName());
    File sourceExtensionJar = null;
    ZipFile zipFile = null;
    try {
      // first copy the zip entry into the extension folder and identify
      // it as a jar
      sourceExtensionJar = FileManager.copyZipEntry(widgetArchive,
          jarFile, getExtensionPath() + extensionName + ".jar");

      zipFile = new ZipFile(sourceExtensionJar);
      Enumeration<?> enu = zipFile.entries();

      // go through the jar, copy each entry into the temporary folder
      while (enu.hasMoreElements()) {
        ZipEntry zipEntry = (ZipEntry) enu.nextElement();
       
        if (zipEntry.isDirectory()) {
          continue;
        }
       
        FileManager.copyZipEntry(zipFile, zipEntry,
            getTempExtensionPath() + extensionName + File.separator);
      }
    } finally {
      if (zipFile != null) {
        zipFile.close();
      }

      if (sourceExtensionJar != null) {
              if (sourceExtensionJar.delete() == false) {
                  Logger.logMessage(LogType.WARNING,
                          "EXCEPTION_DELETING_FILE", sourceExtensionJar.toString());
              }
      }
    }

    File[] fileList = _temporaryDirectory.listFiles();
    for (File f : fileList) {
      if (extensionName.equals(f.getName())) {
        return f;
      }
    }

    return null;
  }

  private static String getExtensionName(String extensionName) {
    if (extensionName == null) {
      return null;
    }
    int fileTypePosition = extensionName.lastIndexOf(".jar");
    // the zip entry might look like "ext/xxx.jar" or "ext\xxx.jar"
    // if checking index of "/" gives -1, should check the index of "\"
    int fileSepPosition = extensionName.lastIndexOf("/");

    if (fileSepPosition < 0) {
      fileSepPosition = extensionName.lastIndexOf("\\");
    }
   
    if (fileTypePosition < 0) {           
      fileTypePosition = extensionName.length();
    }
    return extensionName.substring(fileSepPosition + 1, fileTypePosition);
  }

  private Hashtable<String, ExtensionInfo> getEligibleFeatures(
      File sourceExtension) {
    Hashtable<String, ExtensionInfo> eligibleFeatures = new Hashtable<String, ExtensionInfo>();

    File[] files = sourceExtension.listFiles();
    Hashtable<String, ExtensionInfo> availableFeatures = null;

    // library.xml should at top level
    for (File f : files) {
      if (f.getName().equalsIgnoreCase(LIBRARY_XML)) {
        try {
          availableFeatures = parseFeaturesInLibraryXML(f, true);
        } catch (Exception e) {
          return eligibleFeatures;
        }
       
        if (availableFeatures != null) {
          for (Entry<String, ExtensionInfo> entry : availableFeatures
              .entrySet()) {
            eligibleFeatures.put(entry.getKey(), entry.getValue());
          }
        }
      }
    }

    return eligibleFeatures;
  }

  @SuppressWarnings("unchecked")
    private void finalizeEligibleIDs(Hashtable<String, ExtensionInfo> eligibleFeatures) {
      for (Entry<String, ExtensionInfo> entry : eligibleFeatures.entrySet()) {
          String key = entry.getKey();
          ExtensionInfo value = entry.getValue();
          if (_requiredFeatures.contains(key)) {
              copyExtensionPathsToSourceDir(value.getRepositoryJavaPaths(), getExtensionPath(), null);
        _resolvedPaths.addAll((HashSet<String>) _curPaths.clone());
              _extensionClasses.add(value.getLibrary().getEntryClass());

        // remove features from the list, so that even if the feature is
        // available in repository, the repository version will not be used
              _requiredFeatures.remove(key);
          }
      }
  }
 
  private static HashSet<String> getJSRelativePaths(HashSet<String> fullPaths) {
    String relPath = null;
    HashSet<String> relativePaths = new HashSet<String>();
   
    for (String path : fullPaths) {
      relPath = new File(SessionManager.getInstance().getSourceFolder()).toURI().relativize(new File(path).toURI()).getPath();
      relativePaths.add(relPath);
    }
   
    return relativePaths;
  }

  /**
   * Resolve features from extension repository
   */
  @SuppressWarnings("unchecked")
  private void resolveFeaturesFromRepository() throws Exception {
    parseRepository();

    HashSet<String> extensions = new HashSet<String>();
   
    // derive extensions to be built based on features on white list
    for (String featureId : _requiredFeatures) {
      ExtensionInfo info = _repositoryFeatures.get(featureId);
     
      if (info != null) {
        String extensionId = info.getExtensionId();

        // unable to build app that uses feature from an extension that
        // does not have an id
        // because it is not possible to resolve dependencies
        if (extensionId != null && !extensionId.isEmpty()) {
          extensions.add(extensionId);
         
          // if the extension has any JAR dependencies, add it to the
          // list so that it gets added to rapc classpath
          if (info.getCompiledJARPaths() != null) {
            for (String jarPath : info.getCompiledJARPaths()) {
              File jarFile = new File(jarPath);
              _compiledJARDependencies.add(jarFile
                  .getAbsolutePath());
            }
          }
        } else {
          throw new PackageException(
              "EXCEPTION_NEED_FEATURE_FROM_UNIDENTIFIED_EXTENSION", featureId);
        }
      } else {
        // TODO temp workaround to not throw error when widgetcache
        // features cannot be found in repository
        if (!FRAMEWORK_FEATURES.contains(featureId)) {
          throw new PackageException("EXCEPTION_FEATURE_NOT_FOUND",
              featureId);
        }
      }
    }
   
    // find all extensions that need to be built with dependencies taken
    // into account
    ExtensionDependencyManager edm = new ExtensionDependencyManager(
        _extensionLookupTable);
    extensions = edm.resolveExtensions(extensions);
       
    for (String extensionId : extensions) {
      ExtensionInfo info = _extensionLookupTable.get(extensionId);
      HashSet<String> javaPaths = info.getRepositoryJavaPaths();
      copyExtensionPathsToSourceDir(javaPaths, getExtensionPath(), info.getExtensionFolder());
      _resolvedPaths.addAll((HashSet<String>) _curPaths.clone());
     
      HashSet<String> jsPaths = info.getRepositoryJavaScriptPaths();
      copyExtensionPathsToSourceDir(jsPaths, getJavaScriptPath()
          + File.separator
          + getEscapedEntryClass(info.getLibrary().getEntryClass())
          + File.separator, info.getExtensionFolder());
      _resolvedPaths.addAll((HashSet<String>) _curPaths.clone());
     
      _extensionJSFiles.addAll(getJSRelativePaths(_curPaths));
     
      // extension can be found in lookup table for sure, otherwise
      // exception would have been thrown in ExtensionDependencyManager.resolve
      Library lib = _extensionLookupTable.get(extensionId).getLibrary();
      _extensionClasses.add(lib.getEntryClass());
    }
  }
 
  @SuppressWarnings("unchecked")
  private void copyCommonAPI() {
    File dir = new File(_repositoryDir + File.separator + _commonAPIDir);   
    File[] files = dir.listFiles();
    boolean sharedGlobalJS = false;
   
    for (File f : files) {
      if (f.exists()) {
        try {
          File destFile = null;
         
          if (f.isDirectory() && f.getName().equals(COMMON_JS_DIRECTORY)) {
            destFile = new File(getJavaScriptPath() + f.getName());
            sharedGlobalJS = true;
          } else {
            destFile = new File(getExtensionPath() + f.getName());
          }
         
          _curPaths.clear();
          copyFiles(f, destFile);
          _commonAPIPaths
              .addAll((HashSet<String>) _curPaths.clone());
         
          if (sharedGlobalJS) {
            _sharedGlobalJSFiles = getJSRelativePaths(_curPaths);
          }
                } catch (IOException e) {
                    Logger.logMessage(LogType.ERROR, "EXCEPTION_IO_COPY_FILES",
                            new String[] {f.getAbsolutePath(), e.getMessage()});
                }
      }
    }
  }

  /**
   * For each folder in the extension repository, look for its library.xml and
   * parse it to resolve source file paths
   */
  private void parseRepository() {
    File dir = new File(_repositoryDir);

    if (dir.exists() && dir.isDirectory()) {
      File[] files = dir.listFiles();

      for (File f : files) {
        if (f.isDirectory()) {
          File[] extFiles = f.listFiles();

          for (File g : extFiles) {
            try {
              if (g.getName().equalsIgnoreCase(LIBRARY_XML)) {
                Hashtable<String, ExtensionInfo> features = parseFeaturesInLibraryXML(
                    g, false);
                if (features != null) {
                  _repositoryFeatures.putAll(features);
                }
              }
            } catch (Exception e) {
              // TODO handle error
            }
          }
        }
      }
    }
  }

  /**
   * Given a library file, find the configuration element that matches the
   * current platform and target
   *
   * @param lib
   * @return the configuration that matches the current platform and target
   */
  private Configuration getTargetConfiguration(Library lib) {
    String matchedConfigName = null;

    // check whether platform and target match what we support
    ArrayList<Platform> platforms = lib.getPlatforms();
    if (platforms != null) {
      for (Platform p : platforms) {
        if (p.getValue().equals(_platform)) {
          ArrayList<Target> targets = p.getTargets();

          if (targets != null) {
            for (Target t : targets) {
              if (t.getVersion().equals(_targetVersion)) {
                matchedConfigName = t.getConfigName();
              }
            }
          }
        }
      }
    }

    // make sure the config is defined
    if (matchedConfigName != null) {
      ArrayList<Configuration> configurations = lib.getConfigurations();

      for (Configuration config : configurations) {
        if (config.getName().equals(matchedConfigName)) {
          return config;
        }
      }
    }

    return null;
  }

  /**
   * Helper method for parsing out library.xml into an object
   *
   * @param libraryXML
   * @throws Exception
   */
  private static Library parseLibraryXML(File libraryXML) throws Exception {
    LibraryXMLParser parser = new LibraryXMLParser();
    return parser.parseXML(libraryXML.getAbsolutePath());
  }

  /**
   * Parse a given a library.xml to find out the features it offers and store
   * the proper set of source file paths for the current platform and target
   *
   * @param libraryXML
   *            library.xml file, cannot be null
   * @param allowBackwardCompatibility
   *            true if it's parsing library.xml from an extension JAR
   * @return hashtable that contains feature id's and the paths for the source
   *         files, or null if (1) library.xml is malformed, (2) if
   *         allowBackwardCompatibility is false, and <target>,
   *         <configuration>, <platform> or <src> is not specified correctly
   * @throws Exception
   */
  private Hashtable<String, ExtensionInfo> parseFeaturesInLibraryXML(
      File libraryXML, boolean allowBackwardCompatibility) throws Exception {
    Library lib = parseLibraryXML(libraryXML);
   
    if (lib == null) {
      return null;
    }   
   
    ArrayList<WidgetFeature> features = lib.getFeatures();
    HashSet<String> javaPaths = new HashSet<String>();
    HashSet<String> jsPaths = new HashSet<String>();
    Hashtable<String, ExtensionInfo> availableFeatures = new Hashtable<String, ExtensionInfo>();   
   
    if (allowBackwardCompatibility) {
      // have to work for library.xml that doesn't contain configuration and platform elements
      File[] files = _temporaryDirectory.listFiles();
     
      for (File f : files) {
        javaPaths.add(f.getAbsolutePath());
      }       
    } else {
      ExtensionInfo info = new ExtensionInfo(lib, javaPaths, jsPaths);
      boolean extensionIdFound = false;
     
      if (lib.getExtension() != null) {
        Extension extension = lib.getExtension();
        String id = extension.getId();

        if (id != null && !id.isEmpty()) {
          if (_extensionLookupTable.contains(id)) {
            // more than one library.xml contain the same extension id
            Logger.logMessage(LogType.WARNING,
                "VALIDATION_EXTENSION_DEFINED_MORE_THAN_ONCE",
                new String[] { id });
          }
             
          _extensionLookupTable.put(id, info);
         
          info.setExtensionFolder(libraryXML.getParentFile());
         
          extensionIdFound = true;
        }
      }
     
      if (!extensionIdFound) {
        // not considered an error, this extension might not be used
        // by the app being compiled
        Logger.logMessage(LogType.WARNING,
            "VALIDATION_LIBRARYXML_EXTENSION_ID_NOT_DEFINED",
            new String[] { libraryXML.getAbsolutePath() });
      }     
     
      Configuration config = getTargetConfiguration(lib);
     
      if (config == null) {
                Logger.logMessage(LogType.WARNING, "VALIDATION_LIBRARYXML_NO_CONFIG",
                        new String[] { libraryXML.getAbsolutePath() });
                return null;
      }

      ArrayList<Src> src = config.getSrc();

      if (src == null || src.isEmpty()) {
                Logger.logMessage(LogType.WARNING, "VALIDATION_LIBRARYXML_NO_SRC",
                    new String[] { libraryXML.getAbsolutePath() });
                return null;
      }

      File extensionDir = libraryXML.getParentFile();

      for (Src s : src) {
        String path = s.getPath();
       
        if (s.getType().equalsIgnoreCase("text/java")) {
          javaPaths.add(extensionDir.getAbsolutePath() + File.separator
              + path);
        } else if (s.getType().equalsIgnoreCase("text/javascript")) {
          jsPaths.add(extensionDir.getAbsolutePath() + File.separator
              + path);
        }
      }
    }

    ExtensionInfo info = new ExtensionInfo(lib, javaPaths, jsPaths);
   
    for (WidgetFeature feature : features) {
      availableFeatures.put(feature.getID(), info);
    }
   
    if (lib.getCompiledJARDependencies() != null) {
      for (Jar j : lib.getCompiledJARDependencies()) {
        String path = j.getPath();
        File temp = new File(path);
       
        if (temp.isAbsolute()) {
          info.addCompiledJARPath(path);
        } else {
          info.addCompiledJARPath(libraryXML.getParentFile()
              .getAbsolutePath()
              + File.separator + path);
        }
      }
    }
   
    return availableFeatures;
  }

  private static String getExtensionPath() {
    return SessionManager.getInstance().getSourceFolder() + File.separator
        + EXTENSION_DIRECTORY + File.separator;
  }
 
  private static String getJavaScriptPath() {
    return SessionManager.getInstance().getSourceFolder() + File.separator
        + JS_DIRECTORY + File.separator;
  }

  private static String getTempExtensionPath() {
    return SessionManager.getInstance().getSourceFolder()
        + TEMPORARY_DIRECTORY + File.separator;
  }
 
  // simply replace all occurrences of "." with "_"
  private static String getEscapedEntryClass(String entryClass) {
    return entryClass.replace(".", "_");
  }

  private void copyExtensionPathsToSourceDir(HashSet<String> paths, String destDir, File extensionFolder) {
    _curPaths.clear();

    for (String path : paths) {
      File file = new File(path);
      String relativePath = "";
     
      if (extensionFolder != null) {
        relativePath = extensionFolder.toURI().relativize(file.getParentFile().toURI()).getPath();
        relativePath += File.separator;
      }

      if (file.exists()) {
        try {
          copyFiles(file, new File(
              destDir + relativePath + file.getName()));
        } catch (IOException e) {
                    Logger.logMessage(LogType.ERROR, "EXCEPTION_IO_COPY_FILES",
                            new String[] {file.getAbsolutePath(), e.getMessage()});
        }
      }
    }
  }

  /**
   * This method copies file recursively from src to dest
   */
  private void copyFiles(File src, File dest) throws IOException {
    // Check to ensure that the source is valid
    if (!src.exists()) {
      throw new IOException("copyFiles: Cannot find source: "
          + src.getAbsolutePath() + ".");
    } else if (!src.canRead()) {
      // check to ensure we have rights to the source
      throw new IOException("copyFiles: No right to read source: "
          + src.getAbsolutePath() + ".");
    }

    // is this a directory copy?
    if (src.isDirectory()) {
      if (!dest.exists()) { // does the destination already exist?
        // if not we need to make it exist if possible (note this is
        // mkdirs not mkdir)
        if (!dest.mkdirs()) {
          throw new IOException(
              "copyFiles: Could not create direcotry: "
                  + dest.getAbsolutePath() + ".");
        }
      }

      String list[] = src.list();
      // copy all the files in the list.
      for (String path : list) {
        File dest1 = new File(dest, path);
        File src1 = new File(src, path);
        copyFiles(src1, dest1);
      }
    } else {
      // This was not a directory, just copy the file
      try {
        if (!dest.getParentFile().exists()) {
          dest.getParentFile().mkdirs();
        }
       
        // open the files for input and output
        FileManager.copyFile(src, dest);
        _curPaths.add(dest.getAbsolutePath());
      } catch (IOException e) { // Error copying file
        IOException wrapper = new IOException(
            "copyFiles: Unable to copy file: "
                + src.getAbsolutePath() + " to "
                + dest.getAbsolutePath() + ".");
        wrapper.initCause(e);
        wrapper.setStackTrace(e.getStackTrace());
        throw wrapper;
      }
    }
  }
}
TOP

Related Classes of net.rim.tumbler.config.FeatureManager$ExtensionInfo

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.