4 package eu
.etaxonomy
.taxeditor
.parser
;
6 import java
.lang
.reflect
.Method
;
7 import java
.util
.ArrayList
;
10 import org
.apache
.log4j
.Logger
;
11 import org
.eclipse
.swt
.widgets
.Control
;
13 import eu
.etaxonomy
.cdm
.hibernate
.HibernateProxyHelper
;
14 import eu
.etaxonomy
.cdm
.model
.agent
.TeamOrPersonBase
;
15 import eu
.etaxonomy
.cdm
.model
.name
.NonViralName
;
16 import eu
.etaxonomy
.cdm
.model
.name
.TaxonNameBase
;
17 import eu
.etaxonomy
.cdm
.model
.reference
.INomenclaturalReference
;
18 import eu
.etaxonomy
.cdm
.model
.reference
.ReferenceBase
;
19 import eu
.etaxonomy
.cdm
.strategy
.match
.MatchException
;
20 import eu
.etaxonomy
.cdm
.strategy
.parser
.NonViralNameParserImpl
;
21 import eu
.etaxonomy
.taxeditor
.preference
.PreferencesUtil
;
22 import eu
.etaxonomy
.taxeditor
.store
.CdmStore
;
28 public class ParseHandler
{
29 private static final Logger logger
= Logger
.getLogger(ParseHandler
.class);
31 private TaxonNameBase taxonNameBase
;
33 private List
<INomenclaturalReference
> duplicateReferences
;
34 private List
<INomenclaturalReference
> duplicateInReferences
;
36 private List
<TaxonNameBase
> duplicateNames
;
38 private List
<TeamOrPersonBase
> duplicateCombinationAuthorTeams
;
39 private List
<TeamOrPersonBase
> duplicateExCombinationAuthorTeams
;
40 private List
<TeamOrPersonBase
> duplicateBasionymAuthorTeams
;
41 private List
<TeamOrPersonBase
> duplicateExBasionymAuthorTeams
;
43 private static NonViralNameParserImpl nonViralNameParser
= NonViralNameParserImpl
.NewInstance();
46 * The name that should get parsed
48 private NonViralName name
;
51 * The widget, the name got entered in
53 private Control textWidget
;
55 private boolean doResolveInReferences
;
58 * Creates a new instance
63 private ParseHandler(Control textWidget
, TaxonNameBase name
){
64 if(textWidget
!= null){
65 this.textWidget
= textWidget
;
66 checkControlHasText();
68 throw new IllegalArgumentException("text widget must not be null");
72 this.name
= nonViralNameParser
.getNonViralNameInstance("", PreferencesUtil
.getPreferredNomenclaturalCode());
74 this.name
= (NonViralName
) HibernateProxyHelper
.deproxy(name
);
79 * Factory method to create a new instance of the this class
81 * @param textWidget The text widget where the NonViralName may be entered into
82 * @param name An initial NonViralName or null when creating a new name
83 * @return An instance of this class
85 public static ParseHandler
NewInstance(Control textWidget
, TaxonNameBase name
){
86 return new ParseHandler(textWidget
, name
);
91 * Parses a given string and returns a <code>TaxonNameBase</code> instance with the
92 * reuslts of the parsing.
94 * This method should be used to quickly create a new name from a string.
95 * Wherever the string will be parsed again in subsequent editing, an instance
96 * of <code>ParseHandler</code> should be attached to the text widget.
98 * @param unparsedNameString
101 public static TaxonNameBase
quickParse(String unparsedNameString
){
102 TaxonNameBase name
= nonViralNameParser
.parseReferencedName(unparsedNameString
,
103 PreferencesUtil
.getPreferredNomenclaturalCode(), null);
105 if (name
.hasProblem()) {
106 name
.setFullTitleCache(unparsedNameString
);
113 * Creates an empty <code>TaxonNameBase</code> instance with the nomenclatural code
114 * currently set in preferences.
118 public static TaxonNameBase
createEmptyName(){
119 return nonViralNameParser
.getNonViralNameInstance("", PreferencesUtil
.getPreferredNomenclaturalCode());
123 * Check if the given control has a getText() method
125 private void checkControlHasText(){
126 Class clazz
= textWidget
.getClass();
129 clazz
.getDeclaredMethod("getText", null);
130 } catch (SecurityException e
) {
131 } catch (NoSuchMethodException e
) {
132 throw new IllegalArgumentException("Given composite does not have a getText method");
137 * Parses the string that was entered into the text widget and returns a
138 * NonViralName object that resulted from the parsing process.
140 * @return The parsed NonViralName object
142 public NonViralName
parse(){
145 String unparsedNameString
= "";
148 getText
= textWidget
.getClass().getDeclaredMethod("getText", null);
149 unparsedNameString
= (String
) getText
.invoke(textWidget
, null);
150 } catch (Exception e
) {
151 // we should never get here
152 logger
.error("Error trying to invoke getText method");
156 nonViralNameParser
.parseReferencedName(name
, unparsedNameString
,
157 name
.getRank(), true);
159 if (name
.hasProblem()) {
160 name
.setFullTitleCache(unparsedNameString
);
167 * Parses the string that was entered into the text widget and returns a
168 * NonViralName object that resulted from the parsing process.
170 * The atomized fields (scientific name, author and reference) will be matched
171 * against the database to find possible duplicates. If duplicates were found
172 * the respective parts of the NonViralName will be replaced with the found
175 * @return The parsed NonViralName object
177 public NonViralName
parseAndResolveDuplicates(){
183 resolveDuplicates(name
);
192 * @param name The name to resolve duplicates for.
194 private void resolveDuplicates(NonViralName name
) {
195 resolveDuplicateNames(name
);
197 resolveAllDuplicateAuthors(name
);
199 resolveDuplicateReferences(name
);
201 if(duplicateInReferences
!= null)
202 resolveDuplicateInReferences(name
);
207 * @param name The name to resolve duplicates for.
209 private void resolveDuplicateNames(NonViralName name
) {
211 if (duplicateNames
.size() == 1){
212 name
= (NonViralName
) duplicateNames
.iterator().next();
213 }else if(duplicateNames
.size() > 1){
214 // FIXME TODO resolve multiple duplications. Use first match for a start
215 name
= (NonViralName
) duplicateNames
.iterator().next();
220 * @param name The name to resolve duplicates for.
222 private void resolveDuplicateReferences(NonViralName name
) {
223 if(duplicateReferences
.size() == 1){
224 // exactly one match. We assume that the user wants this reference
225 INomenclaturalReference duplicate
= duplicateReferences
.iterator().next();
226 name
.setNomenclaturalReference(duplicate
);
227 }else if(duplicateReferences
.size() > 1){
228 // FIXME TODO resolve multiple duplications. Use first match for a start
229 INomenclaturalReference duplicate
= duplicateReferences
.iterator().next();
230 name
.setNomenclaturalReference(duplicate
);
235 * @param name The name to resolve duplicates for.
237 private void resolveDuplicateInReferences(NonViralName name
) {
238 ReferenceBase reference
= (ReferenceBase
) HibernateProxyHelper
.deproxy(name
.getNomenclaturalReference());
240 if(duplicateInReferences
.size() > 0){
241 ReferenceBase inReference
= (ReferenceBase
) duplicateInReferences
.iterator().next();
242 reference
.setInReference(inReference
);
243 logger
.warn(reference
.generateTitle());
244 // FIXME TODO resolve multiple duplications. We use first match for a start
245 logger
.warn(reference
.getTitleCache());
251 * @param name The name to resolve duplicates for.
253 private void resolveAllDuplicateAuthors(NonViralName name
) {
255 if(duplicateCombinationAuthorTeams
.size() > 0){
256 name
.setCombinationAuthorTeam(duplicateCombinationAuthorTeams
.iterator().next());
257 ReferenceBase reference
= (ReferenceBase
) name
.getNomenclaturalReference();
258 if(reference
!= null){
259 reference
.setAuthorTeam(duplicateCombinationAuthorTeams
.iterator().next());
261 // FIXME TODO resolve multiple duplications. We use first match for a start.
264 if(duplicateExCombinationAuthorTeams
.size() > 0){
265 name
.setExCombinationAuthorTeam(duplicateExCombinationAuthorTeams
.iterator().next());
266 // FIXME TODO resolve multiple duplications. We use first match for a start.
269 if(duplicateBasionymAuthorTeams
.size() > 0){
270 name
.setBasionymAuthorTeam(duplicateBasionymAuthorTeams
.iterator().next());
271 // FIXME TODO resolve multiple duplications. We use first match for a start.
274 if(duplicateExBasionymAuthorTeams
.size() > 0){
275 name
.setExBasionymAuthorTeam(duplicateExBasionymAuthorTeams
.iterator().next());
276 // FIXME TODO resolve multiple duplications. We use first match for a start.
281 * Splits a NonViralName into its parts and calls methods to find matches for these
282 * parts in the database.
284 * @param name The NonViralName to find matches for.
286 private void findMatches(NonViralName name
){
288 duplicateNames
= findMatchingLatinNames(name
);
290 duplicateCombinationAuthorTeams
= findMatchingAuthors((TeamOrPersonBase
) name
.getCombinationAuthorTeam());
291 duplicateExCombinationAuthorTeams
= findMatchingAuthors((TeamOrPersonBase
) name
.getExCombinationAuthorTeam());
292 duplicateBasionymAuthorTeams
= findMatchingAuthors((TeamOrPersonBase
) name
.getBasionymAuthorTeam());
293 duplicateExBasionymAuthorTeams
= findMatchingAuthors((TeamOrPersonBase
) name
.getExBasionymAuthorTeam());
295 INomenclaturalReference nomenclaturalReference
= name
.getNomenclaturalReference();
297 // check if the reference has an inreference and also check if the inReference already exists
298 if(nomenclaturalReference
!= null){
299 ReferenceBase inReference
= ((ReferenceBase
)nomenclaturalReference
).getInReference();
300 if(inReference
!= null){
301 doResolveInReferences
= true;
302 duplicateInReferences
= findMatchingNomenclaturalReference(inReference
);
306 duplicateReferences
= findMatchingNomenclaturalReference(nomenclaturalReference
);
310 * @param nomenclaturalReference The NomenclaturalReference to find matches for.
311 * @return A <code>List</code> of possibly matching NomenclaturalReference's.
313 private List
<INomenclaturalReference
> findMatchingNomenclaturalReference(INomenclaturalReference nomenclaturalReference
) {
314 if(nomenclaturalReference
== null) return new ArrayList
<INomenclaturalReference
>();
316 return CdmStore
.getCommonService().findMatching(nomenclaturalReference
, MatchStrategyConfigurator
.ReferenceMatchStrategy());
317 }catch (MatchException e
) {
318 logger
.error("Error finding matching references", e
);
324 * @param authorTeam The TeamOrPersonBase to find matches for.
325 * @return A <code>List</code> of possibly matching TeamOrPersonBase's.
327 private List
<TeamOrPersonBase
> findMatchingAuthors(TeamOrPersonBase authorTeam
) {
329 if(authorTeam
== null){
330 return new ArrayList
<TeamOrPersonBase
>();
334 return CdmStore
.getCommonService().findMatching(authorTeam
, MatchStrategyConfigurator
.TeamOrPersonMatchStrategy());
335 }catch (MatchException e
) {
336 logger
.error("Error finding matching authors", e
);
342 * @param taxonNameBase The TaxonNameBase to find matches for.
343 * @return A <code>List</code> of possibly matching TaxonNameBase's.
345 private List
<TaxonNameBase
> findMatchingLatinNames(TaxonNameBase taxonNameBase
) {
348 return CdmStore
.getCommonService().findMatching(taxonNameBase
, MatchStrategyConfigurator
.NonViralNameMatchStrategy());
350 } catch (MatchException e
) {
351 logger
.error("Error finding matching names", e
);
357 * @return The Control this ParseHandler is attached to.
359 public Control
getTextWidget() {
364 * @param textWidget The textWidget to set
366 public void setTextWidget(Control textWidget
) {
367 this.textWidget
= textWidget
;
368 checkControlHasText();