程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 使您的應用程序調用我的應用程序,第2部分: James應用程序

使您的應用程序調用我的應用程序,第2部分: James應用程序

編輯:關於JAVA

繼續您在 第 1 部分 中尚未完成的學習,在第 1 部分中,您學習了如何開發消息驅動 bean(MDB)、實體 bean 和容器管理的持久性 (CMP),還了解了如何在 Apache Geronimo 中部署並測試這些組件。本期是共分三部分的系列教程的第 2 部分,為您展示 Java Apache Mail Enterprise Server(也稱為 Apache James)的整體架構。您將了解如何構建、部署和測試電子郵件應用程序(mailet 和 matcher ),以及如何在 Apache James 電子郵件服務器中部署這個應用程序。

開始之前

本系列教程面向希望學習如何使用各種 Java EE 組件 —— 包括 MDB 和 Java 2 Platform,Enterprise Edition (J2EE)Connector Architecture(JCA)資源適配器 —— 構建集成化解決方案的 Java™ Platform, Enterprise Edition(Java EE)程序員。本教程假設您熟悉基本的 Java 和 Java EE 概念,例如 EJB、Java Message Service(JMS)、 MDB 和 Unified Modeling Language(UML)圖。

關於本系列

在這個共分三部分的系列教程中,您將構建一個示例應用程序 ,通過這種方式了解如何將不同的 Java EE 組件集成在一起,來開發復雜的應用程序。

您可 下載 本文的示例應用程序,它示范 了 Apache James 中電子郵件的數據通過 JCA 資源適配器、MDB、EJB 流向 Apache Geronimo 應用服務器。

本系列的 第 1 部分 介紹了如何開發 MDB、實體 bean 和容器管理的持久性(CMP),以及如何在 Apache Geronimo 中部署和測試這些組件。

本期是系 列教程的第 2 部分,解釋如何創建電子郵件應用程序(mailet 和 matcher)並將其在 Apache James 電子郵件服務器中進行部署。

第 3 部分將整個應用程序聯系在一起。您將學習為 Apache James 電子郵件服務器開發、部署和測試 JCA 資源適配器,它將通過 MDB 與James 和 Geronimo 交互。

關於本教程

在 第 1 部分 中,您構建了 MDB 和實體 bean,從而在 Apache Derby 數據 庫中創建了一個采購訂單項。在這一期教程中,您將了解 Apache James 的整體架構,並構建一個電子郵件應用程序,用於處理傳入的電 子郵件。

先決條件

本教程不要求您預先具備任何 Apache James 或 JavaMail 的知識,但希望您了解電子郵件的工作原理 。

系統要求

為完成本教程的學習,您需要具備以下工具:

Apache Geronimo —— Apache 提供的 Java EE 應用服務器

Apache James 2.2 -—— 基於 Java 的 Simple Mail Transfer Protocol(SMTP)、Post Office Protocol version 3(POP3)和 Network News Transfer Protocol(NNTP)新聞服務器

Apache Derby 數據庫 —— 開放源碼、輕量級數據庫,嵌入在 Geronimo 之中,無需獨立安裝

Sun Microsystems 提供的 Java 1.4.2

示例源文件

要開始學習,請下載 part2.source.zip(參見 下載 部分),其中包括本教程中提到的源 文件、mailet 二進制文件和 .bat 文件。下面詳細列出了 part2.source.zip 文件的組成部分:

- deploy(po-mailet.jar,包含 mailet 和 matcher)

- lib(tester.jar)

- src(mailet、matcher 和測試客戶機的 java 文件)

- deploy.cmd

- undeploy.cmd

- runSendEmail.cmd

- runReadEmail.cmd

Apache James —— 概述

為了繼續開發示例應用程序,您需要很好地理解 Apache James 服務器。本節簡單介紹 James 服務器及其組件。

Apache James 是什麼?

Apache James 也可簡稱為 James,它是 Java Apache Mail Enterprise Server 的縮寫。James 是基於 100% 純 Java 的電子郵件服務器,使用 Java 2 SDK 和 JavaMail 1.3 API 構建而成,因而具有高度的可移植性,可以移植到不同的平台上。 James 是一種獨立的郵件服務器,提供了一個完整的電子郵件解決方案,既可發送又可存儲電子郵件,無需任何其他軟件。

Apache James 架構

