View Javadoc

1   package com.ozacc.mail.fetch.impl;
2   
3   import java.util.Properties;
4   
5   import javax.mail.AuthenticationFailedException;
6   import javax.mail.Flags;
7   import javax.mail.Folder;
8   import javax.mail.Message;
9   import javax.mail.MessagingException;
10  import javax.mail.NoSuchProviderException;
11  import javax.mail.Session;
12  import javax.mail.Store;
13  import javax.mail.internet.MimeMessage;
14  
15  import org.apache.commons.logging.Log;
16  import org.apache.commons.logging.LogFactory;
17  
18  import com.ozacc.mail.MailAuthenticationException;
19  import com.ozacc.mail.MailException;
20  import com.ozacc.mail.NotConnectedException;
21  import com.ozacc.mail.fetch.FetchMailPro;
22  import com.ozacc.mail.fetch.MailFetchException;
23  import com.ozacc.mail.fetch.ReceivedMail;
24  
25  /***
26   * <code>FetchMail</code>インターフェースの実装クラス。
27   * <p>
28   * このクラスのインスタンスは、インスタンス変数を用いて状態を保持するため、
29   * ステートレスではありません。ステートフルです。
30   * 
31   * @since 1.2
32   * @author Tomohiro Otsuka
33   * @version $Id: FetchMailProImpl.java,v 1.1.2.11 2005/02/05 21:37:21 otsuka Exp $
34   */
35  public class FetchMailProImpl implements FetchMailPro {
36  
37  	private static Log log = LogFactory.getLog(FetchMailProImpl.class);
38  
39  	/*** デフォルトのSMTPサーバ。「localhost」 */
40  	public static final String DEFAULT_HOST = "localhost";
41  
42  	/*** デフォルトのプロトコル。「pop3」 */
43  	public static final String DEFAULT_PROTOCOL = "pop3";
44  
45  	/***
46  	 * デフォルトのポート。「-1」<br>
47  	 * -1はプロトコルに応じた適切なポートを設定する特別な値。
48  	 */
49  	public static final int DEFAULT_PORT = -1;
50  
51  	private static final String INBOX_NAME = "INBOX";
52  
53  	private String host = DEFAULT_HOST;
54  
55  	private String protocol = DEFAULT_PROTOCOL;
56  
57  	private int port = DEFAULT_PORT;
58  
59  	private String username;
60  
61  	private String password;
62  
63  	private boolean javaMailLogEnabled;
64  
65  	private Store store;
66  
67  	private Folder currentFolder;
68  
69  	/***
70  	 * コンストラクタ。
71  	 */
72  	public FetchMailProImpl() {
73  		System.setProperty("mail.mime.multipart.ignoremissingendboundary", "true");
74  	}
75  
76  	/***
77  	 * @see com.ozacc.mail.fetch.FetchMailPro#connect()
78  	 */
79  	public synchronized void connect() throws MailException {
80  		if (isConnected()) {
81  			log.warn("既にサーバ[" + host + "]に接続されています。再接続するには先に接続を切断する必要があります。");
82  			return;
83  		}
84  
85  		log.debug(protocol.toUpperCase() + "サーバ[" + host + "]に接続します。");
86  		Session session = Session.getInstance(createProperties(), null);
87  		if (javaMailLogEnabled) {
88  			session.setDebug(true);
89  		}
90  		try {
91  			store = session.getStore(protocol);
92  			store.connect(host, port, username, password);
93  		} catch (NoSuchProviderException e) {
94  			log.error("指定されたプロトコル[" + protocol + "]はサポートされていません。", e);
95  			throw new MailException("指定されたプロトコル[" + protocol + "]はサポートされていません。", e);
96  		} catch (AuthenticationFailedException e) {
97  			log.error(protocol.toUpperCase() + "サーバ[" + host + "]への接続認証に失敗しました。", e);
98  			throw new MailAuthenticationException(protocol.toUpperCase() + "サーバ[" + host
99  					+ "]への接続認証に失敗しました。", e);
100 		} catch (MessagingException e) {
101 			log.error(protocol.toUpperCase() + "サーバ[" + host + "]への接続に失敗しました。", e);
102 			throw new MailException(protocol.toUpperCase() + "サーバ[" + host + "]への接続に失敗しました。", e);
103 		}
104 		log.info(protocol.toUpperCase() + "サーバ[" + host + "]に接続しました。");
105 
106 		changeFolder(INBOX_NAME);
107 	}
108 
109 	/***
110 	 * Sessionに渡すPropertiesインスタンスを返します。
111 	 * APOP認証を行う場合に、"mail.pop3.apop.enable"をセットします。
112 	 * 
113 	 * @return Sessionに渡すPropertiesインスタンス
114 	 */
115 	private Properties createProperties() {
116 		Properties prop = new Properties();
117 		if ("apop".equalsIgnoreCase(protocol)) {
118 			prop.put("mail.pop3.apop.enable", "true");
119 		}
120 		return prop;
121 	}
122 
123 	/***
124 	 * @see com.ozacc.mail.fetch.FetchMailPro#disconnect()
125 	 */
126 	public synchronized void disconnect() throws MailException {
127 		try {
128 			closeCurrentFolderIfOpen();
129 		} finally {
130 			if (isConnected()) {
131 				log.debug(protocol.toUpperCase() + "サーバ[" + host + "]との接続を切断します。");
132 				try {
133 					store.close();
134 					store = null;
135 				} catch (MessagingException e) {
136 					throw new MailException("サーバ[" + host + "]との接続切断に失敗しました。", e);
137 				}
138 			}
139 		}
140 		log.info(protocol.toUpperCase() + "サーバ[" + host + "]との接続を切断しました。");
141 	}
142 
143 	/***
144 	 * 現在のメッセージフォルダをクローズします。
145 	 * 
146 	 * @throws MailException メッセージフォルダのクローズに失敗した場合
147 	 */
148 	private void closeCurrentFolderIfOpen() throws MailException {
149 		if (currentFolder != null && currentFolder.isOpen()) {
150 			log.debug("メッセージフォルダ[" + currentFolder.getName() + "]をクローズします。");
151 			try {
152 				currentFolder.close(true);
153 			} catch (MessagingException e) {
154 				log.error("メッセージフォルダ[" + currentFolder.getName() + "]のクローズに失敗しました。", e);
155 				throw new MailException("メッセージフォルダ[" + currentFolder.getName() + "]のクローズに失敗しました。",
156 						e);
157 			}
158 			log.debug("メッセージフォルダ[" + currentFolder.getName() + "]をクローズしました。");
159 			currentFolder = null;
160 		}
161 	}
162 
163 	/***
164 	 * @see com.ozacc.mail.fetch.FetchMailPro#changeFolder(java.lang.String)
165 	 */
166 	public synchronized void changeFolder(String folderName) throws MailException {
167 		if (!isConnected()) {
168 			log.warn("メールサーバに接続されていません。");
169 			return;
170 		}
171 
172 		closeCurrentFolderIfOpen();
173 		log.debug("メッセージフォルダ[" + folderName + "]をオープンします。");
174 		try {
175 			currentFolder = store.getFolder(folderName);
176 			currentFolder.open(Folder.READ_WRITE);
177 		} catch (MessagingException e) {
178 			log.error("メッセージフォルダ[" + folderName + "]のオープンに失敗しました。", e);
179 			throw new MailException("メッセージフォルダ[" + folderName + "]のオープンに失敗しました。", e);
180 		}
181 		log.debug("メッセージフォルダ[" + folderName + "]をオープンしました。");
182 	}
183 
184 	/***
185 	 * @see com.ozacc.mail.fetch.FetchMailPro#getMailCount()
186 	 */
187 	public int getMailCount() throws MailException {
188 		checkIfCurrentFolderIsOpen();
189 		try {
190 			return currentFolder.getMessageCount();
191 		} catch (MessagingException e) {
192 			throw new MailFetchException("メール数の取得に失敗しました。", e);
193 		}
194 	}
195 
196 	/***
197 	 * メールサーバに接続されていて、フォルダが操作できる状態かどうか調べます。
198 	 * フォルダが操作できる状態にない場合、NotConnectedExceptionをスローします。
199 	 * 
200 	 * @throws NotConnectedException
201 	 */
202 	private void checkIfCurrentFolderIsOpen() throws NotConnectedException {
203 		if (currentFolder == null || !currentFolder.isOpen()) {
204 			throw new NotConnectedException(protocol.toUpperCase() + "サーバ[" + host + "]に接続されていません。");
205 		}
206 	}
207 
208 	/***
209 	 * @see com.ozacc.mail.fetch.FetchMailPro#getMail(int)
210 	 */
211 	public ReceivedMail getMail(int num) throws MailException {
212 		MimeMessage mimeMessage = getMessage(num);
213 		MailConverter converter = new MailConverter(mimeMessage);
214 		return converter.convertIntoMails()[0];
215 	}
216 
217 	public ReceivedMail[] getMails(boolean delete) throws MailException {
218 		MimeMessage[] mimeMessages = getMessages(delete);
219 		MailConverter converter = new MailConverter(mimeMessages);
220 		return converter.convertIntoMails();
221 	}
222 
223 	/***
224 	 * @see com.ozacc.mail.fetch.FetchMailPro#getMessage(int)
225 	 */
226 	public synchronized MimeMessage getMessage(int num) throws MailException {
227 		checkIfCurrentFolderIsOpen();
228 		try {
229 			return (MimeMessage)currentFolder.getMessage(num);
230 		} catch (MessagingException e) {
231 			log.error("メッセージの取得に失敗しました。", e);
232 			throw new MailFetchException("メッセージの取得に失敗しました。", e);
233 		}
234 	}
235 
236 	public synchronized MimeMessage[] getMessages(boolean delete) throws MailException {
237 		checkIfCurrentFolderIsOpen();
238 		try {
239 			Message[] messages = currentFolder.getMessages();
240 			if (log.isInfoEnabled()) {
241 				if (messages.length > 0) {
242 					log.info(messages.length + "通のメールを受信します。");
243 				} else {
244 					log.info("受信するメールはありません。");
245 				}
246 			}
247 			// SEENフラグを立てる
248 			currentFolder.setFlags(messages, new Flags(Flags.Flag.SEEN), true);
249 			// DELETEDフラグを立てる
250 			if (delete) {
251 				currentFolder.setFlags(messages, new Flags(Flags.Flag.DELETED), true);
252 			}
253 			MimeMessage[] mimeMessages = new MimeMessage[messages.length];
254 			for (int i = 0; i < messages.length; i++) {
255 				mimeMessages[i] = (MimeMessage)messages[i];
256 			}
257 			return mimeMessages;
258 		} catch (MessagingException e) {
259 			log.error("メッセージの取得に失敗しました。", e);
260 			throw new MailFetchException("メッセージの取得に失敗しました。", e);
261 		}
262 	}
263 
264 	/***
265 	 * @see com.ozacc.mail.fetch.FetchMailPro#isConnected()
266 	 */
267 	public boolean isConnected() {
268 		return store != null && store.isConnected();
269 	}
270 
271 	/***
272 	 *  メールサーバのホスト名、またはIPアドレスを返します。
273 	 * 
274 	 * @return  メールサーバのホスト名、またはIPアドレス
275 	 */
276 	public String getHost() {
277 		return host;
278 	}
279 
280 	/***
281 	 * メールサーバのホスト名、またはIPアドレスをセットします。
282 	 * デフォルトは localhost です。
283 	 * 
284 	 * @param host メールサーバのホスト名、またはIPアドレス
285 	 */
286 	public void setHost(String host) {
287 		this.host = host;
288 	}
289 
290 	/***
291 	 * メールサーバの認証パスワードを返します。
292 	 * 
293 	 * @return メールサーバの認証パスワード
294 	 */
295 	public String getPassword() {
296 		return password;
297 	}
298 
299 	/***
300 	 * メールサーバの認証パスワード名をセットします。
301 	 * 
302 	 * @param password メールサーバの認証パスワード
303 	 */
304 	public void setPassword(String password) {
305 		this.password = password;
306 	}
307 
308 	/***
309 	 * メール受信に使用するプロトコロルをセットします。
310 	 * 
311 	 * @return プロトコル
312 	 */
313 	public String getProtocol() {
314 		return protocol;
315 	}
316 
317 	/***
318 	 * メール受信に使用するプロトコロルをセットします。
319 	 * 現在サポートされているプロトコルは、「pop3」と「imap」の二つです。
320 	 * デフォルトは「pop3」です。
321 	 * <p>
322 	 * POP3サーバへの認証をAPOPで行いたい場合は、プロトコル名ではありませんが、
323 	 * 「apop」を指定してください。APOP認証を使用するには、JavaMail 1.3.2以降が必要です。
324 	 * 
325 	 * @param protocol プロトコル
326 	 */
327 	public void setProtocol(String protocol) {
328 		this.protocol = protocol;
329 	}
330 
331 	/***
332 	 * @return 認証ユーザ名
333 	 */
334 	public String getUsername() {
335 		return username;
336 	}
337 
338 	/***
339 	 * メールサーバの認証ユーザ名をセットします。
340 	 * 
341 	 * @param username 認証ユーザ名
342 	 */
343 	public void setUsername(String username) {
344 		this.username = username;
345 	}
346 
347 	/***
348 	 * @return ポート番号
349 	 */
350 	public int getPort() {
351 		return port;
352 	}
353 
354 	/***
355 	 * メール受信に使用するポート番号をセットします。
356 	 * プロトコルに応じたポート番号が自動的に使用されますので、通常ここでポート番号をセットする必要はありません。
357 	 * 
358 	 * @param port ポート番号
359 	 */
360 	public void setPort(int port) {
361 		this.port = port;
362 	}
363 
364 	/***
365 	 * JavaMailのデバッグが有効かどうか判定します。
366 	 * 
367 	 * @return JavaMailのデバッグが有効な場合 ture
368 	 */
369 	public boolean isJavaMailLogEnabled() {
370 		return javaMailLogEnabled;
371 	}
372 
373 	/***
374 	 * JavaMailのデバッグを有効にするかどうか指定します。
375 	 * 有効にすると、<code>System.out</code>のデバッグメッセージが出力されます。<br>
376 	 * デフォルトは無効になっています。
377 	 * 
378 	 * @see javax.mail.session#setDebug(boolean)
379 	 * @param javaMailLogEnabled The javaMailLogEnabled to set.
380 	 */
381 	public void setJavaMailLogEnabled(boolean javaMailLogEnabled) {
382 		this.javaMailLogEnabled = javaMailLogEnabled;
383 	}
384 }