4. 创建Store企业应用
本节将利用前面安装的Tuscany Eclipse插件开发Store企业应用。这个应用的组合图如图-14
图-14
你将要创建的这个组合构件应用由四个服务组成,组合的服务提供在线Store服务。Catalog service提供浏览商品服务,它依赖决定货币类型是USD还是EUR的currencyCode属性配置。Catalog服务并不直接做货币转换,而是引用Currency Converter提供的货币转换服务。ShoppingCart提供将选择的商品添加到购物篮的REST服务。Catalog服务采用JSONRPC绑定,而ShoppingCart服务采用ATOM绑定。最后Store构件作为基于浏览器的用户接口提供前端服务。Store服务通过JSONRPC绑定引用Catalog服务,通过ATOM绑定引用ShoppingCart服务。
4.1. 创建Java项目
单击工具栏中的New Java Project按钮加载新建Java工程对话框。工程名称设置为store,工程布局(Project Layout)选择Create separatefolders for sources and class files。
图-15
按提示到下一步,在Libraries选项卡中点击“Add Library...”按钮,把Tuscany Library添加到此Project中。
图-16
点击完成按钮后,store工程如图-17
图-17
4.2. 构建服务
分别创建名称为services,ufservices的Java包
图-18
图-19
services包放置常规的服务,而ufservices包放置你创建的组合应用的前端服务。
4.3. Calalog
在这一小节中你将创建Catalog服务接口及其实现。在services包中新建Catalog接口,其内容如下
package services;
import org.osoa.sca.annotations.Remotable;
@Remotable public interface Catalog { Item[] get(); } |
接着在services包中创建Catalog接口的实现CatalogImpl,CatalogImpl类内容如下
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工程如图-20
图-20
注意:图-20中的红叉是因为CurrencyConverter接口还没建。
4.4. CurrencyConverter
在services包中新建CurrencyConverter接口及其实现CurrencyConverterImpl
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); } |
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工程如图-21
图-21
4.5. ShoppingCart
在这一小节中你将创建Item模型对象,Cart,Total及ShoppingCart服务实现。
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; } } |
package services;
import org.apache.tuscany.sca.data.collection.Collection; import org.osoa.sca.annotations.Remotable;
@Remotable public interface Cart extends Collection<String, Item> {
} |
package services;
import org.osoa.sca.annotations.Remotable;
@Remotable public interface Total { String getTotal(); } |
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); } } |
建完后store工程如图-22
图-22
4.6. Store
在这一节中我们将创建Store服务的用户前端,它是基于WEB浏览器的,为整个Store服务提供前端UI功能。
在ufservices包中新建store.html文件,内容如下
<html> <head> <title>Store</title>
<script type="text/javascript" src="store.js"></script>
<script language="JavaScript">
//@Reference var catalog = new Reference("catalog");
//@Reference var shoppingCart = new Reference("shoppingCart");
//@Reference var shoppingTotal = new 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 οnlοad="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应用Project Explorer如图-23所示
图-23
4.7. 组合服务
这一节我们将前面创建的服务实现组合起来,以提供Store组合构件服务。
在src目录中新建store.composite文件,内容如下
<?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应用Project Explorer如图-24所示
图-24
4.8. 使用服务
通过上面的配置,我们就可以运行Store服务了,在Store应用Project Explorer中选择store.composite文件,右击鼠标,选择Run as->Tuscany,运行Store应用。Eclipse控制台截图如图-25
图-25
接下来从浏览器加载应用,使用http://localhost:8080/store/store.html访问Store服务。
图-26
图-27
由于ShoppingCart服务使用ATOM绑定,所以可以点击查看Shopping Cart的ATOM feed内容。
图-28
图-29
图-30