/**
  * Checks whether the dependencies among the given Packs. Specifically it checks that no pack
  * point to a non existent pack and also that there are no circular dependencies in the packs.
  *
  * @param packs - List<Pack> representing the packs in the installation
  */
 public void checkDependencies(List packs) throws CompilerException {
   // Because we use package names in the configuration file we assosiate
   // the names with the objects
   Map names = new HashMap();
   for (int i = 0; i < packs.size(); i++) {
     PackInfo pack = (PackInfo) packs.get(i);
     names.put(pack.getPack().name, pack);
   }
   int result = dfs(packs, names);
   // @todo More informative messages to include the source of the error
   if (result == -2) parseError("Circular dependency detected");
   else if (result == -1) parseError("A dependency doesn't exist");
 }
  /**
   * Look for an IzPack resource either in the compiler jar, or within IZPACK_HOME. The path must
   * not be absolute. The path must use '/' as the fileSeparator (it's used to access the jar file).
   * If the resource is not found, a CompilerException is thrown indicating fault in the parent
   * element.
   *
   * @param path the relative path (using '/' as separator) to the resource.
   * @param desc the description of the resource used to report errors
   * @return a URL to the resource.
   */
  public URL findIzPackResource(String path, String desc) throws CompilerException {
    URL url = getClass().getResource("/" + path);
    if (url == null) {
      File resource = new File(path);
      if (!resource.isAbsolute()) resource = new File(IZPACK_HOME, path);

      if (!resource.exists()) // fatal
      parseError(desc + " not found: " + resource);

      try {
        url = resource.toURL();
      } catch (MalformedURLException how) {
        parseError(desc + "(" + resource + ")", how);
      }
    }

    return url;
  }
 /**
  * Returns a newly created instance of the output stream which should be used by this pack
  * compressor. This method do not declare the return value as FilterOutputStream although there
  * must be an constructor with a slave output stream as argument. This is done in this way because
  * some encoding streams from third party are only implemented as "normal" output stream.
  *
  * @param slave output stream to be used as slave
  * @return a newly created instance of the output stream which should be used by this pack
  *     compressor
  * @throws Exception
  */
 protected OutputStream getOutputInstance(OutputStream slave) throws Exception {
   if (needsBufferedOutputStream()) {
     slave = new BufferedOutputStream(slave);
   }
   Object[] params = resolveConstructorParams(slave);
   if (constructor == null) {
     loadClass(getEncoderClassName());
   }
   if (constructor == null) {
     return (null);
   }
   Object instance = null;
   instance = constructor.newInstance(params);
   if (!OutputStream.class.isInstance(instance)) {
     compiler.parseError(
         "'" + getEncoderClassName() + "' must be derived from " + OutputStream.class.toString());
   }
   return ((OutputStream) instance);
 }
  /**
   * Loads the given class from the previos setted container paths.
   *
   * @param className full qualified name of the class to be loaded
   * @throws Exception
   */
  public void loadClass(String className) throws Exception {
    if (getEncoderClassName() == null) {
      return;
    }
    Class<Object> encoder = null;
    if (getContainerPaths() == null) { // May be class files are in the compiler.jar.
      encoder = (Class<Object>) Class.forName(className);
    }
    if (encoder == null) {
      String[] rawPaths = getContainerPaths();
      URL[] uRLs = new URL[rawPaths.length];
      Object instance = null;
      int i;
      int j = 0;

      for (i = 0; i < rawPaths.length; ++i) {
        if (rawPaths[i] == null) {
          continue;
        }
        String jarPath = compiler.replaceProperties(rawPaths[i]);
        URL url = compiler.findIzPackResource(jarPath, "Pack compressor jar file");
        if (url != null) {
          uRLs[j++] = url;
          if (getClass().getResource("/" + jarPath)
              != null) { // Oops, standalone, URLClassLoader will not work ...
            // Write the jar to a temp file.
            InputStream in = null;
            FileOutputStream outFile = null;
            byte[] buffer = new byte[5120];
            File tf = null;
            try {
              tf = File.createTempFile("izpj", ".jar");
              tf.deleteOnExit();
              outFile = new FileOutputStream(tf);
              in = getClass().getResourceAsStream("/" + jarPath);
              long bytesCopied = 0;
              int bytesInBuffer;
              while ((bytesInBuffer = in.read(buffer)) != -1) {
                outFile.write(buffer, 0, bytesInBuffer);
                bytesCopied += bytesInBuffer;
              }
            } finally {
              if (in != null) {
                in.close();
              }
              if (outFile != null) {
                outFile.close();
              }
            }
            url = tf.toURL();
          }
        }
      }
      if (j > 0) {
        if (j < uRLs.length) {
          URL[] nurl = new URL[j];
          for (i = 0; i < j; ++i) {
            nurl[i] = uRLs[i];
          }
          uRLs = nurl;
        }
        // Use the class loader of the interface as parent, else
        // compile will fail at using it via an Ant task.
        URLClassLoader ucl = new URLClassLoader(uRLs, PackCompressor.class.getClassLoader());
        encoder = (Class<Object>) ucl.loadClass(className);
      }
    }

    if (encoder != null) {
      // Be aware, paramsClasses should be defined earlier! For
      // default in the constructor of this class.
      constructor = encoder.getDeclaredConstructor(paramsClasses);
    } else {
      compiler.parseError("Cannot find defined compressor " + className);
    }
  }