View Javadoc

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