You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

KeyMapper.java 5.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. /*
  2. * Copyright 2000-2018 Vaadin Ltd.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  5. * use this file except in compliance with the License. You may obtain a copy of
  6. * the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  12. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. * License for the specific language governing permissions and limitations under
  14. * the License.
  15. */
  16. package com.vaadin.server;
  17. import java.util.ArrayList;
  18. import java.util.HashMap;
  19. import java.util.HashSet;
  20. import java.util.List;
  21. import java.util.Map;
  22. import java.util.Set;
  23. import java.util.function.Predicate;
  24. import com.vaadin.data.ValueProvider;
  25. import com.vaadin.data.provider.DataKeyMapper;
  26. import com.vaadin.event.Action;
  27. /**
  28. * <code>KeyMapper</code> is the simple two-way map for generating textual keys
  29. * for objects and retrieving the objects later with the key.
  30. *
  31. * @author Vaadin Ltd.
  32. * @since 3.0
  33. */
  34. public class KeyMapper<V> implements DataKeyMapper<V> {
  35. private int lastKey = 0;
  36. private final Map<Object, String> objectIdKeyMap = new HashMap<>();
  37. private final Map<String, V> keyObjectMap = new HashMap<>();
  38. private ValueProvider<V, Object> identifierGetter;
  39. /**
  40. * Constructs a new mapper.
  41. *
  42. * @param identifierGetter
  43. * has to return a unique key for every bean, and the returned
  44. * key has to follow general {@code hashCode()} and
  45. * {@code equals()} contract, see {@link Object#hashCode()} for
  46. * details.
  47. * @since 8.1
  48. */
  49. public KeyMapper(ValueProvider<V, Object> identifierGetter) {
  50. this.identifierGetter = identifierGetter;
  51. }
  52. /**
  53. * Constructs a new mapper with trivial {@code identifierGetter}.
  54. */
  55. public KeyMapper() {
  56. this(v -> v);
  57. }
  58. /**
  59. * Gets key for an object.
  60. *
  61. * @param o
  62. * the object.
  63. */
  64. @Override
  65. public String key(V o) {
  66. if (o == null) {
  67. return "null";
  68. }
  69. // If the object is already mapped, use existing key
  70. Object id = identifierGetter.apply(o);
  71. String key = objectIdKeyMap.get(id);
  72. if (key != null) {
  73. return key;
  74. }
  75. // If the object is not yet mapped, map it
  76. key = createKey();
  77. objectIdKeyMap.put(id, key);
  78. keyObjectMap.put(key, o);
  79. return key;
  80. }
  81. /**
  82. * Creates a key for a new item.
  83. * <p>
  84. * This method can be overridden to customize the keys used.
  85. *
  86. * @return new key
  87. * @since 8.1.2
  88. */
  89. protected String createKey() {
  90. return String.valueOf(++lastKey);
  91. }
  92. @Override
  93. public boolean has(V o) {
  94. return objectIdKeyMap.containsKey(identifierGetter.apply(o));
  95. }
  96. /**
  97. * Retrieves object with the key.
  98. *
  99. * @param key
  100. * the name with the desired value.
  101. * @return the object with the key.
  102. */
  103. @Override
  104. public V get(String key) {
  105. return keyObjectMap.get(key);
  106. }
  107. /**
  108. * Removes object from the mapper.
  109. *
  110. * @param removeobj
  111. * the object to be removed.
  112. */
  113. @Override
  114. public void remove(V removeobj) {
  115. final String key = objectIdKeyMap
  116. .remove(identifierGetter.apply(removeobj));
  117. if (key != null) {
  118. keyObjectMap.remove(key);
  119. }
  120. }
  121. /**
  122. * Removes all objects from the mapper.
  123. */
  124. @Override
  125. public void removeAll() {
  126. objectIdKeyMap.clear();
  127. keyObjectMap.clear();
  128. }
  129. /**
  130. * Merge Objects into the mapper.
  131. * <p>
  132. * This method will add the new objects to the mapper and remove inactive
  133. * objects from it.
  134. *
  135. * @param objects
  136. * new objects set needs to be merged.
  137. * @since 8.7
  138. */
  139. public void merge(Set<V> objects) {
  140. final Set<String> keys = new HashSet<>(keyObjectMap.size());
  141. for (V object : objects) {
  142. if (object == null) {
  143. continue;
  144. }
  145. String key = key(object);
  146. keys.add(key);
  147. }
  148. keyObjectMap.entrySet()
  149. .removeIf(entry -> !keys.contains(entry.getKey()));
  150. objectIdKeyMap.entrySet()
  151. .removeIf(entry -> !keys.contains(entry.getValue()));
  152. }
  153. /**
  154. * Checks if the given key is mapped to an object.
  155. *
  156. * @param key
  157. * the key to check
  158. * @return <code>true</code> if the key is currently mapped,
  159. * <code>false</code> otherwise
  160. * @since 7.7
  161. */
  162. public boolean containsKey(String key) {
  163. return keyObjectMap.containsKey(key);
  164. }
  165. @Override
  166. public void refresh(V dataObject) {
  167. Object id = identifierGetter.apply(dataObject);
  168. String key = objectIdKeyMap.get(id);
  169. if (key != null) {
  170. keyObjectMap.put(key, dataObject);
  171. }
  172. }
  173. @Override
  174. public void setIdentifierGetter(ValueProvider<V, Object> identifierGetter) {
  175. if (this.identifierGetter != identifierGetter) {
  176. this.identifierGetter = identifierGetter;
  177. objectIdKeyMap.clear();
  178. for (Map.Entry<String, V> entry : keyObjectMap.entrySet()) {
  179. objectIdKeyMap.put(identifierGetter.apply(entry.getValue()),
  180. entry.getKey());
  181. }
  182. }
  183. }
  184. }