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