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.10 2005/01/29 23:13:17 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  		log.debug(protocol.toUpperCase() + "サーバ[" + host + "]に接続します。");
81  
82  		Session session = Session.getInstance(createProperties(), null);
83  		if (javaMailLogEnabled) {
84  			session.setDebug(true);
85  		}
86  
87  		try {
88  			store = session.getStore(protocol);
89  		} catch (NoSuchProviderException e) {
90  			log.error("指定されたプロトコル[" + protocol + "]はサポートされていません。", e);
91  			throw new MailException("指定されたプロトコル[" + protocol + "]はサポートされていません。", e);
92  		}
93  
94  		try {
95  			store.connect(host, port, username, password);
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 
105 		log.info(protocol.toUpperCase() + "サーバ[" + host + "]に接続しました。");
106 
107 		changeFolder(INBOX_NAME);
108 	}
109 
110 	/***
111 	 * Sessionに渡すPropertiesインスタンスを返します。
112 	 * APOP認証を行う場合に、"mail.pop3.apop.enable"をセットします。
113 	 * 
114 	 * @return Sessionに渡すPropertiesインスタンス
115 	 */
116 	private Properties createProperties() {
117 		Properties prop = new Properties();
118 		if ("apop".equalsIgnoreCase(protocol)) {
119 			prop.put("mail.pop3.apop.enable", "true");
120 		}
121 		return prop;
122 	}
123 
124 	/***
125 	 * @see com.ozacc.mail.fetch.FetchMailPro#disconnect()
126 	 */
127 	public synchronized void disconnect() throws MailException {
128 		try {
129 			closeCurrentFolderIfOpen();
130 		} finally {
131 			if (isConnected()) {
132 				log.debug(protocol.toUpperCase() + "サーバ[" + host + "]との接続を切断します。");
133 				try {
134 					store.close();
135 					store = null;
136 				} catch (MessagingException e) {
137 					throw new MailException("サーバ[" + host + "]との接続切断に失敗しました。", e);
138 				}
139 			}
140 		}
141 		log.info(protocol.toUpperCase() + "サーバ[" + host + "]との接続を切断しました。");
142 	}
143 
144 	/***
145 	 * 現在のメッセージフォルダをクローズします。
146 	 * 
147 	 * @throws MailException メッセージフォルダのクローズに失敗した場合
148 	 */
149 	private void closeCurrentFolderIfOpen() throws MailException {
150 		if (currentFolder != null && currentFolder.isOpen()) {
151 			log.debug("メッセージフォルダ[" + currentFolder.getName() + "]をクローズします。");
152 			try {
153 				currentFolder.close(true);
154 			} catch (MessagingException e) {
155 				log.error("メッセージフォルダ[" + currentFolder.getName() + "]のクローズに失敗しました。", e);
156 				throw new MailException("メッセージフォルダ[" + currentFolder.getName() + "]のクローズに失敗しました。",
157 						e);
158 			}
159 			log.debug("メッセージフォルダ[" + currentFolder.getName() + "]をクローズしました。");
160 			currentFolder = null;
161 		}
162 	}
163 
164 	/***
165 	 * @see com.ozacc.mail.fetch.FetchMailPro#changeFolder(java.lang.String)
166 	 */
167 	public synchronized void changeFolder(String folderName) throws MailException {
168 		closeCurrentFolderIfOpen();
169 		log.debug("メッセージフォルダ[" + folderName + "]をオープンします。");
170 		try {
171 			currentFolder = store.getFolder(folderName);
172 			currentFolder.open(Folder.READ_WRITE);
173 		} catch (MessagingException e) {
174 			log.error("メッセージフォルダ[" + folderName + "]のオープンに失敗しました。", e);
175 			throw new MailException("メッセージフォルダ[" + folderName + "]のオープンに失敗しました。", e);
176 		}
177 		log.debug("メッセージフォルダ[" + folderName + "]をオープンしました。");
178 	}
179 
180 	/***
181 	 * @see com.ozacc.mail.fetch.FetchMailPro#getMailCount()
182 	 */
183 	public int getMailCount() throws MailException {
184 		checkIfCurrentFolderIsOpen();
185 		try {
186 			return currentFolder.getMessageCount();
187 		} catch (MessagingException e) {
188 			throw new MailFetchException("メール数の取得に失敗しました。", e);
189 		}
190 	}
191 
192 	/***
193 	 * メールサーバに接続されていて、フォルダが操作できる状態かどうか調べます。
194 	 * フォルダが操作できる状態にない場合、NotConnectedExceptionをスローします。
195 	 * 
196 	 * @throws NotConnectedException
197 	 */
198 	private void checkIfCurrentFolderIsOpen() throws NotConnectedException {
199 		if (currentFolder == null || !currentFolder.isOpen()) {
200 			throw new NotConnectedException(protocol.toUpperCase() + "サーバ[" + host + "]に接続されていません。");
201 		}
202 	}
203 
204 	/***
205 	 * @see com.ozacc.mail.fetch.FetchMailPro#getMail(int)
206 	 */
207 	public ReceivedMail getMail(int num) throws MailException {
208 		MimeMessage mimeMessage = getMessage(num);
209 		MailConverter converter = new MailConverter(mimeMessage);
210 		return converter.convertIntoMails()[0];
211 	}
212 
213 	public ReceivedMail[] getMails(boolean delete) throws MailException {
214 		MimeMessage[] mimeMessages = getMessages(delete);
215 		MailConverter converter = new MailConverter(mimeMessages);
216 		return converter.convertIntoMails();
217 	}
218 
219 	/***
220 	 * @see com.ozacc.mail.fetch.FetchMailPro#getMessage(int)
221 	 */
222 	public MimeMessage getMessage(int num) throws MailException {
223 		checkIfCurrentFolderIsOpen();
224 		try {
225 			return (MimeMessage)currentFolder.getMessage(num);
226 		} catch (MessagingException e) {
227 			log.error("メッセージの取得に失敗しました。", e);
228 			throw new MailFetchException("メッセージの取得に失敗しました。", e);
229 		}
230 	}
231 
232 	public MimeMessage[] getMessages(boolean delete) throws MailException {
233 		checkIfCurrentFolderIsOpen();
234 		try {
235 			Message[] messages = currentFolder.getMessages();
236 			if (log.isInfoEnabled()) {
237 				if (messages.length > 0) {
238 					log.info(messages.length + "通のメールを受信します。");
239 				} else {
240 					log.info("受信するメールはありません。");
241 				}
242 			}
243 			// SEENフラグを立てる
244 			currentFolder.setFlags(messages, new Flags(Flags.Flag.SEEN), true);
245 			// DELETEDフラグを立てる
246 			if (delete) {
247 				currentFolder.setFlags(messages, new Flags(Flags.Flag.DELETED), true);
248 			}
249 			MimeMessage[] mimeMessages = new MimeMessage[messages.length];
250 			for (int i = 0; i < messages.length; i++) {
251 				mimeMessages[i] = (MimeMessage)messages[i];
252 			}
253 			return mimeMessages;
254 		} catch (MessagingException e) {
255 			log.error("メッセージの取得に失敗しました。", e);
256 			throw new MailFetchException("メッセージの取得に失敗しました。", e);
257 		}
258 	}
259 
260 	/***
261 	 * @see com.ozacc.mail.fetch.FetchMailPro#isConnected()
262 	 */
263 	public boolean isConnected() {
264 		return store != null && store.isConnected();
265 	}
266 
267 	/***
268 	 *  メールサーバのホスト名、またはIPアドレスを返します。
269 	 * 
270 	 * @return  メールサーバのホスト名、またはIPアドレス
271 	 */
272 	public String getHost() {
273 		return host;
274 	}
275 
276 	/***
277 	 * メールサーバのホスト名、またはIPアドレスをセットします。
278 	 * デフォルトは localhost です。
279 	 * 
280 	 * @param host メールサーバのホスト名、またはIPアドレス
281 	 */
282 	public void setHost(String host) {
283 		this.host = host;
284 	}
285 
286 	/***
287 	 * メールサーバの認証パスワードを返します。
288 	 * 
289 	 * @return メールサーバの認証パスワード
290 	 */
291 	public String getPassword() {
292 		return password;
293 	}
294 
295 	/***
296 	 * メールサーバの認証パスワード名をセットします。
297 	 * 
298 	 * @param password メールサーバの認証パスワード
299 	 */
300 	public void setPassword(String password) {
301 		this.password = password;
302 	}
303 
304 	/***
305 	 * メール受信に使用するプロトコロルをセットします。
306 	 * 
307 	 * @return プロトコル
308 	 */
309 	public String getProtocol() {
310 		return protocol;
311 	}
312 
313 	/***
314 	 * メール受信に使用するプロトコロルをセットします。
315 	 * 現在サポートされているプロトコルは、「pop3」と「imap」の二つです。
316 	 * デフォルトは「pop3」です。
317 	 * <p>
318 	 * POP3サーバへの認証をAPOPで行いたい場合は、プロトコル名ではありませんが、
319 	 * 「apop」を指定してください。APOP認証を使用するには、JavaMail 1.3.2以降が必要です。
320 	 * 
321 	 * @param protocol プロトコル
322 	 */
323 	public void setProtocol(String protocol) {
324 		this.protocol = protocol;
325 	}
326 
327 	/***
328 	 * @return 認証ユーザ名
329 	 */
330 	public String getUsername() {
331 		return username;
332 	}
333 
334 	/***
335 	 * メールサーバの認証ユーザ名をセットします。
336 	 * 
337 	 * @param username 認証ユーザ名
338 	 */
339 	public void setUsername(String username) {
340 		this.username = username;
341 	}
342 
343 	/***
344 	 * @return ポート番号
345 	 */
346 	public int getPort() {
347 		return port;
348 	}
349 
350 	/***
351 	 * メール受信に使用するポート番号をセットします。
352 	 * プロトコルに応じたポート番号が自動的に使用されますので、通常ここでポート番号をセットする必要はありません。
353 	 * 
354 	 * @param port ポート番号
355 	 */
356 	public void setPort(int port) {
357 		this.port = port;
358 	}
359 
360 	/***
361 	 * JavaMailのデバッグが有効かどうか判定します。
362 	 * 
363 	 * @return JavaMailのデバッグが有効な場合 ture
364 	 */
365 	public boolean isJavaMailLogEnabled() {
366 		return javaMailLogEnabled;
367 	}
368 
369 	/***
370 	 * JavaMailのデバッグを有効にするかどうか指定します。
371 	 * 有効にすると、<code>System.out</code>のデバッグメッセージが出力されます。<br>
372 	 * デフォルトは無効になっています。
373 	 * 
374 	 * @see javax.mail.session#setDebug(boolean)
375 	 * @param javaMailLogEnabled The javaMailLogEnabled to set.
376 	 */
377 	public void setJavaMailLogEnabled(boolean javaMailLogEnabled) {
378 		this.javaMailLogEnabled = javaMailLogEnabled;
379 	}
380 }