My FAQ,最新最全的IT技术FAQ
最新100篇 | 推荐100篇 | 专题100篇 | 排行榜 | 搜索 | 在线API文档
首 页 | 程序开发 | 操作系统 | 软件应用 | 图形图象 | 网络应用 | 精文荟萃 | 教育认证 | 未整理篇 | 技术讨论
  当前位置:> Bea专区 > WebLogic Server 8.1
漫游WebLogic Workshop 8.1
作者:佚名 时间:2005-11-23 20:20 出处:bea 责编:My FAQ
              摘要:暂无
新WebLogic Workshop 8.1包含了许多新特性,相比以前的产品有了巨大飞跃。现在除了Web服务之外,您还可以构建许多其它类型的J2EE应用。为了更好地介绍这一新版本,本文将会向您演示如何创建一个包含诸多WebLogic Workshop 8.1新特性的企业级应用。

本文假定读者具备J2EE (Java 2 企业版)的基本知识。
在本文中我们将要创建的应用的名称为"Westside 汽车销售"--一个端到端的汽车销售工具。如下图所示,该应用由多个部分组成。其中核心模块是1)Web应用前端,2)订购汽车的Web服务,以及3)处理汽车订单的制造商Web服务。这些模块依次调用那些执行应用级任务的Java控件和EJB(企业级Java Bean)。本应用的基本体系结构如下:



我们的这个应用的数据流程是这样的:首先用户进入Westside汽车销售(WAS)网站并浏览产品目录(通过一个JSP上的NetUI网格控件,该JSP由页面流中的数据库控件驱动)。用户选定了一辆自己喜欢的汽车就可以进行购买,但他必须首先登录(通过集成安全检验)。他所购买的汽车被置为"售出"状态(通过一个客户控件调用一个实体EJB),同时另外一辆同型号的汽车被添加到数据库中并被置为"待售"状态(仍是通过实体EJB)。最后,一条消息被发送到Java 消息服务(JMS)的主题上(通过JMS控件),目的是初始化另外一辆汽车的定购。用户收到购买确认信息之后就可以继续购物。

与此同时,一个消息驱动EJB得知前面发出的消息到达WAS JMS主题后,就调用WAS Web服务的方法来初始化另外一辆汽车的定购处理。WAS Web服务首先利用XMLBean构建一个"OrderCar"XML包发送给制造商。借助Web服务控件,定购新车的请求被发送到制造商Web服务上。制造商首先利用XMLBean(处理本田的是XQuery)解码XML,接着添加订单到数据库中并马上返回一个订单号。以后运送该汽车的时候,制造商的Web服务会调用WAS Web服务上的回调方法将汽车的详细信息,包括最终价格发送过去,最后WAS Web服务会使用一个实体EJB设置汽车的实际价格并将其标记为待售。
我们将会从头开始构建这个应用,并讨论各个部分是如何协作的。

数据存储

开始构建应用之前,首先需要创建我们自己的数据库和表,并向WebLogic Server域中添加一个连接池和一个JMS消息主题。在该项目中,我使用的是Microsoft SQL Server 2000,您也可以使用其它任何兼容JDBC的数据库。首先在数据库服务器中创建一个名为"WASdb"的数据库并执行下面的SQL语句来创建必要的表、存储过程、和默认数据。注意:这个SQL语句是针对Microsoft SQL的;您可能需要对它进行修改,以便可以运行在自己的数据库上。

------------------------------------
-- Westside Auto Sales Tables & View
------------------------------------

create table Cars
(
CarID int identity primary key,
Make varchar(50) not null,
Model varchar(50) not null,
Description varchar(800) not null
)
go

create table Inventory
(
SKU int identity primary key,
CarID int not null,
Price int not null,
Status varchar(50)
)
go

create view CarInventory
as
select c.CarID, Make, Model, Description, SKU, Price, Status
from Cars c, Inventory i where c.CarID = i.CarID
go

----------------------------------
-- Sample Data
----------------------------------

insert Cars select "Volkswagen", "New Beetle",
"The 2003 New Beetle is a 2-door, 4-passenger family coupe, or sports coupe,
available in 8 trims, ranging from the GL 2.0L to the Turbo S 1.8L."

insert Cars select "Mini", "Cooper",
"The new Mini Cooper is more fun than a carnival ride. Both models handle
like sports cars and the Mini Cooper S can accelerate from 0 to 60 mph in
less than seven seconds."

insert Cars select "Mercedes-Benz", "SL-Class",
"The 2003 SL-Class is a 2-door, 2-passenger luxury convertible, or convertible
sports car, available in two trims, the SL500 Roadster and the SL55
AMG Roadster."

insert Cars select "Land Rover", "Range Rover",
"The 2003 Range Rover is a 4-door, 5-passenger luxury sport-utility,
available in one trim only, the HSE."

insert Cars select "Honda", "Civic Coupe",
"The 2003 Civic Coupe is a 2-door, 5-passenger family coupe, available
in 16 trims, ranging from the DX 5-spd MT to the EX 4-spd AT w/
Front Side Airbags."

insert Inventory select 1, 18999, "Available"

insert Inventory select 2, 17597, "Available"

insert Inventory select 3, 92399, "Available"

insert Inventory select 4, 71200, "Available"

insert Inventory select 5, 12110, "Available"

------------------------------------------
-- Manufacturer Web Service Tables
------------------------------------------

create table ManufacturerOrders
(
OrderNumber int identity primary key,
SKU int not null,
Make varchar(50) not null,
Model varchar(50) not null,
Price int not null,
Status varchar(20) not null
)
go

Create table BasePrices
(
Make varchar(50) not null,
Model varchar(50) not null,
Price int not null,
primary key (Make, Model)
)
go

------------------------------------------
-- Manufacturer Web Service Tables
------------------------------------------

create procedure AddOrder ( int, varchar(50), varchar(50),
int, varchar(20))
as
set nocount on;

insert ManufacturerOrders
select , , , ,

select @ as "ID"
go

create procedure UpdateOrder ( int)
as
set nocount on

update ManufacturerOrders set Status = "Shipped" where
OrderNumber = ;

SELECT SKU, Price FROM ManufacturerOrders
WHERE OrderNumber =
go

------------------------------------------
-- Manufacturer Web Sample Data
------------------------------------------

insert BasePrices select "Volkswagen", "New Beetle", 18000
insert BasePrices select "Mini", "Cooper", 1700
insert BasePrices select "Mercedes-Benz", "SL-Class", 85000
insert BasePrices select "Honda", "Civic Coupe", 12000
insert BasePrices select "Land Rover", "Range Rover", 65000


配置域

