fix #7629 restricting new registrations to those which make sense in the current...
[cdm-vaadin.git] / src / main / java / eu / etaxonomy / cdm / vaadin / view / registration / RegistrationWorkingsetPresenter.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.vaadin.view.registration;
10
11 import java.util.ArrayList;
12 import java.util.Arrays;
13 import java.util.EnumSet;
14 import java.util.HashSet;
15 import java.util.List;
16 import java.util.Objects;
17 import java.util.Set;
18 import java.util.Stack;
19 import java.util.UUID;
20
21 import org.apache.log4j.Logger;
22 import org.hibernate.Session;
23 import org.hibernate.Transaction;
24 import org.springframework.beans.factory.annotation.Autowired;
25 import org.springframework.security.core.Authentication;
26 import org.springframework.transaction.TransactionStatus;
27 import org.vaadin.spring.events.EventScope;
28 import org.vaadin.spring.events.annotation.EventBusListenerMethod;
29
30 import com.vaadin.server.SystemError;
31 import com.vaadin.spring.annotation.SpringComponent;
32 import com.vaadin.spring.annotation.ViewScope;
33 import com.vaadin.ui.AbstractField;
34 import com.vaadin.ui.Button;
35 import com.vaadin.ui.Label;
36 import com.vaadin.ui.UI;
37 import com.vaadin.ui.VerticalLayout;
38 import com.vaadin.ui.Window;
39
40 import eu.etaxonomy.cdm.api.service.INameService;
41 import eu.etaxonomy.cdm.api.service.IRegistrationService;
42 import eu.etaxonomy.cdm.api.service.config.RegistrationStatusTransitions;
43 import eu.etaxonomy.cdm.api.service.dto.RegistrationDTO;
44 import eu.etaxonomy.cdm.api.service.dto.RegistrationWorkingSet;
45 import eu.etaxonomy.cdm.api.service.exception.RegistrationValidationException;
46 import eu.etaxonomy.cdm.api.service.idminter.IdentifierMinter.Identifier;
47 import eu.etaxonomy.cdm.api.service.idminter.RegistrationIdentifierMinter;
48 import eu.etaxonomy.cdm.api.service.name.TypeDesignationSetManager.TypeDesignationWorkingSetType;
49 import eu.etaxonomy.cdm.api.service.registration.IRegistrationWorkingSetService;
50 import eu.etaxonomy.cdm.api.utility.UserHelper;
51 import eu.etaxonomy.cdm.ext.common.ExternalServiceException;
52 import eu.etaxonomy.cdm.ext.registration.messages.IRegistrationMessageService;
53 import eu.etaxonomy.cdm.model.common.User;
54 import eu.etaxonomy.cdm.model.name.NameTypeDesignation;
55 import eu.etaxonomy.cdm.model.name.Rank;
56 import eu.etaxonomy.cdm.model.name.Registration;
57 import eu.etaxonomy.cdm.model.name.RegistrationStatus;
58 import eu.etaxonomy.cdm.model.name.TaxonName;
59 import eu.etaxonomy.cdm.model.name.TaxonNameFactory;
60 import eu.etaxonomy.cdm.model.name.TypeDesignationBase;
61 import eu.etaxonomy.cdm.model.reference.Reference;
62 import eu.etaxonomy.cdm.model.reference.ReferenceType;
63 import eu.etaxonomy.cdm.persistence.hibernate.permission.CRUD;
64 import eu.etaxonomy.cdm.persistence.hibernate.permission.Operation;
65 import eu.etaxonomy.cdm.ref.EntityReference;
66 import eu.etaxonomy.cdm.ref.TypedEntityReference;
67 import eu.etaxonomy.cdm.service.CdmFilterablePagingProvider;
68 import eu.etaxonomy.cdm.service.CdmStore;
69 import eu.etaxonomy.cdm.service.UserHelperAccess;
70 import eu.etaxonomy.cdm.vaadin.component.CdmBeanItemContainerFactory;
71 import eu.etaxonomy.cdm.vaadin.component.registration.RegistrationItem;
72 import eu.etaxonomy.cdm.vaadin.component.registration.RegistrationStatusFieldInstantiator;
73 import eu.etaxonomy.cdm.vaadin.component.registration.RegistrationStatusSelect;
74 import eu.etaxonomy.cdm.vaadin.event.AbstractEditorAction.EditorActionContext;
75 import eu.etaxonomy.cdm.vaadin.event.EditorActionTypeFilter;
76 import eu.etaxonomy.cdm.vaadin.event.EntityChangeEvent;
77 import eu.etaxonomy.cdm.vaadin.event.ReferenceEditorAction;
78 import eu.etaxonomy.cdm.vaadin.event.RegistrationEditorAction;
79 import eu.etaxonomy.cdm.vaadin.event.ShowDetailsEvent;
80 import eu.etaxonomy.cdm.vaadin.event.ShowDetailsEventEntityTypeFilter;
81 import eu.etaxonomy.cdm.vaadin.event.TaxonNameEditorAction;
82 import eu.etaxonomy.cdm.vaadin.event.TypeDesignationWorkingsetEditorAction;
83 import eu.etaxonomy.cdm.vaadin.event.registration.RegistrationWorkingsetAction;
84 import eu.etaxonomy.cdm.vaadin.permission.RegistrationCuratorRoleProbe;
85 import eu.etaxonomy.cdm.vaadin.theme.EditValoTheme;
86 import eu.etaxonomy.cdm.vaadin.ui.RegistrationUIDefaults;
87 import eu.etaxonomy.cdm.vaadin.util.CdmTitleCacheCaptionGenerator;
88 import eu.etaxonomy.cdm.vaadin.view.name.NameTypeDesignationPopupEditor;
89 import eu.etaxonomy.cdm.vaadin.view.name.SpecimenTypeDesignationWorkingsetPopupEditor;
90 import eu.etaxonomy.cdm.vaadin.view.name.TaxonNamePopupEditor;
91 import eu.etaxonomy.cdm.vaadin.view.name.TaxonNamePopupEditorMode;
92 import eu.etaxonomy.cdm.vaadin.view.name.TaxonNamePopupEditorView;
93 import eu.etaxonomy.cdm.vaadin.view.name.TypeDesignationWorkingsetEditorIdSet;
94 import eu.etaxonomy.cdm.vaadin.view.reference.ReferencePopupEditor;
95 import eu.etaxonomy.vaadin.mvp.AbstractPopupEditor;
96 import eu.etaxonomy.vaadin.mvp.AbstractPresenter;
97 import eu.etaxonomy.vaadin.mvp.AbstractView;
98 import eu.etaxonomy.vaadin.mvp.BeanInstantiator;
99 import eu.etaxonomy.vaadin.ui.navigation.NavigationEvent;
100 import eu.etaxonomy.vaadin.ui.view.DoneWithPopupEvent;
101 import eu.etaxonomy.vaadin.ui.view.DoneWithPopupEvent.Reason;
102
103 /**
104 * @author a.kohlbecker
105 * @since Mar 3, 2017
106 *
107 */
108 @SpringComponent
109 @ViewScope
110 public class RegistrationWorkingsetPresenter extends AbstractPresenter<RegistrationWorkingsetView> {
111
112 private static final Logger logger = Logger.getLogger(RegistrationWorkingsetPresenter.class);
113
114 private static final List<String> REGISTRATION_INIT_STRATEGY = Arrays.asList(
115 "$",
116 "blockedBy",
117 "name.combinationAuthorship",
118 "name.exCombinationAuthorship",
119 "name.basionymAuthorship",
120 "name.exBasionymAuthorship"
121 );
122
123 private static final long serialVersionUID = 1L;
124
125 @Autowired
126 private IRegistrationWorkingSetService regWorkingSetService;
127
128 @Autowired
129 private RegistrationIdentifierMinter minter;
130
131 @Autowired
132 private IRegistrationMessageService messageService;
133
134 /**
135 * @return the regWorkingSetService
136 */
137 public IRegistrationWorkingSetService getWorkingSetService() {
138 return regWorkingSetService;
139 }
140
141 private RegistrationWorkingSet workingset;
142
143 private TaxonName newTaxonNameForRegistration = null;
144
145 private RegistrationDTO newRegistrationDTOWithExistingName;
146
147 private RegistrationDTO newNameTypeDesignationTarget;
148
149
150 /**
151 *
152 */
153 public RegistrationWorkingsetPresenter() {
154 }
155
156 /**
157 * Always create a new Store
158 *
159 * @return
160 */
161 protected CdmStore<Registration, IRegistrationService> getRegistrationStore(){
162 return new CdmStore<Registration, IRegistrationService>(getRepo(), getRepo().getRegistrationService());
163 }
164
165 /**
166 * Always create a new Store
167 *
168 * @return
169 */
170 protected CdmStore<TaxonName, INameService> getTaxonNameStore(){
171 return new CdmStore<TaxonName, INameService>(getRepo(), getRepo().getNameService());
172 }
173
174 /**
175 * Checks
176 * <ol>
177 * <li>if there is NOT any registration for this name created in the current registration system</li>
178 * <li>Checks if the name belongs to the current workingset</li>
179 * </ol>
180 * If both checks are successful the method returns <code>true</code>.
181 */
182 public boolean canCreateNameRegistrationFor(TaxonName name) {
183 return !checkRegistrationExistsFor(name) && checkWokingsetContainsProtologe(name);
184 }
185
186 /**
187 * @param name
188 * @return
189 */
190 public boolean checkWokingsetContainsProtologe(TaxonName name) {
191 Reference nomRef = name.getNomenclaturalReference();
192 UUID citationUuid = workingset.getCitationUuid();
193 // @formatter:off
194 return nomRef != null && (
195 // nomref matches
196 nomRef.getUuid().equals(citationUuid) ||
197 // nomref.inreference matches
198 (nomRef.getType() != null && nomRef.getType() == ReferenceType.Section && nomRef.getInReference() != null && nomRef.getInReference().getUuid().equals(citationUuid))
199 );
200 // @formatter:on
201 }
202
203 /**
204 * @param name
205 */
206 public boolean checkRegistrationExistsFor(TaxonName name) {
207
208 for(Registration reg : name.getRegistrations()){
209 if(minter.isFromOwnRegistration(reg.getIdentifier())){
210 return true;
211 }
212 }
213 return false;
214 }
215
216
217
218 /**
219 * @param taxonNameId
220 * @return
221 */
222 protected Registration createNewRegistrationForName(UUID taxonNameUuid) {
223 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
224 // move into RegistrationWorkflowStateMachine
225 TransactionStatus txStatus = getRepo().startTransaction();
226
227 Identifier<String> identifiers = minter.mint();
228 if(identifiers.getIdentifier() == null){
229 throw new RuntimeException("RegistrationIdentifierMinter configuration incomplete.");
230 }
231 Registration reg = Registration.NewInstance(
232 identifiers.getIdentifier(),
233 identifiers.getLocalId(),
234 taxonNameUuid != null ? getRepo().getNameService().load(taxonNameUuid, Arrays.asList("nomenclaturalReference.inReference")) : null,
235 null);
236 Authentication authentication = currentSecurityContext().getAuthentication();
237 reg.setSubmitter((User)authentication.getPrincipal());
238 EntityChangeEvent event = getRegistrationStore().saveBean(reg, (AbstractView) getView());
239 UserHelperAccess.userHelper().createAuthorityForCurrentUser(Registration.class, event.getEntityUuid(), Operation.UPDATE, RegistrationStatus.PREPARATION.name());
240 getRepo().commitTransaction(txStatus);
241 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
242 return getRepo().getRegistrationService().load(event.getEntityUuid(), Arrays.asList(new String []{"blockedBy"}));
243 }
244
245 /**
246 * @param doReload TODO
247 *
248 */
249 protected void refreshView(boolean doReload) {
250 if(workingset == null){
251 return; // nothing to do
252 }
253 if(doReload){
254 loadWorkingSet(workingset.getCitationUuid());
255 }
256 applyWorkingset();
257 }
258
259 /**
260 * {@inheritDoc}
261 */
262 @Override
263 public void handleViewEntered() {
264 super.handleViewEntered();
265 // TODO currently cannot specify type more precisely, see AbstractSelect
266 // FIXME externalize into class file!!!!!!!!!!!!
267 getView().setStatusComponentInstantiator(new RegistrationStatusFieldInstantiator<Object>(){
268
269 private static final long serialVersionUID = 7099181280977511048L;
270
271 @Override
272 public AbstractField<Object> create(RegistrationDTO regDto) {
273
274 CdmBeanItemContainerFactory selectFieldFactory = new CdmBeanItemContainerFactory(getRepo());
275 // submitters have GrantedAuthorities like REGISTRATION(PREPARATION).[UPDATE]{ab4459eb-3b96-40ba-bfaa-36915107d59e}
276 UserHelper userHelper = UserHelperAccess.userHelper();
277 Set<RegistrationStatus> availableStatus = new HashSet<>();
278
279 boolean canChangeStatus = userHelper.userHasPermission(regDto.registration(), CRUD.UPDATE);
280 availableStatus.add(regDto.getStatus());
281 if(canChangeStatus){
282 if(userHelper.userIsAdmin()){
283 availableStatus.addAll(Arrays.asList(RegistrationStatus.values()));
284 } else {
285 availableStatus.addAll(RegistrationStatusTransitions.possibleTransitions(regDto.getStatus()));
286 }
287 }
288
289 RegistrationStatusSelect select = new RegistrationStatusSelect(null, selectFieldFactory.buildBeanItemContainer(
290 RegistrationStatus.class,
291 availableStatus.toArray(new RegistrationStatus[availableStatus.size()]))
292 );
293 select.addValueChangeListener(e -> saveRegistrationStatusChange(regDto.getUuid(), e.getProperty().getValue()));
294 select.setEnabled(canChangeStatus);
295 select.setNullSelectionAllowed(false);
296 return select;
297 }
298
299
300 });
301 loadWorkingSet(getView().getCitationUuid());
302 applyWorkingset();
303
304 }
305
306 private void applyWorkingset(){
307 getView().setWorkingset(workingset);
308 // PagingProviders and CacheGenerator for the existingNameCombobox
309 activateComboboxes();
310 // update the messages
311 updateMessages();
312 }
313
314 /**
315 *
316 */
317 protected void activateComboboxes() {
318 CdmFilterablePagingProvider<TaxonName, TaxonName> pagingProvider = new CdmFilterablePagingProvider<TaxonName, TaxonName>(
319 getRepo().getNameService());
320 pagingProvider.setInitStrategy(Arrays.asList("registrations", "nomenclaturalReference"));
321 CdmTitleCacheCaptionGenerator<TaxonName> titleCacheGenerator = new CdmTitleCacheCaptionGenerator<TaxonName>();
322 getView().getAddExistingNameCombobox().setCaptionGenerator(titleCacheGenerator);
323 getView().getAddExistingNameCombobox().loadFrom(pagingProvider, pagingProvider, pagingProvider.getPageSize());
324 }
325
326 /**
327 *
328 */
329 protected void updateMessages() {
330 User user = UserHelperAccess.userHelper().user();
331 for (UUID registrationUuid : getView().getRegistrationItemMap().keySet()) {
332 Button messageButton = getView().getRegistrationItemMap().get(registrationUuid).regItemButtons.getMessagesButton();
333
334 RegistrationDTO regDto = workingset.getRegistrationDTO(registrationUuid).get();
335 try {
336 int messageCount = messageService.countActiveMessagesFor(regDto.registration(), user);
337
338 boolean activeMessages = messageCount > 0;
339 boolean currentUserIsSubmitter = regDto.getSubmitterUserName() != null && regDto.getSubmitterUserName().equals(UserHelperAccess.userHelper().userName());
340 boolean currentUserIsCurator = UserHelperAccess.userHelper().userIs(new RegistrationCuratorRoleProbe());
341 messageButton.setEnabled(false);
342 if(currentUserIsCurator){
343 if(currentUserIsSubmitter){
344 messageButton.setDescription("No point sending messages to your self.");
345 } else {
346 messageButton.setEnabled(true);
347 messageButton.setDescription("Open the messages dialog.");
348 }
349 } else {
350 messageButton.setDescription("Sorry, only a curator can start a conversation.");
351 }
352 if(activeMessages){
353 messageButton.setEnabled(true);
354 messageButton.addStyleName(EditValoTheme.BUTTON_HIGHLITE);
355 String who = currentUserIsSubmitter ? "curator" : "submitter";
356 messageButton.setDescription("The " + who + " is looking forward to your reply.");
357
358 }
359 } catch (ExternalServiceException e) {
360 messageButton.setComponentError(new SystemError(e.getMessage(), e));
361 }
362 }
363 }
364
365
366 /**
367 * @param referenceID
368 */
369 protected void loadWorkingSet(UUID referenceUuid) {
370 try {
371 workingset = getWorkingSetService().loadWorkingSetByReferenceUuid(referenceUuid, true);
372 } catch (RegistrationValidationException error) {
373 logger.error(error);
374 Window errorDialog = new Window("Validation Error");
375 errorDialog.setModal(true);
376 VerticalLayout subContent = new VerticalLayout();
377 subContent.setMargin(true);
378 errorDialog.setContent(subContent);
379 subContent.addComponent(new Label(error.getMessage()));
380 UI.getCurrent().addWindow(errorDialog);
381 }
382 if(workingset == null || workingset.getCitationUuid() == null){
383 Reference citation = getRepo().getReferenceService().find(referenceUuid);
384 workingset = new RegistrationWorkingSet(citation);
385 }
386 }
387
388 private void saveRegistrationStatusChange(UUID uuid, Object value) {
389 Registration reg = getRepo().getRegistrationService().load(uuid);
390 if(value != null && value instanceof RegistrationStatus){
391 if(!Objects.equals(value, reg.getStatus())){
392 reg.setStatus((RegistrationStatus)value);
393 getRegistrationStore().saveBean(reg, (AbstractView)getView());
394 refreshView(true);
395 }
396 } else {
397 // only log here as error
398 logger.error("Ivalid attempt to set RegistrationStatus to " + Objects.toString(value.toString(), "NULL"));
399 }
400 }
401
402
403 @EventBusListenerMethod(filter = EditorActionTypeFilter.Add.class)
404 public void onReferenceEditorActionAdd(ReferenceEditorAction event) {
405
406 if(!checkFromOwnView(event)){
407 return;
408 }
409
410 ReferencePopupEditor popup = openPopupEditor(ReferencePopupEditor.class, event);
411 popup.withReferenceTypes(RegistrationUIDefaults.PRINTPUB_REFERENCE_TYPES);
412 popup.loadInEditor(null);
413 }
414
415 @EventBusListenerMethod(filter = EditorActionTypeFilter.Edit.class)
416 public void onReferenceEditorActionEdit(ReferenceEditorAction event) {
417
418 if(!checkFromOwnView(event)){
419 return;
420 }
421 ReferencePopupEditor popup = openPopupEditor(ReferencePopupEditor.class, event);
422 popup.withReferenceTypes(RegistrationUIDefaults.PRINTPUB_REFERENCE_TYPES);
423 popup.withDeleteButton(true);
424 popup.loadInEditor(event.getEntityUuid());
425 }
426
427 @EventBusListenerMethod
428 public void onDoneWithReferencePopupEditor(DoneWithPopupEvent event) throws RegistrationValidationException{
429 if(event.getPopup() instanceof ReferencePopupEditor){
430 if(event.getReason().equals(Reason.SAVE)){
431 refreshView(true);
432 }
433 }
434 }
435
436 @EventBusListenerMethod
437 public void onDoneWithSpecimenTypeDesignationWorkingsetPopupEditor(DoneWithPopupEvent event) throws RegistrationValidationException{
438 if(event.getPopup() instanceof SpecimenTypeDesignationWorkingsetPopupEditor){
439 if(event.getReason().equals(Reason.SAVE)){
440 refreshView(true);
441 }
442 }
443 }
444
445 @EventBusListenerMethod(filter = EditorActionTypeFilter.Edit.class)
446 public void onRegistrationEditorAction(RegistrationEditorAction event) {
447
448 if(!checkFromOwnView(event)){
449 return;
450 }
451
452 RegistrationPopupEditor popup = openPopupEditor(RegistrationPopupEditor.class, event);
453 popup.loadInEditor(event.getEntityUuid());
454 }
455
456 @EventBusListenerMethod(filter = EditorActionTypeFilter.Edit.class)
457 public void onTaxonNameEditorActionEdit(TaxonNameEditorAction event) {
458
459 if(!checkFromOwnView(event)){
460 return;
461 }
462
463 TaxonNamePopupEditor popup = openPopupEditor(TaxonNamePopupEditor.class, event);
464 popup.setParentEditorActionContext(event.getContext());
465 popup.withDeleteButton(true);
466 configureTaxonNameEditor(popup);
467 popup.loadInEditor(event.getEntityUuid());
468 if(event.hasSource() && event.getSource().isReadOnly()){
469 // avoid resetting readonly to false
470 popup.setReadOnly(true);
471 }
472
473 }
474
475
476 @EventBusListenerMethod(filter = EditorActionTypeFilter.Add.class)
477 public void onTaxonNameEditorActionAdd(TaxonNameEditorAction event) {
478
479 if(!checkFromOwnView(event)){
480 return;
481 }
482
483 newTaxonNameForRegistration = TaxonNameFactory.NewNameInstance(RegistrationUIDefaults.NOMENCLATURAL_CODE, Rank.SPECIES());
484 newTaxonNameForRegistration.setNomenclaturalReference(getRepo().getReferenceService().find(workingset.getCitationUuid()));
485 EntityChangeEvent nameSaveEvent = getTaxonNameStore().saveBean(newTaxonNameForRegistration, (AbstractView) getView());
486 newTaxonNameForRegistration = getRepo().getNameService().find(nameSaveEvent.getEntityUuid());
487 TaxonNamePopupEditor popup = openPopupEditor(TaxonNamePopupEditor.class, event);
488 popup.setParentEditorActionContext(event.getContext());
489 popup.grantToCurrentUser(EnumSet.of(CRUD.UPDATE,CRUD.DELETE));
490 popup.withDeleteButton(true);
491 configureTaxonNameEditor(popup);
492 popup.loadInEditor(newTaxonNameForRegistration.getUuid());
493 }
494
495 /**
496 * TODO consider putting this into a Configurer Bean per UIScope.
497 * In the configurator bean this methods popup papamerter should be of the type
498 * AbstractPopupEditor
499 *
500 * @param popup
501 */
502 protected void configureTaxonNameEditor(TaxonNamePopupEditorView popup) {
503 popup.enableMode(TaxonNamePopupEditorMode.AUTOFILL_AUTHORSHIP_DATA);
504 popup.enableMode(TaxonNamePopupEditorMode.NOMENCLATURALREFERENCE_SECTION_EDITING_ONLY);
505 popup.enableMode(TaxonNamePopupEditorMode.VALIDATE_AGAINST_HIGHER_NAME_PART);
506 // popup.enableMode(TaxonNamePopupEditorMode.REQUIRE_NOMENCLATURALREFERENCE);
507 }
508
509 /**
510 * Creates a new <code>Registration</code> for a new name that has just been edited
511 * using the <code>TaxonNamePopupEditor</code>. The new name was previously created
512 * in this presenter as <code>newTaxonNameForRegistration</code> (see {@link #onTaxonNameEditorActionAdd(TaxonNameEditorAction)})
513 * and is either filled with data (<code>Reason.SAVE</code>) or it is still empty
514 * (<code>Reason.CANCEL</code>).
515 *
516 *
517 * @param event
518 * @throws RegistrationValidationException
519 */
520 @EventBusListenerMethod
521 public void onDoneWithTaxonnameEditor(DoneWithPopupEvent event) throws RegistrationValidationException{
522 if(event.getPopup() instanceof TaxonNamePopupEditor){
523 TransactionStatus txStatus = getRepo().startTransaction();
524 if(event.getReason().equals(Reason.SAVE)){
525 if(newTaxonNameForRegistration != null){
526 UUID taxonNameUuid = newTaxonNameForRegistration.getUuid();
527 getRepo().getSession().refresh(newTaxonNameForRegistration);
528 Registration reg = createNewRegistrationForName(taxonNameUuid);
529 // reload workingset into current session
530 loadWorkingSet(workingset.getCitationUuid());
531 workingset.add(reg);
532 }
533 refreshView(true);
534 } else if(event.getReason().equals(Reason.CANCEL)){
535 if(newTaxonNameForRegistration != null){
536 // clean up
537 getTaxonNameStore().deleteBean(newTaxonNameForRegistration, (AbstractView) getView());
538 }
539 }
540 getRepo().commitTransaction(txStatus);
541 newTaxonNameForRegistration = null;
542 }
543 }
544
545
546 /**
547 * Creates a new Registration for an exiting (previously published name).
548 *
549 * @param event
550 * @throws RegistrationValidationException
551 */
552 @EventBusListenerMethod
553 public void onRegistrationWorkflowEventActionStart(RegistrationWorkingsetAction event) throws RegistrationValidationException {
554
555 if(!event.isStart()){
556 return;
557 }
558
559 getView().getAddExistingNameCombobox().commit(); // update the chosen value in the datasource
560 TaxonName typifiedName = getView().getAddExistingNameCombobox().getValue();
561 if(typifiedName != null){
562 boolean reloadWorkingSet = false;
563 Reference citation = getRepo().getReferenceService().find(workingset.getCitationUuid());
564 // here we completely ignore the ExistingNameRegistrationType since the user should not have the choice
565 // to create a typification only registration in the working (publication) set which contains
566 // the protologe. This is known from the nomenclatural reference.
567 if(canCreateNameRegistrationFor(typifiedName)){
568 // the citation which is the base for workingset contains the protologe of the name and the name has not
569 // been registered before:
570 // create a registration for the name and the first typifications
571 Registration newRegistrationWithExistingName = createNewRegistrationForName(typifiedName.getUuid());
572 newRegistrationDTOWithExistingName = new RegistrationDTO(newRegistrationWithExistingName, typifiedName, citation);
573 reloadWorkingSet = true;
574 } else {
575 if(!checkWokingsetContainsProtologe(typifiedName)){
576 // create a typification only registration
577 Registration typificationOnlyRegistration = createNewRegistrationForName(null);
578 if(!checkRegistrationExistsFor(typifiedName)){
579 // oops, yet no registration for this name, so we create it as blocking registration:
580 Registration blockingNameRegistration = createNewRegistrationForName(typifiedName.getUuid());
581 typificationOnlyRegistration.getBlockedBy().add(blockingNameRegistration);
582 }
583 newRegistrationDTOWithExistingName = new RegistrationDTO(typificationOnlyRegistration, typifiedName, citation);
584 }
585 }
586 workingset.add(newRegistrationDTOWithExistingName);
587 // tell the view to update the workingset
588 refreshView(reloadWorkingSet);
589 getView().getAddExistingNameRegistrationButton().setEnabled(false);
590 if(newRegistrationDTOWithExistingName.registration().getName() == null){
591 getView().getAddExistingNameCombobox().setEnabled(false);
592 getView().getAddNewNameRegistrationButton().setEnabled(false);
593 getView().getAddNewNameRegistrationButton().setDescription("You first need to add a type designation to the previously created registration.");
594 getView().getAddExistingNameCombobox().setDescription("You first need to add a type designation to the previously created registration.");
595 getView().getAddExistingNameRegistrationButton().setDescription("You first need to add a type designation to the previously created registration.");
596 }
597 } else {
598 logger.error("Seletced name is NULL");
599 }
600
601 }
602
603
604 @EventBusListenerMethod(filter = EditorActionTypeFilter.Edit.class)
605 public void onTypeDesignationsEditorActionEdit(TypeDesignationWorkingsetEditorAction event) {
606
607 if(!checkFromOwnView(event)){
608 return;
609 }
610
611 if(event.getWorkingSetType() == TypeDesignationWorkingSetType.SPECIMEN_TYPE_DESIGNATION_WORKINGSET ){
612 SpecimenTypeDesignationWorkingsetPopupEditor popup = openPopupEditor(SpecimenTypeDesignationWorkingsetPopupEditor.class, event);
613 popup.setParentEditorActionContext(event.getContext());
614 popup.withDeleteButton(true);
615 popup.loadInEditor(new TypeDesignationWorkingsetEditorIdSet(event.getRegistrationUuid(), event.getBaseEntityRef()));
616 if(event.hasSource()){
617 // propagate readonly state from source button to popup
618 popup.setReadOnly(event.getSource().isReadOnly());
619 }
620 } else {
621 NameTypeDesignationPopupEditor popup = openPopupEditor(NameTypeDesignationPopupEditor.class, event);
622 popup.setParentEditorActionContext(event.getContext());
623 popup.withDeleteButton(true);
624 popup.loadInEditor(new TypeDesignationWorkingsetEditorIdSet(event.getRegistrationUuid(), event.getBaseEntityRef()));
625
626 popup.getCitationCombobox().setEnabled(false);
627 popup.getTypifiedNamesComboboxSelect().setEnabled(false);
628
629 if(event.hasSource()){
630 // propagate readonly state from source button to popup
631 popup.setReadOnly(event.getSource().isReadOnly());
632 }
633 newNameTypeDesignationTarget = workingset.getRegistrationDTO(event.getRegistrationUuid()).get();
634 }
635 }
636
637 @EventBusListenerMethod(filter = EditorActionTypeFilter.Add.class)
638 public void onTypeDesignationWorkingsetAdd(TypeDesignationWorkingsetEditorAction event) {
639
640 if(!event.hasSource()){
641 return;
642 }
643
644 if(event.getWorkingSetType() == TypeDesignationWorkingSetType.SPECIMEN_TYPE_DESIGNATION_WORKINGSET){
645 SpecimenTypeDesignationWorkingsetPopupEditor popup = openPopupEditor(SpecimenTypeDesignationWorkingsetPopupEditor.class, event);
646 popup.setParentEditorActionContext(event.getContext());
647 TypeDesignationWorkingsetEditorIdSet identifierSet;
648 UUID typifiedNameUuid;
649 if(newRegistrationDTOWithExistingName != null){
650 typifiedNameUuid = newRegistrationDTOWithExistingName.getTypifiedNameRef().getUuid();
651 } else {
652 RegistrationDTO registrationDTO = workingset.getRegistrationDTO(event.getRegistrationUuid()).get();
653 EntityReference typifiedNameRef = registrationDTO.getTypifiedNameRef();
654 if(typifiedNameRef != null){
655 // case for registrations without name, in which case the typifiedName is only defined via the typedesignations
656 typifiedNameUuid = typifiedNameRef.getUuid();
657 } else {
658 // case of registrations with a name in the nomenclatural act.
659 typifiedNameUuid = registrationDTO.getNameRef().getUuid();
660 }
661 }
662 identifierSet = new TypeDesignationWorkingsetEditorIdSet(
663 event.getRegistrationUuid(),
664 getView().getCitationUuid(),
665 typifiedNameUuid
666 );
667 popup.grantToCurrentUser(EnumSet.of(CRUD.UPDATE, CRUD.DELETE));
668 popup.loadInEditor(identifierSet);
669 popup.withDeleteButton(true);
670 if(event.hasSource()){
671 // propagate readonly state from source component to popup
672 popup.setReadOnly(event.getSource().isReadOnly());
673 }
674 } else {
675 NameTypeDesignationPopupEditor popup = openPopupEditor(NameTypeDesignationPopupEditor.class, event);
676 popup.setParentEditorActionContext(event.getContext());
677 popup.withDeleteButton(true);
678 popup.grantToCurrentUser(EnumSet.of(CRUD.UPDATE, CRUD.DELETE));
679 newNameTypeDesignationTarget = workingset.getRegistrationDTO(event.getRegistrationUuid()).get();
680 popup.setBeanInstantiator(new BeanInstantiator<NameTypeDesignation>() {
681
682 @Override
683 public NameTypeDesignation createNewBean() {
684
685 TaxonName typifiedName = getRepo().getNameService().load(event.getTypifiedNameUuid(), Arrays.asList(new String[]{"typeDesignations", "homotypicalGroup"}));
686 NameTypeDesignation nameTypeDesignation = NameTypeDesignation.NewInstance();
687 nameTypeDesignation.setCitation(newNameTypeDesignationTarget.getCitation());
688 nameTypeDesignation.getTypifiedNames().add(typifiedName);
689 return nameTypeDesignation;
690 }
691 });
692 popup.loadInEditor(null);
693 popup.getCitationCombobox().setEnabled(false);
694 popup.getTypifiedNamesComboboxSelect().setEnabled(false);
695 if(event.hasSource()){
696 // propagate readonly state from source component to popup
697 popup.setReadOnly(event.getSource().isReadOnly());
698 }
699 }
700 }
701
702 /**
703 * Performs final actions after a TypeDesignationEditor which has been
704 * opened to add a TypeDesignation to a Registration object which was
705 * created for an previously published name. Prior adding a typedesignation,
706 * the according Registration object is dangling, that has no association to
707 * any entity denoting an nomenclatural act which has a reference to a
708 * publication. This means that the registration object is not in the
709 * working set.
710 *
711 *
712 * @param event
713 * @throws RegistrationValidationException
714 */
715 @EventBusListenerMethod
716 public void onDoneWithTypeDesignationEditor(DoneWithPopupEvent event) throws RegistrationValidationException{
717 if(event.getPopup() instanceof SpecimenTypeDesignationWorkingsetPopupEditor){
718 if(event.getReason().equals(Reason.SAVE)){
719 refreshView(true);
720 } else if(event.getReason().equals(Reason.CANCEL)){
721 // noting to do
722 }
723 newRegistrationDTOWithExistingName = null;
724 } else if(event.getPopup() instanceof NameTypeDesignationPopupEditor){
725 if(event.getReason().equals(Reason.SAVE)){
726 UUID uuid = ((NameTypeDesignationPopupEditor)event.getPopup()).getBean().getUuid();
727
728 Session session = getRepo().getSessionFactory().openSession();
729 Transaction txstate = session.beginTransaction();
730 TypeDesignationBase<?> nameTypeDesignation = getRepo().getNameService().loadTypeDesignation(uuid, Arrays.asList(""));
731 // only load the typeDesignations with the registration so that the typified name can not be twice in the session
732 // otherwise multiple representation problems might occur
733 Registration registration = getRepo().getRegistrationService().load(newNameTypeDesignationTarget.getUuid(), Arrays.asList("typeDesignations"));
734 registration.getTypeDesignations().add(nameTypeDesignation);
735 session.merge(registration);
736 txstate.commit();
737 session.close();
738
739 refreshView(true);
740 } else if(event.getReason().equals(Reason.CANCEL)){
741 // noting to do
742 }
743 newNameTypeDesignationTarget = null;
744 }
745 // ignore other editors
746 }
747
748
749 @EventBusListenerMethod(filter = ShowDetailsEventEntityTypeFilter.RegistrationWorkingSet.class)
750 public void onShowDetailsEventForRegistrationWorkingSet(ShowDetailsEvent<RegistrationWorkingSet,?> event) {
751
752 if(event.getProperty().equals(RegistrationItem.VALIDATION_PROBLEMS)){
753 List<String> messages = new ArrayList<>();
754 for(RegistrationDTO dto : workingset.getRegistrationDTOs()){
755 dto.getValidationProblems().forEach(m -> messages.add(dto.getSummary() + ": " + m));
756 }
757 getView().openDetailsPopup("Validation Problems", messages);
758 }
759 }
760
761 @EventBusListenerMethod
762 public void onEntityChangeEvent(EntityChangeEvent event){
763
764 if(workingset == null){
765 return;
766 }
767 if(Reference.class.isAssignableFrom(event.getEntityType())){
768
769 if(workingset.getCitationUuid().equals(event.getEntityUuid())){
770 if(event.isRemovedType()){
771 viewEventBus.publish(EventScope.UI, this, new NavigationEvent(StartRegistrationViewBean.NAME));
772 } else {
773 refreshView(true);
774 }
775 }
776
777 } else
778 if(Registration.class.isAssignableFrom(event.getEntityType())){
779 if(workingset.getRegistrations().stream().anyMatch(reg -> reg.getUuid() == event.getEntityUuid())){
780 refreshView(true);
781 }
782 } else
783 if(TaxonName.class.isAssignableFrom(event.getEntityType()) && isFromOwnView(event)){
784 if(event.getType().equals(EntityChangeEvent.Type.CREATED)){
785 // new name! create a blocking registration
786 Stack<EditorActionContext>context = ((AbstractPopupEditor)event.getSourceView()).getEditorActionContext();
787 EditorActionContext rootContext = context.get(0);
788 if(rootContext.getParentView().equals(getView())){
789 Registration blockingRegistration = createNewRegistrationForName(event.getEntityUuid());
790 TypedEntityReference<Registration> regReference = (TypedEntityReference<Registration>)rootContext.getParentEntity();
791 Registration registration = getRepo().getRegistrationService().load(regReference.getUuid(), REGISTRATION_INIT_STRATEGY);
792 registration.getBlockedBy().add(blockingRegistration);
793 getRepo().getRegistrationService().saveOrUpdate(registration);
794 logger.debug("Blocking registration created");
795 } else {
796 logger.debug("Non blocking registration, since a new name for a new registration has been created");
797 }
798 }
799 if(workingset.getRegistrationDTOs().stream().anyMatch(reg ->
800 reg.getTypifiedNameRef() != null
801 && reg.getTypifiedNameRef().getUuid().equals(event.getEntityUuid()))){
802 refreshView(true);
803 }
804 } else
805 if(TypeDesignationBase.class.isAssignableFrom(event.getEntityType())){
806 if(workingset.getRegistrationDTOs().stream().anyMatch(
807 reg -> reg.typeDesignations() != null && reg.typeDesignations().stream().anyMatch(
808 td -> td.getUuid() == event.getEntityUuid()
809 )
810 )
811 ){
812 refreshView(true);
813 }
814 }
815 }
816
817
818 @EventBusListenerMethod(filter = ShowDetailsEventEntityTypeFilter.RegistrationDTO.class)
819 public void onShowDetailsEventForRegistrationDTO(ShowDetailsEvent<RegistrationDTO, UUID> event) {
820
821 // FIXME check from own view!!!
822 if(getView() == null){
823 return;
824 }
825
826 UUID registrationUuid = event.getIdentifier();
827
828 RegistrationDTO regDto = getWorkingSetService().loadDtoByUuid(registrationUuid);
829 if(event.getProperty().equals(RegistrationItem.BLOCKED_BY)){
830
831 Set<RegistrationDTO> blockingRegs = getWorkingSetService().loadBlockingRegistrations(registrationUuid);
832 getView().setBlockingRegistrations(registrationUuid, blockingRegs);
833 } else if(event.getProperty().equals(RegistrationItem.MESSAGES)){
834
835 RegistrationMessagesPopup popup = openPopupEditor(RegistrationMessagesPopup.class, null);
836 popup.loadMessagesFor(regDto.getUuid());
837
838 } else if(event.getProperty().equals(RegistrationItem.VALIDATION_PROBLEMS)){
839 getView().openDetailsPopup("Validation Problems", regDto.getValidationProblems());
840 }
841
842
843 }
844
845 }