服务组件体系架构(Service Component Architecture,SCA)允许您开发和组装由独立组件组成的面向服务的体系架构(Service-Oriented Architecture,SOA)解决方案,而不管这些组件的实现和环境如何。SCA 是一项主要的 SOA 活动,并正在成为 OASIS 标准。Apache Tuscany 为 SCA 应用程序的开发和操作提供了易于使用的开放源代码基础结构。本文向您介绍如何使用基于 Web 的 Tuscany 域管理器 UI 和代码管理 SCA 域,以及如何使用域管理 UI 部署由 SCA 组件组成的 SOA 解决方案。
引言
SCA 组合应用程序中的组件可以在网络中的不同节点上运行。在 Apache Tuscany 中,可以使用 SCA 域管理一组节点。在 SCA 中,组合、组件、其实现和运行它们的节点属于一个所谓的 SCA 域。诸如 Tuscany 等 SCA 实现提供了管理工具,允许系统管理员管理域中的 SCA 构件。使用域可为您提供在将节点添加到域时指定节点安装特征(例如主机和端口)的灵活性,而不是在组合文件中指定这些特征。本文演示如何通过 SCA 域管理由许多 SCA 组件组成的应用程序。了解将 SCA 应用程序添加到域所涉及到的每个步骤。
本文中使用的示例是“Getting started with Tuscany”指南(请参见参考资料部分提供的相关链接)中的商店应用程序。虽然“Getting started with Tuscany”指南使用了 Eclipse 来部署应用程序,但是本文将向您介绍如何在实际生产环境中运行同一个应用程序。本文使用一个无需附加的中间件要求即可在独立 Tuscany 运行时中运行的应用程序来演示所需的步骤。
系统要求
确保您已经:
- 下载并在某个目录中本地安装了 Tuscany 分发包,例如 /tuscany-sca-1.3.1。
- 安装了 Java Platform 2, Standard Edition (J2SE) 1.5。
应用程序包
在开始部署解决方案之前,您需要获得解决方案的安装存档。这些存档包含 SCA 贡献包 (contribution)、组合应用和 SCA 组件,下面的部分将简要描述这些概念。该商店解决方案包含三个 Eclipse 项目:
- assets 包含所有的服务和 store UI 的必需 Java™ 实现(请参见图 1)。
图 1. assets 项目
- web-services 包含了描述 Web 服务目录和流通性的组合应用(请参见图 2)。
图 2. web-services 项目
- store 包含商店组合应用,如图 3 所示。
图 3. store 项目
将这些项目作为 JAR 文件导出到 c:\repository 目录中。如果下载完整的 Tuscany 1.3.1 分发包,您将在 Tuscany 分发包目录的 tutorial 子目录中发现已经导出的该商店示例的 JAR 文件。这些文件包括:
- /tuscany-sca-1.3.1/tutorial/assets/target/tutorial-assets.jar
- /tuscany-sca-1.3.1/tutorial/store/target/tutorial-store.jar
- /tuscany-sca-1.3.1/tutorial/web-services/target/tutorial-web-services.jar
基本概念
在继续之前,让我们简要描述一下以下 SCA 和 Tuscany 概念:
- 贡献包 (Contribution):描述组合服务应用程序的组合文件和项目构件的集合。典型的贡献包包括 SCA 构件:一个或多个组合文件、Java 类和接口文件、HTML 文件等等。贡献包可以是某个单独的组合、目录,或者是某个 JAR、WAR 或 EAR 存档。在此例中,您有三个贡献包:
- tutorial-assets.jar 包含其他组件使用的类。
- tutorial-web-services.jar 包含描述 Web 服务目录和流通性的组合。
- tutorial-store.jar 包含描述该商店解决方案的组合。
图 4. 商店应用程序的总体组合
图 5. 商店应用程序的贡献包
在图 4 中,商店组合包含在 tutorial-store.jar 贡献包中,目录和流通性组合包含在 tutorial-web-services.jar 贡献包中,导入实现包含在 tutorial-assets.jar 贡献包中。store.composite 引用包含在 tutorial-web-services.jar 贡献包中的组合所描述的组件。 - 组合应用:描述构成应用程序的组件、每个组件提供的服务、组件对其他组件提供的服务的引用,以及联系它们的连接。有些组合包括在其他组合中。
- 可部署的组合应用:为进行部署而打包在一起的顶级组合。本文示例中的 store.composite、catalog.composite 和 currency.composite 全都是可部署的组合。
- 节点:包装 Tuscany 运行时,该运行时由 Tuscany 分发包库组成。在 Tuscany 中,每个 SCA 可部署组合在一个节点中运行。每个节点使用某个贡献包、某个组合和运行节点的环境的属性(例如主机和端口)进行配置。
- 域:在其中配置贡献包、组合和节点的范围。
域中的所有 SCA 资源——贡献包、组合和节点——全都是可通过 HTTP 进行访问的 Web 资源。这些资源的集合可通过 Atom 进行访问,并且可以使用 Atompub 进行管理。这是 SCA 和 Tuscany 标准。(有关 Atom 发布协议的描述,请参阅参考资料。)
部署步骤
将 SCA 组件安装到 Tuscany 域涉及到以下步骤:
- 启动域管理器应用程序。
- 向我们的域添加贡献包。
- 添加组合。
- 为组合添加节点。
- 启动节点。
让我们在下面几个部分中分别介绍这些步骤。
启动域管理器应用程序
- 选择您希望用作域管理器应用程序工作目录的目录。对于此示例,让我们将其命名为 /tuscany/admin。
- 切换到该目录并执行以下命令:
java -jar \tuscany-sca-1.3.1\modules\tuscany-node2-launcher-1.3.1.jar domain - 打开浏览器窗口并转到域管理器主页。如果是在本地主机上启动域管理器,则域管理器的主页地址为 http://localhost:9990/ui/home。
- 在主页中,从顶部的菜单中单击 Contributions。如果域管理器正确地启动,您应该看到如图 6 所示的页面。
图 6. 空域
添加贡献包
现在您需要添加包含应用程序构件的贡献包。要成功添加和使用某个贡献包,域管理器和运行应用程序的节点都必须能够访问该贡献包,因为它们需要在运行时加载这些构件。如果所有组件都位于相同主机上,则可以指定文件路径。在分布式部署中,您可以使用以下配置之一:
- 使贡献包在存储库中可用,可从所有节点和域管理器应用程序对其进行访问。该存储库可以是简单的 HTTP 服务器、Apache Maven 存储库或 Subversion 存储库,并通过 URL 进行引用。
- 使共享包在运行域和节点的计算机上通过 FTP、网络文件系统 (NFS) Samba 或任何其他文件共享机制本地可用。
第一个选项是首选选项,因为它允许多人参与分布式 SCA 域。
为简单起见,在此示例中,让我们假设所有节点在同一主机上运行。在适当的时候,我们将指出本地和分布式部署之间的差异。
- 在添加贡献包之前,请选择每个贡献包的贡献包 URI。例如,对于 tutorial-assets.jar,可以使用贡献包 URI http://myassets(请参见图 7)。
图 7. 添加贡献包
- 单击 Add。该贡献包现在应该已经添加到域,并出现在贡献包列表中。
- 使用各自的 URI(例如 http://myws 和 http://mystore)分别对 tutorial-web-services.jar 和 tutorial-store.jar 重复上述步骤。如果正确添加了贡献包,您现在应该看到如图 8 所示的列表。
图 8. 带有所有已添加的贡献包的 Contributions 页面
在此示例中,您使用 GUI 将贡献包添加到了 SCA 域。还可以使用程序添加贡献包。在 Tuscany 1.3.1 中,这可以通过将包含贡献包的贡献包名称和 URI 的表单发送到域管理器 URL(<domainURL>/workspace)来完成。例如,要为 tutorial-web-services.jar 贡献包发送的条目类似于清单 1。
清单 1. 用于添加贡献包的示例条目
<?xml version='1.0' encoding='UTF-8'?> <entry xmlns='http://www.w3.org/2005/Atom'> <title>Contribution - http://myws</title> <id>http://myws</id> <link href="file:/c:/repository/tutorial-web-services.jar"/> </entry> |
可以使用清单 2 中的代码将贡献包添加到 SCA 域。
清单 2. 用于添加贡献包的示例代码
String contributionURI = "http://myws"; String contributionLocation = "file:/c:/repository/tutorial-web-services.jar"; String domainURL = "http://localhost:9990"; try { String entry = "<?xml version=\'1.0\' encoding=\'UTF-8\'?>"+ "<entry xmlns=\'http://www.w3.org/2005/Atom\'>" + "<title>Contribution - " + contributionURI +"</title>" + "<id>" + contributionURI+ "</id>" + "<link href=\"" + contributionLocation + "\" />" + "</entry>"; post(domainURL+"/workspace", entry); } catch (MalformedURLException e1) { // from post() method e1.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } |
在清单 2 中,contributionLocation 是贡献包存储库中或磁盘上的贡献包存档的 URL。在本文使用的示例中,tutorial-web-services.jar 的贡献包位置将是 file:/c:/repository/tutorial-web-services.jar。
清单 2 使用了 post() 方法。这个本地方法使用 Java java.net.URLConnection 类将字符串发送到某个 URL。(有关用于将字符串发送到 URL 的代码,请参阅参考资料。)将此表单发送到 URL 时,将 URLConnection 对象的 Content-Type 请求属性设置为 "application/atom+xml",如清单 3 所示。
清单 3. 设置 URLConnection 对象的 Content-Type 请求属性
URL url = new URL (targetURL); URLConnection conn = url.openConnection(); conn.setDoInput (true); conn.setDoOutput (true); // Disable use of caches. conn.setUseCaches (false); conn.setRequestProperty("Content-Type","application/atom+xml"); [...] |
添加组合
下一步是将组合添加到域。此示例中共有三个组合:
- catalogs
- currency
- store
首先添加 catalogs.composite。观察该组合的内部可以看到,其目标命名空间为 http://services。它位于您刚才使用命名空间 http://myws 添加的 tutorial-web-services.jar 贡献包中。
- 在域管理器网页上的菜单中,单击 Composites。
- 输入如图 9 所示的 catalogs.composite 信息:
图 9. 添加组合
这里的命名空间和名称标识贡献包中的该组合,而贡献包 URI 则是您在前一步中为贡献包提供的 URI。 - 单击 Add。该组合将出现在页面顶部的列表中。
- 重复上述步骤添加 currency.composite 和 store.composite。如果正确完成所有操作,您将看到如图 10 所示的内容。
图 10. 带有已添加的组合的 Composites 页面部分
还可以通过脚本或程序添加组合。在此示例中,您可以通过将清单 4 中的 XML 发送到 URL http://localhost:9990/composite,从而将 catalogs.composite 添加到域。
清单 4. 用于添加组合的示例条目
<?xml version='1.0' encoding='UTF-8'?> <entry xmlns="http://www.w3.org/2005/Atom"> <title>composite:http://myws;http://services;catalogs</title> <id>composite:http://myws;http://services;catalogs</id> </entry> |
标题和 ID 需要包含如下语法的字符串: composite:contribution-namespace;composite-namespace;composite-name.
清单 5 显示了从 Java 程序中完成此任务所需要的代码。
清单 5. 用于添加组合的示例代码
String compositeName = "catalogs"; String compositeNamespace = "http://services"; String contributionURI = "http://myws"; String domainURL="http://localhost:9990"; String id = "composite:"+contributionURI+";"+compositeNamespace+";"+compositeName; String entry= "<?xml version=\'1.0\' encoding=\'UTF-8\'?>" + "<entry xmlns=\"http://www.w3.org/2005/Atom\">" + "<title>" + id +"</title>" + "<id>" + id + "</id>" + "</entry>"; try { post(domainURL+"/composite", entry); } catch (Exception e) { e.printStackTrace(); } |
添加节点
最后一个步骤是为每个组合创建节点。请记住,节点提供在其中运行组合的 Tuscany 运行时环境。在此步骤中,您需要为节点指定主机和端口。也可以在组合本身中指定此信息。但是,务必要注意的是,在分布式环境中,在组合中省略此信息并在节点创建过程中指定此信息,可以实现更高的应用程序组件部署灵活性。这样做意味着,您不会将组合与其部署位置绑定,并且在某个时候需要将组合移动到不同的主机或端口时,您将不需要更改此信息。通常,应用程序开发人员不知道将在其中安装应用程序的环境中有哪些端口可用。然而在此步骤中,需要提供可用的端口。
- 单击页面顶部的 Cloud 链接。
- 为 catalogs.composite 创建节点。
如果打算在本地主机上运行节点,请在 URL 中指定 localhost 并选择可用的端口。由于您的目录节点在独立 Tuscany 环境中运行,您可以指定任何可用的 TCP/IP 端口。如果将 catalogs 组合中的组件实现为 Web 应用程序,则节点将在 Web 容器中运行,并且您必须指定 Web 容器中配置的相应 URL。
如果打算在远程主机上运行节点,您需要确保远程主机已安装了 Tuscany 运行时,并且用于运行节点所必需的贡献包可通过您在添加贡献包时指定的 URL 进行访问。
在此例中,让我们使用本地主机(请参见图 11)。
图 11. 添加节点
- Node name:您可以使用任何名称。
- Node URI:此选项指定您希望用于运行节点的主机和端口。
- Composite namespace 和 Composite name:这两个选项标识您在为其创建节点的组合。这是您在添加组合时输入的相同命名空间和名称。
- Contribution URI:这是您在第一步中添加的对应贡献包的 URI。
- 单击 Add。该节点将出现在节点列表中。
- 类似地,为 currency 和 store 组合添加节点。如果正确地添加了节点,您将看到如图 12 所示的页面。
图 12. 带有已添加的节点的 Cloud 页面部分
您还可以通过将清单 6 中的条目发送到位于 cloud 上下文根的域,从而在 Java 程序中将节点添加到域。在此示例中,您可以通过将清单 6 所示的条目发送到 http://localhost:9990/cloud,从而添加 catalogs.composite 的节点。
如果在上面的步骤中手动添加节点,您可以单击节点的名称。您将看到清单 6 所示的条目的内容确切对应于您单击该节点时所看到的内容。这是描述该节点的组合文件。其中包括节点名称(在此例中为 MyCatalogsNode)、您在为其创建节点的组合(在此例中为 catalogs)、为其创建节点的组合的命名空间(这里为 http://services),以及在支持该节点与其他节点之间通信的绑定中指定的节点的主机和端口信息。
清单 6. 用于添加节点的示例条目
<?xml version='1.0' encoding='UTF-8'?> <entry xmlns="http://www.w3.org/2005/Atom"> <id> composite:http://tuscany.apache.org/cloud;http://tuscany.apache.org/cloud;MyCatalogsNode </id> <content type="text/xml"> <composite xmlns="http://www.osoa.org/xmlns/sca/1.0" xmlns:t="http://tuscany.apache.org/xmlns/sca/1.0" targetNamespace="http://tuscany.apache.org/cloud" xmlns:c="http://services" name="MyCatalogsNode"> <component name="MyCatalogsNode""> <t:implementation.node uri="http://myws" composite="c:catalogs"/> <service name="Node"> <binding.ws uri="http://localhost:8081"> <t:binding.http uri="http://localhost:8081"/> <t:binding.jsonrpc uri="http://localhost:8081"/> <t:binding.atom uri="http://localhost:8081"/> </service> </component> </composite> </content> </entry> |
请注意,此示例将 http://localhost 用于节点的 URI。如果将在与域管理器的主机不同的计算机上启动节点,则需要指定将运行节点的计算机的名称,而不是指定 localhost。
清单 7 中的示例 Java 代码将清单 6 中的条目发送到域。
清单 7. 用于将节点添加到域的示例代码
String compositeName = "catalogs"; String contributionURI = "http://myws"; String compositeNamespace = "http://services"; String nodeName = "MyCatalogsNode"; String domainURL="http://localhost:9990"; String host = "localhost"; String port = "8081"; String nodeIdEntry = "composite:" + "http://tuscany.apache.org/cloud" + ";" + "http://tuscany.apache.org/cloud" + ';' + nodeName; String addNodeEntry = "<?xml version=\'1.0\' encoding=\'UTF-8\'?>" + "<entry xmlns=\"http://www.w3.org/2005/Atom\">" + "<id>" + nodeIdEntry + "</id>" + "<content type=\"text/xml\">" + "<composite xmlns=\"http://www.osoa.org/xmlns/sca/1.0\"\n" + "xmlns:t=\"http://tuscany.apache.org/xmlns/sca/1.0\"\n" + "targetNamespace=\"http://tuscany.apache.org/cloud\"\n" + "xmlns:c=\""+ compositeNamespace + "\"\n" + "name=\""+nodeName + "\">\n\n" + "<component name=\"" +nodeName +"\">\n" + "<t:implementation.node uri=\""+contributionURI + "\" composite=\"c:" + compositeName +"\"/>\n" + "<service name=\"Node\">" + "<binding.ws uri=\"http://"+host+":"+port+"\"/>\n" + "<t:binding.http uri=\"http://"+host+":"+port+ "\"/>\n" + "<t:binding.jsonrpc uri=\"http://"+host+":"+port+"\"/>\n" + "<t:binding.atom uri=\"http://"+host+":" + port +"\"/>\n </service>\n" + "</component>\n</composite>\n</content>\n</entry>"; try { post(domainURL+"/cloud", addNodeEntry); } catch (Exception e) { e.printStackTrace(); } |
启动节点
现在可以启动节点了。可以采用多种方法启动 Tuscany 中的 SCA 运行时节点:
- 选择某个节点并从上面所示的 UI 中单击 Start。但是,除非远程主机正在运行 Tuscany 运行时,否则此方法不适用于远程节点。
- 在节点主机的命令行输入以下命令:
java -jar <tuscany-install>/modules/tuscany-node2-launcher-1.3.1.jar <domainURL>/node-config/<nodeName>
其中 <tuscany-install> 是您安装 Tuscany 分发包的目录。例如,c:\tuscany-sca-1.3.1;<domainURL> 是域管理器的 URL,例如 http://localhost:9990;<nodeName> 是您在创建节点时输入的节点名称,例如 MyCatalogsNode。由于您是在运行节点的主机上发出命令,您可以在这里使用 localhost,如清单 8 所示。 - 在 Java 程序中,使用清单 8 中的代码。
清单 8. 用于启动节点的示例代码
import org.apache.tuscany.sca.node.launcher.LauncherException; import org.apache.tuscany.sca.node.launcher.NodeLauncher; import org.apache.tuscany.sca.node.SCANode2; ... NodeLauncher nodeLauncher = NodeLauncher.newInstance(); String domainURL = "http://localhost:9990"; // could be read from input argument String nodeName = "MyCatalogsNode"; SCANode2 node; try { node = nodeLauncher.createNode(domainURL+"/node-config/"+nodeName); node.start(); } catch (LauncherException e) { System.out.println("Exception starting node"); e.printStackTrace(); } ... |
请注意,清单 8 中的代码要求将 <tuscany-install>/lib 目录中的 Tuscany 库添加到项目的类路径。
图 13 显示了启动节点的命令的示例输出。在此输出中,所显示的节点 URL 表明了运行节点的实际主机名称,而 Tuscany 运行时则安装在 c:\tuscany\tuscany-sca-1.3.1 目录中。
图 13. 启动节点
测试应用程序
现在可以在 Web 浏览器中测试应用程序了。该应用程序在您为 store.composite 添加节点时所选择的端口上运行。您将其命名为 MyStoreNode。例如,如果是在本地主机上运行应用程序,您可以将浏览器指向位于 http://localhost:8083/ui/store.html 的应用程序(请参见图 14)。
图 14. 商店应用程序
您现在可以使用该应用程序从目录中选择商品,将商品添加到购物车,清空购物车,以及付款后离开。
结束语
您了解了如何使用 Tuscany 域管理器应用程序在 SCA 域中部署 SCA 应用程序。在此示例中,您在没有 Web 容器或应用程序服务器的 J2SE 中运行 Tuscany 运行时。对于更复杂的配置,SCA 域还可以包括运行 IBM WebSphere Application Server、IBM WebSphere Process Server、Apache Geronimo、Apache Tomcat 或其他应用程序服务器的节点。后续的相关文章将进一步深入介绍有关如何将组合应用程序部署到这些不同环境的细节。(责任编辑:A6)