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 }