ref #6867 ref #7026 extending UserHelper to allow creation of authorities with propet...
[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.EnumSet;
13 import java.util.List;
14
15 import org.springframework.beans.factory.annotation.Autowired;
16 import org.springframework.context.event.EventListener;
17 import org.springframework.security.core.Authentication;
18
19 import com.vaadin.spring.annotation.SpringComponent;
20 import com.vaadin.spring.annotation.ViewScope;
21 import com.vaadin.ui.Label;
22 import com.vaadin.ui.UI;
23 import com.vaadin.ui.VerticalLayout;
24 import com.vaadin.ui.Window;
25
26 import eu.etaxonomy.cdm.api.service.INameService;
27 import eu.etaxonomy.cdm.api.service.IRegistrationService;
28 import eu.etaxonomy.cdm.model.common.User;
29 import eu.etaxonomy.cdm.model.name.Rank;
30 import eu.etaxonomy.cdm.model.name.Registration;
31 import eu.etaxonomy.cdm.model.name.TaxonName;
32 import eu.etaxonomy.cdm.model.name.TaxonNameFactory;
33 import eu.etaxonomy.cdm.model.name.TypeDesignationBase;
34 import eu.etaxonomy.cdm.model.reference.Reference;
35 import eu.etaxonomy.cdm.persistence.hibernate.permission.CRUD;
36 import eu.etaxonomy.cdm.service.CdmFilterablePagingProvider;
37 import eu.etaxonomy.cdm.service.CdmStore;
38 import eu.etaxonomy.cdm.service.IRegistrationWorkingSetService;
39 import eu.etaxonomy.cdm.vaadin.event.EntityChangeEvent;
40 import eu.etaxonomy.cdm.vaadin.event.ReferenceEditorAction;
41 import eu.etaxonomy.cdm.vaadin.event.RegistrationEditorAction;
42 import eu.etaxonomy.cdm.vaadin.event.ShowDetailsEvent;
43 import eu.etaxonomy.cdm.vaadin.event.TaxonNameEditorAction;
44 import eu.etaxonomy.cdm.vaadin.event.TypeDesignationWorkingsetEditorAction;
45 import eu.etaxonomy.cdm.vaadin.event.registration.RegistrationWorkflowEvent;
46 import eu.etaxonomy.cdm.vaadin.model.EntityReference;
47 import eu.etaxonomy.cdm.vaadin.model.registration.RegistrationWorkingSet;
48 import eu.etaxonomy.cdm.vaadin.security.UserHelper;
49 import eu.etaxonomy.cdm.vaadin.util.CdmTitleCacheCaptionGenerator;
50 import eu.etaxonomy.cdm.vaadin.util.converter.TypeDesignationSetManager.TypeDesignationWorkingSetType;
51 import eu.etaxonomy.cdm.vaadin.view.name.SpecimenTypeDesignationWorkingsetPopupEditor;
52 import eu.etaxonomy.cdm.vaadin.view.name.TaxonNamePopupEditor;
53 import eu.etaxonomy.cdm.vaadin.view.name.TypeDesignationWorkingsetEditorIdSet;
54 import eu.etaxonomy.cdm.vaadin.view.reference.ReferencePopupEditor;
55 import eu.etaxonomy.vaadin.mvp.AbstractPresenter;
56 import eu.etaxonomy.vaadin.ui.view.DoneWithPopupEvent;
57 import eu.etaxonomy.vaadin.ui.view.DoneWithPopupEvent.Reason;
58
59 /**
60 * @author a.kohlbecker
61 * @since Mar 3, 2017
62 *
63 */
64 @SpringComponent
65 @ViewScope
66 public class RegistrationWorkingsetPresenter extends AbstractPresenter<RegistrationWorkingsetView> {
67
68 private static final long serialVersionUID = 1L;
69
70 @Autowired
71 private IRegistrationWorkingSetService workingSetService;
72
73 /**
74 * @return the workingSetService
75 */
76 public IRegistrationWorkingSetService getWorkingSetService() {
77 ensureBoundConversation();
78 return workingSetService;
79 }
80
81 private RegistrationWorkingSet workingset;
82
83 private TaxonName newTaxonNameForRegistration = null;
84
85 private RegistrationDTO newRegistrationDTOWithExistingName;
86
87
88 /**
89 *
90 */
91 public RegistrationWorkingsetPresenter() {
92 }
93
94
95 /**
96 * Always create a new Store
97 *
98 * @return
99 */
100 protected CdmStore<Registration, IRegistrationService> getRegistrationStore(){
101 return new CdmStore<Registration, IRegistrationService>(getRepo(), getRepo().getRegistrationService());
102 }
103
104 /**
105 * Always create a new Store
106 *
107 * @return
108 */
109 protected CdmStore<TaxonName, INameService> getTaxonNameStore(){
110 return new CdmStore<TaxonName, INameService>(getRepo(), getRepo().getNameService());
111 }
112
113
114 /**
115 * @param taxonNameId
116 * @return
117 */
118 protected Registration createNewRegistrationForName(Integer taxonNameId) {
119 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
120 // move into RegistrationWorkflowStateMachine
121 long identifier = System.currentTimeMillis();
122 Registration reg = Registration.NewInstance(
123 "http://phycobank.org/" + identifier,
124 "" + identifier,
125 taxonNameId != null ? getRepo().getNameService().find(taxonNameId) : null,
126 null);
127 Authentication authentication = currentSecurityContext().getAuthentication();
128 reg.setSubmitter((User)authentication.getPrincipal());
129 EntityChangeEvent event = getRegistrationStore().saveBean(reg);
130 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
131 return getRepo().getRegistrationService().find(event.getEntityId());
132 }
133
134
135 /**
136 *
137 */
138 protected void refreshView() {
139 getConversationHolder().getSession().clear();
140 presentWorkingSet(workingset.getCitationId());
141 }
142
143
144 /**
145 * {@inheritDoc}
146 */
147 @Override
148 public void handleViewEntered() {
149
150 super.handleViewEntered();
151
152 presentWorkingSet(getView().getCitationID());
153
154 CdmFilterablePagingProvider<TaxonName> pagingProvider = new CdmFilterablePagingProvider<TaxonName>(
155 getRepo().getNameService(), this);
156 CdmTitleCacheCaptionGenerator<TaxonName> titleCacheGenrator = new CdmTitleCacheCaptionGenerator<TaxonName>();
157 getView().getAddExistingNameCombobox().setCaptionGenerator(titleCacheGenrator);
158 getView().getAddExistingNameCombobox().loadFrom(pagingProvider, pagingProvider, pagingProvider.getPageSize());
159 }
160
161 /**
162 * Loads the WorkingSet from the data base and passes it to the view.
163 *
164 * @param registrationID
165 */
166 private void presentWorkingSet(Integer referenceID) {
167 try {
168 workingset = getWorkingSetService().loadWorkingSetByReferenceID(referenceID);
169 } catch (RegistrationValidationException error) {
170 logger.error(error);
171 Window errorDialog = new Window("Validation Error");
172 errorDialog.setModal(true);
173 VerticalLayout subContent = new VerticalLayout();
174 subContent.setMargin(true);
175 errorDialog.setContent(subContent);
176 subContent.addComponent(new Label(error.getMessage()));
177 UI.getCurrent().addWindow(errorDialog);
178 }
179 if(workingset == null || workingset.getCitationId() == null){
180 Reference citation = getRepo().getReferenceService().find(referenceID);
181 workingset = new RegistrationWorkingSet(citation);
182 }
183 // getView().setHeaderText("Registrations for " + workingset.getCitation());
184 getView().setWorkingset(workingset);
185 }
186
187 @EventListener(condition = "#event.type == T(eu.etaxonomy.cdm.vaadin.event.AbstractEditorAction.Action).ADD && #event.sourceComponent == null")
188 public void onReferenceEditorActionAdd(ReferenceEditorAction event) {
189 ReferencePopupEditor popup = getNavigationManager().showInPopup(ReferencePopupEditor.class);
190 popup.loadInEditor(null);
191 }
192
193 @EventListener(condition = "#event.type == T(eu.etaxonomy.cdm.vaadin.event.AbstractEditorAction.Action).EDIT && #event.sourceComponent == null")
194 public void onReferenceEditorActionEdit(ReferenceEditorAction event) {
195 ReferencePopupEditor popup = getNavigationManager().showInPopup(ReferencePopupEditor.class);
196 popup.withDeleteButton(true);
197 popup.loadInEditor(event.getEntityId());
198 }
199
200 @EventListener(condition = "#event.type == T(eu.etaxonomy.cdm.vaadin.event.AbstractEditorAction.Action).EDIT && #event.sourceComponent == null")
201 public void onRegistrationEditorAction(RegistrationEditorAction event) {
202 RegistrationPopupEditor popup = getNavigationManager().showInPopup(RegistrationPopupEditor.class);
203 popup.loadInEditor(event.getEntityId());
204 }
205
206 @EventListener(condition = "#event.type == T(eu.etaxonomy.cdm.vaadin.event.AbstractEditorAction.Action).EDIT && #event.sourceComponent == null")
207 public void onTaxonNameEditorActionEdit(TaxonNameEditorAction event) {
208
209 TaxonNamePopupEditor popup = getNavigationManager().showInPopup(TaxonNamePopupEditor.class);
210 popup.withDeleteButton(true);
211 // disable NomReferenceCombobox:
212 // the in the registration application inReferences should only edited centrally
213 popup.getNomReferenceCombobox().setEnabled(false);
214 popup.loadInEditor(event.getEntityId());
215 }
216
217 @EventListener(condition = "#event.type == T(eu.etaxonomy.cdm.vaadin.event.AbstractEditorAction.Action).ADD")
218 public void onTaxonNameEditorActionAdd(TaxonNameEditorAction event) {
219
220 newTaxonNameForRegistration = TaxonNameFactory.NewBotanicalInstance(Rank.SPECIES());
221 newTaxonNameForRegistration.setNomenclaturalReference(getRepo().getReferenceService().find(workingset.getCitationId()));
222 EntityChangeEvent nameSaveEvent = getTaxonNameStore().saveBean(newTaxonNameForRegistration);
223 UserHelper.fromSession().createAuthorityForCurrentUser(TaxonName.class, nameSaveEvent.getEntityId(), EnumSet.of(CRUD.UPDATE,CRUD.DELETE), null);
224 newTaxonNameForRegistration = getRepo().getNameService().find(nameSaveEvent.getEntityId());
225 TaxonNamePopupEditor popup = getNavigationManager().showInPopup(TaxonNamePopupEditor.class);
226 popup.withDeleteButton(true);
227 popup.loadInEditor(newTaxonNameForRegistration.getId());
228 // disable NomReferenceCombobox:
229 // the in the registration application inReferences should only edited centrally
230 popup.getNomReferenceCombobox().setEnabled(false);
231 }
232
233 /**
234 * Creates a new <code>Registration</code> for a new name that has just been edited
235 * using the <code>TaxonNamePopupEditor</code>. The new name was previously created
236 * in this presenter as <code>newTaxonNameForRegistration</code> (see {@link #onTaxonNameEditorActionAdd(TaxonNameEditorAction)})
237 * and is either filled with data (<code>Reason.SAVE</code>) or it is still empty
238 * (<code>Reason.CANCEL</code>).
239 *
240 *
241 * @param event
242 * @throws RegistrationValidationException
243 */
244 @EventListener
245 public void onDoneWithTaxonnameEditor(DoneWithPopupEvent event) throws RegistrationValidationException{
246 if(event.getPopup() instanceof TaxonNamePopupEditor){
247 if(event.getReason().equals(Reason.SAVE)){
248 if(newTaxonNameForRegistration != null){
249 int taxonNameId = newTaxonNameForRegistration.getId();
250 Registration reg = createNewRegistrationForName(taxonNameId);
251 workingset.add(reg);
252 }
253 refreshView();
254 } else if(event.getReason().equals(Reason.CANCEL)){
255 // clean up
256 getTaxonNameStore().deleteBean(newTaxonNameForRegistration);
257 }
258 newTaxonNameForRegistration = null;
259 }
260 }
261
262
263 /**
264 * Creates a new Registration for an exiting (previously published name).
265 *
266 * @param event
267 * @throws RegistrationValidationException
268 */
269 @EventListener(condition = "#event.action == T(eu.etaxonomy.cdm.vaadin.event.registration.RegistrationWorkflowEvent.Action).start")
270 public void onRegistrationWorkflowEventActionStart(RegistrationWorkflowEvent event) throws RegistrationValidationException {
271
272 getView().getAddExistingNameCombobox().commit();
273 TaxonName typifiedName = getView().getAddExistingNameCombobox().getValue();
274 if(typifiedName != null){
275 Registration newRegistrationWithExistingName = createNewRegistrationForName(null);
276 Reference citation = getRepo().getReferenceService().find(workingset.getCitationId());
277 newRegistrationDTOWithExistingName = new RegistrationDTO(newRegistrationWithExistingName, typifiedName, citation);
278 workingset.add(newRegistrationDTOWithExistingName);
279 // tell the view to update the workingset
280 getView().setWorkingset(workingset);
281 getView().getAddExistingNameRegistrationButton().setEnabled(false);
282 getView().getAddExistingNameRegistrationButton().setDescription("You first need to add a type designation to the previously created registration.");
283 } else {
284 logger.error("Seletced name is NULL");
285 }
286
287 }
288
289 @EventListener(condition = "#event.type == T(eu.etaxonomy.cdm.vaadin.event.AbstractEditorAction.Action).EDIT && #event.sourceComponent == null")
290 public void onTypeDesignationsEditorActionEdit(TypeDesignationWorkingsetEditorAction event) {
291
292 if(event.getWorkingSetType() == TypeDesignationWorkingSetType.SPECIMEN_TYPE_DESIGNATION_WORKINGSET ){
293 SpecimenTypeDesignationWorkingsetPopupEditor popup = getNavigationManager().showInPopup(SpecimenTypeDesignationWorkingsetPopupEditor.class);
294 popup.loadInEditor(new TypeDesignationWorkingsetEditorIdSet(event.getRegistrationId(), event.getEntityId()));
295 } else {
296 // TypeDesignationWorkingSetType.NAME_TYPE_DESIGNATION_WORKINGSET
297 // FIXME implement NameTypeDesignationWorkingsetPopupEditor
298 }
299 }
300
301 @EventListener(condition = "#event.type == T(eu.etaxonomy.cdm.vaadin.event.AbstractEditorAction.Action).ADD && #event.sourceComponent == null")
302 public void onAddNewTypeDesignationWorkingset(TypeDesignationWorkingsetEditorAction event) {
303
304 if(event.getWorkingSetType() == TypeDesignationWorkingSetType.SPECIMEN_TYPE_DESIGNATION_WORKINGSET){
305 SpecimenTypeDesignationWorkingsetPopupEditor popup = getNavigationManager().showInPopup(SpecimenTypeDesignationWorkingsetPopupEditor.class);
306 TypeDesignationWorkingsetEditorIdSet identifierSet;
307 Integer typifiedNameId;
308 if(newRegistrationDTOWithExistingName != null){
309 typifiedNameId = newRegistrationDTOWithExistingName.getTypifiedName().getId();
310 } else {
311 RegistrationDTO registrationDTO = workingset.getRegistrationDTO(event.getRegistrationId()).get();
312 EntityReference typifiedNameRef = registrationDTO.getTypifiedName();
313 if(typifiedNameRef != null){
314 // case for registrations without name, in which case the typifiedName is only defined via the typedesignations
315 typifiedNameId = typifiedNameRef.getId();
316 } else {
317 // case of registrations with a name in the nomenclatural act.
318 typifiedNameId = registrationDTO.getName().getId();
319 }
320 }
321 identifierSet = new TypeDesignationWorkingsetEditorIdSet(
322 event.getRegistrationId(),
323 getView().getCitationID(),
324 typifiedNameId
325 );
326 popup.loadInEditor(identifierSet
327 );
328 popup.withDeleteButton(true);
329 } else {
330 // TypeDesignationWorkingSetType.NAME_TYPE_DESIGNATION_WORKINGSET
331 // FIXME implement NameTypeDesignationWorkingsetPopupEditor
332 }
333 }
334
335 /**
336 * Performs final actions after a TypeDesignationEditor which has been
337 * opened to add a TypeDesignation to a Registration object which was
338 * created for an previously published name. Prior adding a typedesignation,
339 * the according Registration object is dangling, that has no association to
340 * any entity denoting an nomenclatural act which has a reference to a
341 * publication. This means that the registration object is not in the
342 * working set.
343 *
344 *
345 * @param event
346 * @throws RegistrationValidationException
347 */
348 @EventListener
349 public void onDoneWithTypeDesignationEditor(DoneWithPopupEvent event) throws RegistrationValidationException{
350 if(event.getPopup() instanceof SpecimenTypeDesignationWorkingsetPopupEditor){
351 if(event.getReason().equals(Reason.SAVE)){
352 refreshView();
353 } else if(event.getReason().equals(Reason.CANCEL)){
354 // clean up
355 if(newRegistrationDTOWithExistingName != null){
356 getRegistrationStore().deleteBean(newRegistrationDTOWithExistingName.registration());
357 }
358 }
359 // set newRegistrationDTOWithExistingName NULL in any case
360 newRegistrationDTOWithExistingName = null;
361 }
362 }
363
364
365 @EventListener(classes=ShowDetailsEvent.class, condition = "#event.type == T(eu.etaxonomy.cdm.vaadin.model.registration.RegistrationWorkingSet)")
366 public void onShowRegistrationWorkingSetMessages(ShowDetailsEvent<?,?> event) { // WARNING don't use more specific generic type arguments
367 List<String> messages = new ArrayList<>();
368 for(RegistrationDTO dto : workingset.getRegistrationDTOs()){
369 dto.getMessages().forEach(m -> messages.add(dto.getSummary() + ": " + m));
370 }
371 if(event.getProperty().equals("messages")){
372 getView().openDetailsPopup("Messages", messages);
373 }
374 }
375
376 @EventListener(classes=ShowDetailsEvent.class, condition = "#event.type == T(eu.etaxonomy.cdm.vaadin.view.registration.RegistrationDTO)")
377 public void onShowRegistrationMessages(ShowDetailsEvent<?,?> event) { // WARNING don't use more specific generic type arguments
378 RegistrationDTO regDto = workingSetService.loadDtoById((Integer)event.getIdentifier());
379 if(event.getProperty().equals("messages")){
380 if(getView() != null){
381 getView().openDetailsPopup("Messages", regDto.getMessages());
382 }
383 }
384 }
385
386 @EventListener
387 public void onEntityChangeEvent(EntityChangeEvent event){
388 if(workingset == null){
389 return;
390 }
391 if(Reference.class.isAssignableFrom(event.getEntityType())){
392 if(workingset.getCitationId().equals(event.getEntityId())){
393 refreshView();
394 }
395 } else
396 if(Registration.class.isAssignableFrom(event.getEntityType())){
397 if(workingset.getRegistrations().stream().anyMatch(reg -> reg.getId() == event.getEntityId())){
398 refreshView();
399 }
400 } else
401 if(TaxonName.class.isAssignableFrom(event.getEntityType())){
402 if(workingset.getRegistrationDTOs().stream().anyMatch(reg ->
403 reg.getTypifiedName() != null
404 && reg.getTypifiedName().getId() == event.getEntityId())){
405 refreshView();
406 }
407 } else
408 if(TypeDesignationBase.class.isAssignableFrom(event.getEntityType())){
409 if(workingset.getRegistrationDTOs().stream().anyMatch(
410 reg -> reg.getTypeDesignations().stream().anyMatch(
411 td -> td.getId() == event.getEntityId()
412 )
413 )
414 ){
415 refreshView();
416 }
417 }
418
419 }
420
421 }