下面更詳細地介紹 James 架構及其部分優點。如 圖 1 所示,正像其他任何電子郵件服務器一樣,James 提供了大多數標准的電子郵件服務,例如用於發送電子郵件的 Simple Mail Transfer Protocol(SMTP)和檢索電子郵件的 Post Office Protocol(POP3)等。

James 還支持閱讀新聞組、在新聞組中發帖的 Net News Transfer Protocol(NNTP)和有助於從外部電子 郵件服務器檢索電子郵件消息的 FetchMail。目前,James 的 Internet Message Access Protocol(IMAP)實現依然處於實驗階段,有望 在 James V3 中發布。

圖 1. James 服務器架構概覽

除了上述服務之外,James 還有一個稱為假脫機管理器 (spool manager)的郵件引擎,用於處理傳入的電子郵件。James 服務器的所有組件,包括假脫機管理器在內,均使用自己的儲存庫來存 儲各種數據,例如用戶信息、電子郵件、新聞等等。James 支持不同的儲存庫格式,例如文件系統、數據庫、DBFile。當今的大多數電子 郵件服務器都提供了這些特性,那麼我們為什麼要用 James 呢?

James 不僅僅是一種可移植、獨立的電子郵件服務器,更提供了 獨一無二的可插入式架構,允許用戶構建定制的電子郵件應用程序。這些應用程序稱為 matcher 和 mailet(如 圖 1 所示),與 Java servlet 類似,在 James 郵件引擎(也稱為 mailet 容器)內部署和配置。

James 提供了一種低調、開箱即用的管理控制台,稱 為遠程管理器。這是一種基於 Telnet 的命令行工具,可用於添加或刪除用戶、配置、轉發和別名等服務。

現在您對 James 服務 器的架構和其中的組件應該已經有了很好的理解,接下來探討 mailet 和 matcher。

Mailet 和 matcher

James 構建在健 壯、可定制的架構之上,這有助於用戶開發定制的電子郵件應用程序,允許他們發送電子郵件或根據業務規則對傳入的電子郵件進行處理 。這些定制的電子郵件應用程序就稱為 mailet 和 matcher。James 提供了一種非常公開的 mailet API,使開發人員能夠輕松開始編寫定 制應用程序。

mailet 或 matcher 與 James mailet 容器的關系就像是 servlet 與 Java Web 容器的關系。如 表 1 所示, mailet 和 matcher 都具有與 servlet 類似的定義良好的生命周期。但與接收 HTTP 請求的 servlet 不同,mailet 和 matcher 接收的 是傳入的電子郵件消息。Apache James 提供了大量的 mailet 和 matcher。

表 1. servlet、mailet 和 matcher 之間的比較

  Servlet Mailet Matcher 開發工具: Java Servlet API James Mailet API 和 JavaMail API James Mailet API 和 JavaMail API 生命周期方法: init(ServletConfig) init(MailetConfig) init(MatcherConfig)   service (ServletRequest, ServletResponse) service(Mail) match(Mail)   doGet()/doPost()       destroy() destroy() destroy() 部署環 境: Java Web 服務器(例如 Tomcat) James 服務器 James 服務器

mailet 是 一種定制的應用程序組件,具有處理傳入的電子郵件消息的應用程序邏輯。例如,您可編寫一個 mailet 來過濾垃圾郵件、在您外出度假 期間自動回復郵件,或在接收到新電子郵件時向您的手機發送短消息(SMS)。可能性無窮無盡。圖 2 列出了定制 mailet 必須實現的所 有生命周期方法。在部署定制 mailet 後,James 服務器將初始化定制 mailet,方法是調用其 init () 方法一次。此後,每傳入一條新 的電子郵件消息,service () 方法就會被調用。取消部署 mailet 時,或者服務器關閉期間,mailet 的 destroy () 方法將被調用,以 釋放 mailet 應用程序使用的所有資源。

另一方面,matcher 負責發送電子郵件,而不是處理它們。matcher 的生命周期方法的行 為與 mailet 類似,不同之處只有 match () 方法。與 mailet 的 service () 方法不同,match () 方法返回必須由 mailet 處理的一組 收件人電子郵件地址。

matcher 通常與 mailet 配對使用,以開發復雜的電子郵件應用程序。圖 2 描述了 James 服務器中對傳入 電子郵件消息的處理流。

圖 2. 與 James 服務器交互的 Matcher 和 mailet