现在需要在WebLogic Server域中创建一个数据库连接。我们将采用WebLogic示例(位于[BEAInstall Directory]WebLogic81samplesdomainsworkshop)中附带的"Workshop"域。为了添加需要的服务,请首先启动域,然后进入控制台(通常是http://localhost:7001/console)并登录(用户名:"weblogic",密码:"weblogic")。
首先配置连接池。在主页面的JDBC下面,选择"Connection Pools"。点击"Configure a new JDBC Connection Pool",然后选择数据库类型并选择驱动程序。因为将会用到事务,所以需要选择一个"XA"驱动程序。因为用的是Microsoft SQL (带有JDBC 驱动服务补丁),所以我选择了BEA's MS SQL Server Driver (Type 4XA)。请把连接池命名为"WASPool"。测试连接,然后创建它并将其部署到服务器上。因为将要用到本地事务,所以请单击刚刚创建的"WASPool",然后选择"Connections"选项卡并选择advanced options。选定"Supports Local Transactions"并单击"Apply"。

一旦创建了连接池,接着就可以创建数据源了。单击页面右上方的Home图标,选择JDBC下面的"Datasources"。单击"Configure a JDBC Data Source",用"WASDataSource"作为name和JNDI name。单击"continue"并选择"WASPool"作为连接池。最后单击"continue"和"create"。

现在需要为消息传输创建JMS主题。在控制台的左端,进入ServicesJMSServersJMSServerDestinations并配置一个新的JMS主题。设置name和JNDI name为"WASTopic"并单击"Create"。一旦新的JMS主题被创建您需要重新启动服务器。

Web应用

现在可以构建自己的应用了。我们将从Web应用开始。启动WebLogic Workshop 8.1并创建一个名为"Westside"的默认应用。WLW中的Web应用采用了一种称为页面流的新技术,该技术建立在Struts框架之上,能够把业务逻辑和显示逻辑分开。这意味着不再需要用大量代码填充JSP文件,而是把所有的代码都放到JPF中。开始构建网站的时候这一点将会给予更清楚的描述。

我们将会得到一个默认的页面流,请启动服务器并运行该页面流来体会一下。打开WestsideWeb目录下的Controller.jpf,然后单击工具栏上的play按钮。站点被编译之后您将会在测试浏览器上看到一个页面,上面显示"New Web Application Page"。我们的站点还不够有趣,但这种状况马上就会有所改观。

我们的这个应用的第一部分需要向用户展示当前的车辆目录。以往我们需要花费几小时来创建一些JSP,这些JSP用于显示结果并能够进行过滤、排序、分页等等。有了WLW这个工作就简单多了。首先需要一个RowSet控件来访问数据库中的数据。我们将把所有控件放到"WestsideWeb"目录下一个名为"Controls"的新目录下。创建这个新文件夹并右击它,然后选择NewOther File TypeRowSet Control。在RowSet控件向导中,把新控件命名为Inventory.jcx并确保指定了WASDataSource。单击"Next",选择"Query a View or Table",然后选择"CarInventory"视图。把SKU 设置成主键并单击"Create"。以上操作将会创建一个含有两个方法的数据库控件:detailsCarinventory 方法和getAllCarinventory方法。现在,在项目面板上右击刚创建的控件并选择"Generate Page Flow",将其命名为"Inventory"并单击"Create"。将会出现一组新文件并在编辑窗口中出现了"InventoryController.jpf"。单击"play",您将会看到一个功能完整的汽车目录列表,它具备了排序、分页、和过滤功能。details链接将会把您引向汽车的详细信息。以往需要几个小时的工作轻点几次鼠标就轻松完成了。

 



现在让我们完成Web界面的其它工作。首先添加一个从主页面到新页面流的链接。最好再添加一个返回主页的链接。请把链接添加到产品目录的标题栏上。因为所有页面都使用NetUI模板,所以可以在WestsideWeb esourcesjspheader.jsp文件中添加该链接,这样它就能出现在所有产品目录页面上了。添加以下代码到该文件中(添加的代码用斜体字显示):

<!-- Styled, graphical look of "bar" defined here using a repeatable image
specified as "background="bar-background.gif"" -->
<td width="100%" height="21" background="<%=request.getContextPath ()
%>/resources/images/bar-background.gif">
<a href="<%=request.getContextPath ()%>/Controller.jpf">Home</a>
|
<a href="<%=request.getContextPath ()
%>/Inventory/InventoryController.jpf">
Inventory</a>
</td>

重新运行InventoryController.jpf文件,您应该可以看到页面顶部的导航栏:



现在我们已经有了一个通用导航系统,请把该模板加到主页中去。回到WestsideWeb下的index.jsp文件并把它修改成如下样子:

<%@ page language="java" contentType="text/html;charset=UTF-8"%>
<%@ taglib uri="netui-tags-databinding.tld" prefix="netui-data"%>
<%@ taglib uri="netui-tags-html.tld" prefix="netui"%>
<%@ taglib uri="netui-tags-template.tld" prefix="netui-template"%>
<netui-template:template templatePage="/resources/jsp/grid_template.jsp">
<netui-template:setAttribute value="Home" name="title"/>
<netui-template:section name="bodySection">
<blockquote>
<h1>Westside Auto Sales</h1><br>
<a href="./Inventory/InventoryController.jpf">View our Inventory</a>
</blockquote>
</netui-template:section>
</netui-template:template>

现在添加允许用户购买汽车的代码。首先,在产品目录页面流中需要有一个"buyCar"动作。进入InventoryController.jpf的设计视图,添加一个"buyCar"动作并接受那些默认值。您可以通过右击页面并选择"New Action"来完成,也可以直接从控件面板上拖动一个Action到页面中。我们还希望有一个确认页面通知用户他们已经成功购买了汽车。添加一个名为"Confirm.jsp"的新页到页面流中(右击页面流或从控件面板上拖动一个Page)。添加一条从"buyCar"动作到新页之间的流程线。现在需要在details页面中添加一个到buyCar动作的链接。在detailsCarinventory.jsp中,把以下代码添加到网格链接代码之前(添加的代码用斜体字显示):

</table>
<br/>
<% DatabaseForm myForm = (DatabaseForm)request.getAttribute("databaseForm");
if (myForm.getStatus().equals("Available")) { %>
<netui:anchor action="buyCar" >Buy This Car
<netui:parameter name="SKU" value="{request.databaseForm.sku}" />
</netui:anchor><p>
<% } %>
<netui:imageAnchor action="showGrid" border="0"
src="/WestsideWeb/resources/images/
grid.gif">
<netui:parameterMap map="{pageFlow.sortFilterService.queryParamsMap}"/>
</netui:imageAnchor>

只有汽车可售的情况下用户才能购买它,所以需要首先确认该车没有被售出,然后才能显示链接。为了达到目的,我们首先创建一个DatabaseForm本地实例,DatabaseForm中包含了汽车的详细信息。接着就可以访问该表单的成员了。注意:进行购车的链接是指向页面流上一个动作的链接,而不是指向文件的硬链接。

添加这些代码的时候,将有一个蓝色弹出式消息框询问是否要导入Inventory.InventoryController.DatabaseForm到页面中。按下Alt+Enter表示接受。以下代码将被添加到页面中:

<% import="Inventory.InventoryController.DatabaseForm"%>

添加本文代码的时候您还会多次遇到这样的情形,请接受WebLogic Workshop提示的import语句。

如果返回到InventoryController.jpf的设计视图,您应该可以看到站点上下文中出现的新动作和新页面:



安全性
用户单击"buyCar"链接的时候,我们希望他们是作为注册用户登录的。dev2dev 网站上有许多关于安全的文章,所以这里我们仅创建一个用户并确保潜在购买者以该用户身份访问购买动作。想要创建新用户,请右击Security Roles并选择"Create New Role",把该角色命名为"WASUser"然后单击"OK"。为了保证"buyCar"动作的安全性,请打开WestsideWebWEB-INFweb.xml文件并把以下代码添加到文件尾部的</web-app>标签之前:

<security-constraint>
<display-name>Security Constraint for resources within this project.</
display-name>
- <web-resource-collection>
<web-resource-name>Security for the buyCar action
</web-resource-name>
<description>A web service secured by basic authentication
</description>
<url-pattern>/Inventory/buyCar.do</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
- <auth-constraint>
<role-name>WASUser</role-name>
</auth-constraint>
</security-constraint>
- <security-role>
<description>A general pre-defined role in WebLogic Server.
All logged in
users are mapped to this role by default.</description>
<role-name>WASUser</role-name>
</security-role>

这些代码强制用户在购车的时候必须登录。如果用户以"WASUser"身份并以"password"作为密码登录,他将可以继续购车,否则将会返回一个错误。打开WestsideWebInventoryConfirm.jsp并添加以下代码:


<%@ page language="java" contentType="text/html;charset=UTF-8"%>
<%@ taglib uri="netui-tags-databinding.tld" prefix="netui-data"%>
<%@ taglib uri="netui-tags-html.tld" prefix="netui"%>
<%@ taglib uri="netui-tags-template.tld" prefix="netui-template"%>
<netui-template:template templatePage="/resources/jsp/grid_template.jsp">
<netui-template:setAttribute value="Confirmation" name="title"/>
<netui-template:section name="bodySection">
<blockquote>
<h2>Thank you for your order.</h2><br>
<a href="InventoryController.jpf">Continue Shopping</a>
</blockquote>
</netui-template:section>
</netui-template:template>

现在需要添加应用的关键部分--把汽车置为售出并定购一辆新车。开始之前,请测试一下已有的代码。当单击buy按钮之后,您应该被强制要求登录。一旦登录成功,您将会看到确认页面。

实体企业级Java Beans
因为处理的是单辆汽车,所以与一个汽车实体打交道将比读写多个数据库字段要简单的多。利用实体EJBs可以达到这个目的。一个实体EJB代表数据库中的一条记录。我们可以通过成员变量访问它,并且通过创建新对象就可以方便地添加一条新的数据记录。

我们将使用EJB访问inventory表中的汽车数据。为此,首先右击"Westside"文件夹并选择"NewProjectJB Project",这样就添加了一个EJB项目到应用中,请把新项目命名为"WASejb"。右击WASejb文件夹并选择"New Entity Bean from Database Table",然后选择"WASDataSource",单击next,选择inventory表。单击next两次,输入"CarBean"作为bean名称、"Westside"作为包名,单击"Finish"。因为我们将会添加新的记录行到inventory表中,所以需要添加以下代码到CarBean.ejb文件的顶端(添加的代码用斜体字显示):


/**
* :automatic-key-generation
* type="SQL_SERVER"
* cache-size="0"
* name="SQL_SERVER"
*
* :entity order-database-operations="false"
enable-batch-operations="false"
* ejb-name = "CarBean"
* data-source-name = "WASDataSource"
* table-name = "Inventory"
* prim-key-class = "java.lang.Integer"
*
* :jndi-name
* local = "ejb.CarBeanHome"
*
* :file-generation local-class = "true" local-class-name = "Car"
local-home = "true" local-home-name = "CarHome" remote-class = "false"
remote-class-name = "CarRemote" remote-home = "false"
remote-home-name = "CarRemoteHome" value-class = "false"
value-class-name = "CarValue" pk-class = "true"
*/

并且,由于数据库表为我们创建了新的主键,所以需要修改该文件中的create()和ejbPostCreate方法,这样它们就不再需要任何参数:

public Java.lang.Integer ejbCreate()
throws CreateException
{
return null;
}

public void ejbPostCreate()
throws CreateException
{}

构建EJB曾经需要做很多工作。实际上,这是J2EE中最难理解的领域。我们仅仅完成了创建实体bean所需的工作。为了使用它,我们将把对bean的调用封装到一个EJB控件中,这样可以隐藏查找或创建bean这样的复杂工作。首先需要右击WASejb项目并选择"Build"来构建和部署EJB。然后,右击WestsideWeb下的"Controls"目录并选择"New Java Control"。选择EJB control,命名它为"InventoryEJB"并单击next。因为我们需要的是本地bean,所以单击"Browse local EJBs...",选择carBean,然后单击"Create"。这样我们的EJB就有了一个封装器,我们将在后面用到它。

自定义Java控件
我们不把代码写到页面流中,而是使用自定义Java控件来处理对实体bean的所有调用,将来也要这样处理JMS bean。JPF和汽车定购Web服务将会共享这个控件。为了创建该控件,请右击"Controls"目录并选择"New Custom Java Control",把它命名为"WASControlImpl",然后单击"Create"。 自定义控件包含两个文件:将控件描述成class的Java文件、包含该class具体实现代码的实现文件。所有代码都将被写入到这个实现文件中。该文件首先需要一个标志汽车已经售出的方法,这个方法将被InventoryController.jpf.中的buyCar动作调用。为了创建该方法,请右击控件设计视图并选择"Add Method"。把方法命名为"purchaseCar"。进入设计视图并按如下所示修改方法声明:

/**
* :operation
*/
public String purchaseCar(Integer SKU, String User)
{
return "";
}

该方法被调用时,用户欲购车的SKU需要连同他的用户名一起传递给方法。接着这辆车会被标记为售出并向用户发送一条消息告知他已经成功购买该车。我们将从JPF的"buyCar"动作中调用该方法。为此,首先拖动WASControl到InventoryController.jpf上,这将创建一个名为wASControl的成员变量,您可以使用它来调用控件。添加以下代码到"buyCar"动作,这些代码负责调用purchaseCar方法(添加的代码用斜体字显示):


protected Forward buyCar()
{
// Call the main control to purchase the car and order a new one
String OrderText = new String();
OrderText = wASControl.purchaseCar
(new Integer(getRequest().getParameter("SKU")),
getRequest().getRemoteUser());

// Put the message in the request string so we can show it on the JSP
getRequest().setAttribute("Message", OrderText);

return new Forward("success");
}


我们首先获取请求中的SKU及远程用户名称,然后把它们发送给自定义控件的purchaseCar方法。接着,我们得到结果信息并把它们放入请求字符串中,这样就可以读取它们并在confirm.jps中显示给用户。
重新回到WASControl.jcx的设计视图,拖动InventoryEJB.jcx到控件上。我们将会得到一个名为"inventoryEJB"的变量,使用它就可以访问InventoryEJB。添加以下代码到purchaseCar方法中,这些代码把当前汽车置为售出状态并在数据库中创建一辆新车的记录。

public String purchaseCar(Integer SKU, String User)
{
String OrderText = new String();

try{
// Use my entity bean wrapper to access the Inventory EJB
Car IBean = inventoryEJB.findByPrimaryKey(SKU);

// Can only sell the car if it is available
if (IBean.getStatus().equals("Available"))
{
// Set the status of the car to sold
IBean.setStatus("Sold to " + User);
OrderText = "Thank you for your order, " + User + ".
Your bill is +
IBean.getPrice() + ".";

// Create a new car based on the old car to
replace it in inventory
Car NewBean = inventoryEJB.create();
NewBean.setCarID(IBean.getCarID());
NewBean.setPrice(-1);
NewBean.setStatus("Waiting to be ordered");
}
else
// Opps. Someone else got it first.
OrderText = "I'm sorry. That vehicle has been sold.
Please choose another one.";

} catch (Exception e){
OrderText = "Error using EJB: " + e.getMessage();
}

return OrderText;
}

然后,当弹出提示框要求把"Westside.Car"作为一条导入语句的时候请再次按下"Alt+Enter"。回到WestsideWebInventoryConfirm.jsp,我们需要把调用生成的信息在WASControl中显示给用户。JPF把消息转换成请求流,所以我们只需从流中将其取出即可(添加的代码用斜体字显示):


<h2>Thank you for your order.</h2><br>
<%= request.getAttribute("Message") %><p>
<a href="InventoryController.jpf">Continue Shopping</a>

现在可以测试一下应用了。在汽车详细信息页面里单击buy链接,如果已经登录,您将会看见Confim.jsp上的确认。当返回产品目录时,将会看到该车已经被标记为售给该用户,同时数据库中将会出现一辆状态为"Waiting to be ordered"的新车。在下一节,我们将会使用JMS发送一条消息到消息驱动bean来向生产商定购另外一辆汽车。

Java 消息服务主题

用户购买了一辆汽车之后,我们希望从制造商那里订购另外一辆汽车来填补空缺。但不必马上定购该车,实际上,尽快返回确认信息给用户显得更为重要。我们只是想发送一条消息给汽车订购系统,通知它在空闲的时候定购一辆新车。由于消息具备非持续性连接的特性,所以这个场合十分适合JMS。
为此我们将会创建两个控件:一个向主题发送消息的Java控件、和一个用来获取消息并开始新车定购的消息驱动EJB。

首先我们需要一个将消息发到JMS主题的方法,通过创建JMS控件可以很容易地实现。右击Controls目录并选择"New Java Control"。选择"JMS"并将其命名为"MessageSender"。消息类型为"Text/XMLBean"、目的地类型为"Topic"。浏览一个send-jndi-name,选择"WASTopic"(先前在Workshop域中创建的JMS主题。)忽略接收主题(因为EJB将会接收消息),向下拖动滚动条并单击"browse"查找一个connection-factory (采用默认值:"weblogic.jws.jms.QueueConnectionFactory"),单击"Create"。返回WASControl,在设计视图中把新的"MessageSender.jcx"拖动到控件上。想要发送消息到JMS主题,我们只需在purchaseCar方法中添加以下代码即可(添加的代码用斜体字显示):

NewBean.setPrice(-1);
NewBean.setStatus("Waiting to be ordered");

// Send a message to the topic to order another car
messageSender.sendTextMessage(NewBean.getSku().toString());
}

