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 }