(no commit message)
[taxeditor.git] / eu.etaxonomy.taxeditor.store / src / main / java / eu / etaxonomy / taxeditor / parser / ParseHandler.java
1 /**
2 *
3 */
4 package eu.etaxonomy.taxeditor.parser;
5
6 import java.util.ArrayList;
7 import java.util.List;
8
9 import eu.etaxonomy.cdm.api.service.ICommonService;
10 import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
11 import eu.etaxonomy.cdm.model.agent.TeamOrPersonBase;
12 import eu.etaxonomy.cdm.model.name.NonViralName;
13 import eu.etaxonomy.cdm.model.name.Rank;
14 import eu.etaxonomy.cdm.model.name.TaxonNameBase;
15 import eu.etaxonomy.cdm.model.reference.INomenclaturalReference;
16 import eu.etaxonomy.cdm.model.reference.Reference;
17 import eu.etaxonomy.cdm.strategy.match.MatchException;
18 import eu.etaxonomy.cdm.strategy.match.MatchStrategyConfigurator.MatchStrategy;
19 import eu.etaxonomy.cdm.strategy.parser.NonViralNameParserImpl;
20 import eu.etaxonomy.taxeditor.model.MessagingUtils;
21 import eu.etaxonomy.taxeditor.preference.PreferencesUtil;
22 import eu.etaxonomy.taxeditor.store.CdmStore;
23
24 /**
25 * <p>ParseHandler class.</p>
26 *
27 * @author n.hoffmann
28 * @version $Id: $
29 */
30 public class ParseHandler{
31
32 private TaxonNameBase taxonNameBase;
33
34 private class MatchMatrix {
35 List<TaxonNameBase> duplicateNames = new ArrayList<TaxonNameBase>();
36
37 List<INomenclaturalReference> duplicateReferences = new ArrayList<INomenclaturalReference>();
38 List<INomenclaturalReference> duplicateInReferences = new ArrayList<INomenclaturalReference>();
39
40 List<TeamOrPersonBase> duplicateCombinationAuthorTeams = new ArrayList<TeamOrPersonBase>();
41 List<TeamOrPersonBase> duplicateExCombinationAuthorTeams = new ArrayList<TeamOrPersonBase>();
42 List<TeamOrPersonBase> duplicateBasionymAuthorTeams = new ArrayList<TeamOrPersonBase>();
43 List<TeamOrPersonBase> duplicateExBasionymAuthorTeams = new ArrayList<TeamOrPersonBase>();
44 }
45
46 private static NonViralNameParserImpl nonViralNameParser = NonViralNameParserImpl.NewInstance();
47
48 /**
49 * The name that should get parsed
50 */
51 private NonViralName name;
52
53 private boolean doResolveInReferences;
54
55 /**
56 * Creates a new instance
57 *
58 * @param textWidget
59 * @param name
60 */
61 private ParseHandler(TaxonNameBase name){
62 if(name == null){
63 this.name = nonViralNameParser.getNonViralNameInstance("", PreferencesUtil.getPreferredNomenclaturalCode());
64 }else{
65 this.name = (NonViralName) HibernateProxyHelper.deproxy(name);
66 }
67 }
68
69 /**
70 * Factory method to create a new instance of the this class
71 *
72 * @param textWidget The text widget where the NonViralName may be entered into
73 * @param name An initial NonViralName or null when creating a new name
74 * @return An instance of this class
75 */
76 public static ParseHandler NewInstance(TaxonNameBase name){
77 return new ParseHandler(name);
78
79 }
80
81 /**
82 * Parses a given string and returns a <code>TaxonNameBase</code> instance with the
83 * results of the parsing.
84 *
85 * This method should be used to quickly create a new name from a string.
86 * Wherever the string will be parsed again in subsequent editing, an instance
87 * of <code>ParseHandler</code> should be attached to the text widget.
88 *
89 * @param unparsedNameString a {@link java.lang.String} object.
90 * @return a {@link eu.etaxonomy.cdm.model.name.TaxonNameBase} object.
91 */
92 public static NonViralName parseReferencedName(String unparsedNameString, Rank rank){
93 NonViralName name = nonViralNameParser.parseReferencedName(unparsedNameString,
94 PreferencesUtil.getPreferredNomenclaturalCode(), rank);
95
96 // if (name.hasProblem()) {
97 // name.setFullTitleCache(unparsedNameString);
98 // }
99
100 return name;
101 }
102
103 public static NonViralName parseName(String unparsedNameString, Rank rank){
104 NonViralName name = nonViralNameParser.parseFullName(unparsedNameString,
105 PreferencesUtil.getPreferredNomenclaturalCode(), rank);
106
107 return name;
108 }
109
110 /**
111 * Creates an empty <code>TaxonNameBase</code> instance with the nomenclatural code
112 * currently set in preferences.
113 *
114 * @return a {@link eu.etaxonomy.cdm.model.name.TaxonNameBase} object.
115 */
116 public static NonViralName createEmptyName(){
117 return nonViralNameParser.getNonViralNameInstance("", PreferencesUtil.getPreferredNomenclaturalCode());
118 }
119
120 /**
121 * Parses the string that was entered into the text widget and returns a
122 * NonViralName object that resulted from the parsing process.
123 *
124 * @return The parsed NonViralName object
125 */
126 public NonViralName parse(String unparsedNameString){
127
128 // String unparsedNameString = "";
129 // try {
130 // Method getText;
131 // getText = textWidget.getClass().getDeclaredMethod("getText", null);
132 // unparsedNameString = (String) getText.invoke(textWidget, null);
133 // } catch (Exception e) {
134 // // we should never get here
135 // StoreUtil.error(this.getClass(), "Error trying to invoke getText method", e);
136 // }
137
138
139 nonViralNameParser.parseReferencedName(name, unparsedNameString,
140 name.getRank(), true);
141
142 // if (name.hasProblem()) {
143 // name.setFullTitleCache(unparsedNameString);
144 // }
145
146 return name;
147 }
148
149 /**
150 * Parses the string that was entered into the text widget and returns a
151 * NonViralName object that resulted from the parsing process.
152 *
153 * The atomized fields (scientific name, author and reference) will be matched
154 * against the database to find possible duplicates. If duplicates were found
155 * the respective parts of the NonViralName will be replaced with the found
156 * objects.
157 *
158 * @return The parsed NonViralName object
159 */
160 public NonViralName parseAndResolveDuplicates(String unparsedNameString){
161
162 NonViralName parsedName = parse(unparsedNameString);
163
164 MatchMatrix matchMatrix = findMatches(parsedName);
165
166 resolveDuplicates(parsedName, matchMatrix);
167
168 return parsedName;
169 }
170
171
172
173
174 /**
175 * @param name The name to resolve duplicates for.
176 */
177 private void resolveDuplicates(NonViralName name, MatchMatrix matchMatrix) {
178 resolveDuplicateNames(name, matchMatrix);
179
180 resolveAllDuplicateAuthors(name, matchMatrix);
181
182 resolveDuplicateReferences(name, matchMatrix);
183
184 if(matchMatrix.duplicateInReferences != null) {
185 resolveDuplicateInReferences(name, matchMatrix);
186 }
187 }
188
189
190 /**
191 * @param name The name to resolve duplicates for.
192 */
193 private void resolveDuplicateNames(NonViralName name, MatchMatrix matchMatrix) {
194
195 if (matchMatrix.duplicateNames.size() == 1){
196 name = (NonViralName) matchMatrix.duplicateNames.iterator().next();
197 }else if(matchMatrix.duplicateNames.size() > 1){
198 // FIXME TODO resolve multiple duplications. Use first match for a start
199 name = (NonViralName) matchMatrix.duplicateNames.iterator().next();
200 }
201 }
202
203 /**
204 * @param name The name to resolve duplicates for.
205 */
206 private void resolveDuplicateReferences(NonViralName name, MatchMatrix matchMatrix) {
207 if(matchMatrix.duplicateReferences.size() == 1){
208 // exactly one match. We assume that the user wants this reference
209 INomenclaturalReference duplicate = matchMatrix.duplicateReferences.iterator().next();
210 name.setNomenclaturalReference(duplicate);
211 }else if(matchMatrix.duplicateReferences.size() > 1){
212 // FIXME TODO resolve multiple duplications. Use first match for a start
213 INomenclaturalReference duplicate = matchMatrix.duplicateReferences.iterator().next();
214 name.setNomenclaturalReference(duplicate);
215 }
216 }
217
218 /**
219 * @param name The name to resolve duplicates for.
220 */
221 private void resolveDuplicateInReferences(NonViralName name, MatchMatrix matchMatrix) {
222 Reference reference = (Reference) HibernateProxyHelper.deproxy(name.getNomenclaturalReference());
223
224 if(matchMatrix.duplicateInReferences.size() > 0){
225 Reference inReference = (Reference) matchMatrix.duplicateInReferences.iterator().next();
226 reference.setInReference(inReference);
227 MessagingUtils.warn(this.getClass(), reference.generateTitle());
228 // FIXME TODO resolve multiple duplications. We use first match for a start
229 MessagingUtils.warn(this.getClass(), reference.getTitleCache());
230 }
231 }
232
233
234 /**
235 * @param name The name to resolve duplicates for.
236 */
237 private void resolveAllDuplicateAuthors(NonViralName name, MatchMatrix matchMatrix) {
238
239 if(matchMatrix.duplicateCombinationAuthorTeams.size() > 0){
240 name.setCombinationAuthorTeam(matchMatrix.duplicateCombinationAuthorTeams.iterator().next());
241 Reference reference = (Reference) name.getNomenclaturalReference();
242 if(reference != null){
243 reference.setAuthorship(matchMatrix.duplicateCombinationAuthorTeams.iterator().next());
244 }
245 // FIXME TODO resolve multiple duplications. We use first match for a start.
246 }
247
248 if(matchMatrix.duplicateExCombinationAuthorTeams.size() > 0){
249 name.setExCombinationAuthorTeam(matchMatrix.duplicateExCombinationAuthorTeams.iterator().next());
250 // FIXME TODO resolve multiple duplications. We use first match for a start.
251 }
252
253 if(matchMatrix.duplicateBasionymAuthorTeams.size() > 0){
254 name.setBasionymAuthorTeam(matchMatrix.duplicateBasionymAuthorTeams.iterator().next());
255 // FIXME TODO resolve multiple duplications. We use first match for a start.
256 }
257
258 if(matchMatrix.duplicateExBasionymAuthorTeams.size() > 0){
259 name.setExBasionymAuthorTeam(matchMatrix.duplicateExBasionymAuthorTeams.iterator().next());
260 // FIXME TODO resolve multiple duplications. We use first match for a start.
261 }
262 }
263
264 /**
265 * Splits a NonViralName into its parts and calls methods to find matches for these
266 * parts in the database.
267 *
268 * @param name The NonViralName to find matches for.
269 */
270 private MatchMatrix findMatches(NonViralName name){
271
272 MatchMatrix matchMatrix = new MatchMatrix();
273
274 matchMatrix.duplicateNames = findMatchingLatinNames(name);
275
276 matchMatrix.duplicateCombinationAuthorTeams = findMatchingAuthors(name.getCombinationAuthorTeam());
277 matchMatrix.duplicateExCombinationAuthorTeams = findMatchingAuthors(name.getExCombinationAuthorTeam());
278 matchMatrix.duplicateBasionymAuthorTeams = findMatchingAuthors(name.getBasionymAuthorTeam());
279 matchMatrix.duplicateExBasionymAuthorTeams = findMatchingAuthors(name.getExBasionymAuthorTeam());
280
281 INomenclaturalReference nomenclaturalReference = name.getNomenclaturalReference();
282
283 // check if the reference has an inreference and also check if the inReference already exists
284 if(nomenclaturalReference != null){
285 Reference inReference = ((Reference)nomenclaturalReference).getInReference();
286 if(inReference != null){
287 doResolveInReferences = true;
288 matchMatrix.duplicateInReferences = findMatchingNomenclaturalReference(inReference);
289 }
290 }
291
292 matchMatrix.duplicateReferences = findMatchingNomenclaturalReference(nomenclaturalReference);
293
294 return matchMatrix;
295 }
296
297 /**
298 * @param nomenclaturalReference The NomenclaturalReference to find matches for.
299 * @return A <code>List</code> of possibly matching NomenclaturalReference's.
300 */
301 private List<INomenclaturalReference> findMatchingNomenclaturalReference(INomenclaturalReference nomenclaturalReference) {
302 if(nomenclaturalReference == null) {
303 return new ArrayList<INomenclaturalReference>();
304 }
305 try{
306 return CdmStore.getService(ICommonService.class).findMatching(nomenclaturalReference, MatchStrategy.Reference);
307 }catch (MatchException e) {
308 MessagingUtils.error(this.getClass(), "Error finding matching references", e);
309 }
310 return null;
311 }
312
313 /**
314 * @param authorTeam The TeamOrPersonBase to find matches for.
315 * @return A <code>List</code> of possibly matching TeamOrPersonBase's.
316 */
317 private List<TeamOrPersonBase> findMatchingAuthors(TeamOrPersonBase authorTeam) {
318
319 if(authorTeam == null){
320 return new ArrayList<TeamOrPersonBase>();
321 }
322
323 try{
324 return CdmStore.getService(ICommonService.class).findMatching(authorTeam, MatchStrategy.TeamOrPerson);
325 }catch (MatchException e) {
326 MessagingUtils.error(this.getClass(), "Error finding matching authors", e);
327 }
328 return null;
329 }
330
331 /**
332 * @param taxonNameBase The TaxonNameBase to find matches for.
333 * @return A <code>List</code> of possibly matching TaxonNameBase's.
334 */
335 private List<TaxonNameBase> findMatchingLatinNames(TaxonNameBase taxonNameBase) {
336
337 try {
338 return CdmStore.getService(ICommonService.class).findMatching(taxonNameBase, MatchStrategy.NonViralName);
339
340 } catch (MatchException e) {
341 MessagingUtils.error(this.getClass(), "Error finding matching names", e);
342 }
343 return null;
344 }
345 }