ref #8509 improve tagged names handling in PESI export (ERMS and others)
[cdmlib-apps.git] / cdm-pesi / src / main / java / eu / etaxonomy / cdm / io / pesi / out / PesiTaxonExport.java
index 749d1fceb73fdf1170ac3586cc30691b2257cf9a..c1ddea0cc92650e1b62665ec8a2b70a1bf307b3d 100644 (file)
-// $Id$\r
-/**\r
-* Copyright (C) 2009 EDIT\r
-* European Distributed Institute of Taxonomy \r
-* http://www.e-taxonomy.eu\r
-* \r
-* The contents of this file are subject to the Mozilla Public License Version 1.1\r
-* See LICENSE.TXT at the top of this package for the full license terms.\r
-*/\r
-package eu.etaxonomy.cdm.io.pesi.out;\r
-\r
-import java.sql.Connection;\r
-import java.sql.PreparedStatement;\r
-import java.sql.ResultSet;\r
-import java.sql.SQLException;\r
-import java.sql.Types;\r
-import java.util.ArrayList;\r
-import java.util.BitSet;\r
-import java.util.HashMap;\r
-import java.util.HashSet;\r
-import java.util.Iterator;\r
-import java.util.List;\r
-import java.util.Set;\r
-import java.util.UUID;\r
-\r
-import org.apache.commons.lang.StringUtils;\r
-import org.apache.log4j.Logger;\r
-import org.joda.time.DateTime;\r
-import org.joda.time.format.DateTimeFormat;\r
-import org.joda.time.format.DateTimeFormatter;\r
-import org.springframework.stereotype.Component;\r
-import org.springframework.transaction.TransactionStatus;\r
-\r
-import eu.etaxonomy.cdm.api.service.TaxonServiceImpl;\r
-import eu.etaxonomy.cdm.common.CdmUtils;\r
-import eu.etaxonomy.cdm.io.berlinModel.BerlinModelTransformer;\r
-import eu.etaxonomy.cdm.io.common.Source;\r
-import eu.etaxonomy.cdm.io.common.mapping.UndefinedTransformerMethodException;\r
-import eu.etaxonomy.cdm.io.common.mapping.out.DbConstantMapper;\r
-import eu.etaxonomy.cdm.io.common.mapping.out.DbExtensionMapper;\r
-import eu.etaxonomy.cdm.io.common.mapping.out.DbLastActionMapper;\r
-import eu.etaxonomy.cdm.io.common.mapping.out.DbObjectMapper;\r
-import eu.etaxonomy.cdm.io.common.mapping.out.DbStringMapper;\r
-import eu.etaxonomy.cdm.io.common.mapping.out.IdMapper;\r
-import eu.etaxonomy.cdm.io.common.mapping.out.MethodMapper;\r
-import eu.etaxonomy.cdm.io.common.mapping.out.ObjectChangeMapper;\r
-import eu.etaxonomy.cdm.io.pesi.erms.ErmsTransformer;\r
-import eu.etaxonomy.cdm.model.common.Annotation;\r
-import eu.etaxonomy.cdm.model.common.AnnotationType;\r
-import eu.etaxonomy.cdm.model.common.CdmBase;\r
-import eu.etaxonomy.cdm.model.common.Extension;\r
-import eu.etaxonomy.cdm.model.common.ExtensionType;\r
-import eu.etaxonomy.cdm.model.common.IdentifiableEntity;\r
-import eu.etaxonomy.cdm.model.common.IdentifiableSource;\r
-import eu.etaxonomy.cdm.model.common.Language;\r
-import eu.etaxonomy.cdm.model.common.Marker;\r
-import eu.etaxonomy.cdm.model.common.MarkerType;\r
-import eu.etaxonomy.cdm.model.common.RelationshipBase;\r
-import eu.etaxonomy.cdm.model.name.BacterialName;\r
-import eu.etaxonomy.cdm.model.name.BotanicalName;\r
-import eu.etaxonomy.cdm.model.name.HybridRelationship;\r
-import eu.etaxonomy.cdm.model.name.NameRelationship;\r
-import eu.etaxonomy.cdm.model.name.NameTypeDesignation;\r
-import eu.etaxonomy.cdm.model.name.NameTypeDesignationStatus;\r
-import eu.etaxonomy.cdm.model.name.NomenclaturalCode;\r
-import eu.etaxonomy.cdm.model.name.NomenclaturalStatus;\r
-import eu.etaxonomy.cdm.model.name.NonViralName;\r
-import eu.etaxonomy.cdm.model.name.Rank;\r
-import eu.etaxonomy.cdm.model.name.TaxonNameBase;\r
-import eu.etaxonomy.cdm.model.name.ZoologicalName;\r
-import eu.etaxonomy.cdm.model.reference.INomenclaturalReference;\r
-import eu.etaxonomy.cdm.model.reference.Reference;\r
-import eu.etaxonomy.cdm.model.taxon.Classification;\r
-import eu.etaxonomy.cdm.model.taxon.Synonym;\r
-import eu.etaxonomy.cdm.model.taxon.SynonymRelationship;\r
-import eu.etaxonomy.cdm.model.taxon.SynonymRelationshipType;\r
-import eu.etaxonomy.cdm.model.taxon.Taxon;\r
-import eu.etaxonomy.cdm.model.taxon.TaxonBase;\r
-import eu.etaxonomy.cdm.model.taxon.TaxonNode;\r
-import eu.etaxonomy.cdm.model.taxon.TaxonRelationship;\r
-import eu.etaxonomy.cdm.profiler.ProfilerController;\r
-import eu.etaxonomy.cdm.strategy.cache.HTMLTagRules;\r
-import eu.etaxonomy.cdm.strategy.cache.TagEnum;\r
-import eu.etaxonomy.cdm.strategy.cache.name.BacterialNameDefaultCacheStrategy;\r
-import eu.etaxonomy.cdm.strategy.cache.name.BotanicNameDefaultCacheStrategy;\r
-import eu.etaxonomy.cdm.strategy.cache.name.INonViralNameCacheStrategy;\r
-import eu.etaxonomy.cdm.strategy.cache.name.NonViralNameDefaultCacheStrategy;\r
-import eu.etaxonomy.cdm.strategy.cache.name.ZooNameNoMarkerCacheStrategy;\r
-\r
-/**\r
- * The export class for {@link eu.etaxonomy.cdm.model.name.TaxonNameBase TaxonNames}.<p>\r
- * Inserts into DataWarehouse database table <code>Taxon</code>.\r
- * It is divided into four phases:<p><ul>\r
- * <li>Phase 1:        Export of all {@link eu.etaxonomy.cdm.model.name.TaxonNameBase TaxonNames} except some data exported in the following phases.\r
- * <li>Phase 2:        Export of additional data: ParenTaxonFk and TreeIndex.\r
- * <li>Phase 3:        Export of additional data: Rank data, KingdomFk, TypeNameFk, expertFk and speciesExpertFk.\r
- * <li>Phase 4:        Export of Inferred Synonyms.</ul>\r
- * @author e.-m.lee\r
- * @date 23.02.2010\r
- *\r
- */\r
-@Component\r
-public class PesiTaxonExport extends PesiExportBase {\r
-       private static final Logger logger = Logger.getLogger(PesiTaxonExport.class);\r
-       private static final Class<? extends CdmBase> standardMethodParameter = TaxonBase.class;\r
-\r
-       private static int modCount = 1000;\r
-       private static final String dbTableName = "Taxon";\r
-       private static final String dbTableNameSynRel = "RelTaxon";\r
-       private static final String dbTableAdditionalSourceRel = "AdditionalTaxonSource";\r
-       private static final String pluralString = "Taxa";\r
-       private static final String parentPluralString = "Taxa";\r
-       private PreparedStatement parentTaxonFk_TreeIndex_KingdomFkStmt;\r
-       private PreparedStatement parentTaxonFkStmt;\r
-       private PreparedStatement rankTypeExpertsUpdateStmt;\r
-       private PreparedStatement rankUpdateStmt;\r
-       private NomenclaturalCode nomenclaturalCode;\r
-       private Integer kingdomFk;\r
-       private HashMap<Rank, Rank> rank2endRankMap = new HashMap<Rank, Rank>();\r
-       private List<Rank> rankList = new ArrayList<Rank>();\r
-       private static final UUID uuidTreeIndex = UUID.fromString("28f4e205-1d02-4d3a-8288-775ea8413009");\r
-       private AnnotationType treeIndexAnnotationType;\r
-       private static ExtensionType lastActionExtensionType;\r
-       private static ExtensionType lastActionDateExtensionType;\r
-       private static ExtensionType expertNameExtensionType;\r
-       private static ExtensionType speciesExpertNameExtensionType;\r
-       private static ExtensionType cacheCitationExtensionType;\r
-       public static NonViralNameDefaultCacheStrategy<?> zooNameStrategy = ZooNameNoMarkerCacheStrategy.NewInstance();\r
-       public static NonViralNameDefaultCacheStrategy<?> botanicalNameStrategy = BotanicNameDefaultCacheStrategy.NewInstance();\r
-       public static NonViralNameDefaultCacheStrategy<?> nonViralNameStrategy = NonViralNameDefaultCacheStrategy.NewInstance();\r
-       public static NonViralNameDefaultCacheStrategy<?> bacterialNameStrategy = BacterialNameDefaultCacheStrategy.NewInstance();\r
-       private static int currentTaxonId;\r
-       \r
-       \r
-       /**\r
-        * @return the treeIndexAnnotationType\r
-        */\r
-       protected AnnotationType getTreeIndexAnnotationType() {\r
-               return treeIndexAnnotationType;\r
-       }\r
-\r
-       /**\r
-        * @param treeIndexAnnotationType the treeIndexAnnotationType to set\r
-        */\r
-       protected void setTreeIndexAnnotationType(AnnotationType treeIndexAnnotationType) {\r
-               this.treeIndexAnnotationType = treeIndexAnnotationType;\r
-       }\r
-\r
-       enum NamePosition {\r
-               beginning,\r
-               end,\r
-               between,\r
-               alone,\r
-               nowhere\r
-       }\r
-\r
-       public PesiTaxonExport() {\r
-               super();\r
-       }\r
-\r
-       /* (non-Javadoc)\r
-        * @see eu.etaxonomy.cdm.io.common.DbExportBase#getStandardMethodParameter()\r
-        */\r
-       @Override\r
-       public Class<? extends CdmBase> getStandardMethodParameter() {\r
-               return standardMethodParameter;\r
-       }\r
-\r
-       /* (non-Javadoc)\r
-        * @see eu.etaxonomy.cdm.io.common.CdmIoBase#doCheck(eu.etaxonomy.cdm.io.common.IoStateBase)\r
-        */\r
-       @Override\r
-       protected boolean doCheck(PesiExportState state) {\r
-               boolean result = true;\r
-               return result;\r
-       }\r
-       \r
-       \r
-       /* (non-Javadoc)\r
-        * @see eu.etaxonomy.cdm.io.common.CdmIoBase#doInvoke(eu.etaxonomy.cdm.io.common.IoStateBase)\r
-        */\r
-       @Override\r
-       protected void doInvoke(PesiExportState state) {\r
-               try {\r
-                       logger.info("*** Started Making " + pluralString + " ...");\r
-\r
-                       initPreparedStatements(state);\r
-                       \r
-                       // Stores whether this invoke was successful or not.\r
-                       boolean success = true;\r
-       \r
-                       // PESI: Clear the database table Taxon.\r
-//                     doDelete(state);\r
-                       \r
-                       // Get specific mappings: (CDM) Taxon -> (PESI) Taxon\r
-                       PesiExportMapping mapping = getMapping();\r
-                       PesiExportMapping synonymRelMapping = getSynRelMapping();\r
-                       PesiExportMapping additionalSourceMapping = getAdditionalSourceMapping(state); \r
-                       \r
-                       // Initialize the db mapper\r
-                       mapping.initialize(state);\r
-                       synonymRelMapping.initialize(state);\r
-                       additionalSourceMapping.initialize(state);\r
-                       \r
-                       // Find extensionTypes\r
-                       lastActionExtensionType = (ExtensionType)getTermService().find(PesiTransformer.lastActionUuid);\r
-                       lastActionDateExtensionType = (ExtensionType)getTermService().find(PesiTransformer.lastActionDateUuid);\r
-                       expertNameExtensionType = (ExtensionType)getTermService().find(PesiTransformer.expertNameUuid);\r
-                       speciesExpertNameExtensionType = (ExtensionType)getTermService().find(PesiTransformer.speciesExpertNameUuid);\r
-                       cacheCitationExtensionType = (ExtensionType)getTermService().find(PesiTransformer.cacheCitationUuid);\r
-                       \r
-                       //Export Taxa..\r
-                       success &= doPhase01(state, mapping, additionalSourceMapping);\r
-\r
-                       //"PHASE 1b: Handle names without taxa ...\r
-                       success &= doNames(state, additionalSourceMapping);\r
-\r
-                       \r
-                       // 2nd Round: Add ParentTaxonFk to each taxon\r
-                       success &= doPhase02(state);\r
-                       \r
-                       //PHASE 3: Add Rank data, KingdomFk, TypeNameFk ...\r
-                       success &= doPhase03(state);\r
-                       \r
-                       // 4nd Round: Add TreeIndex to each taxon\r
-                       success &= doPhase04(state);\r
-                                               \r
-                       \r
-                       //"PHASE 4: Creating Inferred Synonyms...\r
-                       success &= doPhase05(state, mapping, synonymRelMapping);\r
-                       \r
-                       logger.info("*** Finished Making " + pluralString + " ..." + getSuccessString(success));\r
-\r
-                       if (!success){\r
-                               state.setUnsuccessfull();\r
-                       }\r
-                       return;\r
-               } catch (Exception e) {\r
-                       e.printStackTrace();\r
-                       logger.error(e.getMessage());\r
-                       state.setUnsuccessfull();\r
-               }\r
-       }\r
-\r
-       \r
-       private void initPreparedStatements(PesiExportState state) throws SQLException {\r
-               initTreeIndexStatement(state);\r
-               initRankExpertsUpdateStmt(state);\r
-               initRankUpdateStatement(state);\r
-               \r
-               initParentFkStatement(state);\r
-       }\r
-\r
-       // Prepare TreeIndex-And-KingdomFk-Statement\r
-       private void initTreeIndexStatement(PesiExportState state) throws SQLException {\r
-               Connection connection = state.getConfig().getDestination().getConnection();\r
-               String parentTaxonFk_TreeIndex_KingdomFkSql = "UPDATE Taxon SET ParentTaxonFk = ?, TreeIndex = ? WHERE TaxonId = ?"; \r
-               parentTaxonFk_TreeIndex_KingdomFkStmt = connection.prepareStatement(parentTaxonFk_TreeIndex_KingdomFkSql);\r
-       }\r
-\r
-       // Prepare TreeIndex-And-KingdomFk-Statement\r
-       private void initParentFkStatement(PesiExportState state) throws SQLException {\r
-               Connection connection = state.getConfig().getDestination().getConnection();\r
-               String parentTaxonFkSql = "UPDATE Taxon SET ParentTaxonFk = ? WHERE TaxonId = ?"; \r
-               parentTaxonFkStmt = connection.prepareStatement(parentTaxonFkSql);\r
-       }\r
-       \r
-       private void initRankUpdateStatement(PesiExportState state) throws SQLException {\r
-               Connection connection = state.getConfig().getDestination().getConnection();\r
-               String rankSql = "UPDATE Taxon SET RankFk = ?, RankCache = ?, KingdomFk = ? WHERE TaxonId = ?";\r
-               rankUpdateStmt = connection.prepareStatement(rankSql);\r
-       }\r
-\r
-       private void initRankExpertsUpdateStmt(PesiExportState state) throws SQLException {\r
-//             String sql_old = "UPDATE Taxon SET RankFk = ?, RankCache = ?, TypeNameFk = ?, KingdomFk = ?, " +\r
-//                             "ExpertFk = ?, SpeciesExpertFk = ? WHERE TaxonId = ?";\r
-               //TODO handle experts GUIDs\r
-               Connection connection = state.getConfig().getDestination().getConnection();\r
-               \r
-               String sql = "UPDATE Taxon SET RankFk = ?, RankCache = ?, TypeNameFk = ?, KingdomFk = ? " +\r
-                               " WHERE TaxonId = ?";\r
-               rankTypeExpertsUpdateStmt = connection.prepareStatement(sql);\r
-       }\r
-\r
-       private boolean doPhase01(PesiExportState state, PesiExportMapping mapping, PesiExportMapping additionalSourceMapping) throws SQLException {\r
-               int count = 0;\r
-               int pastCount = 0;\r
-               List<TaxonBase> list;\r
-               boolean success = true;\r
-               // Get the limit for objects to save within a single transaction.\r
-               int limit = state.getConfig().getLimitSave();\r
-\r
-               \r
-               logger.info("PHASE 1: Export Taxa...limit is " + limit);\r
-               // Start transaction\r
-               TransactionStatus txStatus = startTransaction(true);\r
-               logger.info("Started new transaction. Fetching some " + pluralString + " (max: " + limit + ") ...");\r
-               \r
-               \r
-               \r
-               int partitionCount = 0;\r
-\r
-               logger.info("Taking snapshot at the beginning of phase 1 of taxonExport");\r
-               ProfilerController.memorySnapshot();\r
-               while ((list = getNextTaxonPartition(null, limit, partitionCount++, null)) != null   ) {\r
-                       \r
-                       logger.debug("Fetched " + list.size() + " " + pluralString + ". Exporting...");\r
-                       for (TaxonBase<?> taxon : list) {\r
-                               doCount(count++, modCount, pluralString);\r
-                               TaxonNameBase<?,?> taxonName = taxon.getName();\r
-                               NonViralName<?> nvn = CdmBase.deproxy(taxonName, NonViralName.class);\r
-                                                               \r
-                               if (! nvn.isProtectedTitleCache()){\r
-                                       nvn.setTitleCache(null, false); \r
-                               }\r
-                               if (! nvn.isProtectedNameCache()){\r
-                                       nvn.setNameCache(null, false);  \r
-                               }\r
-                               if (! nvn.isProtectedFullTitleCache()){\r
-                                       nvn.setFullTitleCache(null, false);     \r
-                               }\r
-                               if (! nvn.isProtectedAuthorshipCache()){\r
-                                       nvn.setAuthorshipCache(null, false);    \r
-                               }\r
-                               \r
-                               //core mapping\r
-                               success &= mapping.invoke(taxon);\r
-                               //additional source\r
-                               if (nvn.getNomenclaturalReference() != null || StringUtils.isNotBlank(nvn.getNomenclaturalMicroReference() )){\r
-                                       additionalSourceMapping.invoke(taxon);\r
-                               }\r
-                               \r
-                               validatePhaseOne(taxon, nvn);\r
-                               taxon = null;\r
-                               nvn = null;\r
-                               taxonName = null;\r
-\r
-                               \r
-                               \r
-                       }\r
-                       \r
-\r
-                       // Commit transaction\r
-                       commitTransaction(txStatus);\r
-                       logger.debug("Committed transaction.");\r
-                       logger.info("Exported " + (count - pastCount) + " " + pluralString + ". Total: " + count);\r
-                       pastCount = count;\r
-                       /*logger.warn("Taking snapshot at the end of the loop of phase 1 of taxonExport");\r
-                       ProfilerController.memorySnapshot();\r
-                       */\r
-                       // Start transaction\r
-                       txStatus = startTransaction(true);\r
-                       logger.info("Started new transaction. Fetching some " + pluralString + " (max: " + limit + ") ...");\r
-                       \r
-               }\r
-               if (list == null ) {\r
-                       logger.info("No " + pluralString + " left to fetch.");\r
-               }\r
-               \r
-               \r
-               \r
-               // Commit transaction\r
-               commitTransaction(txStatus);\r
-               txStatus = null;\r
-               logger.debug("Committed transaction.");\r
-               list = null;\r
-               if (logger.isDebugEnabled()){\r
-                       logger.debug("Taking snapshot at the end of phase 1 of taxonExport");\r
-                       ProfilerController.memorySnapshot();\r
-               }\r
-               return success;\r
-       }\r
-\r
-\r
-       private void validatePhaseOne(TaxonBase<?> taxon, NonViralName taxonName) {\r
-               // Check whether some rules are violated\r
-               nomenclaturalCode = taxonName.getNomenclaturalCode();\r
-               String genusOrUninomial = taxonName.getGenusOrUninomial();\r
-               String specificEpithet = taxonName.getSpecificEpithet();\r
-               String infraSpecificEpithet = taxonName.getInfraSpecificEpithet();\r
-               String infraGenericEpithet = taxonName.getInfraGenericEpithet();\r
-               Integer rank = getRankFk(taxonName, nomenclaturalCode);\r
-               \r
-               if (rank == null) {\r
-                       logger.error("Rank was not determined: " + taxon.getUuid() + " (" + taxon.getTitleCache() + ")");\r
-               } else {\r
-                       \r
-                       // Check whether infraGenericEpithet is set correctly\r
-                       // 1. Childs of an accepted taxon of rank subgenus that are accepted taxa of rank species have to have an infraGenericEpithet\r
-                       // 2. Grandchilds of an accepted taxon of rank subgenus that are accepted taxa of rank subspecies have to have an infraGenericEpithet\r
-                       \r
-                       int ancestorLevel = 0;\r
-                       if (taxonName.getRank().equals(Rank.SUBSPECIES())) {\r
-                               // The accepted taxon two rank levels above should be of rank subgenus\r
-                               ancestorLevel  = 2;\r
-                       }\r
-                       if (taxonName.getRank().equals(Rank.SPECIES())) {\r
-                               // The accepted taxon one rank level above should be of rank subgenus\r
-                               ancestorLevel = 1;\r
-                       }\r
-                       if (ancestorLevel > 0) {\r
-                               if (validateAncestorOfSpecificRank(taxon, ancestorLevel, Rank.SUBGENUS())) {\r
-                                       // The child (species or subspecies) of this parent (subgenus) has to have an infraGenericEpithet\r
-                                       if (infraGenericEpithet == null) {\r
-                                               logger.warn("InfraGenericEpithet for (sub)species of infrageneric taxon does not exist even though it should (also valid for Botanical Names?) for: " + taxon.getUuid() + " (" + taxon.getTitleCache() + ")");\r
-                                               // maybe the taxon could be named here\r
-                                       }\r
-                               }\r
-                       }\r
-                       \r
-                       if (infraGenericEpithet == null && rank.intValue() == 190) {\r
-                               logger.warn("InfraGenericEpithet was not determined although it should exist for rank 190: " + taxon.getUuid() + " (" + taxon.getTitleCache() + ")");\r
-                       }\r
-                       if (specificEpithet != null && rank.intValue() < 216) {\r
-                               logger.warn("SpecificEpithet was determined for rank " + rank + " although it should only exist for ranks higher or equal to 220: TaxonName " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");\r
-                       }\r
-                       if (infraSpecificEpithet != null && rank.intValue() < 225) {\r
-                               String message = "InfraSpecificEpithet '" +infraSpecificEpithet + "' was determined for rank " + rank + " although it should only exist for ranks higher or equal to 230: "  + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")"; \r
-                               if (StringUtils.isNotBlank(infraSpecificEpithet)){\r
-                                       logger.warn(message);\r
-                               }else{\r
-                                       logger.warn(message);\r
-                               }\r
-                       }\r
-               }\r
-               if (infraSpecificEpithet != null && specificEpithet == null) {\r
-                       logger.warn("An infraSpecificEpithet was determined, but a specificEpithet was not determined: "  + taxon.getUuid() + " (" + taxon.getTitleCache() + ")");\r
-               }\r
-               if (genusOrUninomial == null) {\r
-                       logger.warn("GenusOrUninomial was not determined: " + taxon.getUuid() + " (" + taxon.getTitleCache() + ")");\r
-               }\r
-       }\r
-\r
-       \r
-       \r
-       /**\r
-        * 2nd Round: Add ParentTaxonFk to each taxon and add Biota if not exists\r
-        * @param state\r
-        * @return\r
-        */\r
-       private boolean doPhase02(PesiExportState state) {\r
-               int count = 0;\r
-               int pastCount = 0;\r
-               boolean success = true;\r
-               if (! state.getConfig().isDoParentAndBiota()){\r
-                       logger.info ("Ignore PHASE 2: Make ParentFk and Biota...");\r
-                       return success;\r
-               }\r
-               \r
-               List<Taxon> list;\r
-               \r
-               // Get the limit for objects to save within a single transaction.\r
-               int limit = state.getConfig().getLimitSave();\r
-               \r
-               insertBiota(state);\r
-               \r
-               logger.info("PHASE 2: Make ParentFk and Biota ... limit is " + limit);\r
-               // Start transaction\r
-               TransactionStatus txStatus = startTransaction(true);\r
-               int partitionCount = 0;\r
-\r
-//             ProfilerController.memorySnapshot();\r
-               while ((list = getNextTaxonPartition(Taxon.class, limit, partitionCount++, null)) != null   ) {\r
-                       \r
-                       logger.info("Fetched " + list.size() + " " + pluralString + ". Exporting...");\r
-                       for (Taxon taxon : list) {\r
-                               for (TaxonNode node : taxon.getTaxonNodes()){\r
-                                       doCount(count++, modCount, pluralString);\r
-                                       TaxonNode parentNode = node.getParent();\r
-                                       if (parentNode != null && parentNode.getTaxon() != null){  //new root node handling requires has root taxon with taxon == null\r
-                                               int childId = state.getDbId( taxon); \r
-                                               int parentId = state.getDbId(parentNode.getTaxon());\r
-                                               success &= invokeParentTaxonFk(parentId, childId);\r
-                                       }\r
-                               }\r
-                               \r
-                       }\r
-                       \r
-                       // Commit transaction\r
-                       commitTransaction(txStatus);\r
-                       logger.info("Exported " + (count - pastCount) + " " + pluralString + ". Total: " + count);\r
-                       pastCount = count;\r
-                       // Start transaction\r
-                       txStatus = startTransaction(true);\r
-                       logger.info("Started new transaction. Fetching some " + pluralString + " (max: " + limit + ") ...");\r
-                       \r
-               }\r
-               if (list == null ) {\r
-                       logger.info("No " + pluralString + " left to fetch.");\r
-               }\r
-               \r
-               // Commit transaction\r
-               commitTransaction(txStatus);\r
-               \r
-               return success;\r
-               \r
-       }\r
-\r
-       /**\r
-        * Inserts the Biota Taxon if not yet exists.\r
-        * @param state\r
-        * @throws SQLException\r
-        */\r
-       private void insertBiota(PesiExportState state) {\r
-               try {\r
-                       ResultSet rs = state.getConfig().getDestination().getResultSet("SELECT * FROM Taxon WHERE GenusOrUninomial = 'Biota' ");\r
-                       if (rs.next() == false){\r
-                               int biotaId = state.getConfig().getNameIdStart() -1 ;\r
-                               String sqlInsertBiota = "INSERT INTO Taxon (TaxonId, KingdomFk, RankFk, RankCache, GenusOrUninomial, WebSearchName, WebShowName, FullName, DisplayName, TaxonStatusFk, TaxonStatusCache) " +\r
-                                                                              " VALUES (" + biotaId + ",    0,    0,   'Superdomain',   'Biota',          'Biota',  '<i>Biota</i>',   'Biota', '<i>Biota</i>',  1 ,      'accepted')";\r
-                               state.getConfig().getDestination().update(sqlInsertBiota);\r
-                       }\r
-               } catch (SQLException e) {\r
-                       logger.warn ("Biota could not be requested or inserted");\r
-               }\r
-       }\r
-       \r
-       // 4th round: Add TreeIndex to each taxon\r
-       private boolean doPhase04(PesiExportState state) {\r
-               boolean success = true;\r
-               \r
-               logger.info("PHASE 4: Make TreeIndex ... ");\r
-       \r
-               //TODO test if possible to move to phase 02 \r
-               String sql = " UPDATE Taxon SET ParentTaxonFk = (Select TaxonId from Taxon where RankFk = 0) " +\r
-                               " WHERE (RankFk = 10) and TaxonStatusFk = 1 ";\r
-               state.getConfig().getDestination().update(sql);\r
-               \r
-               state.getConfig().getDestination().update("EXEC dbo.recalculateallstoredpaths");\r
-               \r
-               return success;\r
-               \r
-       }\r
-       \r
-       \r
-       // 2nd Round: Add ParentTaxonFk, TreeIndex to each Taxon\r
-       private boolean doPhase02_OLD(PesiExportState state) {\r
-               boolean success = true;\r
-               if (! state.getConfig().isDoTreeIndex()){\r
-                       logger.info ("Ignore PHASE 2: ParentTaxonFk and TreeIndex");\r
-                       return success;\r
-               }\r
-               \r
-               List<Classification> classificationList = null;\r
-               logger.info("PHASE 2: Add ParenTaxonFk and TreeIndex...");\r
-               \r
-               // Specify starting ranks for tree traversing\r
-               rankList.add(Rank.KINGDOM());\r
-               rankList.add(Rank.GENUS());\r
-\r
-               // Specify where to stop traversing (value) when starting at a specific Rank (key)\r
-               rank2endRankMap.put(Rank.GENUS(), null); // Since NULL does not match an existing Rank, traverse all the way down to the leaves\r
-               rank2endRankMap.put(Rank.KINGDOM(), Rank.GENUS()); // excludes rank genus\r
-               \r
-               StringBuffer treeIndex = new StringBuffer();\r
-               \r
-               // Retrieve list of classifications\r
-               TransactionStatus txStatus = startTransaction(true);\r
-               logger.info("Started transaction for parentFk and treeIndex. Fetching all classifications...");\r
-               classificationList = getClassificationService().listClassifications(null, 0, null, null);\r
-               commitTransaction(txStatus);\r
-               logger.debug("Committed transaction.");\r
-\r
-               logger.info("Fetched " + classificationList.size() + " classification(s).");\r
-\r
-               setTreeIndexAnnotationType(getAnnotationType(uuidTreeIndex, "TreeIndex", "TreeIndex", "TI"));\r
-               List<TaxonNode> rankSpecificRootNodes;\r
-               for (Classification classification : classificationList) {\r
-                       for (Rank rank : rankList) {\r
-                               \r
-                               txStatus = startTransaction(true);\r
-                               logger.info("Started transaction to fetch all rootNodes specific to Rank " + rank.getLabel() + " ...");\r
-\r
-                               rankSpecificRootNodes = getClassificationService().loadRankSpecificRootNodes(classification, rank, null, null, null);\r
-                               logger.info("Fetched " + rankSpecificRootNodes.size() + " RootNodes for Rank " + rank.getLabel());\r
-\r
-                               commitTransaction(txStatus);\r
-                               logger.debug("Committed transaction.");\r
-\r
-                               for (TaxonNode rootNode : rankSpecificRootNodes) {\r
-                                       txStatus = startTransaction(false);\r
-                                       Rank endRank = rank2endRankMap.get(rank);\r
-                                       if (endRank != null) {\r
-                                               logger.debug("Started transaction to traverse childNodes of rootNode (" + rootNode.getUuid() + ") till Rank " + endRank.getLabel() + " ...");\r
-                                       } else {\r
-                                               logger.debug("Started transaction to traverse childNodes of rootNode (" + rootNode.getUuid() + ") till leaves are reached ...");\r
-                                       }\r
-\r
-                                       TaxonNode newNode = getTaxonNodeService().load(rootNode.getUuid());\r
-\r
-                                       if (isPesiTaxon(newNode.getTaxon())){\r
-                                               TaxonNode parentNode = newNode.getParent();\r
-                                               if (rank.equals(Rank.KINGDOM())) {\r
-                                                       treeIndex = new StringBuffer();\r
-                                                       treeIndex.append("#");\r
-                                               } else {\r
-                                                       // Get treeIndex from parentNode\r
-                                                       if (parentNode != null) {\r
-                                                               boolean annotationFound = false;\r
-                                                               Set<Annotation> annotations = parentNode.getAnnotations();\r
-                                                               for (Annotation annotation : annotations) {\r
-                                                                       AnnotationType annotationType = annotation.getAnnotationType();\r
-                                                                       if (annotationType != null && annotationType.equals(getTreeIndexAnnotationType())) {\r
-                                                                               treeIndex = new StringBuffer(CdmUtils.Nz(annotation.getText()));\r
-                                                                               annotationFound = true;\r
-       //                                                                      logger.error("treeIndex: " + treeIndex);\r
-                                                                               break;\r
-                                                                       }\r
-                                                               }\r
-                                                               if (!annotationFound) {\r
-                                                                       // This should not happen because it means that the treeIndex was not set correctly as an annotation to parentNode\r
-                                                                       logger.error("TreeIndex could not be read from annotation of TaxonNode: " + parentNode.getUuid() + ", Taxon: " + parentNode.getTaxon().getUuid());\r
-                                                                       treeIndex = new StringBuffer();\r
-                                                                       treeIndex.append("#");\r
-                                                               }\r
-                                                       } else {\r
-                                                               // TreeIndex could not be determined, but it's unclear how to proceed to generate a correct treeIndex if the parentNode is NULL\r
-                                                               logger.error("ParentNode for RootNode is NULL. TreeIndex could not be determined: " + newNode.getUuid());\r
-                                                               treeIndex = new StringBuffer(); // This just prevents growing of the treeIndex in a wrong manner\r
-                                                               treeIndex.append("#");\r
-                                                       }\r
-                                               }\r
-                                               nomenclaturalCode = newNode.getTaxon().getName().getNomenclaturalCode();\r
-                                               kingdomFk = PesiTransformer.nomenClaturalCode2Kingdom(nomenclaturalCode);\r
-                                               traverseTree(newNode, parentNode, treeIndex, endRank, state);\r
-                                               parentNode =null;\r
-                                       }else{\r
-                                               logger.debug("Taxon is not a PESI taxon: " + newNode.getTaxon().getUuid());\r
-                                       }\r
-                                       \r
-                                       newNode = null;\r
-                                       \r
-                                       try {\r
-                                               commitTransaction(txStatus);\r
-                                               logger.debug("Committed transaction.");\r
-                                       } catch (Exception e) {\r
-                                               logger.error(e.getMessage());\r
-                                               e.printStackTrace();\r
-                                       }\r
-\r
-                               }\r
-                               rankSpecificRootNodes = null;\r
-                       }\r
-                       \r
-               }\r
-               \r
-               logger.warn("Taking snapshot at the end of phase 2 of taxonExport");\r
-               ProfilerController.memorySnapshot();\r
-               return success;\r
-       }       \r
-\r
-       //PHASE 3: Add Rank data, KingdomFk, TypeNameFk, expertFk and speciesExpertFk...\r
-       private boolean doPhase03(PesiExportState state) {\r
-               int count = 0;\r
-               int pastCount = 0;\r
-               boolean success = true;\r
-               if (! state.getConfig().isDoTreeIndex()){\r
-                       logger.info ("Ignore PHASE 3: Add Rank data, KingdomFk, TypeNameFk, expertFk and speciesExpertFk...");\r
-                       return success;\r
-               }\r
-               // Get the limit for objects to save within a single transaction.\r
-               int limit = state.getConfig().getLimitSave();\r
-\r
-               List<TaxonBase> list;\r
-               logger.info("PHASE 3: Add Rank data, KingdomFk, TypeNameFk, expertFk and speciesExpertFk...");\r
-               // Be sure to add rank information, KingdomFk, TypeNameFk, expertFk and speciesExpertFk to every taxonName\r
-               \r
-               // Start transaction\r
-               TransactionStatus txStatus = startTransaction(true);\r
-               logger.info("Started new transaction for rank, kingdom, typeName, expertFk and speciesExpertFK. Fetching some " + pluralString + " (max: " + limit + ") ...");\r
-               int partitionCount = 0;\r
-               while ((list = getNextTaxonPartition(TaxonBase.class, limit, partitionCount++, null)) != null) {\r
-\r
-                       logger.debug("Fetched " + list.size() + " " + pluralString + ". Exporting...");\r
-                       for (TaxonBase<?> taxon : list) {\r
-                               TaxonNameBase<?,?> taxonName = taxon.getName();\r
-                               // Determine expertFk\r
-//                             Integer expertFk = makeExpertFk(state, taxonName);\r
-//\r
-//                             // Determine speciesExpertFk\r
-//                             Integer speciesExpertFk = makeSpeciesExpertFk(state, taxonName);\r
-\r
-                               doCount(count++, modCount, pluralString);\r
-                               Integer typeNameFk = getTypeNameFk(taxonName, state);\r
-                               kingdomFk = PesiTransformer.nomenClaturalCode2Kingdom(nomenclaturalCode);\r
-                               \r
-                               //TODO why are expertFks needed? (Andreas M.)\r
-//                             if (expertFk != null || speciesExpertFk != null) {\r
-                                       invokeRankDataAndTypeNameFkAndKingdomFk(taxonName, nomenclaturalCode, state.getDbId(taxon), \r
-                                                       typeNameFk, kingdomFk, state);\r
-//                             }\r
-                                       \r
-                                       taxon = null;\r
-                                       taxonName = null;\r
-                       }\r
-\r
-                       // Commit transaction\r
-                       commitTransaction(txStatus);\r
-                       logger.debug("Committed transaction.");\r
-                       logger.info("Exported " + (count - pastCount) + " " + pluralString + ". Total: " + count);\r
-                       pastCount = count;\r
-\r
-                       // Start transaction\r
-                       txStatus = startTransaction(true);\r
-                       logger.info("Started new transaction for rank, kingdom, typeName, expertFk and speciesExpertFK. Fetching some " + pluralString + " (max: " + limit + ") ...");\r
-               }\r
-               if (list == null) {\r
-                       logger.info("No " + pluralString + " left to fetch.");\r
-               }\r
-               \r
-               list = null;\r
-               \r
-               // Commit transaction\r
-               commitTransaction(txStatus);\r
-               \r
-               logger.debug("Committed transaction.");\r
-               logger.debug("Try to take snapshot at the end of phase 3 of taxonExport, number of partitions: " + partitionCount);\r
-               ProfilerController.memorySnapshot();\r
-               return success;\r
-       }\r
-       \r
-       //      "PHASE 5: Creating Inferred Synonyms..."\r
-       private boolean doPhase05(PesiExportState state, PesiExportMapping mapping, PesiExportMapping synRelMapping) throws SQLException {\r
-               int count;\r
-               int pastCount;\r
-               boolean success = true;\r
-               // Get the limit for objects to save within a single transaction.\r
-               if (! state.getConfig().isDoInferredSynonyms()){\r
-                       logger.info ("Ignore PHASE 5: Creating Inferred Synonyms...");\r
-                       return success;\r
-               }\r
-               \r
-               int limit = state.getConfig().getLimitSave();\r
-               // Create inferred synonyms for accepted taxa\r
-               logger.info("PHASE 4: Creating Inferred Synonyms...");\r
-\r
-               // Determine the count of elements in datawarehouse database table Taxon\r
-               currentTaxonId = determineTaxonCount(state);\r
-               currentTaxonId++;\r
-\r
-               count = 0;\r
-               pastCount = 0;\r
-               int pageSize = limit;\r
-               int pageNumber = 1;\r
-               String inferredSynonymPluralString = "Inferred Synonyms";\r
-               \r
-               // Start transaction\r
-               TransactionStatus txStatus = startTransaction(true);\r
-               logger.info("Started new transaction. Fetching some " + parentPluralString + " first (max: " + limit + ") ...");\r
-               List<TaxonBase> taxonList = null;\r
-               \r
-               \r
-               \r
-               while ((taxonList  = getTaxonService().listTaxaByName(Taxon.class, "*", "*", "*", "*", Rank.SPECIES(), pageSize, pageNumber)).size() > 0) {\r
-                       HashMap<Integer, TaxonNameBase<?,?>> inferredSynonymsDataToBeSaved = new HashMap<Integer, TaxonNameBase<?,?>>();\r
-\r
-                       logger.info("Fetched " + taxonList.size() + " " + parentPluralString + ". Exporting...");\r
-                       inferredSynonymsDataToBeSaved.putAll(createInferredSynonymsForTaxonList(state, mapping,\r
-                                       synRelMapping, taxonList));\r
-                       \r
-                       doCount(count += taxonList.size(), modCount, inferredSynonymPluralString);\r
-                       // Commit transaction\r
-                       commitTransaction(txStatus);\r
-                       logger.debug("Committed transaction.");\r
-                       logger.info("Exported " + (taxonList.size()) + " " + inferredSynonymPluralString + ". Total: " + count);\r
-                       //pastCount = count;\r
-                       \r
-                       // Save Rank Data and KingdomFk for inferred synonyms\r
-                       for (Integer taxonFk : inferredSynonymsDataToBeSaved.keySet()) {\r
-                               invokeRankDataAndKingdomFk(inferredSynonymsDataToBeSaved.get(taxonFk), nomenclaturalCode, taxonFk, kingdomFk, state);\r
-                       }\r
-\r
-                       // Start transaction\r
-                       txStatus = startTransaction(true);\r
-                       logger.info("Started new transaction. Fetching some " + parentPluralString + " first (max: " + limit + ") ...");\r
-                       \r
-                       // Increment pageNumber\r
-                       pageNumber++;\r
-               }\r
-               taxonList = null;\r
-               while ((taxonList  = getTaxonService().listTaxaByName(Taxon.class, "*", "*", "*", "*", Rank.SUBSPECIES(), pageSize, pageNumber)).size() > 0) {\r
-                       HashMap<Integer, TaxonNameBase<?,?>> inferredSynonymsDataToBeSaved = new HashMap<Integer, TaxonNameBase<?,?>>();\r
-\r
-                       logger.info("Fetched " + taxonList.size() + " " + parentPluralString + ". Exporting...");\r
-                       inferredSynonymsDataToBeSaved.putAll(createInferredSynonymsForTaxonList(state, mapping,\r
-                                       synRelMapping, taxonList));\r
-                       ;\r
-                       doCount(count += taxonList.size(), modCount, inferredSynonymPluralString);\r
-                       // Commit transaction\r
-                       commitTransaction(txStatus);\r
-                       logger.debug("Committed transaction.");\r
-                       logger.info("Exported " + taxonList.size()+ " " + inferredSynonymPluralString + ". Total: " + count);\r
-                       //pastCount = count;\r
-                       \r
-                       // Save Rank Data and KingdomFk for inferred synonyms\r
-                       for (Integer taxonFk : inferredSynonymsDataToBeSaved.keySet()) {\r
-                               invokeRankDataAndKingdomFk(inferredSynonymsDataToBeSaved.get(taxonFk), nomenclaturalCode, taxonFk, kingdomFk, state);\r
-                       }\r
-\r
-                       // Start transaction\r
-                       txStatus = startTransaction(true);\r
-                       logger.info("Started new transaction. Fetching some " + parentPluralString + " first (max: " + limit + ") ...");\r
-                       \r
-                       // Increment pageNumber\r
-                       pageNumber++;\r
-               }\r
-               if (taxonList.size() == 0) {\r
-                       logger.info("No " + parentPluralString + " left to fetch.");\r
-               }\r
-               \r
-               taxonList = null;\r
-//             logger.warn("Taking snapshot at the end of phase 4 of taxonExport");\r
-//             ProfilerController.memorySnapshot();\r
-               \r
-               // Commit transaction\r
-               commitTransaction(txStatus);\r
-               System.gc();\r
-               logger.debug("Taking snapshot at the end of phase 4 after gc() of taxonExport");\r
-               ProfilerController.memorySnapshot();\r
-               logger.debug("Committed transaction.");\r
-               return success;\r
-       }\r
-\r
-       /**\r
-        * @param state\r
-        * @param mapping\r
-        * @param synRelMapping\r
-        * @param currentTaxonId\r
-        * @param taxonList\r
-        * @param inferredSynonymsDataToBeSaved\r
-        * @return\r
-        */\r
-       private HashMap<Integer, TaxonNameBase<?, ?>> createInferredSynonymsForTaxonList(PesiExportState state,\r
-                       PesiExportMapping mapping, PesiExportMapping synRelMapping,      List<TaxonBase> taxonList) {\r
-               \r
-               Taxon acceptedTaxon;\r
-               Classification classification = null;\r
-               List<Synonym> inferredSynonyms = null;\r
-               boolean localSuccess = true;\r
-               \r
-               HashMap<Integer, TaxonNameBase<?,?>> inferredSynonymsDataToBeSaved = new HashMap<Integer, TaxonNameBase<?,?>>();\r
-               \r
-               for (TaxonBase<?> taxonBase : taxonList) {\r
-               \r
-                       if (taxonBase.isInstanceOf(Taxon.class)) { // this should always be the case since we should have fetched accepted taxon only, but you never know...\r
-                               acceptedTaxon = CdmBase.deproxy(taxonBase, Taxon.class);\r
-                               TaxonNameBase<?,?> taxonName = acceptedTaxon.getName();\r
-                               \r
-                               if (taxonName.isInstanceOf(ZoologicalName.class)) {\r
-                                       nomenclaturalCode  = taxonName.getNomenclaturalCode();\r
-                                       kingdomFk = PesiTransformer.nomenClaturalCode2Kingdom(nomenclaturalCode);\r
-\r
-                                       Set<TaxonNode> taxonNodes = acceptedTaxon.getTaxonNodes();\r
-                                       TaxonNode singleNode = null;\r
-                                       \r
-                                       if (taxonNodes.size() > 0) {\r
-                                               // Determine the classification of the current TaxonNode\r
-                                               \r
-                                               singleNode = taxonNodes.iterator().next();\r
-                                               if (singleNode != null) {\r
-                                                       classification = singleNode.getClassification();\r
-                                               } else {\r
-                                                       logger.error("A TaxonNode belonging to this accepted Taxon is NULL: " + acceptedTaxon.getUuid() + " (" + acceptedTaxon.getTitleCache() +")");\r
-                                               }\r
-                                       } else {\r
-                                               // Classification could not be determined directly from this TaxonNode\r
-                                               // The stored classification from another TaxonNode is used. It's a simple, but not a failsafe fallback solution.\r
-                                               if (taxonNodes.size() == 0) {\r
-                                                       //logger.error("Classification could not be determined directly from this Taxon: " + acceptedTaxon.getUuid() + " is misapplication? "+acceptedTaxon.isMisapplication()+ "). The classification of the last taxon is used");\r
-                                               \r
-                                               }\r
-                                       }\r
-                                       \r
-                                       if (classification != null) {\r
-                                               try{\r
-                                                       TaxonNameBase name = acceptedTaxon.getName();\r
-                                                       //if (name.isSpecies() || name.isInfraSpecific()){\r
-                                                               inferredSynonyms  = getTaxonService().createAllInferredSynonyms(acceptedTaxon, classification, true);\r
-                                                       //}\r
-//                                                             inferredSynonyms = getTaxonService().createInferredSynonyms(classification, acceptedTaxon, SynonymRelationshipType.INFERRED_GENUS_OF());\r
-                                                       if (inferredSynonyms != null) {\r
-                                                               for (Synonym synonym : inferredSynonyms) {\r
-//                                                                     TaxonNameBase<?,?> synonymName = synonym.getName();\r
-                                                                       MarkerType markerType =getUuidMarkerType(PesiTransformer.uuidMarkerGuidIsMissing, state);\r
-                                                                       synonym.addMarker(Marker.NewInstance(markerType, true));\r
-                                                                       // Both Synonym and its TaxonName have no valid Id yet\r
-                                                                       synonym.setId(currentTaxonId++);\r
-                                                                       \r
-                                                                       \r
-                                                                       localSuccess &= mapping.invoke(synonym);\r
-                                                                       //get SynonymRelationship and export\r
-                                                                       if (synonym.getSynonymRelations().isEmpty() ){\r
-                                                                               SynonymRelationship synRel;                                     \r
-                                                                               IdentifiableSource source = synonym.getSources().iterator().next();\r
-                                                                               if (source.getIdNamespace().contains("Potential combination")){\r
-                                                                                       synRel = acceptedTaxon.addSynonym(synonym, SynonymRelationshipType.POTENTIAL_COMBINATION_OF());\r
-                                                                                       logger.error(synonym.getTitleCache() + " has no synonym relationship to " + acceptedTaxon.getTitleCache() + " type is set to potential combination");\r
-                                                                               } else if (source.getIdNamespace().contains("Inferred Genus")){\r
-                                                                                       synRel = acceptedTaxon.addSynonym(synonym, SynonymRelationshipType.INFERRED_GENUS_OF());\r
-                                                                                       logger.error(synonym.getTitleCache() + " has no synonym relationship to " + acceptedTaxon.getTitleCache() + " type is set to inferred genus");\r
-                                                                               } else if (source.getIdNamespace().contains("Inferred Epithet")){\r
-                                                                                       synRel = acceptedTaxon.addSynonym(synonym, SynonymRelationshipType.INFERRED_EPITHET_OF());\r
-                                                                                       logger.error(synonym.getTitleCache() + " has no synonym relationship to " + acceptedTaxon.getTitleCache() + " type is set to inferred epithet");\r
-                                                                               } else{\r
-                                                                                       synRel = acceptedTaxon.addSynonym(synonym, SynonymRelationshipType.INFERRED_SYNONYM_OF());\r
-                                                                                       logger.error(synonym.getTitleCache() + " has no synonym relationship to " + acceptedTaxon.getTitleCache() + " type is set to inferred synonym");\r
-                                                                               }\r
-                                                                               \r
-                                                                               localSuccess &= synRelMapping.invoke(synRel);\r
-                                                                               if (!localSuccess) {\r
-                                                                                       logger.error("Synonym relationship export failed " + synonym.getTitleCache() + " accepted taxon: " + acceptedTaxon.getUuid() + " (" + acceptedTaxon.getTitleCache()+")");\r
-                                                                               }\r
-                                                                               synRel = null;\r
-                                                                       } else {\r
-                                                                               for (SynonymRelationship synRel: synonym.getSynonymRelations()){\r
-                                                                                       localSuccess &= synRelMapping.invoke(synRel);\r
-                                                                                       if (!localSuccess) {\r
-                                                                                               logger.error("Synonym relationship export failed " + synonym.getTitleCache() + " accepted taxon: " + acceptedTaxon.getUuid() + " (" + acceptedTaxon.getTitleCache()+")");\r
-                                                                                       } else {\r
-                                                                                               logger.info("Synonym relationship successfully exported: " + synonym.getTitleCache() + "  " +acceptedTaxon.getUuid() + " (" + acceptedTaxon.getTitleCache()+")");\r
-                                                                                       }\r
-                                                                                       synRel = null;\r
-                                                                               }\r
-                                                                       }\r
-                                                                       \r
-                                                                       inferredSynonymsDataToBeSaved.put(synonym.getId(), synonym.getName());\r
-                                                               }\r
-                                                       }\r
-                                               }catch(Exception e){\r
-                                                       logger.error(e.getMessage());\r
-                                                       e.printStackTrace();\r
-                                               }\r
-                                       } else {\r
-                                               logger.error("Classification is NULL. Inferred Synonyms could not be created for this Taxon: " + acceptedTaxon.getUuid() + " (" + acceptedTaxon.getTitleCache() + ")");\r
-                                       }\r
-                               } else {\r
-//                                                     logger.error("TaxonName is not a ZoologicalName: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");\r
-                               }\r
-                       } else {\r
-                               logger.error("This TaxonBase is not a Taxon even though it should be: " + taxonBase.getUuid() + " (" + taxonBase.getTitleCache() + ")");\r
-                       }\r
-               }\r
-               taxonList = null;\r
-               return inferredSynonymsDataToBeSaved;\r
-       }\r
-       \r
-\r
-       /**\r
-        * Handles names that do not appear in taxa\r
-        * @param state\r
-        * @param mapping\r
-        * @return\r
-        */\r
-       private boolean doNames(PesiExportState state, PesiExportMapping additionalSourceMapping)  throws SQLException {\r
-               \r
-               boolean success = true;\r
-               if (! state.getConfig().isDoPureNames()){\r
-                       logger.info ("Ignore PHASE 1b: PureNames");\r
-                       return success;\r
-               }\r
-               \r
-               try {\r
-                       PesiExportMapping mapping = getPureNameMapping(state);\r
-                       mapping.initialize(state);\r
-                       int count = 0;\r
-                       int pastCount = 0;\r
-                       List<NonViralName<?>> list;\r
-                       success = true;\r
-                       // Get the limit for objects to save within a single transaction.\r
-                       int limit = state.getConfig().getLimitSave();\r
-\r
-                       \r
-                       logger.info("PHASE 1b: Export Pure Names ...");\r
-                       // Start transaction\r
-                       TransactionStatus txStatus = startTransaction(true);\r
-                       logger.info("Started new transaction for Pure Names. Fetching some " + pluralString + " (max: " + limit + ") ...");\r
-                       \r
-                       int partitionCount = 0;\r
-                       while ((list = getNextPureNamePartition(null, limit, partitionCount++)) != null   ) {\r
-\r
-                               logger.info("Fetched " + list.size() + " names without taxa. Exporting...");\r
-                               for (TaxonNameBase<?,?> taxonName : list) {\r
-                                       doCount(count++, modCount, pluralString);\r
-                                       success &= mapping.invoke(taxonName);\r
-                                       //additional source\r
-                                       if (taxonName.getNomenclaturalReference() != null || StringUtils.isNotBlank(taxonName.getNomenclaturalMicroReference() )){\r
-                                               additionalSourceMapping.invoke(taxonName);\r
-                                       }\r
-                               }\r
-\r
-                               // Commit transaction\r
-                               commitTransaction(txStatus);\r
-                               logger.debug("Committed transaction.");\r
-                               logger.info("Exported " + (count - pastCount) + " " + pluralString + ". Total: " + count);\r
-                               pastCount = count;\r
-\r
-                               // Start transaction\r
-                               txStatus = startTransaction(true);\r
-                               logger.info("Started new transaction for PureNames. Fetching some " + pluralString + " (max: " + limit + ") ...");\r
-                       }\r
-                       if (list == null) {\r
-                               logger.info("No " + pluralString + " left to fetch.");\r
-                       }\r
-                       // Commit transaction\r
-                       commitTransaction(txStatus);\r
-                       logger.debug("Committed transaction.");\r
-               } catch (Exception e) {\r
-                       logger.error("Error occurred in pure name export");\r
-                       e.printStackTrace();\r
-                       success = false;\r
-               }\r
-               return success;\r
-       }\r
-\r
-       /**\r
-        * Determines the current number of entries in the DataWarehouse database table <code>Taxon</code>.\r
-        * @param state The {@link PesiExportState PesiExportState}.\r
-        * @return The count.\r
-        */\r
-       private Integer determineTaxonCount(PesiExportState state) {\r
-               Integer result = null;\r
-               PesiExportConfigurator pesiConfig = (PesiExportConfigurator) state.getConfig();\r
-               \r
-               String sql;\r
-               Source destination =  pesiConfig.getDestination();\r
-               sql = "SELECT max(taxonId) FROM Taxon";\r
-               destination.setQuery(sql);\r
-               ResultSet resultSet = destination.getResultSet();\r
-               try {\r
-                       resultSet.next();\r
-                       result = resultSet.getInt(1);\r
-               } catch (SQLException e) {\r
-                       logger.error("TaxonCount could not be determined: " + e.getMessage());\r
-                       e.printStackTrace();\r
-               }\r
-               return result;\r
-       }\r
-       \r
-       /**\r
-        * Checks whether a parent at specific level has a specific Rank.\r
-        * @param taxonName A {@link TaxonNameBase TaxonName}.\r
-        * @param level The ancestor level.\r
-        * @param ancestorRank The ancestor rank.\r
-        * @return Whether a parent at a specific level has a specific Rank.\r
-        */\r
-       private boolean validateAncestorOfSpecificRank(TaxonBase<?> taxonBase, int level, Rank ancestorRank) {\r
-               boolean result = false;\r
-               TaxonNode parentNode = null;\r
-               if (taxonBase.isInstanceOf(Taxon.class)){\r
-                       Taxon taxon = CdmBase.deproxy(taxonBase, Taxon.class);\r
-                       // Get ancestor Taxon via TaxonNode\r
-                       Set<TaxonNode> taxonNodes = taxon.getTaxonNodes();\r
-                       if (taxonNodes.size() == 1) {\r
-                               TaxonNode taxonNode = taxonNodes.iterator().next();\r
-                               if (taxonNode != null) {\r
-                                       for (int i = 0; i < level; i++) {\r
-                                               if (taxonNode != null) {\r
-                                                       taxonNode  = taxonNode.getParent();\r
-                                               }\r
-                                       }\r
-                                       parentNode = taxonNode;\r
-                               }\r
-                       } else if (taxonNodes.size() > 1) {\r
-                               logger.error("This taxon has " + taxonNodes.size() + " taxonNodes: " + taxon.getUuid() + " (" + taxon.getTitleCache() + ")");\r
-                       }\r
-               }\r
-               //compare\r
-               if (parentNode != null) {\r
-                       TaxonNode node = CdmBase.deproxy(parentNode, TaxonNode.class);\r
-                       Taxon parentTaxon = node.getTaxon();\r
-                       if (parentTaxon != null) {\r
-                               TaxonNameBase<?,?> parentTaxonName = parentTaxon.getName();\r
-                               if (parentTaxonName != null && parentTaxonName.getRank().equals(ancestorRank)) {\r
-                                       result = true;\r
-                               }\r
-                       } else if (parentNode.treeIndex().matches("#t\\d+#\\d+#")) {\r
-                               //do nothing (is root node)\r
-                       } else {\r
-                               logger.error("This TaxonNode has no Taxon: " + node.getUuid());\r
-                       }\r
-               }\r
-               return result;\r
-       }\r
-\r
-       /**\r
-        * Returns the AnnotationType for a given UUID.\r
-        * @param uuid The Annotation UUID.\r
-        * @param label The Annotation label.\r
-        * @param text The Annotation text.\r
-        * @param labelAbbrev The Annotation label abbreviation.\r
-        * @return The AnnotationType.\r
-        */\r
-       protected AnnotationType getAnnotationType(UUID uuid, String label, String text, String labelAbbrev){\r
-               AnnotationType annotationType = (AnnotationType)getTermService().find(uuid);\r
-               if (annotationType == null) {\r
-                       annotationType = AnnotationType.NewInstance(label, text, labelAbbrev);\r
-                       annotationType.setUuid(uuid);\r
-//                     annotationType.setVocabulary(AnnotationType.EDITORIAL().getVocabulary());\r
-                       getTermService().save(annotationType);\r
-               }\r
-               return annotationType;\r
-       }\r
-\r
-       /**\r
-        * Traverses the classification recursively and stores determined values for every Taxon.\r
-        * @param childNode The {@link TaxonNode TaxonNode} to process.\r
-        * @param parentNode The parent {@link TaxonNode TaxonNode} of the childNode.\r
-        * @param treeIndex The TreeIndex at the current level.\r
-        * @param fetchLevel Rank to stop fetching at.\r
-        * @param state The {@link PesiExportState PesiExportState}.\r
-        */\r
-       private void traverseTree(TaxonNode childNode, TaxonNode parentNode, StringBuffer treeIndex, Rank fetchLevel, PesiExportState state) {\r
-               // Traverse all branches from this childNode until specified fetchLevel is reached.\r
-               StringBuffer localTreeIndex = new StringBuffer(treeIndex);\r
-               Taxon childTaxon = childNode.getTaxon();\r
-               if (childTaxon != null) {\r
-                       if (isPesiTaxon(childTaxon)){\r
-                               Integer taxonId = state.getDbId(childTaxon);\r
-                               TaxonNameBase<?,?> childName = childTaxon.getName();\r
-                               if (taxonId != null) {\r
-                                       Rank childRank = childName.getRank();\r
-                                       if (childRank != null) {\r
-                                               if (! childRank.equals(fetchLevel)) {\r
-       \r
-                                                       localTreeIndex.append(taxonId + "#");\r
-                                                       \r
-                                                       saveData(childNode, parentNode, localTreeIndex, state, taxonId);\r
-       \r
-                                                       // Store treeIndex as annotation for further use\r
-                                                       Annotation annotation = Annotation.NewInstance(localTreeIndex.toString(), getTreeIndexAnnotationType(), Language.DEFAULT());\r
-                                                       childNode.addAnnotation(annotation);\r
-       \r
-                                                       for (TaxonNode newNode : childNode.getChildNodes()) {\r
-                                                               if (newNode.getTaxon() != null && isPesiTaxon(newNode.getTaxon())){\r
-                                                                       traverseTree(newNode, childNode, localTreeIndex, fetchLevel, state);\r
-                                                               }\r
-                                                       }\r
-                                                       \r
-                                               } else {\r
-       //                                              logger.debug("Target Rank " + fetchLevel.getLabel() + " reached");\r
-                                                       return;\r
-                                               }\r
-                                       } else {\r
-                                               logger.error("Rank is NULL. FetchLevel can not be checked: " + childName.getUuid() + " (" + childName.getTitleCache() + ")");\r
-                                       }\r
-                               } else {\r
-                                       logger.error("Taxon can not be found in state: " + childTaxon.getUuid() + " (" + childTaxon.getTitleCache() + ")");\r
-                               }\r
-                       }else{\r
-                               if (logger.isDebugEnabled()){ \r
-                                       logger.debug("Taxon is not a PESI taxon: " + childTaxon.getUuid());\r
-                               }\r
-                       }\r
-\r
-               } else {\r
-                       logger.error("Taxon is NULL for TaxonNode: " + childNode.getUuid());\r
-               }\r
-       }\r
-\r
-       /**\r
-        * Stores values in database for every recursive round.\r
-        * @param childNode The {@link TaxonNode TaxonNode} to process.\r
-        * @param parentNode The parent {@link TaxonNode TaxonNode} of the childNode.\r
-        * @param treeIndex The TreeIndex at the current level.\r
-        * @param state The {@link PesiExportState PesiExportState}.\r
-        * @param currentTaxonFk The TaxonFk to store the values for.\r
-        */\r
-       private void saveData(TaxonNode childNode, TaxonNode parentNode, StringBuffer treeIndex, PesiExportState state, Integer currentTaxonFk) {\r
-               // We are differentiating kingdoms by the nomenclatural code for now.\r
-               // This needs to be handled in a better way as soon as we know how to differentiate between more kingdoms.\r
-               Taxon childTaxon = childNode.getTaxon();\r
-               if (isPesiTaxon(childTaxon)) {\r
-                       TaxonBase<?> parentTaxon = null;\r
-                       if (parentNode != null) {\r
-                               parentTaxon = parentNode.getTaxon();\r
-                               \r
-                       }\r
-\r
-                       invokeParentTaxonFkAndTreeIndex(state.getDbId(parentTaxon), currentTaxonFk,     treeIndex);\r
-               }\r
-               \r
-       }\r
-\r
-       /**\r
-        * Inserts values into the Taxon database table.\r
-        * @param taxonName The {@link TaxonNameBase TaxonName}.\r
-        * @param state The {@link PesiExportState PesiExportState}.\r
-        * @param stmt The prepared statement.\r
-        * @return Whether save was successful or not.\r
-        */\r
-       protected boolean invokeParentTaxonFkAndTreeIndex(Integer parentTaxonFk, Integer currentTaxonFk, StringBuffer treeIndex) {\r
-               try {\r
-                       if (parentTaxonFk != null) {\r
-                               parentTaxonFk_TreeIndex_KingdomFkStmt.setInt(1, parentTaxonFk);\r
-                       } else {\r
-                               parentTaxonFk_TreeIndex_KingdomFkStmt.setObject(1, null);\r
-                       }\r
-\r
-                       if (treeIndex != null) {\r
-                               parentTaxonFk_TreeIndex_KingdomFkStmt.setString(2, treeIndex.toString());\r
-                       } else {\r
-                               parentTaxonFk_TreeIndex_KingdomFkStmt.setObject(2, null);\r
-                       }\r
-\r
-                       if (currentTaxonFk != null) {\r
-                               parentTaxonFk_TreeIndex_KingdomFkStmt.setInt(3, currentTaxonFk);\r
-                       } else {\r
-                               parentTaxonFk_TreeIndex_KingdomFkStmt.setObject(3, null);\r
-                       }\r
-                       \r
-                       parentTaxonFk_TreeIndex_KingdomFkStmt.executeUpdate();\r
-                       return true;\r
-               } catch (SQLException e) {\r
-                       logger.error("ParentTaxonFk (" + parentTaxonFk ==null? "-":parentTaxonFk + ") and TreeIndex could not be inserted into database for taxon "+ (currentTaxonFk == null? "-" :currentTaxonFk) + ": " + e.getMessage());\r
-                       e.printStackTrace();\r
-                       return false;\r
-               }\r
-       }\r
-       \r
-       protected boolean invokeParentTaxonFk(Integer parentId, Integer childId) {\r
-               try {\r
-                       parentTaxonFkStmt.setInt(1, parentId);\r
-                       parentTaxonFkStmt.setInt(2, childId);\r
-                       parentTaxonFkStmt.executeUpdate();\r
-                       return true;\r
-               } catch (SQLException e) {\r
-                       logger.warn("ParentTaxonFk (" + parentId ==null? "-":parentId + ") could not be inserted into database for taxon "+ (childId == null? "-" :childId) + ": " + e.getMessage());\r
-                       e.printStackTrace();\r
-                       return false;\r
-               }\r
-       }\r
-\r
-\r
-       /**\r
-        * Inserts Rank data and KingdomFk into the Taxon database table.\r
-        * @param taxonName The {@link TaxonNameBase TaxonName}.\r
-        * @param nomenclaturalCode The {@link NomenclaturalCode NomenclaturalCode}.\r
-        * @param taxonFk The TaxonFk to store the values for.\r
-        * @param state \r
-        * @param kindomFk The KingdomFk.\r
-        * @return Whether save was successful or not.\r
-        */\r
-       private boolean invokeRankDataAndKingdomFk(TaxonNameBase<?,?> taxonName, NomenclaturalCode nomenclaturalCode, Integer taxonFk, Integer kingdomFk, PesiExportState state) {\r
-               try {\r
-                       Integer rankFk = getRankFk(taxonName, nomenclaturalCode);\r
-                       if (rankFk != null) {\r
-                               rankUpdateStmt.setInt(1, rankFk);\r
-                       } else {\r
-                               rankUpdateStmt.setObject(1, null);\r
-                       }\r
-       \r
-                       String rankCache = getRankCache(taxonName, nomenclaturalCode, state);\r
-                       if (rankCache != null) {\r
-                               rankUpdateStmt.setString(2, rankCache);\r
-                       } else {\r
-                               rankUpdateStmt.setObject(2, null);\r
-                       }\r
-                       \r
-                       if (kingdomFk != null) {\r
-                               rankUpdateStmt.setInt(3, kingdomFk);\r
-                       } else {\r
-                               rankUpdateStmt.setObject(3, null);\r
-                       }\r
-                       \r
-                       if (taxonFk != null) {\r
-                               rankUpdateStmt.setInt(4, taxonFk);\r
-                       } else {\r
-                               rankUpdateStmt.setObject(4, null);\r
-                       }\r
-                       \r
-                       rankUpdateStmt.executeUpdate();\r
-                       return true;\r
-               } catch (SQLException e) {\r
-                       logger.error("Data (RankFk, RankCache, KingdomFk) could not be inserted into database: " + e.getMessage());\r
-                       e.printStackTrace();\r
-                       return false;\r
-               }\r
-       }\r
-\r
-       /**\r
-        * Inserts Rank data, TypeNameFk, KingdomFk, expertFk and speciesExpertFk into the Taxon database table.\r
-        * @param taxonName The {@link TaxonNameBase TaxonName}.\r
-        * @param nomenclaturalCode The {@link NomenclaturalCode NomenclaturalCode}.\r
-        * @param taxonFk The TaxonFk to store the values for.\r
-        * @param typeNameFk The TypeNameFk.\r
-        * @param state \r
-        * @param kindomFk The KingdomFk.\r
-        * @param expertFk The ExpertFk.\r
-        * @param speciesExpertFk The SpeciesExpertFk.\r
-        * @return Whether save was successful or not.\r
-        */\r
-       private boolean invokeRankDataAndTypeNameFkAndKingdomFk(TaxonNameBase<?,?> taxonName, NomenclaturalCode nomenclaturalCode, \r
-                       Integer taxonFk, Integer typeNameFk, Integer kingdomFkk, PesiExportState state) {\r
-               try {\r
-                       int index = 1;\r
-                       Integer rankFk = getRankFk(taxonName, nomenclaturalCode);\r
-                       if (rankFk != null) {\r
-                               rankTypeExpertsUpdateStmt.setInt(index++, rankFk);\r
-                       } else {\r
-                               rankTypeExpertsUpdateStmt.setObject(index++, null);\r
-                       }\r
-       \r
-                       String rankCache = getRankCache(taxonName, nomenclaturalCode, state);\r
-                       if (rankCache != null) {\r
-                               rankTypeExpertsUpdateStmt.setString(index++, rankCache);\r
-                       } else {\r
-                               rankTypeExpertsUpdateStmt.setObject(index++, null);\r
-                       }\r
-                       \r
-                       if (typeNameFk != null) {\r
-                               rankTypeExpertsUpdateStmt.setInt(index++, typeNameFk);\r
-                       } else {\r
-                               rankTypeExpertsUpdateStmt.setObject(index++, null);\r
-                       }\r
-                       \r
-                       if (kingdomFk != null) {\r
-                               rankTypeExpertsUpdateStmt.setInt(index++, kingdomFk);\r
-                       } else {\r
-                               rankTypeExpertsUpdateStmt.setObject(index++, null);\r
-                       }\r
-                       \r
-//                     if (expertFk != null) {\r
-//                             rankTypeExpertsUpdateStmt.setInt(5, expertFk);\r
-//                     } else {\r
-//                             rankTypeExpertsUpdateStmt.setObject(5, null);\r
-//                     }\r
-//\r
-//                     //TODO handle experts GUIDS\r
-//                     if (speciesExpertFk != null) {\r
-//                             rankTypeExpertsUpdateStmt.setInt(6, speciesExpertFk);\r
-//                     } else {\r
-//                             rankTypeExpertsUpdateStmt.setObject(6, null);\r
-//                     }\r
-//                     \r
-                       if (taxonFk != null) {\r
-                               rankTypeExpertsUpdateStmt.setInt(index++, taxonFk);\r
-                       } else {\r
-                               rankTypeExpertsUpdateStmt.setObject(index++, null);\r
-                       }\r
-\r
-                       rankTypeExpertsUpdateStmt.executeUpdate();\r
-                       return true;\r
-               } catch (SQLException e) {\r
-                       logger.error("Data could not be inserted into database: " + e.getMessage());\r
-                       e.printStackTrace();\r
-                       return false;\r
-               } catch (Exception e) {\r
-                       logger.error("Some exception occurred: " + e.getMessage());\r
-                       e.printStackTrace();\r
-                       return false;\r
-               }\r
-       }\r
-\r
-       /**\r
-        * Deletes all entries of database tables related to <code>Taxon</code>.\r
-        * @param state The {@link PesiExportState PesiExportState}.\r
-        * @return Whether the delete operation was successful or not.\r
-        */\r
-       protected boolean doDelete(PesiExportState state) {\r
-               PesiExportConfigurator pesiConfig = (PesiExportConfigurator) state.getConfig();\r
-               \r
-               String sql;\r
-               Source destination =  pesiConfig.getDestination();\r
-\r
-               // Clear Taxon\r
-               sql = "DELETE FROM " + dbTableName;\r
-               destination.setQuery(sql);\r
-               destination.update(sql);\r
-               return true;\r
-       }\r
-\r
-       /* (non-Javadoc)\r
-        * @see eu.etaxonomy.cdm.io.common.CdmIoBase#isIgnore(eu.etaxonomy.cdm.io.common.IoStateBase)\r
-        */\r
-       @Override\r
-       protected boolean isIgnore(PesiExportState state) {\r
-               return ! state.getConfig().isDoTaxa();\r
-       }\r
-\r
-       \r
-       /**\r
-        * Creates the kingdom fk.\r
-        * @param taxonName\r
-        * @return\r
-        */\r
-       @SuppressWarnings("unused")  //used by mapper\r
-       private static Integer getKingdomFk(TaxonNameBase taxonName){\r
-               return PesiTransformer.nomenClaturalCode2Kingdom(taxonName.getNomenclaturalCode());\r
-       }\r
-       \r
-       /**\r
-        * Creates the parent fk.\r
-        * @param taxonName\r
-        * @return\r
-        */\r
-       @SuppressWarnings("unused")  //used by mapper\r
-       private static Integer getParentTaxonFk(TaxonBase<?> taxonBase, PesiExportState state){\r
-               if (taxonBase.isInstanceOf(Taxon.class)){\r
-                       Taxon taxon = CdmBase.deproxy(taxonBase, Taxon.class);\r
-                       if (! isMisappliedName(taxon)){\r
-                               Set<TaxonNode> nodes = taxon.getTaxonNodes();\r
-                               if (nodes.size() == 0){\r
-                                       if (taxon.getName().getRank().isLower(Rank.KINGDOM())){\r
-                                               logger.warn("Accepted taxon has no parent. " + taxon.getTitleCache() + ", " +  taxon.getUuid());\r
-                                       }\r
-                               }else if (nodes.size() > 1){\r
-                                       logger.warn("Taxon has more than 1 node attached. This is not supported by PESI export." +  taxon.getTitleCache() + ", " +  taxon.getUuid());\r
-                               }else{\r
-                                       Taxon parent =nodes.iterator().next().getParent().getTaxon();\r
-                                       return state.getDbId(parent);\r
-                               }\r
-                       }\r
-               }\r
-               return null;\r
-       }\r
-\r
-       /**\r
-        * Returns the rankFk for the taxon name based on the names nomenclatural code.\r
-        * You may not use this method for kingdoms other then Animalia, Plantae and Bacteria.\r
-        * @param taxonName\r
-        * @return\r
-        */\r
-       @SuppressWarnings("unused")  //used by mapper\r
-       private static Integer getRankFk(TaxonNameBase<?,?> taxonName) {\r
-               return getRankFk(taxonName, taxonName.getNomenclaturalCode());\r
-       }\r
-               \r
-       \r
-       /**\r
-        * Returns the <code>RankFk</code> attribute.\r
-        * @param taxonName The {@link TaxonNameBase TaxonName}.\r
-        * @param nomenclaturalCode The {@link NomenclaturalCode NomenclaturalCode}.\r
-        * @return The <code>RankFk</code> attribute.\r
-        * @see MethodMapper\r
-        */\r
-       private static Integer getRankFk(TaxonNameBase<?,?> taxonName, NomenclaturalCode nomenclaturalCode) {\r
-               Integer result = null;\r
-               try {\r
-                       if (nomenclaturalCode != null) {\r
-                               if (taxonName != null) {\r
-                                       if (taxonName.getRank() == null) {\r
-                                               logger.warn("Rank is null: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");\r
-                                       } else {\r
-                                               result = PesiTransformer.rank2RankId(taxonName.getRank(), PesiTransformer.nomenClaturalCode2Kingdom(nomenclaturalCode));\r
-                                       }\r
-                                       if (result == null) {\r
-                                               logger.warn("Rank could not be determined for PESI-Kingdom-Id " + PesiTransformer.nomenClaturalCode2Kingdom(nomenclaturalCode) + " and TaxonName " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");\r
-                                       }\r
-                               }\r
-                       }\r
-               } catch (Exception e) {\r
-                       e.printStackTrace();\r
-               }\r
-               return result;\r
-       }\r
-\r
-       /**\r
-        * Returns the rank cache for the taxon name based on the names nomenclatural code.\r
-        * You may not use this method for kingdoms other then Animalia, Plantae and Bacteria.\r
-        * @param taxonName\r
-        * @return\r
-        */\r
-       @SuppressWarnings("unused")  //used by mapper\r
-       private static String getRankCache(TaxonNameBase<?,?> taxonName, PesiExportState state) {\r
-               return getRankCache(taxonName, taxonName.getNomenclaturalCode(), state);\r
-       }\r
-\r
-       \r
-       /**\r
-        * Returns the <code>RankCache</code> attribute.\r
-        * @param taxonName The {@link TaxonNameBase TaxonName}.\r
-        * @param nomenclaturalCode The {@link NomenclaturalCode NomenclaturalCode}.\r
-        * @param state \r
-        * @return The <code>RankCache</code> attribute.\r
-        * @see MethodMapper\r
-        */\r
-       private static String getRankCache(TaxonNameBase<?,?> taxonName, NomenclaturalCode nomenclaturalCode, PesiExportState state) {\r
-               if (nomenclaturalCode != null) {\r
-                       return state.getTransformer().getCacheByRankAndKingdom(taxonName.getRank(), PesiTransformer.nomenClaturalCode2Kingdom(nomenclaturalCode));\r
-               }else{\r
-                       logger.warn("No nomenclatural code defined for name " + taxonName.getUuid());\r
-                       return null;\r
-               }\r
-               \r
-       }\r
-\r
-       \r
-       /**\r
-        * Returns the <code>DisplayName</code> attribute.\r
-        * @param taxon The {@link TaxonBase Taxon}.\r
-        * @return The <code>DisplayName</code> attribute.\r
-        * @see MethodMapper\r
-        */\r
-       @SuppressWarnings("unused")  //used by Mapper\r
-       private static String getDisplayName(TaxonBase<?> taxon) {\r
-               TaxonNameBase<?,?> taxonName = taxon.getName();\r
-               String result = getDisplayName(taxonName);\r
-               if (isMisappliedName(taxon)){\r
-                       result = result + " " + getAuthorString(taxon);\r
-               }\r
-               return result;\r
-       }\r
-       \r
-       /**\r
-        * Returns the <code>AuthorString</code> attribute.\r
-        * @param taxonName The {@link TaxonNameBase TaxonName}.\r
-        * @return The <code>AuthorString</code> attribute.\r
-        * @see MethodMapper\r
-        */\r
-       @SuppressWarnings("unused") //used by mapper\r
-       protected static String getAuthorString(TaxonBase<?> taxon) {\r
-               try {\r
-                       String result = null;\r
-                       boolean isNonViralName = false;\r
-                       String authorshipCache = null;\r
-                       TaxonNameBase<?,?> taxonName = taxon.getName();\r
-                       if (taxonName != null && taxonName.isInstanceOf(NonViralName.class)){\r
-                               authorshipCache = CdmBase.deproxy(taxonName, NonViralName.class).getAuthorshipCache();\r
-                               isNonViralName = true;\r
-                       }\r
-                       result = authorshipCache;\r
-                       \r
-                       // For a misapplied names there are special rules\r
-                       if (isMisappliedName(taxon)){\r
-                               if (taxon.getSec() != null){\r
-                                       String secTitle = taxon.getSec().getTitleCache();\r
-                                       if (! secTitle.startsWith("auct")){\r
-                                               secTitle = "sensu " + secTitle;\r
-                                       }else if (secTitle.equals("auct")){  //may be removed once the title cache is generated correctly for references with title auct. #\r
-                                               secTitle = "auct.";\r
-                                       }\r
-                                       return secTitle;\r
-                               }else if (StringUtils.isBlank(authorshipCache)) {\r
-                                       // Set authorshipCache to "auct."\r
-                                       result = PesiTransformer.AUCT_STRING;\r
-                               }else{\r
-                                       result = PesiTransformer.AUCT_STRING;\r
-//                                     result = authorshipCache;\r
-                               }\r
-                       }\r
-                       \r
-                       if (taxonName == null){\r
-                               logger.warn("TaxonName does not exist for taxon: " + taxon.getUuid() + " (" + taxon.getTitleCache() + ")");\r
-                       }else if (! isNonViralName){\r
-                               logger.warn("TaxonName is not of instance NonViralName: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");\r
-                       }\r
-                       \r
-                       if (StringUtils.isBlank(result)) {\r
-                               return null;\r
-                       } else {\r
-                               return result;\r
-                       }\r
-               } catch (Exception e) {\r
-                       e.printStackTrace();\r
-                       return null;\r
-               }\r
-               \r
-       }\r
-               \r
-       \r
-       /**\r
-        * Returns the <code>DisplayName</code> attribute.\r
-        * @param taxonName The {@link TaxonNameBase TaxonName}.\r
-        * @return The <code>DisplayName</code> attribute.\r
-        * @see MethodMapper\r
-        */\r
-       @SuppressWarnings("unused")  //used by Mapper\r
-       private static String getDisplayName(TaxonNameBase<?,?> taxonName) {\r
-               // TODO: extension?\r
-               if (taxonName == null) {\r
-                       return null;\r
-               }else{\r
-                       INonViralNameCacheStrategy<NonViralName<?>> cacheStrategy = getCacheStrategy(taxonName);\r
-                       HTMLTagRules tagRules = new HTMLTagRules().\r
-                                       addRule(TagEnum.name, "i").\r
-                                       addRule(TagEnum.nomStatus, "@status@");\r
-                       \r
-                       NonViralName<?> nvn = CdmBase.deproxy(taxonName, NonViralName.class);\r
-                       String result = cacheStrategy.getFullTitleCache(nvn, tagRules);\r
-                       cacheStrategy = null;\r
-                       nvn = null;\r
-                       return result.replaceAll(",?\\<@status@\\>.*\\</@status@\\>", "");\r
-               }\r
-       }\r
-       \r
-\r
-       /**\r
-        * Returns the <code>WebShowName</code> attribute for a taxon.\r
-        * @param taxonName The {@link TaxonNameBase TaxonName}.\r
-        * @return The <code>WebShowName</code> attribute.\r
-        * @see MethodMapper\r
-       */\r
-       @SuppressWarnings("unused")\r
-       private static String getWebShowName(TaxonBase<?> taxon) {\r
-               TaxonNameBase<?,?> taxonName = taxon.getName();\r
-               String result = getWebShowName(taxonName);\r
-               if (isMisappliedName(taxon)){\r
-                       result = result + " " + getAuthorString(taxon);\r
-               }\r
-               return result;\r
-       }\r
-       \r
-       /**\r
-        * Returns the <code>WebShowName</code> attribute.\r
-        * @param taxonName The {@link TaxonNameBase TaxonName}.\r
-        * @return The <code>WebShowName</code> attribute.\r
-        * @see MethodMapper\r
-        */\r
-       private static String getWebShowName(TaxonNameBase<?,?> taxonName) {\r
-               //TODO extensions?\r
-               if (taxonName == null) {\r
-                       return null;\r
-               }else{\r
-                       INonViralNameCacheStrategy<NonViralName<?>> cacheStrategy = getCacheStrategy(taxonName);\r
-               \r
-                       HTMLTagRules tagRules = new HTMLTagRules().addRule(TagEnum.name, "i");\r
-                       NonViralName<?> nvn = CdmBase.deproxy(taxonName, NonViralName.class);\r
-                       String result = cacheStrategy.getTitleCache(nvn, tagRules);\r
-                       cacheStrategy = null;\r
-                       nvn = null;\r
-                       return result;\r
-               }\r
-       }\r
-\r
-       \r
-       /**\r
-        * Returns the <code>WebSearchName</code> attribute.\r
-        * @param taxonName The {@link NonViralName NonViralName}.\r
-        * @return The <code>WebSearchName</code> attribute.\r
-        * @see MethodMapper\r
-        */\r
-       @SuppressWarnings("unused")\r
-       private static String getWebSearchName(TaxonNameBase<?,?> taxonName) {\r
-               //TODO extensions?\r
-               NonViralName<?> nvn = CdmBase.deproxy(taxonName, NonViralName.class);\r
-               NonViralNameDefaultCacheStrategy<NonViralName<?>> strategy = getCacheStrategy(nvn);\r
-               String result = strategy.getNameCache(nvn);\r
-               strategy = null;\r
-               nvn = null;\r
-               return result;\r
-       }\r
-\r
-\r
-       /**\r
-        * Returns the <code>FullName</code> attribute.\r
-        * @param taxonName The {@link NonViralName NonViralName}.\r
-        * @return The <code>FullName</code> attribute.\r
-        * @see MethodMapper\r
-        */\r
-       @SuppressWarnings("unused")\r
-       private static String getFullName(TaxonNameBase taxonName) {\r
-               //TODO extensions?\r
-               NonViralName<?> nvn = CdmBase.deproxy(taxonName, NonViralName.class);\r
-               String result = getCacheStrategy(nvn).getTitleCache(nvn);\r
-               Iterator<TaxonBase> taxa = taxonName.getTaxa().iterator();\r
-               if (taxonName.getTaxa().size() >0){\r
-                       if (taxonName.getTaxa().size() == 1){\r
-                               TaxonBase taxon = taxa.next();\r
-                               if (isMisappliedName(taxon)){\r
-                                       result = result + " " + getAuthorString(taxon);\r
-                               }\r
-                               taxon = null;\r
-                       }\r
-               }\r
-               taxa = null;\r
-               nvn = null;\r
-               return result;\r
-       }\r
-       \r
-       /**\r
-        * Returns the <code>FullName</code> attribute.\r
-        * @param taxon The {@link TaxonBase taxon}.\r
-        * @return The <code>FullName</code> attribute.\r
-        * @see MethodMapper\r
-        */\r
-       /*@SuppressWarnings("unused")\r
-       private static String getFullName(TaxonBase taxon) {\r
-               //TODO extensions?\r
-               TaxonNameBase name = taxon.getName();\r
-               String result = getFullName(name);\r
-               if (isMisappliedName(taxon)){\r
-                       result = result + " " + getAuthorString(taxon);\r
-               }\r
-               \r
-               return result;\r
-       }\r
-*/\r
-       \r
-       /**\r
-        * Returns the nomenclatural reference which is the reference\r
-        * including the detail (microreference).\r
-        * @param taxonName The {@link TaxonNameBase TaxonName}.\r
-        * @return The <code>AuthorString</code> attribute.\r
-        * @see MethodMapper\r
-        */\r
-       @SuppressWarnings("unused")\r
-       private static String getNomRefString(TaxonNameBase<?,?> taxonName) {\r
-               INomenclaturalReference ref = taxonName.getNomenclaturalReference();\r
-               return ref == null ? null : ref.getNomenclaturalCitation(taxonName.getNomenclaturalMicroReference());\r
-       }\r
-       \r
-\r
-       /**\r
-        * Returns the <code>NameStatusFk</code> attribute.\r
-        * @param taxonName The {@link TaxonNameBase TaxonName}.\r
-        * @return The <code>NameStatusFk</code> attribute.\r
-        * @see MethodMapper\r
-        */\r
-       @SuppressWarnings("unused")\r
-       private static Integer getNameStatusFk(TaxonNameBase<?,?> taxonName) {\r
-               Integer result = null;\r
-\r
-               NomenclaturalStatus state = getNameStatus(taxonName);\r
-               if (state != null) {\r
-                       result = PesiTransformer.nomStatus2nomStatusFk(state.getType());\r
-               }\r
-               return result;\r
-       }\r
-       \r
-       /**\r
-        * Returns the <code>NameStatusCache</code> attribute.\r
-        * @param taxonName The {@link TaxonNameBase TaxonName}.\r
-        * @return The <code>NameStatusCache</code> attribute.\r
-        * @throws UndefinedTransformerMethodException \r
-        * @see MethodMapper\r
-        */\r
-       @SuppressWarnings("unused")\r
-       private static String getNameStatusCache(TaxonNameBase taxonName, PesiExportState state) throws UndefinedTransformerMethodException {\r
-               String result = null;\r
-               NomenclaturalStatus status = getNameStatus(taxonName);\r
-               if (status != null) {\r
-                       result = state.getTransformer().getCacheByNomStatus(status.getType());\r
-               }\r
-               return result;\r
-       }\r
-       \r
-       \r
-       private static NomenclaturalStatus getNameStatus(TaxonNameBase<?,?> taxonName) {\r
-               try {\r
-                       if (taxonName != null && (taxonName.isInstanceOf(NonViralName.class))) {\r
-                               NonViralName<?> nonViralName = CdmBase.deproxy(taxonName, NonViralName.class);\r
-                               Set<NomenclaturalStatus> states = nonViralName.getStatus();\r
-                               if (states.size() == 1) {\r
-                                       NomenclaturalStatus status = states.iterator().next();\r
-                                       return status;\r
-                               } else if (states.size() > 1) {\r
-                                       logger.error("This TaxonName has more than one Nomenclatural Status: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");\r
-                               }\r
-                       }\r
-               \r
-               } catch (Exception e) {\r
-                       e.printStackTrace();\r
-               }\r
-               return null;\r
-       }\r
-       /**\r
-        * Returns the <code>TaxonStatusFk</code> attribute.\r
-        * @param taxonName The {@link TaxonNameBase TaxonName}.\r
-        * @param state The {@link PesiExportState PesiExportState}.\r
-        * @return The <code>TaxonStatusFk</code> attribute.\r
-        * @see MethodMapper\r
-        */\r
-       private static Integer getTaxonStatusFk(TaxonBase<?> taxon, PesiExportState state) {\r
-               Integer result = null;\r
-               \r
-               try {\r
-                       if (isMisappliedName(taxon)) {\r
-                               Synonym synonym = Synonym.NewInstance(null, null);\r
-                               \r
-                               // This works as long as only the instance is important to differentiate between TaxonStatus.\r
-                               result = PesiTransformer.taxonBase2statusFk(synonym); // Auct References are treated as Synonyms in Datawarehouse now.\r
-                       } else {\r
-                               result = PesiTransformer.taxonBase2statusFk(taxon);\r
-                       }\r
-               \r
-               } catch (Exception e) {\r
-                       e.printStackTrace();\r
-               }\r
-               return result;\r
-       }\r
-       \r
-       /**\r
-        * Returns the <code>TaxonStatusCache</code> attribute.\r
-        * @param taxonName The {@link TaxonNameBase TaxonName}.\r
-        * @param state The {@link PesiExportState PesiExportState}.\r
-        * @return The <code>TaxonStatusCache</code> attribute.\r
-        * @throws UndefinedTransformerMethodException \r
-        * @see MethodMapper\r
-        */\r
-       @SuppressWarnings("unused")\r
-       private static String getTaxonStatusCache(TaxonBase<?> taxon, PesiExportState state) throws UndefinedTransformerMethodException {\r
-               return state.getTransformer().getTaxonStatusCacheByKey(getTaxonStatusFk(taxon, state));\r
-       }\r
-       \r
-       /**\r
-        * Returns the <code>TypeNameFk</code> attribute.\r
-        * @param taxonName The {@link TaxonNameBase TaxonName}.\r
-        * @param state The {@link PesiExportState PesiExportState}.\r
-        * @return The <code>TypeNameFk</code> attribute.\r
-        * @see MethodMapper\r
-        */\r
-       private static Integer getTypeNameFk(TaxonNameBase<?,?> taxonNameBase, PesiExportState state) {\r
-               Integer result = null;\r
-               if (taxonNameBase != null) {\r
-                       Set<NameTypeDesignation> nameTypeDesignations = taxonNameBase.getNameTypeDesignations();\r
-                       if (nameTypeDesignations.size() == 1) {\r
-                               NameTypeDesignation nameTypeDesignation = nameTypeDesignations.iterator().next();\r
-                               if (nameTypeDesignation != null) {\r
-                                       TaxonNameBase<?,?> typeName = nameTypeDesignation.getTypeName();\r
-                                       if (typeName != null) {\r
-                                               result = state.getDbId(typeName);\r
-                                       }\r
-                               }\r
-                       } else if (nameTypeDesignations.size() > 1) {\r
-                               logger.warn("This TaxonName has " + nameTypeDesignations.size() + " NameTypeDesignations: " + taxonNameBase.getUuid() + " (" + taxonNameBase.getTitleCache() + ")");\r
-                       }\r
-               }\r
-               return result;\r
-       }\r
-       \r
-       /**\r
-        * Returns the <code>TypeFullnameCache</code> attribute.\r
-        * @param taxonName The {@link TaxonNameBase TaxonName}.\r
-        * @return The <code>TypeFullnameCache</code> attribute.\r
-        * @see MethodMapper\r
-        */\r
-       @SuppressWarnings("unused")\r
-       private static String getTypeFullnameCache(TaxonNameBase<?,?> taxonName) {\r
-               String result = null;\r
-               \r
-               try {\r
-               if (taxonName != null) {\r
-                       Set<NameTypeDesignation> nameTypeDesignations = taxonName.getNameTypeDesignations();\r
-                       if (nameTypeDesignations.size() == 1) {\r
-                               NameTypeDesignation nameTypeDesignation = nameTypeDesignations.iterator().next();\r
-                               if (nameTypeDesignation != null) {\r
-                                       TaxonNameBase<?,?> typeName = nameTypeDesignation.getTypeName();\r
-                                       if (typeName != null) {\r
-                                               result = typeName.getTitleCache();\r
-                                       }\r
-                               }\r
-                       } else if (nameTypeDesignations.size() > 1) {\r
-                               logger.warn("This TaxonName has " + nameTypeDesignations.size() + " NameTypeDesignations: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");\r
-                       }\r
-               }\r
-               \r
-               } catch (Exception e) {\r
-                       e.printStackTrace();\r
-               }\r
-               return result;\r
-       }\r
-\r
-       \r
-       /**\r
-        * Returns the <code>QualityStatusFk</code> attribute.\r
-        * @param taxonName The {@link TaxonNameBase TaxonName}.\r
-        * @return The <code>QualityStatusFk</code> attribute.\r
-        * @see MethodMapper\r
-        */\r
-       private static Integer getQualityStatusFk(TaxonNameBase taxonName) {\r
-               BitSet sources = getSources(taxonName);\r
-               return PesiTransformer.getQualityStatusKeyBySource(sources, taxonName);\r
-       }\r
-\r
-       \r
-       /**\r
-        * Returns the <code>QualityStatusCache</code> attribute.\r
-        * @param taxonName The {@link TaxonNameBase TaxonName}.\r
-        * @return The <code>QualityStatusCache</code> attribute.\r
-        * @throws UndefinedTransformerMethodException \r
-        * @see MethodMapper\r
-        */\r
-       @SuppressWarnings("unused")\r
-       private static String getQualityStatusCache(TaxonNameBase taxonName, PesiExportState state) throws UndefinedTransformerMethodException {\r
-               return state.getTransformer().getQualityStatusCacheByKey(getQualityStatusFk(taxonName));\r
-       }\r
-\r
-       \r
-       /**\r
-        * Returns the <code>TypeDesignationStatusFk</code> attribute.\r
-        * @param taxonName The {@link TaxonNameBase TaxonName}.\r
-        * @return The <code>TypeDesignationStatusFk</code> attribute.\r
-        * @see MethodMapper\r
-        */\r
-       @SuppressWarnings("unused")\r
-       private static Integer getTypeDesignationStatusFk(TaxonNameBase<?,?> taxonName) {\r
-               Integer result = null;\r
-               \r
-               try {\r
-               if (taxonName != null) {\r
-                       Set<NameTypeDesignation> typeDesignations = taxonName.getNameTypeDesignations();\r
-                       if (typeDesignations.size() == 1) {\r
-                               Object obj = typeDesignations.iterator().next().getTypeStatus();\r
-                               NameTypeDesignationStatus designationStatus = CdmBase.deproxy(obj, NameTypeDesignationStatus.class);\r
-                               result = PesiTransformer.nameTypeDesignationStatus2TypeDesignationStatusId(designationStatus);\r
-                       } else if (typeDesignations.size() > 1) {\r
-                               logger.error("Found a TaxonName with more than one NameTypeDesignation: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");\r
-                       }\r
-               }\r
-               \r
-               } catch (Exception e) {\r
-                       e.printStackTrace();\r
-               }\r
-               return result;\r
-       }\r
-\r
-       /**\r
-        * Returns the <code>TypeDesignationStatusCache</code> attribute.\r
-        * @param taxonName The {@link TaxonNameBase TaxonName}.\r
-        * @return The <code>TypeDesignationStatusCache</code> attribute.\r
-        * @see MethodMapper\r
-        */\r
-       @SuppressWarnings("unused")\r
-       private static String getTypeDesignationStatusCache(TaxonNameBase<?,?> taxonName) {\r
-               String result = null;\r
-               \r
-               try {\r
-               if (taxonName != null) {\r
-                       Set<NameTypeDesignation> typeDesignations = taxonName.getNameTypeDesignations();\r
-                       if (typeDesignations.size() == 1) {\r
-                               Object obj = typeDesignations.iterator().next().getTypeStatus();\r
-                               NameTypeDesignationStatus designationStatus = CdmBase.deproxy(obj, NameTypeDesignationStatus.class);\r
-                               result = PesiTransformer.nameTypeDesignationStatus2TypeDesignationStatusCache(designationStatus);\r
-                       } else if (typeDesignations.size() > 1) {\r
-                               logger.error("Found a TaxonName with more than one NameTypeDesignation: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");\r
-                       }\r
-               }\r
-               \r
-               } catch (Exception e) {\r
-                       e.printStackTrace();\r
-               }\r
-               return result;\r
-       }\r
-       \r
-       /**\r
-        * Returns the <code>FossilStatusFk</code> attribute.\r
-        * @param taxonName The {@link TaxonNameBase TaxonName}.\r
-        * @return The <code>FossilStatusFk</code> attribute.\r
-        * @see MethodMapper\r
-        */\r
-       @SuppressWarnings("unused")\r
-       private static Integer getFossilStatusFk(IdentifiableEntity<?> identEntity, PesiExportState state) {\r
-               Integer result = null;\r
-               \r
-               Set<String> fossilStatuus = identEntity.getExtensions(ErmsTransformer.uuidFossilStatus);\r
-               if (fossilStatuus.size() == 0){\r
-                       return null;\r
-               }else if (fossilStatuus.size() > 1){\r
-                       logger.warn("More than 1 fossil status given for " +  identEntity.getTitleCache() + " " + identEntity.getUuid());\r
-               }\r
-               String fossilStatus = fossilStatuus.iterator().next();\r
-               \r
-               int statusFk = state.getTransformer().FossilStatusCache2FossilStatusFk(fossilStatus);\r
-               return statusFk;\r
-       }\r
-       \r
-       /**\r
-        * Returns the <code>FossilStatusCache</code> attribute.\r
-        * @param taxonName The {@link TaxonNameBase TaxonName}.\r
-        * @return The <code>FossilStatusCache</code> attribute.\r
-        * @see MethodMapper\r
-        */\r
-       @SuppressWarnings("unused")\r
-       private static String getFossilStatusCache(IdentifiableEntity<?> identEntity, PesiExportState state) {\r
-               String result = null;\r
-               Set<String> fossilStatuus = identEntity.getExtensions(ErmsTransformer.uuidFossilStatus);\r
-               if (fossilStatuus.size() == 0){\r
-                       return null;\r
-               }\r
-               for (String strFossilStatus : fossilStatuus){\r
-                       result = CdmUtils.concat(";", result, strFossilStatus);\r
-               }\r
-               return result;\r
-       }\r
-       \r
-       /**\r
-        * Returns the <code>IdInSource</code> attribute.\r
-        * @param taxonName The {@link TaxonNameBase TaxonName}.\r
-        * @return The <code>IdInSource</code> attribute.\r
-        * @see MethodMapper\r
-        */\r
-       @SuppressWarnings("unused")\r
-       private static String getIdInSource(IdentifiableEntity taxonName) {\r
-               String result = null;\r
-               \r
-               try {\r
-                       Set<IdentifiableSource> sources = getPesiSources(taxonName);\r
-                       if (sources.size() > 1){\r
-                               logger.warn("There is > 1 Pesi source. This is not yet handled.");\r
-                       }\r
-                       if (sources.size() == 0){\r
-                               logger.warn("There is no Pesi source!" +taxonName.getUuid() + " (" + taxonName.getTitleCache() +")");\r
-                       }\r
-                       for (IdentifiableSource source : sources) {\r
-                               Reference<?> ref = source.getCitation();\r
-                               UUID refUuid = ref.getUuid();\r
-                               String idInSource = source.getIdInSource();\r
-                               if (refUuid.equals(BerlinModelTransformer.uuidSourceRefEuroMed)){\r
-                                       result = idInSource != null ? ("NameId: " + source.getIdInSource()) : null;\r
-                               }else if (refUuid.equals(PesiTransformer.uuidSourceRefFaunaEuropaea)){\r
-                                       result = idInSource != null ? ("TAX_ID: " + source.getIdInSource()) : null;\r
-                               }else if (refUuid.equals(PesiTransformer.uuidSourceRefErms)){\r
-                                       result = idInSource != null ? ("tu_id: " + source.getIdInSource()) : null;\r
-                               }else if (refUuid.equals(PesiTransformer.uuidSourceRefIndexFungorum)){  //Index Fungorum\r
-                                       result = idInSource != null ? ("if_id: " + source.getIdInSource()) : null;\r
-                               }else{\r
-                                       if (logger.isDebugEnabled()){logger.debug("Not a PESI source");};\r
-                               }\r
-                               \r
-                               String sourceIdNameSpace = source.getIdNamespace();\r
-                               if (sourceIdNameSpace != null) {\r
-                                       if (sourceIdNameSpace.equals(PesiTransformer.STR_NAMESPACE_NOMINAL_TAXON)) {\r
-                                               result =  idInSource != null ? ("Nominal Taxon from TAX_ID: " + source.getIdInSource()):null;\r
-                                       } else if (sourceIdNameSpace.equals(TaxonServiceImpl.INFERRED_EPITHET_NAMESPACE)) {\r
-                                               result =  idInSource != null ? ("Inferred epithet from TAX_ID: " + source.getIdInSource()) : null;\r
-                                       } else if (sourceIdNameSpace.equals(TaxonServiceImpl.INFERRED_GENUS_NAMESPACE)) {\r
-                                               result =  idInSource != null ? ("Inferred genus from TAX_ID: " + source.getIdInSource()):null;\r
-                                       } else if (sourceIdNameSpace.equals(TaxonServiceImpl.POTENTIAL_COMBINATION_NAMESPACE)) {\r
-                                               result =  idInSource != null ? ("Potential combination from TAX_ID: " + source.getIdInSource()):null;\r
-                                       } \r
-                               }\r
-                               if (result == null) {\r
-                                       logger.warn("IdInSource is NULL for this taxonName: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() +", sourceIdNameSpace: " + source.getIdNamespace()+")");\r
-                               }\r
-                       }\r
-               } catch (Exception e) {\r
-                       e.printStackTrace();\r
-                       logger.error("An error occurs while creating idInSource..." + taxonName.getUuid() + " (" + taxonName.getTitleCache()+ e.getMessage());\r
-               }\r
-\r
-               if (result == null) {\r
-                       logger.warn("IdInSource is NULL for this taxonName: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() +")");\r
-               }\r
-               return result;\r
-       }\r
-       \r
-       /**\r
-        * Returns the idInSource for a given TaxonName only.\r
-        * @param taxonName The {@link TaxonNameBase TaxonName}.\r
-        * @return The idInSource.\r
-        */\r
-       private static String getIdInSourceOnly(IdentifiableEntity identEntity) {\r
-               String result = null;\r
-               \r
-               // Get the sources first\r
-               Set<IdentifiableSource> sources = getPesiSources(identEntity);\r
-\r
-               // Determine the idInSource\r
-               if (sources.size() == 1) {\r
-                       IdentifiableSource source = sources.iterator().next();\r
-                       if (source != null) {\r
-                               result = source.getIdInSource();\r
-                       }\r
-               } else if (sources.size() > 1) {\r
-                       int count = 1;\r
-                       result = "";\r
-                       for (IdentifiableSource source : sources) {\r
-                               result += source.getIdInSource();\r
-                               if (count < sources.size()) {\r
-                                       result += "; ";\r
-                               }\r
-                               count++;\r
-                       }\r
-\r
-               }\r
-               \r
-               return result;\r
-       }\r
-       \r
-       /**\r
-        * Returns the Sources for a given TaxonName only.\r
-        * @param taxonName The {@link TaxonNameBase TaxonName}.\r
-        * @return The Sources.\r
-        */\r
-       private static Set<IdentifiableSource> getPesiSources(IdentifiableEntity identEntity) {\r
-               Set<IdentifiableSource> sources = new java.util.HashSet<IdentifiableSource>();\r
-\r
-               //Taxon Names\r
-               if (identEntity.isInstanceOf(TaxonNameBase.class)){\r
-                       // Sources from TaxonName\r
-                       TaxonNameBase taxonName = CdmBase.deproxy(identEntity, TaxonNameBase.class);\r
-                       Set<IdentifiableSource> testSources = identEntity.getSources();\r
-                       sources = filterPesiSources(identEntity.getSources());\r
-                       \r
-                       if (sources.size() == 0 && testSources.size()>0){\r
-                               IdentifiableSource source = testSources.iterator().next();\r
-                               logger.warn("There are sources, but they are no pesi sources!!!" + source.getIdInSource() + " - " + source.getIdNamespace() + " - " + source.getCitation().getTitleCache());\r
-                       }\r
-                       if (sources.size() > 1) {\r
-                               logger.warn("This TaxonName has more than one Source: " + identEntity.getUuid() + " (" + identEntity.getTitleCache() + ")");\r
-                       }\r
-                       \r
-                       // name has no PESI source, take sources from TaxonBase\r
-                       if (sources == null || sources.isEmpty()) {\r
-                               Set<TaxonBase> taxa = taxonName.getTaxonBases();\r
-                               for (TaxonBase taxonBase: taxa){\r
-                                       sources.addAll(filterPesiSources(taxonBase.getSources()));\r
-                               }\r
-                       }\r
-\r
-               //for TaxonBases\r
-               }else if (identEntity.isInstanceOf(TaxonBase.class)){\r
-                       sources = filterPesiSources(identEntity.getSources());  \r
-               }\r
-\r
-               /*TODO: deleted only for testing the inferred synonyms \r
-               if (sources == null || sources.isEmpty()) {\r
-                       logger.warn("This TaxonName has no PESI Sources: " + identEntity.getUuid() + " (" + identEntity.getTitleCache() +")");\r
-               }else if (sources.size() > 1){\r
-                       logger.warn("This Taxon(Name) has more than 1 PESI source: " + identEntity.getUuid() + " (" + identEntity.getTitleCache() +")");\r
-               }\r
-               */\r
-               return sources;\r
-       }\r
-       \r
-       // return all sources with a PESI reference     \r
-       private static Set<IdentifiableSource> filterPesiSources(Set<? extends IdentifiableSource> sources) {\r
-               Set<IdentifiableSource> result = new HashSet<IdentifiableSource>();\r
-               for (IdentifiableSource source : sources){\r
-                       Reference ref = source.getCitation();\r
-                       UUID refUuid = ref.getUuid();\r
-                       if (refUuid.equals(BerlinModelTransformer.uuidSourceRefEuroMed) || \r
-                               refUuid.equals(PesiTransformer.uuidSourceRefFaunaEuropaea)||\r
-                               refUuid.equals(PesiTransformer.uuidSourceRefErms)||\r
-                               refUuid.equals(PesiTransformer.uuidSourceRefIndexFungorum) ||\r
-                               refUuid.equals(PesiTransformer.uuidSourceRefAuct)){\r
-                               result.add(source);\r
-                       }\r
-               }\r
-               return result;\r
-       }\r
-\r
-       /**\r
-        * Returns the <code>GUID</code> attribute.\r
-        * @param taxonName The {@link TaxonNameBase TaxonName}.\r
-        * @return The <code>GUID</code> attribute.\r
-        * @see MethodMapper\r
-        */\r
-       private static String getGUID(TaxonBase<?> taxon) {\r
-               if (taxon.getLsid() != null ){\r
-                       return taxon.getLsid().getLsid();\r
-               }else if (taxon.hasMarker(PesiTransformer.uuidMarkerGuidIsMissing, true)){\r
-                       return null;\r
-               }else{\r
-                       return taxon.getUuid().toString();\r
-               }\r
-       }\r
-       \r
-       \r
-       \r
-       \r
-       /**\r
-        * Returns the <code>DerivedFromGuid</code> attribute.\r
-        * @param taxonName The {@link TaxonNameBase TaxonName}.\r
-        * @return The <code>DerivedFromGuid</code> attribute.\r
-        * @see MethodMapper\r
-        */\r
-       @SuppressWarnings("unused")\r
-       private static String getDerivedFromGuid(TaxonBase<?> taxon) {\r
-               String result = null;\r
-               try {\r
-               // The same as GUID for now\r
-               result = getGUID(taxon);\r
-               } catch (Exception e) {\r
-                       e.printStackTrace();\r
-               }\r
-               return result;\r
-       }\r
-       \r
-       /**\r
-        * Returns the <code>CacheCitation</code> attribute.\r
-        * @param taxonName The {@link TaxonNameBase TaxonName}.\r
-        * @return The CacheCitation.\r
-        * @see MethodMapper\r
-        */\r
-       @SuppressWarnings("unused")\r
-       private static String getCacheCitation(TaxonBase taxon) {\r
-               // !!! See also doPhaseUpdates\r
-               \r
-               TaxonNameBase<?,?> taxonName = taxon.getName();\r
-               String result = "";\r
-               //TODO implement anew for taxa\r
-               try {\r
-                       BitSet sources = getSources(taxonName);\r
-                       if (sources.isEmpty()) {\r
-//                             logger.error("OriginalDB is NULL for this TaxonName: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");\r
-                       } else if (sources.get(PesiTransformer.SOURCE_ERMS)) {\r
-                               // TODO: 19.08.2010: An import of CacheCitation does not exist in the ERMS import yet or it will be imported in a different way...\r
-                               //               So the following code is some kind of harmless assumption.\r
-                               Set<Extension> extensions = taxonName.getExtensions();\r
-                               for (Extension extension : extensions) {\r
-                                       if (extension.getType().equals(cacheCitationExtensionType)) {\r
-                                               result = extension.getValue();\r
-                                       }\r
-                               }\r
-                       } else {\r
-                               String expertName = getExpertName(taxon);\r
-                               String webShowName = getWebShowName(taxonName);\r
-                               \r
-                               // idInSource only\r
-                               String idInSource = getIdInSourceOnly(taxonName);\r
-                               \r
-                               // build the cacheCitation\r
-                               if (expertName != null) {\r
-                                       result += expertName + ". ";\r
-                               } else {\r
-                                       if (logger.isDebugEnabled()){logger.debug("ExpertName could not be determined for this TaxonName: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");}\r
-                               }\r
-                               if (webShowName != null) {\r
-                                       result += webShowName + ". ";\r
-                               } else {\r
-                                       logger.warn("WebShowName could not be determined for this TaxonName: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");\r
-                               }\r
-                               \r
-                               if (getOriginalDB(taxonName).equals("FaEu")) {\r
-                                       result += "Accessed through: Fauna Europaea at http://faunaeur.org/full_results.php?id=";\r
-                               } else if (getOriginalDB(taxonName).equals("EM")) {\r
-                                       result += "Accessed through: Euro+Med PlantBase at http://ww2.bgbm.org/euroPlusMed/PTaxonDetail.asp?UUID=";\r
-                               }\r
-                               \r
-                               if (idInSource != null) {\r
-                                       result += idInSource;\r
-                               } else {\r
-                                       logger.warn("IdInSource could not be determined for this TaxonName: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");\r
-                               }\r
-                       }\r
-               } catch (Exception e) {\r
-                       e.printStackTrace();\r
-               }\r
-               \r
-               if (StringUtils.isBlank(result)) {\r
-                       return null;\r
-               } else {\r
-                       return result;\r
-               }\r
-       }\r
-       \r
-       /**\r
-        * Returns the <code>OriginalDB</code> attribute.\r
-        * @param taxonName The {@link TaxonNameBase TaxonName}.\r
-        * @return The <code>OriginalDB</code> attribute.\r
-        * @see MethodMapper\r
-        */\r
-       private static String getOriginalDB(IdentifiableEntity identEntity) {\r
-               // Sources from TaxonName\r
-               BitSet sources  = getSources(identEntity);\r
-               return PesiTransformer.getOriginalDbBySources(sources);\r
-       }\r
-       \r
-       /**\r
-        * Returns the <code>LastAction</code> attribute.\r
-        * @param taxonName The {@link TaxonNameBase TaxonName}.\r
-        * @return The <code>LastAction</code> attribute.\r
-        * @see MethodMapper\r
-        */\r
-       @SuppressWarnings("unused")\r
-       private static String getLastAction(IdentifiableEntity<?> identEntity) {\r
-               String result = null;\r
-               try {\r
-               Set<Extension> extensions = identEntity.getExtensions();\r
-               for (Extension extension : extensions) {\r
-                       if (extension.getType().equals(lastActionExtensionType)) {\r
-                               result = extension.getValue();\r
-                       }\r
-               }\r
-               } catch (Exception e) {\r
-                       e.printStackTrace();\r
-               }\r
-               return result;\r
-       }\r
-       \r
-       /**\r
-        * Returns the <code>LastActionDate</code> attribute.\r
-        * @param taxonName The {@link TaxonNameBase TaxonName}.\r
-        * @return The <code>LastActionDate</code> attribute.\r
-        * @see MethodMapper\r
-        */\r
-       @SuppressWarnings({ "unused" })\r
-       private static DateTime getLastActionDate(IdentifiableEntity identEntity) {\r
-               DateTime result = null;\r
-               try {\r
-                       Set<Extension> extensions = identEntity.getExtensions();\r
-                       for (Extension extension : extensions) {\r
-                               if (extension.getType().equals(lastActionDateExtensionType)) {\r
-                                       String dateTime = extension.getValue();\r
-                                       if (dateTime != null) {\r
-                                               DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss.S");\r
-                                               result = formatter.parseDateTime(dateTime);\r
-                                       }\r
-                               }\r
-                       }\r
-               } catch (Exception e) {\r
-                       e.printStackTrace();\r
-               }\r
-               return result;\r
-       }\r
-       \r
-       /**\r
-        * Returns the <code>ExpertName</code> attribute.\r
-        * @param taxonName The {@link TaxonNameBase TaxonName}.\r
-        * @return The <code>ExpertName</code> attribute.\r
-        * @see MethodMapper\r
-        */\r
-       @SuppressWarnings("unused")\r
-       private static String getExpertName(TaxonBase<?> taxonName) {\r
-               String result = null;\r
-               try {\r
-               Set<Extension> extensions = taxonName.getExtensions();\r
-               for (Extension extension : extensions) {\r
-                       if (extension.getType().equals(expertNameExtensionType)) {\r
-                               result = extension.getValue();\r
-                       }\r
-               }\r
-               } catch (Exception e) {\r
-                       e.printStackTrace();\r
-               }\r
-               return result;\r
-       }\r
-       \r
-       /**\r
-        * Returns the <code>ExpertFk</code> attribute.\r
-        * @param taxonName The {@link TaxonNameBase TaxonName}.\r
-        * @param state The {@link PesiExportState PesiExportState}.\r
-        * @return The <code>ExpertFk</code> attribute.\r
-        * @see MethodMapper\r
-        */\r
-       private static Integer getExpertFk(Reference<?> reference, PesiExportState state) {\r
-               Integer result = state.getDbId(reference);\r
-               return result;\r
-       }\r
-       \r
-       /**\r
-        * Returns the <code>SpeciesExpertName</code> attribute.\r
-        * @param taxonName The {@link TaxonNameBase TaxonName}.\r
-        * @return The <code>SpeciesExpertName</code> attribute.\r
-        * @see MethodMapper\r
-        */\r
-       @SuppressWarnings("unused")\r
-       private static String getSpeciesExpertName(TaxonBase<?> taxonName) {\r
-               String result = null;\r
-               try {\r
-               Set<Extension> extensions = taxonName.getExtensions();\r
-               for (Extension extension : extensions) {\r
-                       if (extension.getType().equals(speciesExpertNameExtensionType)) {\r
-                               result = extension.getValue();\r
-                       }\r
-               }\r
-               } catch (Exception e) {\r
-                       e.printStackTrace();\r
-               }\r
-               return result;\r
-       }\r
-       \r
-       /**\r
-        * Returns the <code>SpeciesExpertFk</code> attribute.\r
-        * @param reference The {@link Reference Reference}.\r
-        * @param state The {@link PesiExportState PesiExportState}.\r
-        * @return The <code>SpeciesExpertFk</code> attribute.\r
-        * @see MethodMapper\r
-        */\r
-       private static Integer getSpeciesExpertFk(Reference<?> reference, PesiExportState state) {\r
-               Integer result = state.getDbId(reference);\r
-               return result;\r
-       }\r
-       \r
-       \r
-       /**\r
-        * Returns the source (E+M, Fauna Europaea, Index Fungorum, ERMS) of a given\r
-        * Identifiable Entity as a BitSet\r
-        * @param identEntity\r
-        * @return\r
-        */\r
-       private static BitSet getSources(IdentifiableEntity<?> identEntity){\r
-               BitSet bitSet = new BitSet();\r
-               Set<IdentifiableSource> sources = getPesiSources(identEntity);\r
-               for (IdentifiableSource source : sources) {\r
-                       Reference<?> ref = source.getCitation();\r
-                       UUID refUuid = ref.getUuid();\r
-                       if (refUuid.equals(BerlinModelTransformer.uuidSourceRefEuroMed)){\r
-                               bitSet.set(PesiTransformer.SOURCE_EM);\r
-                       }else if (refUuid.equals(PesiTransformer.uuidSourceRefFaunaEuropaea)){\r
-                               bitSet.set(PesiTransformer.SOURCE_FE);\r
-                       }else if (refUuid.equals(PesiTransformer.uuidSourceRefErms)){\r
-                               bitSet.set(PesiTransformer.SOURCE_ERMS);\r
-                       }else if (refUuid.equals(PesiTransformer.uuidSourceRefIndexFungorum)){\r
-                               bitSet.set(PesiTransformer.SOURCE_IF);\r
-                       }else{\r
-                               if (logger.isDebugEnabled()){logger.debug("Not a PESI source");};\r
-                       }\r
-               }\r
-               return bitSet;\r
-               \r
-       }\r
-       \r
-       protected static NonViralNameDefaultCacheStrategy getCacheStrategy(TaxonNameBase<?, ?> taxonName) {\r
-               taxonName = CdmBase.deproxy(taxonName, TaxonNameBase.class);\r
-               NonViralNameDefaultCacheStrategy<?> cacheStrategy;\r
-               if (taxonName.isInstanceOf(ZoologicalName.class)){\r
-                       cacheStrategy = zooNameStrategy;\r
-               }else if (taxonName.isInstanceOf(BotanicalName.class)) {\r
-                       cacheStrategy = botanicalNameStrategy;\r
-               }else if (taxonName.getClass().equals(NonViralName.class)) {\r
-                       cacheStrategy = nonViralNameStrategy;\r
-               }else if (taxonName.getClass().equals(BacterialName.class)) {\r
-                       cacheStrategy = bacterialNameStrategy;\r
-               }else{\r
-                       logger.error("Unhandled taxon name type. Can't define strategy class");\r
-                       cacheStrategy = botanicalNameStrategy;\r
-               }\r
-               return cacheStrategy;\r
-       }\r
-       \r
-       /**\r
-        * Returns the <code>TaxonFk1</code> attribute. It corresponds to a CDM <code>TaxonRelationship</code>.\r
-        * @param relationship The {@link RelationshipBase Relationship}.\r
-        * @param state The {@link PesiExportState PesiExportState}.\r
-        * @return The <code>TaxonFk1</code> attribute.\r
-        * @see MethodMapper\r
-        */\r
-       private static Integer getTaxonFk1(RelationshipBase<?, ?, ?> relationship, PesiExportState state) {\r
-               \r
-               return getObjectFk(relationship, state, true);\r
-       }\r
-       \r
-       /**\r
-        * Returns the <code>TaxonFk2</code> attribute. It corresponds to a CDM <code>SynonymRelationship</code>.\r
-        * @param relationship The {@link RelationshipBase Relationship}.\r
-        * @param state The {@link PesiExportState PesiExportState}.\r
-        * @return The <code>TaxonFk2</code> attribute.\r
-        * @see MethodMapper\r
-        */\r
-       private static Integer getTaxonFk2(RelationshipBase<?, ?, ?> relationship, PesiExportState state) {\r
-               return getObjectFk(relationship, state, false);\r
-       }\r
-       \r
-       /**\r
-        * Returns the database key of an object in the given relationship.\r
-        * @param relationship {@link RelationshipBase RelationshipBase}.\r
-        * @param state {@link PesiExportState PesiExportState}.\r
-        * @param isFrom A boolean value indicating whether the database key of the parent or child in this relationship is searched. <code>true</code> means the child is searched. <code>false</code> means the parent is searched.\r
-        * @return The database key of an object in the given relationship.\r
-        */\r
-       private static Integer getObjectFk(RelationshipBase<?, ?, ?> relationship, PesiExportState state, boolean isFrom) {\r
-               TaxonBase<?> taxonBase = null;\r
-               if (relationship.isInstanceOf(TaxonRelationship.class)) {\r
-                       TaxonRelationship tr = (TaxonRelationship)relationship;\r
-                       taxonBase = (isFrom) ? tr.getFromTaxon():  tr.getToTaxon();\r
-               } else if (relationship.isInstanceOf(SynonymRelationship.class)) {\r
-                       SynonymRelationship sr = (SynonymRelationship)relationship;\r
-                       taxonBase = (isFrom) ? sr.getSynonym() : sr.getAcceptedTaxon();\r
-               } else if (relationship.isInstanceOf(NameRelationship.class) ||  relationship.isInstanceOf(HybridRelationship.class)) {\r
-                       if (isFrom){\r
-                               return state.getDbId(state.getCurrentFromObject());\r
-                       }else{\r
-                               return state.getDbId(state.getCurrentToObject());\r
-                       }\r
-               }\r
-               if (taxonBase != null) {\r
-                       if (! isPesiTaxon(taxonBase)){\r
-                               logger.warn("Related taxonBase is not a PESI taxon. Taxon: " + taxonBase.getId() + "/" + taxonBase.getUuid() + "; TaxonRel: " +  relationship.getId() + "(" + relationship.getType().getTitleCache() + ")");\r
-                               return null;\r
-                       }else{\r
-                               return state.getDbId(taxonBase);        \r
-                       }\r
-                       \r
-               }\r
-               logger.warn("No taxon found in state for relationship: " + relationship.toString());\r
-               return null;\r
-       }\r
-       \r
-       /**\r
-        * Returns the <code>RelQualifierCache</code> attribute.\r
-        * @param relationship The {@link RelationshipBase Relationship}.\r
-        * @return The <code>RelQualifierCache</code> attribute.\r
-        * @see MethodMapper\r
-        */\r
-       @SuppressWarnings("unused")\r
-       private static String getRelQualifierCache(RelationshipBase<?, ?, ?> relationship, PesiExportState state) {\r
-               String result = null;\r
-               NomenclaturalCode code = null;\r
-               if (relationship.isInstanceOf(TaxonRelationship.class)){\r
-                       code = CdmBase.deproxy(relationship, TaxonRelationship.class).getToTaxon().getName().getNomenclaturalCode();\r
-               }else if (relationship.isInstanceOf(SynonymRelationship.class)){\r
-                       code = CdmBase.deproxy(relationship, SynonymRelationship.class).getAcceptedTaxon().getName().getNomenclaturalCode();\r
-               }else if (relationship.isInstanceOf(NameRelationship.class)){\r
-                       code = CdmBase.deproxy(relationship,  NameRelationship.class).getFromName().getNomenclaturalCode();\r
-               }else if (relationship.isInstanceOf(HybridRelationship.class)){\r
-                       code = CdmBase.deproxy(relationship,  HybridRelationship.class).getParentName().getNomenclaturalCode();\r
-               }\r
-               if (code != null) {\r
-                       result = state.getConfig().getTransformer().getCacheByRelationshipType(relationship, code);\r
-               } else {\r
-                       logger.error("NomenclaturalCode is NULL while creating the following relationship: " + relationship.getUuid());\r
-               }\r
-               return result;\r
-       }\r
-       \r
-       /**\r
-        * Returns the <code>RelTaxonQualifierFk</code> attribute.\r
-        * @param relationship The {@link RelationshipBase Relationship}.\r
-        * @return The <code>RelTaxonQualifierFk</code> attribute.\r
-        * @see MethodMapper\r
-        */\r
-       @SuppressWarnings("unused")\r
-       private static Integer getRelTaxonQualifierFk(RelationshipBase<?, ?, ?> relationship) {\r
-               return PesiTransformer.taxonRelation2RelTaxonQualifierFk(relationship);\r
-       }\r
-       /**\r
-        * Returns the <code>Notes</code> attribute.\r
-        * @param relationship The {@link RelationshipBase Relationship}.\r
-        * @return The <code>Notes</code> attribute.\r
-        * @see MethodMapper\r
-        */\r
-       @SuppressWarnings("unused")\r
-       private static String getNotes(RelationshipBase<?, ?, ?> relationship) {\r
-               // TODO\r
-               return null;\r
-       }\r
-\r
-       \r
-       /**\r
-        * Returns the CDM to PESI specific export mappings.\r
-        * @return The {@link PesiExportMapping PesiExportMapping}.\r
-        */\r
-       private PesiExportMapping getMapping() {\r
-               PesiExportMapping mapping = new PesiExportMapping(dbTableName);\r
-               \r
-               //mapping.addMapper(IdMapper.NewInstance("TaxonId"));\r
-               mapping.addMapper(DbObjectMapper.NewInstance("sec", "sourceFk")); //OLD:mapping.addMapper(MethodMapper.NewInstance("SourceFK", this.getClass(), "getSourceFk", standardMethodParameter, PesiExportState.class));\r
-               mapping.addMapper(MethodMapper.NewInstance("TaxonStatusFk", this.getClass(), "getTaxonStatusFk", standardMethodParameter, PesiExportState.class));\r
-               mapping.addMapper(MethodMapper.NewInstance("TaxonStatusCache", this.getClass(), "getTaxonStatusCache", standardMethodParameter, PesiExportState.class));\r
-               \r
-               mapping.addMapper(MethodMapper.NewInstance("GUID", this));\r
-               \r
-               mapping.addMapper(MethodMapper.NewInstance("DerivedFromGuid", this));\r
-               mapping.addMapper(MethodMapper.NewInstance("CacheCitation", this));\r
-               mapping.addMapper(MethodMapper.NewInstance("AuthorString", this));  //For Taxon because Misallied Names are handled differently\r
-               mapping.addMapper(MethodMapper.NewInstance("WebShowName", this));\r
-               \r
-               // DisplayName\r
-               mapping.addMapper(MethodMapper.NewInstance("DisplayName", this));\r
-\r
-               // FossilStatus (Fk, Cache)\r
-               mapping.addMapper(MethodMapper.NewInstance("FossilStatusCache", this, IdentifiableEntity.class, PesiExportState.class));\r
-               mapping.addMapper(MethodMapper.NewInstance("FossilStatusFk", this, IdentifiableEntity.class, PesiExportState.class)); // PesiTransformer.FossilStatusCache2FossilStatusFk?\r
-               \r
-               //handled by name mapping\r
-               mapping.addMapper(DbLastActionMapper.NewInstance("LastActionDate", false));\r
-               mapping.addMapper(DbLastActionMapper.NewInstance("LastAction", true));\r
-               \r
-               //experts\r
-               ExtensionType extensionTypeSpeciesExpertName = (ExtensionType)getTermService().find(PesiTransformer.speciesExpertNameUuid);\r
-               mapping.addMapper(DbExtensionMapper.NewInstance(extensionTypeSpeciesExpertName, "SpeciesExpertName"));\r
-               ExtensionType extensionTypeExpertName = (ExtensionType)getTermService().find(PesiTransformer.expertNameUuid);\r
-               mapping.addMapper(DbExtensionMapper.NewInstance(extensionTypeExpertName, "ExpertName"));\r
-               \r
-//             mapping.addMapper(MethodMapper.NewInstance("ParentTaxonFk", this, TaxonBase.class, PesiExportState.class));  //by AM, doesn't work, FK exception\r
-               mapping.addMapper(ObjectChangeMapper.NewInstance(TaxonBase.class, TaxonNameBase.class, "Name"));\r
-               \r
-               addNameMappers(mapping);\r
-\r
-               return mapping;\r
-       }\r
-       \r
-       /**\r
-        * Returns the CDM to PESI specific export mappings.\r
-        * @param state \r
-        * @return The {@link PesiExportMapping PesiExportMapping}.\r
-        * @throws UndefinedTransformerMethodException \r
-        */\r
-       private PesiExportMapping getPureNameMapping(PesiExportState state) throws UndefinedTransformerMethodException {\r
-               PesiExportMapping mapping = new PesiExportMapping(dbTableName);\r
-               \r
-               mapping.addMapper(IdMapper.NewInstance("TaxonId"));\r
-\r
-               //              mapping.addMapper(MethodMapper.NewInstance("TaxonStatusFk", this.getClass(), "getTaxonStatusFk", standardMethodParameter, PesiExportState.class));\r
-\r
-               mapping.addMapper(MethodMapper.NewInstance("KingdomFk", this, TaxonNameBase.class));\r
-               mapping.addMapper(MethodMapper.NewInstance("RankFk", this, TaxonNameBase.class));\r
-               mapping.addMapper(MethodMapper.NewInstance("RankCache", this, TaxonNameBase.class, PesiExportState.class));\r
-               mapping.addMapper(DbConstantMapper.NewInstance("TaxonStatusFk", Types.INTEGER , PesiTransformer.T_STATUS_UNACCEPTED));\r
-               mapping.addMapper(DbConstantMapper.NewInstance("TaxonStatusCache", Types.VARCHAR , state.getTransformer().getTaxonStatusCacheByKey( PesiTransformer.T_STATUS_UNACCEPTED)));\r
-               mapping.addMapper(DbStringMapper.NewInstance("AuthorshipCache", "AuthorString").setBlankToNull(true));  \r
-               mapping.addMapper(MethodMapper.NewInstance("WebShowName", this, TaxonNameBase.class));\r
-               \r
-               // DisplayName\r
-               mapping.addMapper(MethodMapper.NewInstance("DisplayName", this, TaxonNameBase.class));\r
-               \r
-               mapping.addMapper(DbLastActionMapper.NewInstance("LastActionDate", false));\r
-               mapping.addMapper(DbLastActionMapper.NewInstance("LastAction", true));\r
-               \r
-               addNameMappers(mapping);\r
-               //TODO add author mapper, TypeNameFk\r
-\r
-               return mapping;\r
-       }\r
-\r
-       private void addNameMappers(PesiExportMapping mapping) {\r
-               mapping.addMapper(DbStringMapper.NewInstance("GenusOrUninomial", "GenusOrUninomial"));\r
-               mapping.addMapper(DbStringMapper.NewInstance("InfraGenericEpithet", "InfraGenericEpithet"));\r
-               mapping.addMapper(DbStringMapper.NewInstance("SpecificEpithet", "SpecificEpithet"));\r
-               mapping.addMapper(DbStringMapper.NewInstance("InfraSpecificEpithet", "InfraSpecificEpithet"));\r
-               \r
-//             mapping.addMapper(DbStringMapper.NewInstance("NameCache", "WebSearchName"));  //does not work as we need other cache strategy\r
-               mapping.addMapper(MethodMapper.NewInstance("WebSearchName", this, TaxonNameBase.class));\r
-               \r
-//             mapping.addMapper(DbStringMapper.NewInstance("TitleCache", "FullName"));    //does not work as we need other cache strategy\r
-               mapping.addMapper(MethodMapper.NewInstance("FullName", this, TaxonNameBase.class));\r
-               \r
-               \r
-               mapping.addMapper(MethodMapper.NewInstance("NomRefString", this, TaxonNameBase.class));\r
-               \r
-               mapping.addMapper(MethodMapper.NewInstance("NameStatusFk", this, TaxonNameBase.class));\r
-               mapping.addMapper(MethodMapper.NewInstance("NameStatusCache", this, TaxonNameBase.class, PesiExportState.class));\r
-               mapping.addMapper(MethodMapper.NewInstance("TypeFullnameCache", this, TaxonNameBase.class));\r
-               //TODO TypeNameFk\r
-               \r
-               //quality status\r
-               mapping.addMapper(MethodMapper.NewInstance("QualityStatusFk", this, TaxonNameBase.class));\r
-               mapping.addMapper(MethodMapper.NewInstance("QualityStatusCache", this, TaxonNameBase.class, PesiExportState.class));\r
-               \r
-               mapping.addMapper(MethodMapper.NewInstance("IdInSource", this, IdentifiableEntity.class));\r
-               mapping.addMapper(MethodMapper.NewInstance("OriginalDB", this, IdentifiableEntity.class) );\r
-\r
-               //mapping.addMapper(ExpertsAndLastActionMapper.NewInstance());\r
-\r
-       }\r
-       \r
-       private PesiExportMapping getSynRelMapping() {\r
-               PesiExportMapping mapping = new PesiExportMapping(dbTableNameSynRel);\r
-               \r
-               mapping.addMapper(MethodMapper.NewInstance("TaxonFk1", this.getClass(), "getTaxonFk1", RelationshipBase.class, PesiExportState.class));\r
-               mapping.addMapper(MethodMapper.NewInstance("TaxonFk2", this.getClass(), "getTaxonFk2", RelationshipBase.class, PesiExportState.class));\r
-               mapping.addMapper(MethodMapper.NewInstance("RelTaxonQualifierFk", this,  RelationshipBase.class));\r
-               mapping.addMapper(MethodMapper.NewInstance("RelQualifierCache", this, RelationshipBase.class, PesiExportState.class));\r
-               mapping.addMapper(MethodMapper.NewInstance("Notes", this,  RelationshipBase.class));\r
-\r
-               return mapping;\r
-       }\r
-\r
-       private PesiExportMapping getAdditionalSourceMapping(PesiExportState state)  throws UndefinedTransformerMethodException{\r
-               PesiExportMapping mapping = new PesiExportMapping(dbTableAdditionalSourceRel);\r
-               \r
-               mapping.addMapper(IdMapper.NewInstance("TaxonFk"));\r
-               mapping.addMapper(ObjectChangeMapper.NewInstance(TaxonBase.class, TaxonNameBase.class, "Name"));\r
-               \r
-               mapping.addMapper(DbObjectMapper.NewInstance("NomenclaturalReference", "SourceFk"));\r
-               mapping.addMapper(DbObjectMapper.NewInstance("NomenclaturalReference", "SourceNameCache", IS_CACHE));\r
-\r
-               //we have only nomenclatural references here\r
-               mapping.addMapper(DbConstantMapper.NewInstance("SourceUseFk", Types.INTEGER , PesiTransformer.NOMENCLATURAL_REFERENCE));\r
-               mapping.addMapper(DbConstantMapper.NewInstance("SourceUseCache", Types.VARCHAR, state.getTransformer().getSourceUseCacheByKey( PesiTransformer.NOMENCLATURAL_REFERENCE)));\r
-               \r
-               mapping.addMapper(DbStringMapper.NewInstance("NomenclaturalMicroReference", "SourceDetail"));\r
-               \r
-               return mapping;\r
-       }\r
-\r
-}\r
+/**
+* Copyright (C) 2009 EDIT
+* European Distributed Institute of Taxonomy
+* http://www.e-taxonomy.eu
+*
+* The contents of this file are subject to the Mozilla Public License Version 1.1
+* See LICENSE.TXT at the top of this package for the full license terms.
+*/
+package eu.etaxonomy.cdm.io.pesi.out;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Types;
+import java.util.ArrayList;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.log4j.Logger;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.TransactionStatus;
+
+import eu.etaxonomy.cdm.api.service.TaxonServiceImpl;
+import eu.etaxonomy.cdm.common.CdmUtils;
+import eu.etaxonomy.cdm.io.common.Source;
+import eu.etaxonomy.cdm.io.common.mapping.UndefinedTransformerMethodException;
+import eu.etaxonomy.cdm.io.common.mapping.out.DbConstantMapper;
+import eu.etaxonomy.cdm.io.common.mapping.out.DbLastActionMapper;
+import eu.etaxonomy.cdm.io.common.mapping.out.DbObjectMapper;
+import eu.etaxonomy.cdm.io.common.mapping.out.DbStringMapper;
+import eu.etaxonomy.cdm.io.common.mapping.out.IdMapper;
+import eu.etaxonomy.cdm.io.common.mapping.out.MethodMapper;
+import eu.etaxonomy.cdm.io.common.mapping.out.ObjectChangeMapper;
+import eu.etaxonomy.cdm.io.pesi.erms.ErmsTransformer;
+import eu.etaxonomy.cdm.model.common.AnnotationType;
+import eu.etaxonomy.cdm.model.common.CdmBase;
+import eu.etaxonomy.cdm.model.common.Extension;
+import eu.etaxonomy.cdm.model.common.ExtensionType;
+import eu.etaxonomy.cdm.model.common.IdentifiableEntity;
+import eu.etaxonomy.cdm.model.common.IdentifiableSource;
+import eu.etaxonomy.cdm.model.common.Marker;
+import eu.etaxonomy.cdm.model.common.MarkerType;
+import eu.etaxonomy.cdm.model.common.RelationshipBase;
+import eu.etaxonomy.cdm.model.name.NameTypeDesignation;
+import eu.etaxonomy.cdm.model.name.NameTypeDesignationStatus;
+import eu.etaxonomy.cdm.model.name.NomenclaturalCode;
+import eu.etaxonomy.cdm.model.name.NomenclaturalStatus;
+import eu.etaxonomy.cdm.model.name.Rank;
+import eu.etaxonomy.cdm.model.name.TaxonName;
+import eu.etaxonomy.cdm.model.reference.INomenclaturalReference;
+import eu.etaxonomy.cdm.model.reference.Reference;
+import eu.etaxonomy.cdm.model.taxon.Classification;
+import eu.etaxonomy.cdm.model.taxon.Synonym;
+import eu.etaxonomy.cdm.model.taxon.SynonymType;
+import eu.etaxonomy.cdm.model.taxon.Taxon;
+import eu.etaxonomy.cdm.model.taxon.TaxonBase;
+import eu.etaxonomy.cdm.model.taxon.TaxonNode;
+import eu.etaxonomy.cdm.model.taxon.TaxonRelationship;
+import eu.etaxonomy.cdm.model.taxon.TaxonRelationshipType;
+import eu.etaxonomy.cdm.strategy.cache.HTMLTagRules;
+import eu.etaxonomy.cdm.strategy.cache.TagEnum;
+import eu.etaxonomy.cdm.strategy.cache.name.INonViralNameCacheStrategy;
+import eu.etaxonomy.cdm.strategy.cache.name.TaxonNameDefaultCacheStrategy;
+import eu.etaxonomy.cdm.strategy.cache.name.ZooNameNoMarkerCacheStrategy;
+
+/**
+ * The export class for {@link eu.etaxonomy.cdm.model.name.TaxonNameBase TaxonNames}.<p>
+ * Inserts into DataWarehouse database table <code>Taxon</code>.
+ * It is divided into four phases:<p><ul>
+ * <li>Phase 1:        Export of all {@link eu.etaxonomy.cdm.model.name.TaxonName TaxonNames} except some data exported in the following phases.
+ * <li>Phase 2:        Export of additional data: ParentTaxonFk and TreeIndex.
+ * <li>Phase 3:        Export of additional data: Rank data, KingdomFk, TypeNameFk, expertFk and speciesExpertFk.
+ * <li>Phase 4:        Export of Inferred Synonyms.</ul>
+ *
+ * @author e.-m.lee
+ * @since 23.02.2010
+ */
+@Component
+public class PesiTaxonExport extends PesiExportBase {
+
+    private static final long serialVersionUID = -3412722058790200078L;
+    private static final Logger logger = Logger.getLogger(PesiTaxonExport.class);
+
+       private static final Class<? extends CdmBase> standardMethodParameter = TaxonBase.class;
+
+       private static int modCount = 1000;
+       private static final String dbTableName = "Taxon";
+       private static final String dbTableNameSynRel = "RelTaxon";
+       private static final String dbTableAdditionalSourceRel = "AdditionalTaxonSource";
+
+       private static final String pluralString = "Taxa";
+       private static final String parentPluralString = "Taxa";
+       private static final String pluralStringNames = "Names";
+
+//     private PreparedStatement parentTaxonFk_TreeIndex_KingdomFkStmts;
+       private PreparedStatement parentTaxonFkStmt;
+       private PreparedStatement rankTypeExpertsUpdateStmt;
+       private PreparedStatement rankUpdateStmt;
+       private Integer kingdomFk;
+
+       private static ExtensionType lastActionExtensionType;
+       private static ExtensionType lastActionDateExtensionType;
+       private static ExtensionType expertNameExtensionType;
+       private static ExtensionType speciesExpertNameExtensionType;
+       private static ExtensionType cacheCitationExtensionType;
+
+       public static TaxonNameDefaultCacheStrategy zooNameStrategy = ZooNameNoMarkerCacheStrategy.NewInstance();
+       public static TaxonNameDefaultCacheStrategy nonViralNameStrategy = TaxonNameDefaultCacheStrategy.NewInstance();
+       private static int currentTaxonId;
+
+       enum NamePosition {
+               beginning,
+               end,
+               between,
+               alone,
+               nowhere
+       }
+
+       public PesiTaxonExport() {
+               super();
+       }
+
+       @Override
+       public Class<? extends CdmBase> getStandardMethodParameter() {
+               return standardMethodParameter;
+       }
+
+       @Override
+       protected void doInvoke(PesiExportState state) {
+               try {
+                       logger.info("*** Started Making " + pluralString + " ...");
+
+                       initPreparedStatements(state);
+
+                       // Stores whether this invoke was successful or not.
+                       boolean success = true;
+
+                       // PESI: Clear the database table Taxon.
+                       doDelete(state);
+
+                       // Get specific mappings: (CDM) Taxon -> (PESI) Taxon
+                       PesiExportMapping mapping = getMapping();
+                       PesiExportMapping synonymRelMapping = getSynRelMapping();
+                       PesiExportMapping additionalSourceMapping = getAdditionalSourceMapping(state);
+
+                       // Initialize the db mapper
+                       mapping.initialize(state);
+                       synonymRelMapping.initialize(state);
+                       additionalSourceMapping.initialize(state);
+
+                       // Find extensionTypes
+                       lastActionExtensionType = (ExtensionType)getTermService().find(PesiTransformer.uuidExtLastAction);
+                       lastActionDateExtensionType = (ExtensionType)getTermService().find(PesiTransformer.uuidExtLastActionDate);
+                       expertNameExtensionType = (ExtensionType)getTermService().find(PesiTransformer.uuidExtExpertName);
+                       speciesExpertNameExtensionType = (ExtensionType)getTermService().find(PesiTransformer.uuidExtSpeciesExpertName);
+                       cacheCitationExtensionType = (ExtensionType)getTermService().find(PesiTransformer.uuidExtCacheCitation);
+
+                       //Export Taxa..
+                       success &= doPhase01(state, mapping, additionalSourceMapping);
+
+                       //"PHASE 1b: Handle names without taxa ...
+                       success &= doPhase01b_Names(state, additionalSourceMapping);
+
+                       // 2nd Round: Add ParentTaxonFk to each taxon
+                       success &= doPhase02(state);
+
+                       //PHASE 3: Add Rank data, KingdomFk, TypeNameFk ...
+                       success &= doPhase03(state);
+
+                       // 4nd Round: Add TreeIndex to each taxon
+                       success &= doPhase04(state);
+
+                       //"PHASE 5: Creating Inferred Synonyms...
+                       success &= doPhase05(state, mapping, synonymRelMapping);
+
+                       logger.info("*** Finished Making " + pluralString + " ..." + getSuccessString(success));
+
+                       if (!success){
+                               state.getResult().addError("An error occurred in PesiTaxonExport.doInvoke. Success = false");
+                       }
+                       return;
+               } catch (Exception e) {
+                       e.printStackTrace();
+                       logger.error(e.getMessage());
+                       state.getResult().addException(e);
+               }
+       }
+
+
+       private void initPreparedStatements(PesiExportState state) throws SQLException {
+//             initTreeIndexStatement(state);
+               initRankExpertsUpdateStmt(state);
+               initRankUpdateStatement(state);
+
+               initParentFkStatement(state);
+       }
+
+//     // Prepare TreeIndex-And-KingdomFk-Statement
+//     private void initTreeIndexStatement(PesiExportState state) throws SQLException {
+//             Connection connection = state.getConfig().getDestination().getConnection();
+//             String parentTaxonFk_TreeIndex_KingdomFkSql = "UPDATE Taxon SET ParentTaxonFk = ?, TreeIndex = ? WHERE TaxonId = ?";
+//             parentTaxonFk_TreeIndex_KingdomFkStmt = connection.prepareStatement(parentTaxonFk_TreeIndex_KingdomFkSql);
+//     }
+
+       // Prepare TreeIndex-And-KingdomFk-Statement
+       private void initParentFkStatement(PesiExportState state) throws SQLException {
+               Connection connection = state.getConfig().getDestination().getConnection();
+               String parentTaxonFkSql = "UPDATE Taxon SET ParentTaxonFk = ? WHERE TaxonId = ?";
+               parentTaxonFkStmt = connection.prepareStatement(parentTaxonFkSql);
+       }
+
+       private void initRankUpdateStatement(PesiExportState state) throws SQLException {
+               Connection connection = state.getConfig().getDestination().getConnection();
+               String rankSql = "UPDATE Taxon SET RankFk = ?, RankCache = ?, KingdomFk = ? WHERE TaxonId = ?";
+               rankUpdateStmt = connection.prepareStatement(rankSql);
+       }
+
+       private void initRankExpertsUpdateStmt(PesiExportState state) throws SQLException {
+//             String sql_old = "UPDATE Taxon SET RankFk = ?, RankCache = ?, TypeNameFk = ?, KingdomFk = ?, " +
+//                             "ExpertFk = ?, SpeciesExpertFk = ? WHERE TaxonId = ?";
+               //TODO handle experts GUIDs
+               Connection connection = state.getConfig().getDestination().getConnection();
+
+               String sql = "UPDATE Taxon SET RankFk = ?, RankCache = ?, TypeNameFk = ?, KingdomFk = ? " +
+                               " WHERE TaxonId = ?";
+               rankTypeExpertsUpdateStmt = connection.prepareStatement(sql);
+       }
+
+       private boolean doPhase01(PesiExportState state, PesiExportMapping mapping, PesiExportMapping additionalSourceMapping){
+
+           int count = 0;
+               int pastCount = 0;
+               boolean success = true;
+               // Get the limit for objects to save within a single transaction.
+               int limit = state.getConfig().getLimitSave();
+
+               logger.info("PHASE 1: Export Taxa...limit is " + limit);
+               // Start transaction
+               TransactionStatus txStatus = startTransaction(true);
+               if (logger.isDebugEnabled()) {
+            logger.info("Started new transaction. Fetching some " + pluralString + " (max: " + limit + ") ...");
+            logger.info("Taking snapshot at the beginning of phase 1 of taxonExport");
+            //ProfilerController.memorySnapshot();
+        }
+
+               int partitionCount = 0;
+               List<TaxonBase<?>> list;
+               while ((list = getNextTaxonPartition(null, limit, partitionCount++, null)) != null   ) {
+
+                       logger.debug("Fetched " + list.size() + " " + pluralString + ". Exporting...");
+
+                       for (TaxonBase<?> taxon : list) {
+                               doCount(count++, modCount, pluralString);
+                               TaxonName taxonName = taxon.getName();
+
+                               TaxonName nvn = CdmBase.deproxy(taxonName);
+                               if (! nvn.isProtectedTitleCache()){
+                                       nvn.setTitleCache(null, false);
+                               }
+                               if (! nvn.isProtectedNameCache()){
+                                       nvn.setNameCache(null, false);
+                               }
+                               if (! nvn.isProtectedFullTitleCache()){
+                                       nvn.setFullTitleCache(null, false);
+                               }
+                               if (! nvn.isProtectedAuthorshipCache()){
+                                       nvn.setAuthorshipCache(null, false);
+                               }
+                               try{
+                               if (nvn.getRank().equals(Rank.KINGDOM())){
+                                   if(taxon.isInstanceOf(Taxon.class)){
+                                       String treeIndex = ((Taxon)taxon).getTaxonNodes().iterator().next().treeIndex();
+                                       Integer kingdomId = PesiTransformer.pesiKingdomId(nvn.getGenusOrUninomial());
+                                       state.getTreeIndexKingdomMap().put(treeIndex, kingdomId);
+                                   }else{
+                                       logger.warn("Kingdom taxon is not of class Taxon but " + taxon.getClass().getSimpleName() + ": " + nvn.getGenusOrUninomial());
+                                   }
+                               }
+                               }catch(NullPointerException e){
+                                   logger.error(nvn.getTitleCache() + " has no Rank!");
+                                   System.err.println(nvn.getTitleCache() + " has no Rank!");
+                               }
+                               //core mapping
+                               success &= mapping.invoke(taxon);
+                               //additional source
+                               if (nvn.getNomenclaturalReference() != null || StringUtils.isNotBlank(nvn.getNomenclaturalMicroReference() )){
+                                       additionalSourceMapping.invoke(taxon);
+                               }
+
+                               //TODO switch on again, leads to some warnings in ERMS for taxa of not correctly handled kingdoms
+                               validatePhaseOne(taxon, nvn);
+                       }
+
+                       // Commit transaction
+                       commitTransaction(txStatus);
+                       logger.info("Exported " + (count - pastCount) + " " + pluralString + ". Total: " + count + " (Phase 01)");
+                       pastCount = count;
+
+                       // Start new transaction
+                       txStatus = startTransaction(true);
+                       if (logger.isDebugEnabled()) {
+                logger.info("Started new transaction. Fetching some " + pluralString + " (max: " + limit + ") ...");
+            }
+
+               }
+               logger.debug("No " + pluralString + " left to fetch.");
+
+               // Commit transaction
+               commitTransaction(txStatus);
+               txStatus = null;
+
+               return success;
+       }
+
+       private void validatePhaseOne(TaxonBase<?> taxon, TaxonName taxonName) {
+
+           // Check whether some rules are violated
+               String genusOrUninomial = taxonName.getGenusOrUninomial();
+               String specificEpithet = taxonName.getSpecificEpithet();
+               String infraSpecificEpithet = taxonName.getInfraSpecificEpithet();
+               String infraGenericEpithet = taxonName.getInfraGenericEpithet();
+               Rank rank =  taxonName.getRank();
+
+               //as kingdomFk can not be defined in Phase 01 the below code was switched to use the CDM rank.
+               //This may be changed if we move validation to Phase03 or later
+//             Integer rankFk = getRankFk(taxonName, taxonName.getNameType());
+//             if (rankFk == null) {
+//                     logger.error("Rank was not determined: " + taxon.getUuid() + " (" + taxon.getTitleCache() + ")");
+//             } else {
+
+                       // Check whether infraGenericEpithet is set correctly
+                       // 1. Childs of an accepted taxon of rank subgenus that are accepted taxa of rank species have to have an infraGenericEpithet
+                       // 2. Grandchilds of an accepted taxon of rank subgenus that are accepted taxa of rank subspecies have to have an infraGenericEpithet
+
+                       int ancestorLevel = 0;
+                       if (rank == null){
+                           logger.warn("PhaseOne validation: Taxon name has no rank: " + taxonName.getTitleCache());
+                       }else if (rank.equals(Rank.SUBSPECIES())) {
+                               // The accepted taxon two rank levels above should be of rank subgenus
+                               ancestorLevel  = 2;
+                       }else if (rank.equals(Rank.SPECIES())) {
+                               // The accepted taxon one rank level above should be of rank subgenus
+                               ancestorLevel = 1;
+                       }
+                       if (ancestorLevel > 0) {
+                               if (validateAncestorOfSpecificRank(taxon, ancestorLevel, Rank.SUBGENUS())) {
+                                       // The child (species or subspecies) of this parent (subgenus) has to have an infraGenericEpithet
+                                       if (infraGenericEpithet == null) {
+                                               logger.warn("InfraGenericEpithet for (sub)species of infrageneric taxon does not exist even though it should (also valid for Botanical Names?) for: " + taxon.getUuid() + " (" + taxon.getTitleCache() + ")");
+                                               // maybe the taxon could be named here
+                                       }
+                               }
+                       }
+
+                       if (rank != null){
+                           if (infraGenericEpithet == null && rank.isInfraGenericButNotSpeciesGroup()) {
+                               logger.warn("InfraGenericEpithet was not determined although it should exist for infra generic names: " + taxon.getUuid() + " (" + taxon.getTitleCache() + ")");
+                           }
+                           if (specificEpithet != null && (rank.isInfraGenericButNotSpeciesGroup()||rank.isGenus()||rank.isSupraGeneric())) {
+                               logger.warn("SpecificEpithet was determined for rank " + rank.getTitleCache() + " although it should only exist for species aggregates, species or infraspecific taxa: TaxonName " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
+                           }
+                           if (infraSpecificEpithet != null && !rank.isInfraSpecific()) {
+                               String message = "InfraSpecificEpithet '" +infraSpecificEpithet + "' was determined for rank " + rank.getTitleCache() + " although it should only exist for rank species and higher: "  + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")";
+                               if (StringUtils.isNotBlank(infraSpecificEpithet)){
+                                   logger.warn(message);
+                               }else{
+                                   logger.warn(message);
+                               }
+                           }
+                       }
+//             }
+               if (infraSpecificEpithet != null && specificEpithet == null) {
+                       logger.warn("An infraSpecificEpithet was determined, but a specificEpithet was not determined: "  + taxon.getUuid() + " (" + taxon.getTitleCache() + ")");
+               }
+               if (genusOrUninomial == null) {
+                       logger.warn("GenusOrUninomial was not determined: " + taxon.getUuid() + " (" + taxon.getTitleCache() + ")");
+               }
+       }
+
+       /**
+        * 2nd Round: Add ParentTaxonFk to each taxon and add Biota if not exists
+        */
+       private boolean doPhase02(PesiExportState state) {
+               int count = 0;
+               int pastCount = 0;
+               boolean success = true;
+               if (! state.getConfig().isDoParentAndBiota()){
+                       logger.info ("Ignore PHASE 2: Make ParentFk and Biota...");
+                       return success;
+               }
+
+               // Get the limit for objects to save within a single transaction.
+               int limit = state.getConfig().getLimitSave();
+
+               insertBiota(state);
+
+               logger.info("PHASE 2: Make ParentFk and Biota ... limit is " + limit);
+               // Start transaction
+               TransactionStatus txStatus = startTransaction(true);
+               int partitionCount = 0;
+
+//             ProfilerController.memorySnapshot();
+               List<Taxon> list;
+               while ((list = getNextTaxonPartition(Taxon.class, limit, partitionCount++, null)) != null   ) {
+
+                       if(logger.isDebugEnabled()) {
+                logger.info("Fetched " + list.size() + " " + pluralString + ". Exporting...");
+            }
+                       for (Taxon taxon : list) {
+                               for (TaxonNode node : taxon.getTaxonNodes()){
+                                       doCount(count++, modCount, pluralString);
+                                       TaxonNode parentNode = node.getParent();
+                                       if (parentNode != null && isPesiTaxon(parentNode.getTaxon())){ //exclude root taxa and unpublished parents (relevant for "Valueless" parent for E+M Rubus taxa). Usually a parent should not be unpublished
+                                               int childId = state.getDbId( taxon);
+                                               int parentId = state.getDbId(parentNode.getTaxon());
+                                               success &= invokeParentTaxonFk(parentId, childId);
+                                       }
+                               }
+                       }
+
+                       // Commit transaction
+                       commitTransaction(txStatus);
+                       logger.info("Exported " + (count - pastCount) + " " + pluralString + ". Total: " + count + " (Phase 2)");
+                       pastCount = count;
+                       // Start transaction
+                       txStatus = startTransaction(true);
+                       if (logger.isDebugEnabled()){
+                           logger.info("Started new transaction. Fetching some " + pluralString + " (max: " + limit + ") ...");
+                       }
+               }
+               logger.debug("No " + pluralString + " left to fetch.");
+
+               // Commit transaction
+               commitTransaction(txStatus);
+
+               return success;
+       }
+
+       /**
+        * Inserts the Biota Taxon if not yet exists.
+        */
+       private void insertBiota(PesiExportState state) {
+               try {
+                       ResultSet rs = state.getConfig().getDestination().getResultSet("SELECT * FROM Taxon WHERE GenusOrUninomial = 'Biota' ");
+                       if (rs.next() == false){
+                               int biotaId = state.getConfig().getNameIdStart() -1 ;
+                               String sqlInsertBiota = "INSERT INTO Taxon (TaxonId, KingdomFk, RankFk, RankCache, GenusOrUninomial, WebSearchName, WebShowName, FullName, DisplayName, TaxonStatusFk, TaxonStatusCache) " +
+                                                                              " VALUES (" + biotaId + ",    0,    0,   'Superdomain',   'Biota',          'Biota',  '<i>Biota</i>',   'Biota', '<i>Biota</i>',  1 ,      'accepted')";
+                               state.getConfig().getDestination().update(sqlInsertBiota);
+                       }
+                       rs = null;
+               } catch (SQLException e) {
+                       logger.warn ("Biota could not be requested or inserted");
+               }
+       }
+
+       //PHASE 3: Add Rank data, KingdomFk, TypeNameFk, expertFk and speciesExpertFk...
+       private boolean doPhase03(PesiExportState state) {
+               int count = 0;
+               int pastCount = 0;
+               boolean success = true;
+               if (! state.getConfig().isDoTreeIndex()){
+                       logger.info ("Ignore PHASE 3: Add Rank data, KingdomFk, TypeNameFk, expertFk and speciesExpertFk...");
+                       return success;
+               }
+
+               addValuelessTaxonToKingdomMap(state);
+
+               // Get the limit for objects to save within a single transaction.
+               int limit = state.getConfig().getLimitSave();
+
+               logger.info("PHASE 3: Add Rank data, KingdomFk, TypeNameFk, expertFk and speciesExpertFk...");
+               // Be sure to add rank information, KingdomFk, TypeNameFk, expertFk and speciesExpertFk to every taxonName
+
+               // Start transaction
+               TransactionStatus txStatus = startTransaction(true);
+               if (logger.isDebugEnabled()) {
+            logger.info("Started new transaction for rank, kingdom, typeName, expertFk and speciesExpertFK. Fetching some " + pluralString + " (max: " + limit + ") ...");
+        }
+               int partitionCount = 0;
+               @SuppressWarnings("rawtypes")
+        List<TaxonBase> list;
+               while ((list = getNextTaxonPartition(TaxonBase.class, limit, partitionCount++, null)) != null) {
+
+                       if (logger.isDebugEnabled()) {
+                logger.debug("Fetched " + list.size() + " " + pluralString + ". Exporting...");
+            }
+                       for (TaxonBase<?> taxon : list) {
+                               TaxonName taxonName = CdmBase.deproxy(taxon.getName());
+                               // Determine expertFk
+//                             Integer expertFk = makeExpertFk(state, taxonName);
+//
+//                             // Determine speciesExpertFk
+//                             Integer speciesExpertFk = makeSpeciesExpertFk(state, taxonName);
+
+                               doCount(count++, modCount, pluralString);
+                               Integer typeNameFk = getTypeNameFk(taxonName, state);
+                               Integer kingdomFk = findKingdomIdFromTreeIndex(taxon, state);
+                               Integer rankFk = getRankFk(taxonName, kingdomFk);
+
+                           invokeRankDataAndTypeNameFkAndKingdomFk(taxonName, state.getDbId(taxon),
+                                               typeNameFk, kingdomFk, rankFk, state);
+                       }
+
+                       // Commit transaction
+                       commitTransaction(txStatus);
+                       if (logger.isDebugEnabled()){logger.debug("Committed transaction.");}
+                       logger.info("Exported " + (count - pastCount) + " " + pluralString + ". Total: " + count + " (Phase 3)");
+                       pastCount = count;
+
+                       // Start transaction
+                       txStatus = startTransaction(true);
+                       if (logger.isDebugEnabled()) {
+                logger.info("Started new transaction for rank, kingdom, typeName, expertFk and speciesExpertFK. Fetching some " + pluralString + " (max: " + limit + ") ...");
+            }
+               }
+               logger.debug("No " + pluralString + " left to fetch.");
+
+               // Commit transaction
+               commitTransaction(txStatus);
+
+               if (logger.isDebugEnabled()){
+                   logger.debug("Committed transaction.");
+                   logger.debug("Try to take snapshot at the end of phase 3 of taxonExport, number of partitions: " + partitionCount);
+                   //ProfilerController.memorySnapshot();
+               }
+               return success;
+       }
+
+    private void addValuelessTaxonToKingdomMap(PesiExportState state) {
+        TransactionStatus txStatus = startTransaction();
+        Taxon valuelessTaxon = (Taxon)getTaxonService().find(PesiTransformer.uuidTaxonValuelessEuroMed);
+        if (valuelessTaxon != null){
+            String treeIndex = valuelessTaxon.getTaxonNodes().iterator().next().treeIndex();
+            Integer kingdomId = PesiTransformer.pesiKingdomId("Plantae");
+            state.getTreeIndexKingdomMap().put(treeIndex, kingdomId);
+        }
+        commitTransaction(txStatus);
+    }
+
+    // 4th round: Add TreeIndex to each taxon
+    private boolean doPhase04(PesiExportState state) {
+        boolean success = true;
+
+        logger.info("PHASE 4: Make TreeIndex ... ");
+
+        //TODO test if possible to move to phase 02
+        String sql = " UPDATE Taxon SET ParentTaxonFk = (SELECT TaxonId FROM Taxon WHERE RankFk = 0) " +
+                " WHERE (RankFk = 10) and TaxonStatusFk = 1 ";
+        state.getConfig().getDestination().update(sql);
+
+        state.getConfig().getDestination().update("EXEC dbo.recalculateallstoredpaths");
+
+        logger.info("PHASE 4: Make TreeIndex DONE");
+
+        return success;
+    }
+
+    private static Integer findKingdomIdFromTreeIndex(TaxonBase<?> taxonBase, PesiExportState state) {
+        Taxon taxon;
+        if (taxonBase instanceof Synonym){
+            taxon = ((Synonym) taxonBase).getAcceptedTaxon();
+        }else{
+            taxon = checkPseudoOrRelatedTaxon((Taxon)taxonBase);
+        }
+        if (taxon == null){
+            NomenclaturalCode nomenclaturalCode = taxonBase.getName().getNameType();
+            logger.warn("Taxon is synonym with no accepted taxon attached: " + taxonBase.getTitleCache() + ". The kingdom is taken from the nomenclatural code: " + PesiTransformer.nomenclaturalCode2Kingdom(nomenclaturalCode) );
+            return PesiTransformer.nomenclaturalCode2Kingdom(nomenclaturalCode);
+        } else{
+            Set<TaxonNode> nodes = taxon.getTaxonNodes();
+            if (nodes.isEmpty()){
+                NomenclaturalCode nomenclaturalCode = taxon.getName().getNameType();
+                logger.warn("The taxon has no nodes: " + taxon.getTitleCache() + ". The kingdom is taken from the nomenclatural code: " + PesiTransformer.nomenclaturalCode2Kingdom(nomenclaturalCode));
+                return PesiTransformer.nomenclaturalCode2Kingdom(nomenclaturalCode);
+            } else {
+                if (nodes.size()>1){
+                    logger.warn("The taxon has more then 1 taxon node: " + taxon.getTitleCache() + ". Take arbitrary one.");
+                }
+                String treeIndex = nodes.iterator().next().treeIndex();
+
+                Pattern pattern = Pattern.compile("#t[0-9]+#([0-9]+#){3}");
+                Matcher matcher = pattern.matcher(treeIndex);
+                Integer kingdomID = null;
+                if(matcher.find()) {
+                    String treeIndexKingdom = matcher.group(0);
+                    kingdomID = state.getTreeIndexKingdomMap().get(treeIndexKingdom);
+                }
+                if (kingdomID == null){
+                    pattern = Pattern.compile("#t[0-9]+#([0-9]+#){2}");
+                    matcher = pattern.matcher(treeIndex);
+                    if(matcher.find()) {
+                        String treeIndexKingdom = matcher.group(0);
+                        Map<String, Integer> map = state.getTreeIndexKingdomMap();
+                        kingdomID = map.get(treeIndexKingdom);
+                    }
+                }
+                if(Rank.DOMAIN().equals(taxon.getName().getRank())){
+                    return 0;
+                }
+                if(kingdomID == null){
+                    logger.warn("Kingdom could not be defined for treeindex " + treeIndex);
+                }
+                return kingdomID;
+            }
+        }
+    }
+
+    private static Taxon checkPseudoOrRelatedTaxon(Taxon taxon) {
+        if (!taxon.getTaxonNodes().isEmpty()){
+            return taxon;
+        }else if(hasPseudoTaxonRelationship(taxon)){
+            return acceptedPseudoTaxon(taxon);
+        }else if(isMisappliedNameOrProParteSynonym(taxon)){
+            return acceptedTaxonConcept(taxon);
+        }else{
+            return taxon;
+        }
+    }
+
+    private static Taxon acceptedPseudoTaxon(Taxon taxon) {
+        for (TaxonRelationship rel : taxon.getRelationsFromThisTaxon()){
+            if (TaxonRelationshipType.pseudoTaxonUuids().contains(rel.getType().getUuid())){
+                return rel.getToTaxon();
+            }
+        }
+        return taxon;
+    }
+
+    private static Taxon acceptedTaxonConcept(Taxon taxon) {
+       for (TaxonRelationship rel : taxon.getRelationsFromThisTaxon()){
+            if (TaxonRelationshipType.misappliedNameUuids().contains(rel.getType().getUuid())||
+                    TaxonRelationshipType.proParteOrPartialSynonymUuids().contains(rel.getType().getUuid())){
+                return rel.getToTaxon();
+            }
+        }
+        return taxon;
+    }
+
+    private static boolean hasPseudoTaxonRelationship(Taxon taxon) {
+        for (TaxonRelationship rel : taxon.getRelationsFromThisTaxon()){
+            if (TaxonRelationshipType.pseudoTaxonUuids().contains(rel.getType().getUuid())){
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private static boolean isMisappliedNameOrProParteSynonym(Taxon taxon) {
+        for (TaxonRelationship rel : taxon.getRelationsFromThisTaxon()){
+            if (TaxonRelationshipType.misappliedNameUuids().contains(rel.getType().getUuid())||
+                    TaxonRelationshipType.proParteOrPartialSynonymUuids().contains(rel.getType().getUuid())){
+                return true;
+            }
+        }
+        return false;
+    }
+
+    // "PHASE 5: Creating Inferred Synonyms..."
+       private boolean doPhase05(PesiExportState state, PesiExportMapping mapping, PesiExportMapping synRelMapping) {
+               int count;
+               int pastCount;
+               boolean success = true;
+               // Get the limit for objects to save within a single transaction.
+               if (! state.getConfig().isDoInferredSynonyms()){
+                       logger.info ("Ignore PHASE 5: Creating Inferred Synonyms...");
+                       return success;
+               }
+
+               int limit = state.getConfig().getLimitSave();
+               // Create inferred synonyms for accepted taxa
+               logger.info("PHASE 5: Creating Inferred Synonyms...");
+
+               // Determine the count of elements in data warehouse database table Taxon
+               currentTaxonId = determineTaxonCount(state);
+               currentTaxonId++;
+
+               count = 0;
+               pastCount = 0;
+               int pageSize = limit/10;
+               int pageNumber = 1;
+               String inferredSynonymPluralString = "Inferred Synonyms";
+
+               // Start transaction
+               TransactionStatus txStatus = startTransaction(true);
+               if (logger.isDebugEnabled()) {
+            logger.info("Started new transaction. Fetching some " + parentPluralString + " first (max: " + limit + ") ...");
+        }
+
+               List<TaxonBase> taxonList = null;
+               while ((taxonList  = getTaxonService().listTaxaByName(Taxon.class, "*", "*", "*", "*", "*", Rank.SPECIES(), pageSize, pageNumber, null)).size() > 0) {
+
+                   Map<Integer, TaxonName> inferredSynonymsDataToBeSaved = new HashMap<>();
+
+                       if (logger.isDebugEnabled()) {
+                logger.info("Fetched " + taxonList.size() + " " + parentPluralString + ". Exporting...");
+            }
+                       inferredSynonymsDataToBeSaved.putAll(createInferredSynonymsForTaxonList(state, mapping,
+                                       synRelMapping, taxonList));
+
+                       doCount(count += taxonList.size(), modCount, inferredSynonymPluralString);
+                       // Commit transaction
+                       commitTransaction(txStatus);
+                       if (logger.isDebugEnabled()){logger.debug("Committed transaction.");}
+                       logger.info("Exported " + (taxonList.size()) + " " + inferredSynonymPluralString + ". Total: " + count);
+                       //pastCount = count;
+
+                       // Save Rank Data and KingdomFk for inferred synonyms
+                       for (Integer taxonFk : inferredSynonymsDataToBeSaved.keySet()) {
+                           TaxonName taxonName = inferredSynonymsDataToBeSaved.get(taxonFk);
+                invokeRankDataAndKingdomFk(inferredSynonymsDataToBeSaved.get(taxonFk), taxonFk, kingdomFk, state);
+                       }
+
+                       // Start transaction
+                       txStatus = startTransaction(true);
+                       if (logger.isDebugEnabled()) {
+                logger.info("Started new transaction. Fetching some " + parentPluralString + " first (max: " + limit + ") ...");
+            }
+
+                       // Increment pageNumber
+                       pageNumber++;
+               }
+               taxonList = null;
+               while ((taxonList  = getTaxonService().listTaxaByName(Taxon.class, "*", "*", "*", "*", "*", Rank.SUBSPECIES(), pageSize, pageNumber, null)).size() > 0) {
+                       Map<Integer, TaxonName> inferredSynonymsDataToBeSaved = new HashMap<>();
+
+                       logger.info("Fetched " + taxonList.size() + " " + parentPluralString + ". Exporting...");
+                       inferredSynonymsDataToBeSaved.putAll(createInferredSynonymsForTaxonList(state, mapping,
+                                       synRelMapping, taxonList));
+
+                       doCount(count += taxonList.size(), modCount, inferredSynonymPluralString);
+                       // Commit transaction
+                       commitTransaction(txStatus);
+                       logger.debug("Committed transaction.");
+                       logger.info("Exported " + taxonList.size()+ " " + inferredSynonymPluralString + ". Total: " + count);
+                       //pastCount = count;
+
+                       // Save Rank Data and KingdomFk for inferred synonyms
+                       for (Integer taxonFk : inferredSynonymsDataToBeSaved.keySet()) {
+                           TaxonName taxonName = inferredSynonymsDataToBeSaved.get(taxonFk);
+                           invokeRankDataAndKingdomFk(taxonName, taxonFk, kingdomFk, state);
+                       }
+
+                       // Start transaction
+                       txStatus = startTransaction(true);
+                       logger.info("Started new transaction. Fetching some " + parentPluralString + " first (max: " + limit + ") ...");
+
+                       // Increment pageNumber
+                       pageNumber++;
+                       inferredSynonymsDataToBeSaved = null;
+               }
+               if (taxonList.size() == 0) {
+                       logger.info("No " + parentPluralString + " left to fetch.");
+               }
+
+               taxonList = null;
+//             logger.warn("Taking snapshot at the end of phase 5 of taxonExport");
+//             ProfilerController.memorySnapshot();
+
+               // Commit transaction
+               commitTransaction(txStatus);
+               System.gc();
+               logger.debug("Taking snapshot at the end of phase 5 after gc() of taxonExport");
+               //ProfilerController.memorySnapshot();
+               logger.debug("Committed transaction.");
+               return success;
+       }
+
+       private Map<Integer, TaxonName> createInferredSynonymsForTaxonList(PesiExportState state,
+                       PesiExportMapping mapping, PesiExportMapping synRelMapping,      List<TaxonBase> taxonList) {
+
+               Taxon acceptedTaxon;
+               Classification classification = null;
+               List<Synonym> inferredSynonyms = null;
+               boolean localSuccess = true;
+
+               Map<Integer, TaxonName> inferredSynonymsDataToBeSaved = new HashMap<>();
+
+               for (TaxonBase<?> taxonBase : taxonList) {
+
+                       if (taxonBase.isInstanceOf(Taxon.class)) { // this should always be the case since we should have fetched accepted taxon only, but you never know...
+                               acceptedTaxon = CdmBase.deproxy(taxonBase, Taxon.class);
+                               TaxonName taxonName = acceptedTaxon.getName();
+
+                               if (taxonName.isZoological()) {
+                                       kingdomFk = findKingdomIdFromTreeIndex(taxonBase, state);
+
+                                       Set<TaxonNode> taxonNodes = acceptedTaxon.getTaxonNodes();
+                                       TaxonNode singleNode = null;
+
+                                       if (taxonNodes.size() > 0) {
+                                               // Determine the classification of the current TaxonNode
+
+                                               singleNode = taxonNodes.iterator().next();
+                                               if (singleNode != null) {
+                                                       classification = singleNode.getClassification();
+                                               } else {
+                                                       logger.error("A TaxonNode belonging to this accepted Taxon is NULL: " + acceptedTaxon.getUuid() + " (" + acceptedTaxon.getTitleCache() +")");
+                                               }
+                                       } else {
+                                               // Classification could not be determined directly from this TaxonNode
+                                               // The stored classification from another TaxonNode is used. It's a simple, but not a failsafe fallback solution.
+                                               if (taxonNodes.size() == 0) {
+                                                       //logger.error("Classification could not be determined directly from this Taxon: " + acceptedTaxon.getUuid() + " is misapplication? "+acceptedTaxon.isMisapplication()+ "). The classification of the last taxon is used");
+                                               }
+                                       }
+
+                                       if (classification != null) {
+                                               try{
+                                                   TaxonName name = acceptedTaxon.getName();
+                                                       //if (name.isSpecies() || name.isInfraSpecific()){
+                                                               inferredSynonyms  = getTaxonService().createAllInferredSynonyms(acceptedTaxon, classification, true);
+                                                       //}
+//                                                             inferredSynonyms = getTaxonService().createInferredSynonyms(classification, acceptedTaxon, SynonymType.INFERRED_GENUS_OF());
+                                                       if (inferredSynonyms != null) {
+                                                               for (Synonym synonym : inferredSynonyms) {
+//                                                                     TaxonName synonymName = synonym.getName();
+                                                                       MarkerType markerType =getUuidMarkerType(PesiTransformer.uuidMarkerGuidIsMissing, state);
+                                                                       synonym.addMarker(Marker.NewInstance(markerType, true));
+                                                                       // Both Synonym and its TaxonName have no valid Id yet
+                                                                       synonym.setId(currentTaxonId++);
+
+
+                                                                       localSuccess &= mapping.invoke(synonym);
+                                                                       //get SynonymRelationship and export
+                                                                       if (synonym.getAcceptedTaxon() == null ){
+                                                                               IdentifiableSource source = synonym.getSources().iterator().next();
+                                                                               if (source.getIdNamespace().contains("Potential combination")){
+                                                                                       acceptedTaxon.addSynonym(synonym, SynonymType.POTENTIAL_COMBINATION_OF());
+                                                                                       logger.error(synonym.getTitleCache() + " is not attached to " + acceptedTaxon.getTitleCache() + " type is set to potential combination");
+                                                                               } else if (source.getIdNamespace().contains("Inferred Genus")){
+                                                                                       acceptedTaxon.addSynonym(synonym, SynonymType.INFERRED_GENUS_OF());
+                                                                                       logger.error(synonym.getTitleCache() + " is not attached to " + acceptedTaxon.getTitleCache() + " type is set to inferred genus");
+                                                                               } else if (source.getIdNamespace().contains("Inferred Epithet")){
+                                                                                       acceptedTaxon.addSynonym(synonym, SynonymType.INFERRED_EPITHET_OF());
+                                                                                       logger.error(synonym.getTitleCache() + " is not attached to " + acceptedTaxon.getTitleCache() + " type is set to inferred epithet");
+                                                                               } else{
+                                                                                       acceptedTaxon.addSynonym(synonym, SynonymType.INFERRED_SYNONYM_OF());
+                                                                                       logger.error(synonym.getTitleCache() + " is not attached to " + acceptedTaxon.getTitleCache() + " type is set to inferred synonym");
+                                                                               }
+
+                                                                               localSuccess &= synRelMapping.invoke(synonym);
+                                                                               if (!localSuccess) {
+                                                                                       logger.error("Synonym relationship export failed " + synonym.getTitleCache() + " accepted taxon: " + acceptedTaxon.getUuid() + " (" + acceptedTaxon.getTitleCache()+")");
+                                                                               }
+                                                                       } else {
+                                                                               localSuccess &= synRelMapping.invoke(synonym);
+                                                                               if (!localSuccess) {
+                                                                                       logger.error("Synonym relationship export failed " + synonym.getTitleCache() + " accepted taxon: " + acceptedTaxon.getUuid() + " (" + acceptedTaxon.getTitleCache()+")");
+                                                                               } else {
+                                                                                       logger.info("Synonym relationship successfully exported: " + synonym.getTitleCache() + "  " +acceptedTaxon.getUuid() + " (" + acceptedTaxon.getTitleCache()+")");
+                                                                               }
+                                                                       }
+
+                                                                       inferredSynonymsDataToBeSaved.put(synonym.getId(), synonym.getName());
+                                                               }
+                                                       }
+                                               }catch(Exception e){
+                                                       logger.error(e.getMessage());
+                                                       e.printStackTrace();
+                                               }
+                                       } else {
+                                               logger.error("Classification is NULL. Inferred Synonyms could not be created for this Taxon: " + acceptedTaxon.getUuid() + " (" + acceptedTaxon.getTitleCache() + ")");
+                                       }
+                               } else {
+//                                                     logger.error("TaxonName is not a ZoologicalName: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
+                               }
+                       } else {
+                               logger.error("This TaxonBase is not a Taxon even though it should be: " + taxonBase.getUuid() + " (" + taxonBase.getTitleCache() + ")");
+                       }
+               }
+               return inferredSynonymsDataToBeSaved;
+       }
+
+       /**
+        * Handles names that do not appear in taxa.
+        */
+       private boolean doPhase01b_Names(PesiExportState state, PesiExportMapping additionalSourceMapping) {
+
+               boolean success = true;
+               if (! state.getConfig().isDoPureNames()){
+                       logger.info ("Ignore PHASE 1b: PureNames");
+                       return success;
+               }
+
+               try {
+                       PesiExportMapping mapping = getPureNameMapping(state);
+                       mapping.initialize(state);
+                       int count = 0;
+                       int pastCount = 0;
+                       success = true;
+                       // Get the limit for objects to save within a single transaction.
+                       int limit = state.getConfig().getLimitSave();
+
+                       logger.info("PHASE 1b: Export Pure Names ...");
+                       // Start transaction
+                       TransactionStatus txStatus = startTransaction(true);
+                       logger.info("Started new transaction for Pure Names. Fetching some " + pluralString + " (max: " + limit + ") ...");
+
+                       int partitionCount = 0;
+                       List<TaxonName> list;
+                       while ((list = getNextPureNamePartition(null, limit, partitionCount++)) != null   ) {
+
+                               logger.debug("Fetched " + list.size() + pluralStringNames + " without taxa. Exporting...");
+                               for (TaxonName taxonName : list) {
+                                       doCount(count++, modCount, pluralString);
+                                       success &= mapping.invoke(taxonName);
+                                       //additional source
+                                       if (taxonName.getNomenclaturalReference() != null || StringUtils.isNotBlank(taxonName.getNomenclaturalMicroReference() )){
+                                               additionalSourceMapping.invoke(taxonName);
+                                       }
+                               }
+
+                               // Commit transaction
+                               commitTransaction(txStatus);
+                               logger.debug("Committed transaction.");
+                               logger.info("Exported " + (count - pastCount) + " " + pluralStringNames + ". Total: " + count + ". Partition: " + partitionCount);
+                               pastCount = count;
+
+                               // Start transaction
+                               txStatus = startTransaction(true);
+                               logger.debug("Started new transaction for PureNames. Fetching some " + pluralString + " (max: " + limit + ") ...");
+                       }
+                       logger.debug("No " + pluralString + " left to fetch.");
+
+                       // Commit transaction
+                       commitTransaction(txStatus);
+                       logger.debug("Committed transaction.");
+               } catch (Exception e) {
+                       logger.error("Error occurred in pure name export");
+                       e.printStackTrace();
+                       success = false;
+               }
+               return success;
+       }
+
+       /**
+        * Determines the current number of entries in the DataWarehouse database table <code>Taxon</code>.
+        * @param state The {@link PesiExportState PesiExportState}.
+        * @return The count.
+        */
+       private Integer determineTaxonCount(PesiExportState state) {
+               Integer result = null;
+               PesiExportConfigurator pesiConfig = state.getConfig();
+
+               String sql;
+               Source destination =  pesiConfig.getDestination();
+               sql = "SELECT max(taxonId) FROM Taxon";
+               destination.setQuery(sql);
+               ResultSet resultSet = destination.getResultSet();
+               try {
+                       resultSet.next();
+                       result = resultSet.getInt(1);
+               } catch (SQLException e) {
+                       logger.error("TaxonCount could not be determined: " + e.getMessage());
+                       e.printStackTrace();
+               }
+               resultSet = null;
+               return result;
+       }
+
+       /**
+        * Checks whether a parent at specific level has a specific Rank.
+        * @param taxonName A {@link TaxonNameBase TaxonName}.
+        * @param level The ancestor level.
+        * @param ancestorRank The ancestor rank.
+        * @return Whether a parent at a specific level has a specific Rank.
+        */
+       private boolean validateAncestorOfSpecificRank(TaxonBase<?> taxonBase, int level, Rank ancestorRank) {
+               boolean result = false;
+               TaxonNode parentNode = null;
+               if (taxonBase.isInstanceOf(Taxon.class)){
+                       Taxon taxon = CdmBase.deproxy(taxonBase, Taxon.class);
+                       // Get ancestor Taxon via TaxonNode
+                       Set<TaxonNode> taxonNodes = taxon.getTaxonNodes();
+                       if (taxonNodes.size() == 1) {
+                               TaxonNode taxonNode = taxonNodes.iterator().next();
+                               if (taxonNode != null) {
+                                       for (int i = 0; i < level; i++) {
+                                               if (taxonNode != null) {
+                                                       taxonNode  = taxonNode.getParent();
+                                               }
+                                       }
+                                       parentNode = taxonNode;
+                               }
+                       } else if (taxonNodes.size() > 1) {
+                               logger.error("This taxon has " + taxonNodes.size() + " taxonNodes: " + taxon.getUuid() + " (" + taxon.getTitleCache() + ")");
+                       }
+               }
+               //compare
+               if (parentNode != null) {
+                       TaxonNode node = CdmBase.deproxy(parentNode, TaxonNode.class);
+                       Taxon parentTaxon = node.getTaxon();
+                       if (parentTaxon != null) {
+                               TaxonName parentTaxonName = parentTaxon.getName();
+                               if (parentTaxonName != null && parentTaxonName.getRank().equals(ancestorRank)) {
+                                       result = true;
+                               }
+                       } else if (parentNode.treeIndex().matches("#t\\d+#\\d+#")) {
+                               //do nothing (is root node)
+                       } else {
+                               logger.error("This TaxonNode has no Taxon: " + node.getUuid());
+                       }
+               }
+               return result;
+       }
+
+       /**
+        * Returns the AnnotationType for a given UUID.
+        * @param uuid The Annotation UUID.
+        * @param label The Annotation label.
+        * @param text The Annotation text.
+        * @param labelAbbrev The Annotation label abbreviation.
+        * @return The AnnotationType.
+        */
+       protected AnnotationType getAnnotationType(UUID uuid, String label, String text, String labelAbbrev){
+               AnnotationType annotationType = (AnnotationType)getTermService().find(uuid);
+               if (annotationType == null) {
+                       annotationType = AnnotationType.NewInstance(label, text, labelAbbrev);
+                       annotationType.setUuid(uuid);
+//                     annotationType.setVocabulary(AnnotationType.EDITORIAL().getVocabulary());
+                       getTermService().save(annotationType);
+               }
+               return annotationType;
+       }
+
+       private boolean invokeParentTaxonFk(Integer parentId, Integer childId) {
+               try {
+                       parentTaxonFkStmt.setInt(1, parentId);
+                       parentTaxonFkStmt.setInt(2, childId);
+                       parentTaxonFkStmt.executeUpdate();
+                       return true;
+               } catch (SQLException e) {
+                       logger.warn("ParentTaxonFk (" + (parentId ==null? "-":parentId) + ") could not be inserted into database "
+                               + "for taxon "+ (childId == null? "-" :childId) + ": " + e.getMessage());
+                       e.printStackTrace();
+                       return false;
+               }
+       }
+
+
+       /**
+        * Inserts Rank data and KingdomFk into the Taxon database table.
+        * @param taxonName The {@link TaxonNameBase TaxonName}.
+        * @param nomenclaturalCode The {@link NomenclaturalCode NomenclaturalCode}.
+        * @param taxonFk The TaxonFk to store the values for.
+        * @param state
+        * @param kindomFk The KingdomFk.
+        * @return Whether save was successful or not.
+        */
+       private boolean invokeRankDataAndKingdomFk(TaxonName taxonName,
+               Integer taxonFk, Integer kingdomFk, PesiExportState state) {
+
+           try {
+                       Integer rankFk = getRankFk(taxonName, kingdomFk);
+                       if (rankFk != null) {
+                               rankUpdateStmt.setInt(1, rankFk);
+                       } else {
+                               rankUpdateStmt.setObject(1, null);
+                       }
+
+                       String rankCache = getRankCache(taxonName, kingdomFk, state);
+                       if (rankCache != null) {
+                               rankUpdateStmt.setString(2, rankCache);
+                       } else {
+                               rankUpdateStmt.setObject(2, null);
+                       }
+
+                       if (kingdomFk != null) {
+
+                               rankUpdateStmt.setInt(3, kingdomFk);
+                       } else {
+                               rankUpdateStmt.setObject(3, null);
+                       }
+
+                       if (taxonFk != null) {
+                               rankUpdateStmt.setInt(4, taxonFk);
+                       } else {
+                               rankUpdateStmt.setObject(4, null);
+                       }
+
+                       rankUpdateStmt.executeUpdate();
+                       return true;
+               } catch (SQLException e) {
+                       logger.error("Data (RankFk, RankCache, KingdomFk) could not be inserted into database: " + e.getMessage());
+                       e.printStackTrace();
+                       return false;
+               }
+       }
+
+       /**
+        * Inserts Rank data, TypeNameFk, KingdomFk, expertFk and speciesExpertFk into the Taxon database table.
+        * @param taxonName The {@link TaxonNameBase TaxonName}.
+        * @param nomenclaturalCode The {@link NomenclaturalCode NomenclaturalCode}.
+        * @param taxonFk The TaxonFk to store the values for.
+        * @param typeNameFk The TypeNameFk.
+        * @param rankFk
+        * @param state
+        * @param kindomFk The KingdomFk.
+        * @param expertFk The ExpertFk.
+        * @param speciesExpertFk The SpeciesExpertFk.
+        * @return Whether save was successful or not.
+        */
+       private boolean invokeRankDataAndTypeNameFkAndKingdomFk(TaxonName taxonName,
+                       Integer taxonFk, Integer typeNameFk, Integer kingdomFk, Integer rankFk, PesiExportState state) {
+
+           try {
+                       int index = 1;
+                       if (rankFk != null) {
+                               rankTypeExpertsUpdateStmt.setInt(index++, rankFk);
+                       } else {
+                               rankTypeExpertsUpdateStmt.setObject(index++, null);
+                       }
+
+                       String rankCache = getRankCache(taxonName, kingdomFk, state);
+                       if (rankCache != null) {
+                               rankTypeExpertsUpdateStmt.setString(index++, rankCache);
+                       } else {
+                               rankTypeExpertsUpdateStmt.setObject(index++, null);
+                       }
+
+                       if (typeNameFk != null) {
+                               rankTypeExpertsUpdateStmt.setInt(index++, typeNameFk);
+                       } else {
+                               rankTypeExpertsUpdateStmt.setObject(index++, null);
+                       }
+
+                       if (kingdomFk != null) {
+                               rankTypeExpertsUpdateStmt.setInt(index++, kingdomFk);
+                       } else {
+                               rankTypeExpertsUpdateStmt.setObject(index++, null);
+                       }
+
+//                     if (expertFk != null) {
+//                             rankTypeExpertsUpdateStmt.setInt(5, expertFk);
+//                     } else {
+//                             rankTypeExpertsUpdateStmt.setObject(5, null);
+//                     }
+//
+//                     //TODO handle experts GUIDS
+//                     if (speciesExpertFk != null) {
+//                             rankTypeExpertsUpdateStmt.setInt(6, speciesExpertFk);
+//                     } else {
+//                             rankTypeExpertsUpdateStmt.setObject(6, null);
+//                     }
+//
+                       if (taxonFk != null) {
+                               rankTypeExpertsUpdateStmt.setInt(index++, taxonFk);
+                       } else {
+                               rankTypeExpertsUpdateStmt.setObject(index++, null);
+                       }
+
+                       rankTypeExpertsUpdateStmt.executeUpdate();
+                       return true;
+               } catch (SQLException e) {
+                   String name = taxonName == null? null:taxonName.getTitleCache();
+                       logger.error("Data could not be inserted into database: " + e.getMessage() + "; rankFk = " + rankFk + "; kingdomFk = " + kingdomFk  + "; taxonFk = "+ taxonFk  + "; typeNameFk = "  + typeNameFk + "; name = " + name);
+                       e.printStackTrace();
+                       return false;
+               } catch (Exception e) {
+                   String name = taxonName == null? null:taxonName.getTitleCache();
+            logger.error("Some exception occurred: " + e.getMessage() + "; rankFk = " + rankFk + "; kingdomFk = " + kingdomFk  + "; taxonFk = "+ taxonFk + "; typeNameFk = " + typeNameFk + "; name = " + name);
+                       e.printStackTrace();
+                       return false;
+               }
+       }
+
+       /**
+        * Deletes all entries of database tables related to <code>Taxon</code>.
+        * @param state The {@link PesiExportState PesiExportState}.
+        * @return Whether the delete operation was successful or not.
+        */
+       protected boolean doDelete(PesiExportState state) {
+
+               Source destination =  state.getConfig().getDestination();
+
+               String[] tables = new String[]{"AdditionalTaxonSource","CommonNameSource","CommonName",
+                       "Image","NoteSource","Note","OccurrenceSource","Occurrence","RelTaxon","Taxon"};
+
+               for(String table : tables){
+                   String sql = "DELETE FROM " + table;
+                   destination.update(sql);
+               }
+
+               return true;
+       }
+
+       private static Integer getRankFk(TaxonName taxonName, NomenclaturalCode nomenclaturalCode) {
+           Integer kingdomId = PesiTransformer.nomenclaturalCode2Kingdom(nomenclaturalCode);
+           return getRankFk(taxonName, kingdomId);
+       }
+
+       /**
+        * Returns the <code>RankFk</code> attribute.
+        * @param taxonName The {@link TaxonNameBase TaxonName}.
+        * @param nomenclaturalCode The {@link NomenclaturalCode NomenclaturalCode}.
+        * @return The <code>RankFk</code> attribute.
+        * @see MethodMapper
+        */
+       private static Integer getRankFk(TaxonName taxonName, Integer kingdomId) {
+               Integer result = null;
+               try {
+                       if (taxonName != null) {
+                               if (taxonName.getRank() == null) {
+                                       logger.warn("Rank is null: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
+                               } else {
+                                       result = PesiTransformer.rank2RankId(taxonName.getRank(), kingdomId);
+                               }
+                               if (result == null) {
+                                       logger.warn("Rank could not be determined for PESI-Kingdom-Id " + kingdomId + " and TaxonName " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
+                               }
+                       }
+               } catch (Exception e) {
+                       e.printStackTrace();
+               }
+               return result;
+       }
+
+       @SuppressWarnings("unused")  //used by mapper
+    private static String getRankCache(TaxonName taxonName, PesiExportState state) {
+           List<TaxonNode> nodes = getTaxonNodes(taxonName);
+           Integer kingdomId;
+           if (nodes == null||nodes.isEmpty()){
+               kingdomId = getKingdomFk(taxonName);
+           }else{
+               //should not happen, method exists only pure names
+               kingdomId = findKingdomIdFromTreeIndex(nodes.iterator().next().getTaxon(), state);
+           }
+        return getRankCache(taxonName, kingdomId, state);
+       }
+
+       private static String getRankCache(TaxonName taxonName, Integer kingdomFk, PesiExportState state) {
+           if (Rank.DOMAIN().equals(taxonName.getRank())){
+            return state.getTransformer().getCacheByRankAndKingdom(Rank.DOMAIN(), null);
+        }else if (kingdomFk != null) {
+            return state.getTransformer().getCacheByRankAndKingdom(taxonName.getRank(), kingdomFk);
+        }else if (taxonName.getNameType() != null){
+            return state.getTransformer().getCacheByRankAndKingdom(taxonName.getRank(), PesiTransformer.nomenclaturalCode2Kingdom(taxonName.getNameType()));
+        }else{
+                       logger.warn("No kingdom ID could be defined for name " + taxonName.getUuid());
+                       return null;
+               }
+       }
+
+    private static List<TaxonNode> getTaxonNodes(TaxonName taxonName) {
+        List<TaxonNode> result = new ArrayList<>();
+        for (TaxonBase<?> tb:taxonName.getTaxonBases()){
+            Taxon taxon;
+            //TODO handle ERMS taxon relationships
+            if (tb.isInstanceOf(Taxon.class)){
+                taxon = CdmBase.deproxy(tb, Taxon.class);
+            }else{
+                taxon = CdmBase.deproxy(tb, Synonym.class).getAcceptedTaxon();
+            }
+            if (isPesiTaxon(taxon)){
+                for (TaxonNode node : taxon.getTaxonNodes()){
+                    result.add(node);
+                }
+            }
+        }
+        return result;
+    }
+
+//    @SuppressWarnings("unused")  //used by pure name mapper and by getRankFk
+    private static Integer getKingdomFk(TaxonName taxonName){
+        EnumSet<PesiSource> origin = getSources(taxonName);
+        if (origin.size() == 1 && origin.contains(PesiSource.EM)){
+            //maybe simply replace by
+            //return PesiTransformer.KINGDOM_PLANTAE;
+            return PesiTransformer.nomenclaturalCode2Kingdom(taxonName.getNameType());
+        }else{
+            logger.warn("getKingdomFk not yet implemented for non-EuroMed pure names");
+            return null;
+        }
+    }
+
+    /**
+     * Returns the rankFk for the taxon name based on the names nomenclatural code.
+     * You may not use this method for kingdoms other then Animalia, Plantae and Bacteria.
+     */
+    @SuppressWarnings("unused")  //used by pure name mapper
+    private static Integer getRankFk(TaxonName taxonName) {
+        EnumSet<PesiSource> origin = getSources(taxonName);
+        if (origin.size() == 1 && origin.contains(PesiSource.EM)){
+            return getRankFk(taxonName, getKingdomFk(taxonName));
+        }else{
+            logger.warn("getRankFk not yet implemented for non-EuroMed pure names");
+            return null;
+        }
+    }
+
+       /**
+        * Returns the <code>AuthorString</code> attribute.
+        * @param taxonName The {@link TaxonNameBase TaxonName}.
+        * @return The <code>AuthorString</code> attribute.
+        * @see MethodMapper
+        */
+       //used by mapper
+       protected static String getAuthorString(TaxonBase<?> taxon) {
+               try {
+                   // For misapplied names there are special rules
+            if (isMisappliedName(taxon)){
+                return getMisappliedNameAuthorship(taxon);
+            }else{
+                boolean isNonViralName = false;
+                String authorshipCache = null;
+                TaxonName taxonName = taxon.getName();
+                if (taxonName != null && taxonName.isNonViral()){
+                    authorshipCache = taxonName.getAuthorshipCache();
+                    isNonViralName = true;
+                }
+                String result = authorshipCache;
+
+                if (taxonName == null){
+                    logger.warn("TaxonName does not exist for taxon: " + taxon.getUuid() + " (" + taxon.getTitleCache() + ")");
+                }else if (! isNonViralName){
+                    logger.warn("TaxonName is not of instance NonViralName: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
+                }
+
+                if (StringUtils.isBlank(result)) {
+                    return null;
+                } else {
+                    return result;
+                }
+            }
+               } catch (Exception e) {
+                       e.printStackTrace();
+                       return null;
+               }
+       }
+
+       private static String getMisappliedNameAuthorship(TaxonBase<?> taxon){
+        String result;
+           String relAppendedPhrase = taxon.getAppendedPhrase();
+        Reference sec = taxon.getSec();
+        String secTitle = sec != null ? sec.getTitleCache(): null;
+        if(relAppendedPhrase == null && sec == null) {
+            result = "auct.";
+        }else if (relAppendedPhrase != null && sec == null){
+            result = relAppendedPhrase;
+        }else if (relAppendedPhrase == null && sec != null){
+            result = "sensu " + secTitle;
+        }else{  //append!=null && sec!=null
+            result = relAppendedPhrase + " " + secTitle;
+        }
+        String authorship = taxon.getName().getAuthorshipCache();
+        if (isNotBlank(authorship)){
+            result += ", non " + authorship;
+        }
+        return result;
+       }
+
+    /**
+     * Returns the <code>DisplayName</code> attribute.
+     * @param taxon The {@link TaxonBase Taxon}.
+     * @return The <code>DisplayName</code> attribute.
+     * @see MethodMapper
+     */
+    //used by Mapper
+    private static String getDisplayName(TaxonBase<?> taxon) {
+        boolean isMisapplied = isMisappliedName(taxon);
+        TaxonName taxonName = taxon.getName();
+        String result = getDisplayName(taxonName, isMisapplied);
+        if (isMisapplied){
+            result = result + " " + getMisappliedNameAuthorship(taxon);
+        }
+        return result;
+    }
+
+    /**
+     * Returns the <code>DisplayName</code> attribute.
+     * @param taxonName The {@link TaxonNameBase TaxonName}.
+     * @return The <code>DisplayName</code> attribute.
+     * @see MethodMapper
+     */
+    @SuppressWarnings("unused")  //used by Mapper
+    private static String getDisplayName(TaxonName taxonName) {
+        return getDisplayName(taxonName, false);
+    }
+
+       private static String getDisplayName(TaxonName taxonName, boolean useNameCache) {
+               if (taxonName == null) {
+                       return null;
+               }else{
+                   taxonName = CdmBase.deproxy(taxonName);
+                       INonViralNameCacheStrategy cacheStrategy = getCacheStrategy(taxonName);
+                       HTMLTagRules tagRules = new HTMLTagRules().
+                                       addRule(TagEnum.name, "i").
+                                       addRule(TagEnum.nomStatus, "@status@");
+
+                       String result;
+                       if (useNameCache){
+                result = cacheStrategy.getNameCache(taxonName, tagRules);
+                       }else{
+                           EnumSet<PesiSource> sources = getSources(taxonName);
+                           if (sources.contains(PesiSource.ERMS)){
+                               result = cacheStrategy.getTitleCache(taxonName, tagRules);  //according to SQL script (also in ERMS sources are not abbreviated)
+                           }else if (sources.contains(PesiSource.FE) || sources.contains(PesiSource.IF)){
+                               //TODO define for FE + IF and for multiple sources
+                               result = cacheStrategy.getFullTitleCache(taxonName, tagRules);
+                           }else if (sources.contains(PesiSource.EM)){
+                               result = cacheStrategy.getFullTitleCache(taxonName, tagRules);
+                           }else{
+                               logger.warn("Source not yet handled");
+                               result = cacheStrategy.getTitleCache(taxonName, tagRules);
+                           }
+                           result = replaceTagForInfraSpecificMarkerForProtectedTitleCache(taxonName, result);
+                           result = result.replaceAll("(, ?)?\\<@status@\\>.*\\</@status@\\>", "").trim();
+                       }
+            return result;
+               }
+       }
+
+       /**
+        * Returns the <code>WebShowName</code> attribute for a taxon.
+        * See {@link #getWebShowName(TaxonName)} for further explanations.
+        * @param taxon The {@link TaxonBase taxon}.
+        * @return The <code>WebShowName</code> attribute.
+        * @see #getWebShowName(TaxonName)
+        * @see #getDisplayName(TaxonBase)
+        * @see #getFullName(TaxonBase)
+        * @see MethodMapper
+       */
+       @SuppressWarnings("unused")
+       private static String getWebShowName(TaxonBase<?> taxon) {
+           if (isMisappliedName(taxon)){
+               //for misapplications the webshowname is the same as the displayname as they do not show the nom.ref. in displayname
+               return getDisplayName(taxon);
+           }else{
+               TaxonName taxonName = taxon.getName();
+               return getWebShowName(taxonName);
+           }
+       }
+
+       /**
+        * Returns the <code>WebShowName</code> attribute for a name. The
+        * <code>WebShowName</code> is like fullName but with
+        * tagged (<i>) name part. It is also similar to
+        * <code>DisplayName</code> but for titleCache not fullTitleCache.
+        * For misapplications it slightly differs (see {@link #getWebShowName(TaxonBase)} )
+        *
+        * @param taxonName The {@link TaxonNameBase TaxonName}.
+        * @return The <code>WebShowName</code> attribute.
+        * @see #getDisplayName(TaxonName)
+        * @see #getFullName(TaxonName)
+        * @see #getWebShowName(TaxonBase)
+        * @see MethodMapper
+        */
+       private static String getWebShowName(TaxonName taxonName) {
+               if (taxonName == null) {
+                       return null;
+               }else{
+                   taxonName = CdmBase.deproxy(taxonName);
+            INonViralNameCacheStrategy cacheStrategy = getCacheStrategy(taxonName);
+
+                       HTMLTagRules tagRules = new HTMLTagRules().addRule(TagEnum.name, "i");
+                       String result = cacheStrategy.getTitleCache(taxonName, tagRules);
+                       result = replaceTagForInfraSpecificMarkerForProtectedTitleCache(taxonName, result);
+                       return result;
+               }
+       }
+
+    private static String replaceTagForInfraSpecificMarkerForProtectedTitleCache(TaxonName taxonName, String result) {
+        if (taxonName.isProtectedTitleCache()||taxonName.isProtectedNameCache()){
+            if (!taxonName.isAutonym()){
+                result = result
+                        .replace(" subsp. ", "</i> subsp. <i>")
+                        .replace(" var. ", "</i> var. <i>")
+                        .replace(" subvar. ", "</i> subvar. <i>")
+                        .replace(" f. ", "</i> f. <i>")
+                        .replace(" subf. ", "</i> subf. <i>")  //does this exist?
+                        ;
+            }
+        }
+        return result;
+    }
+
+    /**
+        * Returns the <code>WebSearchName</code> attribute.
+        * @param taxonName The {@link NonViralName NonViralName}.
+        * @return The <code>WebSearchName</code> attribute.
+        * @see MethodMapper
+        */
+       @SuppressWarnings("unused")
+       private static String getWebSearchName(TaxonName taxonName) {
+               //TODO extensions?
+           TaxonNameDefaultCacheStrategy strategy = getCacheStrategy(taxonName);
+               String result = strategy.getNameCache(taxonName);
+               return result;
+       }
+
+    @SuppressWarnings("unused")     //used by mapper
+    private static String getFullName(TaxonBase<?> taxon) {
+        if (isMisappliedName(taxon)){
+            String result = getCacheStrategy(taxon.getName()).getNameCache(taxon.getName());
+            result = result + " " + getMisappliedNameAuthorship(taxon);
+            return result;
+        }else{
+            return getFullName(taxon.getName());
+        }
+    }
+
+       /**
+        * Returns the <code>FullName</code> attribute.
+        * @param taxonName The {@link NonViralName NonViralName}.
+        * @return The <code>FullName</code> attribute.
+        * @see MethodMapper
+        */
+    //used by mapper
+       private static String getFullName(TaxonName taxonName) {
+               //TODO extensions?
+               String result = getCacheStrategy(taxonName).getTitleCache(taxonName);
+               //misapplied names are now handled differently in getFullName(TaxonBase)
+//             Iterator<Taxon> taxa = taxonName.getTaxa().iterator();
+//             if (taxonName.getTaxa().size() >0){
+//                     if (taxonName.getTaxa().size() == 1){
+//                             Taxon taxon = taxa.next();
+//                             if (isMisappliedName(taxon)){
+//                                     result = result + " " + getAuthorString(taxon);
+//                             }
+//                     }
+//             }
+               return result;
+       }
+
+    @SuppressWarnings("unused")
+    private static String getGUID(TaxonName taxonName) {
+        UUID uuid = taxonName.getUuid();
+        String result = "NameUUID:" + uuid.toString();
+        return result;
+    }
+
+    static boolean isFirstAbbrevTitle = true;
+       /**
+        * Returns the SourceNameCache for the AdditionalSource table
+        */
+       @SuppressWarnings("unused")
+       private static String getSourceNameCache(TaxonName taxonName) {
+               if (taxonName != null){
+                       Reference nomRef = taxonName.getNomenclaturalReference();
+                       if (nomRef != null ){
+                           if (isFirstAbbrevTitle){
+                               //#5388 is definetely not the correct ticket number
+                               logger.warn("Semantics of getAbbrevTitleCache has changed. Please check if output is still correct. See #5388");
+                               isFirstAbbrevTitle = false;
+                           }
+                           return nomRef.getAbbrevTitleCache();
+                       }
+               }
+               return null;
+       }
+
+       /**
+        * Returns the nomenclatural reference which is the reference
+        * including the detail (microreference).
+        * @param taxonName The {@link TaxonName taxon name}.
+        * @see MethodMapper
+        */
+       @SuppressWarnings("unused")
+       private static String getNomRefString(TaxonName taxonName) {
+               INomenclaturalReference ref = taxonName.getNomenclaturalReference();
+               if (ref == null){
+                       return null;
+               }
+               String result = null;
+               EnumSet<PesiSource> sources = getSources(taxonName);
+               if(sources.contains(PesiSource.EM)){
+                   if (! ref.isProtectedAbbrevTitleCache()){
+                       ref.setAbbrevTitleCache(null, false);  //to remove a false cache
+                   }
+                   result = ref.getNomenclaturalCitation(taxonName.getNomenclaturalMicroReference());
+               }else if(sources.contains(PesiSource.FE)||sources.contains(PesiSource.IF) ){
+            //TODO still need to check if correct for FE + IF
+                   if (! ref.isProtectedAbbrevTitleCache()){
+                ref.setAbbrevTitleCache(null, false);  //to remove a false cache
+            }
+            result = ref.getNomenclaturalCitation(taxonName.getNomenclaturalMicroReference());
+            return result;   // according to SQL script
+               }else if(sources.contains(PesiSource.ERMS)) {
+            //result = null; //according to SQL script
+               }else{
+                   logger.warn("Source not yet supported");
+               }
+               return result;
+       }
+
+       /**
+        * Returns the <code>NameStatusFk</code> attribute.
+        * @param taxonName The {@link TaxonNameBase TaxonName}.
+        * @return The <code>NameStatusFk</code> attribute.
+        * @see MethodMapper
+        */
+       @SuppressWarnings("unused")
+       private static Integer getNameStatusFk(TaxonName taxonName) {
+               Integer result = null;
+
+               NomenclaturalStatus status = getNameStatus(taxonName);
+               if (status != null) {
+                       result = PesiTransformer.nomStatus2nomStatusFk(status.getType());
+               }
+               return result;
+       }
+
+       /**
+        * Returns the <code>NameStatusCache</code> attribute.
+        * @param taxonName The {@link TaxonNameBase TaxonName}.
+        * @return The <code>NameStatusCache</code> attribute.
+        * @throws UndefinedTransformerMethodException
+        * @see MethodMapper
+        */
+       @SuppressWarnings("unused")
+       private static String getNameStatusCache(TaxonName taxonName, PesiExportState state) throws UndefinedTransformerMethodException {
+               String result = null;
+               NomenclaturalStatus status = getNameStatus(taxonName);
+               if (status != null) {
+                       result = state.getTransformer().getCacheByNomStatus(status.getType());
+               }
+               return result;
+       }
+
+       private static NomenclaturalStatus getNameStatus(TaxonName taxonName) {
+               try {
+                       if (taxonName != null) {
+                           Set<NomenclaturalStatus> states = taxonName.getStatus();
+                               if (states.size() >= 1) {
+                                   if (states.size() > 1) {
+                                       String statusStr = null;
+                                       for (NomenclaturalStatus status: states){
+                                           statusStr = CdmUtils.concat(",", statusStr, status.getType()== null? null:status.getType().getTitleCache());
+                                       }
+                                       //a known case is ad43508a-8a10-480a-8519-2a76de2c0a0f (Labiatae Juss.) from E+M
+                           logger.warn("This TaxonName has more than one nomenclatural status. This may happen in very rare cases but is not handled by the PESI data warehouse. Taxon name: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")Status:" + statusStr);
+                       }
+                                   NomenclaturalStatus status = states.iterator().next();
+                                       return status;
+                               }
+                       }
+               } catch (Exception e) {
+                       e.printStackTrace();
+               }
+               return null;
+       }
+
+       /**
+        * Returns the <code>TaxonStatusFk</code> attribute.
+        * @param taxonName The {@link TaxonNameBase TaxonName}.
+        * @param state The {@link PesiExportState PesiExportState}.
+        * @return The <code>TaxonStatusFk</code> attribute.
+        * @see MethodMapper
+        */
+       private static Integer getTaxonStatusFk(TaxonBase<?> taxon, PesiExportState state) {
+               try {
+                       return PesiTransformer.taxonBase2statusFk(taxon);
+               } catch (Exception e) {
+                       e.printStackTrace();
+                       return null;
+               }
+       }
+
+       /**
+        * Returns the <code>TaxonStatusCache</code> attribute.
+        * @param taxonName The {@link TaxonNameBase TaxonName}.
+        * @param state The {@link PesiExportState PesiExportState}.
+        * @return The <code>TaxonStatusCache</code> attribute.
+        * @throws UndefinedTransformerMethodException
+        * @see MethodMapper
+        */
+       @SuppressWarnings("unused")
+       private static String getTaxonStatusCache(TaxonBase<?> taxon, PesiExportState state) throws UndefinedTransformerMethodException {
+               return state.getTransformer().getTaxonStatusCacheByKey(getTaxonStatusFk(taxon, state));
+       }
+
+    /**
+     * Returns the <code>TaxonFk1</code> attribute. It corresponds to a CDM <code>TaxonRelationship</code>.
+     * @param relationship The {@link RelationshipBase Relationship}.
+     * @param state The {@link PesiExportState PesiExportState}.
+     * @return The <code>TaxonFk1</code> attribute.
+     * @see MethodMapper
+     */
+    @SuppressWarnings("unused")
+    private static Integer getSynonym(Synonym synonym, PesiExportState state) {
+         return state.getDbId(synonym);
+    }
+
+       /**
+        * Returns the <code>TypeNameFk</code> attribute.
+        * @param taxonName The {@link TaxonNameBase TaxonName}.
+        * @param state The {@link PesiExportState PesiExportState}.
+        * @return The <code>TypeNameFk</code> attribute.
+        * @see MethodMapper
+        */
+       private static Integer getTypeNameFk(TaxonName taxonName, PesiExportState state) {
+               Integer result = null;
+               if (taxonName != null) {
+                       Set<NameTypeDesignation> nameTypeDesignations = taxonName.getNameTypeDesignations();
+                       if (nameTypeDesignations.size() == 1) {
+                               NameTypeDesignation nameTypeDesignation = nameTypeDesignations.iterator().next();
+                               if (nameTypeDesignation != null) {
+                                       TaxonName typeName = nameTypeDesignation.getTypeName();
+                                       if (typeName != null) {
+                                           if (typeName.getTaxonBases().isEmpty()){
+                                               logger.warn("Type name does not belong to a taxon and therefore is not expected to be a European taxon. Type name not added. Type name: " + typeName.getTitleCache() + ", typified name: " + taxonName.getTitleCache());
+                                           }else{
+                                               result = state.getDbId(typeName);
+                                           }
+                                       }
+                               }
+                       } else if (nameTypeDesignations.size() > 1) {
+                               logger.warn("This TaxonName has " + nameTypeDesignations.size() + " NameTypeDesignations: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
+                       }
+               }
+               return result;
+       }
+
+       /**
+        * Returns the <code>TypeFullnameCache</code> attribute.
+        * @param taxonName The {@link TaxonNameBase TaxonName}.
+        * @return The <code>TypeFullnameCache</code> attribute.
+        * @see MethodMapper
+        */
+       @SuppressWarnings("unused")
+       private static String getTypeFullnameCache(TaxonName taxonName) {
+               String result = null;
+
+               try {
+               if (taxonName != null) {
+                       Set<NameTypeDesignation> nameTypeDesignations = taxonName.getNameTypeDesignations();
+                       if (nameTypeDesignations.size() == 1) {
+                               NameTypeDesignation nameTypeDesignation = nameTypeDesignations.iterator().next();
+                               if (nameTypeDesignation != null) {
+                                       TaxonName typeName = nameTypeDesignation.getTypeName();
+                                       if (typeName != null) {
+                                               result = typeName.getTitleCache();
+                                       }
+                               }
+                       } else if (nameTypeDesignations.size() > 1) {
+                               logger.warn("This TaxonName has " + nameTypeDesignations.size() + " NameTypeDesignations: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
+                       }
+               }
+               } catch (Exception e) {
+                       e.printStackTrace();
+               }
+               return result;
+       }
+
+
+       /**
+        * Returns the <code>QualityStatusFk</code> attribute.
+        * @param taxonName The {@link TaxonNameBase TaxonName}.
+        * @return The <code>QualityStatusFk</code> attribute.
+        * @see MethodMapper
+        */
+       private static Integer getQualityStatusFk(TaxonName taxonName) {
+           EnumSet<PesiSource> sources = getSources(taxonName);
+               return PesiTransformer.getQualityStatusKeyBySource(sources, taxonName);
+       }
+
+       /**
+        * Returns the <code>QualityStatusCache</code> attribute.
+        * @param taxonName The {@link TaxonNameBase TaxonName}.
+        * @return The <code>QualityStatusCache</code> attribute.
+        * @throws UndefinedTransformerMethodException
+        * @see MethodMapper
+        */
+       @SuppressWarnings("unused")
+       private static String getQualityStatusCache(TaxonName taxonName, PesiExportState state) throws UndefinedTransformerMethodException {
+               return state.getTransformer().getQualityStatusCacheByKey(getQualityStatusFk(taxonName));
+       }
+
+
+       /**
+        * Returns the <code>TypeDesignationStatusFk</code> attribute.
+        * @param taxonName The {@link TaxonNameBase TaxonName}.
+        * @return The <code>TypeDesignationStatusFk</code> attribute.
+        * @see MethodMapper
+        */
+       //TODO seems not to be used
+       private static Integer getTypeDesignationStatusFk(TaxonName taxonName) {
+               Integer result = null;
+
+               try {
+               if (taxonName != null) {
+                       Set<NameTypeDesignation> typeDesignations = taxonName.getNameTypeDesignations();
+                       if (typeDesignations.size() == 1) {
+                               Object obj = typeDesignations.iterator().next().getTypeStatus();
+                               NameTypeDesignationStatus designationStatus = CdmBase.deproxy(obj, NameTypeDesignationStatus.class);
+                               result = PesiTransformer.nameTypeDesignationStatus2TypeDesignationStatusId(designationStatus);
+                       } else if (typeDesignations.size() > 1) {
+                               logger.error("Found a TaxonName with more than one NameTypeDesignation: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
+                       }
+               }
+               } catch (Exception e) {
+                       e.printStackTrace();
+               }
+               return result;
+       }
+
+       /**
+        * Returns the <code>TypeDesignationStatusCache</code> attribute.
+        * @param taxonName The {@link TaxonNameBase TaxonName}.
+        * @return The <code>TypeDesignationStatusCache</code> attribute.
+        * @see MethodMapper
+        */
+       //TODO seems not to be used
+       private static String getTypeDesignationStatusCache(TaxonName taxonName) {
+               String result = null;
+
+               try {
+               if (taxonName != null) {
+                       Set<NameTypeDesignation> typeDesignations = taxonName.getNameTypeDesignations();
+                       if (typeDesignations.size() == 1) {
+                               Object obj = typeDesignations.iterator().next().getTypeStatus();
+                               NameTypeDesignationStatus designationStatus = CdmBase.deproxy(obj, NameTypeDesignationStatus.class);
+                               result = PesiTransformer.nameTypeDesignationStatus2TypeDesignationStatusCache(designationStatus);
+                       } else if (typeDesignations.size() > 1) {
+                               logger.error("Found a TaxonName with more than one NameTypeDesignation: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
+                       }
+               }
+               } catch (Exception e) {
+                       e.printStackTrace();
+               }
+               return result;
+       }
+
+       /**
+        * Returns the <code>FossilStatusFk</code> attribute.
+        * @param taxonName The {@link TaxonNameBase TaxonName}.
+        * @return The <code>FossilStatusFk</code> attribute.
+        * @see MethodMapper
+        */
+       @SuppressWarnings("unused")
+       private static Integer getFossilStatusFk(IdentifiableEntity<?> identEntity, PesiExportState state) {
+               Integer result = null;
+
+               Set<String> fossilStatuus = identEntity.getExtensions(ErmsTransformer.uuidExtFossilStatus);
+               if (fossilStatuus.size() == 0){
+                       return null;
+               }else if (fossilStatuus.size() > 1){
+                       logger.warn("More than 1 fossil status given for " +  identEntity.getTitleCache() + " " + identEntity.getUuid());
+               }
+               String fossilStatus = fossilStatuus.iterator().next();
+
+               int statusFk = state.getTransformer().fossilStatusCache2FossilStatusFk(fossilStatus);
+               return statusFk;
+       }
+
+       /**
+        * Returns the <code>FossilStatusCache</code> attribute.
+        * @param taxonName The {@link TaxonNameBase TaxonName}.
+        * @return The <code>FossilStatusCache</code> attribute.
+        * @see MethodMapper
+        */
+       @SuppressWarnings("unused")
+       private static String getFossilStatusCache(IdentifiableEntity<?> identEntity, PesiExportState state) {
+               String result = null;
+               Set<String> fossilStatuus = identEntity.getExtensions(ErmsTransformer.uuidExtFossilStatus);
+               if (fossilStatuus.size() == 0){
+                       return null;
+               }
+               for (String strFossilStatus : fossilStatuus){
+                       result = CdmUtils.concat(";", result, strFossilStatus);
+               }
+               return result;
+       }
+
+       /**
+        * Returns the <code>IdInSource</code> attribute.
+        * @param taxonName The {@link TaxonNameBase TaxonName}.
+        * @return The <code>IdInSource</code> attribute.
+        * @see MethodMapper
+        */
+       @SuppressWarnings("unused")
+       private static String getIdInSource(IdentifiableEntity<?> taxonName) {
+               String result = null;
+
+               try {
+                       Set<IdentifiableSource> sources = getPesiSources(taxonName);
+                       if (sources.size() > 1){
+                               logger.warn("There is > 1 Pesi source. This is not yet handled.");
+                       }
+                       if (sources.size() == 0){
+                               logger.warn("There is no Pesi source!" +taxonName.getUuid() + " (" + taxonName.getTitleCache() +")");
+                       }
+                       for (IdentifiableSource source : sources) {
+                               Reference ref = source.getCitation();
+                               UUID refUuid = ref.getUuid();
+                               String idInSource = source.getIdInSource();
+                               if (refUuid.equals(PesiTransformer.uuidSourceRefEuroMed)){
+                                       result = idInSource != null ? ("NameId: " + source.getIdInSource()) : null;
+                               }else if (refUuid.equals(PesiTransformer.uuidSourceRefFaunaEuropaea)){
+                                       result = idInSource != null ? ("TAX_ID: " + source.getIdInSource()) : null;
+                               }else if (refUuid.equals(PesiTransformer.uuidSourceRefErms)){
+                                       result = idInSource != null ? ("tu_id: " + source.getIdInSource()) : null;
+                               }else if (refUuid.equals(PesiTransformer.uuidSourceRefIndexFungorum)){  //Index Fungorum
+                                       result = idInSource != null ? ("if_id: " + source.getIdInSource()) : null;
+                               }else{
+                                       if (logger.isDebugEnabled()){logger.debug("Not a PESI source");}
+                               }
+
+                               String sourceIdNameSpace = source.getIdNamespace();
+                               if (sourceIdNameSpace != null) {
+                                       if (sourceIdNameSpace.equals(PesiTransformer.STR_NAMESPACE_NOMINAL_TAXON)) {
+                                               result =  idInSource != null ? ("Nominal Taxon from TAX_ID: " + source.getIdInSource()):null;
+                                       } else if (sourceIdNameSpace.equals(TaxonServiceImpl.INFERRED_EPITHET_NAMESPACE)) {
+                                               result =  idInSource != null ? ("Inferred epithet from TAX_ID: " + source.getIdInSource()) : null;
+                                       } else if (sourceIdNameSpace.equals(TaxonServiceImpl.INFERRED_GENUS_NAMESPACE)) {
+                                               result =  idInSource != null ? ("Inferred genus from TAX_ID: " + source.getIdInSource()):null;
+                                       } else if (sourceIdNameSpace.equals(TaxonServiceImpl.POTENTIAL_COMBINATION_NAMESPACE)) {
+                                               result =  idInSource != null ? ("Potential combination from TAX_ID: " + source.getIdInSource()):null;
+                                       }
+                               }
+                               if (result == null) {
+                                       logger.warn("IdInSource is NULL for this taxonName: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() +", sourceIdNameSpace: " + source.getIdNamespace()+")");
+                               }
+                       }
+               } catch (Exception e) {
+                       e.printStackTrace();
+                       logger.error("An error occurs while creating idInSource..." + taxonName.getUuid() + " (" + taxonName.getTitleCache()+ e.getMessage());
+               }
+
+               if (result == null) {
+                       logger.warn("IdInSource is NULL for this taxonName: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() +")");
+               }
+               return result;
+       }
+
+       /**
+        * Returns the idInSource for a given TaxonName only.
+        * @param taxonName The {@link TaxonNameBase TaxonName}.
+        * @return The idInSource.
+        */
+       private static String getIdInSourceOnly(IdentifiableEntity<?> identEntity) {
+               String result = null;
+
+               // Get the sources first
+               Set<IdentifiableSource> sources = getPesiSources(identEntity);
+
+               // Determine the idInSource
+               if (sources.size() == 1) {
+                       IdentifiableSource source = sources.iterator().next();
+                       if (source != null) {
+                               result = source.getIdInSource();
+                       }
+               } else if (sources.size() > 1) {
+                       int count = 1;
+                       result = "";
+                       for (IdentifiableSource source : sources) {
+                               result += source.getIdInSource();
+                               if (count < sources.size()) {
+                                       result += "; ";
+                               }
+                               count++;
+                       }
+
+               }
+
+               return result;
+       }
+
+       /**
+        * Returns the <code>GUID</code> attribute.
+        * @param taxonName The {@link TaxonNameBase TaxonName}.
+        * @return The <code>GUID</code> attribute.
+        * @see MethodMapper
+        */
+       private static String getGUID(TaxonBase<?> taxon) {
+               if (taxon.getLsid() != null ){
+                       return taxon.getLsid().getLsid();
+               }else if (taxon.hasMarker(PesiTransformer.uuidMarkerGuidIsMissing, true)){
+                       return null;
+               }else{
+                       return taxon.getUuid().toString();
+               }
+       }
+
+       /**
+        * Returns the <code>DerivedFromGuid</code> attribute.
+        * @param taxonName The {@link TaxonNameBase TaxonName}.
+        * @return The <code>DerivedFromGuid</code> attribute.
+        * @see MethodMapper
+        */
+       @SuppressWarnings("unused")
+       private static String getDerivedFromGuid(TaxonBase<?> taxon) {
+               String result = null;
+               try {
+               // The same as GUID for now
+               result = getGUID(taxon);
+               } catch (Exception e) {
+                       e.printStackTrace();
+               }
+               return result;
+       }
+
+       /**
+        * Returns the <code>CacheCitation</code> attribute.
+        * @param taxonName The {@link TaxonNameBase TaxonName}.
+        * @return The CacheCitation.
+        * @see MethodMapper
+        */
+       @SuppressWarnings("unused")
+       private static String getCacheCitation(TaxonBase<?> taxon) {
+               // !!! See also doPhaseUpdates
+
+               TaxonName taxonName = taxon.getName();
+               String result = "";
+               //TODO implement anew for taxa
+               try {
+                       EnumSet<PesiSource> sources = getSources(taxon);
+                       //TODO what if 2 sources? In PESI 2014 they were pipe separated
+                       //TODO why does ERMS use accessed through eu-nomen, while E+M uses accessed through E+M
+                       if (sources.isEmpty()) {
+//                             logger.error("OriginalDB is NULL for this TaxonName: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
+                       } else if (sources.contains(PesiSource.ERMS)) {
+                               //TODO check if correct, compare with PESI 2014
+                           Set<Extension> extensions = taxon.getExtensions();
+                               for (Extension extension : extensions) {
+                                       if (extension.getType().equals(cacheCitationExtensionType)) {
+                                               result = extension.getValue();
+                                       }
+                               }
+                       } else if (sources.contains(PesiSource.EM)) {
+                           //TODO
+                           boolean isMisapplied = isMisappliedName(taxon);
+                           boolean isProParteSyn = isProParteOrPartialSynonym(taxon);
+                           Reference sec = null;
+                           if(!isMisapplied && !isProParteSyn){
+                               sec = taxon.getSec();
+                           }else if (isMisapplied){
+                               sec = getAcceptedTaxonForMisappliedName(taxon).getSec();
+                           }else if (isProParteSyn){
+                    sec = getAcceptedTaxonForProParteSynonym(taxon).getSec();
+                }
+                           if (sec == null){
+                               logger.warn("Sec could not be defined for taxon " + taxon.getTitleCache()+ "; " + taxon.getUuid());
+                           }
+                           String author = sec == null? "" : sec.getTitleCache();
+                           String webShowName = isMisapplied? getDisplayName(taxon):getWebShowName(taxonName);  //for misapplied we need also the sensu and non author part, for ordinary names name + author is enough
+                           String accessed = ". Accessed through: Euro+Med PlantBase at https://www.europlusmed.org/cdm_dataportal/taxon/";
+                           result = CdmUtils.removeTrailingDot(author)
+                                   + ". " + CdmUtils.removeTrailingDot(webShowName)
+                                   + accessed + taxon.getUuid();
+                       } else {
+                               //TODO check for IF + FE
+
+                           String expertName = getExpertName(taxon);
+                               String webShowName = getWebShowName(taxonName);
+
+                               // idInSource only
+                               String idInSource = getIdInSourceOnly(taxonName);
+
+                               // build the cacheCitation
+                               if (expertName != null) {
+                                       result += expertName + ". ";
+                               } else {
+                                       if (logger.isDebugEnabled()){logger.debug("ExpertName could not be determined for this TaxonName: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");}
+                               }
+                               if (webShowName != null) {
+                                       result += webShowName + ". ";
+                               } else {
+                                       logger.warn("WebShowName could not be determined for this TaxonName: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
+                               }
+
+                               if (getOriginalDB(taxonName).equals("FaEu")) {
+                                       result += "Accessed through: Fauna Europaea at http://faunaeur.org/full_results.php?id=";
+                               } else if (getOriginalDB(taxonName).equals("EM")) {
+                                       result += "Accessed through: Euro+Med PlantBase at http://ww2.bgbm.org/euroPlusMed/PTaxonDetail.asp?UUID=";
+                               }
+
+                               if (idInSource != null) {
+                                       result += idInSource;
+                               } else {
+                                       logger.warn("IdInSource could not be determined for this TaxonName: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
+                               }
+                       }
+               } catch (Exception e) {
+                       e.printStackTrace();
+               }
+
+               if (StringUtils.isBlank(result)) {
+                       return null;
+               } else {
+                       return result;
+               }
+       }
+
+       /**
+        * Returns the <code>OriginalDB</code> attribute.
+        * @param identifiableEntity
+        * @return The <code>OriginalDB</code> attribute.
+        * @see MethodMapper
+        */
+//     @SuppressWarnings("unused")
+       private static String getOriginalDB(IdentifiableEntity<?> identifiableEntity) {
+               EnumSet<PesiSource> sources  = getSources(identifiableEntity);
+               return PesiTransformer.getOriginalDbBySources(sources);
+       }
+
+       /**
+        * Returns the <code>ExpertName</code> attribute.
+        * @param taxonName The {@link TaxonNameBase TaxonName}.
+        * @return The <code>ExpertName</code> attribute.
+        * @see MethodMapper
+        */
+       @SuppressWarnings("unused")  //for some reason it is also called by getCacheCitation
+       private static String getExpertName(TaxonBase<?> taxon) {
+               try {
+                   String result = null;
+               if(expertNameExtensionType!=null){  //some databases do not have this extension type
+                   Set<Extension> extensions = taxon.getExtensions();
+                   for (Extension extension : extensions) {
+                       if (extension.getType().equals(expertNameExtensionType)) {
+                           result = extension.getValue();
+                       }
+                   }
+               }
+               if (getPesiSources(taxon).contains(PesiSource.EM)){
+                return taxon.getSec().getTitleCache();
+            }
+            return null;
+               } catch (Exception e) {
+                       e.printStackTrace();
+                       return null;
+               }
+       }
+
+       //TODO change to ExpertGUID
+       private static Integer getExpertFk(Reference reference, PesiExportState state) {
+               Integer result = state.getDbId(reference);
+               return result;
+       }
+
+       /**
+        * Returns the <code>SpeciesExpertName</code> attribute.
+        * @param taxonName The {@link TaxonNameBase TaxonName}.
+        * @return The <code>SpeciesExpertName</code> attribute.
+        * @see MethodMapper
+        */
+       @SuppressWarnings("unused")
+       private static String getSpeciesExpertName(TaxonBase<?> taxon) {
+               try {
+               Set<Extension> extensions = taxon.getExtensions();
+               if(speciesExpertNameExtensionType != null){  //some databases do not have this extension type
+                for (Extension extension : extensions) {
+                               if (extension.getType().equals(speciesExpertNameExtensionType)) {
+                                       return extension.getValue();
+                               }
+                       }
+               }
+               if (getPesiSources(taxon).contains(PesiSource.EM)){
+                   return taxon.getSec().getTitleCache();
+            }
+               return null;
+               } catch (Exception e) {
+                       e.printStackTrace();
+                       return null;
+               }
+       }
+
+       /**
+        * Returns the <code>SpeciesExpertFk</code> attribute.
+        * @param reference The {@link Reference Reference}.
+        * @param state The {@link PesiExportState PesiExportState}.
+        * @return The <code>SpeciesExpertFk</code> attribute.
+        * @see MethodMapper
+        */
+       //TODO should be changed to SpeciesExpertGUID
+       private static Integer getSpeciesExpertFk(Reference reference, PesiExportState state) {
+               Integer result = state.getDbId(reference);
+               return result;
+       }
+
+       protected static TaxonNameDefaultCacheStrategy getCacheStrategy(TaxonName taxonName) {
+               taxonName = CdmBase.deproxy(taxonName);
+               TaxonNameDefaultCacheStrategy cacheStrategy;
+               if (taxonName.isZoological()){
+                       cacheStrategy = zooNameStrategy;
+               }else if (taxonName.isBotanical()) {
+                       cacheStrategy = nonViralNameStrategy;
+               }else if (taxonName.isNonViral()) {
+                       cacheStrategy = nonViralNameStrategy;
+               }else if (taxonName.isBacterial()) {
+                       cacheStrategy = nonViralNameStrategy;
+               }else{
+                       logger.error("Unhandled taxon name type. Can't define strategy class");
+                       cacheStrategy = nonViralNameStrategy;
+               }
+               return cacheStrategy;
+       }
+
+       /**
+        * Returns the <code>RelTaxonQualifierFk</code> attribute.
+        * @param relationship The {@link RelationshipBase Relationship}.
+        * @return The <code>RelTaxonQualifierFk</code> attribute.
+        * @see MethodMapper
+        */
+       @SuppressWarnings("unused")
+       private static Integer getRelTaxonQualifierFk(RelationshipBase<?, ?, ?> relationship) {
+               return PesiTransformer.taxonRelation2RelTaxonQualifierFk(relationship);
+       }
+
+    //TODO still in use?
+    private static String getSynonymTypeCache(Synonym synonym, PesiExportState state) {
+        String result = null;
+        NomenclaturalCode code = null;
+        code = CdmBase.deproxy(synonym, Synonym.class).getAcceptedTaxon().getName().getNameType();
+
+        if (code != null) {
+            result = state.getConfig().getTransformer().getCacheBySynonymType(synonym, code);
+        } else {
+            logger.error("NomenclaturalCode is NULL while creating the following synonym: " + synonym.getUuid());
+        }
+        return result;
+    }
+
+// ********************************** MAPPINGS ********************************/
+
+       /**
+        * Returns the CDM to PESI specific export mappings.
+        * @return The {@link PesiExportMapping PesiExportMapping}.
+        */
+       private PesiExportMapping getMapping() {
+               PesiExportMapping mapping = new PesiExportMapping(dbTableName);
+
+               mapping.addMapper(IdMapper.NewInstance("TaxonId"));
+               mapping.addMapper(DbObjectMapper.NewInstance("sec", "sourceFk")); //OLD:mapping.addMapper(MethodMapper.NewInstance("SourceFK", this.getClass(), "getSourceFk", standardMethodParameter, PesiExportState.class));
+               mapping.addMapper(MethodMapper.NewInstance("TaxonStatusFk", this.getClass(), "getTaxonStatusFk", standardMethodParameter, PesiExportState.class));
+               mapping.addMapper(MethodMapper.NewInstance("TaxonStatusCache", this.getClass(), "getTaxonStatusCache", standardMethodParameter, PesiExportState.class));
+
+               mapping.addMapper(MethodMapper.NewInstance("GUID", this));
+
+               mapping.addMapper(MethodMapper.NewInstance("DerivedFromGuid", this));
+               mapping.addMapper(MethodMapper.NewInstance("CacheCitation", this));
+               mapping.addMapper(MethodMapper.NewInstance("AuthorString", this));  //For Taxon because misapplied names are handled differently
+               mapping.addMapper(MethodMapper.NewInstance("FullName", this));    //For Taxon because misapplied names are handled differently
+               mapping.addMapper(MethodMapper.NewInstance("WebShowName", this));
+
+               // DisplayName
+               mapping.addMapper(MethodMapper.NewInstance("DisplayName", this));
+
+               // FossilStatus (Fk, Cache)
+               mapping.addMapper(MethodMapper.NewInstance("FossilStatusCache", this, IdentifiableEntity.class, PesiExportState.class));
+               mapping.addMapper(MethodMapper.NewInstance("FossilStatusFk", this, IdentifiableEntity.class, PesiExportState.class)); // PesiTransformer.FossilStatusCache2FossilStatusFk?
+
+               //handled by name mapping
+               mapping.addMapper(DbLastActionMapper.NewInstance("LastActionDate", false));
+               mapping.addMapper(DbLastActionMapper.NewInstance("LastAction", true));
+
+               //experts
+//             mapping.addMapper(DbExtensionMapper.NewInstance(extensionTypeSpeciesExpertName, "SpeciesExpertName"));
+               mapping.addMapper(MethodMapper.NewInstance("SpeciesExpertName", this, TaxonBase.class));
+//             ExtensionType extensionTypeExpertName = (ExtensionType)getTermService().find(PesiTransformer.uuidExtExpertName);
+//             mapping.addMapper(DbExtensionMapper.NewInstance(extensionTypeExpertName, "ExpertName"));
+               mapping.addMapper(MethodMapper.NewInstance("ExpertName", this, TaxonBase.class));
+
+               //ParentTaxonFk handled in Phase02 now
+               mapping.addMapper(ObjectChangeMapper.NewInstance(TaxonBase.class, TaxonName.class, "Name"));
+
+               addNameMappers(mapping);
+
+               return mapping;
+       }
+
+       /**
+        * Returns the CDM to PESI specific export mappings.
+        * @param state
+        * @return The {@link PesiExportMapping PesiExportMapping}.
+        * @throws UndefinedTransformerMethodException
+        */
+       private PesiExportMapping getPureNameMapping(PesiExportState state) throws UndefinedTransformerMethodException {
+               PesiExportMapping mapping = new PesiExportMapping(dbTableName);
+
+               mapping.addMapper(IdMapper.NewInstance("TaxonId"));
+
+               mapping.addMapper(MethodMapper.NewInstance("KingdomFk", this, TaxonName.class));
+               mapping.addMapper(MethodMapper.NewInstance("RankFk", this, TaxonName.class));
+               mapping.addMapper(MethodMapper.NewInstance("RankCache", this, TaxonName.class, PesiExportState.class));
+               mapping.addMapper(DbConstantMapper.NewInstance("TaxonStatusFk", Types.INTEGER, PesiTransformer.T_STATUS_UNACCEPTED));
+               mapping.addMapper(DbConstantMapper.NewInstance("TaxonStatusCache", Types.VARCHAR, state.getTransformer().getTaxonStatusCacheByKey( PesiTransformer.T_STATUS_UNACCEPTED)));
+               mapping.addMapper(DbStringMapper.NewInstance("AuthorshipCache", "AuthorString").setBlankToNull(true));
+               mapping.addMapper(MethodMapper.NewInstance("FullName", this, TaxonName.class));
+               mapping.addMapper(MethodMapper.NewInstance("WebShowName", this, TaxonName.class));
+               mapping.addMapper(MethodMapper.NewInstance("GUID", this, TaxonName.class));
+
+               // DisplayName
+               mapping.addMapper(MethodMapper.NewInstance("DisplayName", this, TaxonName.class));
+
+               mapping.addMapper(DbLastActionMapper.NewInstance("LastActionDate", false));
+               mapping.addMapper(DbLastActionMapper.NewInstance("LastAction", true));
+
+               addNameMappers(mapping);
+               return mapping;
+       }
+
+       private void addNameMappers(PesiExportMapping mapping) {
+
+           //epithets
+               mapping.addMapper(DbStringMapper.NewInstance("GenusOrUninomial", "GenusOrUninomial"));
+               mapping.addMapper(DbStringMapper.NewInstance("InfraGenericEpithet", "InfraGenericEpithet"));
+               mapping.addMapper(DbStringMapper.NewInstance("SpecificEpithet", "SpecificEpithet"));
+               mapping.addMapper(DbStringMapper.NewInstance("InfraSpecificEpithet", "InfraSpecificEpithet"));
+
+               //full name
+//             mapping.addMapper(DbStringMapper.NewInstance("NameCache", "WebSearchName"));  //does not work as we need other cache strategy
+               mapping.addMapper(MethodMapper.NewInstance("WebSearchName", this, TaxonName.class));
+
+               //nom ref
+               mapping.addMapper(MethodMapper.NewInstance("NomRefString", this, TaxonName.class));
+
+               //status
+               mapping.addMapper(MethodMapper.NewInstance("NameStatusFk", this, TaxonName.class));
+               mapping.addMapper(MethodMapper.NewInstance("NameStatusCache", this, TaxonName.class, PesiExportState.class));
+               mapping.addMapper(MethodMapper.NewInstance("QualityStatusFk", this, TaxonName.class));
+               mapping.addMapper(MethodMapper.NewInstance("QualityStatusCache", this, TaxonName.class, PesiExportState.class));
+
+               //types
+               mapping.addMapper(MethodMapper.NewInstance("TypeFullnameCache", this, TaxonName.class));
+               //TypeNameFk handled in Phase3
+
+               //supplemental
+               mapping.addMapper(MethodMapper.NewInstance("IdInSource", this, IdentifiableEntity.class));
+               mapping.addMapper(MethodMapper.NewInstance("OriginalDB", this, IdentifiableEntity.class) );
+
+               //mapping.addMapper(ExpertsAndLastActionMapper.NewInstance());
+
+       }
+
+       private PesiExportMapping getSynRelMapping() {
+               PesiExportMapping mapping = new PesiExportMapping(dbTableNameSynRel);
+               logger.warn("SynRelMapping currently not implemented. Needs to be checked");
+
+               mapping.addMapper(MethodMapper.NewInstance("TaxonFk1", this.getClass(), "getSynonym", Synonym.class, PesiExportState.class));
+               mapping.addMapper(DbObjectMapper.NewInstance("acceptedTaxon", "TaxonFk2"));
+               mapping.addMapper(DbObjectMapper.NewInstance("type", "RelTaxonQualifierFk"));
+               mapping.addMapper(MethodMapper.NewInstance("RelQualifierCache", this.getClass(), "getSynonymTypeCache", Synonym.class, PesiExportState.class));
+               // TODO
+//             mapping.addMapper(MethodMapper.NewInstance("Notes", this,  RelationshipBase.class));
+
+               return mapping;
+       }
+
+       private PesiExportMapping getAdditionalSourceMapping(PesiExportState state) {
+               PesiExportMapping mapping = new PesiExportMapping(dbTableAdditionalSourceRel);
+
+               mapping.addMapper(IdMapper.NewInstance("TaxonFk"));
+               mapping.addMapper(ObjectChangeMapper.NewInstance(TaxonBase.class, TaxonName.class, "Name"));
+
+               mapping.addMapper(DbObjectMapper.NewInstance("NomenclaturalReference", "SourceFk"));
+//             mapping.addMapper(DbObjectMapper.NewInstance("NomenclaturalReference", "SourceNameCache", IS_CACHE));
+               mapping.addMapper(MethodMapper.NewInstance("SourceNameCache", this, TaxonName.class));
+
+               //we have only nomenclatural references here
+               mapping.addMapper(DbConstantMapper.NewInstance("SourceUseFk", Types.INTEGER , PesiTransformer.NOMENCLATURAL_REFERENCE));
+               mapping.addMapper(DbConstantMapper.NewInstance("SourceUseCache", Types.VARCHAR, state.getTransformer().getSourceUseCacheByKey( PesiTransformer.NOMENCLATURAL_REFERENCE)));
+
+               mapping.addMapper(DbStringMapper.NewInstance("NomenclaturalMicroReference", "SourceDetail"));
+
+               return mapping;
+       }
+
+
+    @Override
+    protected boolean doCheck(PesiExportState state) {
+        return true;
+    }
+
+    @Override
+    protected boolean isIgnore(PesiExportState state) {
+        return ! state.getConfig().isDoTaxa();
+    }
+}