minor
[cdmlib.git] / cdmlib-io / src / main / java / eu / etaxonomy / cdm / io / specimen / excel / in / SpecimenCdmExcelImport.java
index 62855db63d03674b0d7305b5ac8734deb599571f..efdb083d4a6900e472f1e653e84317803c748315 100644 (file)
@@ -11,35 +11,29 @@ package eu.etaxonomy.cdm.io.specimen.excel.in;
 
 import java.text.ParseException;
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Set;
 import java.util.UUID;
 
 import org.apache.commons.lang.StringUtils;
 import org.apache.log4j.Logger;
 import org.springframework.stereotype.Component;
 
-import sun.security.util.DerEncoder;
-
 import eu.etaxonomy.cdm.api.facade.DerivedUnitFacade;
 import eu.etaxonomy.cdm.api.facade.DerivedUnitFacade.DerivedUnitType;
 import eu.etaxonomy.cdm.api.service.config.MatchingTaxonConfigurator;
 import eu.etaxonomy.cdm.common.CdmUtils;
-import eu.etaxonomy.cdm.io.common.CdmImportBase.TermMatchMode;
 import eu.etaxonomy.cdm.io.common.ICdmIO;
 import eu.etaxonomy.cdm.io.common.mapping.UndefinedTransformerMethodException;
-import eu.etaxonomy.cdm.io.excel.common.ExcelImporterBase;
+import eu.etaxonomy.cdm.io.excel.common.ExcelRowBase.PostfixTerm;
+import eu.etaxonomy.cdm.io.excel.common.ExcelTaxonOrSpecimenImportBase;
 import eu.etaxonomy.cdm.io.specimen.excel.in.SpecimenRow.DeterminationLight;
-import eu.etaxonomy.cdm.io.specimen.excel.in.SpecimenRow.PostfixTerm;
 import eu.etaxonomy.cdm.model.agent.AgentBase;
 import eu.etaxonomy.cdm.model.agent.Person;
 import eu.etaxonomy.cdm.model.agent.Team;
 import eu.etaxonomy.cdm.model.agent.TeamOrPersonBase;
 import eu.etaxonomy.cdm.model.common.Annotation;
 import eu.etaxonomy.cdm.model.common.AnnotationType;
-import eu.etaxonomy.cdm.model.common.Extension;
-import eu.etaxonomy.cdm.model.common.ExtensionType;
+import eu.etaxonomy.cdm.model.common.CdmBase;
 import eu.etaxonomy.cdm.model.common.IdentifiableSource;
 import eu.etaxonomy.cdm.model.common.Language;
 import eu.etaxonomy.cdm.model.common.TimePeriod;
@@ -63,6 +57,7 @@ import eu.etaxonomy.cdm.model.occurrence.DeterminationEvent;
 import eu.etaxonomy.cdm.model.reference.Reference;
 import eu.etaxonomy.cdm.model.reference.ReferenceFactory;
 import eu.etaxonomy.cdm.model.taxon.Taxon;
+import eu.etaxonomy.cdm.model.taxon.TaxonBase;
 import eu.etaxonomy.cdm.persistence.query.MatchMode;
 import eu.etaxonomy.cdm.strategy.exceptions.UnknownCdmTypeException;
 import eu.etaxonomy.cdm.strategy.parser.NonViralNameParserImpl;
@@ -73,12 +68,11 @@ import eu.etaxonomy.cdm.strategy.parser.NonViralNameParserImpl;
  * @version 1.0
  */
 @Component
