2 * Copyright (C) 2007 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
6 * The contents of this file are subject to the Mozilla Public License Version 1.1
7 * See LICENSE.TXT at the top of this package for the full license terms.
10 package eu
.etaxonomy
.taxeditor
.editor
;
12 import java
.util
.ArrayList
;
13 import java
.util
.List
;
16 import org
.apache
.log4j
.Logger
;
18 import eu
.etaxonomy
.cdm
.api
.service
.ICommonService
;
19 import eu
.etaxonomy
.cdm
.hibernate
.HibernateProxyHelper
;
20 import eu
.etaxonomy
.cdm
.model
.agent
.TeamOrPersonBase
;
21 import eu
.etaxonomy
.cdm
.model
.name
.NonViralName
;
22 import eu
.etaxonomy
.cdm
.model
.name
.TaxonNameBase
;
23 import eu
.etaxonomy
.cdm
.model
.reference
.ReferenceBase
;
24 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonBase
;
25 import eu
.etaxonomy
.cdm
.strategy
.match
.DefaultMatchStrategy
;
26 import eu
.etaxonomy
.cdm
.strategy
.match
.IMatchStrategy
;
27 import eu
.etaxonomy
.cdm
.strategy
.match
.MatchException
;
28 import eu
.etaxonomy
.cdm
.strategy
.match
.MatchMode
;
29 import eu
.etaxonomy
.taxeditor
.editor
.name
.NameComposite
;
30 import eu
.etaxonomy
.taxeditor
.editor
.name
.TaxonNameEditor
;
31 import eu
.etaxonomy
.taxeditor
.store
.CdmStore
;
34 * This class is supposed to handle possible duplications of cdm entities
35 * for a specific editor
37 * TODO break dependency to editor
44 public class DuplicateArbitrator
{
45 private static final Logger logger
= Logger
.getLogger(DuplicateArbitrator
.class);
48 * The editor this arbitrator should manage possible duplicates for
50 private MultiPageTaxonEditor editor
;
51 private TaxonNameEditor nameEditor
;
52 private Set
<NameComposite
<TaxonBase
>> dirtyNameComposites
;
54 private List
<ReferenceBase
> duplicateReferences
;
56 private List
<TaxonNameBase
> duplicateNames
;
58 private List
<TeamOrPersonBase
> duplicateCombinationAuthorTeams
;
59 private List
<TeamOrPersonBase
> duplicateExCombinationAuthorTeams
;
60 private List
<TeamOrPersonBase
> duplicateBasionymAuthorTeams
;
61 private List
<TeamOrPersonBase
> duplicateExBasionymAuthorTeams
;
63 private ICommonService commonService
;
67 * @param adaptableObject
69 public DuplicateArbitrator(MultiPageTaxonEditor editor
) {
72 commonService
= CdmStore
.getCommonService();
74 nameEditor
= (TaxonNameEditor
) editor
.getPage(Page
.NAME
);
76 duplicateReferences
= new ArrayList
<ReferenceBase
>();
77 duplicateNames
= new ArrayList
<TaxonNameBase
>();
78 duplicateCombinationAuthorTeams
= new ArrayList
<TeamOrPersonBase
>();
79 duplicateExCombinationAuthorTeams
= new ArrayList
<TeamOrPersonBase
>();
80 duplicateBasionymAuthorTeams
= new ArrayList
<TeamOrPersonBase
>();
81 duplicateExBasionymAuthorTeams
= new ArrayList
<TeamOrPersonBase
>();
85 * Provide strategies on how to handle possible duplications
87 public void arbitrate() {
88 // iterate over all names that were edited
89 for(NameComposite composite
: nameEditor
.getDirtyNames()){
90 logger
.warn("Found " + composite
+ " with possible duplicates");
92 NonViralName nonViralName
= (NonViralName
) composite
.getParsedName();
95 duplicateNames
= findMatchingLatinNames(nonViralName
);
96 duplicateCombinationAuthorTeams
= findMatchingAuthors((TeamOrPersonBase
) nonViralName
.getCombinationAuthorTeam());
97 duplicateExCombinationAuthorTeams
= findMatchingAuthors((TeamOrPersonBase
) nonViralName
.getExCombinationAuthorTeam());
98 duplicateBasionymAuthorTeams
= findMatchingAuthors((TeamOrPersonBase
) nonViralName
.getBasionymAuthorTeam());
99 duplicateExBasionymAuthorTeams
= findMatchingAuthors((TeamOrPersonBase
) nonViralName
.getExBasionymAuthorTeam());
100 duplicateReferences
= findMatchingNomenclaturalReference(nonViralName
.getNomenclaturalReference());
102 saveNameElements(composite
);
104 emptyDuplicateSets();
111 private void emptyDuplicateSets() {
112 duplicateReferences
.clear();
113 duplicateCombinationAuthorTeams
.clear();
114 duplicateExCombinationAuthorTeams
.clear();
115 duplicateBasionymAuthorTeams
.clear();
116 duplicateExBasionymAuthorTeams
.clear();
117 duplicateNames
.clear();
121 * Provides strategies to solve found duplicates
122 * This can either happen automatically or through user input
124 private void saveNameElements(NameComposite composite
) {
126 resolveDuplicateNames(composite
);
128 resolveAllDuplicateAuthors(composite
);
130 resolveDuplicateReferences(composite
);
132 // FIXME this is a workaround, because title cache does not get generated correctly in library
133 // remove once #964 is closed
134 composite
.getTaxon().setTitleCache((composite
.getTaxon().generateTitle()));
140 private void resolveDuplicateNames(NameComposite composite
) {
142 /* When creating a new taxon editor, a taxon with an empty name is created.
143 * We have to delete this empty name explicitly from the session, otherwise it
144 * will be persisted into the database
146 if(composite
.getName().getFullTitleCache().length() == 0){
147 editor
.getConversationHolder().delete(composite
.getName());
150 if(duplicateNames
.size() == 0){
151 // No matches were found for the name part. We can safely
152 // replace the taxons name with the parsed name
154 composite
.setName(composite
.getParsedName());
155 }else if (duplicateNames
.size() == 1){
156 composite
.setName(duplicateNames
.iterator().next());
163 for(TaxonNameBase name
: duplicateNames
){
164 logger
.warn(name
.getFullTitleCache());
172 private void resolveDuplicateReferences(NameComposite composite
) {
173 if(duplicateReferences
.size() == 0){
174 // nomatches found for the reference we replace the reference with the parsed one
175 composite
.getName().setNomenclaturalReference(composite
.getParsedName().getNomenclaturalReference());
176 }else if(duplicateReferences
.size() == 1){
177 // exactly one match. We assume that the user wants this reference
178 composite
.getName().setNomenclaturalReference(duplicateReferences
.iterator().next());
184 for(ReferenceBase reference
: duplicateReferences
){
185 logger
.info(reference
.getTitleCache());
194 private void resolveAllDuplicateAuthors(NameComposite composite
) {
195 NonViralName name
= HibernateProxyHelper
.deproxy(composite
.getName(), NonViralName
.class);
196 NonViralName parsedName
= HibernateProxyHelper
.deproxy(composite
.getParsedName(), NonViralName
.class);
199 if(duplicateCombinationAuthorTeams
.size() == 0){
200 name
.setCombinationAuthorTeam(parsedName
.getCombinationAuthorTeam());
201 }else if(duplicateCombinationAuthorTeams
.size() == 1){
202 name
.setCombinationAuthorTeam(duplicateCombinationAuthorTeams
.iterator().next());
207 if(duplicateExCombinationAuthorTeams
.size() == 0){
208 name
.setExCombinationAuthorTeam(parsedName
.getExCombinationAuthorTeam());
209 }else if(duplicateExCombinationAuthorTeams
.size() == 1){
210 name
.setExCombinationAuthorTeam(duplicateExCombinationAuthorTeams
.iterator().next());
215 if(duplicateBasionymAuthorTeams
.size() == 0){
216 name
.setBasionymAuthorTeam(parsedName
.getBasionymAuthorTeam());
217 }else if(duplicateBasionymAuthorTeams
.size() == 1){
218 name
.setBasionymAuthorTeam(duplicateBasionymAuthorTeams
.iterator().next());
223 if(duplicateExBasionymAuthorTeams
.size() == 0){
224 name
.setExBasionymAuthorTeam(parsedName
.getExBasionymAuthorTeam());
225 }else if(duplicateExBasionymAuthorTeams
.size() == 1){
226 name
.setExBasionymAuthorTeam(duplicateExBasionymAuthorTeams
.iterator().next());
233 for(TeamOrPersonBase authorTeam
: duplicateCombinationAuthorTeams
){
234 logger
.info(authorTeam
.getTitleCache());
237 for(TeamOrPersonBase authorTeam
: duplicateExCombinationAuthorTeams
){
238 logger
.info(authorTeam
.getTitleCache());
241 for(TeamOrPersonBase authorTeam
: duplicateBasionymAuthorTeams
){
242 logger
.info(authorTeam
.getTitleCache());
245 for(TeamOrPersonBase authorTeam
: duplicateExBasionymAuthorTeams
){
246 logger
.info(authorTeam
.getTitleCache());
254 private List
<ReferenceBase
> findMatchingNomenclaturalReference(ReferenceBase referenceBase
) {
255 if(referenceBase
== null) return new ArrayList
<ReferenceBase
>();
257 return commonService
.findMatching(referenceBase
, null);
258 }catch (MatchException e
) {
259 logger
.error("Error finding matching references", e
);
267 private List
<TeamOrPersonBase
> findMatchingAuthors(TeamOrPersonBase authorTeam
) {
269 if(authorTeam
== null){
270 return new ArrayList
<TeamOrPersonBase
>();
274 return commonService
.findMatching(authorTeam
, null);
275 }catch (MatchException e
) {
276 logger
.error("Error finding matching authors", e
);
284 private List
<TaxonNameBase
> findMatchingLatinNames(TaxonNameBase taxonNameBase
) {
287 IMatchStrategy strategy
= DefaultMatchStrategy
.NewInstance(NonViralName
.class);
288 strategy
.setMatchMode("nomenclaturalReference", MatchMode
.IGNORE
);
289 strategy
.setMatchMode("combinationAuthorTeam", MatchMode
.IGNORE
);
290 strategy
.setMatchMode("exCombinationAuthorTeam", MatchMode
.IGNORE
);
291 strategy
.setMatchMode("basionymAuthorTeam", MatchMode
.IGNORE
);
292 strategy
.setMatchMode("exBasionymAuthorTeam", MatchMode
.IGNORE
);
294 return commonService
.findMatching(taxonNameBase
, strategy
);
296 } catch (MatchException e
) {
297 logger
.error("Error finding matching names", e
);