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