/** {@inheritDoc} */
  public VirtualFile decompile(DecompilationDescriptor descriptor, DecompilationContext context)
      throws DecompilationException {
    LOG.debug("About to decompile");

    VirtualFile decompiledFile = null;
    try {
      boolean prepared =
          classPreparers.get(descriptor.getClassPathType()).execute(context, descriptor);

      if (prepared) {
        ConsoleContext consoleContext = context.getConsoleContext();
        File targetClass = descriptor.getSourceFile(context.getTargetDirectory());

        StringBuilder command = new StringBuilder(context.getCommand());

        String path = targetClass.getAbsolutePath();
        if (path.indexOf(' ') != -1) {
          path = "\"" + path + "\"";
        }
        command.append(path);
        consoleContext.addMessage(
            ConsoleEntryType.DECOMPILATION_OPERATION, "message.executing-jad", command.toString());

        try {
          OperationStatus status = setup(descriptor, context);
          if (status == OperationStatus.CONTINUE) {
            ByteArrayOutputStream output = new ByteArrayOutputStream();
            ByteArrayOutputStream err = new ByteArrayOutputStream();
            ResultType resultType = runExternalDecompiler(command.toString(), context, output, err);

            // occasionally the result will be empty - there's no point in endlessly
            // decompiling, so it gives a couple of more chances
            int count = 0;
            while (output.size() == 0 && count++ < 3) {
              consoleContext.addMessage(
                  ConsoleEntryType.DECOMPILATION_OPERATION,
                  "message.reexecuting-jad",
                  command.toString());
              resultType = runExternalDecompiler(command.toString(), context, output, err);
            }
            decompiledFile =
                getDecompilationAftermathHandler(resultType)
                    .execute(context, descriptor, targetClass, output, err);
          }
        } catch (IOException e) {
          throw new DecompilationException(e);
        } catch (InterruptedException e) {
          throw new DecompilationException(e);
        }
      }
    } finally {
      FileUtil.delete(context.getTargetDirectory());
    }

    return decompiledFile;
  }
 /**
  * Extract the class files from the library to the target directory.
  *
  * @param jarFile the library containing the class files
  * @param context the context
  * @param decompilationDescriptor the decompilation descriptor
  * @throws DecompilationException if an error occurs extracting the class files
  */
 private void extractClassFiles(
     VirtualFile jarFile,
     DecompilationContext context,
     DecompilationDescriptor decompilationDescriptor)
     throws DecompilationException {
   try {
     JarFile lib = JarFileSystem.getInstance().getJarFile(jarFile);
     context
         .getConsoleContext()
         .addMessage(ConsoleEntryType.JAR_OPERATION, "message.examining", jarFile.getPath());
     JarExtractor jarExtractor = new JarExtractor();
     jarExtractor.extract(
         context,
         lib,
         decompilationDescriptor.getPackageNameAsPath(),
         decompilationDescriptor.getClassName());
   } catch (IOException e) {
     throw new DecompilationException(e);
   }
 }