001    /*
002     * Copyright 2010 the original author or authors.
003     * 
004     *  Licensed under the Apache License, Version 2.0 (the "License");
005     *  you may not use this file except in compliance with the License.
006     *  You may obtain a copy of the License at
007     *
008     *      http://www.apache.org/licenses/LICENSE-2.0
009     *
010     *  Unless required by applicable law or agreed to in writing, software
011     *  distributed under the License is distributed on an "AS IS" BASIS,
012     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     *  See the License for the specific language governing permissions and
014     *  limitations under the License.
015     */
016    package com.hs.mail.smtp.message;
017    
018    import java.io.BufferedInputStream;
019    import java.io.BufferedOutputStream;
020    import java.io.File;
021    import java.io.FileInputStream;
022    import java.io.FileNotFoundException;
023    import java.io.FileOutputStream;
024    import java.io.IOException;
025    import java.io.InputStream;
026    import java.io.ObjectInputStream;
027    import java.io.ObjectOutputStream;
028    import java.io.OutputStream;
029    import java.io.Serializable;
030    import java.text.DateFormat;
031    import java.util.Date;
032    import java.util.Set;
033    import java.util.TreeSet;
034    
035    import javax.mail.MessagingException;
036    import javax.mail.Session;
037    import javax.mail.internet.MailDateFormat;
038    import javax.mail.internet.MimeMessage;
039    
040    import org.apache.commons.io.IOUtils;
041    
042    import com.hs.mail.container.config.Config;
043    import com.hs.mail.imap.message.MailMessage;
044    import com.hs.mail.smtp.SmtpException;
045    
046    /**
047     * 
048     * @author Won Chul Doh
049     * @since May 31, 2010
050     *
051     */
052    public class SmtpMessage implements Serializable {
053    
054            private static final long serialVersionUID = 7983042396136261548L;
055        private static final DateFormat SMTP_DATE_FORMAT = new MailDateFormat();
056    
057            public static final int LOCAL = 1;
058            public static final int REMOTE = 2;
059            public static final int ALL = 3;
060            
061            /**
062         * The number of mails generated.  Access needs to be synchronized for
063         * thread safety and to ensure that all threads see the latest value.
064         */
065        private static long count;
066            
067            private String name;
068            
069            private int node;
070            /**
071             * The sender of this message.
072             */
073            private MailAddress from;
074            /**
075             * The remained recipients of this message. 
076             */
077            private Set<Recipient> recipients;
078            /**
079             * The retry count.
080             */
081            private int retryCount = 0;
082            /**
083             * The last time this message was updated.
084             */
085            private Date lastUpdate = new Date();
086            /**
087             * The error message, if any, associated with this mail.
088             */
089            private transient String errorMessage = "";
090            /**
091             * The MailMessage that holds the mail data.
092             */
093            private transient MailMessage mailMessage = null;
094            /**
095             * The time this message was created. 
096             */
097            private transient long time;
098    
099            public SmtpMessage(MailAddress from, int node) {
100                    this.time = System.currentTimeMillis();
101                    this.from = from;
102                    this.recipients = new TreeSet<Recipient>();
103                    this.name = getId();
104                    this.node = node;
105                    this.errorMessage = "";
106            }
107            
108            public SmtpMessage(MailAddress from) {
109                    this(from, ALL);
110            }
111            
112            public String getName() {
113                    return name;
114            }
115    
116            public int getNode() {
117                    return node;
118            }
119    
120            public void setNode(int node) {
121                    this.node = node;
122            }
123    
124            public MailAddress getFrom() {
125                    return from;
126            }
127            
128            public Set<Recipient> getRecipients() {
129                    return recipients;
130            }
131    
132            public void addRecipient(Recipient recipient) {
133                    recipients.add(recipient);
134            }
135            
136            public int getRecipientsSize() {
137                    return recipients.size();
138            }
139            
140            public long getTime() {
141                    return time;
142            }
143    
144            public int getRetryCount() {
145                    return retryCount;
146            }
147            
148            public void setRetryCount(int retryCount) {
149                    this.retryCount = retryCount;
150            }
151    
152            public String getDate() {
153                    return SMTP_DATE_FORMAT.format(new Date(time));
154            }
155            
156            public Date getLastUpdate() {
157                    return lastUpdate;
158            }
159    
160            public void setLastUpdate(Date lastUpdate) {
161                    this.lastUpdate = lastUpdate;
162            }
163    
164            public String getErrorMessage() {
165                    return errorMessage;
166            }
167            
168            public boolean isNotificationMessage() {
169                    return "".equals(getFrom().getMailbox());
170            }
171    
172            public void appendErrorMessage(String errorMessage) {
173                    if (this.errorMessage == null)
174                            this.errorMessage  = errorMessage;
175                    else
176                            this.errorMessage += errorMessage;
177            }
178    
179            public File getDataFile() {
180                    return new File(Config.getSpoolDirectory(), getName());
181            }
182            
183            private File getControlFile() {
184                    return new File(Config.getSpoolDirectory(), getName() + ".control");
185            }
186            
187            public void setContent(InputStream is) throws IOException {
188                    OutputStream os = null;
189                    try {
190                            os = new FileOutputStream(getDataFile());
191                            IOUtils.copyLarge(is, os);
192                    } finally {
193                            IOUtils.closeQuietly(os);
194                    }
195            }
196            
197            public void setContent(MimeMessage msg) throws IOException,
198                            MessagingException {
199                    OutputStream os = null;
200                    try {
201                            os = new BufferedOutputStream(new FileOutputStream(getDataFile()));
202                            msg.writeTo(os);
203                    } finally {
204                            IOUtils.closeQuietly(os);
205                    }
206            }
207    
208            public void store() throws IOException {
209                    File file = getControlFile();
210                    ObjectOutputStream os = null;
211                    try {
212                            OutputStream out = new BufferedOutputStream(new FileOutputStream(
213                                            file), 1024 * 4);
214                            os = new ObjectOutputStream(out);
215                            os.writeObject(this);
216                            os.flush();
217                    } finally {
218                            IOUtils.closeQuietly(os);
219                    }
220            }
221            
222            public void createTrigger() throws IOException {
223                    File file = new File(Config.getSnapshotDirectory(), getName());
224                    file.createNewFile();
225            }
226            
227            public MailMessage getMailMessage() throws IOException {
228                    if (mailMessage == null) {
229                            mailMessage = MailMessage.createMailMessage(getDataFile());
230                    }
231                    return mailMessage;
232            }
233    
234            public MimeMessage getMimeMessage() throws MessagingException {
235                    Session session = Session.getInstance(System.getProperties(), null);
236                    InputStream is = null;
237                    try {
238                            is = new FileInputStream(getDataFile());
239                            return new MimeMessage(session, is);
240                    } catch (FileNotFoundException e) {
241                            throw new MessagingException(e.getMessage(), e);
242                    } finally {
243                            IOUtils.closeQuietly(is);
244                    }
245            }
246    
247            public void dispose() {
248                    File file = getDataFile();
249                    if (file.exists()) {
250                            if (file.delete()) {
251                                    file = getControlFile();
252                                    if (file.exists()) {
253                                            file.delete();
254                                    }
255                            }
256                    }
257            }
258            
259            private String getId() {
260                    File d = Config.getSpoolDirectory(); 
261                    File f;
262                    String id;
263                    do {
264                            f = new File(d, (id = _getId()));
265                    } while (f.exists());
266                    return id;
267            }
268            
269            private String _getId() {
270                    long localCount = -1;
271                    synchronized (SmtpMessage.class) {
272                            localCount = count++;
273                    }
274                    return new StringBuffer(64)
275                                    .append(time)
276                                    .append("-")
277                                    .append(localCount)
278                                    .toString();
279            }
280            
281            public static SmtpMessage readMessage(String name) throws SmtpException {
282                    File dir = Config.getSpoolDirectory();
283                    File file = new File(dir, name + ".control");
284                    ObjectInputStream is = null;
285                    try {
286                            InputStream in = new BufferedInputStream(new FileInputStream(file),
287                                            1024);
288                            is = new ObjectInputStream(in);
289                            SmtpMessage message = (SmtpMessage) is.readObject();
290                            return message;
291                    } catch (Exception e) {
292                            throw new SmtpException("Error while reading message file: " + file);
293                    } finally {
294                            IOUtils.closeQuietly(is);
295                    }
296            }
297    
298    }