fix Original Source mix ERMS<->IF
[cdmlib-apps.git] / cdm-pesi / src / main / java / eu / etaxonomy / cdm / io / pesi / out / PesiTaxonExport.java
index e3ff3dc0688c697c36e9aeda7dead491530d8642..23dc78965fe61aab99d6b5caf1380efa6a9b574c 100644 (file)
@@ -13,7 +13,9 @@ import java.sql.Connection;
 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.List;\r
@@ -29,12 +31,12 @@ import org.springframework.stereotype.Component;
 import org.springframework.transaction.TransactionStatus;\r
 \r
 import eu.etaxonomy.cdm.api.service.TaxonServiceImpl;\r
-import eu.etaxonomy.cdm.app.pesi.ErmsActivator;\r
-import eu.etaxonomy.cdm.app.pesi.EuroMedActivator;\r
-import eu.etaxonomy.cdm.app.pesi.FaunaEuropaeaActivator;\r
 import eu.etaxonomy.cdm.common.CdmUtils;\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
@@ -58,6 +60,7 @@ import eu.etaxonomy.cdm.model.name.NonViralName;
 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
@@ -66,14 +69,11 @@ import eu.etaxonomy.cdm.model.taxon.TaxonBase;
 import eu.etaxonomy.cdm.model.taxon.TaxonNode;\r
 import eu.etaxonomy.cdm.model.taxon.TaxonRelationship;\r
 import eu.etaxonomy.cdm.model.taxon.TaxonRelationshipType;\r
-import eu.etaxonomy.cdm.persistence.query.MatchMode;\r
 import eu.etaxonomy.cdm.strategy.cache.HTMLTagRules;\r
 import eu.etaxonomy.cdm.strategy.cache.TagEnum;\r