James 服務器在開發或啟動過程中初始化 matcher 和 mailet。James 服務器接收到電子郵件時,它將調用部署好的 matcher 的 match () 方法。若 matcher 返回收件人電子郵件地址列表, James 會將電子郵件地址發送給相應的 mailet,供其進一步處理。

現在您已經熟悉了 James,就可以安裝和配置 James 服務器了 。

安裝和配置 James 服務器

這一部分詳細介紹 Apache James 服務器的安裝和配置。如果您尚未下載 James 服務器,那 麼請立即下載(下載鏈接請參見 系統要求 部分)。我們將使用 Apache James 2.2。

安裝

下載了 James 2.2 的 .zip 文 件之後,將其解壓到您的本地驅動器中(假設是 c:\)。那麼您現在可能擁有目錄 c:\james-2.2.0。James 安裝與其他 Apache 產品的安 裝並無差別,只需要解壓縮歸檔文件即可。

在啟動 James 服務器之前,請確保您已設置好了 JAVA_HOME。如果您尚未在自己的環 境中設置 JAVA_HOME,請在 c:\james-2.2.0\bin 目錄下的 run.bat 文件中進行設置。建議您將 JRE 1.4.x 與 James 配合使用。

現在您已經為啟動 James 服務器作好了一切准備。打開命令提示符,運行 c:\james-2.2.0\bin\run.bat 文件。成功啟動 James 之後,您將看到一些日志記錄,如 圖 3 所示。

圖 3. 帶有 James 服務器的日志記錄的控制台

在 James 啟動時,有些服務將在其默 認端口啟動:SMTP 服務在端口 25 啟動、POP3 服務在端口 110 啟動、NNTP 服務在端口 119 啟動、遠程管理器服務在端口 4555 啟動。

要停止 James 服務器,可在控制台窗口中按下 Ctrl + C。

配置

下面介紹一些配置細節。盡管在本教程中不會用到 所有這些內容,但在將 James 用做生產環境中的電子郵件服務器時,這些細節無疑是有用的。James 的大多數配置信息都存儲在 C:\james-2.2.0\apps\james\SAR-INF 目錄下的 config.xml 文件中。在初次安裝 James 時,您不會看到這個文件,該文件只有在第一次 運行服務器之後才會構建。

讓我們來看看一些基本但重要的配置細節。默認情況下,服務器名是 localhost,但為學習本教程,請 將其更改為 localhost.com。如果願意,您可在這裡按自己的意願指定服務器名稱(請參見 清單 1)。

清單 1. 服務器名

 <servernames autodetect="true" autodetectIP="true">
     <servername>localhost</servername>
 </servernames>

默認情況下,James 中已創建了一名 用戶 root,其口令是 root,如下所示:

<account login="root" password="root"/>

localhost IP 127.0.01 將默認添加為 DNS 服務器。對於本教程來說,這已足夠,因為您將在本地機器上運行 James。但在生產環境中,您必須要在以 下部分中為 DNS 服務器添加一項(參見 清單 2)。

清單 2. DNS 服務器

  <dnsserver>
    <servers>
 <server>127.0.0.1</server>
   </servers>
    <autodiscover>true</autodiscover>
   <authoritative>false</authoritative>
   </dnsserver>

James 設置為使用文件系統作為默認儲存庫。同樣,對於我們的示例應用程序來說,您不必更改這一 設置,但 James 確實提供了其他可選數據庫或 DBFile 儲存庫,在生產環境中的電子郵件服務器中,它們可能是更好的選擇(參見 清單 3)。

清單 3. 儲存庫

   <inboxRepository>
     <repository  destinationURL="file://var/mail/inboxes/" 
 type="MAIL"/>
   </inboxRepository>

這樣 ,通過在 config.xml 文件中使用不同的選項,您就可以按照自己的需求來打造 James。後文中您還將為本文的示例應用程序再次配置 James。

應用程序設計

您已經熟悉了 Apache James,那麼就可以繼續構建示例應用程序了。在這一部分中,您將構建一個 電子郵件應用程序,包含一個 matcher 和一個 mailet,用於處理 Foo, Inc. 的員工發送的采購請求電子郵件。

首先識別您的業 務規則,因為它們將管理 matcher 和 mailet 的邏輯。

業務規則

