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