前言:
这个例子只是一个简单的HelloWord的例子。翻译是转载的。 写于2011-11-05
官网示例:
http://tuscany.apache.org/getting-started-with-tuscany-using-tuscany-eclipse-plugin.html
原文内容:
准备、设置、开始——开始使用Tuscany |
这篇文章将向你描述如何下载Tuscany,在Eclipse中将Tuscany添加到用户库中,创建一个名为Store的Java工程实例,然后运行它并通过浏览器访问它。
虽然本指南的很多图片是基于Java SCA 1.3.2版本的,但是你在操作那些必要的步骤是还是应该尽量使用最新版本。 |
“点击此处,获取本指南视频”
安装Tuscany |
你需要做的第一件事情是为你将要下载的Tuscany介质创建一个存放文件夹。
接下来,你下载最新版本的介质。登陆浏览器,输入下面网址:
最新版本 - http://cwiki.apache.org/TUSCANY/sca-java-releases.html
注意:上面地址在我访问不到,可使用:http://archive.apache.org/dist/tuscany/java/sca/
将bin文件压缩包和src文件压缩包都下载到你刚创建的文件夹中,下载后,你在文件夹中将看到以下内容:
然后,解压bin文件夹压缩包到本地,解压完成后,你将在你的硬盘上看到如下目录结构:
在Eclipse中配置Tuscany |
启动Eclipse并创建一个包含Tuscany运行所必须的所有jar包的用户库。
从菜单栏中选择Window 然后Preferences...打开参数对话框。
在对话框左侧的导航树中点击Java ,再点击Build Path,然后点击User Libraries
点击用户库对话框的右侧的New...按钮创建一个新的用户库Tuscany。
刚创建的用户库是空的,你需要通过点击右侧的Add JARs...按钮将Tuscany安装目录下的lib子目录中的所有jar包导入到新建的Tuscany用户库中。
你可能对调试Tuscany源码有兴趣,下一步我们将把Tuscany源码包和运行jar包相匹配。在用户库对话框中,下拉滚动条,直到你找到tuscany运行jar包,选择Source attachment
点击Edit... 右侧的编辑按钮,在弹出编辑对话框中点击External File...按钮,然后选中你之前下载的Tuscany的源码包。
通过点击OK 按钮,关闭本对话框和参数对话框,完成Eclipse中Tuscany的配置。
创建你的第一个综合服务程序 |
接下来,将向你展示你即将创建的综合服务程序的综合示意图。
你将创建的综合服务程序包括4个服务。所提供的综合服务是一个网上店铺。
这有一个你可以用来查询目录项的目录服务,根据货币代码配置它可以提供目录项的美元或者欧元价格。目录服务并不自己进行外汇汇兑,而是通过汇兑服务来做这项工作。这里还有购物车服务,从目录服务中选择的条目都可以被添加到其中,它被作为一个REST服务来实现的,目录服务结合JSONRPC协议实现,而购物车服务结合ATOM协议实现. 最后,这里还有一个面向用户服务,它提供基于商铺用户界面的浏览服务.商铺服务通过JSONRPC协议和ATOM协议分别使用目录服务、购物车服务。
创建一个Java工程 |
在这一步,你将在Eclipse中创建一个Java项目来管理这个综合服务程序。
点击工具条上的新建Java工程按钮,打开工程创建对话框。然后输入“store”作为工程名,然后在Project Layout 中选择Create separate folders for sources and class files。
点击Next 按钮,然后在下一界面进入Libraries 标签页。点击右侧Add Library...按钮,为工程添加TUSCANY用户库。
点击Finish 按钮,结束新建Java工程对话框,完成“store”工程的创建。
构建服务 |
首先,你需要创建2个源码包文件夹,在稍后的步骤里你将在这2个源码包中实现你的服务。
选中”store”工程,点击工具条上的新建Java包文件夹按钮打开新建包文件夹对话框。然后输入”services”作为包文件夹名,点击Finish按钮完成包文件夹的创建。
重复之前的步骤创建另一个包为”ufservices”包文件夹。现在”store”工程应该看起来如下图:
接下来,你将在”services”包中实现综合服务程序的常规服务,而在”ufservices”包中实现综合服务程序的用户交互服务。
目录服务 |
这一步,你将创建目录服务接口并实现它。
选中”services”包文件夹。然后点击新建Java类按钮旁边的下拉箭头,从下拉菜单中选中新建接口选项。在对话框中输入”Catalog”作为接口名,点击Finish按钮关闭对话框。Java编辑器将打开一个新的接口编辑窗口,使用下面代码覆盖编辑窗口原有代码。
package services; import org.osoa.sca.annotations.Remotable; @Remotable public interface Catalog { Item[] get(); } 再次选中"services"包文件夹,点击新建Java类按钮。在对话框中输入"CatalogImpl"作为类名,并引入” Catalog”接口,然后点击Finish按钮关闭对话框。 |
Java编辑器将打开一个新的类编辑窗口,使用下面代码覆盖编辑窗口原有代码。
package services; import java.util.ArrayList; import java.util.List; import org.osoa.sca.annotations.Init; import org.osoa.sca.annotations.Property; import org.osoa.sca.annotations.Reference; public class CatalogImpl implements Catalog { @Property public String currencyCode = "USD"; @Reference public CurrencyConverter currencyConverter; private List<Item> catalog = new ArrayList<Item>(); @Init public void init() { String currencySymbol = currencyConverter .getCurrencySymbol(currencyCode); catalog.add(new Item("Apple", currencySymbol + currencyConverter.getConversion("USD", currencyCode, 2.99))); catalog.add(new Item("Orange", currencySymbol + currencyConverter.getConversion("USD", currencyCode, 3.55))); catalog.add(new Item("Pear", currencySymbol + currencyConverter.getConversion("USD", currencyCode, 1.55))); } public Item[] get() { Item[] catalogArray = new Item[catalog.size()]; catalog.toArray(catalogArray); return catalogArray; } }
完成上述步骤后,”store”工程应该看起来如下图, |
提示: 类” CatalogImpl”上的红叉是因为我们还没有实现它引用”CurrencyConverter”接口。
汇兑服务 |
在这一步中,你将创建汇兑服务接口并实现它。
依照前边你所学到的步骤创建接口并实现。首先在”services”包中创建一个名为"CurrencyConverter"的接口。使用下面代码覆盖原有代码。
package services; import org.osoa.sca.annotations.Remotable; @Remotable public interface CurrencyConverter { public double getConversion(String fromCurrenycCode, String toCurrencyCode, double amount); public String getCurrencySymbol(String currencyCode); }
接下来在”services”包中创建一个名为"CurrencyConverterImpl" 的Java类,并使用下面代码覆盖原有代码。
package services; public class CurrencyConverterImpl implements CurrencyConverter { public double getConversion(String fromCurrencyCode, String toCurrencyCode, double amount) { if (toCurrencyCode.equals("USD")) return amount; else if (toCurrencyCode.equals("EUR")) return ((double) Math.round(amount * 0.7256 * 100)) / 100; return 0; } public String getCurrencySymbol(String currencyCode) { if (currencyCode.equals("USD")) return "$"; else if (currencyCode.equals("EUR")) return "E"; // "€"; return "?"; } }
完成上述步骤后,"store"工程应该看起来如下图所示。 |
购物车服务 |
在这一步中,你将创建Item、Cart和Total服务接口,以及实现ShoppingCart类。
重复之前学到的方式创建接口并实现它们。
首先在 "services"包中创建名为"Item"的Java类,并复制下面的代码覆盖原有代码。
package services; public class Item { private String name; private String price; public Item() { } public Item(String name, String price) { this.name = name; this.price = price; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPrice() { return price; } public void setPrice(String price) { this.price = price; } }
在 "services"包中创建名为" Cart "的Java接口,并复制下面的代码覆盖原有代码。 |
package services;
import org.apache.tuscany.sca.data.collection.Collection;
import org.osoa.sca.annotations.Remotable;
@Remotable
public interface Cart extends Collection<String, Item> {
} |
在 "services"包中创建名为" Total "的Java接口,并复制下面的代码覆盖原有代码.
package services;
import org.osoa.sca.annotations.Remotable;
@Remotable
public interface Total {
String getTotal();
} |
在 "services"包中创建名为" ShoppingCartImpl "的Java类,并复制下面的代码覆盖原有代码。
package services; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.UUID; import org.apache.tuscany.sca.data.collection.Entry; import org.apache.tuscany.sca.data.collection.NotFoundException; import org.osoa.sca.annotations.Init; import org.osoa.sca.annotations.Scope; @Scope("COMPOSITE") public class ShoppingCartImpl implements Cart, Total { private Map<String, Item> cart; @Init public void init() { cart = new HashMap<String, Item>(); } public Entry<String, Item>[] getAll() { Entry<String, Item>[] entries = new Entry[cart.size()]; int i = 0; for (Map.Entry<String, Item> e : cart.entrySet()) { entries[i++] = new Entry<String, Item>(e.getKey(), e.getValue()); } return entries; } public Item get(String key) throws NotFoundException { Item item = cart.get(key); if (item == null) { throw new NotFoundException(key); } else { return item; } } public String post(String key, Item item) { if (key == null) { key = "cart-" + UUID.randomUUID().toString(); } cart.put(key, item); return key; } public void put(String key, Item item) throws NotFoundException { if (!cart.containsKey(key)) { throw new NotFoundException(key); } cart.put(key, item); } public void delete(String key) throws NotFoundException { if (key == null || key.equals("")) { cart.clear(); } else { Item item = cart.remove(key); if (item == null) throw new NotFoundException(key); } } public Entry<String, Item>[] query(String queryString) { List<Entry<String, Item>> entries = new ArrayList<Entry<String, Item>>(); if (queryString.startsWith("name=")) { String name = queryString.substring(5); for (Map.Entry<String, Item> e : cart.entrySet()) { Item item = e.getValue(); if (item.getName().equals(name)) { entries.add(new Entry<String, Item>(e.getKey(), e .getValue())); } } } return entries.toArray(new Entry[entries.size()]); } public String getTotal() { double total = 0; String currencySymbol = ""; if (!cart.isEmpty()) { Item item = cart.values().iterator().next(); currencySymbol = item.getPrice().substring(0, 1); } for (Item item : cart.values()) { total += Double.valueOf(item.getPrice().substring(1)); } return currencySymbol + String.valueOf(total); } }
提示: 由于Tuscany尚未支持会话服务,因此cart被作为一个黑盒实现。cart被定义为静态的。 |
完成上述步骤后,工程”store”将看起来如下图所示。
商铺服务 |
在这一步中,你将创建面向用户服务,他可以通过Web浏览器访问,并提供与你创建的其他服务相交互的接口。
选中"ufservices" 包文件夹,右键点击,在右键菜单中选择New -> File 。在新建文件对话框中输入"store.html"作为文件名,然后点Finish按钮关闭对话框。
文本编辑器将打开一个新的文件编辑窗口,使用下面Html代码覆盖原有代码。
<html> <head> <title>Store</title> <script type="text/javascript" src="store.js"></script> <script language="JavaScript"> //@Reference var catalog = new tuscany.sca.Reference("catalog"); //@Reference var shoppingCart = new tuscany.sca.Reference("shoppingCart"); //@Reference var shoppingTotal = new tuscany.sca.Reference("shoppingTotal"); var catalogItems; function catalog_getResponse(items) { var catalog = ""; for (var i=0; i<items.length; i++) { var item = items[i].name + ' - ' + items[i].price; catalog += '<input name="items" type="checkbox" value="' + item + '">' + item + ' <br>'; } document.getElementById('catalog').innerHTML=catalog; catalogItems = items; } function shoppingCart_getResponse(feed) { if (feed != null) { var entries = feed.getElementsByTagName("entry"); var list = ""; for (var i=0; i<entries.length; i++) { var content = entries[i].getElementsByTagName("content")[0]; var name = content.getElementsByTagName("name")[0].firstChild.nodeValue; var price = content.getElementsByTagName("price")[0].firstChild.nodeValue; list += name + ' - ' + price + ' <br>'; } document.getElementById("shoppingCart").innerHTML = list; if (entries.length != 0) { shoppingTotal.getTotal(shoppingTotal_getTotalResponse); } } } function shoppingTotal_getTotalResponse(total) { document.getElementById('total').innerHTML = total; } function shoppingCart_postResponse(entry) { shoppingCart.get("", shoppingCart_getResponse); } function addToCart() { var items = document.catalogForm.items; var j = 0; for (var i=0; i<items.length; i++) if (items[i].checked) { var entry = '<entry xmlns="http://www.w3.org/2005/Atom"><title>item</title><content type="text/xml">' + '<Item xmlns="http://services/">' + '<name xmlns="">' + catalogItems[i].name + '</name>' + '<price xmlns="">' + catalogItems[i].price + '</price>' + '</Item>' + '</content></entry>'; shoppingCart.post(entry, shoppingCart_postResponse); items[i].checked = false; } } function checkoutCart() { document.getElementById('store').innerHTML='<h2>' + 'Thanks for Shopping With Us!</h2>'+ '<h2>Your Order</h2>'+ '<form name="orderForm">'+ document.getElementById('shoppingCart').innerHTML+ '<br>'+ document.getElementById('total').innerHTML+ '<br>'+ '<br>'+ '<input type="submit" value="Continue Shopping">'+ '</form>'; shoppingCart.del("", null); } function deleteCart() { shoppingCart.del("", null); document.getElementById('shoppingCart').innerHTML = ""; document.getElementById('total').innerHTML = ""; } function init() { catalog.get(catalog_getResponse); shoppingCart.get("", shoppingCart_getResponse); } </script> </head> <body onload="init()"> <h1>Store</h1> <div id="store"> <h2>Catalog</h2> <form name="catalogForm"> <div id="catalog" ></div> <br> <input type="button" onClick="addToCart()" value="Add to Cart"> </form> <br> <h2>Your Shopping Cart</h2> <form name="shoppingCartForm"> <div id="shoppingCart"></div> <br> <div id="total"></div> <br> <input type="button" onClick="checkoutCart()" value="Checkout"> <input type="button" onClick="deleteCart()" value="Empty"> <a href="../ShoppingCart/Cart/">(feed)</a> </form> </div> </body> </html>
完成这些步骤后,"store"工程将看起来如下图所示
组织服务 |
既然你已经实现了所有必须的服务,那么你可以把他们组织在一起,提供商铺综合服务。结构配置存储在一个后缀为.composite的文件中。
选中"store"工程的"src"文件夹,右键点击,在右键菜单中选择New-> File,在新建文件对话框中输入”store.composite”作为文件名,然后点击Finish 按钮关闭对话框。
文本编辑器将打开一个新的文件编辑窗口来创建结构配置文件,使用下面内容覆盖原有代码。
<?xml version="1.0" encoding="UTF-8"?> <composite xmlns="http://www.osoa.org/xmlns/sca/1.0" xmlns:t="http://tuscany.apache.org/xmlns/sca/1.0" xmlns:s="http://store" targetNamespace="http://store" name="store"> <component name="store"> <t:implementation.widget location="ufservices/store.html" /> <service name="Widget"> <t:binding.http uri="http://localhost:8080/store" /> </service> <reference name="catalog" target="Catalog"> <t:binding.jsonrpc /> </reference> <reference name="shoppingCart" target="ShoppingCart/Cart"> <t:binding.atom /> </reference> <reference name="shoppingTotal" target="ShoppingCart/Total"> <t:binding.jsonrpc /> </reference> </component> <component name="Catalog"> <implementation.java class="services.CatalogImpl" /> <property name="currencyCode">USD</property> <service name="Catalog"> <t:binding.jsonrpc uri="http://localhost:8080/Catalog"/> </service> <reference name="currencyConverter" target="CurrencyConverter" /> </component> <component name="ShoppingCart"> <implementation.java class="services.ShoppingCartImpl" /> <service name="Cart"> <t:binding.atom uri="http://localhost:8080/ShoppingCart/Cart" /> </service> <service name="Total"> <t:binding.jsonrpc uri="http://localhost:8080/Total"/> </service> </component> <component name="CurrencyConverter"> <implementation.java class="services.CurrencyConverterImpl" /> </component> </composite>
完成上述步骤后,工程”store”应该看起来如下图所示。
启动服务 |
在这一步中,你将创建Tuscany运行你建立的综合商铺服务的启动代码。
选中"store"工程,点击工具条上的新建Java源码包按钮,启动新建包文件对话框。使用此对话框创建一个新的名为"launch"的包文件夹。
选中”launch”包,点击新建Java类按钮。在对话框中输入”Launch”作为类名,在复选框中选择创建main方法,然后点击Finish 按钮,结束对话框。
Java编辑器将打开一个新的Java类编辑窗口,使用下面代码覆盖原有代码。
package launch; import org.apache.tuscany.sca.host.embedded.SCADomain; public class Launch { public static void main(String[] args) throws Exception { System.out.println("Starting ..."); SCADomain scaDomain = SCADomain.newInstance("store.composite"); System.out.println("store.composite ready for big business !!!"); System.in.read(); System.out.println("Stopping ..."); scaDomain.close(); System.out.println(); } }
恭喜你完成了你的第一个综合服务程序,现在,是时候让它运行了。
使用服务 |
在这一步,你将运行并使用你创建的商铺综合服务程序。
首先选中"store"工程的"launch"包中的"Launch"类,右键点击,在右键菜单中选中Run As-> Java application ,Tuscany运行环境将启动并加载商铺综合服务程序到它的运行域中。
Eclipse控制台将输出如下信息:
然后登陆你的浏览器,输入如下网址:
http://localhost:8080/store/store.html
打开综合服务程序的用户交互服务界面。
既然购物车服务是结合ATOM协议实现,你也可以通过点击样式切换图标来使用ATOM形式查看销售内容,你得到的ATOM样式:
使用浏览器回退按钮,重新回到商铺页面。
然后,你可以检查并完成你的订单。
恭喜你,你已经使用Tuscany SCA技术实现了一个简单的,灵活的,可重复使用的商铺程序。