首先,您需要一種機制來區分采購請求和非采購請求電子 郵件。假設所有主題是 Purchase Request 的電子郵件都是采購請求電子郵件。一旦您識別出一封采購請求電子郵件,就需要驗證發件人 是否有權限請求采購。您將利用發件人的電子郵件地址驗證授權。如果發件人經過授權,則將采購請求電子郵件轉發到指定的電子郵件地 址,所有經過授權的采購請求都存儲在那裡。如果發件人未經過授權,則不對采購請求電子郵件進行任何處理。

整合了業務規則之 後,您就有了以下匹配規則和處理行為:

匹配規則

主題是 Purchase Request。

發件人的電子郵件地址有效。

處理行為

將電子郵件轉發到存儲經過授權的采購請求電子郵件的指定文件夾。

在這個練習中,您已識別出 matcher(匹配規則)和 mailet(處理行為)的應用程序邏輯。現在我們開始編寫一些代碼。

matcher

您已為 matcher 識別出兩條匹配規則:第一 條是主題匹配,第二條是檢查發件人是否經過授權。要驗證發件人的授權情況,您需要根據一個經過授權的電子郵件地址列表驗證發件人 的電子郵件地址。我們在初始化過程中為 matcher 提供經過授權的電子郵件列表。您將在 部署 一節中了解到如何為 matcher 配置初始 化屬性。

編寫定制 matcher 的第一步就是查看 James mailet API 提供的 GenericMatcher,並對其加以擴展。將您的 matcher 命名為 POMatcher。GenericMatcher 有一個默認實現,提供了大多數必需的方法,僅有一個抽象方法 match (Mail)。查看 清單 4 中 POMatcher.java 的 init () 方法。

清單 4. POMatcher.java 的 init() 方法

/*
 * This method  initializes the list of authorized senders.
 *
 * @param config Contains configuration information  for this matcher.
 *
 * @see org.apache.mailet.Matcher#init(org.apache.mailet.MatcherConfig)
  */
public void init(MatcherConfig config) throws MessagingException {
   super.init(config);
    ilog("Entering POMatcher init() " + config);

   //comma-separated list of authorized e-mail  addresses
   String senders = getCondition();

   // initialize the authorized senders  list
   StringTokenizer st = new StringTokenizer(senders, ",");
   authorizedSenderList = new  HashMap();
   while (st.hasMoreTokens()) {
      String sender = st.nextToken();
       authorizedSenderList.put(sender, sender);
   }

   ilog("Authorized Senders are: " +  authorizedSenderList);
   ilog("Exiting POMatcher init()");

}//end init() method

在 init() 方法中,您調用了 getCondition(),它返回配置時設置的參數值。這是一個以逗號分隔的經授權的電子郵件地址列表。現在看一 下 清單 5 中的 match () 方法。

清單 5. POMatcher.java 中的 match () 方法

/*
 * Checks if  subject is 'Purchase Request' and
 * Checks if the sender is authorized to request a purchase.
 *
 * @see org.apache.mailet.Matcher#match(org.apache.mailet.Mail)
 */
public Collection match(Mail  mail) throws MessagingException {

   ilog("Entering POMatcher match() " + mail);
    MimeMessage mimeMsg = mail.getMessage();

   String subject = mimeMsg.getSubject();
    InternetAddress[] fromList
      = (InternetAddress[]) mimeMsg.getFrom();

   // checks if  the subject is 'Purchase Request' 
   if (subject != null && subject.indexOf(PURCHASE_REQUEST)
> 0) {

      // checks if the sender is authorized to request a purchase
       if (isSenderAuthorized(fromList)) {
         ilog("Exiting POMatcher match()");
          return mail.getRecipients();
      }
   }
   ilog("Sender is not authorized. "+  fromList);
   ilog("Exiting POMatcher match()");
   return null;

}//end match method

private boolean isSenderAuthorized(InternetAddress[] fromList) {

   boolean foundSender =  false;

   for (int i = 0; i < fromList.length; i++) {
   if  (authorizedSenderList.containsKey(fromList[i].toString())) {
      foundSender = true;
   }
}
   return foundSender;

}//end isSenderAuthorized

isSenderAuthorized () 方法檢查發件人 的電子郵件地址是否出現在經授權的發件人列表中,若找到匹配項,則返回 true。在 match () 方法中,您根據兩條匹配規則檢查主題和 經過授權的發件人。如果兩個條件都滿足,則返回整個收件人列表,否則返回 null。

POMatcher 的源文件(.java)可在 $part2.home/src/examples/po/email/matcher 目錄下找到。

我們已經准備好了 matcher。接下來介紹 mailet。

