public AbstractPipelineOutput execute(final AbstractPipelineInput input) throws DITAOTException {
    if (logger == null) {
      throw new IllegalStateException("Logger not set");
    }
    final Date startTime = TimingUtils.getNowTime();

    try {
      logger.logInfo(moduleStartMsg);
      parseInputParameters(input);

      // set grammar pool flag
      GrammarPoolManager.setGramCache(gramcache);

      reader = new GenListModuleReader();
      reader.setLogger(logger);
      reader.initXMLReader(ditaDir, xmlValidate, rootFile, setSystemid);
      final FilterUtils filterUtils = parseFilterFile();
      reader.setFilterUtils(filterUtils);
      reader.setOutputUtils(outputUtils);

      addToWaitList(inputFile);
      processWaitList();
      // Depreciated function
      // The base directory does not change according to the referenceing
      // topic files in the new resolution
      updateBaseDirectory();
      refactoringResult();
      outputResult();
      schemekeydef.writeEndDocument();
      schemekeydef.close();
      // Added by William on 2009-06-25 for req #12014 start
      // write the end tag
      export.write("</stub>");
      // close the steam
      export.close();
      // Added by William on 2009-06-25 for req #12014 end
    } catch (final DITAOTException e) {
      throw e;
    } catch (final SAXException e) {
      throw new DITAOTException(e.getMessage(), e);
    } catch (final Exception e) {
      throw new DITAOTException(e.getMessage(), e);
    } finally {

      logger.logInfo(moduleEndMsg + TimingUtils.reportElapsedTime(startTime));
    }

    return null;
  }
  /**
   * Write result files.
   *
   * @throws DITAOTException if writing result files failed
   */
  private void outputResult() throws DITAOTException {
    final File dir = new File(tempDir);
    if (!dir.exists()) {
      dir.mkdirs();
    }

    Job prop = null;
    try {
      prop = new Job(dir);
    } catch (final IOException e) {
      throw new DITAOTException("Failed to create empty job: " + e.getMessage(), e);
    }

    prop.setProperty(INPUT_DIR, baseInputDir);
    prop.setProperty(INPUT_DITAMAP, prefix + inputFile);

    prop.setProperty(INPUT_DITAMAP_LIST_FILE_LIST, USER_INPUT_FILE_LIST_FILE);
    final File inputfile = new File(tempDir, USER_INPUT_FILE_LIST_FILE);
    Writer bufferedWriter = null;
    try {
      bufferedWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(inputfile)));
      bufferedWriter.write(prefix + inputFile);
      bufferedWriter.flush();
    } catch (final FileNotFoundException e) {
      logger.logException(e);
    } catch (final IOException e) {
      logger.logException(e);
    } finally {
      if (bufferedWriter != null) {
        try {
          bufferedWriter.close();
        } catch (final IOException e) {
          logger.logException(e);
        }
      }
    }

    // add out.dita.files,tempdirToinputmapdir.relative.value to solve the
    // output problem
    relativeValue = prefix;
    formatRelativeValue = formatRelativeValue(relativeValue);
    prop.setProperty("tempdirToinputmapdir.relative.value", formatRelativeValue);

    prop.setProperty("uplevels", getUpdateLevels());
    addSetToProperties(prop, OUT_DITA_FILES_LIST, outDitaFilesSet);

    addSetToProperties(prop, FULL_DITAMAP_TOPIC_LIST, ditaSet);
    addSetToProperties(prop, FULL_DITA_TOPIC_LIST, fullTopicSet);
    addSetToProperties(prop, FULL_DITAMAP_LIST, fullMapSet);
    addSetToProperties(prop, HREF_DITA_TOPIC_LIST, hrefTopicSet);
    addSetToProperties(prop, CONREF_LIST, conrefSet);
    addSetToProperties(prop, IMAGE_LIST, imageSet);
    addSetToProperties(prop, FLAG_IMAGE_LIST, flagImageSet);
    addSetToProperties(prop, HTML_LIST, htmlSet);
    addSetToProperties(prop, HREF_TARGET_LIST, hrefTargetSet);
    addSetToProperties(prop, HREF_TOPIC_LIST, hrefWithIDSet);
    addSetToProperties(prop, CHUNK_TOPIC_LIST, chunkTopicSet);
    addSetToProperties(prop, SUBJEC_SCHEME_LIST, schemeSet);
    addSetToProperties(prop, CONREF_TARGET_LIST, conrefTargetSet);
    addSetToProperties(prop, COPYTO_SOURCE_LIST, copytoSourceSet);
    addSetToProperties(prop, SUBSIDIARY_TARGET_LIST, subsidiarySet);
    addSetToProperties(prop, CONREF_PUSH_LIST, conrefpushSet);
    addSetToProperties(prop, KEYREF_LIST, keyrefSet);
    addSetToProperties(prop, CODEREF_LIST, coderefSet);

    // @processing-role
    addSetToProperties(prop, RESOURCE_ONLY_LIST, resourceOnlySet);

    addFlagImagesSetToProperties(prop, REL_FLAGIMAGE_LIST, relFlagImagesSet);

    // Convert copyto map into set and output
    final Set<String> copytoSet = new HashSet<String>(INT_128);
    for (final Map.Entry<String, String> entry : copytoMap.entrySet()) {
      copytoSet.add(entry.toString());
    }
    addSetToProperties(prop, COPYTO_TARGET_TO_SOURCE_MAP_LIST, copytoSet);
    addKeyDefSetToProperties(prop, KEY_LIST, keysDefMap.values());

    try {
      logger.logInfo("Serializing job specification");
      prop.write();
    } catch (final IOException e) {
      throw new DITAOTException(
          "Failed to serialize job configuration files: " + e.getMessage(), e);
    }

    // Output relation-graph
    writeMapToXML(reader.getRelationshipGrap(), FILE_NAME_SUBJECT_RELATION);
    // Output topic-scheme dictionary
    writeMapToXML(this.schemeDictionary, FILE_NAME_SUBJECT_DICTIONARY);

    // added by Willam on 2009-07-17 for req #12014 start
    if (INDEX_TYPE_ECLIPSEHELP.equals(transtype)) {
      // Output plugin id
      final File pluginIdFile = new File(tempDir, FILE_NAME_PLUGIN_XML);
      final DelayConrefUtils delayConrefUtils = new DelayConrefUtils();
      delayConrefUtils.writeMapToXML(reader.getPluginMap(), pluginIdFile);
      // write the result into the file
      final StringBuffer result = reader.getResult();
      try {
        export.write(result.toString());
      } catch (final IOException e) {
        logger.logException(e);
      }
    }
    // added by Willam on 2009-07-17 for req #12014 end

  }
  private void processFile(String currentFile) throws DITAOTException {
    File fileToParse;
    final File file = new File(currentFile);
    if (file.isAbsolute()) {
      fileToParse = file;
      currentFile = FileUtils.getRelativePath(rootFile, currentFile);
    } else {
      fileToParse = new File(baseInputDir, currentFile);
    }
    try {
      fileToParse = fileToParse.getCanonicalFile();
    } catch (final IOException e1) {
      logger.logError(e1.toString());
    }
    logger.logInfo("Processing " + fileToParse.getAbsolutePath());
    String msg = null;
    final Properties params = new Properties();
    params.put("%1", currentFile);

    if (!fileToParse.exists()) {
      logger.logError(MessageUtils.getMessage("DOTX008E", params).toString());
      return;
    }
    try {
      if (FileUtils.isValidTarget(currentFile.toLowerCase())) {
        reader.setTranstype(transtype);
        reader.setCurrentDir(new File(currentFile).getParent());
        reader.parse(fileToParse);

      } else {
        // edited by Alan on Date:2009-11-02 for Work Item:#1590 start
        // logger.logWarn("Input file name is not valid DITA file name.");
        final Properties prop = new Properties();
        prop.put("%1", fileToParse);
        logger.logWarn(MessageUtils.getMessage("DOTJ053W", params).toString());
        // edited by Alan on Date:2009-11-02 for Work Item:#1590 end
      }

      // don't put it into dita.list if it is invalid
      if (reader.isValidInput()) {
        processParseResult(currentFile);
        categorizeCurrentFile(currentFile);
      } else if (!currentFile.equals(inputFile)) {
        logger.logWarn(MessageUtils.getMessage("DOTJ021W", params).toString());
      }
    } catch (final SAXParseException sax) {

      // To check whether the inner third level is DITAOTBuildException
      // :FATALERROR
      final Exception inner = sax.getException();
      if (inner != null && inner instanceof DITAOTException) { // second
        // level
        logger.logInfo(inner.getMessage());
        throw (DITAOTException) inner;
      }
      if (currentFile.equals(inputFile)) {
        // stop the build if exception thrown when parsing input file.
        final MessageBean msgBean = MessageUtils.getMessage("DOTJ012F", params);
        msg = MessageUtils.getMessage("DOTJ012F", params).toString();
        msg = new StringBuffer(msg).append(":").append(sax.getMessage()).toString();
        throw new DITAOTException(msgBean, sax, msg);
      }
      final StringBuffer buff = new StringBuffer();
      msg = MessageUtils.getMessage("DOTJ013E", params).toString();
      buff.append(msg).append(LINE_SEPARATOR).append(sax.getMessage());
      logger.logError(buff.toString());
    } catch (final Exception e) {

      if (currentFile.equals(inputFile)) {
        // stop the build if exception thrown when parsing input file.
        final MessageBean msgBean = MessageUtils.getMessage("DOTJ012F", params);
        msg = MessageUtils.getMessage("DOTJ012F", params).toString();
        msg = new StringBuffer(msg).append(":").append(e.getMessage()).toString();
        throw new DITAOTException(msgBean, e, msg);
      }
      final StringBuffer buff = new StringBuffer();
      msg = MessageUtils.getMessage("DOTJ013E", params).toString();
      buff.append(msg).append(LINE_SEPARATOR).append(e.getMessage());
      logger.logError(buff.toString());
    }

    if (!reader.isValidInput() && currentFile.equals(inputFile)) {

      if (xmlValidate == true) {
        // stop the build if all content in the input file was filtered
        // out.
        msg = MessageUtils.getMessage("DOTJ022F", params).toString();
        throw new DITAOTException(msg);
      } else {
        // stop the build if the content of the file is not valid.
        msg = MessageUtils.getMessage("DOTJ034F", params).toString();
        throw new DITAOTException(msg);
      }
    }

    doneList.add(currentFile);
    reader.reset();
  }