View Javadoc

1   /*
2    * $Id: IdempotentReceiver.java 12296 2008-07-11 16:56:21Z dfeist $
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.MessagingException;
14  import org.mule.api.MuleEvent;
15  import org.mule.api.lifecycle.InitialisationException;
16  import org.mule.api.routing.RoutingException;
17  import org.mule.api.store.ObjectStore;
18  import org.mule.config.i18n.CoreMessages;
19  import org.mule.util.expression.ExpressionEvaluatorManager;
20  import org.mule.util.store.InMemoryObjectStore;
21  
22  /**
23   * <code>IdempotentReceiver</code> ensures that only unique messages are received by a
24   * service. It does this by checking the unique ID of the incoming message. Note that
25   * the underlying endpoint must support unique message IDs for this to work, otherwise a
26   * <code>UniqueIdNotSupportedException</code> is thrown.<br>
27   * By default this implementation uses an instance of
28   * {@link IdempotentInMemoryMessageIdStore}.
29   */
30  public class IdempotentReceiver extends SelectiveConsumer
31  {
32      protected volatile ObjectStore store;
33      protected volatile String assignedComponentName;
34  
35      protected String idExpression = "${message:id}";
36  
37      public IdempotentReceiver()
38      {
39          super();
40      }
41  
42      protected void initialize(MuleEvent event) throws RoutingException
43      {
44          if (assignedComponentName == null && store == null)
45          {
46              this.assignedComponentName = event.getService().getName();
47              try
48              {
49                  this.store = this.createMessageIdStore();
50              }
51              catch (InitialisationException e)
52              {
53                  throw new RoutingException(event.getMessage(), event.getEndpoint(), e);
54              }
55          }
56      }
57  
58      protected ObjectStore createMessageIdStore() throws InitialisationException
59      {
60          InMemoryObjectStore s = new InMemoryObjectStore();
61          s.setName(assignedComponentName);
62          s.setMaxEntries(-1);
63          s.setEntryTTL(60 * 5);
64          s.setExpirationInterval(6000);
65          s.initialise();
66          return s;
67      }
68  
69      // @Override
70      public boolean isMatch(MuleEvent event) throws MessagingException
71      {
72          if (!super.isMatch(event))
73          {
74              return false;
75          }
76          else
77          {
78              if (store == null)
79              {
80                  // we need to load this on the first request as we need the service
81                  // name
82                  synchronized (this)
83                  {
84                      this.initialize(event);
85                  }
86              }
87  
88              try
89              {
90                  return !store.containsObject(this.getIdForEvent(event));
91              }
92              catch (Exception ex)
93              {
94                  throw new RoutingException(event.getMessage(), event.getEndpoint(), ex);
95              }
96          }
97      }
98  
99      // @Override
100     public MuleEvent[] process(MuleEvent event) throws MessagingException
101     {
102         String eventComponentName = event.getService().getName();
103         if (!assignedComponentName.equals(eventComponentName))
104         {
105             IllegalArgumentException iex = new IllegalArgumentException(
106                 "This receiver is assigned to service: " + assignedComponentName
107                                 + " but has received an event for service: " + eventComponentName
108                                 + ". Please check your config to make sure each service"
109                                 + "has its own instance of IdempotentReceiver.");
110             throw new RoutingException(event.getMessage(), event.getEndpoint(), iex);
111         }
112 
113         String id = this.getIdForEvent(event);
114 
115         try
116         {
117             if (store.storeObject(id, id))
118             {
119                 return new MuleEvent[]{event};
120             }
121             else
122             {
123                 return null;
124             }
125         }
126         catch (Exception e)
127         {
128             throw new RoutingException(CoreMessages.failedToWriteMessageToStore(id, assignedComponentName),
129                 event.getMessage(), event.getEndpoint(), e);
130         }
131     }
132 
133     protected String getIdForEvent(MuleEvent event) throws MessagingException
134     {
135         return ExpressionEvaluatorManager.parse(idExpression, event.getMessage(), true);
136     }
137 
138     public String getIdExpression()
139     {
140         return idExpression;
141     }
142 
143     public void setIdExpression(String idExpression)
144     {
145         this.idExpression = idExpression;
146     }
147 
148     public ObjectStore getStore()
149     {
150         return store;
151     }
152 
153     public void setStore(ObjectStore store)
154     {
155         this.store = store;
156     }
157 }