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;
  }
  private void processParseResult(String currentFile) {
    final Map<String, String> cpMap = reader.getCopytoMap();
    final Map<String, KeyDef> kdMap = reader.getKeysDMap();
    // Added by William on 2010-06-09 for bug:3013079 start
    // the reader's reset method will clear the map.
    final Map<String, String> exKdMap = reader.getExKeysDefMap();
    exKeyDefMap.putAll(exKdMap);
    // Added by William on 2010-06-09 for bug:3013079 end

    // Category non-copyto result and update uplevels accordingly
    for (final String file : reader.getNonCopytoResult()) {
      categorizeResultFile(file);
      updateUplevels(file);
    }

    // Update uplevels for copy-to targets, and store copy-to map.
    // Note: same key(target) copy-to will be ignored.
    for (final String key : cpMap.keySet()) {
      final String value = cpMap.get(key);

      if (copytoMap.containsKey(key)) {
        // edited by Alan on Date:2009-11-02 for Work Item:#1590 start
        /*
         * StringBuffer buff = new StringBuffer();
         * buff.append("Copy-to task [href=\""); buff.append(value);
         * buff.append("\" copy-to=\""); buff.append(key);
         * buff.append("\"] which points to another copy-to target");
         * buff.append(" was ignored.");
         * logger.logWarn(buff.toString());
         */
        final Properties prop = new Properties();
        prop.setProperty("%1", value);
        prop.setProperty("%2", key);
        logger.logWarn(MessageUtils.getMessage("DOTX065W", prop).toString());
        // edited by Alan on Date:2009-11-02 for Work Item:#1590 end
        ignoredCopytoSourceSet.add(value);
      } else {
        updateUplevels(key);
        copytoMap.put(key, value);
      }
    }
    // TODO Added by William on 2009-06-09 for scheme key bug(497)
    schemeSet.addAll(reader.getSchemeRefSet());

    // collect key definitions
    for (final String key : kdMap.keySet()) {
      // key and value.keys will differ when keydef is a redirect to another keydef
      final KeyDef value = kdMap.get(key);
      if (keysDefMap.containsKey(key)) {
        // if there already exists duplicated key definition in
        // different map files.
        // Should only emit this if in a debug mode; comment out for now
        /*
         * Properties prop = new Properties(); prop.put("%1", key);
         * prop.put("%2", value); prop.put("%3", currentFile); logger
         * .logInfo(MessageUtils.getMessage("DOTJ048I",
         * prop).toString());
         */
      } else {
        updateUplevels(key);
        // add the ditamap where it is defined.
        /*
         * try { keydef.write("<keydef ");
         * keydef.write("keys=\""+key+"\" ");
         * keydef.write("href=\""+value+"\" ");
         * keydef.write("source=\""+currentFile+"\"/>");
         * keydef.write("\n"); keydef.flush(); } catch (IOException e) {
         *
         * logger.logException(e); }
         */
        keysDefMap.put(key, new KeyDef(key, value.href, currentFile));
      }
      // TODO Added by William on 2009-06-09 for scheme key bug(532-547)
      // if the current file is also a schema file
      if (schemeSet.contains(currentFile)) {
        // write the keydef into the scheme keydef file
        try {
          schemekeydef.writeStartElement(ELEMENT_KEYDEF);
          schemekeydef.writeAttribute(ATTRIBUTE_KEYS, key);
          if (value.href != null) {
            schemekeydef.writeAttribute(ATTRIBUTE_HREF, value.href);
          }
          schemekeydef.writeAttribute(ATTRIUBTE_SOURCE, currentFile);
          schemekeydef.writeEndElement();
        } catch (final SAXException e) {
          logger.logException(e);
        }
      }
    }

    hrefTargetSet.addAll(reader.getHrefTargets());
    hrefWithIDSet.addAll(reader.getHrefTopicSet());
    chunkTopicSet.addAll(reader.getChunkTopicSet());
    // schemeSet.addAll(reader.getSchemeRefSet());
    conrefTargetSet.addAll(reader.getConrefTargets());
    nonConrefCopytoTargetSet.addAll(reader.getNonConrefCopytoTargets());
    ignoredCopytoSourceSet.addAll(reader.getIgnoredCopytoSourceSet());
    subsidiarySet.addAll(reader.getSubsidiaryTargets());
    outDitaFilesSet.addAll(reader.getOutFilesSet());
    resourceOnlySet.addAll(reader.getResourceOnlySet());

    // Generate topic-scheme dictionary
    if (reader.getSchemeSet() != null && reader.getSchemeSet().size() > 0) {
      Set<String> children = null;
      children = this.schemeDictionary.get(currentFile);
      if (children == null) {
        children = new HashSet<String>();
      }
      children.addAll(reader.getSchemeSet());
      // for Linux support
      currentFile = FileUtils.separatorsToUnix(currentFile);

      this.schemeDictionary.put(currentFile, children);
      final Set<String> hrfSet = reader.getHrefTargets();
      for (final String f : hrfSet) {
        // for Linux support
        final String filename = FileUtils.separatorsToUnix(f);

        children = this.schemeDictionary.get(filename);
        if (children == null) {
          children = new HashSet<String>();
        }
        children.addAll(reader.getSchemeSet());
        this.schemeDictionary.put(filename, children);
      }
    }
  }
  private void parseInputParameters(final AbstractPipelineInput input) {
    final String basedir = input.getAttribute(ANT_INVOKER_PARAM_BASEDIR);
    final String ditaInput = input.getAttribute(ANT_INVOKER_PARAM_INPUTMAP);

    tempDir = input.getAttribute(ANT_INVOKER_PARAM_TEMPDIR);
    ditaDir = input.getAttribute(ANT_INVOKER_EXT_PARAM_DITADIR);
    ditavalFile = input.getAttribute(ANT_INVOKER_PARAM_DITAVAL);
    xmlValidate = Boolean.valueOf(input.getAttribute(ANT_INVOKER_EXT_PARAM_VALIDATE));

    // Added by William on 2009-07-18 for req #12014 start
    // get transtype
    transtype = input.getAttribute(ANT_INVOKER_EXT_PARAM_TRANSTYPE);
    // Added by William on 2009-07-18 for req #12014 start

    gramcache = "yes".equalsIgnoreCase(input.getAttribute(ANT_INVOKER_EXT_PARAM_GRAMCACHE));
    setSystemid = "yes".equalsIgnoreCase(input.getAttribute(ANT_INVOKER_EXT_PARAN_SETSYSTEMID));

    // For the output control
    outputUtils = new OutputUtils();
    outputUtils.setGeneratecopyouter(input.getAttribute(ANT_INVOKER_EXT_PARAM_GENERATECOPYOUTTER));
    outputUtils.setOutterControl(input.getAttribute(ANT_INVOKER_EXT_PARAM_OUTTERCONTROL));
    outputUtils.setOnlyTopicInMap(input.getAttribute(ANT_INVOKER_EXT_PARAM_ONLYTOPICINMAP));

    // Set the OutputDir
    final File path = new File(input.getAttribute(ANT_INVOKER_EXT_PARAM_OUTPUTDIR));
    if (path.isAbsolute()) {
      outputUtils.setOutputDir(path.getAbsolutePath());
    } else {
      throw new IllegalArgumentException("Output directory " + tempDir + " must be absolute");
    }

    // Resolve relative paths base on the basedir.
    File inFile = new File(ditaInput);
    if (!inFile.isAbsolute()) {
      // XXX Shouldn't this be resolved to current directory, not Ant script base directory?
      inFile = new File(basedir, ditaInput);
    }
    try {
      inFile = inFile.getCanonicalFile();
    } catch (final IOException e1) {
      logger.logException(e1);
    }
    if (!new File(tempDir).isAbsolute()) {
      throw new IllegalArgumentException("Temporary directory " + tempDir + " must be absolute");
    } else {
      tempDir = FileUtils.normalize(tempDir);
    }
    if (!new File(ditaDir).isAbsolute()) {
      throw new IllegalArgumentException(
          "DITA-OT installation directory " + tempDir + " must be absolute");
    } else {
      ditaDir = FileUtils.normalize(ditaDir);
    }
    if (ditavalFile != null && !new File(ditavalFile).isAbsolute()) {
      // XXX Shouldn't this be resolved to current directory, not Ant script base directory?
      ditavalFile = new File(basedir, ditavalFile).getAbsolutePath();
    }

    baseInputDir = new File(inFile.getAbsolutePath()).getParent();
    baseInputDir = FileUtils.normalize(baseInputDir);

    rootFile = inFile.getAbsolutePath();
    rootFile = FileUtils.normalize(rootFile);

    inputFile = inFile.getName();
    try {
      // Added by William on 2009-06-09 for scheme key bug
      // create the keydef file for scheme files
      schemekeydef =
          XMLSerializer.newInstance(new FileOutputStream(new File(tempDir, "schemekeydef.xml")));
      schemekeydef.writeStartDocument();
      schemekeydef.writeStartElement(ELEMENT_STUB);

      // Added by William on 2009-06-25 for req #12014 start
      // create the export file for exportanchors
      // write the head
      export =
          new OutputStreamWriter(new FileOutputStream(new File(tempDir, FILE_NAME_EXPORT_XML)));
      export.write(XML_HEAD);
      export.write("<stub>");
      // Added by William on 2009-06-25 for req #12014 end
    } catch (final FileNotFoundException e) {
      logger.logException(e);
    } catch (final IOException e) {
      logger.logException(e);
    } catch (final SAXException e) {
      logger.logException(e);
    }

    // Set the mapDir
    outputUtils.setInputMapPathName(inFile.getAbsolutePath());
  }
 /**
  * Write key definition XML configuration file
  *
  * @param keydefFile key definition file
  * @param keydefs list of key definitions
  * @throws DITAOTException if writing configuration file failed
  */
 public static void writeKeydef(final File keydefFile, final Collection<KeyDef> keydefs)
     throws DITAOTException {
   XMLSerializer keydef = null;
   try {
     keydef = XMLSerializer.newInstance(new FileOutputStream(keydefFile));
     keydef.writeStartDocument();
     keydef.writeStartElement(ELEMENT_STUB);
     for (final KeyDef k : keydefs) {
       keydef.writeStartElement(ELEMENT_KEYDEF);
       keydef.writeAttribute(ATTRIBUTE_KEYS, k.keys);
       if (k.href != null) {
         keydef.writeAttribute(ATTRIBUTE_HREF, k.href);
       }
       if (k.source != null) {
         keydef.writeAttribute(ATTRIUBTE_SOURCE, k.source);
       }
       keydef.writeEndElement();
     }
     keydef.writeEndDocument();
   } catch (final Exception e) {
     throw new DITAOTException(
         "Failed to write key definition file " + keydefFile + ": " + e.getMessage(), e);
   } finally {
     if (keydef != null) {
       try {
         keydef.close();
       } catch (final IOException e) {
       }
     }
   }
 }