[Adobe开发者中心]构建Tour de Flex实况控制台的服务站点

这是来自Adobe开发者中心的一篇文章,原文地址是:

http://www.adobe.com/devnet/flex/articles/serverside_tourdeflex_dashboar...

RIAMeeting特将此文整理翻译后与读者分享:

Greg WilsonDamien Mandrioli都在今天写了日志记录新的Tour de Flex 实况控制台(Tour de Flex real time dashboard)。Greg的灵感来自于“Tour de Flex”,并把他的想法在控制台中付诸实现。关于创建这个项目的经历,他在自己的博客上写了这段故事。Damien (来自于IBM/ILOG)在控制台的客户端编写上做出了极为出色的工作,包括在控制台上使用了非常酷的ILOG Elixir组件,并且他也分享了他的整个开发过程在他的博客上。

我在这个项目中的贡献就是底层实现部分的实时消息传递(real-time messaging)。下面我也将分享这个创建过程的详细信息。

首先预览一下工作流…

workflow

在这个工作流中,我们结合了PHP和Java的原因是有一段历史的。在Tour de Flex的最初版本中,还和Java没有任何关系:Greg坚持直接从他的PHP页面中载入示例的数据(示例ID和时间戳)。后来如图所示,我们增加了LiveCycle Data Service来支持控制台推送数据的需求,并且我们趁这个机会将一些代码(比如数据库持久性)从PHP中迁移到了Java。注意这里我们使用了LCDS来获取更好的性能以及高端通道的可测量性,但是这个应用也同样可以部署在BlazeDS上。

一个非常简单的结构就是客户端直接连接LCDS。比如,客户端可以请求一个远程对象,这样可以直接发送加载完毕的示例数据(示例ID和地理位置)到达消息的目的地。另一种方法就是,客户端可以使用一个Producer对象直接发布信息到目的地。因为一些逻辑(比如定位IP地址和持续数据)在传递信息到发起请求的客户端之前,已经被服务端执行了,如果你使用这个方法,就要写一个自定义的消息适配器。

我们可能在未来会使用一个或两个上述的方式简化工作流,下面的是目前正在使用的servlet的源代码(为了简洁起见,删除了日志和非必要的代码):

  1. package com.adobe.tdf;
  2.  
  3. import java.io.IOException;
  4. import java.io.PrintWriter;
  5. import java.util.Date;
  6.  
  7. import javax.servlet.ServletConfig;
  8. import javax.servlet.ServletException;
  9. import javax.servlet.http.HttpServlet;
  10. import javax.servlet.http.HttpServletRequest;
  11. import javax.servlet.http.HttpServletResponse;
  12.  
  13. import com.maxmind.geoip.Location;
  14. import com.maxmind.geoip.LookupService;
  15.  
  16. import flex.messaging.MessageBroker;
  17. import flex.messaging.messages.AsyncMessage;
  18. import flex.messaging.util.UUIDUtils;
  19.  
  20. publicclass TDFServlet extends HttpServlet {
  21.  
  22. // Unique clientID for the message service
  23. private String clientID = UUIDUtils.createUUID();
  24.  
  25. // The geocoding service
  26. protected LookupService lookupService;
  27.  
  28. // A DAO to store sample requests in a database
  29. protected SampleRequestDAO dao = new SampleRequestDAO();
  30.  
  31. // The LCDS message broker
  32. protected MessageBroker messageBroker;
  33.  
  34. // The LCDS messaging destination where real time sample requests information is pushed
  35. protected String destination;
  36.  
  37. publicvoid init() throws ServletException {
  38.  
  39. ServletConfig config = getServletConfig();
  40. destination = config.getInitParameter("messaging.destination.name");
  41. String path = config.getInitParameter("geocoding.database.path");
  42. try {
  43. // Load the geocoding database in init() to make sure we load it only once
  44. lookupService = new LookupService(path, LookupService.GEOIP_MEMORY_CACHE);
  45. } catch (IOException e) {
  46. // We swallow the exception here. If the database is not available, the feed
  47. // will still work but won't provide the location info.
  48. }
  49. }
  50.  
  51. protectedvoid doGet(HttpServletRequest request, HttpServletResponse response)
  52. throws ServletException, IOException {
  53.  
  54. if (messageBroker == null)
  55. {
  56. messageBroker = MessageBroker.getMessageBroker(null);
  57. }
  58.  
  59. SampleRequest sampleRequest = new SampleRequest();
  60.  
  61. try {
  62. sampleRequest.setSampleId(Integer.parseInt(request.getParameter("sampleId")));
  63. } catch (Exception e) {
  64. String message = "A valid sampleId is required to process this request";
  65. thrownew RuntimeException(message);
  66. }
  67.  
  68. sampleRequest.setTimestamp(new Date());
  69.  
  70. String ipAddress = request.getParameter("ipAddress");
  71.  
  72. // Geolocate the IP address and add the info to the message
  73. if (lookupService != null && ipAddress != null)
  74. {
  75. Location location = lookupService.getLocation(ipAddress);
  76. if (location != null)
  77. {
  78. sampleRequest.setLatitude(location.latitude);
  79. sampleRequest.setLongitude(location.longitude);
  80. sampleRequest.setCountry(location.countryCode);
  81. sampleRequest.setCity(location.city);
  82. }
  83. }
  84.  
  85. try {
  86. dao.create(sampleRequest, ipAddress);
  87. } catch (RuntimeException e) {
  88.  
  89. }
  90.  
  91. String subtopic = request.getParameter("subtopic");
  92. if (subtopic == null) subtopic = "flex";
  93.  
  94. // Publish the message to specified destination and subtopic.
  95. AsyncMessage msg = new AsyncMessage();
  96. msg.setDestination(destination);
  97. msg.setHeader("DSSubtopic", subtopic);
  98. msg.setClientId(clientID);
  99. msg.setMessageId(UUIDUtils.createUUID());
  100. msg.setTimestamp(System.currentTimeMillis());
  101. msg.setBody(sampleRequest);
  102. messageBroker.routeMessageToService(msg, null);
  103.  
  104. PrintWriter out = response.getWriter();
  105. out.println("<html><body>ok</body></html>");
  106.  
  107. }
  108.  
  109. }

