1   package org.djutils.event.util;
2   
3   import java.io.Serializable;
4   import java.rmi.RemoteException;
5   import java.util.Collection;
6   
7   import org.djutils.event.EventInterface;
8   import org.djutils.event.EventListenerInterface;
9   import org.djutils.event.EventProducer;
10  import org.djutils.event.EventType;
11  import org.djutils.event.IdProvider;
12  import org.djutils.event.ref.ReferenceType;
13  import org.djutils.exceptions.Throw;
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  public class EventProducingCollection<T> extends EventProducer implements EventListenerInterface, Collection<T>
32  {
33      
34      private static final long serialVersionUID = 20191230L;
35  
36      
37      public static final EventType>EventType OBJECT_ADDED_EVENT = new EventType("OBJECT_ADDED_EVENT");
38  
39      
40      public static final EventTypeventType OBJECT_REMOVED_EVENT = new EventType("OBJECT_REMOVED_EVENT");
41  
42      
43      public static final EventTypeventType OBJECT_CHANGED_EVENT = new EventType("OBJECT_CHANGED_EVENT");
44  
45      
46      private Collection<T> parent = null;
47  
48      
49      private final IdProvider sourceIdProvider;
50  
51      
52  
53  
54  
55  
56      public EventProducingCollection(final Collection<T> parent, final Serializable sourceId)
57      {
58          this(parent, new IdProvider()
59          {
60              
61              private static final long serialVersionUID = 20200119L;
62  
63              @Override
64              public Serializable id()
65              {
66                  return sourceId;
67              }
68          });
69      }
70  
71      
72  
73  
74  
75  
76  
77      public EventProducingCollection(final Collection<T> parent, final IdProvider sourceIdProvider)
78      {
79          Throw.whenNull(parent, "parent cannot be null");
80          Throw.whenNull(sourceIdProvider, "sourceIdprovider cannot be null");
81          this.parent = parent;
82          this.sourceIdProvider = sourceIdProvider;
83      }
84  
85      
86      @Override
87      public Serializable getSourceId()
88      {
89          return this.sourceIdProvider.id();
90      }
91  
92      
93      @Override
94      public int size()
95      {
96          return this.parent.size();
97      }
98  
99      
100     @Override
101     public boolean isEmpty()
102     {
103         return this.parent.isEmpty();
104     }
105 
106     
107     @Override
108     public void clear()
109     {
110         int nr = this.parent.size();
111         this.parent.clear();
112         if (nr != this.parent.size())
113         {
114             this.fireEvent(OBJECT_REMOVED_EVENT, this.parent.size());
115         }
116     }
117 
118     
119     @Override
120     public boolean add(final T o)
121     {
122         boolean changed = this.parent.add(o);
123         if (changed)
124         {
125             this.fireEvent(OBJECT_ADDED_EVENT, this.parent.size());
126         }
127         else
128         {
129             this.fireEvent(OBJECT_CHANGED_EVENT, this.parent.size());
130         }
131         return changed;
132     }
133 
134     
135     @Override
136     public boolean addAll(final Collection<? extends T> c)
137     {
138         boolean changed = this.parent.addAll(c);
139         if (changed)
140         {
141             this.fireEvent(OBJECT_ADDED_EVENT, this.parent.size());
142         }
143         else
144         {
145             if (!c.isEmpty())
146             {
147                 this.fireEvent(OBJECT_CHANGED_EVENT, this.parent.size());
148             }
149         }
150         return changed;
151     }
152 
153     
154     @Override
155     public boolean contains(final Object o)
156     {
157         return this.parent.contains(o);
158     }
159 
160     
161     @Override
162     public boolean containsAll(final Collection<?> c)
163     {
164         return this.parent.containsAll(c);
165     }
166 
167     
168     @Override
169     public EventProducingIterator<T> iterator()
170     {
171         EventProducingIterator<T> iterator = new EventProducingIterator<T>(this.parent.iterator(), this.sourceIdProvider);
172         
173         iterator.addListener(this, EventProducingIterator.OBJECT_REMOVED_EVENT, ReferenceType.WEAK);
174         return iterator;
175     }
176 
177     
178     @Override
179     public void notify(final EventInterface event) throws RemoteException
180     {
181         
182         if (event.getType().equals(EventProducingIterator.OBJECT_REMOVED_EVENT))
183         {
184             this.fireEvent(OBJECT_REMOVED_EVENT, this.parent.size());
185         }
186     }
187 
188     
189     @Override
190     public boolean remove(final Object o)
191     {
192         boolean changed = this.parent.remove(o);
193         if (changed)
194         {
195             this.fireEvent(OBJECT_REMOVED_EVENT, this.parent.size());
196         }
197         return changed;
198     }
199 
200     
201     @Override
202     public boolean removeAll(final Collection<?> c)
203     {
204         boolean changed = this.parent.removeAll(c);
205         if (changed)
206         {
207             this.fireEvent(OBJECT_REMOVED_EVENT, this.parent.size());
208         }
209         return changed;
210     }
211 
212     
213     @Override
214     public boolean retainAll(final Collection<?> c)
215     {
216         boolean changed = this.parent.retainAll(c);
217         if (changed)
218         {
219             this.fireEvent(OBJECT_REMOVED_EVENT, this.parent.size());
220         }
221         return changed;
222     }
223 
224     
225     @Override
226     public Object[] toArray()
227     {
228         return this.parent.toArray();
229     }
230 
231     
232     @Override
233     public <E> E[] toArray(final E[] a)
234     {
235         return this.parent.toArray(a);
236     }
237 }