mailet

根據您的業務規則,mailet 只有一種處理行為,就是將電子郵件消息轉發到其他電子郵件文件夾。mailet 的初始 化屬性(在部署過程中設置)包括:

forward:這是轉發電子郵件的目標地址。

from:這是轉發電子郵件的新發件人的電子 郵件地址。如果您在轉發電子郵件之前未更改發件人,mailet 將進入無窮遞歸循環處理。

編寫定制 mailet 的第一步與 matcher 類似,不同之處在於您必須查看 James mailet API 提供的 GenericMailet 並擴展它。您將調用 mailet 類 POMailet。GenericMailet 有一個默認實現,提供了大多數必需的方法,只有一個抽象方法 service (Mail)。讓我們來看看 POMailet.java 的 init () 方法,如 清單 6 所示。

清單 6. POMailet.java 中的 init() 方法

/*
 * This method read the 'forward'  and 'from' e-mail addresses from
 * the mailet configuration.
 *
 * @param config Contains  configuration information for this mailet.
 *
 * @see org.apache.mailet.Mailet#init (org.apache.mailet.MailetConfig)
 */
public void init(MailetConfig config) throws MessagingException  {
   super.init(config);
   ilog("Entering POMailet init() " + config);

    this.forwardEmail = getInitParameter("forward");
   this.from = getInitParameter("from");

    ilog("Forward is: " + this.forwardEmail);
   ilog("From is: " + this.from);
   ilog("Exiting  POMailet init()");

}// end init()

在 POMailet.java 的 init () 中,您讀取了初始化參數 forward 和 from。這些參數的值是在部署過程中設置的。清單 7 展示了 POMailet 的 service() 方法。

清單 7. POMailet.java 中的 service () 方法

/*
 * This method processes the e-mail received and forwards the
 * e- mail to a specific 
 * e-mail address set by 'forward' property.
 *
 * @mail Email  Message
 *
 * @see org.apache.mailet.Mailet#service(org.apache.mailet.Mail)
 */
public void  service(Mail mail) throws MessagingException {

   ilog("Entering PO Mailet : " + mail);
    MimeMessage email = mail.getMessage();

   ilog("Email is: " + email);

   // move  the email to a specific user inbox 
   InternetAddress address = new InternetAddress(forwardEmail);
   Address[] list = { address };

   MimeMessage copymsg = new MimeMessage(email);

   // modifying the subject by adding the requestor email address
   Address[] sentByList =  copymsg.getFrom();
   String sentBy = sentByList[0].toString();
   copymsg.setSubject("Purchase  Request by: " + sentBy);

   // modifying the sender email to 'from' 
   InternetAddress  newFrom = new InternetAddress(from);
   copymsg.setFrom(newFrom);

   // sending the email  to a new recipient (like forwarding email)
   Transport.send(copymsg, list);
   ilog("Exiting PO  Mailet");

}// end service 

service () 方法不進行任何檢查,因為檢查已經由 POMatcher 完成了, 它只是修改主題,使主題中包含發件人的電子郵件地址,並將電子郵件消息轉發到 forward 參數指定的其他電子郵件文件夾中。

您可在 $part2.home/src/examples/po/email/mailet 目錄下找到 POMailet 的源文件(.java)。

至此,我們已經編寫好了 mailet 和 matcher,這就完成了示例電子郵件應用程序。由於您已安裝了 James,所以可以配置 James,然後再部署您的示例電子郵件應 用程序。

配置 James

在這一部分中,您將通過創建用戶賬戶來配置 James,完成之後就可以在下一節中部署示例電子郵件 應用程序了。

創建用戶賬戶

與其他配置不同,要創建用戶,您不必忙於處理 config.xml,而是使用 James 提供的基於 Telnet 的客戶機 —— 遠程管理器。

就本教程的目的而言,您將創建以下用戶賬戶,以用戶名/口令的格式列出:

user1 / password

user2 / password

user3 / password

orders / password

authorized-orders / password

為此,使用 c:\james-2.2.0\bin\run.bat 啟動 James 服務器,這將啟動遠程管理器服務。現在,Telnet 在端口 4555 處接入 localhost,您將看到如 圖 4 所示的登錄提示。

圖 4. 遠程管理器服務的登錄提示

