View Javadoc

1   /*
2    * $Id: EventGroup.java 7963 2007-08-21 08:53:15Z dirk.olmes $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSource, Inc.  All rights reserved.  http://www.mulesource.com
5    *
6    * The software in this package is published under the terms of the CPAL v1.0
7    * license, a copy of which has been included with this distribution in the
8    * LICENSE.txt file.
9    */
10  
11  package org.mule.routing.inbound;
12  
13  import org.mule.umo.UMOEvent;
14  import org.mule.util.ClassUtils;
15  
16  import java.io.Serializable;
17  import java.util.ArrayList;
18  import java.util.Iterator;
19  import java.util.List;
20  
21  import edu.emory.mathcs.backport.java.util.concurrent.helpers.Utils;
22  import org.apache.commons.collections.IteratorUtils;
23  
24  /**
25   * <code>EventGroup</code> is a holder over events grouped by a common group Id.
26   * This can be used by components such as routers to managed related events.
27   */
28  // @ThreadSafe
29  public class EventGroup implements Comparable, Serializable
30  {
31      /**
32       * Serial version
33       */
34      private static final long serialVersionUID = 953739659615692697L;
35  
36      public static final UMOEvent[] EMPTY_EVENTS_ARRAY = new UMOEvent[0];
37  
38      private final Object groupId;
39      // @GuardedBy("this")
40      private final List events;
41      private final long created;
42      private final int expectedSize;
43  
44      public EventGroup(Object groupId)
45      {
46          this(groupId, -1);
47      }
48  
49      public EventGroup(Object groupId, int expectedSize)
50      {
51          super();
52          this.created = Utils.nanoTime();
53          this.events = new ArrayList(expectedSize > 0 ? expectedSize : 10);
54          this.expectedSize = expectedSize;
55          this.groupId = groupId;
56      }
57  
58      /**
59       * Compare this EventGroup to another one. If the receiver and the argument both
60       * have groupIds that are {@link Comparable}, they are used for the comparison;
61       * otherwise - since the id can be any object - the group creation time stamp is
62       * used as fallback. Older groups are considered "smaller".
63       * 
64       * @see java.lang.Comparable#compareTo(java.lang.Object)
65       */
66      public int compareTo(Object o)
67      {
68          EventGroup other = (EventGroup) o;
69          Object otherId = other.getGroupId();
70  
71          if (groupId instanceof Comparable && otherId instanceof Comparable)
72          {
73              return ((Comparable) groupId).compareTo(otherId);
74          }
75          else
76          {
77              long diff = created - other.getCreated();
78              return (diff > 0 ? 1 : (diff < 0 ? -1 : 0));
79          }
80      }
81  
82      /**
83       * Compares two EventGroups for equality. EventGroups are considered equal when
84       * their groupIds (as returned by {@link #getGroupId()}) are equal.
85       * 
86       * @see java.lang.Object#equals(Object)
87       */
88      // @Override
89      public boolean equals(Object obj)
90      {
91          if (this == obj)
92          {
93              return true;
94          }
95  
96          if (!(obj instanceof EventGroup))
97          {
98              return false;
99          }
100 
101         final EventGroup other = (EventGroup) obj;
102         if (groupId == null)
103         {
104             return (other.groupId == null);
105         }
106 
107         return groupId.equals(other.groupId);
108     }
109 
110     /**
111      * The hashCode of an EventGroup is derived from the object returned by
112      * {@link #getGroupId()}.
113      * 
114      * @see java.lang.Object#hashCode()
115      */
116     // @Override
117     public int hashCode()
118     {
119         return groupId.hashCode();
120     }
121 
122     /**
123      * Returns an identifier for this EventGroup. It is recommended that this id is
124      * unique and {@link Comparable} e.g. a UUID.
125      * 
126      * @return the id of this event group
127      */
128     public Object getGroupId()
129     {
130         return groupId;
131     }
132 
133     /**
134      * Returns an iterator over a snapshot copy of this group's collected events. If
135      * you need to iterate over the group and e.g. remove select events, do so via
136      * {@link #removeEvent(UMOEvent)}. If you need to do so atomically in order to
137      * prevent e.g. concurrent reception/aggregation of the group during iteration,
138      * wrap the iteration in a synchronized block on the group instance.
139      * 
140      * @return an iterator over collected {@link UMOEvent}s.
141      */
142     public Iterator iterator()
143     {
144         synchronized (this)
145         {
146             if (events.isEmpty())
147             {
148                 return IteratorUtils.emptyIterator();
149             }
150             else
151             {
152                 return IteratorUtils.arrayIterator(this.toArray());
153             }
154         }
155     }
156 
157     /**
158      * Returns a snapshot of collected events in this group.
159      * 
160      * @return an array of collected {@link UMOEvent}s.
161      */
162     public UMOEvent[] toArray()
163     {
164         synchronized (this)
165         {
166             if (events.isEmpty())
167             {
168                 return EMPTY_EVENTS_ARRAY;
169             }
170 
171             return (UMOEvent[]) events.toArray(EMPTY_EVENTS_ARRAY);
172         }
173     }
174 
175     /**
176      * Add the given event to this group.
177      * 
178      * @param event the event to add
179      */
180     public void addEvent(UMOEvent event)
181     {
182         synchronized (this)
183         {
184             events.add(event);
185         }
186     }
187 
188     /**
189      * Remove the given event from the group.
190      * 
191      * @param event the evnt to remove
192      */
193     public void removeEvent(UMOEvent event)
194     {
195         synchronized (this)
196         {
197             events.remove(event);
198         }
199     }
200 
201     /**
202      * Return the creation timestamp of the current group.
203      * 
204      * @return the timestamp when this group was instantiated.
205      * @see {@link Utils#nanoTime()}
206      */
207     public long getCreated()
208     {
209         return created;
210     }
211 
212     /**
213      * Returns the number of events collected so far.
214      * 
215      * @return number of events in this group or 0 if the group is empty.
216      */
217     public int size()
218     {
219         synchronized (this)
220         {
221             return events.size();
222         }
223     }
224 
225     /**
226      * Returns the number of events that this EventGroup is expecting before
227      * correlation can proceed.
228      * 
229      * @return expected number of events or -1 if no expected size was specified.
230      */
231     public int expectedSize()
232     {
233         return expectedSize;
234     }
235 
236     /**
237      * Removes all events from this group.
238      */
239     public void clear()
240     {
241         synchronized (this)
242         {
243             events.clear();
244         }
245     }
246 
247     // @Override
248     public String toString()
249     {
250         StringBuffer buf = new StringBuffer(80);
251         buf.append(ClassUtils.getSimpleName(this.getClass()));
252         buf.append(" {");
253         buf.append("id=").append(groupId);
254         buf.append(", expected size=").append(expectedSize);
255 
256         synchronized (this)
257         {
258             int currentSize = events.size();
259             buf.append(", current events=").append(currentSize);
260 
261             if (currentSize > 0)
262             {
263                 buf.append(" [");
264                 Iterator i = events.iterator();
265                 while (i.hasNext())
266                 {
267                     UMOEvent event = (UMOEvent) i.next();
268                     buf.append(event.getMessage().getUniqueId());
269                     if (i.hasNext())
270                     {
271                         buf.append(", ");
272                     }
273                 }
274                 buf.append(']');
275             }
276         }
277 
278         buf.append('}');
279 
280         return buf.toString();
281     }
282 
283 }