working on duplication detection/arbitration
authorn.hoffmann <n.hoffmann@localhost>
Thu, 3 Sep 2009 07:49:49 +0000 (07:49 +0000)
committern.hoffmann <n.hoffmann@localhost>
Thu, 3 Sep 2009 07:49:49 +0000 (07:49 +0000)
taxeditor-editor/src/main/java/eu/etaxonomy/taxeditor/editor/DuplicateArbitrator.java
taxeditor-editor/src/main/java/eu/etaxonomy/taxeditor/editor/GroupedComposite.java
taxeditor-editor/src/main/java/eu/etaxonomy/taxeditor/editor/MultiPageTaxonEditor.java
taxeditor-editor/src/main/java/eu/etaxonomy/taxeditor/editor/MultiPageTaxonEditorDataChangeBehaviour.java
taxeditor-editor/src/main/java/eu/etaxonomy/taxeditor/editor/TaxonEditorInput.java

index 02a5f399d4f7759287b352b8d13dad43cf7c5abd..830b3931a4b511c18ed83e9bdbbe36e961c09c69 100644 (file)
 package eu.etaxonomy.taxeditor.editor;
 
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 import java.util.Set;
 
 import org.apache.log4j.Logger;
 
 import eu.etaxonomy.cdm.api.service.ICommonService;
 import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
+import eu.etaxonomy.cdm.model.agent.TeamOrPersonBase;
 import eu.etaxonomy.cdm.model.name.NonViralName;
 import eu.etaxonomy.cdm.model.name.TaxonNameBase;
 import eu.etaxonomy.cdm.model.reference.ReferenceBase;
-import eu.etaxonomy.cdm.model.reference.StrictReferenceBase;
 import eu.etaxonomy.cdm.model.taxon.TaxonBase;
+import eu.etaxonomy.cdm.strategy.match.DefaultMatchStrategy;
+import eu.etaxonomy.cdm.strategy.match.IMatchStrategy;
 import eu.etaxonomy.cdm.strategy.match.MatchException;
+import eu.etaxonomy.cdm.strategy.match.MatchMode;
 import eu.etaxonomy.taxeditor.editor.name.NameComposite;
 import eu.etaxonomy.taxeditor.editor.name.TaxonNameEditor;
 import eu.etaxonomy.taxeditor.store.CdmStore;