-import eu.etaxonomy.cdm.strategy.cache.TaggedText;\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.ZooNameDefaultCacheStrategy;\r
 import eu.etaxonomy.cdm.strategy.cache.name.ZooNameNoMarkerCacheStrategy;\r
 \r
 /**\r
@@ -111,10 +111,8 @@ public class PesiTaxonExport extends PesiExportBase {
        private static ExtensionType expertNameExtensionType;\r
        private static ExtensionType speciesExpertNameExtensionType;\r
        private static ExtensionType cacheCitationExtensionType;\r
-       private static ExtensionType expertUserIdExtensionType;\r
-       private static ExtensionType speciesExpertUserIdExtensionType;\r
-       private static NonViralNameDefaultCacheStrategy zooNameStrategy = ZooNameNoMarkerCacheStrategy.NewInstance();\r
-       private static NonViralNameDefaultCacheStrategy botanicalNameStrategy = BotanicNameDefaultCacheStrategy.NewInstance();\r
+       private static NonViralNameDefaultCacheStrategy<?> zooNameStrategy = ZooNameNoMarkerCacheStrategy.NewInstance();\r
+       private static NonViralNameDefaultCacheStrategy<?> botanicalNameStrategy = BotanicNameDefaultCacheStrategy.NewInstance();\r
        \r
        \r
        /**\r
@@ -189,10 +187,6 @@ public class PesiTaxonExport extends PesiExportBase {
                        expertNameExtensionType = (ExtensionType)getTermService().find(PesiTransformer.expertNameUuid);\r
                        speciesExpertNameExtensionType = (ExtensionType)getTermService().find(PesiTransformer.speciesExpertNameUuid);\r
                        cacheCitationExtensionType = (ExtensionType)getTermService().find(PesiTransformer.cacheCitationUuid);\r
-                       expertUserIdExtensionType = (ExtensionType)getTermService().find(PesiTransformer.expertUserIdUuid);\r
-                       speciesExpertUserIdExtensionType = (ExtensionType)getTermService().find(PesiTransformer.speciesExpertUserIdUuid);\r
-\r
-\r
                        \r
                        //Export Taxa..\r
                        success &= doPhase01(state, mapping);\r
@@ -203,13 +197,17 @@ public class PesiTaxonExport extends PesiExportBase {
                        \r
                        // 2nd Round: Add ParentTaxonFk, TreeIndex to each Taxon\r
                        success &= doPhase02(state);\r
-\r
-                       //PHASE 3: Add Rank data, KingdomFk, TypeNameFk, expertFk and speciesExpertFk...\r
+                       \r
+                       //PHASE 3: Add Rank data, KingdomFk, TypeNameFk ...\r
                        success &= doPhase03(state);\r
                        \r
+                       \r
                        //"PHASE 4: Creating Inferred Synonyms...\r
                        success &= doPhase04(state, mapping);\r
                        \r
+                       //updates to TaxonStatus and others\r
+                       success &= doPhaseUpdates(state);\r
+\r
                        \r
                        logger.info("*** Finished Making " + pluralString + " ..." + getSuccessString(success));\r
 \r
@@ -225,6 +223,59 @@ public class PesiTaxonExport extends PesiExportBase {
                }\r
        }\r
 \r
+       //TODO check if this can all be done by getTaxonStatus\r
+       private boolean doPhaseUpdates(PesiExportState state) {\r
+               \r
+               \r
+               String oldStatusFilter = "= 7 ";  //"= '" + PesiTransformer.T_STATUS_STR_UNACCEPTED + "' ";\r
+               String emStr = PesiTransformer.SOURCE_STR_EM;\r
+               String feStr = PesiTransformer.SOURCE_STR_FE;\r
+               String ifStr = PesiTransformer.SOURCE_STR_IF;\r
+               \r
+               //NOT ACCEPTED names\r
+               String updateNotAccepted = " UPDATE Taxon SET TaxonStatusFk = %d, TaxonStatusCache = '%s' " +\r
+                               " WHERE OriginalDB = '%s' AND taxonstatusfk = 1 AND ParentTaxonFk %s AND RankFk > 180 ";\r
+               updateNotAccepted = String.format(updateNotAccepted, 8, "NOT ACCEPTED: TAXONOMICALLY VALUELESS LOCAL OR SINGULAR BIOTYPE", emStr, oldStatusFilter);\r
+               int updated = state.getConfig().getDestination().update(updateNotAccepted);\r
+               \r
+               //alternative names\r
+               String updateAlternativeName = "UPDATE Taxon SET TaxonStatusFk = 1, TaxonStatusCache = 'accepted' " + \r
+                               " FROM RelTaxon RIGHT OUTER JOIN Taxon ON RelTaxon.TaxonFk1 = Taxon.TaxonId " +\r
+                               " WHERE (RelTaxon.RelTaxonQualifierFk = 17) AND (Taxon.TaxonStatusFk %s) ";\r
+               updateAlternativeName = String.format(updateAlternativeName, oldStatusFilter);\r
+               updated = state.getConfig().getDestination().update(updateAlternativeName);\r
+               \r
+               String updateSynonyms = " UPDATE Taxon SET TaxonStatusFk = 2, TaxonStatusCache = 'synonym' " + \r
+                                       " FROM RelTaxon RIGHT OUTER JOIN Taxon ON RelTaxon.TaxonFk1 = Taxon.TaxonId " + \r
+                                       " WHERE (RelTaxon.RelTaxonQualifierFk in (1, 3)) AND (Taxon.TaxonStatusFk %S)";\r
+               updateSynonyms = String.format(updateSynonyms, oldStatusFilter);\r
+               updated = state.getConfig().getDestination().update(updateSynonyms);\r
+               \r
+               // cache citation  - check if this can't be done in getCacheCitation\r
+               // cache citation - FE\r
+//             String updateCacheCitationFE = " UPDATE Taxon " +\r
+//                             " SET CacheCitation = IsNull(SpeciesExpertName + '. ', '') + WebShowName + '. Accessed through: Fauna Europaea at http://www.faunaeur.org/full_results.php?id=' + cast(TempFE_Id as varchar) " +\r
+//                             " WHERE OriginalDb = '%s'";\r
+//             updateCacheCitationFE = String.format(updateCacheCitationFE, feStr);\r
+//             updated = state.getConfig().getDestination().update(updateCacheCitationFE);\r
+               \r
+               // cache citation - EM\r
+               String updateCacheCitationEM = " UPDATE Taxon " +\r
+                               " SET CacheCitation = SpeciesExpertName + ' ' + WebShowName + '. Accessed through: Euro+Med PlantBase at http://ww2.bgbm.org/euroPlusMed/PTaxonDetail.asp?UUID=' + GUID " +\r
+                               " WHERE OriginalDb = '%s'";\r
+               updateCacheCitationEM = String.format(updateCacheCitationEM, emStr);\r
+               updated = state.getConfig().getDestination().update(updateCacheCitationEM);\r
+               \r
+               // cache citation - IF\r
+//             String updateCacheCitationIF = " UPDATE Taxon " +\r
+//                             " SET CacheCitation = IsNull(SpeciesExpertName + ' ', '') + WebShowName + '. Accessed through: Index Fungorum at http://www.indexfungorum.org/names/NamesRecord.asp?RecordID=' + cast(TempIF_Id as varchar) " +\r
+//                             " WHERE OriginalDb = '%s'";\r
+//             updateCacheCitationIF = String.format(updateCacheCitationIF, ifStr);\r
+//             updated = state.getConfig().getDestination().update(updateCacheCitationIF);\r
+               \r
+               return true;\r
+       }\r
+\r
        private void initPreparedStatements(PesiExportState state) throws SQLException {\r
                initTreeIndexStatement(state);\r
                initRankExpertsUpdateStmt(state);\r
@@ -271,7 +322,7 @@ public class PesiTaxonExport extends PesiExportBase {
                \r
                \r
                int partitionCount = 0;\r
-               while ((list = getNextTaxonPartition(null, limit, partitionCount++, null)).size() > 0   ) {\r
+               while ((list = getNextTaxonPartition(null, limit, partitionCount++, null)) != null   ) {\r
 \r
                        logger.info("Fetched " + list.size() + " " + pluralString + ". Exporting...");\r
                        for (TaxonBase<?> taxon : list) {\r
@@ -308,7 +359,7 @@ public class PesiTaxonExport extends PesiExportBase {
                        txStatus = startTransaction(true);\r
                        logger.info("Started new transaction. Fetching some " + pluralString + " (max: " + limit + ") ...");\r
                }\r
-               if (list.size() == 0) {\r
+               if (list == null ) {\r
                        logger.info("No " + pluralString + " left to fetch.");\r
                }\r
                // Commit transaction\r
@@ -345,7 +396,7 @@ public class PesiTaxonExport extends PesiExportBase {
                                ancestorLevel = 1;\r
                        }\r
                        if (ancestorLevel > 0) {\r
-                               if (ancestorOfSpecificRank(taxon, ancestorLevel, Rank.SUBGENUS())) {\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 does not exist even though it should for: " + taxon.getUuid() + " (" + taxon.getTitleCache() + ")");\r
@@ -473,8 +524,13 @@ public class PesiTaxonExport extends PesiExportBase {
                                        \r
                                        \r
                                        \r
-                                       commitTransaction(txStatus);\r
-                                       logger.debug("Committed transaction.");\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
                        }\r
@@ -502,16 +558,16 @@ public class PesiTaxonExport extends PesiExportBase {
                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)).size() > 0) {\r
+               while ((list = getNextTaxonPartition(TaxonBase.class, limit, partitionCount++, null)) != null) {\r
 \r
                        logger.info("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
+//                             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
@@ -519,7 +575,7 @@ public class PesiTaxonExport extends PesiExportBase {
                                //TODO why are expertFks needed? (Andreas M.)\r
 //                             if (expertFk != null || speciesExpertFk != null) {\r
                                        invokeRankDataAndTypeNameFkAndKingdomFk(taxonName, nomenclaturalCode, state.getDbId(taxon), \r
-                                                       typeNameFk, kingdomFk, expertFk, speciesExpertFk);\r
+                                                       typeNameFk, kingdomFk);\r
 //                             }\r
                        }\r
 \r
@@ -533,7 +589,7 @@ public class PesiTaxonExport extends PesiExportBase {
                        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.size() == 0) {\r
+               if (list == null) {\r
                        logger.info("No " + pluralString + " left to fetch.");\r
                }\r
                // Commit transaction\r
@@ -541,49 +597,6 @@ public class PesiTaxonExport extends PesiExportBase {
                logger.debug("Committed transaction.");\r
                return success;\r
        }\r
-\r
-       private Integer makeSpeciesExpertFk(PesiExportState state, TaxonNameBase<?, ?> taxonName) {\r
-               List<Reference> referenceList;\r
-               Integer speciesExpertFk = null;\r
-               String speciesExpertUserId = getSpeciesExpertUserId(taxonName);\r
-               if (speciesExpertUserId != null) {\r
-                       \r
-                       // The speciesExpertUserId was stored in the field 'title' of the corresponding Reference during FaEu import\r
-                       referenceList = getReferenceService().listByReferenceTitle(null, speciesExpertUserId, MatchMode.EXACT, null, null, null, null, null);\r
-                       if (referenceList.size() == 1) {\r
-                               speciesExpertFk  = getSpeciesExpertFk(referenceList.iterator().next(), state);\r
-                       } else if (referenceList.size() > 1) {\r
-                               logger.error("Found more than one match using listByTitle() searching for a Reference with this speciesExpertUserId as title: " + speciesExpertUserId);\r
-                       } else if (referenceList.size() == 0) {\r
-                               logger.error("Found no match using listByReferenceTitle() searching for a Reference with this speciesExpertUserId as title: " + speciesExpertUserId);\r
-                       }\r
-               } else {\r
-                       logger.debug("SpeciesExpertName is NULL for this TaxonName: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");\r
-               }\r
-               return speciesExpertFk;\r
-       }\r
-\r
-       private Integer makeExpertFk(PesiExportState state,\r
-                       TaxonNameBase<?, ?> taxonName) {\r
-               List<Reference> referenceList;\r
-               Integer expertFk = null;\r
-               String expertUserId = getExpertUserId(taxonName);\r
-               if (expertUserId != null) {\r
-\r
-                       // The expertUserId was stored in the field 'title' of the corresponding Reference during FaEu import\r
-                       referenceList = getReferenceService().listByReferenceTitle(null, expertUserId, MatchMode.EXACT, null, null, null, null, null);\r
-                       if (referenceList.size() == 1) {\r
-                               expertFk  = getExpertFk(referenceList.iterator().next(), state);\r
-                       } else if (referenceList.size() > 1) {\r
-                               logger.error("Found more than one match using listByReferenceTitle() searching for a Reference with this expertUserId as title: " + expertUserId);\r
-                       } else if (referenceList.size() == 0) {\r
-                               logger.error("Found no match using listByReferenceTitle() searching for a Reference with this expertUserId as title: " + expertUserId);\r
-                       }\r
-               } else {\r
-                       logger.debug("ExpertName is NULL for this TaxonName: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");\r
-               }\r
-               return expertFk;\r
-       }\r
        \r
        //      "PHASE 4: Creating Inferred Synonyms..."\r
        private boolean doPhase04(PesiExportState state, PesiExportMapping mapping) throws SQLException {\r
@@ -727,7 +740,7 @@ public class PesiTaxonExport extends PesiExportBase {
                }\r
                \r
                try {\r
-                       PesiExportMapping mapping = getNameMapping();\r
+                       PesiExportMapping mapping = getPureNameMapping();\r
                        mapping.initialize(state);\r
                        int count = 0;\r
                        int pastCount = 0;\r
@@ -747,7 +760,7 @@ public class PesiTaxonExport extends PesiExportBase {
                        while ((list = getNextPureNamePartition(null, limit, partitionCount++)) != null   ) {\r
 \r
                                logger.info("Fetched " + list.size() + " names without taxa. Exporting...");\r
-                               for (NonViralName<?> taxonName : list) {\r
+                               for (TaxonNameBase taxonName : list) {\r
                                        doCount(count++, modCount, pluralString);\r
                                        success &= mapping.invoke(taxonName);\r
                                }\r
@@ -799,46 +812,6 @@ public class PesiTaxonExport extends PesiExportBase {
                }\r
                return result;\r
        }\r
-\r
-       /**\r
-        * Returns the userId of the expert associated with the given TaxonName.\r
-        * @param taxonName A {@link TaxonNameBase TaxonName}.\r
-        * @return The userId.\r
-        */\r
-       private String getExpertUserId(TaxonNameBase<?,?> taxonName) {\r
-               String result = null;\r
-               try {\r
-                       Set<Extension> extensions = taxonName.getExtensions();\r
-                       for (Extension extension : extensions) {\r
-                               if (extension.getType().equals(expertUserIdExtensionType)) {\r
-                                       result = extension.getValue();\r
-                               }\r
-                       }\r
-               } catch (Exception e) {\r
-                       e.printStackTrace();\r
-               }\r
-               return result;\r
-       }\r
-\r
-       /**\r
-        * Returns the userId of the speciesExpert associated with the given TaxonName.\r
-        * @param taxonName A {@link TaxonNameBase TaxonName}.\r
-        * @return The userId.\r
-        */\r
-       private String getSpeciesExpertUserId(TaxonNameBase<?,?> taxonName) {\r
-               String result = null;\r
-               try {\r
-                       Set<Extension> extensions = taxonName.getExtensions();\r
-                       for (Extension extension : extensions) {\r
-                               if (extension.getType().equals(speciesExpertUserIdExtensionType)) {\r
-                                       result = extension.getValue();\r
-                               }\r
-                       }\r
-               } catch (Exception e) {\r
-                       e.printStackTrace();\r
-               }\r
-               return result;\r
-       }\r
        \r
        /**\r
         * Checks whether a parent at specific level has a specific Rank.\r
@@ -847,7 +820,7 @@ public class PesiTaxonExport extends PesiExportBase {
         * @param ancestorRank The ancestor rank.\r
         * @return Whether a parent at a specific level has a specific Rank.\r
         */\r
