ref #10334 adapt vaadin to DescriptionBase.publish
[cdm-vaadin.git] / src / main / java / eu / etaxonomy / cdm / vaadin / view / distributionStatus / DistributionTablePresenter.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.distributionStatus;
10
11 import java.sql.SQLException;
12 import java.util.ArrayList;
13 import java.util.Arrays;
14 import java.util.Collections;
15 import java.util.Comparator;
16 import java.util.HashMap;
17 import java.util.HashSet;
18 import java.util.List;
19 import java.util.Set;
20 import java.util.UUID;
21 import java.util.stream.Collectors;
22
23 import org.springframework.beans.factory.annotation.Autowired;
24 import org.springframework.beans.factory.annotation.Qualifier;
25 import org.springframework.transaction.TransactionStatus;
26 import org.vaadin.addons.lazyquerycontainer.LazyQueryContainer;
27 import org.vaadin.addons.lazyquerycontainer.QueryDefinition;
28 import org.vaadin.addons.lazyquerycontainer.QueryFactory;
29 import org.vaadin.spring.events.EventBus.ViewEventBus;
30
31 import com.vaadin.server.VaadinSession;
32 import com.vaadin.spring.annotation.SpringComponent;
33 import com.vaadin.spring.annotation.ViewScope;
34 import com.vaadin.ui.Notification;
35
36 import eu.etaxonomy.cdm.api.application.CdmRepository;
37 import eu.etaxonomy.cdm.api.util.UserHelper;
38 import eu.etaxonomy.cdm.i18n.Messages;
39 import eu.etaxonomy.cdm.model.common.CdmBase;
40 import eu.etaxonomy.cdm.model.common.Language;
41 import eu.etaxonomy.cdm.model.description.DescriptionBase;
42 import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
43 import eu.etaxonomy.cdm.model.description.Distribution;
44 import eu.etaxonomy.cdm.model.description.Feature;
45 import eu.etaxonomy.cdm.model.description.PresenceAbsenceTerm;
46 import eu.etaxonomy.cdm.model.description.TaxonDescription;
47 import eu.etaxonomy.cdm.model.location.NamedArea;
48 import eu.etaxonomy.cdm.model.taxon.Classification;
49 import eu.etaxonomy.cdm.model.taxon.Taxon;
50 import eu.etaxonomy.cdm.model.taxon.TaxonNode;
51 import eu.etaxonomy.cdm.model.term.DefinedTermBase;
52 import eu.etaxonomy.cdm.model.term.OrderedTermVocabulary;
53 import eu.etaxonomy.cdm.model.term.Representation;
54 import eu.etaxonomy.cdm.model.term.TermVocabulary;
55 import eu.etaxonomy.cdm.vaadin.container.CdmSQLContainer;
56 import eu.etaxonomy.cdm.vaadin.container.PresenceAbsenceTermContainer;
57 import eu.etaxonomy.cdm.vaadin.util.CdmQueryFactory;
58 import eu.etaxonomy.cdm.vaadin.util.CdmSpringContextHelper;
59 import eu.etaxonomy.cdm.vaadin.util.DistributionEditorUtil;
60 import eu.etaxonomy.cdm.vaadin.util.DistributionStatusQueryDefinition;
61 import eu.etaxonomy.cdm.vaadin.util.DistributionStatusQueryFactory;
62 import eu.etaxonomy.vaadin.mvp.AbstractPresenter;
63
64 /**
65 * The presenter of the distribution status editor.
66 */
67 @SpringComponent
68 @ViewScope
69 public class DistributionTablePresenter
70 extends AbstractPresenter<DistributionTablePresenter,IDistributionTableView> {
71
72 private static final long serialVersionUID = 3313043335587777217L;
73
74 @Autowired
75 private UserHelper userHelper;
76
77 @Autowired
78 @Qualifier("cdmRepository")
79 private CdmRepository repo; // TODO remove, since this is already in the super class
80
81 @Override
82 protected void eventViewBusSubscription(ViewEventBus viewEventBus) {
83 // no point subscribing
84 }
85
86 /**
87 * Changes the distribution status of the given {@link Taxon} for the given {@link NamedArea} to the sepcified {@link PresenceAbsenceTerm}.
88 * @param area The area to update the distribution status for.
89 * @param distributionStatus The distribution status to update the taxon with.
90 * @param taxon The taxon to be updated.
91 * @return
92 * {@code 0} if the update was successful.
93 * {@code 1} if the distributionStatus was null and the {@link DescriptionElementBase} was deleted successfully.
94 * {@code -1} if an error occurred.
95 */
96 public int updateDistributionField(NamedArea area, PresenceAbsenceTerm distributionStatus, Taxon taxon) {
97 TransactionStatus tx = repo.startTransaction();
98 taxon = (Taxon)repo.getTaxonService().find(taxon.getUuid());
99 if(area==null){
100 Notification.show(Messages.getLocalizedString(Messages.DistributionTablePresenter_ERROR_UPDATE_DISTRIBUTION_TERM));
101 repo.commitTransaction(tx);
102 return -1;
103 }
104 List<Distribution> distributions = getDistributions(taxon);
105 Distribution distribution = null;
106 for(Distribution dist : distributions){
107 if(dist.getArea()!=null && dist.getArea().equals(area)){
108 distribution = dist;
109 break;
110 }
111 }
112 if(distribution==null){
113 //create new distribution
114 distribution = Distribution.NewInstance(area, distributionStatus);
115 Set<TaxonDescription> descriptions = taxon.getDescriptions();
116 if (descriptions != null && !descriptions.isEmpty()) {
117 for (TaxonDescription desc : descriptions) {
118 // add to first taxon description
119 desc.addElement(distribution);
120 repo.commitTransaction(tx);
121 return 0;
122 }
123 } else {// there are no TaxonDescription yet.
124 TaxonDescription taxonDescription = TaxonDescription.NewInstance(taxon);
125 taxonDescription.addElement(distribution);
126 repo.commitTransaction(tx);
127 return 0;
128 }
129 }
130 else if(distributionStatus == null){//delete descriptionElementBase
131 DescriptionBase<?> desc = distribution.getInDescription();
132 desc.removeElement(distribution);
133 repo.commitTransaction(tx);
134 return 1;
135 }
136 else{//update distribution
137 distribution.setStatus(distributionStatus);
138 repo.getCommonService().saveOrUpdate(distribution);
139 repo.commitTransaction(tx);
140 return 0;
141 }
142 repo.commitTransaction(tx);
143 return -1;
144 }
145
146 /**
147 * Returns a {@link CdmSQLContainer} containing the distribution status information
148 * for the chosen {@link TaxonNode}s and {@link NamedArea}s.
149 * @return {@link CdmSQLContainer} containing the distribution status information
150 * for the chosen {@link TaxonNode}s and {@link NamedArea}s.
151 * @throws SQLException
152 */
153 public CdmSQLContainer getSQLContainer() throws SQLException{
154 List<Integer> nodeIds = new ArrayList<>();
155 for (TaxonNode taxonNode : getAllNodes()) {
156 nodeIds.add(taxonNode.getId());
157 }
158 List<NamedArea> namedAreas = getChosenAreas();
159 if(namedAreas!=null){
160 return new CdmSQLContainer(CdmQueryFactory.generateTaxonDistributionQuery(nodeIds, namedAreas));
161 }
162 return null;
163 }
164
165 /**
166 * Returns a {@link PresenceAbsenceTermContainer} containing all allowed and chosen {@link PresenceAbsenceTerm}s.
167 * @return {@link PresenceAbsenceTermContainer} containing all allowed and chosen {@link PresenceAbsenceTerm}s.
168 */
169 public PresenceAbsenceTermContainer getPresenceAbsenceTermContainer() {
170 return PresenceAbsenceTermContainer.getInstance();
171 }
172
173 /**
174 * Returns a list of {@link DescriptionElementBase}s for the specified {@link Taxon} and {@link Feature} set.
175 * @param taxon The {@link Taxon} to get the descriptions for.
176 * @param setFeature The features to get the descriptions for.
177 * @return List of {@link DescriptionElementBase}s for the specified {@link Taxon} and {@link Feature} set.
178 */
179 public List<DescriptionElementBase> listDescriptionElementsForTaxon(Taxon taxon, Set<Feature> setFeature){
180
181 boolean includeUnpublished = true;
182 List<DescriptionElementBase> listDescriptionElementsForTaxon = CdmSpringContextHelper.getDescriptionService().listDescriptionElementsForTaxon(
183 taxon, setFeature, null, includeUnpublished, null, null, DESCRIPTION_INIT_STRATEGY);
184 sort(listDescriptionElementsForTaxon);
185 return listDescriptionElementsForTaxon;
186 }
187
188 /**
189 * Returns the list of {@link NamedArea}s for which the distribution status can't be updated.
190 * @return List of {@link NamedArea}s for which the distribution status can't be updated.
191 */
192 public List<NamedArea> getReadOnlyAreas(){
193 List<NamedArea> readonly = new ArrayList<>();
194 // TODO: HACK FOR RL 2017: Remove as soon as possible by receiving read only areas from cdm preferences
195 readonly.add(this.getAreaFromString("Deutschland"));
196 return readonly;
197 }
198
199 /**
200 * Returns the {@link NamedArea} referred to by the given {@code areaString}.
201 * @param areaString An string referring to a {@link NamedArea}.
202 * @return The {@link NamedArea} referred to by the given {@code areaString}.
203 */
204 public NamedArea getAreaFromString(String areaString){
205 List<NamedArea> namedAreas = getChosenAreas();
206 NamedArea area = null;
207 for(NamedArea namedArea:namedAreas){
208 Representation representation = namedArea.getRepresentation(Language.DEFAULT());
209 if(representation!=null){
210 if(DistributionEditorUtil.isAbbreviatedLabels()){
211 String label = representation.getLabel();
212 String abbreviatedLabel = representation.getAbbreviatedLabel();
213 if(abbreviatedLabel!=null && abbreviatedLabel.equalsIgnoreCase(areaString)){
214 area = namedArea;
215 break;
216 }
217 else if(label!=null && label.equalsIgnoreCase(areaString)){
218 area = namedArea;
219 break;
220 }
221 }
222 }
223 if(namedArea.getTitleCache().equalsIgnoreCase(areaString)){
224 area = namedArea;
225 break;
226 }
227 }
228 return area;
229 }
230
231 /**
232 * Returns the {@link Distribution} of the given {@link Taxon}.
233 * @param taxon Taxon to get the {@link Distribution} of.
234 * @return {@link Distribution} of the given {@link Taxon}.
235 */
236 private List<Distribution> getDistributions(Taxon taxon) {
237
238 boolean includeUnpublished = true;
239 Set<Feature> setFeature = new HashSet<>(Arrays.asList(Feature.DISTRIBUTION()));
240 List<Distribution> listTaxonDescription = CdmSpringContextHelper.getDescriptionService()
241 .listDescriptionElementsForTaxon(taxon, setFeature, null, includeUnpublished,
242 null, null, DESCRIPTION_INIT_STRATEGY);
243 return listTaxonDescription;
244 }
245
246 /**
247 * Returns the list of chosen {@link NamedArea}s defined in the
248 * related vaadin session attribute {@link DistributionEditorUtil#SATTR_SELECTED_AREAS}.
249 * If this vaadin session attribute is not set, all allowed {@link NamedArea}s of the
250 * chosen {@link TermVocabulary} defined by the vaadin session attribute
251 * {@link DistributionEditorUtil#SATTR_SELECTED_AREA_VOCABULARY_UUID} are returned.
252 * @return List of chosen {@link NamedArea}s defined in the
253 * related vaadin session attribute {@link DistributionEditorUtil#SATTR_SELECTED_AREAS}.
254 * If this vaadin session attribute is not set, all allowed {@link NamedArea}s of the
255 * chosen {@link TermVocabulary} defined by the vaadin session attribute
256 * {@link DistributionEditorUtil#SATTR_SELECTED_AREA_VOCABULARY_UUID}.
257 */
258 private List<NamedArea> getChosenAreas(){
259 List<NamedArea> namedAreas = (List<NamedArea>)VaadinSession.getCurrent().getAttribute(DistributionEditorUtil.SATTR_SELECTED_AREAS);
260 if(namedAreas!=null && namedAreas.isEmpty()){
261 return getChosenAreasFromVoc();
262 }
263 return namedAreas;
264 }
265
266 /**
267 * Returns all {@link NamedArea}s of the {@link TermVocabulary} defined
268 * by the vaadin session attribute {@link DistributionEditorUtil#SATTR_SELECTED_AREA_VOCABULARY_UUID}
269 * ordered by labels.
270 * @return all {@link NamedArea}s of the {@link TermVocabulary} defined
271 * by the vaadin session attribute {@link DistributionEditorUtil#SATTR_SELECTED_AREA_VOCABULARY_UUID}
272 * ordered by labels..
273 */
274 private List<NamedArea> getChosenAreasFromVoc(){
275 VaadinSession session = VaadinSession.getCurrent();
276 UUID vocUUID = (UUID) session.getAttribute(DistributionEditorUtil.SATTR_SELECTED_AREA_VOCABULARY_UUID);
277 TermVocabulary<NamedArea> vocabulary = CdmSpringContextHelper.getVocabularyService().load(vocUUID, Arrays.asList("terms")); //$NON-NLS-1$
278 vocabulary = CdmBase.deproxy(vocabulary, TermVocabulary.class);
279 if (vocabulary instanceof OrderedTermVocabulary) {
280 List<NamedArea> list = new ArrayList<>(((OrderedTermVocabulary)vocabulary).getOrderedTerms());
281 Collections.reverse(list);
282 return list;
283 }else {
284 return vocabulary.getTermsOrderedByLabels(Language.DEFAULT()).stream().collect(Collectors.toCollection(ArrayList::new));
285 }
286
287 }
288
289 /**
290 * Returns all {@link TaxonNode}s defined by the
291 * vaadin session attribute {@link DistributionEditorUtil#SATTR_TAXON_NODES_UUID}.
292 * If this session attribute is not set, all {@link TaxonNode}s of the chosen
293 * classification defined by the vaadin session attribute
294 * {@link DistributionEditorUtil#SATTR_CLASSIFICATION} are returned.
295 * @return All {@link TaxonNode}s defined by the
296 * vaadin session attribute {@link DistributionEditorUtil#SATTR_TAXON_NODES_UUID}.
297 * If this session attribute is not set, all {@link TaxonNode}s of the chosen
298 * classification defined by the vaadin session attribute
299 * {@link DistributionEditorUtil#SATTR_CLASSIFICATION}.
300 */
301 private List<TaxonNode> getChosenTaxonNodes() {
302 VaadinSession session = VaadinSession.getCurrent();
303 List<UUID> taxonNodeUUIDs = (List<UUID>) session.getAttribute(DistributionEditorUtil.SATTR_TAXON_NODES_UUID);
304 UUID classificationUuid = (UUID)session.getAttribute(DistributionEditorUtil.SATTR_CLASSIFICATION);
305 if((taxonNodeUUIDs==null || taxonNodeUUIDs.isEmpty()) && classificationUuid!=null){
306 Classification classification = CdmSpringContextHelper.getClassificationService().load(classificationUuid);
307 if(classification!=null){
308 taxonNodeUUIDs = Collections.singletonList(classification.getRootNode().getUuid());
309 }
310 }
311 List<TaxonNode> loadedNodes = CdmSpringContextHelper.getTaxonNodeService().load(taxonNodeUUIDs, null);
312 if(loadedNodes!=null){
313 return loadedNodes;
314 }
315 return Collections.emptyList();
316 }
317
318 /**
319 * Returns the list of chosen {@link TaxonNode}s returned by {@link #getChosenTaxonNodes()}
320 * and adds their children to it.
321 * @return List of chosen {@link TaxonNode}s returned by {@link #getChosenTaxonNodes()}
322 * and their children.
323 */
324 private List<TaxonNode> getAllNodes(){
325 boolean includeUnpublished = DistributionEditorUtil.INCLUDE_UNPUBLISHED;
326
327 List<TaxonNode> allNodes = new ArrayList<>();
328
329 List<TaxonNode> taxonNodes = getChosenTaxonNodes();
330 for (TaxonNode taxonNode : taxonNodes) {
331 if(taxonNode.getTaxon()!=null){
332 allNodes.add(taxonNode);
333 }
334 allNodes.addAll(CdmSpringContextHelper.getTaxonNodeService().loadChildNodesOfTaxonNode(taxonNode, null, true, includeUnpublished, null));
335 }
336 return allNodes;
337 }
338
339 protected static final List<String> DESCRIPTION_INIT_STRATEGY = Arrays.asList(new String []{
340 "$", //$NON-NLS-1$
341 "elements.*", //$NON-NLS-1$
342 "elements.sources.citation.authorship.$", //$NON-NLS-1$
343 "elements.sources.nameUsedInSource.originalInfo", //$NON-NLS-1$
344 "elements.area.level", //$NON-NLS-1$
345 "elements.modifyingText", //$NON-NLS-1$
346 "elements.states.*", //$NON-NLS-1$
347 "elements.media", //$NON-NLS-1$
348 "elements.multilanguageText", //$NON-NLS-1$
349 "multilanguageText", //$NON-NLS-1$
350 "stateData.$", //$NON-NLS-1$
351 "annotations", //$NON-NLS-1$
352 "markers", //$NON-NLS-1$
353 "sources.citation.authorship", //$NON-NLS-1$
354 "sources.nameUsedInSource", //$NON-NLS-1$
355 "multilanguageText", //$NON-NLS-1$
356 "media", //$NON-NLS-1$
357 "name.$", //$NON-NLS-1$
358 "name.rank", //$NON-NLS-1$
359 "name.status.type", //$NON-NLS-1$
360 "taxon2.name", //$NON-NLS-1$
361 });
362
363 /**Helper Methods*/
364 private void sort(List<DescriptionElementBase> list){
365 Collections.sort(list, new Comparator<DescriptionElementBase>() {
366
367 @Override
368 public int compare(DescriptionElementBase o1, DescriptionElementBase o2) {
369 String feature1 = o1.getFeature().getTitleCache();
370 String feature2 = o2.getFeature().getTitleCache();
371 if(feature1 !=null && feature2 !=null){
372 return feature1.compareTo(feature2);
373 }else{
374 return 0;
375
376 }
377 }
378 });
379 }
380
381 /**
382 *
383 * {@inheritDoc}
384 */
385 @Override
386 protected void onPresenterReady() {
387 /*
388 * The area and taxon settings window should only be displayed after login
389 * and only when no classification and areas are chosen yet.
390 */
391 VaadinSession vaadinSession = VaadinSession.getCurrent();
392 if(userHelper.userIsAutheticated()
393 && !userHelper.userIsAnnonymous()
394 && (vaadinSession.getAttribute(DistributionEditorUtil.SATTR_CLASSIFICATION) == null
395 || vaadinSession.getAttribute(DistributionEditorUtil.SATTR_SELECTED_AREA_VOCABULARY_UUID) == null
396 || vaadinSession.getAttribute(DistributionEditorUtil.SATTR_SELECTED_AREAS) == null)) {
397 getView().openAreaAndTaxonSettings();
398 }
399 }
400
401 /**Unused Methods*/
402 // TODO: Currently unused. Remove?
403 private List<String> getAbbreviatedNamedAreas() {
404 List<NamedArea> terms = getChosenAreasFromVoc();
405 List<String> list = new ArrayList<>();
406 for(DefinedTermBase<?> dtb: terms){
407 for(Representation r : dtb.getRepresentations()){
408 list.add(r.getAbbreviatedLabel());
409 }
410 }
411 return list;
412 }
413
414 // TODO: Currently unused. Remove?
415 private HashMap<DescriptionElementBase, Distribution> getDistribution(DefinedTermBase dt, Taxon taxon) {
416
417 boolean includeUnpublished = true;
418 Set<Feature> setFeature = new HashSet<>(Arrays.asList(Feature.DISTRIBUTION()));
419 List<DescriptionElementBase> listTaxonDescription = CdmSpringContextHelper.getDescriptionService()
420 .listDescriptionElementsForTaxon(taxon, setFeature, null, includeUnpublished, null, null, DESCRIPTION_INIT_STRATEGY);
421 HashMap<DescriptionElementBase, Distribution> map = null;
422 for(DescriptionElementBase deb : listTaxonDescription){
423 if(deb instanceof Distribution){
424 Distribution db = (Distribution)deb;
425 String titleCache = dt.getTitleCache();
426 if(db.getArea().getTitleCache().equalsIgnoreCase(titleCache)){
427 map = new HashMap<DescriptionElementBase, Distribution>();
428 map.put(deb, db);
429 }
430 }
431 }
432 return map;
433 }
434
435 public LazyQueryContainer getAreaDistributionStatusContainer() {
436 List<UUID> nodeUuids = getAllNodes().stream().map(n -> n.getUuid()).collect(Collectors.toCollection(ArrayList::new));
437 List<NamedArea> namedAreas = getChosenAreas();
438 if(namedAreas!=null){
439 QueryFactory factory = new DistributionStatusQueryFactory(this.repo, nodeUuids, namedAreas);
440 QueryDefinition defintion = new DistributionStatusQueryDefinition(namedAreas, true, 50);
441 return new LazyQueryContainer(defintion, factory);
442 }
443 return null;
444 }
445 }