class SentenceSourceIndexer extends DefaultHandler implements AutoCloseable {

  public static final String MAX_DOC_COUNT_VALUE = "maxDocCountValue";
  public static final String MAX_DOC_COUNT_FIELD = "maxDocCount";
  public static final String MAX_DOC_COUNT_FIELD_VAL = "1";
  
  private static final boolean LC_ONLY = true;

  private final Indexer indexer;
  private final int maxSentences;
  
  private boolean stopped = false;
  
  private int sentenceCount = 0;
  
  SentenceSourceIndexer(Directory dir, Language language, int maxSentences, Analyzer analyzer) {
    if (analyzer == null) {
      this.indexer = new Indexer(dir, language);
    } else {
      this.indexer = new Indexer(dir, language, analyzer);
    }
    this.indexer.setLowercaseOnly(LC_ONLY);
    this.maxSentences = maxSentences;
    Runtime.getRuntime().addShutdownHook(new Thread() {
      @Override
      public void run() {
        super.run();
        stopped = true;
        System.out.println("----- Got SIGHUP, will commit and exit ----");
        try {
          indexer.commit();
          System.out.println("----- commit done, will exit now ----");
        } catch (Exception e) {
          e.printStackTrace();
        }
      }
    });
  }

  SentenceSourceIndexer(Directory dir, Language language, int maxSentences) {
    this(dir, language, maxSentences, null);
  }

  @Override
  public void close() throws Exception {
    indexer.close();
  }

  private void run(List<String> dumpFileNames, Language language) throws IOException {
    MixingSentenceSource mixingSource = MixingSentenceSource.create(dumpFileNames, language);
    while (mixingSource.hasNext()) {
      if (stopped) {
        return;
      }
      Sentence sentence = mixingSource.next();
      if (sentenceCount % 10_000 == 0) {
        //System.out.println("Indexing sentence #" + sentenceCount + " (" + mixingSource.getSourceDistribution() + "):");  // doesn't work well with URLs as source
        System.out.println("Indexing sentence #" + sentenceCount + ":");
        System.out.println("  [" +  sentence.getSource() + "] " + sentence);
      }
      indexer.indexSentence(sentence, sentenceCount);
      sentenceCount++;
      if (maxSentences > 0 && sentenceCount >= maxSentences) {
        throw new DocumentLimitReachedException(maxSentences);
      }
    }
  }

  private void writeMetaDocuments() throws IOException {<FILL_FUNCTION_BODY>}

  public static void main(String... args) throws Exception {
    if (args.length != 5) {
      System.out.println("Usage: " + SentenceSourceIndexer.class.getSimpleName() + " <dataFile...> <indexDir> <languageCode> <maxSentences> <indexPosTags>");
      System.out.println("\t<dataFiles> comma-separated list of a Wikipedia XML dump (*.xml) and/or Tatoeba files (tatoeba-*)");
      System.out.println("\t<indexDir> directory where Lucene index will be written to, existing index content will be removed");
      System.out.println("\t<languageCode> short code like en for English, de for German etc");
      System.out.println("\t<maxSentences> maximum number of sentences to be indexed, use 0 for no limit");
      System.out.println("\t<indexPosTags> 1 to also index POS tags (i.e. analyze text by LT), 0 to index only the plain text");
      System.exit(1);
    }
    List<String> dumpFilesNames = Arrays.asList(args[0].split(","));
    File indexDir = new File(args[1]);
    String languageCode = args[2];
    int maxSentences = Integer.parseInt(args[3]);

    Language language = Languages.getLanguageForShortCode(languageCode);
    if (maxSentences == 0) {
      System.out.println("Going to index contents from " + dumpFilesNames);
    } else {
      System.out.println("Going to index up to " + maxSentences + " sentences from " + dumpFilesNames);
    }
    System.out.println("Output index dir: " + indexDir);
    long start = System.currentTimeMillis();
    Analyzer analyzer;
    String indexPos = args[4];
    if (indexPos.equals("1")) {
      analyzer = null;  // this will use LanguageToolAnalyzer
    } else if (indexPos.equals("0")) {
      analyzer = new StandardAnalyzer(new CharArraySet(Collections.emptyList(), false));
    } else {
      throw new IllegalArgumentException("Unknown value '" + indexPos + "' for indexPosTags parameter, use 0 or 1");
    }
    try (FSDirectory fsDirectory = FSDirectory.open(indexDir.toPath());
         SentenceSourceIndexer indexer = new SentenceSourceIndexer(fsDirectory, language, maxSentences, analyzer)) {
      try {
        indexer.run(dumpFilesNames, language);
      } catch (DocumentLimitReachedException e) {
        System.out.println("Sentence limit (" + e.getLimit() + ") reached, stopping indexing");
      } finally {
        indexer.writeMetaDocuments();
      }
      if (analyzer != null) {
        analyzer.close();
      }
    }
    long end = System.currentTimeMillis();
    float minutes = (end - start) / (float)(1000 * 60);
    System.out.printf("Indexing took %.2f minutes\n", minutes);
  }

}

    Document doc = new Document();
    doc.add(new StringField(MAX_DOC_COUNT_FIELD, MAX_DOC_COUNT_FIELD_VAL, Field.Store.YES));
    doc.add(new StringField(MAX_DOC_COUNT_VALUE, sentenceCount + "", Field.Store.YES));
    indexer.add(doc);
  
<methods>public void <init>() ,public void characters(char[], int, int) throws org.xml.sax.SAXException,public void endDocument() throws org.xml.sax.SAXException,public void endElement(java.lang.String, java.lang.String, java.lang.String) throws org.xml.sax.SAXException,public void endPrefixMapping(java.lang.String) throws org.xml.sax.SAXException,public void error(org.xml.sax.SAXParseException) throws org.xml.sax.SAXException,public void fatalError(org.xml.sax.SAXParseException) throws org.xml.sax.SAXException,public void ignorableWhitespace(char[], int, int) throws org.xml.sax.SAXException,public void notationDecl(java.lang.String, java.lang.String, java.lang.String) throws org.xml.sax.SAXException,public void processingInstruction(java.lang.String, java.lang.String) throws org.xml.sax.SAXException,public org.xml.sax.InputSource resolveEntity(java.lang.String, java.lang.String) throws java.io.IOException, org.xml.sax.SAXException,public void setDocumentLocator(org.xml.sax.Locator) ,public void skippedEntity(java.lang.String) throws org.xml.sax.SAXException,public void startDocument() throws org.xml.sax.SAXException,public void startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes) throws org.xml.sax.SAXException,public void startPrefixMapping(java.lang.String, java.lang.String) throws org.xml.sax.SAXException,public void unparsedEntityDecl(java.lang.String, java.lang.String, java.lang.String, java.lang.String) throws org.xml.sax.SAXException,public void warning(org.xml.sax.SAXParseException) throws org.xml.sax.SAXException<variables>