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");
96 public void arbitrate(NameComposite composite
){
97 NonViralName nonViralName
= (NonViralName
) composite
.getParsedName();
99 duplicateNames
= findMatchingLatinNames(nonViralName
);
100 duplicateCombinationAuthorTeams
= findMatchingAuthors((TeamOrPersonBase
) nonViralName
.getCombinationAuthorTeam());
101 duplicateExCombinationAuthorTeams
= findMatchingAuthors((TeamOrPersonBase
) nonViralName
.getExCombinationAuthorTeam());
102 duplicateBasionymAuthorTeams
= findMatchingAuthors((TeamOrPersonBase
) nonViralName
.getBasionymAuthorTeam());
103 duplicateExBasionymAuthorTeams
= findMatchingAuthors((TeamOrPersonBase
) nonViralName
.getExBasionymAuthorTeam());
104 duplicateReferences
= findMatchingNomenclaturalReference(nonViralName
.getNomenclaturalReference());
106 saveNameElements(composite
);
108 emptyDuplicateSets();
114 private void emptyDuplicateSets() {
115 duplicateReferences
.clear();
116 duplicateCombinationAuthorTeams
.clear();
117 duplicateExCombinationAuthorTeams
.clear();
118 duplicateBasionymAuthorTeams
.clear();
119 duplicateExBasionymAuthorTeams
.clear();
120 duplicateNames
.clear();
124 * Provides strategies to solve found duplicates
125 * This can either happen automatically or through user input
127 private void saveNameElements(NameComposite composite
) {
129 resolveDuplicateNames(composite
);
131 resolveAllDuplicateAuthors(composite
);
133 resolveDuplicateReferences(composite
);
135 // FIXME this is a workaround, because title cache does not get generated correctly in library
136 // remove once #964 is closed
137 composite
.getTaxon().setTitleCache((composite
.getTaxon().generateTitle()));
143 private void resolveDuplicateNames(NameComposite composite
) {
145 /* When creating a new taxon editor, a taxon with an empty name is created.
146 * We have to delete this empty name explicitly from the session, otherwise it
147 * will be persisted into the database
149 if(composite
.getName().getFullTitleCache().length() == 0){
150 editor
.getConversationHolder().delete(composite
.getName());
153 if(duplicateNames
.size() == 0){
154 // No matches were found for the name part. We can safely
155 // replace the taxons name with the parsed name
157 composite
.setName(composite
.getParsedName());
158 }else if (duplicateNames
.size() == 1){
159 composite
.setName(duplicateNames
.iterator().next());
161 // FIXME TODO resolve multiple duplications. Use first match for a start
162 composite
.setName(duplicateNames
.iterator().next());
166 for(TaxonNameBase name
: duplicateNames
){
167 logger
.info(name
.getFullTitleCache());
175 private void resolveDuplicateReferences(NameComposite composite
) {
176 if(duplicateReferences
.size() == 0){
177 // nomatches found for the reference we replace the reference with the parsed one
178 composite
.getName().setNomenclaturalReference(composite
.getParsedName().getNomenclaturalReference());
179 }else if(duplicateReferences
.size() == 1){
180 // exactly one match. We assume that the user wants this reference
181 composite
.getName().setNomenclaturalReference(duplicateReferences
.iterator().next());
183 // FIXME TODO resolve multiple duplications. Use first match for a start
184 composite
.getName().setNomenclaturalReference(duplicateReferences
.iterator().next());
188 for(ReferenceBase reference
: duplicateReferences
){
189 logger
.info(reference
.getTitleCache());
198 private void resolveAllDuplicateAuthors(NameComposite composite
) {
199 NonViralName name
= HibernateProxyHelper
.deproxy(composite
.getName(), NonViralName
.class);
200 NonViralName parsedName
= HibernateProxyHelper
.deproxy(composite
.getParsedName(), NonViralName
.class);
203 if(duplicateCombinationAuthorTeams
.size() == 0){
204 name
.setCombinationAuthorTeam(parsedName
.getCombinationAuthorTeam());
205 }else if(duplicateCombinationAuthorTeams
.size() == 1){
206 name
.setCombinationAuthorTeam(duplicateCombinationAuthorTeams
.iterator().next());
208 // FIXME TODO resolve multiple duplications. Use first match for a start
209 name
.setCombinationAuthorTeam(duplicateCombinationAuthorTeams
.iterator().next());
212 if(duplicateExCombinationAuthorTeams
.size() == 0){
213 name
.setExCombinationAuthorTeam(parsedName
.getExCombinationAuthorTeam());
214 }else if(duplicateExCombinationAuthorTeams
.size() == 1){
215 name
.setExCombinationAuthorTeam(duplicateExCombinationAuthorTeams
.iterator().next());
217 // FIXME TODO resolve multiple duplications. Use first match for a start
218 name
.setExCombinationAuthorTeam(duplicateExCombinationAuthorTeams
.iterator().next());
221 if(duplicateBasionymAuthorTeams
.size() == 0){
222 name
.setBasionymAuthorTeam(parsedName
.getBasionymAuthorTeam());
223 }else if(duplicateBasionymAuthorTeams
.size() == 1){
224 name
.setBasionymAuthorTeam(duplicateBasionymAuthorTeams
.iterator().next());
226 // FIXME TODO resolve multiple duplications. Use first match for a start
227 name
.setBasionymAuthorTeam(duplicateBasionymAuthorTeams
.iterator().next());
230 if(duplicateExBasionymAuthorTeams
.size() == 0){
231 name
.setExBasionymAuthorTeam(parsedName
.getExBasionymAuthorTeam());
232 }else if(duplicateExBasionymAuthorTeams
.size() == 1){
233 name
.setExBasionymAuthorTeam(duplicateExBasionymAuthorTeams
.iterator().next());
235 // FIXME TODO resolve multiple duplications. Use first match for a start
236 name
.setExBasionymAuthorTeam(duplicateExBasionymAuthorTeams
.iterator().next());
241 for(TeamOrPersonBase authorTeam
: duplicateCombinationAuthorTeams
){
242 logger
.info(authorTeam
.getTitleCache());
245 for(TeamOrPersonBase authorTeam
: duplicateExCombinationAuthorTeams
){
246 logger
.info(authorTeam
.getTitleCache());
249 for(TeamOrPersonBase authorTeam
: duplicateBasionymAuthorTeams
){
250 logger
.info(authorTeam
.getTitleCache());
253 for(TeamOrPersonBase authorTeam
: duplicateExBasionymAuthorTeams
){
254 logger
.info(authorTeam
.getTitleCache());
262 private List
<ReferenceBase
> findMatchingNomenclaturalReference(ReferenceBase referenceBase
) {
263 if(referenceBase
== null) return new ArrayList
<ReferenceBase
>();
265 return commonService
.findMatching(referenceBase
, null);
266 }catch (MatchException e
) {
267 logger
.error("Error finding matching references", e
);
275 private List
<TeamOrPersonBase
> findMatchingAuthors(TeamOrPersonBase authorTeam
) {
277 if(authorTeam
== null){
278 return new ArrayList
<TeamOrPersonBase
>();
282 return commonService
.findMatching(authorTeam
, null);
283 }catch (MatchException e
) {
284 logger
.error("Error finding matching authors", e
);
292 private List
<TaxonNameBase
> findMatchingLatinNames(TaxonNameBase taxonNameBase
) {
295 IMatchStrategy strategy
= DefaultMatchStrategy
.NewInstance(NonViralName
.class);
296 strategy
.setMatchMode("nomenclaturalReference", MatchMode
.IGNORE
);
297 strategy
.setMatchMode("combinationAuthorTeam", MatchMode
.IGNORE
);
298 strategy
.setMatchMode("exCombinationAuthorTeam", MatchMode
.IGNORE
);
299 strategy
.setMatchMode("basionymAuthorTeam", MatchMode
.IGNORE
);
300 strategy
.setMatchMode("exBasionymAuthorTeam", MatchMode
.IGNORE
);
302 return commonService
.findMatching(taxonNameBase
, strategy
);
304 } catch (MatchException e
) {
305 logger
.error("Error finding matching names", e
);