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 }