现在我们需要监听消息的这部分,我们将采用一个消息驱动EJB来扮演该角色。返回到EJB项目中,右击"Westside"文件夹并选择"New/Message-Driven Bean",将其命名为"ListenerBean.ejb"。首先需要告诉该bean监听哪个JMS主题,在EJBGen属性页中,把destination-type设成"javax.jms.Topic" 并把destination-jndi-name设成"WASTopic"。生成Web服务之后,我们再添加代码来定购新车。现在只把以下代码添加到onMessage方法中,看看是否一切顺利。

/**
* :message-driven
* ejb-name = Listener
* destination-jndi-name = "WASTopic"
* destination-type="javax.jms.Topic"
*
*/
public class ListenerBean
extends GenericMessageDrivenBean
implements MessageDrivenBean, MessageListener
{
public void onMessage(Message msg) {

try {
// Print information
System.out.println("Got a message!");
System.out.println("Contents of the message:" +
((TextMessage)msg).getText());
} catch (Exception e) {
System.out.println("Exception in ListenBean: " + e.getMessage());
}
}
}

让我们试验一下。首先保存所有修改过的文件并重新编译EJB项目。现在运行该应用,进入车辆目录,选择一辆汽车并单击"buy"链接。您应该得到一个确认告知已经成功购买该汽车。一辆新车将被添加到产品目录中并被置为"Waiting to be ordered"状态。如果进入WebLogic Server 窗口,您将在控制台中看到一条类似如下的信息:

