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.
9 package eu
.etaxonomy
.taxeditor
.parser
;
11 import java
.util
.ArrayList
;
12 import java
.util
.List
;
14 import org
.apache
.log4j
.Logger
;
16 import eu
.etaxonomy
.cdm
.api
.service
.INameService
;
17 import eu
.etaxonomy
.cdm
.hibernate
.HibernateProxyHelper
;
18 import eu
.etaxonomy
.cdm
.model
.agent
.TeamOrPersonBase
;
19 import eu
.etaxonomy
.cdm
.model
.name
.INonViralName
;
20 import eu
.etaxonomy
.cdm
.model
.name
.ITaxonNameBase
;
21 import eu
.etaxonomy
.cdm
.model
.name
.Rank
;
22 import eu
.etaxonomy
.cdm
.model
.name
.TaxonName
;
23 import eu
.etaxonomy
.cdm
.model
.name
.TaxonNameFactory
;
24 import eu
.etaxonomy
.cdm
.model
.reference
.INomenclaturalReference
;
25 import eu
.etaxonomy
.cdm
.model
.reference
.Reference
;
26 import eu
.etaxonomy
.cdm
.strategy
.match
.MatchException
;
27 import eu
.etaxonomy
.cdm
.strategy
.match
.MatchStrategyConfigurator
.MatchStrategy
;
28 import eu
.etaxonomy
.cdm
.strategy
.parser
.NonViralNameParserImpl
;
29 import eu
.etaxonomy
.taxeditor
.model
.MessagingUtils
;
30 import eu
.etaxonomy
.taxeditor
.preference
.PreferencesUtil
;
31 import eu
.etaxonomy
.taxeditor
.store
.CdmStore
;
34 * <p>ParseHandler class.</p>
39 public class ParseHandler
{
41 public static final Logger logger
= Logger
.getLogger(ParseHandler
.class);
44 private static NonViralNameParserImpl nonViralNameParser
= NonViralNameParserImpl
.NewInstance();
47 * The name that should get parsed
49 private TaxonName name
;
52 * Creates a new instance
54 private ParseHandler(TaxonName name
){
56 this.name
= createEmptyName();
58 this.name
= HibernateProxyHelper
.deproxy(name
);
63 * Factory method to create a new instance of the this class
65 * @param textWidget The text widget where the NonViralName may be entered into
66 * @param name An initial NonViralName or null when creating a new name
67 * @return An instance of this class
69 public static ParseHandler
NewInstance(TaxonName name
){
70 return new ParseHandler(name
);
74 * Parses a given string and returns a <code>TaxonName</code> instance with the
75 * results of the parsing.
77 * This method should be used to quickly create a new name from a string.
78 * Wherever the string will be parsed again in subsequent editing, an instance
79 * of <code>ParseHandler</code> should be attached to the text widget.
81 * @param unparsedNameString a {@link java.lang.String} object.
82 * @return a {@link eu.etaxonomy.cdm.model.name.TaxonNameBase} object.
84 public static INonViralName
parseReferencedName(String unparsedNameString
, Rank rank
){
85 INonViralName name
= nonViralNameParser
.parseReferencedName(unparsedNameString
,
86 PreferencesUtil
.getPreferredNomenclaturalCode(), rank
);
90 public static TaxonName
parseName(String unparsedNameString
, Rank rank
){
91 INonViralName name
= nonViralNameParser
.parseFullName(unparsedNameString
,
92 PreferencesUtil
.getPreferredNomenclaturalCode(), rank
);
93 return (TaxonName
)name
;
97 * Creates an empty <code>TaxonName</code> instance with the nomenclatural code
98 * currently set in preferences.
100 * @return the newly created {@link TaxonName}.
102 public static TaxonName
createEmptyName(){
103 return TaxonNameFactory
.NewNameInstance(PreferencesUtil
.getPreferredNomenclaturalCode(), null);
107 * Parses the string that was entered into the text widget and returns a
108 * NonViralName object that resulted from the parsing process.
110 * @return The parsed NonViralName object
112 public INonViralName
parse(String unparsedNameString
){
113 nonViralNameParser
.parseReferencedName(name
, unparsedNameString
,
114 name
.getRank(), true);
118 public INonViralName
parseAndResolveDuplicates(String unparsedNameString
){
119 // Instant time = java.time.Instant.now();
120 // logger.warn("Start resolve duplicate");
121 INonViralName result
= parseAndResolveDuplicatesNew(unparsedNameString
);
122 // INonViralName result = parseAndResolveDuplicatesOld(unparsedNameString);
123 // logger.warn("End resolve duplicate: "+ time.until(Instant.now(), ChronoUnit.MILLIS));
129 * Parses the string that was entered into the text widget and returns a
130 * TaxonName object that resulted from the parsing process.
132 * The atomized fields (scientific name, author and reference) will be matched
133 * against the database to find possible duplicates. If duplicates were found
134 * the respective parts of the NonViralName will be replaced with the found
137 * @return The parsed NonViralName object
139 public TaxonName
parseAndResolveDuplicatesNew(String unparsedNameString
){
141 CdmStore
.getService(INameService
.class).parseName(name
, unparsedNameString
, null, true, true);
145 //********************************** OLD can be removed once parseAndResolveDuplicatesNew is stable ************************************/
146 private class MatchMatrix
{
147 List
<TaxonName
> duplicateNames
= new ArrayList
<>();
149 List
<INomenclaturalReference
> duplicateReferences
= new ArrayList
<>();
150 List
<INomenclaturalReference
> duplicateInReferences
= new ArrayList
<>();
152 List
<TeamOrPersonBase
> duplicateCombinationAuthorships
= new ArrayList
<>();
153 List
<TeamOrPersonBase
> duplicateExCombinationAuthorships
= new ArrayList
<>();
154 List
<TeamOrPersonBase
> duplicateBasionymAuthorships
= new ArrayList
<>();
155 List
<TeamOrPersonBase
> duplicateExBasionymAuthorships
= new ArrayList
<>();
159 * Creates an empty <code>TaxonNameBase</code> instance with the nomenclatural code
160 * currently set in preferences.
162 * @return a {@link eu.etaxonomy.cdm.model.name.TaxonNameBase} object.
164 public static TaxonName
createEmptyNameOld(){
165 return (TaxonName
)nonViralNameParser
.getNonViralNameInstance("", PreferencesUtil
.getPreferredNomenclaturalCode());
169 * Parses the string that was entered into the text widget and returns a
170 * NonViralName object that resulted from the parsing process.
172 * The atomized fields (scientific name, author and reference) will be matched
173 * against the database to find possible duplicates. If duplicates were found
174 * the respective parts of the NonViralName will be replaced with the found
177 * @return The parsed NonViralName object
179 public INonViralName
parseAndResolveDuplicatesOld(String unparsedNameString
){
181 INonViralName parsedName
= parse(unparsedNameString
);
183 MatchMatrix matchMatrix
= findMatches(parsedName
);
185 resolveDuplicates(parsedName
, matchMatrix
);
194 * @param name The name to resolve duplicates for.
196 private void resolveDuplicates(INonViralName name
, MatchMatrix matchMatrix
) {
197 resolveDuplicateNames(name
, matchMatrix
);
199 resolveAllDuplicateAuthors(name
, matchMatrix
);
201 resolveDuplicateReferences(name
, matchMatrix
);
203 // if(matchMatrix.duplicateInReferences != null) {
204 // resolveDuplicateInReferences(name, matchMatrix);
210 * @param name The name to resolve duplicates for.
212 private void resolveDuplicateNames(INonViralName name
, MatchMatrix matchMatrix
) {
214 if (matchMatrix
.duplicateNames
.size() == 1){
215 name
= matchMatrix
.duplicateNames
.iterator().next();
216 }else if(matchMatrix
.duplicateNames
.size() > 1){
217 // FIXME TODO resolve multiple duplications. Use first match for a start
218 name
= matchMatrix
.duplicateNames
.iterator().next();
223 * @param name The name to resolve duplicates for.
225 private void resolveDuplicateReferences(INonViralName name
, MatchMatrix matchMatrix
) {
226 if(matchMatrix
.duplicateReferences
.size() == 1){
227 // exactly one match. We assume that the user wants this reference
228 INomenclaturalReference duplicate
= matchMatrix
.duplicateReferences
.iterator().next();
229 name
.setNomenclaturalReference(duplicate
);
230 }else if(matchMatrix
.duplicateReferences
.size() > 1){
231 // FIXME TODO resolve multiple duplications. Use first match for a start
232 INomenclaturalReference duplicate
= matchMatrix
.duplicateReferences
.iterator().next();
233 name
.setNomenclaturalReference(duplicate
);
235 //if reference is new but the in reference is already in db
236 if (matchMatrix
.duplicateReferences
.size() == 0 && (name
.getNomenclaturalReference() != null && name
.getNomenclaturalReference().getInReference() != null) && matchMatrix
.duplicateInReferences
.size() > 0){
237 resolveDuplicateInReferences(name
, matchMatrix
);
242 * @param name The name to resolve duplicates for.
244 private void resolveDuplicateInReferences(INonViralName name
, MatchMatrix matchMatrix
) {
245 Reference reference
= HibernateProxyHelper
.deproxy(name
.getNomenclaturalReference());
247 if(matchMatrix
.duplicateInReferences
.size() > 0){
248 Reference inReference
= (Reference
) matchMatrix
.duplicateInReferences
.iterator().next();
249 reference
.setInReference(inReference
);
250 MessagingUtils
.warn(this.getClass(), reference
.generateTitle());
251 // FIXME TODO resolve multiple duplications. We use first match for a start
252 MessagingUtils
.warn(this.getClass(), reference
.getTitleCache());
258 * @param name The name to resolve duplicates for.
260 private void resolveAllDuplicateAuthors(INonViralName name
, MatchMatrix matchMatrix
) {
262 if(matchMatrix
.duplicateCombinationAuthorships
.size() > 0){
263 name
.setCombinationAuthorship(matchMatrix
.duplicateCombinationAuthorships
.iterator().next());
264 Reference reference
= name
.getNomenclaturalReference();
265 if(reference
!= null){
266 reference
.setAuthorship(matchMatrix
.duplicateCombinationAuthorships
.iterator().next());
268 // FIXME TODO resolve multiple duplications. We use first match for a start.
271 if(matchMatrix
.duplicateExCombinationAuthorships
.size() > 0){
272 name
.setExCombinationAuthorship(matchMatrix
.duplicateExCombinationAuthorships
.iterator().next());
273 // FIXME TODO resolve multiple duplications. We use first match for a start.
276 if(matchMatrix
.duplicateBasionymAuthorships
.size() > 0){
277 name
.setBasionymAuthorship(matchMatrix
.duplicateBasionymAuthorships
.iterator().next());
278 // FIXME TODO resolve multiple duplications. We use first match for a start.
281 if(matchMatrix
.duplicateExBasionymAuthorships
.size() > 0){
282 name
.setExBasionymAuthorship(matchMatrix
.duplicateExBasionymAuthorships
.iterator().next());
283 // FIXME TODO resolve multiple duplications. We use first match for a start.
288 * Splits a NonViralName into its parts and calls methods to find matches for these
289 * parts in the database.
291 * @param name The NonViralName to find matches for.
293 private MatchMatrix
findMatches(INonViralName name
){
295 MatchMatrix matchMatrix
= new MatchMatrix();
297 matchMatrix
.duplicateNames
= findMatchingLatinNames(name
);
299 matchMatrix
.duplicateCombinationAuthorships
= findMatchingAuthors(name
.getCombinationAuthorship());
300 matchMatrix
.duplicateExCombinationAuthorships
= findMatchingAuthors(name
.getExCombinationAuthorship());
301 matchMatrix
.duplicateBasionymAuthorships
= findMatchingAuthors(name
.getBasionymAuthorship());
302 matchMatrix
.duplicateExBasionymAuthorships
= findMatchingAuthors(name
.getExBasionymAuthorship());
304 INomenclaturalReference nomenclaturalReference
= name
.getNomenclaturalReference();
306 // check if the reference has an inreference and also check if the inReference already exists
307 if(nomenclaturalReference
!= null){
308 Reference inReference
= ((Reference
)nomenclaturalReference
).getInReference();
309 if(inReference
!= null){
310 matchMatrix
.duplicateInReferences
= findMatchingNomenclaturalReference(inReference
);
314 matchMatrix
.duplicateReferences
= findMatchingNomenclaturalReference(nomenclaturalReference
);
320 * @param nomenclaturalReference The NomenclaturalReference to find matches for.
321 * @return A <code>List</code> of possibly matching NomenclaturalReference's.
323 private List
<INomenclaturalReference
> findMatchingNomenclaturalReference(INomenclaturalReference nomenclaturalReference
) {
324 if(nomenclaturalReference
== null) {
325 return new ArrayList
<INomenclaturalReference
>();
329 return CdmStore
.getCommonService().findMatching(nomenclaturalReference
, MatchStrategy
.Reference
);
331 }catch (MatchException e
) {
332 MessagingUtils
.error(this.getClass(), "Error finding matching references", e
);
338 * @param authorTeam The TeamOrPersonBase to find matches for.
339 * @return A <code>List</code> of possibly matching TeamOrPersonBase's.
341 private List
<TeamOrPersonBase
> findMatchingAuthors(TeamOrPersonBase authorTeam
) {
342 if(authorTeam
== null){
343 return new ArrayList
<>();
346 return CdmStore
.getCommonService().findMatching(authorTeam
, MatchStrategy
.TeamOrPerson
);
348 }catch (MatchException e
) {
349 MessagingUtils
.error(this.getClass(), "Error finding matching authors", e
);
355 * @param taxonName The TaxonNameBase to find matches for.
356 * @return A <code>List</code> of possibly matching TaxonNameBase's.
358 private List
<TaxonName
> findMatchingLatinNames(ITaxonNameBase taxonName
) {
360 return CdmStore
.getCommonService().findMatching(TaxonName
.castAndDeproxy(taxonName
), MatchStrategy
.NonViralName
);
361 } catch (MatchException e
) {
362 MessagingUtils
.error(this.getClass(), "Error finding matching names", e
);