fix #7831 excluding the current name from the WeaklyRelatedEntityCombobox for genus...
[cdm-vaadin.git] / src / main / java / eu / etaxonomy / cdm / service / TaxonNameStringFilterablePagingProvider.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.service;
10
11 import java.util.ArrayList;
12 import java.util.Arrays;
13 import java.util.HashMap;
14 import java.util.List;
15 import java.util.Map;
16 import java.util.UUID;
17
18 import org.apache.log4j.Logger;
19 import org.vaadin.viritin.fields.LazyComboBox.FilterableCountProvider;
20
21 import com.vaadin.data.Property.ValueChangeListener;
22 import com.vaadin.ui.AbstractField;
23 import com.vaadin.ui.Field;
24
25 import eu.etaxonomy.cdm.api.service.INameService;
26 import eu.etaxonomy.cdm.api.service.pager.Pager;
27 import eu.etaxonomy.cdm.api.utility.TaxonNamePartsFilter;
28 import eu.etaxonomy.cdm.model.name.Rank;
29 import eu.etaxonomy.cdm.model.name.TaxonName;
30 import eu.etaxonomy.cdm.persistence.dto.TaxonNameParts;
31 import eu.etaxonomy.cdm.persistence.query.MatchMode;
32 import eu.etaxonomy.cdm.persistence.query.OrderHint;
33
34 /**
35 * IMPORTANT !!!
36 *
37 * The string representations returned as rankSpecificNamePart must be unique in the database since these are being used as weak references between e.g.
38 * genus name and the TaxonName entity for this genus.
39 *
40 * @author a.kohlbecker
41 * @since Jun 7, 2017
42 *
43 */
44 public class TaxonNameStringFilterablePagingProvider implements FilterableStringRepresentationPagingProvider<UUID>, FilterableCountProvider {
45
46 private static final List<String> DEFAULT_INIT_STRATEGY = Arrays.asList("$");
47
48 private static final Logger logger = Logger.getLogger(TaxonNameStringFilterablePagingProvider.class);
49
50 private int pageSize = 20;
51
52 private INameService service;
53
54 private MatchMode matchMode = MatchMode.BEGINNING;
55
56 private List<OrderHint> orderHints = OrderHint.ORDER_BY_TITLE_CACHE.asList();
57
58 List<String> initStrategy = DEFAULT_INIT_STRATEGY;
59
60 private TaxonNamePartsFilter namePartsFilter = new TaxonNamePartsFilter();
61
62 private Map<AbstractField<String>, ValueChangeListener> registeredToFields = new HashMap<>();
63
64 private Map<String, UUID> lastPagedEntityUUIDs;
65
66
67 public TaxonNameStringFilterablePagingProvider(INameService service) {
68 this(service, Rank.GENUS(), null);
69 }
70
71 public TaxonNameStringFilterablePagingProvider(INameService service, Rank rank) {
72 this(service, rank, null);
73 }
74
75 public TaxonNameStringFilterablePagingProvider(INameService service, Rank rank, MatchMode matchMode) {
76 super();
77 this.service = service;
78 if(matchMode != null){
79 this.matchMode = matchMode;
80 }
81 namePartsFilter.setRank(rank);
82 }
83
84 public void listenToFields(AbstractField<String> genusOrUninomialField, AbstractField<String> infraGenericEpithetField,
85 AbstractField<String> specificEpithetField, AbstractField<String> infraSpecificEpithetField){
86
87 unlistenAllFields();
88
89 registerNullSave(genusOrUninomialField, e -> namePartsFilter.setGenusOrUninomial(genusOrUninomialField.getValue()));
90 registerNullSave(infraGenericEpithetField, e -> namePartsFilter.setGenusOrUninomial(infraGenericEpithetField.getValue()));
91 registerNullSave(specificEpithetField, e -> namePartsFilter.setGenusOrUninomial(specificEpithetField.getValue()));
92 registerNullSave(infraSpecificEpithetField, e -> namePartsFilter.setGenusOrUninomial(infraSpecificEpithetField.getValue()));
93 }
94
95 /**
96 *
97 */
98 public void unlistenAllFields() {
99 for(AbstractField<String> f : registeredToFields.keySet()){
100 f.removeValueChangeListener(registeredToFields.get(f));
101 }
102 registeredToFields.clear();
103 }
104
105 public void replaceFields(AbstractField<String> unlistenField, AbstractField<String> listenToField) throws UnknownFieldException{
106 if(registeredToFields.containsKey(unlistenField)){
107 ValueChangeListener listener = registeredToFields.get(unlistenField);
108 unlistenField.removeValueChangeListener(listener);
109 registeredToFields.remove(unlistenField);
110 registerNullSave(listenToField, listener);
111 } else {
112 throw new UnknownFieldException();
113 }
114 }
115
116 public void updateFromFields(){
117 for(AbstractField<String> f : registeredToFields.keySet()){
118 ValueChangeListener listener = registeredToFields.get(f);
119 listener.valueChange(new Field.ValueChangeEvent(f));
120 }
121 }
122
123 /**
124 * @param genusOrUninomialField
125 */
126 protected void registerNullSave(AbstractField<String> field, ValueChangeListener listener) {
127 if(field != null){
128 registeredToFields.put(field, listener);
129 field.addValueChangeListener(listener);
130 }
131 }
132
133 /**
134 * @return the matchMode
135 */
136 protected MatchMode getMatchMode() {
137 return matchMode;
138 }
139
140 /**
141 * @param matchMode the matchMode to set
142 */
143 protected void setMatchMode(MatchMode matchMode) {
144 this.matchMode = matchMode;
145 }
146
147 /**
148 * @return the orderHints
149 */
150 protected List<OrderHint> getOrderHints() {
151 return orderHints;
152 }
153
154 /**
155 * @param orderHints the orderHints to set
156 */
157 protected void setOrderHints(List<OrderHint> orderHints) {
158 this.orderHints = orderHints;
159 }
160
161 public TaxonNamePartsFilter getFilter(){
162 return namePartsFilter;
163 }
164
165 /**
166 * {@inheritDoc}
167 */
168 @Override
169 public List<String> findEntities(int firstRow, String filter) {
170
171 Integer pageIndex = firstRow / pageSize;
172 Pager<TaxonNameParts> taxonNamePager = service.findTaxonNameParts(namePartsFilter, filter, pageSize, pageIndex, orderHints);
173 if(logger.isTraceEnabled()){
174 logger.trace("findEntities() - page: " + taxonNamePager.getCurrentIndex() + "/" + taxonNamePager.getPagesAvailable() + " totalRecords: " + taxonNamePager.getCount() + "\n" + taxonNamePager.getRecords());
175 }
176 List<String> namePartStrings = new ArrayList<>(taxonNamePager.getRecords().size());
177 lastPagedEntityUUIDs = new HashMap<>(taxonNamePager.getRecords().size());
178 for(TaxonNameParts tnp : taxonNamePager.getRecords()){
179 String rankSpecificNamePart = tnp.rankSpecificNamePart();
180 String namePartKey = rankSpecificNamePart;
181 if(lastPagedEntityUUIDs.containsKey(namePartKey)){
182 namePartKey = rankSpecificNamePart + " DUPLICATE[" + tnp.getTaxonNameUuid() + "]";
183 }
184 namePartStrings.add(namePartKey);
185 lastPagedEntityUUIDs.put(namePartKey, tnp.getTaxonNameUuid());
186 }
187 return namePartStrings;
188 }
189
190 /**
191 * {@inheritDoc}
192 */
193 @Override
194 public int size(String filter) {
195
196 Pager<TaxonNameParts> taxonNamePager = service.findTaxonNameParts(namePartsFilter, filter, 1, 0, null);
197 if(logger.isTraceEnabled()){
198 logger.trace("size() - count: " + taxonNamePager.getCount().intValue());
199 }
200 return taxonNamePager.getCount().intValue();
201 }
202
203 /**
204 * @return the pageSize
205 */
206 public int getPageSize() {
207 return pageSize;
208 }
209
210 /**
211 * @param pageSize the pageSize to set
212 */
213 public void setPageSize(int pageSize) {
214 this.pageSize = pageSize;
215 }
216
217 /**
218 * @return the lastPagedEntityUUIDs
219 */
220 public Map<String, UUID> getLastPagedEntityUUIDs() {
221 return lastPagedEntityUUIDs;
222 }
223
224
225 public class UnknownFieldException extends Exception {
226
227 private static final long serialVersionUID = 1L;
228 }
229
230 /**
231 * {@inheritDoc}
232 */
233 @Override
234 public UUID idFor(String stringRepresentation) {
235 if(lastPagedEntityUUIDs == null){
236 findEntities(0, stringRepresentation);
237 }
238 return lastPagedEntityUUIDs.get(stringRepresentation);
239 }
240
241 /**
242 * {@inheritDoc}
243 */
244 @Override
245 public void clearIdCache() {
246 lastPagedEntityUUIDs = null;
247 }
248
249 /**
250 * @param asList
251 * @return
252 */
253 public void excludeNames(TaxonName ... excludedTaxonNames) {
254 namePartsFilter.getExludedNames().clear();
255 for(TaxonName n : excludedTaxonNames){
256 namePartsFilter.getExludedNames().add(n);
257 }
258 }
259 }