@Override
  public void run() throws TaxomaticException {
    List<Taxon> taxaToSave = new ArrayList<Taxon>();
    for (Taxon mergedTaxon : taxaToMerge) {
      mergedTaxon.setStatus(TaxonStatus.STATUS_SYNONYM);
      {
        Synonym synonym = Taxon.synonymizeTaxon(mergedTaxon);
        synonym.setStatus(Synonym.MERGE);
        synonym.setTaxon(mergeTarget);

        mergeTarget.getSynonyms().add(synonym);
      }
      {
        Synonym synonym = Taxon.synonymizeTaxon(mergeTarget);
        synonym.setStatus(Synonym.MERGE);
        synonym.setTaxon(mergedTaxon);

        mergedTaxon.getSynonyms().add(synonym);
      }
      for (Taxon child : mergedTaxon.getChildren()) {
        child.setParent(mergeTarget);
        mergeTarget.getChildren().add(child);
        taxaToSave.add(child);
      }
      taxaToSave.add(mergedTaxon);
    }
    taxaToSave.add(mergeTarget);

    taxomaticIO.updateAndSave(taxaToSave, operation.getUser(), true);

    recordOperationHistory(taxaToSave, operation);
  }
  public MergeNodesOperation(
      Session session, User user, Taxon mergeTarget, List<Taxon> taxaToMerge) {
    super(session, TaxomaticIO.MERGE);
    TaxomaticOperation operation = new TaxomaticOperation();
    operation.setDate(new Date());
    operation.setInstructions(generateInstructions(mergeTarget, taxaToMerge));
    operation.setDetails(generateDetails(mergeTarget, taxaToMerge));
    operation.setOperation(TaxomaticIO.MERGE);
    operation.setUser(user);

    this.operation = operation;
    this.mergeTarget = mergeTarget;
    this.taxaToMerge = taxaToMerge;
  }
 public MergeNodesOperation(Session session, TaxomaticOperation operation) {
   super(session, TaxomaticIO.MERGE);
   this.operation = operation;
   this.mergeTarget = loadMergeTarget(operation.getInstructions());
   this.taxaToMerge = loadTaxaToMerge(operation.getInstructions());
 }