merge from trunk
[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.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> duplicateCombinationAuthorTeams = new ArrayList<TeamOrPersonBase>();
40 List<TeamOrPersonBase> duplicateExCombinationAuthorTeams = new ArrayList<TeamOrPersonBase>();
41 List<TeamOrPersonBase> duplicateBasionymAuthorTeams = new ArrayList<TeamOrPersonBase>();
42 List<TeamOrPersonBase> duplicateExBasionymAuthorTeams = 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 TaxonNameBase parseReferencedName(String unparsedNameString, Rank rank){
92 TaxonNameBase 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 TaxonNameBase parseName(String unparsedNameString, Rank rank){
103 TaxonNameBase 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 TaxonNameBase 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.duplicateCombinationAuthorTeams.size() > 0){
239 name.setCombinationAuthorTeam(matchMatrix.duplicateCombinationAuthorTeams.iterator().next());
240 Reference reference = (Reference) name.getNomenclaturalReference();
241 if(reference != null){
242 reference.setAuthorship(matchMatrix.duplicateCombinationAuthorTeams.iterator().next());
243 }
244 // FIXME TODO resolve multiple duplications. We use first match for a start.
245 }
246
247 if(matchMatrix.duplicateExCombinationAuthorTeams.size() > 0){
248 name.setExCombinationAuthorTeam(matchMatrix.duplicateExCombinationAuthorTeams.iterator().next());
249 // FIXME TODO resolve multiple duplications. We use first match for a start.
250 }
251
252 if(matchMatrix.duplicateBasionymAuthorTeams.size() > 0){
253 name.setBasionymAuthorTeam(matchMatrix.duplicateBasionymAuthorTeams.iterator().next());
254 // FIXME TODO resolve multiple duplications. We use first match for a start.
255 }
256
257 if(matchMatrix.duplicateExBasionymAuthorTeams.size() > 0){
258 name.setExBasionymAuthorTeam(matchMatrix.duplicateExBasionymAuthorTeams.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.duplicateCombinationAuthorTeams = findMatchingAuthors(name.getCombinationAuthorTeam());
276 matchMatrix.duplicateExCombinationAuthorTeams = findMatchingAuthors(name.getExCombinationAuthorTeam());
277 matchMatrix.duplicateBasionymAuthorTeams = findMatchingAuthors(name.getBasionymAuthorTeam());
278 matchMatrix.duplicateExBasionymAuthorTeams = findMatchingAuthors(name.getExBasionymAuthorTeam());
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 return CdmStore.getService(ICommonService.class).findMatching(nomenclaturalReference, MatchStrategyConfigurator.ReferenceMatchStrategy());
306 }catch (MatchException e) {
307 MessagingUtils.error(this.getClass(), "Error finding matching references", e);
308 }
309 return null;
310 }
311
312 /**
313 * @param authorTeam The TeamOrPersonBase to find matches for.
314 * @return A <code>List</code> of possibly matching TeamOrPersonBase's.
315 */
316 private List<TeamOrPersonBase> findMatchingAuthors(TeamOrPersonBase authorTeam) {
317
318 if(authorTeam == null){
319 return new ArrayList<TeamOrPersonBase>();
320 }
321
322 try{
323 return CdmStore.getService(ICommonService.class).findMatching(authorTeam, MatchStrategyConfigurator.TeamOrPersonMatchStrategy());
324 }catch (MatchException e) {
325 MessagingUtils.error(this.getClass(), "Error finding matching authors", e);
326 }
327 return null;
328 }
329
330 /**
331 * @param taxonNameBase The TaxonNameBase to find matches for.
332 * @return A <code>List</code> of possibly matching TaxonNameBase's.
333 */
334 private List<TaxonNameBase> findMatchingLatinNames(TaxonNameBase taxonNameBase) {
335
336 try {
337 return CdmStore.getService(ICommonService.class).findMatching(taxonNameBase, MatchStrategyConfigurator.NonViralNameMatchStrategy());
338
339 } catch (MatchException e) {
340 MessagingUtils.error(this.getClass(), "Error finding matching names", e);
341 }
342 return null;
343 }
344 }