輸入默認用戶/口令,如果您未在 config.xml 文件中 加以改動,應該是 root / root,輸入後按下 enter。創建新用戶的命令是 adduser username password。創建全部 5 個用戶賬戶 (user1、user2、user3、orders 和 authorized-orders),如 圖 5 所示。

圖 5. 創建全部 5 個用戶

創建好所有用戶之後,鍵入 quit 注銷 遠程管理器服務。既然配置好了用戶賬戶,就可以部署您的電子郵件應用程序了。

部署

在 James 服務器中部署一個電子郵 件應用程序共分兩步。在部署示例應用程序時,請確保您的服務器未在運行,因為您將修改 config.xml 文件。

第 1 步:部署定 制 mailet 和 matcher .jar 文件

所下載的文件 part2.source.zip 的 $part2.home 目錄中具有部署(deploy.cmd)和取消部署 (undeploy.cmd)的腳本(請參見 下載 部分)。

在使用前務必修改命令文件中的 JAVA_HOME 和 JAMES_HOME。

定制電子 郵件應用程序的部署實際上只是將一個 .jar 文件(由 POMatcher.class 和 POMailet.class 構成的 po-mailet.jar)復制到 $JAMES_HOME\lib 目錄中。

要運行這個示例應用程序,需要以下 .jar 文件。您可在 C:\james-2.2.0\work\james- xxxxxxxxxxxxx\SAR-INF\lib 目錄下找到這些 .jar 文件(其中的變量 x 代表特定於您的機器的號碼)。

activation.jar

mailet_1_0.jar

mail-1.3.1.jar

將這些 .jar 文件復制到 $JAMES_HOME\lib 目錄。

第 2 步:配置

對於每一個定制的 mailet 和 matcher,您都必須在 config.xml 文件中為其添加一項,格式如 清單 9 所 示。

在 config.xml 文件中為您的示例 matcher(POMatcher)和 mailet(POMailet)添加包。

默認情況下,config.xml 具有以下由 James 默認為 mailet 和 matcher 提供的項(請參見 清單 8)。

清單 8. 用於 mailet 和 matcher 的默認 config.xml 項

<mailetpackages>
<mailetpackage>org.apache.james.transport.mailets</mailetpackage>
</mailetpackages>
<matcherpackages>
<matcherpackage>org.apache.james.transport.matchers
</matcherpackage>
</matcherpackages>

為我們的示例應用程序添加包(examples.po.email.mailet 和 examples.po.email.matcher ),如 清單 9 所示。

清單 9. 為示例應用程序添加包

<mailetpackages>
<mailetpackage>org.apache.james.transport.mailets</mailetpackage>
<mailetpackage>examples.po.email.mailet</mailetpackage>
</mailetpackages>
<matcherpackages>
<matcherpackage>org.apache.james.transport.matchers
</matcherpackage>
<matcherpackage> examples.po.email.matcher</matcherpackage>
</matcherpackages>

在 config.xml 文件中為您的示例 mailet 和 matcher 添加項,如 清單 10 所示。

清單 10. 示例 mailet 和 matcher 的項

<mailet match="[email protected],[email protected]" 
          class="POMailet">
      <forward>[email protected]</forward>
       <from>[email protected]</from>
</mailet>

這就是通常情況下將定制 mailet 和 matcher 一 同定義的方法。一個 matcher 總是與一個 mailet 一起定義。

如下代碼展示了定義 matcher 的語法。

MatcherClassName=<initialization properties>

MatchClassName 是必需的,但初始化屬性是可選的 。

在本例中,有 POMatcher= [email protected],[email protected]。參見 清單 4 中的 POMatcher.java;在 init() 方法 中,您讀取的是一個以逗號分隔的經授權的電子郵件地址列表。這一列表在此處設置為 [email protected],[email protected]。 getCondition() 方法在 POMatcher 中返回這個值。這就意味著,僅有 user1 和 user2 經過授權,可以發送帶有采購請求的電子郵件 (user3 未經授權)。

清單 11 展示了定義 mailet 的語法。

清單 11. 定義 mailet 的語法

<mailet  match="MatchClassName[=][properties]" 
     Class="MailetClassName" 

     
<initialization-property-name>value
</initialization-property-name>
</mailet>

在示例中可以看出,您使用了兩個初始化參數,其名稱分別為 forward 和 from。從示例應用程序的角度來看,經過授權的電子郵件將被 轉發給 forward 屬性中指定的電子郵件地址處。