这个Servlet负责下面的工作:

1.  定位请求观看示例的客户端的IP地址。我们当前使用MaxMind Geolocation API。这个API使用起来非常简单,而且返回的数据看起来相当精确。

2.  保存已加载完毕的示例的信息到数据库。我们保持跟踪历史数据,来支持之后可能增加的数据可视化项目。

3.  发送加载完毕的示例的数据到一个消息的目的地。这个servlet使用了Message Service Java API来直接的推送信息到Flex终端(第97行到第104行)。注意类似的API也可以用在ColdFusion,所以CF开发者可以使用CF页面来代替这个servlet来推送信息到客户端。

通道

信息的目的地被设置为支持多种不同的通道:RTMP,长连接和正常连接。客户端的开发者可以自行决定采用哪种通道连接服务端。比如,如果你想使用RTMP作为主通道,在RTMP连接失败的时候转为长连接,在长连接失败的时候转为正常连接,你可以这样设置你的客户端的ChannelSet:

  1. <mx:ChannelSet id="channelSet"><mx:RTMPChannel id="rtmp" url="rtmp://hostname:2037"/>
  2. <mx:AMFChannel url="http://hostname/context/messagebroker/amflongpolling"/>
  3. <mx:AMFChannel url="http://hostname/context/messagebroker/amfpolling"/>
  4. </mx:ChannelSet>

关于作者

Christophe Coenraets是Adobe的技术布道者,他专注于富因特网应用和企业集成。他从2003年Flex的初级产品开始就工作于Flex。在之前的Macromedia,他的工作职责是JRun,即企业级的J2EE应用服务。在加入Macromedia之前,Christophe在Sybase管理Java和互联网应用。Christophe在过去的15年里都是世界范围内的大会的知名演讲者。他的博客是http://coenraets.org

riadevID: 
您给予的分值: None 平均分: 10 ( 2 票)

关于空指针异常

确认已经配置了BlazeDS环境,确认messaging-config.xml配置正确,否则创建不了messageBroker实例。

messageBroker.routeMessageToS

messageBroker.routeMessageToService(msg, null);的时候会出现空指针异常是什么原因引起的?

这flex文章翻译的不错

这flex文章翻译的不错,我会一直关注的,谢谢!
欢迎访问http://www.belle7.com

发表新评论

  • 网页地址和电子邮件地址将会被自动转换为链接。
  • 行和段被自动切分。
  • 您可以使用下面的标签来高亮显示您的评论内容: <code>, <blockcode>. 可以使用"[foo]".旁边显示标签样式 "<foo>" PHP代码可以用这样的区块来包含<?php ... ?> or <% ... %>

更多格式化选项信息

验证区域
系统验证:请回答下面的问题