View Javadoc
1   package org.djutils.event.util;
2   
3   import java.io.Serializable;
4   import java.util.Collection;
5   import java.util.Map;
6   import java.util.Set;
7   
8   import org.djutils.event.EventProducer;
9   import org.djutils.event.EventType;
10  import org.djutils.event.IdProvider;
11  import org.djutils.exceptions.Throw;
12  import org.djutils.metadata.MetaData;
13  import org.djutils.metadata.ObjectDescriptor;
14  
15  /**
16   * The Event producing map provides a map to which one can subscribe interest in entry changes. This class does not keep track
17   * of changes which take place indirectly. One is for example not notified on <code>map.iterator.remove()</code>. A listener
18   * must subscribe to the iterator, key set, etc. individually.
19   * <p>
20   * Copyright (c) 2002-2022 Delft University of Technology, Jaffalaan 5, 2628 BX Delft, the Netherlands. All rights reserved. See
21   * for project information <a href="https://djutils.org" target="_blank"> https://djutils.org</a>. The DJUTILS project is
22   * distributed under a three-clause BSD-style license, which can be found at
23   * <a href="https://djutils.org/docs/license.html" target="_blank"> https://djutils.org/docs/license.html</a>. This class was
24   * originally part of the DSOL project, see <a href="https://simulation.tudelft.nl/dsol/manual" target="_blank">
25   * https://simulation.tudelft.nl/dsol/manual</a>.
26   * </p>
27   * @author <a href="https://www.linkedin.com/in/peterhmjacobs">Peter Jacobs </a>
28   * @author <a href="https://www.tudelft.nl/averbraeck">Alexander Verbraeck</a>
29   * @param <K> the key type
30   * @param <V> the value type
31   */
32  public class EventProducingMap<K, V> extends EventProducer implements Map<K, V>
33  {
34      /** The default serial version UID for serializable classes. */
35      private static final long serialVersionUID = 20191230L;
36  
37      /** OBJECT_ADDED_EVENT is fired on new entries. */
38      public static final EventType OBJECT_ADDED_EVENT =
39              new EventType("OBJECT_ADDED_EVENT", new MetaData("Size of the map after add", "Size of the map",
40                      new ObjectDescriptor("Size of the map after add", "Size of the map", Integer.class)));
41  
42      /** OBJECT_REMOVED_EVENT is fired on removal of entries. */
43      public static final EventType OBJECT_REMOVED_EVENT =
44              new EventType("OBJECT_REMOVED_EVENT", new MetaData("Size of the map after remove", "Size of the map",
45                      new ObjectDescriptor("Size of the map after remove", "Size of the map", Integer.class)));
46  
47      /** OBJECT_CHANGED_EVENT is fired on change of one or more entries. */
48      public static final EventType OBJECT_CHANGED_EVENT =
49              new EventType("OBJECT_CHANGED_EVENT", new MetaData("Size of the map after change", "Size of the map",
50                      new ObjectDescriptor("Size of the map after change", "Size of the map", Integer.class)));
51  
52      /** the parent map. */
53      private final Map<K, V> parent;
54  
55      /** the function that produces the id by which the EventProducer can be identified. */
56      private final IdProvider sourceIdProvider;
57  
58      /**
59       * constructs a new EventProducingMap.
60       * @param parent Map&lt;K,V&gt;; the embedded map.
61       * @param sourceId Serializable; the id by which the EventProducer can be identified by the EventListener
62       */
63      public EventProducingMap(final Map<K, V> parent, final Serializable sourceId)
64      {
65          this(parent, new IdProvider()
66          {
67              /** */
68              private static final long serialVersionUID = 20200119L;
69  
70              @Override
71              public Serializable id()
72              {
73                  return sourceId;
74              }
75          });
76      }
77  
78      /**
79       * Constructs a new EventProducingMap.
80       * @param parent Map&lt;K, V&gt;; the parent map.
81       * @param sourceIdProvider IdProvider; the function that produces the id by which the EventProducer can be identified by the
82       *            EventListener
83       */
84      public EventProducingMap(final Map<K, V> parent, final IdProvider sourceIdProvider)
85      {
86          Throw.whenNull(parent, "parent cannot be null");
87          Throw.whenNull(sourceIdProvider, "sourceIdprovider cannot be null");
88          this.parent = parent;
89          this.sourceIdProvider = sourceIdProvider;
90      }
91  
92      /** {@inheritDoc} */
93      @Override
94      public Serializable getSourceId()
95      {
96          return this.sourceIdProvider.id();
97      }
98  
99      /** {@inheritDoc} */
100     @Override
101     public int size()
102     {
103         return this.parent.size();
104     }
105 
106     /** {@inheritDoc} */
107     @Override
108     public boolean isEmpty()
109     {
110         return this.parent.isEmpty();
111     }
112 
113     /** {@inheritDoc} */
114     @Override
115     public boolean containsKey(final Object key)
116     {
117         return this.parent.containsKey(key);
118     }
119 
120     /** {@inheritDoc} */
121     @Override
122     public boolean containsValue(final Object value)
123     {
124         return this.parent.containsValue(value);
125     }
126 
127     /** {@inheritDoc} */
128     @Override
129     public V get(final Object key)
130     {
131         return this.parent.get(key);
132     }
133 
134     /** {@inheritDoc} */
135     @Override
136     public V put(final K key, final V value)
137     {
138         int nr = this.parent.size();
139         V result = this.parent.put(key, value);
140         if (nr != this.parent.size())
141         {
142             this.fireEvent(OBJECT_ADDED_EVENT, this.parent.size());
143         }
144         else
145         {
146             this.fireEvent(OBJECT_CHANGED_EVENT, this.parent.size());
147         }
148         return result;
149     }
150 
151     /** {@inheritDoc} */
152     @Override
153     public V remove(final Object key)
154     {
155         int nr = this.parent.size();
156         V result = this.parent.remove(key);
157         if (nr != this.parent.size())
158         {
159             this.fireEvent(OBJECT_REMOVED_EVENT, this.parent.size());
160         }
161         return result;
162     }
163 
164     /** {@inheritDoc} */
165     @Override
166     public void putAll(final Map<? extends K, ? extends V> map)
167     {
168         int nr = this.parent.size();
169         this.parent.putAll(map);
170         if (nr != this.parent.size())
171         {
172             this.fireEvent(OBJECT_ADDED_EVENT, this.parent.size());
173         }
174         else
175         {
176             if (!map.isEmpty())
177             {
178                 this.fireEvent(OBJECT_CHANGED_EVENT, this.parent.size());
179             }
180         }
181     }
182 
183     /** {@inheritDoc} */
184     @Override
185     public void clear()
186     {
187         int nr = this.parent.size();
188         this.parent.clear();
189         if (nr != this.parent.size())
190         {
191             this.fireEvent(OBJECT_REMOVED_EVENT, this.parent.size());
192         }
193     }
194 
195     /** {@inheritDoc} */
196     @Override
197     public Set<K> keySet()
198     {
199         return this.parent.keySet();
200     }
201 
202     /** {@inheritDoc} */
203     @Override
204     public Collection<V> values()
205     {
206         return this.parent.values();
207     }
208 
209     /** {@inheritDoc} */
210     @Override
211     public Set<Map.Entry<K, V>> entrySet()
212     {
213         return this.parent.entrySet();
214     }
215 }