ref #7899 adding MarkerType 'Incorrect name'
[cdm-vaadin.git] / src / main / java / eu / etaxonomy / cdm / dataInserter / RegistrationRequiredDataInserter.java
1 /**
2 * Copyright (C) 2017 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
5 *
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.
8 */
9 package eu.etaxonomy.cdm.dataInserter;
10
11 import java.util.ArrayList;
12 import java.util.Arrays;
13 import java.util.EnumSet;
14 import java.util.HashMap;
15 import java.util.List;
16 import java.util.Map;
17 import java.util.Set;
18 import java.util.UUID;
19
20 import org.apache.log4j.Level;
21 import org.apache.log4j.Logger;
22 import org.hibernate.Session;
23 import org.springframework.context.event.ContextRefreshedEvent;
24 import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
25 import org.springframework.security.core.GrantedAuthority;
26 import org.springframework.transaction.TransactionStatus;
27 import org.springframework.transaction.annotation.Transactional;
28
29 import eu.etaxonomy.cdm.api.application.AbstractDataInserter;
30 import eu.etaxonomy.cdm.api.application.CdmRepository;
31 import eu.etaxonomy.cdm.api.service.pager.Pager;
32 import eu.etaxonomy.cdm.model.agent.Institution;
33 import eu.etaxonomy.cdm.model.common.DefinedTerm;
34 import eu.etaxonomy.cdm.model.common.DefinedTermBase;
35 import eu.etaxonomy.cdm.model.common.GrantedAuthorityImpl;
36 import eu.etaxonomy.cdm.model.common.Group;
37 import eu.etaxonomy.cdm.model.common.MarkerType;
38 import eu.etaxonomy.cdm.model.common.TermVocabulary;
39 import eu.etaxonomy.cdm.model.name.NomenclaturalStatus;
40 import eu.etaxonomy.cdm.model.name.NomenclaturalStatusType;
41 import eu.etaxonomy.cdm.model.name.Rank;
42 import eu.etaxonomy.cdm.model.name.TaxonName;
43 import eu.etaxonomy.cdm.model.taxon.Taxon;
44 import eu.etaxonomy.cdm.model.taxon.TaxonBase;
45 import eu.etaxonomy.cdm.persistence.dao.hibernate.taxonGraph.AbstractHibernateTaxonGraphProcessor;
46 import eu.etaxonomy.cdm.persistence.dao.taxonGraph.TaxonGraphException;
47 import eu.etaxonomy.cdm.persistence.hibernate.permission.CRUD;
48 import eu.etaxonomy.cdm.persistence.hibernate.permission.CdmAuthority;
49 import eu.etaxonomy.cdm.persistence.hibernate.permission.CdmPermissionClass;
50 import eu.etaxonomy.cdm.persistence.hibernate.permission.Role;
51 import eu.etaxonomy.cdm.vaadin.model.registration.KindOfUnitTerms;
52 import eu.etaxonomy.cdm.vaadin.model.registration.RegistrationMarkerTypes;
53 import eu.etaxonomy.cdm.vaadin.permission.RolesAndPermissions;
54
55 ///*
56 // * Can create missing registrations for names which have Extensions of the Type <code>IAPTRegdata.json</code>.
57 //* See https://dev.e-taxonomy.eu/redmine/issues/6621 for further details.
58 //* This feature can be activated by by supplying one of the following jvm command line arguments:
59 //* <ul>
60 //* <li><code>-DregistrationCreate=iapt</code>: create all iapt Registrations if missing</li>
61 //* <li><code>-DregistrationWipeout=iapt</code>: remove all iapt Registrations</li>
62 //* <li><code>-DregistrationWipeout=all</code>: remove all Registrations</li>
63 //* </ul>
64 //* The <code>-DregistrationWipeout</code> commands are executed before the <code>-DregistrationCreate</code> and will not change the name and type designations.
65 //*/
66 /**
67 * This feature can be activated by by supplying one of the following jvm command line arguments:
68 * <ul>
69 * <li><code>-DtaxonGraphCreate=true</code>: create taxon graph relations for all names below genus level</li>
70 * </ul>
71 *
72 * @author a.kohlbecker
73 * @since May 9, 2017
74 *
75 */
76 public class RegistrationRequiredDataInserter extends AbstractDataInserter {
77
78 // protected static final String PARAM_NAME_CREATE = "registrationCreate";
79 //
80 // protected static final String PARAM_NAME_WIPEOUT = "registrationWipeout";
81
82 protected static final String TAXON_GRAPH_CREATE = "taxonGraphCreate";
83
84 protected static final UUID GROUP_SUBMITTER_UUID = UUID.fromString("c468c6a7-b96c-4206-849d-5a825f806d3e");
85
86 protected static final UUID GROUP_CURATOR_UUID = UUID.fromString("135210d3-3db7-4a81-ab36-240444637d45");
87
88 private static final EnumSet<CRUD> CREATE_READ = EnumSet.of(CRUD.CREATE, CRUD.READ);
89 private static final EnumSet<CRUD> CREATE_READ_UPDATE_DELETE = EnumSet.of(CRUD.CREATE, CRUD.READ, CRUD.UPDATE, CRUD.DELETE);
90
91 private static final Logger logger = Logger.getLogger(RegistrationRequiredDataInserter.class);
92
93 // private ExtensionType extensionTypeIAPTRegData;
94
95 Map<String, Institution> instituteMap = new HashMap<>();
96
97 public static boolean commandsExecuted = false;
98
99 private CdmRepository repo;
100
101 private boolean hasRun = false;
102
103 public void setCdmRepository(CdmRepository repo){
104 this.repo = repo;
105 }
106
107 /**
108 * {@inheritDoc}
109 */
110 @Override
111 public void onApplicationEvent(ContextRefreshedEvent event) {
112
113 if(hasRun){
114 return;
115 }
116
117 runAsAuthentication(Role.ROLE_ADMIN);
118
119 insertRequiredData();
120 executeSuppliedCommands();
121
122 restoreAuthentication();
123
124 hasRun = true;
125 }
126
127 /**
128 *
129 */
130 @Transactional
131 private void insertRequiredData() {
132
133 TransactionStatus txStatus = repo.startTransaction(false);
134
135 Role roleCuration = RolesAndPermissions.ROLE_CURATION;
136 if(repo.getGrantedAuthorityService().find(roleCuration.getUuid()) == null){
137 repo.getGrantedAuthorityService().saveOrUpdate(roleCuration.asNewGrantedAuthority());
138 }
139
140 Group groupCurator = repo.getGroupService().load(GROUP_CURATOR_UUID, Arrays.asList("grantedAuthorities"));
141 if(groupCurator == null){
142 groupCurator = Group.NewInstance();
143 groupCurator.setUuid(GROUP_CURATOR_UUID);
144 groupCurator.setName("Curator");
145 }
146 assureGroupHas(groupCurator, new CdmAuthority(CdmPermissionClass.REGISTRATION, CREATE_READ_UPDATE_DELETE).toString());
147 repo.getGroupService().saveOrUpdate(groupCurator);
148
149 Group groupSubmitter = repo.getGroupService().load(GROUP_SUBMITTER_UUID, Arrays.asList("grantedAuthorities"));
150 if(groupSubmitter == null){
151 groupSubmitter = Group.NewInstance();
152 groupSubmitter.setUuid(GROUP_SUBMITTER_UUID);
153 groupSubmitter.setName("Submitter");
154 }
155 assureGroupHas(groupSubmitter, new CdmAuthority(CdmPermissionClass.TAXONNAME, CREATE_READ).toString());
156 assureGroupHas(groupSubmitter, new CdmAuthority(CdmPermissionClass.TEAMORPERSONBASE, CREATE_READ).toString());
157 assureGroupHas(groupSubmitter, new CdmAuthority(CdmPermissionClass.REGISTRATION, CREATE_READ).toString());
158 assureGroupHas(groupSubmitter, new CdmAuthority(CdmPermissionClass.REFERENCE, CREATE_READ).toString());
159 assureGroupHas(groupSubmitter, new CdmAuthority(CdmPermissionClass.SPECIMENOROBSERVATIONBASE, CREATE_READ).toString());
160 assureGroupHas(groupSubmitter, new CdmAuthority(CdmPermissionClass.COLLECTION, CREATE_READ).toString());
161 repo.getGroupService().saveOrUpdate(groupSubmitter);
162
163 TermVocabulary<DefinedTerm> kindOfUnitVocabulary = repo.getVocabularyService().find(KindOfUnitTerms.KIND_OF_UNIT_VOCABULARY().getUuid());
164 if(repo.getVocabularyService().find(KindOfUnitTerms.KIND_OF_UNIT_VOCABULARY().getUuid()) == null){
165 kindOfUnitVocabulary = repo.getVocabularyService().save(KindOfUnitTerms.KIND_OF_UNIT_VOCABULARY());
166 }
167
168 DefinedTermBase kouSpecimen = repo.getTermService().find(KindOfUnitTerms.SPECIMEN().getUuid());
169 DefinedTermBase kouImage = repo.getTermService().find(KindOfUnitTerms.PUBLISHED_IMAGE().getUuid());
170 DefinedTermBase kouUnpublishedImage = repo.getTermService().find(KindOfUnitTerms.UNPUBLISHED_IMAGE().getUuid());
171 DefinedTermBase kouCulture = repo.getTermService().find(KindOfUnitTerms.CULTURE_METABOLIC_INACTIVE().getUuid());
172
173 if(kouSpecimen == null){
174 kouSpecimen = repo.getTermService().save(KindOfUnitTerms.SPECIMEN());
175 }
176 if(kouImage == null){
177 kouImage = repo.getTermService().save(KindOfUnitTerms.PUBLISHED_IMAGE());
178 }
179 if(kouUnpublishedImage == null){
180 kouUnpublishedImage = repo.getTermService().save(KindOfUnitTerms.UNPUBLISHED_IMAGE());
181 }
182 if(kouCulture == null){
183 kouCulture = repo.getTermService().save(KindOfUnitTerms.CULTURE_METABOLIC_INACTIVE());
184 }
185
186 Set<DefinedTerm> termInVocab = kindOfUnitVocabulary.getTerms();
187 List<DefinedTermBase> kouTerms = Arrays.asList(kouCulture, kouImage, kouSpecimen, kouUnpublishedImage);
188
189 for(DefinedTermBase t : kouTerms){
190 if(!termInVocab.contains(t)){
191 kindOfUnitVocabulary.addTerm((DefinedTerm)t);
192 }
193 }
194
195 DefinedTermBase incorrectName = repo.getTermService().find(RegistrationMarkerTypes.INCORRECT_NAME().getUuid());
196 if(incorrectName == null){
197 incorrectName = repo.getTermService().save(RegistrationMarkerTypes.INCORRECT_NAME());
198 MarkerType.COMPLETE().getVocabulary().addTerm((MarkerType) incorrectName);
199 }
200
201 repo.commitTransaction(txStatus);
202
203 }
204
205 private void assureGroupHas(Group group, String authorityString){
206 boolean authorityExists = false;
207
208 for(GrantedAuthority ga : group.getGrantedAuthorities()){
209 if((authorityExists = ga.getAuthority().equals(authorityString)) == true){
210 break;
211 }
212 }
213 if(!authorityExists){
214 group.addGrantedAuthority(findGrantedAuthority(authorityString));
215 }
216 }
217
218 private GrantedAuthorityImpl findGrantedAuthority(String authorityString){
219 GrantedAuthorityImpl ga = null;
220 try{
221 ga = repo.getGrantedAuthorityService().findAuthorityString(authorityString);
222 } catch (AuthenticationCredentialsNotFoundException e){
223 e.printStackTrace();
224 }
225 if(ga == null){
226 ga = GrantedAuthorityImpl.NewInstance(authorityString);
227 repo.getGrantedAuthorityService().save(ga);
228 }
229 return ga;
230 }
231
232 /**
233 *
234 */
235 private void executeSuppliedCommands() {
236
237 if(commandsExecuted){
238 // do not run twice
239 // a second run could take place during initialization of the web context
240 return;
241 }
242 commandsExecuted = true;
243
244 String taxonGraphCreate = System.getProperty(TAXON_GRAPH_CREATE);
245
246 if(taxonGraphCreate != null){
247 AbstractHibernateTaxonGraphProcessor processor = new AbstractHibernateTaxonGraphProcessor() {
248
249 @Override
250 public Session getSession() {
251 return repo.getSession();
252 }
253 };
254 logger.setLevel(Level.DEBUG);
255 int chunksize = 1000;
256 int pageIndex = 0;
257 TransactionStatus tx;
258 Pager<Taxon> taxonPage;
259 List<TaxonBase> taxa = new ArrayList<>();
260 logger.debug("======= fixing sec refrences =========");
261 while(true){
262 tx = repo.startTransaction(false);
263 taxonPage = repo.getTaxonService().page(Taxon.class, chunksize, pageIndex++, null, null);
264 if(taxonPage.getRecords().size() == 0){
265 repo.commitTransaction(tx);
266 break;
267 }
268 for(Taxon taxon : taxonPage.getRecords()){
269 taxon.setSec(processor.secReference());
270 repo.getTaxonService().saveOrUpdate(taxon);
271 }
272 repo.commitTransaction(tx);
273 }
274
275 logger.debug("======= creating taxon graph =========");
276 pageIndex = 0;
277 Pager<TaxonName> page;
278 while(true){
279 tx = repo.startTransaction(false);
280 page = repo.getNameService().page(null, chunksize, pageIndex++, null, null);
281 if(page.getRecords().size() == 0){
282 repo.commitTransaction(tx);
283 break;
284 }
285 logger.debug(TAXON_GRAPH_CREATE + ": chunk " + pageIndex + "/" + Math.ceil(page.getCount() / chunksize));
286 taxa = new ArrayList<>();
287
288 for(TaxonName name : page.getRecords()){
289 if(name.getRank() != null && name.getRank().isLower(Rank.GENUS())){
290 NomenclaturalStatusType illegitimType = findILegitimateStatusType(name);
291 if(illegitimType == null){
292 Taxon taxon;
293 try {
294 logger.debug("Processing name: " + name.getTitleCache() + " [" + name.getRank().getLabel() + "]");
295 taxon = processor.assureSingleTaxon(name);
296 processor.updateEdges(taxon);
297 taxa.add(taxon);
298 } catch (TaxonGraphException e) {
299 logger.error(e.getMessage());
300 }
301 } else {
302 logger.debug("Skipping illegitimate name: " + name.getTitleCache() + " " + illegitimType.getLabel() + " [" + name.getRank().getLabel() + "]");
303 }
304 } else {
305 logger.debug("Skipping name: " + name.getTitleCache() + " [" + (name.getRank() != null ? name.getRank().getLabel() : "NULL") + "]");
306 }
307 }
308 repo.getTaxonService().saveOrUpdate(taxa);
309 repo.commitTransaction(tx);
310 }
311 }
312
313 // String wipeoutCmd = System.getProperty(PARAM_NAME_WIPEOUT);
314 // String createCmd = System.getProperty(PARAM_NAME_CREATE);
315 //
316 // // ============ DELETE
317 // if(wipeoutCmd != null && wipeoutCmd.matches("iapt|all")){
318 //
319 // boolean onlyIapt = wipeoutCmd.equals("iapt");
320 // Set<UUID> deleteCandidates = new HashSet<UUID>();
321 //
322 // TransactionStatus tx = repo.startTransaction(true);
323 // List<Registration> allRegs = repo.getRegistrationService().list(null, null, null, null, null);
324 // for(Registration reg : allRegs){
325 // if(onlyIapt){
326 // try {
327 // @SuppressWarnings("unchecked")
328 // Set<String> extensions = reg.getName().getExtensions(getExtensionTypeIAPTRegData());
329 // if(reg.getUuid() != null){
330 // deleteCandidates.add(reg.getUuid());
331 // }
332 // } catch(NullPointerException e){
333 // // IGNORE
334 // }
335 // } else {
336 // if(reg.getUuid() != null){
337 // deleteCandidates.add(reg.getUuid());
338 // }
339 // }
340 // }
341 // repo.commitTransaction(tx);
342 // if(!deleteCandidates.isEmpty()){
343 // try {
344 // repo.getRegistrationService().delete(deleteCandidates);
345 // } catch (Exception e) {
346 // // MySQLIntegrityConstraintViolationException happens here every second run !!!
347 // logger.error(e);
348 // }
349 // }
350 // }
351 //
352 // // ============ CREATE
353 // int pageIndex = 0;
354 // if(createCmd != null && createCmd.equals("iapt")){
355 //
356 // DateTimeFormatter dateFormat1 = org.joda.time.format.DateTimeFormat.forPattern("dd.MM.yy").withPivotYear(1950);
357 // DateTimeFormatter dateFormat2 = org.joda.time.format.DateTimeFormat.forPattern("yyyy-MM-dd").withPivotYear(1950);
358 //
359 // TransactionStatus tx = repo.startTransaction(false);
360 // while(true) {
361 // Pager<TaxonName> pager = repo.getNameService().page(null, 1000, pageIndex, null, null);
362 // if(pager.getRecords().isEmpty()){
363 // break;
364 // }
365 // List<Registration> newRegs = new ArrayList<>(pager.getRecords().size());
366 // for(TaxonName name : pager.getRecords()){
367 //
368 //
369 //
370 // Set<String> extensionValues = name.getExtensions(getExtensionTypeIAPTRegData());
371 //
372 // // there is for sure only one
373 // if(extensionValues.isEmpty()){
374 // continue;
375 // }
376 //
377 // logger.debug("IAPT Registration for " + name.getTitleCache() + " ...");
378 //
379 // String iaptJson = extensionValues.iterator().next();
380 // try {
381 //
382 // IAPTRegData iaptData = new ObjectMapper().readValue(iaptJson, IAPTRegData.class);
383 //
384 // if(iaptData.getRegId() == null){
385 // continue;
386 // }
387 //
388 // DateTime regDate = null;
389 // if(iaptData.getDate() != null){
390 // DateTimeFormatter dateFormat;
391 // if(iaptData.getDate().matches("\\d{4}-\\d{2}-\\d{2}")){
392 // dateFormat = dateFormat2;
393 // } else {
394 // dateFormat = dateFormat1;
395 // }
396 // try {
397 // regDate = dateFormat.parseDateTime(iaptData.getDate());
398 // regDate.getYear();
399 // } catch (Exception e) {
400 // logger.error("Error parsing date : " + iaptData.getDate(), e);
401 // continue;
402 // }
403 // }
404 //
405 // Registration reg = Registration.NewInstance();
406 // reg.setStatus(RegistrationStatus.PUBLISHED);
407 // reg.setIdentifier("http://phycobank.org/" + iaptData.getRegId());
408 // reg.setSpecificIdentifier(iaptData.getRegId().toString());
409 // reg.setInstitution(getInstitution(iaptData.getOffice()));
410 //
411 // boolean isPhycobankID = Integer.valueOf(reg.getSpecificIdentifier()) >= 100000;
412 //
413 // Partial youngestDate = null;
414 // Reference youngestPub = null;
415 //
416 // // find youngest publication
417 //
418 // // NOTE:
419 // // data imported from IAPT does not have typedesignation citations and sometimes no nomref
420 //
421 // if(isPhycobankID){
422 // youngestPub = name.getNomenclaturalReference();
423 // youngestDate = partial(youngestPub.getDatePublished());
424 //
425 // if(name.getTypeDesignations() != null && !name.getTypeDesignations().isEmpty()){
426 // for(TypeDesignationBase<?> td : name.getTypeDesignations()){
427 // if(td.getCitation() == null){
428 // continue;
429 // }
430 // Partial pubdate = partial(td.getCitation().getDatePublished());
431 // if(pubdate != null){
432 //
433 // try {
434 // if(youngestDate== null || earlierThanOther(youngestDate, pubdate)){
435 // youngestDate = pubdate;
436 // youngestPub = td.getCitation();
437 // }
438 // } catch (Exception e) {
439 // logger.error("Error comparing " + youngestDate + " with" + pubdate , e);
440 // }
441 // }
442 // }
443 // }
444 // }
445 //
446 // if((isPhycobankID && youngestPub == name.getNomenclaturalReference()) || !isPhycobankID) {
447 // reg.setName(name);
448 // } else {
449 // logger.debug("skipping name published in older referece");
450 // }
451 // if(name.getTypeDesignations() != null && !name.getTypeDesignations().isEmpty()){
452 // // do not add the collection directly to avoid "Found shared references to a collection" problem
453 // Set<TypeDesignationBase> typeDesignations = new HashSet<>(name.getTypeDesignations().size());
454 // for(TypeDesignationBase<?> td : name.getTypeDesignations()){
455 // if(td.getCitation() == null && isPhycobankID){
456 // logger.error("Missing TypeDesignation Citation in Phycobank data");
457 // continue;
458 // }
459 // if((isPhycobankID && youngestPub == td.getCitation()) || !isPhycobankID){
460 // typeDesignations.add(td);
461 // } else {
462 // logger.debug("skipping typedesignation published in older reference");
463 // }
464 // }
465 // reg.setTypeDesignations(typeDesignations);
466 // }
467 // reg.setRegistrationDate(regDate);
468 // newRegs.add(reg);
469 //
470 // } catch (JsonParseException e) {
471 // logger.error("Error parsing IAPTRegData from extension", e);
472 // } catch (JsonMappingException e) {
473 // logger.error("Error mapping json from extension to IAPTRegData", e);
474 // } catch (IOException e) {
475 // logger.error(e);
476 // }
477 //
478 // }
479 // repo.getRegistrationService().save(newRegs);
480 // tx.flush();
481 // logger.debug("Registrations saved");
482 // pageIndex++;
483 // }
484 // repo.commitTransaction(tx);
485 // }
486
487 }
488
489 private NomenclaturalStatusType findILegitimateStatusType(TaxonName name){
490 for(NomenclaturalStatus status : name.getStatus()){
491 if(status.getType() != null && !status.getType().isLegitimateType()){
492 return status.getType();
493 }
494 }
495 return null;
496 }
497
498
499 // /**
500 // * @param youngestDate
501 // * @param pubdate
502 // * @return
503 // */
504 // private boolean earlierThanOther(Partial basePartial, Partial other) {
505 //
506 // if(basePartial == null || basePartial.getValues().length == 0){
507 // return false;
508 // }
509 // if(other == null || other.getValues().length == 0){
510 // return true;
511 // }
512 // if(basePartial.size() == other.size()) {
513 // return basePartial.compareTo(other) < 0;
514 // }
515 // basePartial = basePartial.without(DateTimeFieldType.dayOfMonth());
516 // other = other.without(DateTimeFieldType.dayOfMonth());
517 // if(basePartial.size() == other.size()) {
518 // return basePartial.compareTo(other) < 0;
519 // }
520 // basePartial = basePartial.without(DateTimeFieldType.monthOfYear());
521 // other = other.without(DateTimeFieldType.monthOfYear());
522 // return basePartial.compareTo(other) < 0;
523 //
524 // }
525
526
527 // /**
528 // * @param datePublished
529 // * @return
530 // */
531 // private Partial partial(TimePeriod datePublished) {
532 // if(datePublished != null){
533 // if(datePublished.getEnd() != null){
534 // return datePublished.getEnd();
535 // } else {
536 // return datePublished.getStart();
537 // }
538 // }
539 // return null;
540 // }
541
542
543 // /**
544 // * @param office
545 // * @return
546 // */
547 // private Institution getInstitution(String office) {
548 // Institution institution;
549 // if(instituteMap.containsKey(office)){
550 // institution = instituteMap.get(office);
551 // } else {
552 //
553 // Pager<Institution> pager = repo.getAgentService().findByTitleWithRestrictions(Institution.class, office, MatchMode.EXACT, null, null, null, null, null);
554 // ) if(!pager.getRecords().isEmpty()){
555 // institution = pager.getRecords().get(0);
556 // } else {
557 // Institution institute = (Institution) repo.getAgentService().save(Institution.NewNamedInstance(office));
558 // institution = institute;
559 // }
560 // instituteMap.put(office, institution);
561 // }
562 // return institution;
563 // }
564
565
566 // private ExtensionType getExtensionTypeIAPTRegData() {
567 // if(extensionTypeIAPTRegData == null){
568 // extensionTypeIAPTRegData = (ExtensionType) repo.getTermService().load(UUID.fromString("9be1bfe3-6ba0-4560-af15-86971ab96e09"));
569 // }
570 // return extensionTypeIAPTRegData;
571 // }
572
573
574 }