2 * Copyright (C) 2017 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
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.
9 package eu
.etaxonomy
.cdm
.vaadin
.view
.distributionStatus
;
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
;
20 import java
.util
.UUID
;
21 import java
.util
.stream
.Collectors
;
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
;
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
;
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
;
65 * The presenter of the distribution status editor.
69 public class DistributionTablePresenter
70 extends AbstractPresenter
<DistributionTablePresenter
,IDistributionTableView
> {
72 private static final long serialVersionUID
= 3313043335587777217L;
75 private UserHelper userHelper
;
78 @Qualifier("cdmRepository")
79 private CdmRepository repo
; // TODO remove, since this is already in the super class
82 protected void eventViewBusSubscription(ViewEventBus viewEventBus
) {
83 // no point subscribing
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.
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.
96 public int updateDistributionField(NamedArea area
, PresenceAbsenceTerm distributionStatus
, Taxon taxon
) {
97 TransactionStatus tx
= repo
.startTransaction();
98 taxon
= (Taxon
)repo
.getTaxonService().find(taxon
.getUuid());
100 Notification
.show(Messages
.getLocalizedString(Messages
.DistributionTablePresenter_ERROR_UPDATE_DISTRIBUTION_TERM
));
101 repo
.commitTransaction(tx
);
104 List
<Distribution
> distributions
= getDistributions(taxon
);
105 Distribution distribution
= null;
106 for(Distribution dist
: distributions
){
107 if(dist
.getArea()!=null && dist
.getArea().equals(area
)){
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
);
123 } else {// there are no TaxonDescription yet.
124 TaxonDescription taxonDescription
= TaxonDescription
.NewInstance(taxon
);
125 taxonDescription
.addElement(distribution
);
126 repo
.commitTransaction(tx
);
130 else if(distributionStatus
== null){//delete descriptionElementBase
131 DescriptionBase
<?
> desc
= distribution
.getInDescription();
132 desc
.removeElement(distribution
);
133 repo
.commitTransaction(tx
);
136 else{//update distribution
137 distribution
.setStatus(distributionStatus
);
138 repo
.getCommonService().saveOrUpdate(distribution
);
139 repo
.commitTransaction(tx
);
142 repo
.commitTransaction(tx
);
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
153 public CdmSQLContainer
getSQLContainer() throws SQLException
{
154 List
<Integer
> nodeIds
= new ArrayList
<>();
155 for (TaxonNode taxonNode
: getAllNodes()) {
156 nodeIds
.add(taxonNode
.getId());
158 List
<NamedArea
> namedAreas
= getChosenAreas();
159 if(namedAreas
!=null){
160 return new CdmSQLContainer(CdmQueryFactory
.generateTaxonDistributionQuery(nodeIds
, namedAreas
));
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.
169 public PresenceAbsenceTermContainer
getPresenceAbsenceTermContainer() {
170 return PresenceAbsenceTermContainer
.getInstance();
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.
179 public List
<DescriptionElementBase
> listDescriptionElementsForTaxon(Taxon taxon
, Set
<Feature
> setFeature
){
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
;
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.
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"));
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}.
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
)){
217 else if(label
!=null && label
.equalsIgnoreCase(areaString
)){
223 if(namedArea
.getTitleCache().equalsIgnoreCase(areaString
)){
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}.
236 private List
<Distribution
> getDistributions(Taxon taxon
) {
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
;
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}.
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();
267 * Returns all {@link NamedArea}s of the {@link TermVocabulary} defined
268 * by the vaadin session attribute {@link DistributionEditorUtil#SATTR_SELECTED_AREA_VOCABULARY_UUID}
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..
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
);
284 return vocabulary
.getTermsOrderedByLabels(Language
.DEFAULT()).stream().collect(Collectors
.toCollection(ArrayList
::new));
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}.
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());
311 List
<TaxonNode
> loadedNodes
= CdmSpringContextHelper
.getTaxonNodeService().load(taxonNodeUUIDs
, null);
312 if(loadedNodes
!=null){
315 return Collections
.emptyList();
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.
324 private List
<TaxonNode
> getAllNodes(){
325 boolean includeUnpublished
= DistributionEditorUtil
.INCLUDE_UNPUBLISHED
;
327 List
<TaxonNode
> allNodes
= new ArrayList
<>();
329 List
<TaxonNode
> taxonNodes
= getChosenTaxonNodes();
330 for (TaxonNode taxonNode
: taxonNodes
) {
331 if(taxonNode
.getTaxon()!=null){
332 allNodes
.add(taxonNode
);
334 allNodes
.addAll(CdmSpringContextHelper
.getTaxonNodeService().loadChildNodesOfTaxonNode(taxonNode
, null, true, includeUnpublished
, null));
339 protected static final List
<String
> DESCRIPTION_INIT_STRATEGY
= Arrays
.asList(new String
[]{
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$
364 private void sort(List
<DescriptionElementBase
> list
){
365 Collections
.sort(list
, new Comparator
<DescriptionElementBase
>() {
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
);
386 protected void onPresenterReady() {
388 * The area and taxon settings window should only be displayed after login
389 * and only when no classification and areas are chosen yet.
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();
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());
414 // TODO: Currently unused. Remove?
415 private HashMap
<DescriptionElementBase
, Distribution
> getDistribution(DefinedTermBase dt
, Taxon taxon
) {
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
>();
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
);