-       private boolean ancestorOfSpecificRank(TaxonBase<?> taxonBase, int level, Rank ancestorRank) {\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
@@ -1076,8 +1049,7 @@ public class PesiTaxonExport extends PesiExportBase {
         * @return Whether save was successful or not.\r
         */\r
        private boolean invokeRankDataAndTypeNameFkAndKingdomFk(TaxonNameBase<?,?> taxonName, NomenclaturalCode nomenclaturalCode, \r
-                       Integer taxonFk, Integer typeNameFk, Integer kingdomFk,\r
-                       Integer expertFk, Integer speciesExpertFk) {\r
+                       Integer taxonFk, Integer typeNameFk, Integer kingdomFkk) {\r
                try {\r
                        int index = 1;\r
                        Integer rankFk = getRankFk(taxonName, nomenclaturalCode);\r
@@ -1160,6 +1132,55 @@ public class PesiTaxonExport extends PesiExportBase {
                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
@@ -1170,24 +1191,36 @@ public class PesiTaxonExport extends PesiExportBase {
        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
+                       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
-               }\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) {\r
+               return getRankCache(taxonName, taxonName.getNomenclaturalCode());\r
+       }\r
+\r
+       \r
        /**\r
         * Returns the <code>RankCache</code> attribute.\r
         * @param taxonName The {@link TaxonNameBase TaxonName}.\r
@@ -1198,9 +1231,9 @@ public class PesiTaxonExport extends PesiExportBase {
        private static String getRankCache(TaxonNameBase<?,?> taxonName, NomenclaturalCode nomenclaturalCode) {\r
                String result = null;\r
                try {\r
-               if (nomenclaturalCode != null) {\r
-                       result = PesiTransformer.rank2RankCache(taxonName.getRank(), PesiTransformer.nomenClaturalCode2Kingdom(nomenclaturalCode));\r
-               }\r
+                       if (nomenclaturalCode != null) {\r
+                               result = PesiTransformer.rank2RankCache(taxonName.getRank(), PesiTransformer.nomenClaturalCode2Kingdom(nomenclaturalCode));\r
+                       }\r
                } catch (Exception e) {\r
                        e.printStackTrace();\r
                }\r
@@ -1208,13 +1241,69 @@ public class PesiTaxonExport extends PesiExportBase {
        }\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
+       /**\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 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
+                       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
-       @SuppressWarnings("unused")\r
        private static String getWebShowName(TaxonNameBase<?,?> taxonName) {\r
                //TODO extensions?\r
                if (taxonName == null) {\r
@@ -1228,6 +1317,7 @@ public class PesiTaxonExport extends PesiExportBase {
                }\r
        }\r
 \r
+       \r
        /**\r
         * Returns the <code>WebSearchName</code> attribute.\r
         * @param taxonName The {@link NonViralName NonViralName}.\r
@@ -1259,6 +1349,20 @@ public class PesiTaxonExport extends PesiExportBase {
        }\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>AuthorString</code> attribute.\r
         * @param taxonName The {@link TaxonNameBase TaxonName}.\r
@@ -1267,8 +1371,8 @@ public class PesiTaxonExport extends PesiExportBase {
         */\r
        @SuppressWarnings("unused")\r
        private static String getAuthorString(TaxonBase<?> taxon) {\r
-               String result = null;\r
                try {\r
+                       String result = null;\r
                        boolean isNonViralName = false;\r
                        String authorshipCache = null;\r
                        TaxonNameBase<?,?> taxonName = taxon.getName();\r
@@ -1276,92 +1380,77 @@ public class PesiTaxonExport extends PesiExportBase {
                                authorshipCache = CdmBase.deproxy(taxonName, NonViralName.class).getAuthorshipCache();\r
                                isNonViralName = true;\r
                        }\r
-                       // For a misapplied name without an authorshipCache the authorString should be set to "auct."\r
-                       if (isMisappliedName(taxon) && authorshipCache == null) {\r
-                               // Set authorshipCache to "auct."\r
-                               result = PesiTransformer.AUCT_STRING;\r
-                       }else{\r
-                               result = authorshipCache;\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
-               }\r
-               \r
-               if (StringUtils.isBlank(result)) {\r
                        return null;\r
-               } else {\r
-                       return result;\r
                }\r
+               \r
        }\r
 \r
-       \r
+               \r
        /**\r
-        * Checks whether a given TaxonName is a misapplied name.\r
-        * @param taxonName The {@link TaxonNameBase TaxonName}.\r
+        * Checks whether a given taxon is a misapplied name.\r
+        * @param taxon The {@link TaxonBase Taxon}.\r
         * @return Whether the given TaxonName is a misapplied name or not.\r
-        */     \r
-       private static boolean isMisappliedName(TaxonNameBase taxonName) {\r
-               boolean result = false;\r
-               Set<Taxon> taxa = taxonName.getTaxa();\r
-               if (taxa.size() == 1){\r
-                       return isMisappliedName(taxa.iterator().next());\r
-               }else if (taxa.size() > 1){\r
-                       logger.warn("TaxonNameBase has " + taxa.size() + " taxa attached. Can't define if it is a misapplied name.");\r
-               }\r
-               return result;\r
-       }\r
+        */\r
+       private static boolean isMisappliedName(TaxonBase<?> taxon) {\r
+               return getAcceptedTaxonForMisappliedName(taxon) != null;\r
                \r
-       \r
+       }\r
        \r
 \r
        /**\r
-        * Checks whether a given Taxon is a misapplied name.\r
-        * @param taxonName The {@link TaxonNameBase TaxonName}.\r
-        * @return Whether the given TaxonName is a misapplied name or not.\r
+        * Returns the first accepted taxon for this misapplied name.\r
+        * If this misapplied name is not a misapplied name, <code>null</code> is returned. \r
+        * @param taxon The {@link TaxonBase Taxon}.\r
         */\r
-       private static boolean isMisappliedName(TaxonBase<?> taxon) {\r
-               boolean result = false;\r
-               \r
+       private static Taxon getAcceptedTaxonForMisappliedName(TaxonBase<?> taxon) {\r
                if (! taxon.isInstanceOf(Taxon.class)){\r
-                       return false;\r
+                       return null;\r
                }\r
                Set<TaxonRelationship> taxonRelations = CdmBase.deproxy(taxon, Taxon.class).getRelationsFromThisTaxon();\r
                for (TaxonRelationship taxonRelationship : taxonRelations) {\r
                        TaxonRelationshipType taxonRelationshipType = taxonRelationship.getType();\r
                        if (taxonRelationshipType.equals(TaxonRelationshipType.MISAPPLIED_NAME_FOR())) {\r
-                               result = true;\r
+                               return taxonRelationship.getToTaxon();\r
                        }\r
                }\r
-               return result;\r
+               return null;\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")\r
-       private static String getDisplayName(TaxonNameBase<?,?> taxonName) {\r
-               // TODO: extension?\r
-               if (taxonName == null) {\r
-                       return null;\r
-               }else{\r
-               \r
-                       INonViralNameCacheStrategy cacheStrategy = getCacheStrategy(taxonName);\r
-                       \r
-                       HTMLTagRules tagRules = new HTMLTagRules().addRule(TagEnum.name, "i");\r
-                       NonViralName<?> nvn = CdmBase.deproxy(taxonName, NonViralName.class);\r
-                       return cacheStrategy.getFullTitleCache(nvn, tagRules);\r
-               }\r
-       }\r
+\r
 \r
        \r
        /**\r
@@ -1385,14 +1474,15 @@ public class PesiTaxonExport extends PesiExportBase {
         * 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) {\r
+       private static String getNameStatusCache(TaxonNameBase taxonName, PesiExportState state) throws UndefinedTransformerMethodException {\r
                String result = null;\r
-               NomenclaturalStatus state = getNameStatus(taxonName);\r
-               if (state != null) {\r
-                       result = PesiTransformer.nomStatus2NomStatusCache(state.getType());\r
+               NomenclaturalStatus status = getNameStatus(taxonName);\r
+               if (status != null) {\r
+                       result = state.getTransformer().getCacheByNomStatus(status.getType());\r
                }\r
                return result;\r
        }\r
@@ -1405,8 +1495,8 @@ public class PesiTaxonExport extends PesiExportBase {
                                NonViralName<?> nonViralName = CdmBase.deproxy(taxonName, NonViralName.class);\r
                                Set<NomenclaturalStatus> states = nonViralName.getStatus();\r
                                if (states.size() == 1) {\r
-                                       NomenclaturalStatus state = states.iterator().next();\r
-                                       return state;\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
@@ -1528,6 +1618,7 @@ public class PesiTaxonExport extends PesiExportBase {
                }\r
                return result;\r
        }\r
+\r
        \r
        /**\r
         * Returns the <code>QualityStatusFk</code> attribute.\r
@@ -1535,24 +1626,22 @@ public class PesiTaxonExport extends PesiExportBase {
         * @return The <code>QualityStatusFk</code> attribute.\r
         * @see MethodMapper\r
         */\r
-       @SuppressWarnings("unused")\r
-       private static Integer getQualityStatusFk(TaxonBase<?> taxonName) {\r
-               // TODO: Not represented in CDM right now. Depends on import.\r
-               Integer result = null;\r
-               return result;\r
+       private static Integer getQualityStatusFk(TaxonNameBase taxonName) {\r
+               BitSet sources = getSources(taxonName);\r
+               return PesiTransformer.getQualityStatusKeyBySource(sources);\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(TaxonBase<?> taxonName) {\r
-               // TODO: Not represented in CDM right now. Depends on import.\r
-               String result = null;\r
-               return result;\r
+       private static String getQualityStatusCache(TaxonNameBase taxonName, PesiExportState state) throws UndefinedTransformerMethodException {\r
+               return state.getTransformer().getQualityStatusCacheByKey(getQualityStatusFk(taxonName));\r
        }\r
        \r
        /**\r
@@ -1655,7 +1744,7 @@ public class PesiTaxonExport extends PesiExportBase {
                try {\r
                        Set<IdentifiableSource> sources = getPesiSources(taxonName);\r
                        for (IdentifiableSource source : sources) {\r
-                               Reference ref = source.getCitation();\r
+                               Reference<?> ref = source.getCitation();\r
                                UUID refUuid = ref.getUuid();\r
                                if (refUuid.equals(PesiTransformer.uuidSourceRefEuroMed)){\r
                                        result = "NameId: " + source.getIdInSource();\r
@@ -1679,10 +1768,7 @@ public class PesiTaxonExport extends PesiExportBase {
                                                result = "Inferred genus from TAX_ID: " + source.getIdInSource();\r
                                        } else if (sourceIdNameSpace.equals(TaxonServiceImpl.POTENTIAL_COMBINATION_NAMESPACE)) {\r
                                                result = "Potential combination from TAX_ID: " + source.getIdInSource();\r
-                                       } else {\r
-//                                             result = "TAX_ID: " + source.getIdInSource();\r
-                                               result = sourceIdNameSpace + source.getIdInSource();\r
-                                       }\r
+                                       } \r
                                }\r
                        }\r
                } catch (Exception e) {\r
@@ -1822,134 +1908,79 @@ public class PesiTaxonExport extends PesiExportBase {
         * @see MethodMapper\r
         */\r
        @SuppressWarnings("unused")\r
-       private static String getCacheCitation(TaxonBase<?> taxon) {\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
-//                     String originalDb = getOriginalDB(taxon);\r
-//                     if (originalDb == null) {\r
-////                           logger.error("OriginalDB is NULL for this TaxonName: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");\r
-//                     } else if (originalDb.equals("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 = taxon.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(taxon);\r
-//                             \r
-//                             // idInSource only\r
-//                             String idInSource = getIdInSourceOnly(taxo);\r
-//                             \r
-//                             // build the cacheCitation\r
-//                             if (expertName != null) {\r
-//                                     result += expertName + ". ";\r
-//                             } else {\r
-//     //                              logger.error("ExpertName could not be determined for this TaxonName: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");\r
-//                             }\r
-//                             if (webShowName != null) {\r
-//                                     result += webShowName + ". ";\r
-//                             } else {\r
-//     //                              logger.error("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.error("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 ("".equals(result)) {\r
-//                     return null;\r
-//             } else {\r
-//                     return result;\r
-//             }\r
-               return result;\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
-               String result = "";\r
                try {\r
-\r
-               // Sources from TaxonName\r
-//             Set<IdentifiableSource> sources = taxonName.getSources();\r
-               Set<IdentifiableSource>  sources  = identEntity.getSources();\r
-               \r
-//             IdentifiableEntity<?> taxonBase = null;\r
-//             if (sources != null && sources.isEmpty()) {\r
-//                     // Sources from Taxa or Synonyms\r
-//                     Set<Taxon> taxa = taxonName.getTaxa();\r
-//                     if (taxa.size() == 1) {\r
-//                             taxonBase = taxa.iterator().next();\r
-//                             sources  = taxonBase.getSources();\r
-//                     } else if (taxa.size() > 1) {\r
-//                             logger.warn("This TaxonName has " + taxa.size() + " Taxa: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() +")");\r
-//                     }\r
-//                     Set<Synonym> synonyms = taxonName.getSynonyms();\r
-//                     if (synonyms.size() == 1) {\r
-//                             taxonBase = synonyms.iterator().next();\r
-//                             sources = taxonBase.getSources();\r
-//                     } else if (synonyms.size() > 1) {\r
-//                             logger.warn("This TaxonName has " + synonyms.size() + " Synonyms: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() +")");\r
-//                     }\r
-//             }\r
-\r
-               if (sources != null && ! sources.isEmpty()) {\r
-                       if (sources.size() == 1) {\r
-                               IdentifiableSource source = sources.iterator().next();\r
-                               if (source != null) {\r
-                                       Reference<?> citation = source.getCitation();\r
-                                       if (citation != null) {\r
-                                               result = PesiTransformer.databaseString2Abbreviation(citation.getTitleCache());\r
-                                       }\r
-                               }\r
-                       } else if (sources.size() > 1) {\r
-                               int count = 1;\r
-                               for (IdentifiableSource source : sources) {\r
-                                       Reference<?> citation = source.getCitation();\r
-                                       if (citation != null) {\r
-                                               if (count > 1) {\r
-                                                       result += "; ";\r
-                                               }\r
-                                               result += PesiTransformer.databaseString2Abbreviation(citation.getTitleCache());\r
-                                               count++;\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
-                               result = null;\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
-               }\r
-\r
                } catch (Exception e) {\r
                        e.printStackTrace();\r
                }\r
-               if ("".equals(result)) {\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
@@ -2067,6 +2098,34 @@ public class PesiTaxonExport extends PesiExportBase {
        }\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(PesiTransformer.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
        private static NonViralNameDefaultCacheStrategy getCacheStrategy(TaxonNameBase<?, ?> taxonName) {\r
                NonViralNameDefaultCacheStrategy cacheStrategy;\r
                if (taxonName.isInstanceOf(ZoologicalName.class)){\r
@@ -2132,38 +2191,46 @@ public class PesiTaxonExport extends PesiExportBase {
         */\r
        private PesiExportMapping getMapping() {\r
                PesiExportMapping mapping = new PesiExportMapping(dbTableName);\r
-               ExtensionType extensionType = null;\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
                // QualityStatus (Fk, Cache)\r
-               extensionType = (ExtensionType)getTermService().find(ErmsTransformer.uuidQualityStatus);\r
-               if (extensionType != null) {\r
-                       mapping.addMapper(DbExtensionMapper.NewInstance(extensionType, "QualityStatusCache"));\r
-               } else {\r
-                       mapping.addMapper(MethodMapper.NewInstance("QualityStatusCache", this));\r
-               }\r
-               mapping.addMapper(MethodMapper.NewInstance("QualityStatusFk", this)); // PesiTransformer.QualityStatusCache2QualityStatusFk?\r
+//             extensionType = (ExtensionType)getTermService().find(ErmsTransformer.uuidQualityStatus);\r
+//             if (extensionType != null) {\r
+//                     mapping.addMapper(DbExtensionMapper.NewInstance(extensionType, "QualityStatusCache"));\r
+//             } else {\r
+//                     mapping.addMapper(MethodMapper.NewInstance("QualityStatusCache", this));\r
+//             }\r
+//             mapping.addMapper(MethodMapper.NewInstance("QualityStatusFk", this)); // PesiTransformer.QualityStatusCache2QualityStatusFk?\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("OriginalDB", this.getClass(), "getOriginalDB", IdentifiableEntity.class) );\r
+               mapping.addMapper(MethodMapper.NewInstance("AuthorString", this));  //For Taxon because Misallied Names are handled differently\r
+               mapping.addMapper(MethodMapper.NewInstance("WebShowName", this));\r
                \r
-               //handled by name mapping\r
-//             mapping.addMapper(MethodMapper.NewInstance("LastAction", this.getClass(), "getLastAction",  IdentifiableEntity.class));\r
-//             mapping.addMapper(MethodMapper.NewInstance("LastActionDate", this.getClass(), "getLastActionDate",  IdentifiableEntity.class));\r
-//             mapping.addMapper(MethodMapper.NewInstance("SpeciesExpertName", this));\r
-\r
+               // DisplayName\r
+               ExtensionType extensionType = (ExtensionType)getTermService().find(ErmsTransformer.uuidDisplayName);            \r
+               if (extensionType != null) {\r
+                       mapping.addMapper(DbExtensionMapper.NewInstance(extensionType, "DisplayName"));\r
+               } else {\r
+                       mapping.addMapper(MethodMapper.NewInstance("DisplayName", this));\r
+               }\r
                \r
-               mapping.addMapper(MethodMapper.NewInstance("ExpertName", this));\r
-\r
-               mapping.addMapper(MethodMapper.NewInstance("AuthorString", this));  //For Taxon because Misallied Names are handled differently\r
+               //handled by name mapping\r
+               mapping.addMapper(DbLastActionMapper.NewInstance("LastActionDate", false));\r
+               mapping.addMapper(DbLastActionMapper.NewInstance("LastAction", true));\r
                \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));  //doesn't work, FK exceptioni\r
                mapping.addMapper(ObjectChangeMapper.NewInstance(TaxonBase.class, TaxonNameBase.class, "Name"));\r
                \r
                addNameMappers(mapping);\r
@@ -2175,24 +2242,34 @@ public class PesiTaxonExport extends PesiExportBase {
         * Returns the CDM to PESI specific export mappings.\r
         * @return The {@link PesiExportMapping PesiExportMapping}.\r
         */\r
-       private PesiExportMapping getNameMapping() {\r
+       private PesiExportMapping getPureNameMapping() {\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("LastAction", this.getClass(), "getLastAction", IdentifiableEntity.class));\r
-//             mapping.addMapper(MethodMapper.NewInstance("LastActionDate",  this.getClass(), "getLastAction", IdentifiableEntity.class));\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));\r
+               mapping.addMapper(DbConstantMapper.NewInstance("TaxonStatusFk", Types.INTEGER , PesiTransformer.T_STATUS_UNACCEPTED));\r
+               mapping.addMapper(DbConstantMapper.NewInstance("TaxonStatusCache", Types.VARCHAR , PesiTransformer.T_STATUS_STR_UNACCEPTED));\r
+               mapping.addMapper(DbStringMapper.NewInstance("AuthorshipCache", "AuthorString").setBlankToNull(true));  \r
+               mapping.addMapper(MethodMapper.NewInstance("WebShowName", this, TaxonNameBase.class));\r
                \r
-               mapping.addMapper(MethodMapper.NewInstance("OriginalDB", this.getClass(), "getOriginalDB", IdentifiableEntity.class) );\r
+               // DisplayName\r
+               ExtensionType extensionType = (ExtensionType)getTermService().find(ErmsTransformer.uuidDisplayName);            \r
+               if (extensionType != null) {\r
+                       mapping.addMapper(DbExtensionMapper.NewInstance(extensionType, "DisplayName"));\r
+               } else {\r
+                       mapping.addMapper(MethodMapper.NewInstance("DisplayName", this, TaxonNameBase.class));\r
+               }\r
                \r
-               addNameMappers(mapping);\r
+               mapping.addMapper(DbLastActionMapper.NewInstance("LastActionDate", false));\r
+               mapping.addMapper(DbLastActionMapper.NewInstance("LastAction", true));\r
                \r
-               //TODO add author mapper, taxonStatusFk, TaxonStatusCache, TypeNameFk\r
-\r
-//     immer 2 für E+M ?       mapping.addMapper(MethodMapper.NewInstance("QualityStatusFk", this)); // PesiTransformer.QualityStatusCache2QualityStatusFk?\r
-//             mapping.addMapper(MethodMapper.NewInstance("TaxonStatusCache", this.getClass(), "getTaxonStatusCache", standardMethodParameter, PesiExportState.class));\r
+               addNameMappers(mapping);\r
+               //TODO add author mapper, TypeNameFk\r
 \r
                return mapping;\r
        }\r
@@ -2211,22 +2288,17 @@ public class PesiTaxonExport extends PesiExportBase {
                mapping.addMapper(MethodMapper.NewInstance("FullName", this, TaxonNameBase.class));\r
                \r
                \r
-               //TODO FIXME incorrect mapping -> should be ref +  microref but is only microref\r
-               mapping.addMapper(DbStringMapper.NewInstance("NomenclaturalMicroReference", "NomRefString"));\r
-               mapping.addMapper(MethodMapper.NewInstance("WebShowName", this, TaxonNameBase.class));\r
+               mapping.addMapper(MethodMapper.NewInstance("NomRefString", this, TaxonNameBase.class));\r
                \r
-               // DisplayName\r
-               extensionType = (ExtensionType)getTermService().find(ErmsTransformer.uuidDisplayName);          \r
-               if (extensionType != null) {\r
-                       mapping.addMapper(DbExtensionMapper.NewInstance(extensionType, "DisplayName"));\r
-               } else {\r
-                       mapping.addMapper(MethodMapper.NewInstance("DisplayName", this, TaxonNameBase.class));\r
-               }\r
+\r
 \r
                mapping.addMapper(MethodMapper.NewInstance("NameStatusFk", this, TaxonNameBase.class));\r
-               mapping.addMapper(MethodMapper.NewInstance("NameStatusCache", 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
+               mapping.addMapper(MethodMapper.NewInstance("QualityStatusFk", this, TaxonNameBase.class));\r
+               mapping.addMapper(MethodMapper.NewInstance("QualityStatusCache", this, TaxonNameBase.class, PesiExportState.class));\r
+               \r
                \r
                // FossilStatus (Fk, Cache)\r
                extensionType = (ExtensionType)getTermService().find(ErmsTransformer.uuidFossilStatus);\r
@@ -2238,7 +2310,9 @@ public class PesiTaxonExport extends PesiExportBase {
                mapping.addMapper(MethodMapper.NewInstance("FossilStatusFk", this, TaxonNameBase.class)); // PesiTransformer.FossilStatusCache2FossilStatusFk?\r
                \r
                mapping.addMapper(MethodMapper.NewInstance("IdInSource", this, IdentifiableEntity.class));\r
-               mapping.addMapper(ExpertsAndLastActionMapper.NewInstance());\r
+               mapping.addMapper(MethodMapper.NewInstance("OriginalDB", this, IdentifiableEntity.class) );\r
+\r
+               //mapping.addMapper(ExpertsAndLastActionMapper.NewInstance());\r
 \r
        }\r
 \r