Got a message!
Contents of the message:11

信息的内容是已售出汽车的SKU。

Web 服务
接下来构建用于汽车定购的制造商Web服务,我们将会把它创建成一个单独的应用。请关闭Westside应用,然后选择File/New/Application并创建一个名为"CarSource"的空应用。右击"CarSource"并选择NewProjectWeb Service Project,将新项目命名为"CarSourceWS"。这就是将要接受新车请求的Web服务。为了在Web服务项目中创建一个新的Web服务,请右击CarSourceWS项目并选择New/Web Service,把新的Web服务命名为"CarSourceWS.jws"。
我们将拥有两个定购汽车的方法--一个用于定购本田汽车,另外一个用于所有其它汽车。这样做的目的是为了演示如何使用XQuery在两个不同的XML schema之间进行映射。在CarSourceWS.jws的设计视图中,右击并添加一个名为"orderHonda"的方法、以及另外一个名为"orderOther"的方法。Web服务将会采用异步回调,这样做是因为向制造商定购一辆新车时,在定购和运送之间总是有一段时间延迟。在应用中我们将会用一个定时器控件模拟这个时间延迟。在设计视图中右击并选择"Add Callback",将这个回调方法命名为"finishOrder"。

XML Schemas 和XMLBeans
为了使Westside应用和CarSource Web服务之间相互通信,需要来回传递定购汽车的信息。我们将以XML的形式传递该信息。下面是用于汽车定购的schema。


