001: /****************************************************************
002: * Licensed to the Apache Software Foundation (ASF) under one *
003: * or more contributor license agreements. See the NOTICE file *
004: * distributed with this work for additional information *
005: * regarding copyright ownership. The ASF licenses this file *
006: * to you under the Apache License, Version 2.0 (the *
007: * "License"); you may not use this file except in compliance *
008: * with the License. You may obtain a copy of the License at *
009: * *
010: * http://www.apache.org/licenses/LICENSE-2.0 *
011: * *
012: * Unless required by applicable law or agreed to in writing, *
013: * software distributed under the License is distributed on an *
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
015: * KIND, either express or implied. See the License for the *
016: * specific language governing permissions and limitations *
017: * under the License. *
018: ****************************************************************/package org.apache.james.core;
019:
020: import org.apache.avalon.framework.activity.Disposable;
021: import org.apache.avalon.framework.container.ContainerUtil;
022:
023: import javax.activation.DataHandler;
024: import javax.mail.Address;
025: import javax.mail.Flags;
026: import javax.mail.Folder;
027: import javax.mail.Message;
028: import javax.mail.MessagingException;
029: import javax.mail.Multipart;
030: import javax.mail.Session;
031: import javax.mail.Flags.Flag;
032: import javax.mail.internet.MimeMessage;
033: import javax.mail.search.SearchTerm;
034:
035: import java.io.IOException;
036: import java.io.InputStream;
037: import java.io.OutputStream;
038: import java.util.Date;
039: import java.util.Enumeration;
040:
041: /**
042: * This object wraps a "possibly shared" MimeMessage tracking copies and
043: * automatically cloning it (if shared) when a write operation is invoked.
044: */
045: public class MimeMessageCopyOnWriteProxy extends MimeMessage implements
046: Disposable {
047:
048: /**
049: * Used internally to track the reference count
050: * It is important that this is static otherwise it will keep a reference to
051: * the parent object.
052: */
053: protected static class MessageReferenceTracker {
054:
055: /**
056: * reference counter
057: */
058: private int referenceCount = 1;
059:
060: /**
061: * The mime message in memory
062: */
063: private MimeMessage wrapped = null;
064:
065: public MessageReferenceTracker(MimeMessage ref) {
066: wrapped = ref;
067: }
068:
069: protected synchronized void incrementReferenceCount() {
070: referenceCount++;
071: }
072:
073: protected synchronized void decrementReferenceCount() {
074: referenceCount--;
075: if (referenceCount <= 0) {
076: ContainerUtil.dispose(wrapped);
077: wrapped = null;
078: }
079: }
080:
081: protected synchronized int getReferenceCount() {
082: return referenceCount;
083: }
084:
085: public MimeMessage getWrapped() {
086: return wrapped;
087: }
088:
089: }
090:
091: protected MessageReferenceTracker refCount;
092:
093: /**
094: * @param original
095: * MimeMessageWrapper
096: * @throws MessagingException
097: */
098: public MimeMessageCopyOnWriteProxy(MimeMessage original)
099: throws MessagingException {
100: this (original, false);
101: }
102:
103: /**
104: * @param original
105: * MimeMessageSource
106: * @throws MessagingException
107: */
108: public MimeMessageCopyOnWriteProxy(MimeMessageSource original)
109: throws MessagingException {
110: this (new MimeMessageWrapper(original), true);
111: }
112:
113: /**
114: * Private constructor providing an external reference counter.
115: *
116: * @param original
117: * @param refCount
118: * @throws MessagingException
119: */
120: private MimeMessageCopyOnWriteProxy(MimeMessage original,
121: boolean writeable) throws MessagingException {
122: super (Session.getDefaultInstance(System.getProperties(), null));
123:
124: if (original instanceof MimeMessageCopyOnWriteProxy) {
125: refCount = ((MimeMessageCopyOnWriteProxy) original).refCount;
126: } else {
127: refCount = new MessageReferenceTracker(original);
128: }
129:
130: if (!writeable) {
131: refCount.incrementReferenceCount();
132: }
133: }
134:
135: /**
136: * Check the number of references over the MimeMessage and clone it if
137: * needed before returning the reference
138: *
139: * @throws MessagingException
140: * exception
141: */
142: protected MimeMessage getWrappedMessageForWriting()
143: throws MessagingException {
144: synchronized (refCount) {
145: if (refCount.getReferenceCount() > 1) {
146: refCount.decrementReferenceCount();
147: refCount = new MessageReferenceTracker(
148: new MimeMessageWrapper(refCount.getWrapped()));
149: }
150: }
151: return refCount.getWrapped();
152: }
153:
154: /**
155: * @return
156: */
157: public MimeMessage getWrappedMessage() {
158: return refCount.getWrapped();
159: }
160:
161: /**
162: * @see org.apache.avalon.framework.activity.Disposable#dispose()
163: */
164: public synchronized void dispose() {
165: if (refCount != null) {
166: refCount.decrementReferenceCount();
167: refCount = null;
168: }
169: }
170:
171: /**
172: * Rewritten for optimization purposes
173: */
174: public void writeTo(OutputStream os) throws IOException,
175: MessagingException {
176: getWrappedMessage().writeTo(os);
177: }
178:
179: /**
180: * Rewritten for optimization purposes
181: */
182: public void writeTo(OutputStream os, String[] ignoreList)
183: throws IOException, MessagingException {
184: getWrappedMessage().writeTo(os, ignoreList);
185: }
186:
187: /**
188: * Various reader methods
189: */
190:
191: /**
192: * @see javax.mail.Message#getFrom()
193: */
194: public Address[] getFrom() throws MessagingException {
195: return getWrappedMessage().getFrom();
196: }
197:
198: /**
199: * @see javax.mail.Message#getRecipients(javax.mail.Message.RecipientType)
200: */
201: public Address[] getRecipients(Message.RecipientType type)
202: throws MessagingException {
203: return getWrappedMessage().getRecipients(type);
204: }
205:
206: /**
207: * @see javax.mail.Message#getAllRecipients()
208: */
209: public Address[] getAllRecipients() throws MessagingException {
210: return getWrappedMessage().getAllRecipients();
211: }
212:
213: /**
214: * @see javax.mail.Message#getReplyTo()
215: */
216: public Address[] getReplyTo() throws MessagingException {
217: return getWrappedMessage().getReplyTo();
218: }
219:
220: /**
221: * @see javax.mail.Message#getSubject()
222: */
223: public String getSubject() throws MessagingException {
224: return getWrappedMessage().getSubject();
225: }
226:
227: /**
228: * @see javax.mail.Message#getSentDate()
229: */
230: public Date getSentDate() throws MessagingException {
231: return getWrappedMessage().getSentDate();
232: }
233:
234: /**
235: * @see javax.mail.Message#getReceivedDate()
236: */
237: public Date getReceivedDate() throws MessagingException {
238: return getWrappedMessage().getReceivedDate();
239: }
240:
241: /**
242: * @see javax.mail.Part#getSize()
243: */
244: public int getSize() throws MessagingException {
245: return getWrappedMessage().getSize();
246: }
247:
248: /**
249: * @see javax.mail.Part#getLineCount()
250: */
251: public int getLineCount() throws MessagingException {
252: return getWrappedMessage().getLineCount();
253: }
254:
255: /**
256: * @see javax.mail.Part#getContentType()
257: */
258: public String getContentType() throws MessagingException {
259: return getWrappedMessage().getContentType();
260: }
261:
262: /**
263: * @see javax.mail.Part#isMimeType(java.lang.String)
264: */
265: public boolean isMimeType(String mimeType)
266: throws MessagingException {
267: return getWrappedMessage().isMimeType(mimeType);
268: }
269:
270: /**
271: * @see javax.mail.Part#getDisposition()
272: */
273: public String getDisposition() throws MessagingException {
274: return getWrappedMessage().getDisposition();
275: }
276:
277: /**
278: * @see javax.mail.internet.MimePart#getEncoding()
279: */
280: public String getEncoding() throws MessagingException {
281: return getWrappedMessage().getEncoding();
282: }
283:
284: /**
285: * @see javax.mail.internet.MimePart#getContentID()
286: */
287: public String getContentID() throws MessagingException {
288: return getWrappedMessage().getContentID();
289: }
290:
291: /**
292: * @see javax.mail.internet.MimePart#getContentMD5()
293: */
294: public String getContentMD5() throws MessagingException {
295: return getWrappedMessage().getContentMD5();
296: }
297:
298: /**
299: * @see javax.mail.Part#getDescription()
300: */
301: public String getDescription() throws MessagingException {
302: return getWrappedMessage().getDescription();
303: }
304:
305: /**
306: * @see javax.mail.internet.MimePart#getContentLanguage()
307: */
308: public String[] getContentLanguage() throws MessagingException {
309: return getWrappedMessage().getContentLanguage();
310: }
311:
312: /**
313: * @see javax.mail.internet.MimeMessage#getMessageID()
314: */
315: public String getMessageID() throws MessagingException {
316: return getWrappedMessage().getMessageID();
317: }
318:
319: /**
320: * @see javax.mail.Part#getFileName()
321: */
322: public String getFileName() throws MessagingException {
323: return getWrappedMessage().getFileName();
324: }
325:
326: /**
327: * @see javax.mail.Part#getInputStream()
328: */
329: public InputStream getInputStream() throws IOException,
330: MessagingException {
331: return getWrappedMessage().getInputStream();
332: }
333:
334: /**
335: * @see javax.mail.Part#getDataHandler()
336: */
337: public DataHandler getDataHandler() throws MessagingException {
338: return getWrappedMessage().getDataHandler();
339: }
340:
341: /**
342: * @see javax.mail.Part#getContent()
343: */
344: public Object getContent() throws IOException, MessagingException {
345: return getWrappedMessage().getContent();
346: }
347:
348: /**
349: * @see javax.mail.Part#getHeader(java.lang.String)
350: */
351: public String[] getHeader(String name) throws MessagingException {
352: return getWrappedMessage().getHeader(name);
353: }
354:
355: /**
356: * @see javax.mail.internet.MimePart#getHeader(java.lang.String, java.lang.String)
357: */
358: public String getHeader(String name, String delimiter)
359: throws MessagingException {
360: return getWrappedMessage().getHeader(name, delimiter);
361: }
362:
363: /**
364: * @see javax.mail.Part#getAllHeaders()
365: */
366: public Enumeration getAllHeaders() throws MessagingException {
367: return getWrappedMessage().getAllHeaders();
368: }
369:
370: /**
371: * @see javax.mail.Part#getMatchingHeaders(java.lang.String[])
372: */
373: public Enumeration getMatchingHeaders(String[] names)
374: throws MessagingException {
375: return getWrappedMessage().getMatchingHeaders(names);
376: }
377:
378: /**
379: * @see javax.mail.Part#getNonMatchingHeaders(java.lang.String[])
380: */
381: public Enumeration getNonMatchingHeaders(String[] names)
382: throws MessagingException {
383: return getWrappedMessage().getNonMatchingHeaders(names);
384: }
385:
386: /**
387: * @see javax.mail.internet.MimePart#getAllHeaderLines()
388: */
389: public Enumeration getAllHeaderLines() throws MessagingException {
390: return getWrappedMessage().getAllHeaderLines();
391: }
392:
393: /**
394: * @see javax.mail.internet.MimePart#getMatchingHeaderLines(java.lang.String[])
395: */
396: public Enumeration getMatchingHeaderLines(String[] names)
397: throws MessagingException {
398: return getWrappedMessage().getMatchingHeaderLines(names);
399: }
400:
401: /**
402: * @see javax.mail.internet.MimePart#getNonMatchingHeaderLines(java.lang.String[])
403: */
404: public Enumeration getNonMatchingHeaderLines(String[] names)
405: throws MessagingException {
406: return getWrappedMessage().getNonMatchingHeaderLines(names);
407: }
408:
409: /**
410: * @see javax.mail.Message#getFlags()
411: */
412: public Flags getFlags() throws MessagingException {
413: return getWrappedMessage().getFlags();
414: }
415:
416: /**
417: * @see javax.mail.Message#isSet(javax.mail.Flags.Flag)
418: */
419: public boolean isSet(Flags.Flag flag) throws MessagingException {
420: return getWrappedMessage().isSet(flag);
421: }
422:
423: /**
424: * @see javax.mail.internet.MimeMessage#getSender()
425: */
426: public Address getSender() throws MessagingException {
427: return getWrappedMessage().getSender();
428: }
429:
430: /**
431: * @see javax.mail.Message#match(javax.mail.search.SearchTerm)
432: */
433: public boolean match(SearchTerm arg0) throws MessagingException {
434: return getWrappedMessage().match(arg0);
435: }
436:
437: /**
438: * @see javax.mail.internet.MimeMessage#getRawInputStream()
439: */
440: public InputStream getRawInputStream() throws MessagingException {
441: return getWrappedMessage().getRawInputStream();
442: }
443:
444: /**
445: * @see javax.mail.Message#getFolder()
446: */
447: public Folder getFolder() {
448: return getWrappedMessage().getFolder();
449: }
450:
451: /**
452: * @see javax.mail.Message#getMessageNumber()
453: */
454: public int getMessageNumber() {
455: return getWrappedMessage().getMessageNumber();
456: }
457:
458: /**
459: * @see javax.mail.Message#isExpunged()
460: */
461: public boolean isExpunged() {
462: return getWrappedMessage().isExpunged();
463: }
464:
465: /**
466: * @see java.lang.Object#equals(java.lang.Object)
467: */
468: public boolean equals(Object arg0) {
469: return getWrappedMessage().equals(arg0);
470: }
471:
472: /**
473: * @see java.lang.Object#hashCode()
474: */
475: public int hashCode() {
476: return getWrappedMessage().hashCode();
477: }
478:
479: /**
480: * @see java.lang.Object#toString()
481: */
482: public String toString() {
483: return getWrappedMessage().toString();
484: }
485:
486: /*
487: * Various writer methods
488: */
489:
490: /**
491: * @see javax.mail.Message#setFrom(javax.mail.Address)
492: */
493: public void setFrom(Address address) throws MessagingException {
494: getWrappedMessageForWriting().setFrom(address);
495: }
496:
497: /**
498: * @see javax.mail.Message#setFrom()
499: */
500: public void setFrom() throws MessagingException {
501: getWrappedMessageForWriting().setFrom();
502: }
503:
504: /**
505: * @see javax.mail.Message#addFrom(javax.mail.Address[])
506: */
507: public void addFrom(Address[] addresses) throws MessagingException {
508: getWrappedMessageForWriting().addFrom(addresses);
509: }
510:
511: /**
512: * @see javax.mail.Message#setRecipients(javax.mail.Message.RecipientType, javax.mail.Address[])
513: */
514: public void setRecipients(Message.RecipientType type,
515: Address[] addresses) throws MessagingException {
516: getWrappedMessageForWriting().setRecipients(type, addresses);
517: }
518:
519: /**
520: * @see javax.mail.Message#addRecipients(javax.mail.Message.RecipientType, javax.mail.Address[])
521: */
522: public void addRecipients(Message.RecipientType type,
523: Address[] addresses) throws MessagingException {
524: getWrappedMessageForWriting().addRecipients(type, addresses);
525: }
526:
527: /**
528: * @see javax.mail.Message#setReplyTo(javax.mail.Address[])
529: */
530: public void setReplyTo(Address[] addresses)
531: throws MessagingException {
532: getWrappedMessageForWriting().setReplyTo(addresses);
533: }
534:
535: /**
536: * @see javax.mail.Message#setSubject(java.lang.String)
537: */
538: public void setSubject(String subject) throws MessagingException {
539: getWrappedMessageForWriting().setSubject(subject);
540: }
541:
542: /**
543: * @see javax.mail.internet.MimeMessage#setSubject(java.lang.String, java.lang.String)
544: */
545: public void setSubject(String subject, String charset)
546: throws MessagingException {
547: getWrappedMessageForWriting().setSubject(subject, charset);
548: }
549:
550: /**
551: * @see javax.mail.Message#setSentDate(java.util.Date)
552: */
553: public void setSentDate(Date d) throws MessagingException {
554: getWrappedMessageForWriting().setSentDate(d);
555: }
556:
557: /**
558: * @see javax.mail.Part#setDisposition(java.lang.String)
559: */
560: public void setDisposition(String disposition)
561: throws MessagingException {
562: getWrappedMessageForWriting().setDisposition(disposition);
563: }
564:
565: /**
566: * @see javax.mail.internet.MimeMessage#setContentID(java.lang.String)
567: */
568: public void setContentID(String cid) throws MessagingException {
569: getWrappedMessageForWriting().setContentID(cid);
570: }
571:
572: /**
573: * @see javax.mail.internet.MimePart#setContentMD5(java.lang.String)
574: */
575: public void setContentMD5(String md5) throws MessagingException {
576: getWrappedMessageForWriting().setContentMD5(md5);
577: }
578:
579: /**
580: * @see javax.mail.Part#setDescription(java.lang.String)
581: */
582: public void setDescription(String description)
583: throws MessagingException {
584: getWrappedMessageForWriting().setDescription(description);
585: }
586:
587: /**
588: * @see javax.mail.internet.MimeMessage#setDescription(java.lang.String, java.lang.String)
589: */
590: public void setDescription(String description, String charset)
591: throws MessagingException {
592: getWrappedMessageForWriting().setDescription(description,
593: charset);
594: }
595:
596: /**
597: * @see javax.mail.internet.MimePart#setContentLanguage(java.lang.String[])
598: */
599: public void setContentLanguage(String[] languages)
600: throws MessagingException {
601: getWrappedMessageForWriting().setContentLanguage(languages);
602: }
603:
604: /**
605: * @see javax.mail.Part#setFileName(java.lang.String)
606: */
607: public void setFileName(String filename) throws MessagingException {
608: getWrappedMessageForWriting().setFileName(filename);
609: }
610:
611: /**
612: * @see javax.mail.Part#setDataHandler(javax.activation.DataHandler)
613: */
614: public void setDataHandler(DataHandler dh)
615: throws MessagingException {
616: getWrappedMessageForWriting().setDataHandler(dh);
617: }
618:
619: /**
620: * @see javax.mail.Part#setContent(java.lang.Object, java.lang.String)
621: */
622: public void setContent(Object o, String type)
623: throws MessagingException {
624: getWrappedMessageForWriting().setContent(o, type);
625: }
626:
627: /**
628: * @see javax.mail.Part#setText(java.lang.String)
629: */
630: public void setText(String text) throws MessagingException {
631: getWrappedMessageForWriting().setText(text);
632: }
633:
634: /**
635: * @see javax.mail.internet.MimePart#setText(java.lang.String, java.lang.String)
636: */
637: public void setText(String text, String charset)
638: throws MessagingException {
639: getWrappedMessageForWriting().setText(text, charset);
640: }
641:
642: /**
643: * @see javax.mail.Part#setContent(javax.mail.Multipart)
644: */
645: public void setContent(Multipart mp) throws MessagingException {
646: getWrappedMessageForWriting().setContent(mp);
647: }
648:
649: /**
650: * This does not need a writable message
651: * @see javax.mail.Message#reply(boolean)
652: */
653: public Message reply(boolean replyToAll) throws MessagingException {
654: return getWrappedMessage().reply(replyToAll);
655: }
656:
657: /**
658: * @see javax.mail.Part#setHeader(java.lang.String, java.lang.String)
659: */
660: public void setHeader(String name, String value)
661: throws MessagingException {
662: getWrappedMessageForWriting().setHeader(name, value);
663: }
664:
665: /**
666: * @see javax.mail.Part#addHeader(java.lang.String, java.lang.String)
667: */
668: public void addHeader(String name, String value)
669: throws MessagingException {
670: getWrappedMessageForWriting().addHeader(name, value);
671: }
672:
673: /**
674: * @see javax.mail.Part#removeHeader(java.lang.String)
675: */
676: public void removeHeader(String name) throws MessagingException {
677: getWrappedMessageForWriting().removeHeader(name);
678: }
679:
680: /**
681: * @see javax.mail.internet.MimePart#addHeaderLine(java.lang.String)
682: */
683: public void addHeaderLine(String line) throws MessagingException {
684: getWrappedMessageForWriting().addHeaderLine(line);
685: }
686:
687: /**
688: * @see javax.mail.Message#setFlags(javax.mail.Flags, boolean)
689: */
690: public void setFlags(Flags flag, boolean set)
691: throws MessagingException {
692: getWrappedMessageForWriting().setFlags(flag, set);
693: }
694:
695: /**
696: * @see javax.mail.Message#saveChanges()
697: */
698: public void saveChanges() throws MessagingException {
699: getWrappedMessageForWriting().saveChanges();
700: }
701:
702: /*
703: * Since JavaMail 1.2
704: */
705:
706: /**
707: * @see javax.mail.internet.MimeMessage#addRecipients(javax.mail.Message.RecipientType, java.lang.String)
708: */
709: public void addRecipients(Message.RecipientType type,
710: String addresses) throws MessagingException {
711: getWrappedMessageForWriting().addRecipients(type, addresses);
712: }
713:
714: /**
715: * @see javax.mail.internet.MimeMessage#setRecipients(javax.mail.Message.RecipientType, java.lang.String)
716: */
717: public void setRecipients(Message.RecipientType type,
718: String addresses) throws MessagingException {
719: getWrappedMessageForWriting().setRecipients(type, addresses);
720: }
721:
722: /**
723: * @see javax.mail.internet.MimeMessage#setSender(javax.mail.Address)
724: */
725: public void setSender(Address arg0) throws MessagingException {
726: getWrappedMessageForWriting().setSender(arg0);
727: }
728:
729: /**
730: * @see javax.mail.Message#addRecipient(javax.mail.Message.RecipientType, javax.mail.Address)
731: */
732: public void addRecipient(RecipientType arg0, Address arg1)
733: throws MessagingException {
734: getWrappedMessageForWriting().addRecipient(arg0, arg1);
735: }
736:
737: /**
738: * @see javax.mail.Message#setFlag(javax.mail.Flags.Flag, boolean)
739: */
740: public void setFlag(Flag arg0, boolean arg1)
741: throws MessagingException {
742: getWrappedMessageForWriting().setFlag(arg0, arg1);
743: }
744:
745: /**
746: * @see java.lang.Object#finalize()
747: */
748: protected void finalize() throws Throwable {
749: dispose();
750: super .finalize();
751: }
752:
753: /**
754: * @return the message size
755: * @throws MessagingException
756: */
757: public long getMessageSize() throws MessagingException {
758: return MimeMessageUtil.getMessageSize(getWrappedMessage());
759: }
760:
761: }
|