跳到导航
BEA Dev2Dev Oracle and BEA
首页 资源中心 dev2dev学堂 在线技术论坛 User Group CodeShare
dev2dev 首页 > 资源中心 > 技术文章
Dear John(专栏 #2):通过E-mail(SMTP)访问WebLogic Workshop Web服务

时间:2003-03-25
作者:John Bley
浏览次数:
本文关键字:web servicesSMTPWeb服务Web Services
文章工具
推荐给朋友 推荐给朋友
打印文章 打印文章


在详细讨论这个专栏之前,让我们再来回顾一下Web服务的定义。为了解释Web服务定义语言(WSDL)的规范,Web服务由一组相关的网络端点(地址)和关联的消息组成。可以推测,当一个适当的消息发送到端点时,一些有用的操作就会在端点触发。

Web服务调用消息一般根据简单对象访问协议(SOAP)来格式化。SOAP规范的早期版本将SOAP绑定到超文本传输协议(HTTP)中,并且现今存在的大多数Web服务实现都偏向于HTTP。但是Web服务理论上应该可以通过任何"标准的"Internet协议得到。

亲爱的约翰专栏本期回答了该问题:"如何通过简单邮件传输协议(SMTP)和Web服务进行通信?"
尽管SMTP(定义在RFC 821中)仅有短短20年的历史,但在Internet上从点到点传输的大部分电子邮件流依然是通过这个协议发送的。



WebLogic Workshop 7.0没有把内置的SMTP支持当作Web服务传输协议。不过,它把支持Java 消息服务(JMS)的协议当作Web服务传输协议。因此在这个例子中,我将安装自己的邮件服务器(使用Apache Jakarta projectJames,)并且将传入邮件消息的消息内容转发给WebLogicWorkshop内置的JMS队列jws.queue。如果一个格式正确的消息被发送给jws.queue,那么WebLogic Workshop运行时间将会把它分派给Web服务对象,就像它是通过HTTP到达的一样。

我的例子中Web服务对象是EmailService.jws,它展示了helloAsync操作。helloAsync操作用JavaMail API发送一个在WebLogic使用JavaMail的响应消息。

记住,你是通过发送XML(一般是SOAP)消息和Web服务进行通信的,本例中的作业就是把包含收件电子邮件的XML消息递送给目标Web服务。

传入邮件路由选择

正如前所述,我使用来自Apache Jakarta项目的James邮件服务器接收传入的电子邮件消息。我选择James是因为它的安装和配置都出奇的简单。James邮件服务器很容易通过mailets扩充,mails是相对小且简单的Java类,它处理由James接收的电子邮件消息。在James的配置文件中创建一条传送消息的mailets管道。如果消息符合mailets的匹配规则,那么消息就传递到mailet服务方法进行处理。

和James一起安装的默认配置文件通过若干反垃圾邮件(anti-spam)mailets来路由消息,以免James服务器成为一个开放中继器(open relay)。就像任何典型的邮件服务器一样,最后,消息存放在目标用户的邮箱中。我修改了这个文件配置使之不能存放消息,而是通过自定义的mailets(本人写的,权称之为ForwardToJMSQueue)路由所有消息。
下面是ForwardToJMSQueue mailet的代码:


 package com.bea.mailet;

 import weblogic.jndi.Environment;

 import org.apache.mailet.GenericMailet;
 import org.apache.mailet.Mail;

 import javax.mail.MessagingException;
 import javax.mail.internet.MimeMessage;
 import javax.naming.Context;
 import javax.naming.InitialContext;
 import javax.jms.QueueConnectionFactory;
 import javax.jms.QueueConnection;
 import javax.jms.QueueSession;
 import javax.jms.Queue;
 import javax.jms.QueueSender;
 import javax.jms.TextMessage;

 import java.util.*;

 public class ForwardToJMSQueue extends GenericMailet {

   public void service(Mail mail)
   {

     try
     {

       // Use the WebLogic convenience Environment object to
       // create an InitialContext
       Environment env = new Environment();
       Context ctx = env.getInitialContext();

       // get the WebLogic Workshop QueueConnectionFactory
       QueueConnectionFactory factory =
           (QueueConnectionFactory)ctx.lookup
               ("weblogic.jws.jms.QueueConnectionFactory");
       QueueConnection conn = factory.createQueueConnection();
       QueueSession session = conn.createQueueSession(false, 0);

       // look up the queue that is the destination for JWS requests
       Queue queue = (Queue)ctx.lookup("jws.queue");
       QueueSender sender = session.createSender(queue);

       // get the content of the arriving e-mail message
       MimeMessage mimeMsg = mail.getMessage();
       String emailMsgStr = (String)mimeMsg.getContent();

       // create a new TextMessage to send to the JWS JMS queue
       TextMessage textMessage = session.createTextMessage(emailMsgStr);

       // to target a particular JWS, pass its path as the value
       // of the "URI" text property on the JMS message. In the
       // scheme used by this mailet, the path to the JWS must
       // arrive as the Subject: of the message.
       textMessage.setStringProperty("URI", mimeMsg.getSubject());

       // send the message
       sender.send(textMessage);

       // clean up
       session.close();
       conn.close();
     }
     catch(java.lang.Exception ex)
     {
       System.out.println("Exception in ForwardToJMSQueue mailet:");
       ex.printStackTrace();
     }
   }
 }

mailet最重要的几个方面是:

l 使用Java命名和目录接口(JNDN)获得JMS队列连接工厂和目标队列本身(jws.queue)。
l 从电子邮件消息中提取内容,该内容应该是Web服务方法调用消息(SOAP消息)。
l 创建一个包含SOAP消息的JMS TextMessage对象。添加所需的"URI"消息属性,这个属性把期望的Web服务作为消息的发送目标。在这例子中,我期望每个到达的电子邮件消息的Subject:中包含Web服务的相关URL。对于我的例子中的Web服务来讲,它就是"/samples/EmailService.jws"。
l 发送消息。

消息一旦发送,WebLogic Workshop分配器将收到消息并且调用Web服务。通过访问
edocs.bea.com的构建一个JMS客户端这个主题,来得到更多关于如何通过JMS调用WebLogic Workshop Web服务的方法。

EmailService.jws Web服务

EmailService.jws Web服务仅有惟一的方法--helloAsync,它是单任务的:发送电子邮件消息到方法参数提供的地址中。JavaMail API是用来创建并发送发件电子邮件消息。

下面是EmailService.jws Web服务的代码:


 import weblogic.jws.control.JwsContext;

 import javax.mail.Message;
 import javax.mail.Session;
 import javax.mail.Transport;
 import javax.mail.Multipart;
 import javax.mail.internet.InternetAddress;
 import javax.mail.internet.MimeMessage;
 import javax.mail.internet.MimeBodyPart;
 import javax.mail.internet.MimeMultipart;
 import javax.naming.InitialContext;
 import java.util.Date;

 public class EmailService
 {
     /** @jws:context */
     JwsContext context;

     /**
      * @jws:operation
      * @jws:protocol jms-soap="true"
      * @jws:conversation phase="start"
      */
     public void helloAsync(String callbackAddress)
     {
         String dateStr = (new Date()).toString();
         String addr = callbackAddress.trim();

         try
         {
             // do JNDI lookup of mail session
             InitialContext ctx = new InitialContext();
             Session session = (Session)ctx.lookup("jws.mail.response");

             // set up message headers
             Message msg = new MimeMessage(session);
             msg.setFrom();
             msg.setRecipients(Message.RecipientType.TO,
                               InternetAddress.parse(addr, false));
             msg.setSubject("EmailService.jws Response (" +
                            dateStr + ")");
             msg.setSentDate(new Date());

             // Content is stored in a MIME multi-part message
             // with one body part
             MimeBodyPart mbp = new MimeBodyPart();
             mbp.setText(dateStr + ": " + addr);
             Multipart mp = new MimeMultipart();
             mp.addBodyPart(mbp);
             msg.setContent(mp);

             Transport.send(msg);
         }
         catch(Exception ex)
         {
         }

         context.finishConversation();
     }
 }

Web服务最重要的几个方面是:

l helloAsync方法具有@jws:protocol jms-soap="true"属性,可以在WebLogic Workshop中根据Web服务或方法逐个进行配置以支持协议和消息格式。默认情况下,from-get、form-post以及http-soap是启动的,而其它的协议/格式组合被禁用。我需要启用jms-soap组合,允许Web服务接收经由JMS到达的收件SOAP消息。为获得更多的关于@jws:protocol属性的内容,请参见edocs.bea.com的@jws:protocol Tag
l Web服务使用JNDI查找我在WebLogic服务器单独配置的JavaMail会话对象。当我配置JavaMail会话对象时,将它命名为JNDI的名称jws.mail.response。为了获得更多关于WebLogic服务器中JavaMail支持方面的信息,请参见edocs.bea.com的在服务器应用程序中使用JavaMail

监视Web服务调用

如果你用WebLogic Workshop开发过Web服务,那很可能是用Test View来测试该服务。Test View是一个servlet,为所有WebLogic Workshop Web服务提供测试工具。像调用Web服务的方法一样,每次调用的信息都添加到历史日志中,并且每个日志条目都被检查,以便了解到达的请求和响应结果。

你也许不知道Test View不管调用从哪里产生,都会显示它们。如果显示了一个Web服务的Test View,然后从不同的客户端(比方说,在前一专栏中描述的Java客户端)调用该服务,这个调用将会显示在日志中(当你刷新浏览器时)而且可能被检测。

获得示例消息

除了监视Web服务调用之外,Test View作为一种Web服务的方式,也被大量用来获得消息模板。
下面是EmailService.jws Web服务的Test View的Test XML页面:



helloAsync方法的输入字段由带消息模板的Test View servlet进行初始化(我已经用一个真实的电子邮件地址替换了参数占位符)。然而,只有SOAP消息的body才是必须发送到Web服务,以调用该服务的对象。当你从Test View调用这种方法时,Test View将会在SOAP消息中包装这个内容。但是如果想从外部客户端发送消息给Web服务,你需要整个SOAP消息。如果继续从Test XML页面调用该方法,就可以看到完整的SOAP消息。下面所示的就是调用日志条目:

在服务请求部分,你可以看见发送到Web服务的完整的SOAP消息,只要从Test View拷贝这个文本并把它作为来自你客户端测试消息的消息模块使用。本文的例子中把它作为电子邮件消息的正文使用。

此方法的局限性

本例的目的是演示使用HTTP作为Web服务调用消息的传输协议没有什么特别之处。对HTTP的历史的偏见源于两个事实:第一代Web服务实现是基于Web服务器和应用服务器,对于他们来说,HTTP是固有的协议,网络管理员舒适地管理HTTP的缺省端口80的安全,然而,管理由其它协议使用的任意端口的安全就不是那么轻松了。

本文描述的解决方案进行得不是很彻底,尽管在这个例子中,收件Web服务调用消息的路径恰好符合WebLogic Workshop模型是因为SMTP 和 JMS都是固有的异步协议。经过JMS提交的消息从来不会进行异步响应,这是由消息队列的本性决定的:不存在返回到发送异步响应的客户端的路径(准确的说,存在响应客户端的异步响应,但是当消息被放置在队列中时该响应就立即发生,并且与void类型方法的返回值总是一样的,该返回值来自queue,而不是来自消息使用者)。电子邮件也是如此,它通过多级存储转发模式进行某些事务。因此,事实上,到达的消息经过了两次异步处理:一次是邮件服务器;而另一次是JMS分配器,而这并不表示出了问题。 然而对于发件方面,这种解决方案还是不理想的。我的示例Web服务构造了一条任意的消息,并将它发送到客户端特定的地址。换句话说,我在Web服务里面使用了一条支持路径,但在Web服务外面则采取了一条捷径。如果SMTP是一个完全支持Web服务调用的协议,WebLogic Workshop将能够接收电子邮件地址作为一个回叫位置,并且将自动地发送错误(一般是收件消息中错误有关的SOAP故障)和回叫调用给指定的地址。

如果你对本文有什么意见和疑问,或对WebLogic Workshop或Web服务有疑问,认为它们可以作为将来专栏的主题,请按照下面的地址发给我。

原文URL: http://dev2dev.bea.com/articles/DJ_002.jsp

 作者简介
John Bley是Wily Technology 的软件工程师。他有丰富的 Java 编程和架构经验。为了撰写本文,他总结了 Wily 的企业客户的经验,Wily负责管理复杂的 J2EE 环境。
dot dot dot

dot
  作者其它文章
您对本文的评价
您对这篇文章的看法如何?
太棒了!5分 不错啊 4分 一般般 3分 有待提高 2分 不好 1分

   
相关产品