<?xml version="1.0" encoding="UTF-8"?>
<xs:schema targetNamespace="http://www.BEA-OrderCar.com"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:fn="http://www.BEA-OrderCar.com"
elementFormDefault="qualified">
<xs:element name="OrderCar">
<xs:complexType>
<xs:sequence>
<xs:element name="SKU" type="xs:int"/>
<xs:element name="Year" type="xs:int"/>
<xs:element name="Make" type="xs:string"/>
<xs:element name="Model" type="xs:string"/>
<xs:element name="Options" type="xs:string"/>
<xs:element name="Price" type="xs:int"/>
<xs:element name="OrderNumber" type="xs:int"/>
<xs:element name="Status" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>

我们并不直接使用这个XML,而是使用一个XMLBean把XML提取成一个Java类。为此,请在"CarSource"目录下创建一个名为"Schemas"的新schema项目。右击新项目并选择New/XML Schema,将其命名为"OrderCar.xsd"。粘贴上面的代码到这个新文件并单击"Save"。WebLogic Workshop 会立即为这个schema 创建一个XMLBean。我们将在Web服务的orderOther方法中使用这个新XMLBean。请按照以下代码修改方法声明:


public String orderOther(OrderCarDocument newCar)
{
return "";
}

再次按下Alt+Enter添加适当的import语句从而导入com.beaOrderCar.OrderCarDocument。

数据库控件

收到新车订单时,我们将会把它记录到数据库中,启动定时器等待10秒钟,然后接收数据库返回的信息并把它发送给请求者的回调方法。我们需要一个和数据源打交道的数据库控件。右击CarSourceWS 文件夹并创建一个名为"CSControls"的新文件夹。右击该文件夹并选择New/Java Control/Database,将它命名为"CSDataAccess",然后浏览找到WASDataSource。最后,单击"create"。该控件需要有三个方法:getPrice、createOrder、sendOrder。控件中还需要一个Order类负责传递信息给调用者。通过右击控件创建这三个方法,然后进入代码视图按如下代码编辑文件:


package CSControls;

import com.bea.control.*;
import java.sql.SQLException;

/**
* :connection data-source-jndi-name="WASDataSource"
*/
public interface CSDataAccess extends DatabaseControl,
com.bea.control.ControlExtension
{
static public class Order
{
public int SKU;
public int Price;
}

static final long serialVersionUID = 1L;

/**
* :sql statement="exec UpdateOrder {OrderNumber}"
*/
Order sendOrder(int OrderNumber);

/**
* :sql statement="exec AddOrder {SKU}, {Make}, {Model},
{Price}, {Status}"
*/
int createOrder(int SKU, String Make, String Model,
int Price, String Status);

/**
* :sql statement="Select Price from BasePrices where Make =
{Make} and Model = {Model}"
*/
int getPrice(String Make, String Model);
}

注意:在sendOrder和createOrder方法中我们调用了存储过程,在getPrice方法中我们使用了内联SQL。SendOrder方法返回SKU和价格,所以我们使用Order类传输该信息给调用者。其它两个方法只是简单地返回int值。
现在,为了在Web服务中使用该控件,请拖动控件到Web服务的设计视图上。我们将得到一个用于访问"cSDataAccess"控件的新私有变量。

定时器控件

我们将使用一个定时器控件来模拟定购延迟。在现实世界中,已定购汽车可能会经过数天到数月的时间才能运到经销商那里。此种情况下您可能不会使用异步调用,而是在调用者和发送者上使用单独的方法。
为了创建该控件,请在设计视图中右击Web服务并选择"Add Control/Timer"。命名控件为"csTimer"并将timeout设为10秒。

异步Web服务
现在添加响应订单的代码。首先创建一个变量来跟踪被定购汽车的唯一ID(在本例中它是OrderNumber)。在设计视图中右击控件并选择"Add Variable",像下面这样声明变量:

Integer OrderNumber;

现在添加一个被其他方法调用的新方法,添加以下代码到CarSourceWS.jws:


public void orderCar(int SKU, String Make, String Model, int MarkUp)
{
// Calculate Markup can be anywhere from 0 to MarkUp
double markup = Math.random()*MarkUp;
int baseprice = cSDataAccess.getPrice(Make, Model);
double markupprice = ((markup / 100.0 * ((double)baseprice)));

// Create a new order item in the DB and get the order number
OrderNumber = new Integer(cSDataAccess.createOrder
(SKU, Make, Model,
(int)(baseprice + markupprice), "On Order"));

// Start timer
csTimer.start();

return;
}

这些代码计算汽车的价格涨幅并增加到从数据库读取的基本价格上。接着我们把汽车添加到定购数据库中,并将其状态置为"On Order",然后发送信息给控制台告知该车已经被定购。最后,启动定时器等待10秒钟。

我们将会在orderOther方法中使用这个新方法(orderHonda方法将在后面处理)。按照以下代码编辑orderOther方法(被提示导入com.beaOrderCar.OrderCarDocument.OrderCar的时候请按下Alt+Enter):

/**
* :operation
* :conversation phase="start"
*/
public String orderOther(OrderCarDocument newCar)
{
// Get the info
OrderCar myCar = newCar.getOrderCar();

// Markup on exotic cars can be quite high - up to 10%
int nMarkupMax = 10;

// put a message in the console window
System.out.println("[CarSource]Ordering 1 " + myCar.getMake() + " "
+ myCar.getModel() + " from other manufacturing.");

// Create a new order item in the DB and get the order number
orderCar(myCar.getSKU(), myCar.getMake(), myCar.getModel(),
nMarkupMax);

// Send back the order number
return OrderNumber.toString();
}

注意:首先我们使用XMLBean获取传递给方法的XML数据。我们根据OrderCarDocument创建了一个"OrderCar"对象,这样就可以访问所有是成员变量的属性。这种方式十分有用而且避免了XML解析和验证。一旦获得XMLBean,我们就发送新车信息给orderCar方法,该方法将会设置OrderNumber。最后我们把OrderNumber返回给调用者。

当计时器运行了10秒之后,我们需要把该汽车标记为运出并把汽车详细信息发回给原始调用者的回调方法。为了实现onTimeout方法,请在设计视图中单击csTimer控件的onTimeout方法,然后添加以下代码到csTimer_onTimeout方法和finishOrder方法(提示导入CSControls.CSDataAccess.Order的时候请按下Alt+Enter):


