级别: 中级 Andrew Borley (borley@uk.ibm.com), 软件工程师, IBM UK
2007 年 8 月 28 日 服务组件体系结构(Service Component Architecture,SCA)是一组规范,描述了用于使用面向服务的体系结构来构建应用程序和系统的模型。了解如何将服务组件体系结构用于构建 Mashup 应用程序。
引言
服务组件体系结构提供了组合、重用和技术方面的灵活性和部署选择,使其成为了用于构建和运行 Mashup 应用程序的理想环境。本文将介绍 Alert Aggregator 示例;此示例是采用 Web 2.0 接口的 Mashup 样式应用程序,是最近针对 Apache Tuscany SCA Native 运行时开发的。
Alert Aggregator 示例应用程序
 | | 本文中的代码清单和图 1 版权属于 The Apache Software Foundation 2007。 |
|
Alert Aggregator 示例是基于 Web 的应用程序,可将不断变化数据的各个源聚合为一系列“警报”,显示在自动更新的网页中。警报源可以包括 RSS/Atom 新闻 Feed、POP3/IMAP 电子邮件、NNTP 新闻组、SOAP 服务(如股票报价)等等。
SCA 关系图
下面的关系图详细说明了 SCA 组合、组件、外部客户机和数据源,并在所有这些部分之间进行连接,从而组合为应用程序。
图 1. SCA 关系图
示例在 Tuscany 运行时中运行,而这个运行时本身又承载在 Apache HTTPD 服务器上。服务器侦听对 SCA REST 服务的 HTTPD 请求,并在接收到此类请求时调用 Tuscany 运行时。Tuscany 然后执行相应的组件(由连接决定)并以 HTTP 响应的形式返回结果。这意味着标准 Web 浏览器发出的调用能够调用 SCA 服务,而这正是本例中出现的情况:Web 浏览器显示 HTML 页面,其中包含 JavaScript Ajax 代码。Ajax 调用 SCA 组件,并显示所得到的结果数据。
SCA 元素
Alerter Composite 提供应用程序的主要功能,将数据从不同的源聚合到一起(基于配置)并将来自 REST 服务的经过比较的数据作为 XML 呈现。组合包含以下组件:
- RSS/Atom Checker 组件从指定的 RSS 或 Atom Feed 获取最新的文章,并将文章转换为指定的更为简单的 XML 格式。
- POP Checker 组件从指定的 POP3 电子邮件帐户获取最新的电子邮件,同样也将电子邮件转换为指定的 XML 格式。
- NNTP Checker 组件获取 NTTP 服务器上指定新闻组的最新张贴内容。此组件尚未在 Alert Aggregator 示例中实现。
- Web Service Checker 组件调用指定的 Web 服务,并将返回的数据转换为简单的 XML 格式。此组件尚未在 Alert Aggregator 示例中实现。
- Alert Config 组件管理应用程序的配置,保留关于要检索的 RSS/Atom Feed、要检查的 POP 电子邮件帐户等等的详细信息。
- Alert Checker 组件基于 Alert Config 组件提供的配置数据管理对各个 Checker 组件的调用。Checker 组件所返回的 XML 数据聚合为单个 XML 文档,并使用 REST 服务绑定向客户机公开。
Display Composite 提供所需的功能来将 Alerter Composite 提供的 XML 转换可阅读的格式,如可在 Web 浏览器中显示的 HTML。组合包含以下组件:
- HTML Formatter 组件从 Alerter Composite 检索配置 XML 和最新警报 XML,然后基于此数据生成 HTML 表。可以从网页通过对公开此组件的 REST 服务进行 Ajax 调用来检索此HTML。
- Text Formatter 组件也从 Alerter Composite 检索 XML 数据,并将其转换为可供人阅读的文本,供本地客户机访问。此组件尚未在 Alert Aggregator 示例中实现。
组合 SCDL
SCA 定义了一种 XML 语言服务组件定义语言(Service Component Definition Language,SCDL),该语言允许开发人员定义组件并将其连接起来。随后将由 SCA 运行时处理和执行此 XML,以生成运行的 Mashup。通过对 SCDL 进行小的改动,可方便地对组件进行重新排列或替换,或添加新功能,从而创建新 Mashup。Alerter Composite 的 SCDL 如下所示:
清单 1. Alerter Composite SCDL
<composite xmlns="http://www.osoa.org/xmlns/sca/1.0" name="sample.alerter">
<service name="AlerterService">
<binding.rest/>
<reference>AlertCheckerComponent</reference>
</service>
<component name="AlertCheckerComponent">
<implementation.python module="AlertCheckerImpl" scope="composite"/>
<reference name="alertConfigService">AlertConfigComponent</reference>
<reference name="rssCheckerService">RSSCheckerComponent</reference>
<reference name="popCheckerService">POPCheckerComponent</reference>
</component>
<component name="RSSCheckerComponent">
<implementation.python module="RSSCheckerImpl" scope="composite"/>
</component>
<component name="POPCheckerComponent">
<implementation.python module="POPCheckerImpl" scope="composite"/>
</component>
<component name="AlertConfigComponent">
<implementation.python module="AlertConfigImpl" scope="composite"/>
</component>
</composite>
|
Display Composite 的 SCDL 如下所示:
清单 2. Display Composite SCDL
<composite xmlns="http://www.osoa.org/xmlns/sca/1.0" name="sample.display">
<service name="HTMLDisplayService">
<binding.rest/>
<reference>HTMLDisplayComponent</reference>
</service>
<component name="HTMLDisplayComponent">
<implementation.python module="HTMLDisplayImpl" scope="composite"/>
<reference name="alertService">AlerterService</reference>
<property name="showNumberOfReadAlerts">20</property>
</component>
<reference name="AlerterService">
<binding.rest/>
</reference>
</composite>
|
通过这两个 SCDL 文档,可以看到所有的组件都采用 Python 实现(即 implementation.python 元素所指定的内容),组合服务使用 REST 绑定公开。这些选择不是 SCA 运行时强制要求的,任何组件都可以使用运行时所支持的任意语言实现,Tuscany Native 运行时目前支持的语言包括 C++、Python、Ruby 和 PHP。例如,示例中包括 POPChecker 组件的 Ruby 实现,可以使用其替换 Python 实现。同样,也可以方便地更改用于将组件作为服务公开的绑定,直接修改 SCDL 即可。例如,Alerter Composite 还可以作为 SOAP Web 服务公开。
SCDL 是定义组件间的连接的唯一地方;组件实现代码并不知道哪些组件或服务会调用自己,也不知道自己调用的是哪些组件或引用。这意味着组件是完全可重用的;可以在多个 Mashup 中使用相同的实现,直接以不同方式配置其引用和属性,即可得到新的 Mashup。
组件实现
RSSChecker 组件的 Python 实现如下所示:
清单 3. RSSChecker Python 代码
import feedparser, datetime, xml.etree.ElementTree, re
# Get new entries from an RSS/Atom feed
def getNewAlerts(rssaddress, lastchecktimestamp):
print "RSSCheckerImpl.getNewAlerts() called", rssaddress, lastchecktimestamp
# Get and parse the RSS/Atom data
d = feedparser.parse(rssaddress)
newalertsxml = "<alerts "
newalertsxml += xmlns=\"http://tuscany.apache.org/samples/alerter\">\n"
lastcheckdate = datetime.datetime.min
if lastchecktimestamp:
lastcheckdate = datetime.datetime.strptime(lastchecktimestamp,
"%Y-%m-%dT%H:%M:%S")
# Get default values from the feed attributes
defaultTitle = d.feed.get('title', 'RSS feed article')
defaultLink = d.feed.get('link', 'http://incubator.apache.org/tuscany')
defaultSummary = 'No information provided'
# Go through each entry in the feed and add it to the XML
for entry in d.entries:
if entry.has_key('date'):
(year, month, day, hour, minute, second, millisecond,
microsecond, tzinfo) = entry.date_parsed
entrydate = datetime.datetime(year, month, day, hour, minute, second)
else:
entrydate = datetime.datetime.now()
# Only append the latest alerts
if (entrydate > lastcheckdate) :
newalertsxml += "<alert><title>"
newalertsxml += stripXML(entry.get('title', defaultTitle)) + "</title>\n"
newalertsxml += "<address>" + entry.get('link', defaultLink)
newalertsxml += "</address>\n"
newalertsxml += "<date>" + entrydate.isoformat() + "</date>\n"
newalertsxml += "<summary>"
newalertsxml += stripXML(entry.get('description', defaultSummary))
newalertsxml += "</summary>\n"
newalertsxml += "</alert>\n"
newalertsxml += "</alerts>"
return xml.etree.ElementTree.XML(newalertsxml)
# Strips XML elements and entities out of a supplied string
def stripXML(data):
elementsRemoved = re.sub("<.*?>","", data)
entitiesRemoved = re.sub("&.*?;", " ", elementsRemoved)
asciiEncoded = entitiesRemoved.encode('ASCII', 'replace')
returnData = asciiEncoded.replace('&', 'and')
return returnData
|
通过此代码,可以发现使用了 ElementTree Python 库来返回 XML 对象。Tuscany SCA Native 运行时知道如何处理 ElementTree 对象,会将其转换为恰当的 XML 表示形式,以供传输或在其他组件中进行处理。例如,采用 Ruby 的组件实现使用 Ruby REXML 库来处理 XML 数据。
以下 Python 代码详细说明了 AlertChecker 组件实现部分的内容:
清单 4. AlertChecker Python 代码片段
import xml.etree.ElementTree, datetime
def getAllNewAlerts ():
returnXML = "<alerts xmlns=\"http://tuscany.apache.org/samples/alerter\">\n"
returnXML += "</alerts>"
returnElem = xml.etree.ElementTree.XML(returnXML)
# Use the alertConfigService to get the configuration
configElem = alertConfigService.getAlertConfig()
ns = "./{http://tuscany.apache.org/samples/alerter}"
for sourceElem in configElem.findall( ns+"source"):
sourceid = sourceElem.attrib["id"]
newAlerts = getAlerts(sourceElem)
if xml.etree.ElementTree.iselement(newAlerts):
# Add the sourceid to each alert and append to the entire list
for alert in newAlerts.findall(ns+"alert"):
alert.attrib["sourceid"] = sourceid
returnElem.append(alert)
return returnElem
...
|
上面的代码说明了如何在 Tuscany SCA Native 运行时中运行的 Python 代码中处理 SCA 引用。在上面的代码片段中,好像脚本使用了未定义的变量“alertConfigService”,但事实并非如此。Tuscany 将自动创建 Python 代理对象(名为“alertConfigService”)并将其添加到所加载的脚本中。此代理连接到 SCDL 中指定的被引用组件,因此当调用 alertConfigService.getAlertConfig() 方法时,会对所引用组件调用正确的方法。
SCA 属性以类似的方式处理,会向所加载的脚本注入 Python 对象,并会初始化为属性的指定值。
部署和运行应用程序
示例在 Tuscany SCA Native 运行时内运行,部署到 Apache HTTPD 服务器上,此服务器承载两个组合(提供其 REST 服务)并提供网页用户界面。也可以方便地将组合部署到两个独立的 HTTPD 实例。以下屏幕截图显示了所演示的示例:
图 2. Alert Aggregator 屏幕截图 1
图 2 所示的屏幕截图表明其中显示了两个 RSS Feed,数据源列表位于顶部(从 Alert Config 组件检索),最近的警报列表位于其下(使用 Alert Checker 和 RSS Checker 组件检索),再往下是显示特定警报的内联表单。
图 3. Alert Aggregator 屏幕截图 2
上面图 3 中所示的屏幕截图显示用户在向应用程序添加新警报源。在本例中,此源为 POP 电子邮件帐户。当用户单击 Add 按钮时,会通过 Alert Config 组件发送数据并添加到配置中。
图 4. Alert Aggregator 屏幕截图 3
上面图 4 中所示的屏幕截图显示了从 POP 帐户检索的电子邮件清单。用户还删除了两个 RSS 数据源中的一个。其中一封电子邮件在屏幕的底部显示。
结束语
Alert Aggregator 示例说明了可以如何使用 SCA 和 Tuscany SCA 运行时来方便地构建 Mashup 样式的应用程序。通过直接更改 SCDL 和一些代码行,即可方便地添加其他数据源,从而与当前支持的数据源一起使用。Tuscany 提供的 REST 绑定承载在 Apache HTTPD 中,这意味着 Web 浏览器可以访问 SCA 组合所提供的功能,支持基于浏览器的客户机。最后,其多语言支持意味着开发人员可以利用自己的技能和之前就有的代码来方便地将组件构建为新应用程序,而且可在以后对其进行重新安排和部署形成新的 Mashup。
Apache Tuscany 项目期待您的反馈、建议和贡献。访问 Tuscany 网站,了解如何参与到其中。
参考资料 学习
获得产品和技术
讨论
关于作者  | 
|  | Andrew Borley 是英国 IBM Hursley 的一位 IT 专家。他曾担任过各种职务,包括开发人员、团队负责人和项目经理,在 IBM 就职的 7 年中,他曾接触过各种技术。从 2001 年起,他就开始与客户协作进行 Web 服务和网格项目,他目前负责开发 Apache Tuscany 开放源代码 SOA 项目中的 SCA for C++ 实现。 |
对本文的评价
|