1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.james.mailrepository.javamail;
21
22 import java.util.ArrayList;
23 import java.util.Arrays;
24 import java.util.Collection;
25 import java.util.HashMap;
26 import java.util.HashSet;
27 import java.util.Iterator;
28 import java.util.Map;
29 import java.util.NoSuchElementException;
30
31 import javax.mail.Flags;
32 import javax.mail.Folder;
33 import javax.mail.Message;
34 import javax.mail.MessagingException;
35 import javax.mail.UIDFolder;
36 import javax.mail.Flags.Flag;
37 import javax.mail.internet.MimeMessage;
38
39 import org.apache.james.core.MailImpl;
40 import org.apache.mailet.Mail;
41
42
43
44
45
46
47
48
49
50 public class UIDPlusFolderMailRepository extends
51 AbstractJavamailStoreMailRepository {
52
53
54
55
56 private UidToKeyBidiMap uidToKeyBidiMap = null;
57
58 public static final int DELIVERY_MODE_CLOSED = 0;
59 public static final int DELIVERY_MODE_TRY = 1;
60 public static final int DELIVERY_MODE_OPEN = 2;
61
62 private int deliveryMode=DELIVERY_MODE_TRY;
63
64 protected long addUIDMessage(Message message) throws MessagingException {
65 try {
66 getFolderGateKeeper().use();
67 long[] uids = null;
68 if (deliveryMode != DELIVERY_MODE_OPEN) {
69 try {
70 log.debug("Doing a addUIDMessages on maybe closed Folder: isopen="+getFolderGateKeeper().getFolder().isOpen());
71 uids = ((UIDPlusFolder) getFolderGateKeeper().getFolder())
72 .addUIDMessages(new Message[] { message });
73 } catch (IllegalStateException e) {
74 if (deliveryMode == DELIVERY_MODE_CLOSED) {
75 log.error("deliveryMode=DELIVERY_MODE_CLOSED",e);
76 throw e;
77 } else {
78 log.debug("switching to DELIVERY_MODE_OPEN",e);
79 deliveryMode = DELIVERY_MODE_OPEN;
80 }
81
82 }
83 }
84 if (deliveryMode == DELIVERY_MODE_OPEN) {
85 log.debug("Doing a addUIDMessages on a open Folder");
86 uids = ((UIDPlusFolder) getFolderGateKeeper().getOpenFolder())
87 .addUIDMessages(new Message[] { message });
88 }
89 if (uids == null || uids.length != 1) {
90 throw new RuntimeException(
91 "Fatal error while storing Message Container: Message was not Appendet");
92 }
93 return uids[0];
94 } finally {
95 getFolderGateKeeper().free();
96 }
97
98 }
99
100
101
102
103
104
105
106
107
108
109 public void store(Mail mc) throws MessagingException {
110
111 log.debug("UIDPlusFolder store key:" + mc.getName());
112 if (!mc.getMessage().isSet(Flag.RECENT)) {
113 log.debug("Message didn't have RECENT flag");
114 mc.getMessage().setFlag(Flag.RECENT,true);
115 }
116 String key = mc.getName();
117 boolean wasLocked = true;
118 try {
119 getFolderGateKeeper().use();
120 MimeMessage message = mc.getMessage();
121 synchronized (this) {
122 wasLocked = getLock().isLocked(key);
123 if (!wasLocked) {
124
125 lock(key);
126 }
127 }
128
129
130 if (getUidToKeyBidiMap().containsKey(key)) {
131
132 Message mm = getMessageFromInbox(key,
133 (UIDFolder) getFolderGateKeeper().getOpenFolder());
134 if (mm != null) {
135 mm.setFlag(Flags.Flag.DELETED, true);
136 message.setFlag(Flags.Flag.RECENT, false);
137 }
138 }
139 long uid = addUIDMessage(message);
140 getUidToKeyBidiMap().put(key, uid);
141
142 log.info("message stored: UID: " + uid + " Key:" + mc.getName());
143 } finally {
144 getFolderGateKeeper().free();
145 if (!wasLocked) {
146
147 unlock(key);
148 synchronized (this) {
149 notify();
150 }
151 }
152
153 }
154 }
155
156
157
158
159 protected UidToKeyBidiMap getUidToKeyBidiMap() {
160 if (uidToKeyBidiMap == null) {
161 uidToKeyBidiMap = new UidToKeyBidiMapImpl();
162 }
163 return uidToKeyBidiMap;
164 }
165
166
167
168
169
170
171 void setUidToKeyBidiMap(UidToKeyBidiMap uidToKeyBidiMap) {
172 this.uidToKeyBidiMap = uidToKeyBidiMap;
173 }
174
175
176
177
178
179
180
181
182
183
184
185 public Mail retrieve(String key) throws MessagingException {
186 log.debug("UIDPlusFolder retrieve " + key);
187 try {
188 getFolderGateKeeper().use();
189 MimeMessage mm = getMessageFromInbox(key,
190 (UIDFolder) getFolderGateKeeper().getOpenFolder());
191 if (mm == null)
192 return null;
193 Mail mail = new MailImpl();
194 mail.setMessage(mm);
195 mail.setName(key);
196 return mail;
197 } finally {
198 getFolderGateKeeper().free();
199 }
200 }
201
202
203
204
205
206
207
208 public void remove(String key) throws MessagingException {
209
210 log.debug("UIDFolder remove key:" + key);
211 if (lock(key)) {
212 getFolderGateKeeper().use();
213 try {
214 Message mm = getMessageFromInbox(key,
215 (UIDFolder) getFolderGateKeeper().getOpenFolder());
216 if (mm != null) {
217 mm.setFlag(Flags.Flag.DELETED, true);
218 }
219 getUidToKeyBidiMap().removeByKey(key);
220 } finally {
221 unlock(key);
222 getFolderGateKeeper().free();
223 }
224 } else {
225 log.debug("could not optain lock");
226 throw new MessagingException("could not optain lock for remove");
227 }
228 }
229
230
231
232
233
234
235
236
237
238 public Iterator list() throws MessagingException {
239 log.debug("UIDPlusFolder list");
240 try {
241 getFolderGateKeeper().use();
242
243 String[] keysBefore = getUidToKeyBidiMap().getKeys();
244
245 Message[] msgs = getFolderGateKeeper().getOpenFolder().getMessages();
246 Collection keys = new ArrayList(msgs.length);
247 if (msgs == null)
248 throw new RuntimeException("inbox.getMessages returned null");
249 for (int i = 0; i < msgs.length; i++) {
250 try {
251 long uidvalidity = ((UIDFolder) getFolderGateKeeper().getOpenFolder()).getUIDValidity();
252
253 long uid = ((UIDFolder) getFolderGateKeeper().getOpenFolder()).getUID(msgs[i]);
254 String key = getUidToKeyBidiMap().getByUid(uid);
255 if (key == null) {
256
257 key = "james-uid:" + uidvalidity + ";" + uid + ";"
258 + System.currentTimeMillis() + ";"
259 + getRandom().nextLong();
260 getUidToKeyBidiMap().put(key, uid);
261 }
262 keys.add(key);
263 log.info("list: UID: " + uid + " Key:" + key);
264 } catch (NoSuchElementException e) {
265
266
267 }
268 }
269
270
271
272
273
274 getUidToKeyBidiMap()
275 .retainAllListedAndAddedByKeys(keysBefore, keys);
276 return keys.iterator();
277 } catch (MessagingException e) {
278 throw new RuntimeException(e);
279 } finally {
280 getFolderGateKeeper().free();
281 }
282 }
283
284 private MimeMessage getMessageFromInbox(String key, UIDFolder inbox)
285 throws MessagingException {
286
287 long uid = getUidToKeyBidiMap().getByKey(key);
288 if (uid < 0) {
289 return null;
290 }
291
292 MimeMessage mm = (MimeMessage) inbox.getMessageByUID(uid);
293 log.info("getMessageFromInbox: UID: " + uid + " Key:" + key);
294 if (mm == null) {
295 getUidToKeyBidiMap().removeByKey(key);
296 log.info("Message not Found");
297 }
298 return mm;
299 }
300
301
302
303
304
305 private class UidToKeyBidiMapImpl implements UidToKeyBidiMap {
306
307 private Map keyToUid;
308
309 private Map uidToKey;
310
311 public UidToKeyBidiMapImpl() {
312 keyToUid = new HashMap();
313 uidToKey = new HashMap();
314 }
315
316 public synchronized String[] getKeys() {
317 final ArrayList al = new ArrayList(keyToUid.keySet());
318 final String[] keys = (String[]) al.toArray(new String[0]);
319 return keys;
320 }
321
322 public synchronized void retainAllListedAndAddedByKeys(
323 final String[] before, final Collection listed) {
324 Collection added = new HashSet(keyToUid.keySet());
325 added.removeAll(Arrays.asList(before));
326 Collection retain = new HashSet(listed);
327 retain.addAll(added);
328 keyToUid.keySet().retainAll(retain);
329 uidToKey.keySet().retainAll(keyToUid.values());
330 }
331
332 public synchronized void removeByKey(String key) {
333 long uid = getByKey(key);
334 if (uid > -1) {
335 uidToKey.remove(new Long(uid));
336 }
337 keyToUid.remove(key);
338 }
339
340 public synchronized long getByKey(String key) {
341 Long lo = (Long) keyToUid.get(key);
342 long l = -1;
343 if (lo != null) {
344 l = lo.longValue();
345 }
346 return l;
347 }
348
349 public synchronized String getByUid(long uid) {
350
351 return (String) uidToKey.get(new Long(uid));
352 }
353
354 public synchronized boolean containsKey(String key) {
355 return keyToUid.containsKey(key);
356 }
357
358 public synchronized void put(String key, long uid) {
359 keyToUid.put(key, new Long(uid));
360 uidToKey.put(new Long(uid), key);
361 }
362
363 }
364
365
366
367
368
369
370 public FolderInterface createAdapter(Folder folder) {
371 return new UIDPlusFolderAdapter(folder);
372 }
373
374
375 }