@@ -48,14 +49,20 @@ public class DuplicateArbitrator {
         */
        private MultiPageTaxonEditor editor;
        private TaxonNameEditor nameEditor;
-       private Set<NameComposite<TaxonBase>> dirtyNames;
+       private Set<NameComposite<TaxonBase>> dirtyNameComposites;
        
-       private Map<TaxonBase, ReferenceBase> duplicateReferences;
+       private List<ReferenceBase> duplicateReferences;
 
-       private Map<TaxonBase, TaxonNameBase> duplicateNames;
+       private List<TaxonNameBase> duplicateNames;
 
+       private List<TeamOrPersonBase> duplicateCombinationAuthorTeams;
+       private List<TeamOrPersonBase> duplicateExCombinationAuthorTeams;
+       private List<TeamOrPersonBase> duplicateBasionymAuthorTeams;
+       private List<TeamOrPersonBase> duplicateExBasionymAuthorTeams;
+       
        private ICommonService commonService;
 
+
        /**
         * @param adaptableObject
         */
@@ -66,8 +73,12 @@ public class DuplicateArbitrator {
                
                nameEditor = (TaxonNameEditor) editor.getPage(Page.NAME);
                
-               duplicateReferences = new HashMap<TaxonBase, ReferenceBase>();
-               duplicateNames = new HashMap<TaxonBase, TaxonNameBase>();
+               duplicateReferences = new ArrayList<ReferenceBase>();
+               duplicateNames = new ArrayList<TaxonNameBase>();
+               duplicateCombinationAuthorTeams = new ArrayList<TeamOrPersonBase>();
+               duplicateExCombinationAuthorTeams = new ArrayList<TeamOrPersonBase>();
+               duplicateBasionymAuthorTeams = new ArrayList<TeamOrPersonBase>();
+               duplicateExBasionymAuthorTeams = new ArrayList<TeamOrPersonBase>();
        }
 
        /**
@@ -77,107 +88,214 @@ public class DuplicateArbitrator {
                // iterate over all names that were edited
                for(NameComposite composite : nameEditor.getDirtyNames()){
                        logger.warn("Found " + composite + " with possible duplicates");
+                                               
+                       NonViralName nonViralName = (NonViralName) composite.getParsedName();
                        
-                       // since we are dealing with NameComposites getData should always return a TaxonBase
-                       // also we do not want to handle viral names at the moment
-//                     NonViralName name = (NonViralName) ((TaxonBase) composite.getData()).getName();
-                       
-                       TaxonBase taxonBase = HibernateProxyHelper.deproxy(composite.getData(), TaxonBase.class);
-                       
-                       // TODO decide what entities are candidates for duplicate detection
-                       checkDuplicateLatinNames(taxonBase);
-                       checkDuplicateAuthors(taxonBase);
-                       checkDuplicateNomenclaturalReference(taxonBase);
+
+                       duplicateNames = findMatchingLatinNames(nonViralName);
+                       duplicateCombinationAuthorTeams = findMatchingAuthors((TeamOrPersonBase) nonViralName.getCombinationAuthorTeam());
+                       duplicateExCombinationAuthorTeams = findMatchingAuthors((TeamOrPersonBase) nonViralName.getExCombinationAuthorTeam());
+                       duplicateBasionymAuthorTeams = findMatchingAuthors((TeamOrPersonBase) nonViralName.getBasionymAuthorTeam());
+                       duplicateExBasionymAuthorTeams = findMatchingAuthors((TeamOrPersonBase) nonViralName.getExBasionymAuthorTeam());
+                       duplicateReferences = findMatchingNomenclaturalReference(nonViralName.getNomenclaturalReference());
                        
+                       saveNameElements(composite);
                        
+                       emptyDuplicateSets();
                }
-               
-               solveDuplicates();
-               
+       }
+
+       /**
+        * 
+        */
+       private void emptyDuplicateSets() {
+               duplicateReferences.clear();
+               duplicateCombinationAuthorTeams.clear();
+               duplicateExCombinationAuthorTeams.clear();
+               duplicateBasionymAuthorTeams.clear();
+               duplicateExBasionymAuthorTeams.clear();
+               duplicateNames.clear();
        }
 
        /**
         * Provides strategies to solve found duplicates
         * This can either happen automatically or through user input
         */
-       private void solveDuplicates() {
-               /* 
-                * TODO first idea that comes to mind would be to present the user 
-                * a dialog with all possible duplicates and let her mark which entities 
-                * she wants to use
-                * 
-                * If we have sophisticated equals methods that guarantee full equality and 
-                * there is only one match of an entity we might want to resolve the duplication
-                * automatically.  
+       private void saveNameElements(NameComposite composite) {
+               
+               resolveDuplicateNames(composite);
+               
+               resolveAllDuplicateAuthors(composite);
+                               
+               resolveDuplicateReferences(composite);
+               
+               // FIXME this is a workaround, because title cache does not get generated correctly in library
+               // remove once #964 is closed
+               composite.getTaxon().setTitleCache((composite.getTaxon().generateTitle()));
+       }
+       
+       /**
+        * @param composite
+        */
+       private void resolveDuplicateNames(NameComposite composite) {
+               
+               /* When creating a new taxon editor, a taxon with an empty name is created.
+                * We have to delete this empty name explicitly from the session, otherwise it
+                * will be persisted into the database
                 */             
+               if(composite.getName().getFullTitleCache().length() == 0){
+                       editor.getConversationHolder().delete(composite.getName());
+               }
+               
+               if(duplicateNames.size() == 0){
+                       // No matches were found for the name part. We can safely 
+                       // replace the taxons name with the parsed name
+                       
+                       composite.setName(composite.getParsedName());
+               }else if (duplicateNames.size() == 1){
+                       composite.setName(duplicateNames.iterator().next());
+               }else{
+               
+                       // do stuff
+               }
                
                // debug
-               for(ReferenceBase reference : duplicateReferences.values()){
-                       logger.warn(reference);
+               for(TaxonNameBase name : duplicateNames){
+                       logger.warn(name.getFullTitleCache());
                }
-               for(TaxonNameBase name : duplicateNames.values()){
-                       logger.warn(name);
+
+       }
+
+       /**
+        * @param composite
+        */
+       private void resolveDuplicateReferences(NameComposite composite) {
+               if(duplicateReferences.size() == 0){
+                       // nomatches found for the reference we replace the reference with the parsed one
+                       composite.getName().setNomenclaturalReference(composite.getParsedName().getNomenclaturalReference());
+               }else if(duplicateReferences.size() == 1){
+                       // exactly one match. We assume that the user wants this reference
+                       composite.getName().setNomenclaturalReference(duplicateReferences.iterator().next());
+               }else{
+                       // do stuff
                }
                
+               // debug
+               for(ReferenceBase reference : duplicateReferences){
+                       logger.info(reference.getTitleCache());
+               }
        }
 
+
+
        /**
-        * @param name
+        * @param composite
         */
-       private void checkDuplicateNomenclaturalReference(TaxonBase taxonBase) {
+       private void resolveAllDuplicateAuthors(NameComposite composite) {
+               NonViralName name = HibernateProxyHelper.deproxy(composite.getName(), NonViralName.class);
+               NonViralName parsedName = HibernateProxyHelper.deproxy(composite.getParsedName(), NonViralName.class);
                
-               NonViralName name = getName(taxonBase);
                
-               try{
-                       StrictReferenceBase referenceBase = (StrictReferenceBase) name.getNomenclaturalReference();
-                       
-                       List<StrictReferenceBase> matches = commonService.findMatching(referenceBase, null);
-                       
-//                     // query datasource for the reference
-//                     List<ReferenceBase> result = CdmStore.getReferenceService().getReferencesByTitle(referenceBase.getTitleCache());
-                       
-                       // if query delivers results, place possible duplicate in map
-                       for(ReferenceBase duplicateReference : matches){
-                               duplicateReferences.put(taxonBase, duplicateReference);
-                       }
-               }catch(NullPointerException e){
-                       logger.warn("Name has no nomenclatural reference");
-               } catch (MatchException e) {
-                       // TODO Auto-generated catch block
-                       e.printStackTrace();
+               if(duplicateCombinationAuthorTeams.size() == 0){
+                       name.setCombinationAuthorTeam(parsedName.getCombinationAuthorTeam());
+               }else if(duplicateCombinationAuthorTeams.size() == 1){
+                       name.setCombinationAuthorTeam(duplicateCombinationAuthorTeams.iterator().next());
+               }else{
+                       // do stuff
+               }
+               
+               if(duplicateExCombinationAuthorTeams.size() == 0){
+                       name.setExCombinationAuthorTeam(parsedName.getExCombinationAuthorTeam());
+               }else if(duplicateExCombinationAuthorTeams.size() == 1){
+                       name.setExCombinationAuthorTeam(duplicateExCombinationAuthorTeams.iterator().next());
+               }else{
+                       // do stuff
+               }
+               
+               if(duplicateBasionymAuthorTeams.size() == 0){
+                       name.setBasionymAuthorTeam(parsedName.getBasionymAuthorTeam());
+               }else if(duplicateBasionymAuthorTeams.size() == 1){
+                       name.setBasionymAuthorTeam(duplicateBasionymAuthorTeams.iterator().next());
+               }else{
+                       // do stuff
+               }
+               
+               if(duplicateExBasionymAuthorTeams.size() == 0){
+                       name.setExBasionymAuthorTeam(parsedName.getExBasionymAuthorTeam());
+               }else if(duplicateExBasionymAuthorTeams.size() == 1){
+                       name.setExBasionymAuthorTeam(duplicateExBasionymAuthorTeams.iterator().next());
+               }else{
+                       // do stuff
                }
                
+               
+               // debug
+               for(TeamOrPersonBase authorTeam : duplicateCombinationAuthorTeams){
+                       logger.info(authorTeam.getTitleCache());
+               }
+               // debug
+               for(TeamOrPersonBase authorTeam : duplicateExCombinationAuthorTeams){
+                       logger.info(authorTeam.getTitleCache());
+               }
+               // debug
+               for(TeamOrPersonBase authorTeam : duplicateBasionymAuthorTeams){
+                       logger.info(authorTeam.getTitleCache());
+               }
+               // debug
+               for(TeamOrPersonBase authorTeam : duplicateExBasionymAuthorTeams){
+                       logger.info(authorTeam.getTitleCache());
+               }
        }
 
+
        /**
         * @param name
         */
-       private void checkDuplicateAuthors(TaxonBase taxonBase) {
-               // see checkDuplicateNomenclaturalReference for implementation
+       private List<ReferenceBase> findMatchingNomenclaturalReference(ReferenceBase referenceBase) {
+               if(referenceBase == null) return new ArrayList<ReferenceBase>();
+               try{
+                       return commonService.findMatching(referenceBase, null);
+               }catch (MatchException e) {
+                       logger.error("Error finding matching references", e);
+               }
+               return null;
        }
 
        /**
         * @param name
         */
-       private void checkDuplicateLatinNames(TaxonBase taxonBase) {
-               NonViralName name = getName(taxonBase);
-               
-               List<NonViralName> result = new ArrayList(); //commonService.findMatching(name, null);
+       private List<TeamOrPersonBase> findMatchingAuthors(TeamOrPersonBase authorTeam) {
+
+               if(authorTeam == null){
+                       return new ArrayList<TeamOrPersonBase>();
+               }
                
-               for(Object object: result ){
-                       TaxonNameBase duplicateName = HibernateProxyHelper.deproxy(object, TaxonNameBase.class);
-                       duplicateNames.put(taxonBase, duplicateName);
+               try{
+                       return commonService.findMatching(authorTeam, null);
+               }catch (MatchException e) {
+                       logger.error("Error finding matching authors", e);
                }
+               return null;
        }
-       
+
        /**
-        * Helper method to get the NonViralName of a taxon base.
-        * 
-        * @param taxonBase
-        * @return
+        * @param name
         */
-       private NonViralName getName(TaxonBase taxonBase){
-               return HibernateProxyHelper.deproxy(taxonBase.getName(), NonViralName.class);
-       }
+       private List<TaxonNameBase> findMatchingLatinNames(TaxonNameBase taxonNameBase) {
 
+               try {
+                       IMatchStrategy strategy = DefaultMatchStrategy.NewInstance(NonViralName.class);
+                       strategy.setMatchMode("nomenclaturalReference", MatchMode.IGNORE);
+                       strategy.setMatchMode("combinationAuthorTeam", MatchMode.IGNORE);
+                       strategy.setMatchMode("exCombinationAuthorTeam", MatchMode.IGNORE);
+                       strategy.setMatchMode("basionymAuthorTeam", MatchMode.IGNORE);
+                       strategy.setMatchMode("exBasionymAuthorTeam", MatchMode.IGNORE);
+                       
+                       return commonService.findMatching(taxonNameBase, strategy);
+                       
+               } catch (MatchException e) {
+                       logger.error("Error finding matching names", e);
+               }
+               return null;
+       }
 }
index 7874b41b4ae8a8b99811b63927599f2714f08f70..27aeb7295e45bbeb10e1d1088eab04e284744948 100644 (file)
@@ -467,33 +467,6 @@ abstract public class GroupedComposite extends Composite implements IHasProperty
                nonEditableInfoHover.setText(nonEditableHoverText);\r
        }\r
        \r
-       /**\r
-        * If the user entering text requires parsing, call this method and override\r
-        * the method parse().\r
-        */\r
-       protected void createParser() {\r
-               if (textViewer != null) {\r
-                       parseListener = new ParseListener() {\r
-                               @Override\r
-                               public void parse(String text) {\r
-                                       GroupedComposite.this.parse(text);\r
-                               }\r
-                       };\r
-                       textViewer.getTextWidget().addModifyListener(parseListener);\r
-                       \r
-               } else {\r
-                       logger.warn("Can't create parser because textViewer has not been initalized.");\r
-               }\r
-       }\r
-\r
-       /**\r
-        * Implement in derived classes\r
-        * \r
-        * @param text\r
-        */\r
-       protected abstract void parse(String text);\r
-\r
-       \r
        /**\r
         * If the user hitting carriage return should cause something to happen -\r
         * i.e. the creation of a new composite - call this method and override\r
index b1119125ce65ad86bddbcd74d139a484d920e9c4..09543016bba83d022a95ddade33d6d18695ffd67 100644 (file)
@@ -119,19 +119,18 @@ public class MultiPageTaxonEditor extends FormEditor implements IConversationEna
        @Override\r
        public void doSave(IProgressMonitor monitor) {\r
 \r
+               if( ! conversation.isBound()){\r
+                       conversation.bind();\r
+               }\r
+               \r
                //handle existing names and authors\r
                DuplicateArbitrator duplicateArbitrator = (DuplicateArbitrator) getAdapter(DuplicateArbitrator.class);\r
                \r
                if(duplicateArbitrator != null){\r
                        // disable for now because of transaction problems.\r
-//                     duplicateArbitrator.arbitrate();\r
+                       duplicateArbitrator.arbitrate();\r
                }\r
-               \r
-               \r
-               if( ! conversation.isBound()){\r
-                       conversation.bind();\r
-               }\r
-               \r
+\r
                // commit the conversation and start a new transaction immediately\r
                conversation.commit(true);\r
                \r
index fb42f6a3d5587df150083c4acae3a98ff8db4c21..866d3cb5197493b992d4f794b5122b75e4509034 100644 (file)
@@ -14,7 +14,7 @@ import java.util.Vector;
 import org.apache.log4j.Logger;
 
 import eu.etaxonomy.cdm.model.name.TaxonNameBase;
-import eu.etaxonomy.cdm.model.taxon.Taxon;
+import eu.etaxonomy.cdm.model.taxon.TaxonNode;
 import eu.etaxonomy.cdm.persistence.hibernate.CdmDataChangeEvent;
 import eu.etaxonomy.cdm.persistence.hibernate.CdmDataChangeMap;
 import eu.etaxonomy.cdm.persistence.hibernate.CdmDataChangeEvent.EventType;
@@ -67,8 +67,11 @@ public class MultiPageTaxonEditorDataChangeBehaviour extends AbstractDataChangeB
        public void reactOnDelete(Vector<CdmDataChangeEvent> events){
                for(CdmDataChangeEvent event : events){
                        // close open editors
-                       if((event.getEntity() instanceof Taxon) 
-                                       && input.getTaxon().equals(event.getEntity())){
+                       if(event.getEntity() instanceof TaxonNode){
+                               logger.warn("taxon node");
+                       }
+                       if((event.getEntity() instanceof TaxonNode) 
+                                       && input.getTaxonNode().equals(event.getEntity())){
                                EditorUtil.close(source);
                                logger.debug("Closing open editor for deleted taxon.");
                        }
index 56012b8ab3ecbb4a4f0989a90f27be1af918deb0..5785c04f8f58dcd1893bb4dcde9ecec12741daf5 100644 (file)
@@ -106,8 +106,8 @@ public class TaxonEditorInput implements IEditorInput, IConversationEnabled, IPe
                        // add new taxon as root node
                        TaxonomicTree tree = CdmStore.getTaxonService().getTaxonomicTreeByUuid(parentNodeUuid);
                        
-                       newTaxon = Taxon.NewInstance(name, CdmStore.getDefault().getDefaultSec());
-                       newTaxonNode = tree.addRoot(newTaxon, null);
+                       newTaxon = Taxon.NewInstance(name, tree.getReference());
+                       newTaxonNode = tree.addRoot(newTaxon, null, null);
                }else{
                        // add new taxon as child of another taxon
                        newTaxon = Taxon.NewInstance(name, parentTaxonNode.getTaxon().getSec());