您已配置好了示例 mailet 和 matcher,那麼繼續操作,啟動服務器。您將了解 在服務器啟動過程中,POMatcher 和 POMailet 是如何初始化的,如 圖 6 所示。

圖 6. POMatcher 和 POMailet 是在 James 啟 動時初始化的

如 圖 6 所示,POMatcher 和 POMailet 都是由 James 服務器按此順序初始化的。

您已成功地部署了示例電子郵件應用程序。現在可 以創建一個客戶機或測試程序來測試您的應用程序了。

測試應用程序

在這部分中,您將編寫一個電子郵件客戶機,它可以 發送電子郵件並讀取用戶收件箱中的電子郵件。

電子郵件客戶機

客戶機程序 EmailClient.java(請參見 清單 12 和 清單 13)提供了發送電子郵件和顯示用戶收件箱中電子郵件的方法。

您可在 $part2.home/src/examples/po/test 目錄下查看整個客戶 機程序 EmailClient.java,獲得此程序的方式請參見 下載 部分。

清單 12. 電子郵件客戶機的 sendEmail 方法

/**
 * Sends an e- mail message
 *
 * @param from Sender's e-mail address
 * @param to Recipient's e-mail  address
 * @param subject Email Subject
 * @param content Email Message Content
 * @throws  MessagingException 
 */
public void sendEmail(String from,
  String to,
  String  subject,
  String content)
   throws MessagingException {

   Session session =  createSession(host, null, null);

   MimeMessage msg = new MimeMessage(session);
    msg.setFrom(new InternetAddress(from));
   msg.addRecipients(Message.RecipientType.TO, to);
    msg.setSubject(subject);
   msg.setText(content);
   Transport.send(msg);

    System.out.println("Email message is successfully sent to " + to);
}

在 sendEmail 方法中,您創 建了一條新的電子郵件消息(MimeMessage),帶有指定的發件人電子郵件地址(from)、收件人電子郵件地址(to)、主題(subject) 和消息主體(content)。您調用了 Transport.send() 來實際地將消息傳遞到收件人的收件箱中。您將使用此方法來發送采購請求電子郵 件。

現在來看看如何讀取用戶收件箱中的電子郵件(參見 清單 13)。您將使用 readInbox 方法來驗證您的示例電子郵件應用程 序(matcher 和 mailet)是否將來自經授權的發件人的采購請求電子郵件發送到另外一個電子郵件文件夾中。

清單 13. 電子郵件 客戶機的 readInbox 方法

/**
 * Reads all the messages in user's inbox.
 *
 * @param  user user name
 * @param password password
 */
public void readInbox(String user, String  password) {

   Session session = createSession(host, user, password);
   Store store =  null;
   Folder inboxFolder = null;
   try {
   store = session.getStore();

       store.connect();
      Folder rootFolder = store.getDefaultFolder();
      inboxFolder  = rootFolder.getFolder("inbox");

      inboxFolder.open(Folder.READ_ONLY);
      Message[]  emails = inboxFolder.getMessages();

      System.out.println("Inbox for User: [" + user+"]");
      System.out.println("---------------------------------------");

      for (int i = 0;  i < emails.length; i++) {
         MimeMessage msg = (MimeMessage) emails[i];

          System.out.println("Email Message No. :["+ (i+1) +"]");
         System.out.println();
         System.out.println(" - From: " + msg.getFrom()[0]);
         System.out.println("  - Subject: " + msg.getSubject());
         System.out.println(" - Content: " + msg.getContent ());
         System.out.println();
      }//end for 

       System.out.println("---------------------------------------");
   } catch (Exception e) {
       e.printStackTrace();
   }
   finally {
      try {
         inboxFolder.close (true);
      } catch (MessagingException e) {
         e.printStackTrace();
       }
      try {
         store.close();
      } catch (MessagingException e)  {
         e.printStackTrace();
      }
   }
}

readInbox 方法負責在電 子郵件服務器(James 服務器)上讀取一名用戶的收件箱,並顯示收件箱文件夾中出現的所有電子郵件消息。如 清單 13 所示,您需要創 建一個新的會話對象,並連接到存儲,這樣才能獲得對 James 服務器上用戶收件箱文件夾的訪問權限。確保以只讀模式打開收件箱文件夾 (inboxFolder.open(Folder.READ_ONLY)),然後在從中讀取郵件。獲得了收件箱文件夾的句柄之後,您可讀取所有消息、遍歷列表並顯 示每一條電子郵件消息。讀取完成後,不要忘記關閉收件箱文件夾和存儲以釋放資源。

