fix #7968 validators for completeness of Partial and TimePeriod
[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.Collection;
14 import java.util.EnumSet;
15 import java.util.HashMap;
16 import java.util.HashSet;
17 import java.util.List;
18 import java.util.Map;
19 import java.util.Objects;
20 import java.util.Optional;
21 import java.util.Set;
22 import java.util.Stack;
23 import java.util.UUID;
24
25 import org.apache.log4j.Logger;
26 import org.springframework.beans.factory.annotation.Autowired;
27 import org.vaadin.spring.events.EventScope;
28 import org.vaadin.spring.events.annotation.EventBusListenerMethod;
29
30 import com.vaadin.spring.annotation.SpringComponent;
31 import com.vaadin.spring.annotation.ViewScope;
32 import com.vaadin.ui.AbstractField;
33 import com.vaadin.ui.Label;
34 import com.vaadin.ui.UI;
35 import com.vaadin.ui.VerticalLayout;
36 import com.vaadin.ui.Window;
37
38 import eu.etaxonomy.cdm.api.service.config.RegistrationStatusTransitions;
39 import eu.etaxonomy.cdm.api.service.dto.RegistrationDTO;
40 import eu.etaxonomy.cdm.api.service.dto.RegistrationWorkingSet;
41 import eu.etaxonomy.cdm.api.service.exception.RegistrationValidationException;
42 import eu.etaxonomy.cdm.api.service.name.TypeDesignationSetManager.TypeDesignationWorkingSetType;
43 import eu.etaxonomy.cdm.api.service.registration.IRegistrationWorkingSetService;
44 import eu.etaxonomy.cdm.api.utility.UserHelper;
45 import eu.etaxonomy.cdm.cache.CdmTransientEntityAndUuidCacher;
46 import eu.etaxonomy.cdm.database.PermissionDeniedException;
47 import eu.etaxonomy.cdm.model.ICdmEntityUuidCacher;
48 import eu.etaxonomy.cdm.model.common.CdmBase;
49 import eu.etaxonomy.cdm.model.name.NameTypeDesignation;
50 import eu.etaxonomy.cdm.model.name.Rank;
51 import eu.etaxonomy.cdm.model.name.Registration;
52 import eu.etaxonomy.cdm.model.name.RegistrationStatus;
53 import eu.etaxonomy.cdm.model.name.TaxonName;
54 import eu.etaxonomy.cdm.model.name.TaxonNameFactory;
55 import eu.etaxonomy.cdm.model.name.TypeDesignationBase;
56 import eu.etaxonomy.cdm.model.reference.Reference;
57 import eu.etaxonomy.cdm.persistence.hibernate.permission.CRUD;
58 import eu.etaxonomy.cdm.ref.EntityReference;
59 import eu.etaxonomy.cdm.ref.TypedEntityReference;
60 import eu.etaxonomy.cdm.service.CdmBeanItemContainerFactory;
61 import eu.etaxonomy.cdm.service.CdmFilterablePagingProvider;
62 import eu.etaxonomy.cdm.service.CdmFilterablePagingProviderFactory;
63 import eu.etaxonomy.cdm.service.CdmStore;
64 import eu.etaxonomy.cdm.service.IRegistrationWorkflowService;
65 import eu.etaxonomy.cdm.service.UserHelperAccess;
66 import eu.etaxonomy.cdm.vaadin.component.registration.RegistrationItem;
67 import eu.etaxonomy.cdm.vaadin.component.registration.RegistrationStatusFieldInstantiator;
68 import eu.etaxonomy.cdm.vaadin.component.registration.RegistrationStatusSelect;
69 import eu.etaxonomy.cdm.vaadin.event.EditorActionContext;
70 import eu.etaxonomy.cdm.vaadin.event.EditorActionTypeFilter;
71 import eu.etaxonomy.cdm.vaadin.event.EntityChangeEvent;
72 import eu.etaxonomy.cdm.vaadin.event.ReferenceEditorAction;
73 import eu.etaxonomy.cdm.vaadin.event.RegistrationEditorAction;
74 import eu.etaxonomy.cdm.vaadin.event.ShowDetailsEvent;
75 import eu.etaxonomy.cdm.vaadin.event.ShowDetailsEventEntityTypeFilter;
76 import eu.etaxonomy.cdm.vaadin.event.TaxonNameEditorAction;
77 import eu.etaxonomy.cdm.vaadin.event.TypeDesignationWorkingsetEditorAction;
78 import eu.etaxonomy.cdm.vaadin.event.registration.RegistrationWorkingsetAction;
79 import eu.etaxonomy.cdm.vaadin.permission.AccessRestrictedView;
80 import eu.etaxonomy.cdm.vaadin.ui.RegistrationUIDefaults;
81 import eu.etaxonomy.cdm.vaadin.ui.config.TaxonNamePopupEditorConfig;
82 import eu.etaxonomy.cdm.vaadin.util.CdmTitleCacheCaptionGenerator;
83 import eu.etaxonomy.cdm.vaadin.view.name.CachingPresenter;
84 import eu.etaxonomy.cdm.vaadin.view.name.NameTypeDesignationPopupEditor;
85 import eu.etaxonomy.cdm.vaadin.view.name.SpecimenTypeDesignationWorkingsetPopupEditor;
86 import eu.etaxonomy.cdm.vaadin.view.name.TaxonNameEditorPresenter;
87 import eu.etaxonomy.cdm.vaadin.view.name.TaxonNamePopupEditor;
88 import eu.etaxonomy.cdm.vaadin.view.name.TypeDesignationWorkingsetEditorIdSet;
89 import eu.etaxonomy.cdm.vaadin.view.reference.ReferencePopupEditor;
90 import eu.etaxonomy.vaadin.mvp.AbstractPopupEditor;
91 import eu.etaxonomy.vaadin.mvp.AbstractPresenter;
92 import eu.etaxonomy.vaadin.mvp.AbstractView;
93 import eu.etaxonomy.vaadin.mvp.BeanInstantiator;
94 import eu.etaxonomy.vaadin.ui.navigation.NavigationEvent;
95 import eu.etaxonomy.vaadin.ui.view.DoneWithPopupEvent;
96 import eu.etaxonomy.vaadin.ui.view.DoneWithPopupEvent.Reason;
97 import eu.etaxonomy.vaadin.ui.view.PopupView;
98
99 /**
100 * @author a.kohlbecker
101 * @since Mar 3, 2017
102 *
103 */
104 @SpringComponent
105 @ViewScope
106 public class RegistrationWorkingsetPresenter extends AbstractPresenter<RegistrationWorkingsetView> implements CachingPresenter {
107
108 private static final Logger logger = Logger.getLogger(RegistrationWorkingsetPresenter.class);
109
110 private static final long serialVersionUID = 1L;
111
112 @Autowired
113 private IRegistrationWorkingSetService regWorkingSetService;
114
115 @Autowired
116 private IRegistrationWorkflowService registrationWorkflowService;
117
118 @Autowired
119 private CdmFilterablePagingProviderFactory pagingProviderFactory;
120
121 @Autowired
122 private CdmBeanItemContainerFactory selectFieldFactory;
123
124 @Autowired
125 private CdmStore cdmStore;
126
127 /**
128 * @return the regWorkingSetService
129 */
130 public IRegistrationWorkingSetService getWorkingSetService() {
131 return regWorkingSetService;
132 }
133
134 private RegistrationWorkingSet workingset;
135
136 /**
137 * Contains the poupeditor which has been opened to start the registration of a new name as long as it has not been saved or canceled.
138 * There can always only be one popup editor for this purpose.
139 */
140 private TaxonNamePopupEditor newNameForRegistrationPopupEditor = null;
141
142 /**
143 * Contains
144 */
145 private List<Registration> newNameBlockingRegistrations = new ArrayList<>();
146
147 /**
148 * TODO is this still needed? The regitration UUID should be accessible in the popup editor context,
149 * see findRegistrationInContext()
150 */
151 private Map<NameTypeDesignationPopupEditor, UUID> nameTypeDesignationPopupEditorRegistrationUUIDMap = new HashMap<>();
152
153
154 private ICdmEntityUuidCacher cache;
155
156 private Collection<CdmBase> rootEntities = new HashSet<>();
157
158 /**
159 *
160 */
161 public RegistrationWorkingsetPresenter() {
162 }
163
164 /**
165
166
167 /**
168 * @param doReload reload the workingset from the persistent storage.
169 * Workingsets which are not yet persisted are preserved.
170 *
171 */
172 protected void refreshView(boolean doReload) {
173 if(workingset == null){
174 return; // nothing to do
175 }
176 if(doReload){
177 List<RegistrationDTO> unpersisted = new ArrayList<>();
178 for(RegistrationDTO regDto : workingset.getRegistrationDTOs()){
179 if(!regDto.registration().isPersited()){
180 unpersisted.add(regDto);
181 }
182 }
183 loadWorkingSet(workingset.getCitationUuid());
184 for(RegistrationDTO regDtoUnpersisted : unpersisted){
185 if(!workingset.getRegistrationDTOs().stream().anyMatch(dto -> dto.getUuid().equals(regDtoUnpersisted.getUuid()))){
186 // only add if the regDtoUnpersisted has not been persisted meanwhile
187 try {
188 workingset.add(regDtoUnpersisted);
189 } catch (RegistrationValidationException e) {
190 // would never happen here //
191 }
192 }
193 }
194 }
195 applyWorkingset();
196 }
197
198 /**
199 * {@inheritDoc}
200 */
201 @Override
202 public void handleViewEntered() {
203 super.handleViewEntered();
204 // TODO currently cannot specify type more precisely, see AbstractSelect
205 // FIXME externalize into class file!!!!!!!!!!!!
206 getView().setStatusComponentInstantiator(new RegistrationStatusFieldInstantiator<Object>(){
207
208 private static final long serialVersionUID = 7099181280977511048L;
209
210 @Override
211 public AbstractField<Object> create(RegistrationDTO regDto) {
212
213 // submitters have GrantedAuthorities like REGISTRATION(PREPARATION).[UPDATE]{ab4459eb-3b96-40ba-bfaa-36915107d59e}
214 UserHelper userHelper = UserHelperAccess.userHelper().withCache(getCache());
215 Set<RegistrationStatus> availableStatus = new HashSet<>();
216
217 boolean canChangeStatus = userHelper.userHasPermission(regDto.registration(), CRUD.UPDATE);
218 availableStatus.add(regDto.getStatus());
219 if(canChangeStatus){
220 if(userHelper.userIsAdmin()){
221 availableStatus.addAll(Arrays.asList(RegistrationStatus.values()));
222 } else {
223 availableStatus.addAll(RegistrationStatusTransitions.possibleTransitions(regDto.getStatus()));
224 }
225 }
226
227 RegistrationStatusSelect select = new RegistrationStatusSelect(null, selectFieldFactory.buildBeanItemContainer(
228 RegistrationStatus.class,
229 availableStatus.toArray(new RegistrationStatus[availableStatus.size()]))
230 );
231 select.setValue(regDto.getStatus());
232 select.addValueChangeListener(e -> saveRegistrationStatusChange(regDto.getUuid(), e.getProperty().getValue()));
233 select.setEnabled(canChangeStatus);
234 select.setNullSelectionAllowed(false);
235 return select;
236 }
237
238
239 });
240 loadWorkingSet(getView().getCitationUuid());
241 applyWorkingset();
242
243 }
244
245 private void applyWorkingset(){
246 getView().setWorkingset(workingset);
247 // PagingProviders and CacheGenerator for the existingNameCombobox
248 activateComboboxes();
249 }
250
251 protected void activateComboboxes() {
252 CdmTitleCacheCaptionGenerator<TaxonName> titleCacheGenerator = new CdmTitleCacheCaptionGenerator<TaxonName>();
253 getView().getAddExistingNameCombobox().setCaptionGenerator(titleCacheGenerator);
254 CdmFilterablePagingProvider<TaxonName, TaxonName> pagingProvider = pagingProviderFactory.taxonNamesWithoutOrthophicIncorrect();
255 getView().getAddExistingNameCombobox().loadFrom(pagingProvider, pagingProvider, pagingProvider.getPageSize());
256 }
257
258 /**
259 * @param referenceID
260 */
261 protected void loadWorkingSet(UUID referenceUuid) {
262
263 try {
264 workingset = getWorkingSetService().loadWorkingSetByReferenceUuid(referenceUuid, true);
265 } catch (RegistrationValidationException error) {
266 logger.error(error);
267 showErrorDialog("Validation Error", error.getMessage());
268 } catch(PermissionDeniedException e){
269 logger.info(e);
270 ((AccessRestrictedView)getView()).setAccessDeniedMessage(e.getMessage());
271 }
272 cache = new CdmTransientEntityAndUuidCacher(this);
273 for(Registration registration : workingset.getRegistrations()) {
274 addRootEntity(registration);
275 }
276 }
277
278 /**
279 * @param errorDialogCaption
280 * @param errorMessage
281 */
282 public void showErrorDialog(String errorDialogCaption, String errorMessage) {
283 Window errorDialog = new Window(errorDialogCaption);
284 errorDialog.setModal(true);
285 VerticalLayout subContent = new VerticalLayout();
286 subContent.setMargin(true);
287 errorDialog.setContent(subContent);
288 subContent.addComponent(new Label(errorMessage));
289 UI.getCurrent().addWindow(errorDialog);
290 }
291
292 private void saveRegistrationStatusChange(UUID uuid, Object value) {
293 Registration reg = getRepo().getRegistrationService().load(uuid);
294 if(reg == null){
295 // registration was not yet persisted, ignore
296 return;
297 }
298 if(value != null && value instanceof RegistrationStatus){
299 if(!Objects.equals(value, reg.getStatus())){
300 reg.updateStatusAndDate((RegistrationStatus)value);
301 cdmStore.saveBean(reg, (AbstractView)getView());
302 refreshView(true);
303 }
304 } else {
305 // only log here as error
306 logger.error("Ivalid attempt to set RegistrationStatus to " + Objects.toString(value.toString(), "NULL"));
307 }
308 }
309
310
311 @EventBusListenerMethod(filter = EditorActionTypeFilter.Add.class)
312 public void onReferenceEditorActionAdd(ReferenceEditorAction event) {
313
314 if(!checkFromOwnView(event)){
315 return;
316 }
317
318 ReferencePopupEditor popup = openPopupEditor(ReferencePopupEditor.class, event);
319 popup.withReferenceTypes(RegistrationUIDefaults.PRINTPUB_REFERENCE_TYPES);
320 popup.loadInEditor(null);
321 }
322
323 @EventBusListenerMethod(filter = EditorActionTypeFilter.Edit.class)
324 public void onReferenceEditorActionEdit(ReferenceEditorAction event) {
325
326 if(!checkFromOwnView(event)){
327 return;
328 }
329 ReferencePopupEditor popup = openPopupEditor(ReferencePopupEditor.class, event);
330 popup.withReferenceTypes(RegistrationUIDefaults.PRINTPUB_REFERENCE_TYPES);
331 popup.withDeleteButton(true);
332 popup.loadInEditor(event.getEntityUuid());
333 }
334
335 @EventBusListenerMethod
336 public void onDoneWithReferencePopupEditor(DoneWithPopupEvent event) throws RegistrationValidationException{
337 if(event.getPopup() instanceof ReferencePopupEditor){
338 if(event.getReason().equals(Reason.SAVE)){
339 refreshView(true);
340 }
341 }
342 }
343
344 @EventBusListenerMethod(filter = EditorActionTypeFilter.Edit.class)
345 public void onRegistrationEditorAction(RegistrationEditorAction event) {
346
347 if(!checkFromOwnView(event)){
348 return;
349 }
350
351 RegistrationPopupEditor popup = openPopupEditor(RegistrationPopupEditor.class, event);
352 popup.loadInEditor(event.getEntityUuid());
353 }
354
355 @EventBusListenerMethod(filter = EditorActionTypeFilter.Edit.class)
356 public void onTaxonNameEditorActionEdit(TaxonNameEditorAction event) {
357
358 if(!checkFromOwnView(event)){
359 return;
360 }
361
362 TaxonNamePopupEditor popup = openPopupEditor(TaxonNamePopupEditor.class, event);
363 popup.setParentEditorActionContext(event.getContext(), event.getTarget());
364 popup.withDeleteButton(true);
365 TaxonNamePopupEditorConfig.configureForNomenclaturalAct(popup);
366 popup.loadInEditor(event.getEntityUuid());
367 if(event.hasSource() && event.getSource().isReadOnly()){
368 // avoid resetting readonly to false
369 popup.setReadOnly(true);
370 }
371
372 }
373
374
375 @EventBusListenerMethod(filter = EditorActionTypeFilter.Add.class)
376 public void onTaxonNameEditorActionAdd(TaxonNameEditorAction event) {
377
378 if(!checkFromOwnView(event)){
379 return;
380 }
381
382 getView().getAddNewNameRegistrationButton().setEnabled(false);
383 if(newNameForRegistrationPopupEditor == null){
384 TaxonNamePopupEditor popup = openPopupEditor(TaxonNamePopupEditor.class, event);
385 newNameForRegistrationPopupEditor = popup;
386 popup.setParentEditorActionContext(event.getContext(), event.getTarget());
387 popup.grantToCurrentUser(EnumSet.of(CRUD.UPDATE,CRUD.DELETE));
388 popup.withDeleteButton(true);
389 popup.setCdmEntityInstantiator(new BeanInstantiator<TaxonName>() {
390
391 @Override
392 public TaxonName createNewBean() {
393 TaxonName newTaxonName = TaxonNameFactory.NewNameInstance(RegistrationUIDefaults.NOMENCLATURAL_CODE, Rank.SPECIES());
394 newTaxonName.setNomenclaturalReference(getRepo().getReferenceService().load(workingset.getCitationUuid(), TaxonNameEditorPresenter.REFERENCE_INIT_STRATEGY ));
395 return newTaxonName;
396 }
397 });
398 TaxonNamePopupEditorConfig.configureForNomenclaturalAct(popup);
399 popup.loadInEditor(null);
400 }
401 }
402
403 /**
404 * Creates a new <code>Registration</code> for a new name that has just been edited
405 * using a <code>TaxonNamePopupEditor</code>. The popup editor which has been opened to
406 * edit the new name was remembered in <code>newNameForRegistrationPopupEditor</code>.
407 * Any blocking registrations which have been created while editing the new name are
408 * temporarily stored in <code>newNameBlockingRegistrations</code> until the registration
409 * for the first name has been created. Additional new names are created for example
410 * when a new name as basionym, replaced synonym, etc to the new name is created.
411 * <p>
412 * See also {@link #onTaxonNameEditorActionAdd(TaxonNameEditorAction)}).
413 *
414 * @param event
415 * @throws RegistrationValidationException
416 */
417 @EventBusListenerMethod
418 public void onDoneWithTaxonnameEditor(DoneWithPopupEvent event) {
419 if(event.getPopup() instanceof TaxonNamePopupEditor){
420 Registration registration = null;
421 boolean doRefreshView = false;
422 if(newNameForRegistrationPopupEditor != null && event.getPopup().equals(newNameForRegistrationPopupEditor)){
423 if(event.getReason().equals(Reason.SAVE)){
424 try {
425 TaxonName taxonName = newNameForRegistrationPopupEditor.getBean().cdmEntity();
426 registration = registrationWorkflowService.createRegistration(taxonName, newNameBlockingRegistrations);
427 loadWorkingSet(workingset.getCitationUuid());
428 } finally {
429 clearSession();
430 doRefreshView = true;
431 getView().getAddNewNameRegistrationButton().setEnabled(true);
432 }
433 }
434 // nullify and clear the memory on this popup editor in any case (SAVE, CANCEL, DELETE)
435 newNameForRegistrationPopupEditor = null;
436 newNameBlockingRegistrations.clear();
437 getView().getAddNewNameRegistrationButton().setEnabled(true);
438 }
439
440 if(registration == null){
441 // no new registration has been created above, so there must be an existing one.
442 registration = findRegistrationInContext(event.getPopup());
443 }
444
445 // Check if the other names used in the context of the name are registered yet.
446 TaxonNamePopupEditor nameEditor = (TaxonNamePopupEditor)event.getPopup();
447 Set<TaxonName> namesToCheck = new HashSet<>();
448
449 namesToCheck.addAll(nameEditor.getBasionymComboboxSelect().getValue());
450 namesToCheck.addAll(nameEditor.getReplacedSynonymsComboboxSelect().getValue());
451 namesToCheck.add(nameEditor.getValidationField().getRelatedNameComboBox().getValue());
452 namesToCheck.add(nameEditor.getOrthographicVariantField().getRelatedNameComboBox().getValue());
453
454 for(TaxonName name : namesToCheck){
455 if(name != null){
456 clearSession();
457 doRefreshView |= registrationWorkflowService.addBlockingRegistration(name.getUuid(), registration) != null;
458 }
459 }
460
461 refreshView(doRefreshView);
462 }
463 }
464
465
466 /**
467 * Creates a new Registration for an exiting (previously published) name.
468 *
469 * @param event
470 * @throws RegistrationValidationException
471 */
472 @EventBusListenerMethod
473 public void onRegistrationWorkflowEventActionStart(RegistrationWorkingsetAction event) throws RegistrationValidationException {
474
475 if(!event.isStart()){
476 return;
477 }
478
479 getView().getAddExistingNameCombobox().commit(); // update the chosen value in the datasource
480 TaxonName typifiedName = getView().getAddExistingNameCombobox().getValue();
481 if(typifiedName != null){
482 boolean doReloadWorkingSet = false;
483 try {
484 doReloadWorkingSet = registrationWorkflowService.createRegistrationforExistingName(workingset, typifiedName);
485 } finally {
486 clearSession();
487 refreshView(doReloadWorkingSet);
488 getView().getAddExistingNameRegistrationButton().setEnabled(false);
489 }
490 } else {
491 logger.error("Seletced name is NULL");
492 }
493
494 }
495
496 @EventBusListenerMethod(filter = EditorActionTypeFilter.Edit.class)
497 public void onTypeDesignationsEditorActionEdit(TypeDesignationWorkingsetEditorAction event) {
498
499 if(!checkFromOwnView(event)){
500 return;
501 }
502
503 if(event.getWorkingSetType() == TypeDesignationWorkingSetType.SPECIMEN_TYPE_DESIGNATION_WORKINGSET ){
504 SpecimenTypeDesignationWorkingsetPopupEditor popup = openPopupEditor(SpecimenTypeDesignationWorkingsetPopupEditor.class, event);
505 popup.setParentEditorActionContext(event.getContext(), event.getTarget());
506 popup.withDeleteButton(true);
507 popup.loadInEditor(new TypeDesignationWorkingsetEditorIdSet(event.getRegistrationUuid(), event.getBaseEntityRef()));
508 if(event.hasSource()){
509 // propagate readonly state from source button to popup
510 popup.setReadOnly(event.getSource().isReadOnly());
511 }
512 } else {
513 NameTypeDesignationPopupEditor popup = openPopupEditor(NameTypeDesignationPopupEditor.class, event);
514 popup.setParentEditorActionContext(event.getContext(), event.getTarget());
515 popup.withDeleteButton(true);
516 popup.loadInEditor(new TypeDesignationWorkingsetEditorIdSet(event.getRegistrationUuid(), event.getBaseEntityRef()));
517
518 popup.getCitationCombobox().setEnabled(false);
519 popup.getTypifiedNamesComboboxSelect().setEnabled(false);
520
521 if(event.hasSource()){
522 // propagate readonly state from source button to popup
523 popup.setReadOnly(event.getSource().isReadOnly());
524 }
525 nameTypeDesignationPopupEditorRegistrationUUIDMap.put(popup, event.getRegistrationUuid());
526 }
527 }
528
529 @EventBusListenerMethod(filter = EditorActionTypeFilter.Add.class)
530 public void onTypeDesignationWorkingsetAdd(TypeDesignationWorkingsetEditorAction event) {
531
532 if(!event.hasSource()){
533 return;
534 }
535
536 if(event.getWorkingSetType() == TypeDesignationWorkingSetType.SPECIMEN_TYPE_DESIGNATION_WORKINGSET){
537 SpecimenTypeDesignationWorkingsetPopupEditor popup = openPopupEditor(SpecimenTypeDesignationWorkingsetPopupEditor.class, event);
538 popup.setParentEditorActionContext(event.getContext(), event.getTarget());
539 TypeDesignationWorkingsetEditorIdSet identifierSet;
540 UUID typifiedNameUuid;
541
542 RegistrationDTO registrationDTO = workingset.getRegistrationDTO(event.getRegistrationUuid()).get();
543 EntityReference typifiedNameRef = registrationDTO.getTypifiedNameRef();
544 if(typifiedNameRef != null){
545 // case for registrations without name, in which case the typifiedName is only defined via the typedesignations
546 typifiedNameUuid = typifiedNameRef.getUuid();
547 } else {
548 // case of registrations with a name in the nomenclatural act.
549 typifiedNameUuid = registrationDTO.getNameRef().getUuid();
550 }
551
552 identifierSet = new TypeDesignationWorkingsetEditorIdSet(
553 event.getRegistrationUuid(),
554 getView().getCitationUuid(),
555 typifiedNameUuid
556 );
557 popup.grantToCurrentUser(EnumSet.of(CRUD.UPDATE, CRUD.DELETE));
558 popup.loadInEditor(identifierSet);
559 popup.withDeleteButton(true);
560 if(event.hasSource()){
561 // propagate readonly state from source component to popup
562 popup.setReadOnly(event.getSource().isReadOnly());
563 }
564 } else {
565 NameTypeDesignationPopupEditor popup = openPopupEditor(NameTypeDesignationPopupEditor.class, event);
566 popup.setParentEditorActionContext(event.getContext(), event.getTarget());
567 popup.withDeleteButton(true);
568 popup.grantToCurrentUser(EnumSet.of(CRUD.UPDATE, CRUD.DELETE));
569 RegistrationDTO regDto = workingset.getRegistrationDTO(event.getRegistrationUuid()).get();
570 Reference citation = regDto.getCitation();
571 nameTypeDesignationPopupEditorRegistrationUUIDMap.put(popup, event.getRegistrationUuid());
572 popup.setBeanInstantiator(new BeanInstantiator<NameTypeDesignation>() {
573
574 @Override
575 public NameTypeDesignation createNewBean() {
576
577 TaxonName typifiedName = getRepo().getNameService().load(event.getTypifiedNameUuid(), Arrays.asList(new String[]{"typeDesignations", "homotypicalGroup"}));
578 NameTypeDesignation nameTypeDesignation = NameTypeDesignation.NewInstance();
579 nameTypeDesignation.setCitation(citation);
580 nameTypeDesignation.getTypifiedNames().add(typifiedName);
581 return nameTypeDesignation;
582 }
583 });
584 popup.loadInEditor(null);
585 popup.getCitationCombobox().setEnabled(false);
586 popup.getTypifiedNamesComboboxSelect().setEnabled(false);
587 if(event.hasSource()){
588 // propagate readonly state from source component to popup
589 popup.setReadOnly(event.getSource().isReadOnly());
590 }
591 }
592 }
593
594 /**
595 * Performs final actions after a TypeDesignationEditor which has been
596 * opened to add a TypeDesignation to a Registration object which was
597 * created for an previously published name. Prior adding a typedesignation,
598 * the according Registration object is dangling, that has no association to
599 * any entity denoting an nomenclatural act which has a reference to a
600 * publication. This means that the registration object is not in the
601 * working set.
602 *
603 *
604 * @param event
605 * @throws RegistrationValidationException
606 */
607 @EventBusListenerMethod
608 public void onDoneWithTypeDesignationEditor(DoneWithPopupEvent event) {
609 if(event.getPopup() instanceof SpecimenTypeDesignationWorkingsetPopupEditor){
610 if(event.getReason().equals(Reason.SAVE)){
611 // NOTE: adding the SpecimenTypeDesignations to the registration is done in the
612 // SpecimenTypeDesignationWorkingSetServiceImpl.save(SpecimenTypeDesignationWorkingSetDTO dto) method
613 refreshView(true);
614 } else if(event.getReason().equals(Reason.CANCEL)){
615 // noting to do
616 }
617 } else if(event.getPopup() instanceof NameTypeDesignationPopupEditor){
618 if(event.getReason().equals(Reason.SAVE)){
619
620 Registration registration = null;
621 boolean doRefreshView = false;
622
623 UUID typeDesignationUuid = ((NameTypeDesignationPopupEditor)event.getPopup()).getBean().getUuid();
624
625 try {
626 clearSession();
627 Stack<EditorActionContext>context = ((AbstractPopupEditor)event.getPopup()).getEditorActionContext();
628 registration = findRegistrationInContext(context);
629 registrationWorkflowService.addTypeDesignation(typeDesignationUuid, registration);
630 nameTypeDesignationPopupEditorRegistrationUUIDMap.remove(event.getPopup());
631 } finally {
632 clearSession();
633 doRefreshView = true;
634 }
635
636 if(registration == null){
637 // no new registration has been created above, so there must be an existing one.
638 registration = findRegistrationInContext(event.getPopup());
639 }
640
641 // Check if the other names used in the context of the name are registered yet.
642 NameTypeDesignationPopupEditor nameEditor = (NameTypeDesignationPopupEditor)event.getPopup();
643 Set<TaxonName> namesToCheck = new HashSet<>();
644
645 namesToCheck.add(nameEditor.getTypeNameField().getValue());
646
647 for(TaxonName name : namesToCheck){
648 if(name != null){
649 doRefreshView |= registrationWorkflowService.addBlockingRegistration(name.getUuid(), registration) != null;
650 }
651
652 }
653
654 refreshView(doRefreshView);
655
656 } else if(event.getReason().equals(Reason.CANCEL)){
657 // noting to do
658 }
659
660 }
661 // ignore other editors
662 }
663
664 /**
665 *
666 */
667 public void clearSession() {
668 getRepo().clearSession();
669 }
670
671
672 @EventBusListenerMethod(filter = ShowDetailsEventEntityTypeFilter.RegistrationWorkingSet.class)
673 public void onShowDetailsEventForRegistrationWorkingSet(ShowDetailsEvent<RegistrationWorkingSet,?> event) {
674
675 if(event.getProperty().equals(RegistrationItem.VALIDATION_PROBLEMS)){
676 List<String> messages = new ArrayList<>();
677 for(RegistrationDTO dto : workingset.getRegistrationDTOs()){
678 dto.getValidationProblems().forEach(m -> messages.add(dto.getSummary() + ": " + m));
679 }
680 getView().openDetailsPopup("Validation Problems", messages);
681 }
682 }
683
684 @EventBusListenerMethod
685 public void onEntityChangeEvent(EntityChangeEvent event){
686
687 if(workingset == null){
688 return;
689 }
690 if(Reference.class.isAssignableFrom(event.getEntityType())){
691
692 if(workingset.getCitationUuid().equals(event.getEntityUuid())){
693 if(event.isRemovedType()){
694 viewEventBus.publish(EventScope.UI, this, new NavigationEvent(StartRegistrationViewBean.NAME));
695 } else {
696 refreshView(true);
697 }
698 }
699
700 } else
701 if(Registration.class.isAssignableFrom(event.getEntityType())){
702 if(workingset.getRegistrations().stream().anyMatch(reg -> reg.getUuid() == event.getEntityUuid())){
703 refreshView(true);
704 }
705 } else
706 if(TaxonName.class.isAssignableFrom(event.getEntityType())){
707 if(event.getType().equals(EntityChangeEvent.Type.CREATED)){
708 Stack<EditorActionContext>context = ((AbstractPopupEditor)event.getSourceView()).getEditorActionContext();
709 EditorActionContext rootContext = context.get(0);
710 if(rootContext.getParentView().equals(getView()) && event.getSourceView() != newNameForRegistrationPopupEditor){
711 try {
712 clearSession();
713 // create a blocking registration, the new Registration will be persisted
714 UUID taxonNameUUID = event.getEntityUuid();
715
716 if(context.get(1).getParentView() instanceof TaxonNamePopupEditor && !((TaxonNamePopupEditor)context.get(1).getParentView()).getBean().cdmEntity().isPersited()){
717 // Oha!! The event came from a popup editor and the
718 // first popup in the context is a TaxonNameEditor with un-persisted name
719 // This is a name for a new registration which has not yet been created.
720 // It is necessary to store blocking registrations in the newNameBlockingRegistrations
721 Registration blockingRegistration = getRepo().getRegistrationService().createRegistrationForName(taxonNameUUID);
722 newNameBlockingRegistrations.add(blockingRegistration);
723 logger.debug("Blocking registration created and memorized");
724 } else {
725 Registration registration = findRegistrationInContext(context);
726 // some new name somehow related to an existing registration
727 registrationWorkflowService.addBlockingRegistration(taxonNameUUID, registration);
728 }
729 } finally {
730 clearSession();
731 }
732
733 } else {
734 // in case of creating a new name for a registration the parent view is the TaxonNamePopupEditor
735 // this is set
736 logger.debug("Non blocking registration, since a new name for a new registration has been created");
737 }
738 }
739 if(workingset.getRegistrationDTOs().stream().anyMatch(reg ->
740 reg.getTypifiedNameRef() != null
741 && reg.getTypifiedNameRef().getUuid().equals(event.getEntityUuid()))){
742 refreshView(true);
743 }
744 } else
745 if(TypeDesignationBase.class.isAssignableFrom(event.getEntityType())){
746 if(workingset.getRegistrationDTOs().stream().anyMatch(
747 reg -> reg.typeDesignations() != null && reg.typeDesignations().stream().anyMatch(
748 td -> td.getUuid() == event.getEntityUuid()
749 )
750 )
751 ){
752 refreshView(true);
753 }
754 }
755 }
756
757 public Registration findRegistrationInContext(PopupView popupView) {
758 Stack<EditorActionContext>context = ((AbstractPopupEditor)popupView).getEditorActionContext();
759 return findRegistrationInContext(context);
760 }
761 /**
762 * Finds the Registration in the EditorContext stack
763 *
764 * @param context
765 * @return
766 */
767 public Registration findRegistrationInContext(Stack<EditorActionContext> context) {
768 EditorActionContext rootCtx = context.get(0);
769 TypedEntityReference<Registration> regReference = (TypedEntityReference<Registration>)rootCtx.getParentEntity();
770 Optional<RegistrationDTO> registrationDTOOptional = workingset.getRegistrationDTO(regReference.getUuid());
771 if(!registrationDTOOptional.isPresent()){
772 logger.error("RegistrationDTO missing in rootCtx.");
773 }
774 Registration registration = registrationDTOOptional.get().registration();
775
776 // registration = reloadRegistration(registration);
777 return registration;
778 }
779
780
781
782 @EventBusListenerMethod(filter = ShowDetailsEventEntityTypeFilter.RegistrationDTO.class)
783 public void onShowDetailsEventForRegistrationDTO(ShowDetailsEvent<RegistrationDTO, UUID> event) {
784
785 // FIXME check from own view!!!
786 if(getView() == null){
787 return;
788 }
789
790 UUID registrationUuid = event.getIdentifier();
791
792 RegistrationDTO regDto = workingset.getRegistrationDTO(registrationUuid).get();
793 if(event.getProperty().equals(RegistrationItem.BLOCKED_BY)){
794
795 Set<RegistrationDTO> blockingRegs;
796 if(regDto.registration().isPersited()){
797 blockingRegs = getWorkingSetService().loadBlockingRegistrations(registrationUuid);
798 } else {
799 blockingRegs = new HashSet<RegistrationDTO>(getWorkingSetService().makeDTOs(regDto.registration().getBlockedBy()));
800 }
801 getView().setBlockingRegistrations(registrationUuid, blockingRegs);
802 } else if(event.getProperty().equals(RegistrationItem.VALIDATION_PROBLEMS)){
803 getView().openDetailsPopup("Validation Problems", regDto.getValidationProblems());
804 }
805 }
806
807 /**
808 * {@inheritDoc}
809 */
810 @Override
811 public ICdmEntityUuidCacher getCache() {
812 return cache;
813 }
814
815 /**
816 * {@inheritDoc}
817 */
818 @Override
819 public void addRootEntity(CdmBase entity) {
820 rootEntities.add(entity);
821 cache.load(entity);
822 }
823
824
825 /**
826 * {@inheritDoc}
827 */
828 @Override
829 public Collection<CdmBase> getRootEntities() {
830 return rootEntities;
831 }
832
833 @Override
834 public void destroy() throws Exception {
835 super.destroy();
836 disposeCache();
837 }
838
839 /**
840 * {@inheritDoc}
841 */
842 @Override
843 public void disposeCache() {
844 cache.dispose();
845 }
846
847 /**
848 * @param name
849 * @return
850 */
851 public boolean canCreateNameRegistrationFor(TaxonName name) {
852 return registrationWorkflowService.canCreateNameRegistrationFor(workingset, name);
853 }
854
855 /**
856 * @param name
857 * @return
858 */
859 public boolean checkWokingsetContainsProtologe(TaxonName name) {
860 return registrationWorkflowService.checkWokingsetContainsProtologe(workingset, name);
861 }
862
863 }