-public class SpecimenCdmExcelImport  extends ExcelImporterBase<SpecimenCdmExcelImportState>  implements ICdmIO<SpecimenCdmExcelImportState> {
+public class SpecimenCdmExcelImport  extends ExcelTaxonOrSpecimenImportBase<SpecimenCdmExcelImportState, SpecimenRow>  implements ICdmIO<SpecimenCdmExcelImportState> {
        private static final Logger logger = Logger.getLogger(SpecimenCdmExcelImport.class);
 
        private static final String WORKSHEET_NAME = "Specimen";
 
-       private static final String UUID_COLUMN = "(?i)(UUID)";
        private static final String BASIS_OF_RECORD_COLUMN = "(?i)(BasisOfRecord)";
        private static final String COUNTRY_COLUMN = "(?i)(Country)";
        private static final String AREA_COLUMN = "(?i)(Area)";
@@ -89,6 +83,8 @@ public class SpecimenCdmExcelImport  extends ExcelImporterBase<SpecimenCdmExcelI
        private static final String COLLECTION_DATE_COLUMN = "(?i)(CollectionDate)";
        private static final String COLLECTION_DATE_END_COLUMN = "(?i)(CollectionDateEnd)";
        private static final String COLLECTOR_COLUMN = "(?i)(Collector)";
+       private static final String COLLECTORS_COLUMN = "(?i)(Collectors)";
+       private static final String PRIMARY_COLLECTOR_COLUMN = "(?i)(PrimaryCollector)";
        private static final String LONGITUDE_COLUMN = "(?i)(Longitude)";
        private static final String LATITUDE_COLUMN = "(?i)(Latitude)";
        private static final String REFERENCE_SYSTEM_COLUMN = "(?i)(ReferenceSystem)";
@@ -117,12 +113,6 @@ public class SpecimenCdmExcelImport  extends ExcelImporterBase<SpecimenCdmExcelI
        private static final String ID_IN_SOURCE_COLUMN = "(?i)(IdInSource)";
        
        
-       private static final String RANK_COLUMN = "(?i)(Rank)";
-       private static final String FULL_NAME_COLUMN = "(?i)(FullName)";
-       private static final String FAMILY_COLUMN = "(?i)(Family)";
-       private static final String GENUS_COLUMN = "(?i)(Genus)";
-       private static final String SPECIFIC_EPITHET_COLUMN = "(?i)(SpecificEpi(thet)?)";
-       private static final String INFRASPECIFIC_EPITHET_COLUMN = "(?i)(InfraSpecificEpi(thet)?)";
        private static final String DETERMINATION_AUTHOR_COLUMN = "(?i)(Author)";
        private static final String DETERMINATION_MODIFIER_COLUMN = "(?i)(DeterminationModifier)";
        private static final String DETERMINED_BY_COLUMN = "(?i)(DeterminationBy)";
@@ -130,168 +120,142 @@ public class SpecimenCdmExcelImport  extends ExcelImporterBase<SpecimenCdmExcelI
        private static final String DETERMINATION_NOTES_COLUMN = "(?i)(DeterminationNote)";
        private static final String EXTENSION_COLUMN = "(?i)(Ext(ension)?)";
        
-       private static final String IGNORE_COLUMN = "(?i)(Ignore|Not)";
-       
 
        public SpecimenCdmExcelImport() {
                super();
        }
 
        
+
+
        @Override
-       protected boolean analyzeRecord(HashMap<String, String> record, SpecimenCdmExcelImportState state) {
-               boolean success = true;
-       Set<String> keys = record.keySet();
-       
-       SpecimenRow row = new SpecimenRow();
-       state.setSpecimenRow(row);
-       
-       for (String originalKey: keys) {
-               Integer index = 0;
-               String postfix = null;
-               String indexedKey = CdmUtils.removeDuplicateWhitespace(originalKey.trim()).toString();
-               String[] split = indexedKey.split("_");
-               String key = split[0];
-               if (split.length > 1){
-                       for (int i = 1 ; i < split.length ; i++ ){
-                               String indexString = split[i];
-                               if (isInteger(indexString)){
-                                       index = Integer.valueOf(indexString);
-                               }else{
-                                       postfix = split[i];
-                               }
-                       }
-               }
-               
-               String value = (String) record.get(indexedKey);
-               if (! StringUtils.isBlank(value)) {
-                       if (logger.isDebugEnabled()) { logger.debug(key + ": " + value); }
-                       value = CdmUtils.removeDuplicateWhitespace(value.trim()).toString();
-               }else{
-                       continue;
-               }
-               
-               if (key.matches(UUID_COLUMN)) {
-                       row.setUuid(UUID.fromString(value)); //VALIDATE UUID
-                       } else if(key.matches(BASIS_OF_RECORD_COLUMN)) {
-                               row.setBasisOfRecord(value);
-                       } else if(key.matches(COUNTRY_COLUMN)) {
-                               row.setCountry(value);
-                       } else if(key.matches(ISO_COUNTRY_COLUMN)) {
-                               row.setIsoCountry(value);
-                       } else if(key.matches(LOCALITY_COLUMN)) {
-                               row.setLocality(value);
-                       } else if(key.matches(FIELD_NOTES_COLUMN)) {
-                               row.setLocality(value);
-                       } else if(key.matches(ALTITUDE_COLUMN)) {
-                               row.setAltitude(value);         
-                       } else if(key.matches(ALTITUDE_MAX_COLUMN)) {
-                               row.setAltitudeMax(value);              
-                       } else if(key.matches(COLLECTOR_COLUMN)) {
-                               row.putCollector(index, value);         
-                       } else if(key.matches(ECOLOGY_COLUMN)) {
-                               row.setEcology(value);
-                       } else if(key.matches(PLANT_DESCRIPTION_COLUMN)) {
-                               row.setPlantDescription(value);         
-                       } else if(key.matches(SEX_COLUMN)) {
-                               row.setSex(value);
-                       } else if(key.matches(COLLECTION_DATE_COLUMN)) {
-                               row.setCollectingDate(value);           
-                       } else if(key.matches(COLLECTION_DATE_END_COLUMN)) {
-                               row.setCollectingDateEnd(value);                
-                       } else if(key.matches(COLLECTOR_COLUMN)) {
-                               row.putCollector(index, value); 
-                       } else if(key.matches(COLLECTORS_NUMBER_COLUMN)) {
-                               row.setCollectorsNumber(value);         
-                       } else if(key.matches(LONGITUDE_COLUMN)) {
-                               row.setLongitude(value);                
-                       } else if(key.matches(LATITUDE_COLUMN)) {
-                               row.setLatitude(value);         
-                       } else if(key.matches(REFERENCE_SYSTEM_COLUMN)) {
-                               row.setReferenceSystem(value);          
-                       } else if(key.matches(ERROR_RADIUS_COLUMN)) {
-                               row.setErrorRadius(value);              
-                       } else if(key.matches(AREA_COLUMN)) {
-                               if (postfix != null){
-                                       row.addLeveledArea(postfix, value);             
-                               }else{
-                                       logger.warn("Not yet implemented");
-                               }
-                       
-                               
-                               
-                       } else if(key.matches(ACCESSION_NUMBER_COLUMN)) {
-                               row.setLocality(value);         
-                       } else if(key.matches(BARCODE_COLUMN)) {
-                               row.setBarcode(value);          
-                       } else if(key.matches(UNIT_NOTES_COLUMN)) {
-                               row.putUnitNote(index, value);          
-                       
-                               
-                       } else if(key.matches(FAMILY_COLUMN)) {
-                               row.putDeterminationFamily(index, value);               
-                       } else if(key.matches(GENUS_COLUMN)) {
-                               row.putDeterminationGenus(index, value);                
-                       } else if(key.matches(SPECIFIC_EPITHET_COLUMN)) {
-                               row.putDeterminationSpeciesEpi(index, value);                   
-                       } else if(key.matches(INFRASPECIFIC_EPITHET_COLUMN)) {
-                               row.putDeterminationInfraSpeciesEpi(index, value);                      
-                       } else if(key.matches(RANK_COLUMN)) {
-                               row.putDeterminationRank(index, value);                 
-                       } else if(key.matches(FULL_NAME_COLUMN)) {
-                               row.putDeterminationFullName(index, value);                     
-                       } else if(key.matches(DETERMINATION_AUTHOR_COLUMN)) {
-                               row.putDeterminationAuthor(index, value);                       
-                       } else if(key.matches(DETERMINATION_MODIFIER_COLUMN)) {
-                               row.putDeterminationDeterminationModifier(index, value);                        
-                       } else if(key.matches(DETERMINATION_NOTES_COLUMN)) {
-                               row.putDeterminationDeterminationNotes(index, value);                   
-                       } else if(key.matches(DETERMINED_BY_COLUMN)) {
-                               row.putDeterminationDeterminedBy(index, value);                 
-                       } else if(key.matches(DETERMINED_WHEN_COLUMN)) {
-                               row.putDeterminationDeterminedWhen(index, value);                       
-                       
-                       } else if(key.matches(COLLECTION_CODE_COLUMN)) {
-                               row.setCollectionCode(value);           
-                       } else if(key.matches(COLLECTION_COLUMN)) {
-                               row.setCollection(value);               
+       protected void analyzeSingleValue(KeyValue keyValue, SpecimenCdmExcelImportState state) {
+               SpecimenRow row = state.getCurrentRow();
+               String value = keyValue.value;
+               if(keyValue.key.matches(BASIS_OF_RECORD_COLUMN)) {
+                       row.setBasisOfRecord(value);
+               } else if(keyValue.key.matches(COUNTRY_COLUMN)) {
+                       row.setCountry(value);
+               } else if(keyValue.key.matches(ISO_COUNTRY_COLUMN)) {
+                       row.setIsoCountry(value);
+               } else if(keyValue.key.matches(LOCALITY_COLUMN)) {
+                       row.setLocality(value);
+               } else if(keyValue.key.matches(FIELD_NOTES_COLUMN)) {
+                       row.setLocality(value);
+               } else if(keyValue.key.matches(ALTITUDE_COLUMN)) {
+                       row.setAltitude(value);         
+               } else if(keyValue.key.matches(ALTITUDE_MAX_COLUMN)) {
+                       row.setAltitudeMax(value);              
+               } else if(keyValue.key.matches(COLLECTOR_COLUMN)) {
+                       row.putCollector(keyValue.index, value);                
+               } else if(keyValue.key.matches(PRIMARY_COLLECTOR_COLUMN)) {
+                       row.setPrimaryCollector(value);         
+               } else if(keyValue.key.matches(ECOLOGY_COLUMN)) {
+                       row.setEcology(value);
+               } else if(keyValue.key.matches(PLANT_DESCRIPTION_COLUMN)) {
+                       row.setPlantDescription(value);         
+               } else if(keyValue.key.matches(SEX_COLUMN)) {
+                       row.setSex(value);
+               } else if(keyValue.key.matches(COLLECTION_DATE_COLUMN)) {
+                       row.setCollectingDate(value);           
+               } else if(keyValue.key.matches(COLLECTION_DATE_END_COLUMN)) {
+                       row.setCollectingDateEnd(value);                
+               } else if(keyValue.key.matches(COLLECTORS_COLUMN)) {
+                       row.setCollectors(value);       
+               } else if(keyValue.key.matches(COLLECTOR_COLUMN)) {
+                       row.putCollector(keyValue.index, value);        
+               } else if(keyValue.key.matches(COLLECTORS_NUMBER_COLUMN)) {
+                       row.setCollectorsNumber(value);         
+               } else if(keyValue.key.matches(LONGITUDE_COLUMN)) {
+                       row.setLongitude(value);                
+               } else if(keyValue.key.matches(LATITUDE_COLUMN)) {
+                       row.setLatitude(value);         
+               } else if(keyValue.key.matches(REFERENCE_SYSTEM_COLUMN)) {
+                       row.setReferenceSystem(value);          
+               } else if(keyValue.key.matches(ERROR_RADIUS_COLUMN)) {
+                       row.setErrorRadius(value);              
+               } else if(keyValue.key.matches(AREA_COLUMN)) {
+                       if (keyValue.postfix != null){
+                               row.addLeveledArea(keyValue.postfix, value);            
+                       }else{
+                               logger.warn("Not yet implemented");
+                       }
+               
                        
-                       } else if(key.matches(TYPE_CATEGORY_COLUMN)) {
-                               row.putTypeCategory(index, getSpecimenTypeStatus(state, value));        
-                       } else if(key.matches(TYPIFIED_NAME_COLUMN)) {
-                               row.putTypifiedName(index, getTaxonName(state, value));         
                        
+               } else if(keyValue.key.matches(ACCESSION_NUMBER_COLUMN)) {
+                       row.setLocality(value);         
+               } else if(keyValue.key.matches(BARCODE_COLUMN)) {
+                       row.setBarcode(value);          
+               } else if(keyValue.key.matches(UNIT_NOTES_COLUMN)) {
+                       row.putUnitNote(keyValue.index, value);         
+               
                        
-                       } else if(key.matches(SOURCE_COLUMN)) {
-                               row.putSourceReference(index, getOrMakeReference(state, value));        
-                       } else if(key.matches(ID_IN_SOURCE_COLUMN)) {
-                               row.putIdInSource(index, value);                
-                       } else if(key.matches(EXTENSION_COLUMN)) {
-                               if (postfix != null){
-                                       row.addExtension(postfix, value);               
-                               }else{
-                                       logger.warn("Extension without postfix not yet implemented");
-                               }
-                               
-                       } else if(key.matches(IGNORE_COLUMN)) {
-                               logger.debug("Ignored column" + originalKey);           
-                       }else {
-                               success = false;
-                               logger.error("Unexpected column header " + originalKey);
+               } else if(keyValue.key.matches(FAMILY_COLUMN)) {
+                       row.putDeterminationFamily(keyValue.index, value);              
+               } else if(keyValue.key.matches(GENUS_COLUMN)) {
+                       row.putDeterminationGenus(keyValue.index, value);               
+               } else if(keyValue.key.matches(SPECIFIC_EPITHET_COLUMN)) {
+                       row.putDeterminationSpeciesEpi(keyValue.index, value);                  
+               } else if(keyValue.key.matches(INFRASPECIFIC_EPITHET_COLUMN)) {
+                       row.putDeterminationInfraSpeciesEpi(keyValue.index, value);                     
+               } else if(keyValue.key.matches(RANK_COLUMN)) {
+                       row.putDeterminationRank(keyValue.index, value);                        
+               } else if(keyValue.key.matches(TAXON_UUID_COLUMN)) {
+                       row.putDeterminationTaxonUuid(keyValue.index, value);                   
+               } else if(keyValue.key.matches(FULL_NAME_COLUMN)) {
+                       row.putDeterminationFullName(keyValue.index, value);                    
+               } else if(keyValue.key.matches(DETERMINATION_AUTHOR_COLUMN)) {
+                       row.putDeterminationAuthor(keyValue.index, value);                      
+               } else if(keyValue.key.matches(DETERMINATION_MODIFIER_COLUMN)) {
+                       row.putDeterminationDeterminationModifier(keyValue.index, value);                       
+               } else if(keyValue.key.matches(DETERMINATION_NOTES_COLUMN)) {
+                       row.putDeterminationDeterminationNotes(keyValue.index, value);                  
+               } else if(keyValue.key.matches(DETERMINED_BY_COLUMN)) {
+                       row.putDeterminationDeterminedBy(keyValue.index, value);                        
+               } else if(keyValue.key.matches(DETERMINED_WHEN_COLUMN)) {
+                       row.putDeterminationDeterminedWhen(keyValue.index, value);                      
+               
+               } else if(keyValue.key.matches(COLLECTION_CODE_COLUMN)) {
+                       row.setCollectionCode(value);           
+               } else if(keyValue.key.matches(COLLECTION_COLUMN)) {
+                       row.setCollection(value);               
+               
+               } else if(keyValue.key.matches(TYPE_CATEGORY_COLUMN)) {
+                       row.putTypeCategory(keyValue.index, getSpecimenTypeStatus(state, value));       
+               } else if(keyValue.key.matches(TYPIFIED_NAME_COLUMN)) {
+                       row.putTypifiedName(keyValue.index, getTaxonName(state, value));                
+               
+               
+               } else if(keyValue.key.matches(SOURCE_COLUMN)) {
+                       row.putSourceReference(keyValue.index, getOrMakeReference(state, value));       
+               } else if(keyValue.key.matches(ID_IN_SOURCE_COLUMN)) {
+                       row.putIdInSource(keyValue.index, value);               
+               } else if(keyValue.key.matches(EXTENSION_COLUMN)) {
+                       if (keyValue.postfix != null){
+                               row.addExtension(keyValue.postfix, value);              
+                       }else{
+                               logger.warn("Extension without postfix not yet implemented");
                        }
-       }
-       return success;
+                       
+               }else {
+                       state.setUnsuccessfull();
+                       logger.error("Unexpected column header " + keyValue.originalKey);
+               }
+
+       return;
        }
 
+
        @Override
-       protected boolean firstPass(SpecimenCdmExcelImportState state) {
-               SpecimenRow row = state.getSpecimenRow();
+       protected void firstPass(SpecimenCdmExcelImportState state) {
+               SpecimenRow row = state.getCurrentRow();
                
                //basis of record
                DerivedUnitType type = DerivedUnitType.valueOf2(row.getBasisOfRecord());
                if (type == null){
-                       String message = "%s is not a valid BasisOfRecord. 'Unknown' is used instead.";
-                       message = String.format(message, row.getBasisOfRecord());
+                       String message = "%s is not a valid BasisOfRecord. 'Unknown' is used instead in line %d.";
+                       message = String.format(message, row.getBasisOfRecord(), state.getCurrentLine());
                        logger.warn(message);
                        type = DerivedUnitType.DerivedUnit;
                }
@@ -310,6 +274,7 @@ public class SpecimenCdmExcelImport  extends ExcelImporterBase<SpecimenCdmExcelI
 //             facade.setSex(row.get)
                handleExactLocation(facade, row, state);
                facade.setCollector(getOrMakeAgent(state, row.getCollectors()));
+               facade.setPrimaryCollector(getOrMakePrimaryCollector(facade, row.getPrimaryCollector(), state));
                handleAbsoluteElevation(facade, row, state);
                
                
@@ -325,7 +290,7 @@ public class SpecimenCdmExcelImport  extends ExcelImporterBase<SpecimenCdmExcelI
 //                     facade.innerDerivedUnit().addSpecimenTypeDesignation(designation);
                }
                handleDeterminations(state, row, facade);
-               handleExtensions(facade,row, state);
+               handleExtensions(facade.innerDerivedUnit(),row, state);
                for (String note : row.getUnitNotes()){
                        Annotation annotation = Annotation.NewInstance(note, AnnotationType.EDITORIAL(), Language.DEFAULT());
                        facade.addAnnotation(annotation);
@@ -333,7 +298,7 @@ public class SpecimenCdmExcelImport  extends ExcelImporterBase<SpecimenCdmExcelI
                
                //save
                getOccurrenceService().save(facade.innerDerivedUnit());
-               return true;
+               return;
        }
 
        private void handleAbsoluteElevation(DerivedUnitFacade facade, SpecimenRow row, SpecimenCdmExcelImportState state) {
@@ -350,7 +315,7 @@ public class SpecimenCdmExcelImport  extends ExcelImporterBase<SpecimenCdmExcelI
                        int value = Integer.valueOf(altitude);
                        facade.setAbsoluteElevation(value);
                } catch (NumberFormatException e) {
-                       String message = "Absolute elevation / Altitude '%s' is not an integer number in line %d";
+                       String message = "Absolute elevation / altitude '%s' is not an integer number in line %d";
                        message = String.format(message, row.getAltitude(), state.getCurrentLine());
                        logger.warn(message);
                        return;
@@ -392,28 +357,12 @@ public class SpecimenCdmExcelImport  extends ExcelImporterBase<SpecimenCdmExcelI
                
        }
 
-
-       private void handleExtensions(DerivedUnitFacade facade, SpecimenRow row, SpecimenCdmExcelImportState state) {
-               List<PostfixTerm> extensions = row.getExtensions();
-               
-               for (PostfixTerm exType : extensions){
-                       ExtensionType extensionType = state.getPostfixExtensionType(exType.postfix);
-                       
-                       Extension extension = Extension.NewInstance();
-                       extension.setType(extensionType);
-                       extension.setValue(exType.term);
-                       facade.innerDerivedUnit().addExtension(extension);
-               }
-               
-       }
-
-
        private void handleAreas(DerivedUnitFacade facade, SpecimenRow row, SpecimenCdmExcelImportState state) {
                List<PostfixTerm> areas = row.getLeveledAreas();
                
                for (PostfixTerm lArea : areas){
-                       String description = null;
-                       String abbrev = null;
+                       String description = lArea.term;
+                       String abbrev = lArea.term;
                        NamedAreaType type = null;
                        String key = lArea.postfix + "_" + lArea.term;
                        UUID areaUuid = state.getArea(key);
@@ -422,7 +371,7 @@ public class SpecimenCdmExcelImport  extends ExcelImporterBase<SpecimenCdmExcelI
                        TermMatchMode matchMode = state.getConfig().getAreaMatchMode();
                        NamedArea area = getNamedArea(state, areaUuid, lArea.term, description, abbrev, type, level, null, matchMode);
                        facade.addCollectingArea(area);
-                       if (areaUuid == null){
+                       if (areaUuid == null){ 
                                state.putArea(key, area.getUuid());
                        }
                }
@@ -436,9 +385,38 @@ public class SpecimenCdmExcelImport  extends ExcelImporterBase<SpecimenCdmExcelI
         */
        private void handleDeterminations(SpecimenCdmExcelImportState state,SpecimenRow row, DerivedUnitFacade facade) {
                boolean isFirstDetermination = true;
+               DeterminationLight commonDetermination = row.getCommonDetermination();
+               Taxon commonTaxon = null;
+               TaxonNameBase<?,?> commonName = null;
+               
+               boolean hasCommonTaxonInfo = commonDetermination == null ? false : commonDetermination.hasTaxonInformation();
+               if (hasCommonTaxonInfo && commonDetermination != null){
+                       TaxonBase<?> taxonBase = null;
+                       if (StringUtils.isNotBlank(commonDetermination.taxonUuid)){
+                               UUID taxonUuid = UUID.fromString(commonDetermination.taxonUuid);
+                               taxonBase = getTaxonService().find(taxonUuid);
+                               if (taxonBase == null){
+                                       String message = "Taxon for uuid %s not found in line %d.";
+                                       message = String.format(message, taxonUuid.toString(), state.getCurrentLine());
+                                       logger.warn(message);
+                               }
+                       }else{
+                               taxonBase = findBestMatchingTaxon(state, commonDetermination, state.getConfig().isCreateTaxonIfNotExists());
+                       }
+                       commonTaxon = getAcceptedTaxon(taxonBase);
+                       if (taxonBase != null){
+                               commonName = taxonBase.getName();
+                       }
+               }
+               
+               
                for (DeterminationLight determinationLight : row.getDetermination()){
-                       Taxon taxon = findBestMatchingTaxon(state, determinationLight, state.getConfig().isCreateTaxonIfNotExists());
-                       TaxonNameBase<?,?> name = findBestMatchingName(state, determinationLight);
+                       Taxon taxon;
+                       if (! hasCommonTaxonInfo){
+                               taxon = findBestMatchingTaxon(state, determinationLight, state.getConfig().isCreateTaxonIfNotExists());
+                       }else{
+                               taxon = commonTaxon;
+                       }
                        if (taxon != null){
                                getTaxonService().saveOrUpdate(taxon);
                                if (state.getConfig().isMakeIndividualAssociations() && taxon != null){
@@ -464,8 +442,19 @@ public class SpecimenCdmExcelImport  extends ExcelImporterBase<SpecimenCdmExcelI
                                        facade.addDetermination(detEvent);
                                }
                        }
-                       if (name != null){
-                               if (isFirstDetermination && state.getConfig().isFirstDeterminationIsStoredUnder()){
+                       
+                       if (isFirstDetermination && state.getConfig().isFirstDeterminationIsStoredUnder()){
+                               TaxonNameBase<?,?> name;
+                               
+                               if (!hasCommonTaxonInfo){
+                                       name = findBestMatchingName(state, determinationLight);
+                               }else{
+                                       if (commonName == null){
+                                               commonName = findBestMatchingName(state, commonDetermination);
+                                       }
+                                       name = commonName;
+                               }
+                               if (name != null){
                                        facade.setStoredUnder(name);
                                }
                        }
@@ -618,8 +607,10 @@ public class SpecimenCdmExcelImport  extends ExcelImporterBase<SpecimenCdmExcelI
 //             DeterminationModifier modifier = DeterminationModifier.NewInstance(term, label, labelAbbrev);
 //             determination.modifier;
                //notes
-               Annotation annotation = Annotation.NewInstance(determination.notes, AnnotationType.EDITORIAL(), Language.DEFAULT());
-               event.addAnnotation(annotation);
+               if (StringUtils.isNotEmpty(determination.notes)){
+                       Annotation annotation = Annotation.NewInstance(determination.notes, AnnotationType.EDITORIAL(), Language.DEFAULT());
+                       event.addAnnotation(annotation);
+               }
 
                return event;
        }
@@ -638,6 +629,34 @@ public class SpecimenCdmExcelImport  extends ExcelImporterBase<SpecimenCdmExcelI
                        return getOrMakeTeam(state, agents);
                }
        }
+       
+       private Person getOrMakePrimaryCollector(DerivedUnitFacade facade, String primaryCollector, SpecimenCdmExcelImportState state) {
+               if (StringUtils.isBlank(primaryCollector)){
+                       return null;
+               }
+               AgentBase<?> collector = facade.getCollector();
+               List<Person> collectors = new ArrayList<Person>();
+               if (collector.isInstanceOf(Team.class) ){
+                       Team team = CdmBase.deproxy(collector, Team.class);
+                       collectors.addAll(team.getTeamMembers());
+               }else if (collector.isInstanceOf(Person.class)){
+                       collectors.add(CdmBase.deproxy(collector, Person.class));
+               }else{
+                       throw new IllegalStateException("Unknown subclass of agentbase: " + collector.getClass().getName() );
+               }
+               for (Person person :collectors){
+                       if (primaryCollector.equalsIgnoreCase(person.getTitleCache())){
+                               return person;
+                       }
+                       if (primaryCollector.equalsIgnoreCase(person.getNomenclaturalTitle())){
+                               return person;
+                       }
+               }
+               String message = "Primary Agent '%s' could not be determined in collector(s) in line %d";
+               message = String.format(message, primaryCollector, state.getCurrentLine());
+               logger.warn(message);
+               return null;
+       }
 
        private Team getOrMakeTeam(SpecimenCdmExcelImportState state, List<String> agents) {
                String key = CdmUtils.concat("_", agents.toArray(new String[0]));
@@ -730,31 +749,33 @@ public class SpecimenCdmExcelImport  extends ExcelImporterBase<SpecimenCdmExcelI
 
 
        private void handleExactLocation(DerivedUnitFacade facade, SpecimenRow row, SpecimenCdmExcelImportState state) {
-               try {
                        
-                       //reference system
-                       ReferenceSystem refSys = null;
-                       if (StringUtils.isNotBlank(row.getReferenceSystem())){
-                               String strRefSys = row.getReferenceSystem().trim().replaceAll("\\s", "");
-                               UUID refUuid;
-                               try {
-                                       refSys = state.getTransformer().getReferenceSystemByKey(strRefSys);
-                                       if (refSys == null){
-                                               refUuid = state.getTransformer().getReferenceSystemUuid(strRefSys);
-                                               if (refUuid == null){
-                                                       String message = "Unknown reference system %s in line %d";
-                                                       message = String.format(message, strRefSys, state.getCurrentLine());
-                                                       logger.warn(message);
-                                               }
-                                               refSys = getReferenceSystem(state, refUuid, strRefSys, strRefSys, strRefSys, null);
+               //reference system
+               ReferenceSystem refSys = null;
+               if (StringUtils.isNotBlank(row.getReferenceSystem())){
+                       String strRefSys = row.getReferenceSystem().trim().replaceAll("\\s", "");
+                       UUID refUuid;
+                       try {
+                               refSys = state.getTransformer().getReferenceSystemByKey(strRefSys);
+                               if (refSys == null){
+                                       refUuid = state.getTransformer().getReferenceSystemUuid(strRefSys);
+                                       if (refUuid == null){
+                                               String message = "Unknown reference system %s in line %d";
+                                               message = String.format(message, strRefSys, state.getCurrentLine());
+                                               logger.warn(message);
                                        }
-                                       
-                               } catch (UndefinedTransformerMethodException e) {
-                                       throw new RuntimeException(e);
+                                       refSys = getReferenceSystem(state, refUuid, strRefSys, strRefSys, strRefSys, null);
                                }
+                               
+                       } catch (UndefinedTransformerMethodException e) {
+                               throw new RuntimeException(e);
                        }
-                       
-                       // lat/ long /error
+               }
+
+               
+               
+               // lat/ long /error
+               try {
                        String longitude = row.getLongitude();
                        String latitude = row.getLatitude();
                        Integer errorRadius = null;
@@ -777,6 +798,7 @@ public class SpecimenCdmExcelImport  extends ExcelImporterBase<SpecimenCdmExcelI
                }
                
                
+               
        }
 
 
@@ -814,23 +836,11 @@ public class SpecimenCdmExcelImport  extends ExcelImporterBase<SpecimenCdmExcelI
                        }
                }
        }
-               
-
-       
-       
-       protected boolean isInteger(String value){
-               try {
-                       Integer.valueOf(value);
-                       return true;
-               } catch (NumberFormatException e) {
-                       return false;
-               }
-       }
 
        @Override
-       protected boolean secondPass(SpecimenCdmExcelImportState state) {
+       protected void secondPass(SpecimenCdmExcelImportState state) {
                //no second path defined yet
-               return true;
+               return;
        }
 
 
@@ -845,6 +855,17 @@ public class SpecimenCdmExcelImport  extends ExcelImporterBase<SpecimenCdmExcelI
        }
        
        
+       /* (non-Javadoc)
+        * @see eu.etaxonomy.cdm.io.excel.common.ExcelTaxonOrSpecimenImportBase#createDataHolderRow()
+        */
+       @Override
+       protected SpecimenRow createDataHolderRow() {
+               return new SpecimenRow();
+       }
+
+
+       
+       
        /* (non-Javadoc)
         * @see eu.etaxonomy.cdm.io.common.CdmIoBase#doCheck(eu.etaxonomy.cdm.io.common.IoStateBase)
         */