下面的 清單 14 展示了實際調用 sendEmail 和 readInbox 方法的 main 方法的部分內容。

清單 14. EmailClient.java 的 main() 方法的代碼片段

public static void main(String a[]) throws Exception {

   //check if from and to  have been provided
   String mode = System.getProperty("mode");
   String host = null;
    String user = null;
   String password = null;
   String from = null;
   String to =  null;
   String subject = "Purchase Request";
   Calendar cal = Calendar.getInstance();
    String content = "Purchase Request sent on :" + new Date(cal
 .getTime().getTime());

    boolean isSend = false;

//check if there are enough command-line parameters and print usage

   if(mode != null && mode.equalsIgnoreCase("send")) {
host = a[0];
      from  = a[1];
      to = a[2];
isSend = true;
}
   else if(mode != null &&  mode.equalsIgnoreCase("read")) {
      host = a[0];
      user = a[1];
       password = a[2];
}

 
      EmailClient client = new EmailClient( 
             host
          );

   if(isSend)
      client. sendEmail(from, to,  subject, content
          );
   else
      client. readInbox(user, password
           );

}//end main

main() 方法公開了幾個命令行參數,用於發送和讀取電子郵件。在 清 單 14 中可以看到,sendEmail() 方法需要一個電子郵件主機,還需要 from 和 to 值,readInbox() 需要電子郵件主機、一個電子郵件 賬戶的用戶名和口令。

運行測試

part2.source.zip 文件中提供了腳本(runSendEmail.cmd 和 runReadEmail.cmd),用於 測試示例電子郵件應用程序(可在 下載 部分中獲得)。如果您按本教程的指導正確配置好了應用程序,只需修改 JAVA_HOME 以運行這些 測試即可。

如果 James 服務器未運行,請啟動它。首先,您運行 runSendEmail.cmd 腳本,從電子郵件地址 [email protected](切記,[email protected] 是一個經過授權的發件人)向 [email protected](該地址可通過更改 EMAIL_TO 參數在 runSendEmail.cmd 中修改)發送采購請求電子郵件。

運行 runSendEmail.cmd 後,您將看到一些日志記錄,如 圖 7 所示 。

圖 7. 通過運行 runSendEmail.cmd 測試應用程序

如果您看到 圖 7 所示的消息,就表示電子郵件已成 功發送。在 James 服務器中,這一傳入的電子郵件將由 POMatcher-POMailet 處理,如 圖 8 所示。

圖 8. James 服務器的控制 台日志

James 服 務器首先調用 POMatchermatch() 方法。由於發件人 [email protected] 是一個經過授權的發件人,POMailet 的 service() 方法將被 調用,電子郵件應已轉發到 [email protected]。您一定很疑惑,為什麼又一次調用了 POMatchermatch() (參見 圖 9) 。答案是:我們的 POMailet 的 service() 方法將電子郵件發送到 [email protected]。這一電子郵件在 James 服務器 中得到了與其他任何傳入的電子郵件相同的處理,因此,服務器調用 POMatcher match() 方法。(提示:這就是首先將 from 更改為 [email protected] 或其他任何未經授權的發件人、再將電子郵件轉發到 [email protected] 的原因所在,這是為了避 免出現無窮遞歸循環)。這是一個小小的工作區,因為 POP3 協議不支持在文件夾之間移動電子郵件(IMAP 支持這一功能)。

現在,由於發件人的電子郵件地址是 [email protected],這並非經過授權的發件人,因而 POMailet 不會處理這封轉發過來的電子 郵件。

下面檢查一下,看看 POMailet 是否確實將電子郵件發送到了 [email protected]

檢查結果

運行 runReadEmail.cmd,您將看到如 圖 9 所示的結果。

圖 9. 顯示電子郵件

如 圖 9 所示,authorized-orders 收件箱中的電子 郵件顯示了出來。

結束語

祝賀您!第 2 部分的應用程序至此已全部完成,您已學會了使用 Apache James 服務器構建、部 署和測試電子郵件應用程序的方法。

在本系列教程的最後一期:第 3 部分中,您將為 Apache James 服務器開發一個 JCA 資源適 配器(也可稱為連接器),它可將第 2 部分的應用程序(mailet 和 matcher)連接到 第 1 部分 的應用程序(MDB)。

本文配套源碼

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved