1
2
3
4
5
6
7
8
9
10
11 package org.mule.routing.inbound;
12
13 import org.mule.MuleManager;
14 import org.mule.config.i18n.CoreMessages;
15 import org.mule.umo.MessagingException;
16 import org.mule.umo.UMOEvent;
17 import org.mule.umo.routing.RoutingException;
18 import org.mule.util.FileUtils;
19
20 import java.io.BufferedReader;
21 import java.io.File;
22 import java.io.FileReader;
23 import java.io.IOException;
24 import java.util.HashSet;
25 import java.util.Set;
26
27
28
29
30
31
32
33
34
35
36
37 public class IdempotentReceiver extends SelectiveConsumer
38 {
39 private static final String DEFAULT_STORE_PATH = "./idempotent";
40
41 private Set messageIds;
42 private File idStore;
43 private String componentName;
44 private boolean disablePersistence = false;
45 private String storePath;
46
47 public IdempotentReceiver()
48 {
49 messageIds = new HashSet();
50 String path = MuleManager.getConfiguration().getWorkingDirectory() + "/idempotent";
51 setStorePath(path);
52 }
53
54
55 public boolean isMatch(UMOEvent event) throws MessagingException
56 {
57 if (idStore == null)
58 {
59
60
61 this.load(event);
62 }
63 return !messageIds.contains(this.getIdForEvent(event));
64 }
65
66
67 public UMOEvent[] process(UMOEvent event) throws MessagingException
68 {
69 if (isMatch(event))
70 {
71 try
72 {
73 checkComponentName(event.getComponent().getDescriptor().getName());
74 }
75 catch (IllegalArgumentException e)
76 {
77 throw new RoutingException(event.getMessage(), event.getEndpoint(), e);
78 }
79
80 Object id = this.getIdForEvent(event);
81 try
82 {
83 this.storeId(id);
84 return new UMOEvent[]{event};
85 }
86 catch (IOException e)
87 {
88 throw new RoutingException(
89 CoreMessages.failedToWriteMessageToStore(id, idStore.getAbsolutePath()),
90 event.getMessage(), event.getEndpoint(), e);
91 }
92 }
93 else
94 {
95 return null;
96 }
97 }
98
99 protected Object getIdForEvent(UMOEvent event) throws MessagingException
100 {
101 return event.getMessage().getUniqueId();
102 }
103
104 private void checkComponentName(String name) throws IllegalArgumentException
105 {
106 if (!componentName.equals(name))
107 {
108 throw new IllegalArgumentException("This receiver is assigned to component: " + componentName
109 + " but has received an event for component: " + name
110 + ". Please check your config to make sure each component"
111 + "has its own instance of IdempotentReceiver");
112 }
113 }
114
115 protected synchronized void load(UMOEvent event) throws RoutingException
116 {
117 this.componentName = event.getComponent().getDescriptor().getName();
118
119 if (idStore == null)
120 {
121 idStore = FileUtils.newFile(storePath + "/muleComponent_" + componentName + ".store");
122 }
123
124 if (disablePersistence)
125 {
126 return;
127 }
128
129 try
130 {
131 if (idStore.exists())
132 {
133 BufferedReader reader = null;
134 try
135 {
136 reader = new BufferedReader(new FileReader(idStore));
137 String id;
138 while ((id = reader.readLine()) != null)
139 {
140 messageIds.add(id);
141 }
142 }
143 finally
144 {
145 if (reader != null)
146 {
147 reader.close();
148 }
149 }
150 }
151 else
152 {
153 idStore = FileUtils.createFile(idStore.getAbsolutePath());
154 }
155 }
156 catch (IOException e)
157 {
158 throw new RoutingException(
159 CoreMessages.failedToReadFromStore(idStore.getAbsolutePath()),
160 event.getMessage(), event.getEndpoint(), e);
161 }
162 }
163
164 protected synchronized void storeId(Object id) throws IOException
165 {
166 messageIds.add(id);
167 if (disablePersistence)
168 {
169 return;
170 }
171 FileUtils.stringToFile(idStore.getAbsolutePath(), id.toString(), true, true);
172 }
173
174 public boolean isDisablePersistence()
175 {
176 return disablePersistence;
177 }
178
179 public void setDisablePersistence(boolean disablePersistence)
180 {
181 this.disablePersistence = disablePersistence;
182 }
183
184 public String getStorePath()
185 {
186 return storePath;
187 }
188
189 public void setStorePath(String storePath)
190 {
191 if (storePath == null)
192 {
193 this.storePath = DEFAULT_STORE_PATH;
194 }
195 else if (storePath.endsWith("/"))
196 {
197 storePath = storePath.substring(0, storePath.length() - 1);
198 this.storePath = storePath;
199 }
200 else
201 {
202 this.storePath = storePath;
203 }
204 }
205
206 }