public void csTimer_onTimeout(long time)
{
// Stop the timer
csTimer.stop();

// Mark the car as shipped
Order myOrder = cSDataAccess.sendOrder(OrderNumber.intValue());

OrderCarDocument myOrderDoc = OrderCarDocument.Factory.newInstance();
OrderCar retOrder = myOrderDoc.addNewOrderCar();

retOrder.setOrderNumber(OrderNumber.intValue());
retOrder.setPrice(myOrder.Price);
retOrder.setSKU(myOrder.SKU);
retOrder.setStatus("Shipped");

System.out.println("[CarSource]Order " + OrderNumber + "
Complete. Sending message back to requestor.");

callback.finishOrder(myOrderDoc);

return;
}

public interface Callback extends com.bea.control.ServiceControl
{
// Send the car order info back to the requesting web service
/**
* :conversation phase="finish"
*/
public void finishOrder(OrderCarDocument yourOrder);
}

时间过去之后,我们停止计时器并用数据库控件把汽车标记为运出,这将返回一个Order对象(定义在数据库控件中)。然后我们创建一个新的XML文档并使用XMLBean设置这个新文档的所有属性。该文档被发回到回调方法,回调方法又把它发送给请求者。注意:我们在Web服务中使用了会话。OrderOther 和orderHonda 方法启动会话,回调方法结束会话。conversation标签表明会话的整个生命周期都要保持状态,这使得我们可以处理并发请求而不必担心多线程问题。
现在可以试验一下我们的Web服务。保存所有修改过的文件,然后切换到CarSourceWS.jws 文件并单击"Start"。这将打开一个浏览窗口,该窗口提供了一个测试Web服务的接口。因为我们的方法接收XML作为参数,所有请单击屏幕顶端的"Test XML"选项卡。在orderOther部分您将得到一个示例XML参数。现在,我们可以用以下代码来定购一辆新款大众甲克虫:


<orderOther xmlns="http://www.openuri.org/"
xmlns:bea="http://www.BEA-OrderCar.com">
<bea:OrderCar>
<bea:SKU>3</bea:SKU>
<bea:Year>2003</bea:Year>
<bea:Make>Volkswagen</bea:Make>
<bea:Model>New Beetle</bea:Model>
<bea:Options>None</bea:Options>
<bea:Price></bea:Price>
<bea:OrderNumber></bea:OrderNumber>
<bea:Status></bea:Status>
</bea:OrderCar>
</orderOther>

注意:我们不必担心价格、订单号、状态,因为这些将由Web服务设置。单击orderOther按钮开始会话,您将很快得到一个XML格式的订单号:

Service Response
Submitted at Friday, July 11, 2003 4:02:04 PM PDT

<SOAP-ENV:Envelope xmlns:SOAP-ENV=
"http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<SOAP-ENV:Body>
<ns:orderOtherResponse xmlns:ns="http://www.openuri.org/">
<ns:orderOtherResult>1</ns:orderOtherResult>
</ns:orderOtherResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

同时,计时器开始倒计时。在消息日志上单击刷新,可以看到onTimeout被调用了,然后回调方法被执行了。单击callback,您可以看到返回给调用者的OrderCar的XML:

Client Callback
Submitted at Friday, July 11, 2003 4:02:13 PM PDT

<SOAP-ENV:Envelope xmlns:SOAP-ENC=
"http://schemas.xmlsoap.org/soap/encoding/"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<SOAP-ENV:Header>
<CallbackHeader xmlns=
"http://www.openuri.org/2002/04/soap/conversation/">
<conversationID>1057964523220</conversationID>
</CallbackHeader>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<ns:finishOrder xmlns:ns="http://www.openuri.org/">
<bea:OrderCar xmlns:bea="http://www.BEA-OrderCar.com">
<bea:SKU>3</bea:SKU>
<bea:Price>19162</bea:Price>
<bea:OrderNumber>1</bea:OrderNumber>
<bea:Status>Shipped</bea:Status>
</bea:OrderCar>
</ns:finishOrder>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

注意:SKU保持不变,价格和状态被更新从而反映该车已经运出。察看控制台窗口,将会看到以下信息:

[CarSource]Ordering 1 Volkswagen New Beetle from manufacturing.
[CarSource]Order 1 Complete. Sending message back to requestor.

Xquery

添加调用Web服务的代码到Westside应用之前,我们将添加一段代码来接收不同的XML包并通过XQuery将其自动翻译成OrderCar包。在现实世界中,有时几种不同的数据传输模式都是可以接受的。在本例中,可能大多数汽车销售商都使用OrderCar schema来传输汽车定购信息,但本田销售商却使用一种不同的HondaCar格式。以前,在不同schema之间进行映射的工作量是很大的。新的WebLogic XQuery工具使得这种映射变得简单。作为例子,orderHonda方法将会接收HondaCar schema并即时将其翻译成在orderOther 方法中使用的OrderCar schema。

首先我们创建orderHonda schema及其对应的XMLBean。右击Schemas项目并选择"New XML Schema",将其命名为Honda.xsd并添加以下代码到其中:

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema targetNamespace="http://www.BEA-Honda.com"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:fn="http://www.BEA-Honda.com" elementFormDefault="qualified">
<xs:element name="HondaCar">
<xs:complexType>
<xs:sequence>
<xs:element name="countrycode"
type="xs:int"/>
<xs:element name="SKU"
type="xs:int"/>
<xs:element name="model"
type="xs:string"/>
<xs:element name="options"
type="xs:string"/>
<xs:element name="engine"
type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>

把orderHonda修改成下面这样:


/**
* :operation
* :conversation phase="start"
*/
public String orderHonda(OrderCarDocument hondaCar)
{
return "";
}

和orderOther 方法一样,orderHonda方法也会标记会话的开始。仍和orderOther一样,该方法接收一个OrderCarDocument作为输入参数。但定购本田汽车的人将会以HondaCar schema格式传入。我们可以在方法中手工在两种schema间进行映射,但利用XQuery会使工作变得十分简单。为了配置映射,请切换到设计视图并双击orderHonda方法左边的箭头,你将会看到XQuery Mapper。为了将HondaCar映射为OrderCar,请单击Parameter XML 选项卡上的Choose按钮。选择Honda.xsd下的HondaCar元素并单击OK。然后单击Edit XQuery按钮来编辑映射。两种schema之间的映射十分简单,只要在XQuery屏上在SKU、Model、和Options之间拖线即可。当你把某个字段拖到另一个上面时,绿线代表连接。单击OK,然后再次单击OK。现在您拥有了一个定义在XQuery中的两种schema之间的映射。

* :parameter-xml schema-element="ns0:HondaCar" xquery::
* declare namespace ns0="http://www.BEA-Honda.com"
* declare namespace ns1="http://www.openuri.org/"
* declare namespace ns2="http://www.BEA-OrderCar.com" * <ns1:orderHonda>
* <ns2:OrderCar>
* <ns2:SKU>{data(/ns0:SKU)}</ns2:SKU>
* <ns2:Model>{data(/ns0:model)}</ns2:Model>
* <ns2:Options>{data(/ns0:options)}</ns2:Options>
* </ns2:OrderCar>
* </ns1:orderHonda>

这意味着您不必担心用户会传入一个HondaCar XML文档;您可以简单地处理该方法,就好像总是得到OrderCar XML 文档一样。现在添加其余代码到orderHonda方法中:

public String orderHonda(OrderCarDocument hondaCar)
{
// Get the info
OrderCar myCar = hondaCar.getOrderCar();

// Markup on Hondas is minimal
int nMarkupMax = 5;

// put a message in the console window
System.out.println("[CarSource]Ordering 1 " + myCar.getMake()
+ " " + myCar.getModel() + " from Honda manufacturing.");

// Create a new order item in the DB and get the order number
orderCar(myCar.getSKU(), "Honda", myCar.getModel(), nMarkupMax);

// Send back the order number
return OrderNumber.toString();
}

如同在orderOther方法中一样,我们从文档生成一个XMLBean(在本例中,HondaCar XML文档被XQuery翻译成OrderCar XML 文档),然后调用添加汽车到数据库并设置OrderNumber的方法。和orderOther方法一样,我们首先发回OrderNumber,然后启动定时器。当执行到onTimout方法时发送汽车信息给调用者。

现在再次测试Web服务。保存所有修改过的文件,确保CarSourceWS.jws位于编辑窗口,单击"start"。因为方法接收XML包,所以单击Test XML。在orderHonda方法中,请注意输入的XML是否是HondaCar格式。请按下面这样填充测试XML:


<HondaCar xmlns="http://www.BEA-Honda.com">
<countrycode>3</countrycode>
<SKU>3</SKU>
<model>Civic Coupe</model>
<options>None</options>
<engine>I4</engine>
</HondaCar>

单击orderHonda按钮,您将得到返回的订单号。如果10秒钟后点击refresh按钮,将会得到一辆带有价格信息的新车。观察控制台,您将看到如下信息,它告知我们已经成功调用了orderHonda方法:

[CarSource]Ordering 1 null Civic Coupe from Honda manufacturing.
[CarSource]Order 2 Complete. Sending message back to requestor.

从Web服务中调用Web服务
最后我们可以添加代码到前面的Westside应用中,该应用调用CarSource Web服务。开始之前需要一个描述CarSource Web服务的WSDL,这样Westside应用才能够知道如何访问CarSource方法。为了创建该文件,请右击CarSourceWS.jws 文件并选择"Generate WSDL File",这将会生成一个名为CarSourceWSContract.wsdl的文件。
现在返回Westside应用。首先创建一个java控件来和CarSourceWS对话。在WestsideWeb/Controls目录下,右击并选择Import,转到CarSource项目中的WSDL文件然后单击OK。想要创建一个Web服务java控件,只需右击WSDL文件并选择"Generate Service Control"就会生成一个可以和CarSource Web服务通信的控件。
我们还需要导入OrderCar和OrderHonda 的schema。为此,请右击Schemas项目并选择Import。从CarSource项目中选择Honda.xsd和 OrderCar.xsd并单击OK。这将创建用于构建所需XML的XMLBean。
因为我们将在CarSource Web服务中使用XQuery,所以我们需要编辑自己的服务控件,从而使它为orderHonda方法接收HondaCar schema,为orderOther 方法接收orderCar schema。为此,请打开CarSourceWSControl.jcx,删除OrderCar类(既然我们使用XMLBean),并按照以下代码修改orderHonda、orderOther、和回调方法(当被询问是否要修改文件的时候请单击OK):


public interface Callback extends com.bea.control.ServiceControl.Callback
{
/**
* :conversation phase="finish"
*/
public void finishOrder (com.beaOrderCar.OrderCarDocument OrderCar);
}

/**
* :protocol form-post="false" form-get="false"
* :conversation phase="start"
*/
public java.lang.String orderHonda
(com.beaHonda.HondaCarDocument HondaCar);

/**
* :protocol form-post="false" form-get="false"
* :conversation phase="start"
*/
public java.lang.String orderOther
(com.beaOrderCar.OrderCarDocument OrderCar);

现在可以构建car-ordering Web服务了。消息驱动EJB调用该Web服务并处理来自CarSource Web服务的汽车定购。为了创建这个Web服务,请添加一个新文件夹"WebServices"到WestsideWeb项目并添加一个名为"OrderCarFromWS.jws"的Web服务。在新Web服务的设计视图中,拖动Inventory.jcx、CarSourceWSControl.jcx、WASControlImpl.jcs到正在设计的服务上。我们的Web服务将会用到所有这些控件。设计视图看起来应该像下面这样:



首先需要一个调用CarSource Web服务的方法。右击设计界面并添加一个名为"OrderFromCS"的方法。单击方法名称进入代码视图,按如下代码修改方法:


/**
* :operation
* :conversation phase="start"
*/
public void OrderFromCS (String SKU) throws Exception
{
// Look up the make and model
Integer nSKU = new Integer(SKU);
RowSet orderCar = inventory.detailsCarinventory(nSKU);
orderCar.next();
String sMake = orderCar.getString("Make");
String sModel = orderCar.getString("Model");

// Order the car from the proper manufacturer
String OrderNumber = new String();

if (sMake.equalsIgnoreCase("honda"))
{
// order from honda method

// Prepare the XML to send to the manufacturer
HondaCarDocument orderDoc = HondaCarDocument.Factory.newInstance();
HondaCar order = orderDoc.addNewHondaCar();

order.setEngine("I4");
order.setModel(sModel);
order.setOptions("Basic");
order.setCountrycode(03);
order.setSKU(nSKU.intValue());

System.out.println("Ordering 1 " + sModel +
" from Honda manufacturer.");

OrderNumber = carSourceWSControl.orderHonda(orderDoc);
}
else
{
// order a car through the normal channel

// Prepare the XML to send to the manufacturer
OrderCarDocument orderDoc =
OrderCarDocument.Factory.newInstance();
OrderCar order = orderDoc.addNewOrderCar();

order.setMake(sMake);
order.setModel(sModel);
order.setOptions("Loaded");
order.setYear(2003);
order.setSKU(nSKU.intValue());

// Print out the message
System.out.println("Ordering 1 " + sModel +
" from other manufacturer.");

OrderNumber = carSourceWSControl.orderOther(orderDoc);
}

System.out.println("Received Order Number " + OrderNumber );

// Add the car to inventory and set the status as ordered
wASControl.AddCarToInventory(new Integer(SKU),
new Integer(OrderNumber));
}

当进入代码的时候您将被提示(通过按下Alt+Enter)添加以下的import语句:

import com.beaHonda.HondaCarDocument;
import com.beaHonda.HondaCarDocument.HondaCar;
import com.beaOrderCar.OrderCarDocument;
import com.beaOrderCar.OrderCarDocument.OrderCar;
import javax.sql.RowSet;

该方法的代码首先通过产品目录控件查找汽车的详细信息,然后判断调用CarSource Web服务的orderHonda方法还是调用orderOther方法。不论哪个方法,我们都需要首先创建将要传递的XML文档。通过XMLBean的Factory.newInstance()方法可以创建该文档。接着我们获得一个新XMLBean并用它设置XML中的属性。最后,利用Web服务控件发送XML文档给Web服务。
我们在WASControl中实现AddCarToInventory方法。请在WASControlImpl.jcx中添加以下代码:

/**
* :operation
*/
public void AddCarToInventory(Integer SKU, Integer OrderNumber)
throws Exception
{
// Set the status of the car to Ordered and the price to -1
Car IBean = inventoryEJB.findByPrimaryKey(SKU);
IBean.setStatus("Ordered: " + OrderNumber.toString());
System.out.println("Marking Car " + SKU + " as Ordered");
}

一旦汽车通过制造商的Web服务被订购了,我们就把状态置为"ordered"并设置订单号。
最后,我们需要实现回调,它将设置汽车的最终价格并将其标志为待售。在OrderCarFromCS.jws中添加以下代码:

public void carSourceWSControl_finishOrder
(com.beaOrderCar.OrderCarDocument incomingCarDoc) throws Exception
{
// Turn the XML Doc into an XMLBean
OrderCar incomingCar = incomingCarDoc.getOrderCar();
System.out.println("Receiving order number " +
incomingCar.getOrderNumber());

// Got the car back, use the main controller to set
the proper status on it
wASControl.SetCarAsReady(new Integer(incomingCar.getSKU()),
incomingCar.getPrice());
}

再次使用XMLBean访问XML文档中的信息并发送这些信息到WASControl,从而可以更新数据库。
以下代码需要被添加到WASControlImpl.jcx中,它们实现了SetCarAsReady方法:


/**
* :operation
*/
public void SetCarAsReady(Integer SKU, int Price) throws Exception
{
// Set the status of the car to Available from On Order and the price
Car IBean = inventoryEJB.findByPrimaryKey(SKU);
IBean.setStatus("Available");
IBean.setPrice(Price);
System.out.println("Marking Car " + SKU +
" as Available, Price: " + Price);
}

我们再次使用自己的EJB标致汽车为待售并设置最终价格。
剩下的工作仅是从消息驱动EJB中调用OrderCarFromCS Web服务即可。为此,我们采用use.jar文件,该文件使EJB像使用本地Java类一样使用该Web服务。保存所有改动过的文件,然后在编辑窗口中打开OrderCarFromWS.jws文件并单击"play"。当弹出测试Web服务表单时,请选择"Overview"选项卡。在多个链接中您将看到一个通往Java代理的链接、和一个通往代理支持Jar的链接。单击每个链接并在Westside应用的APP-INF/lib目录下保存结果.jar文件。关闭测试浏览器,在代码视图中从WASejb项目打开ListenBean.ejb。按照以下代码修改onMessage方法(新代码用斜体表示):

public void onMessage(Message msg) {

try {
// Print information
System.out.println("Got a message!");
System.out.println("Contents of the message:" +
((TextMessage)msg).getText());

// Order the car via the OrderCarFromWS Web Service
OrderCarFromWS_Impl CSImpl = new OrderCarFromWS_Impl();
OrderCarFromWSSoap soap = CSImpl.getOrderCarFromWSSoap();
soap.orderFromCS(((TextMessage)msg).getText());

} catch (Exception e) {
System.out.println("Exception in ListenBean: " + e.getMessage());
}
}

一旦您的代理jar被添加到应用中,想要调用OrderCarFromCS Web服务,只需使用Impl类创建一个新的soap对象并使用该soap对象调用希望调用的Web服务方法即可。当提示导入weblogic.jws.proxies.OrderCarFromWSSoap和weblogic.jws.proxies.OrderCarFromWS_Impl时请按下Alt+Enter。
到此为止我们的应用就全部完成了。我们需要重新编译EJB来保存所有修改,右击"Westside"文件夹顶部并选择"Build Application"。这将会重新编译所有文件并在服务器上重新部署应用。编译完成后,从WestsideWeb文件夹中打开controller.jpf 文件并单击"Start"。单击"View Inventory"链接并选择一辆待售汽车。单击buy链接。登录成功之后,您将进入确认页面。如果单击"continue shopping"您将会看到汽车状态被修改为"Sold to WASUser",而且创建了一辆新车等待定购。单击refresh,可以看到状态变为"ordered",当CarSource Web服务处理订单的时候又变为"available"。汽车订单处理过程中,您应该能在服务器的控制台窗口到类似下面的信息:

Got a message!
Contents of the message:12
Ordering 1 Range Rover from other manufacturer.
[CarSource]Ordering 1 Land Rover Range Rover from manufacturing.
Received Order Number 8
Marking Car 12 as Ordered
[CarSource]Order 8 Complete. Sending message back to requestor.
Receiving order number 8
Marking Car 12 as Available, Price: 70664

如果定购了一辆本田,您将看到如下信息:


Got a message!
Contents of the message:25
Ordering 1 Civic Coupe from Honda manufacturer.
[CarSource]Ordering 1 null Civic Coupe from Honda manufacturing.
Received Order Number 10
Marking Car 25 as Ordered
[CarSource]Order 10 Complete. Sending message back to requestor.
Receiving order number 10
Marking Car 25 as Available, Price: 12337

这些信息表明定购本田的时候,请求被发送给CarSource Web服务的orderHonda方法,该方法使用XQuery将请求翻译成HondaCar schema。如果想要了解该过程的工作原理,您可以在代码中设置断点并调试程序进行观察。

如同我们所体验到的,新WebLogic Workshop 8.1不仅仅是一个构建Web服务的工具。现在您可以在WLW IDE中构建多种类型的项目。它赋予您创建更复杂应用的能力,而且是在统一的编辑和调试环境下进行。

想要了解关于这篇文章的评论和问题,请通过semyan.com联系Scott Semyan。

 
首页 | 投资与合作 | 服务条款 | 隐私政策 | 收藏本站 | 设为首页 | 新用户注册 | 免责声明 | 使用帮助
Copyright ©2005-2008 myfaq.com.cn All rights reserved. www.myfaq.com.cn 版权所有