作者: 肖菁 (dev2dev ID: powerise)
[文章摘要] Workshop8.1中对EJB的支持非常不错,各种可视化的环境让EJB的开发和配置变得简单起来,美中不足的是,没有提供对BMP的向导支持。作者通过实践提供了一种让Workshop支持BMP开发和配置的方法,希望能够帮助更多的人享受Workshop带来的方便。
关键词: Workshop BMP 可视化
Wokrshop8.1是Weblogic Platform 8.1中BEA提供的开发工具,里面提供的可视化EJB开发、配置环境让开发者通过简单的操作就可以完成复杂的EJB的开发和配置工作,和Weblogic的无缝集成(直接编译、自动部署功能)让他迅速成为我开发基于Weblogic平台企业应用的好帮手。然而,不久就发现有点美中不足,Workshop中只提供了对CMP、Session Bean、Message-driven Bean的向导支持。虽然CMP/CMR越来越受欢迎,而且作用范围越来越大,然而很多时候BMP仍然是一种选择,因为BMP提供的灵活性让人无法拒绝。优秀的工具和优秀的原理无法结合给人的感觉是痛苦的,怎么办?这个问题困扰了我很久,以直到有一天,我无意中看到了Workshop中的这个选项: ,我决定试一试,看看这个功能是否可以帮助我实现在Workshop中编译和部署BMP。很幸运,我成功了,而且发现原来BMP也可以在Workshop中得到更完美的支持,包括可视化的增加、修改其它配置内容,当然还有些其他的高级支持内容。下面是我的操作全过程,希望帮助大家尽情享受Workshop带给我们的方便。
1演示环境
系 统: windows 2000
Weblogic platform: 8.1 sp2 英文版
数 据 库: MySQL 4.0.18
2准备数据库
我的数据库名为CRM,在里面建立了一个简单的表,建表语句如下:
create table company (
id int(5) primary key,
name char(250) not null,
address char(250)
);
注:为了让示例简单,我这里没有定义ID字段为自增长类型。
3简单的代码准备工作
1. 编写简单的源代码
现在我们需要准备一些简单的代码,以便完成接下来的工作,作者的源代码根目录是C:/bmp(后面将引用为%BMP_HOME%),这些代码分为三类,
- 继承自EJBHome的CompanyHome
代码如下:
package org.vivianj.wls.examples.bmp;
import javax.ejb.EJBHome;
public interface CompanyHome
extends EJBHome{}
- 继承自EJBObject的Company
代码如下:
package org.vivianj.wls.examples.bmp;
import javax.ejb.EJBObject;
public interface Company
extends EJBObject{}
- 继承自EntityBean的CompanyBean
代码如下:
package org.vivianj.wls.examples.bmp;
import java.rmi.RemoteException;
import javax.ejb.EJBException;
import javax.ejb.EntityBean;
import javax.ejb.EntityContext;
import javax.ejb.RemoveException;
public class CompanyBean implements EntityBean {
private EntityContext ctx;
public void setEntityContext(EntityContext arg0)
throws EJBException, RemoteException {
ctx = arg0;
}
public void unsetEntityContext() throws EJBException, RemoteException {
ctx = null;
}
public void ejbRemove() throws RemoveException, EJBException, RemoteException {}
public void ejbActivate() throws EJBException, RemoteException {}
public void ejbPassivate() throws EJBException, RemoteException {}
public void ejbLoad() throws EJBException, RemoteException {
}
public void ejbStore() throws EJBException, RemoteException {}
}
2. 编译源代码
设置好环境变量后,将前面编写的内容编译一下
3. 将代码打包成.jar文件
现在请用winzip或者其他工具将%BMP_HOME%下的所有文件(其实只需要其中的所有.class文件就可以了)打包成.jar文件(作者生成了org.jar,放在%BMP_HOME%下)
注:可以包含或者不包含里面的.java源代码文件
4生成EJB描述文件
代码准备好了,现在需要生成必须的EJB描述文件,这个工作当然要借助于Welbogic Builder了。
打开Weblogic Builder,打开刚生成的org.jar,Weblogic Builder提示
表示这个.jar文件中没有配置描述符文件,是否需要Weblogic Builder帮你生成一个,单击“是(Y)”按钮,Weblogic Builder就帮你生成了需要的配置描述符。单击Weblogic Builder界面上工具栏中的 图标,将修改信息保存到.jar文件中。
5导入Workshop
前面的步骤进展顺利的话,现在就可以将BMP导入到Workshop中了:
1. 打开Workshop,建立一个Application,然后建立一个EJB project
2. 在生成的EJB Project上单击右键,在弹出的上下文菜单中选择 弹出的界面如下
界面中需要指定两个内容,第一个是ejb-jar文件,我们这里就是被weblogic builder修改过的文件,也就是%BMP_HOME%/org.jar,下面的那个选择EJB中类的原文件所在的目录,这里就是%BMP_HOME%,选择完了请单击”next”按钮
3. 接下来的界面中直接单击”Finish”按钮结束
现在你可以看到Workshop中多了一个EJB,但是它默认打开了源代码编辑视图,而且没有design视图
6激动人心的时刻
不要紧,虽然是源代码视图,接下来发生的事情仍然让人激动不已:
1. 请将鼠标放到public class CompanyBean implements EntityBean 这行代码上,你看到了什么?右边的Property Editor视图中出现了和这个EJB配置相关的内容:
现在,你如果需要修改这个EJB的配置内容,可以直接在这个Property Editor中修改了(可爱的可视化操作回来了)。
2. 在源代码视图中单击右键,你看到什么?这个界面也许更有震撼力:
不但可以修改EJB相关的配置内容,你还可以通过这个功能可增加资源引用、访问角色定义、环境变量等相关内容。
3. 修改CompanyBean的代码,增加如下内容:
/*
* Created on 2004-3-23
*
* To change the template for this generated file go to
* Window>Preferences>Java>Code Generation>Code and Comments
*/
package org.vivianj.wls.examples.bmp;
import java.rmi.RemoteException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collection;
import javax.ejb.EJBException;
import javax.ejb.EntityBean;
import javax.ejb.EntityContext;
import javax.ejb.ObjectNotFoundException;
import javax.ejb.RemoveException;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
/**
* @author Administrator
*
* To change the template for this generated type comment go to
* Window>Preferences>Java>Code Generation>Code and Comments
* @ejbgen:jndi-name remote="CompanyBean"
* @ejbgen:file-generation local-class="false" remote-home-name="CompanyHome" remote-class-name="Company" remote-home="true" local-home="false" remote-class="true"
* @ejbgen:entity default-transaction="Required" prim-key-class="java.lang.Integer" read-timeout-seconds="600" table-name="companys" delay-database-insert-until="ejbPostCreate" concurrency-strategy="Database" reentrant="False" persistence-type="bmp" ejb-name="CompanyBean" trans-timeout-seconds="0" data-source-name="MyDataSource" max-beans-in-cache="1000"
* @ejbgen:resource-ref jndi-name="datasource/mysql" sharing-scope="Shareable" auth="Container" type="javax.sql.DataSource" name="jdbc/mysqlds"
* @ejbgen:env-entry value="mysqlds" type="java.lang.String" name="poolName"
* @ejbgen:env-entry value="company" type="java.lang.String" name="tablename"
*/
public class CompanyBean implements EntityBean {
private EntityContext ctx;
private DataSource dataSource;
private String tableName;
private Integer id;
private String name;
private String address;
/* (non-Javadoc)
* @see javax.ejb.EntityBean#setEntityContext(javax.ejb.EntityContext)
*/
public void setEntityContext(EntityContext arg0)
throws EJBException, RemoteException {
ctx = arg0;
try{
Context envCtx = (Context) new InitialContext().lookup("java:/comp/env");
tableName = (String)envCtx.lookup("tablename");
String poolName = (String)envCtx.lookup("poolName");
dataSource = (DataSource) envCtx.lookup("/jdbc/"+poolName);
}
catch(NamingException ne){
ne.printStackTrace();
}
}
/* (non-Javadoc)
* @see javax.ejb.EntityBean#unsetEntityContext()
*/
public void unsetEntityContext() throws EJBException, RemoteException {
ctx = null;
}
/* (non-Javadoc)
* @see javax.ejb.EntityBean#ejbRemove()
*/
public void ejbRemove()
throws RemoveException, EJBException, RemoteException {
Connection conn = null;
Statement stmt = null;
try{
conn = dataSource.getConnection();
stmt = conn.createStatement();
stmt.executeUpdate("delete from "+ this.tableName +" where id=" + this.id);
}
catch(Exception e){
e.printStackTrace();
}
finally{
try{
if (stmt != null ) stmt.close();
if (conn != null ) conn.close();
}
catch(Exception e){
e.printStackTrace();
}
}
}
/* (non-Javadoc)
* @see javax.ejb.EntityBean#ejbActivate()
*/
public void ejbActivate() throws EJBException, RemoteException {}
/* (non-Javadoc)
* @see javax.ejb.EntityBean#ejbPassivate()
*/
public void ejbPassivate() throws EJBException, RemoteException {}
/* (non-Javadoc)
* @see javax.ejb.EntityBean#ejbLoad()
*/
public void ejbLoad() throws EJBException, RemoteException {
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try{
this.id = (Integer) ctx.getPrimaryKey();
conn = dataSource.getConnection();
stmt = conn.createStatement();
rs = stmt.executeQuery("select * from "+this.tableName+" where id="+this.id);
while (rs.next()){
this.name = rs.getString("name");
this.address = rs.getString("address");
}
}
catch(Exception e){
e.printStackTrace();
}
finally{
try{
if (rs != null ) rs.close();
if (stmt != null ) stmt.close();
if (conn != null ) conn.close();
}
catch(Exception e){
e.printStackTrace();
}
}
}
/* (non-Javadoc)
* @see javax.ejb.EntityBean#ejbStore()
*/
public void ejbStore() throws EJBException, RemoteException {
Connection conn = null;
Statement stmt = null;
try{
conn = dataSource.getConnection();
stmt = conn.createStatement();
stmt.executeUpdate("update "+ this.tableName +
" set name="+this.name+",address="+this.name+" where id=" + this.id);
}
catch(Exception e){
e.printStackTrace();
}
finally{
try{
if (stmt != null ) stmt.close();
if (conn != null ) conn.close();
}
catch(Exception e){
e.printStackTrace();
}
}
}
public Integer ejbCreate(int p_id,String p_name,String p_address){
this.id = new Integer(p_id);
this.name = p_name;
this.address = p_address;
Connection conn = null;
Statement stmt = null;
try{
conn = dataSource.getConnection();
stmt = conn.createStatement();
stmt.executeUpdate("insert into "+this.tableName+" values("
+ p_id + "," + p_name + "," + p_address + ")");
}
catch(Exception e){
e.printStackTrace();
}
finally{
try{
if (stmt != null ) stmt.close();
if (conn != null ) conn.close();
}
catch(Exception e){
e.printStackTrace();
}
}
return this.id;
}
public void ejbPostCreate(int p_id,String p_name,String p_address){}
public Integer ejbFindByPrimaryKey(Integer p_id){
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
int i = 0;
try{
conn = dataSource.getConnection();
stmt = conn.createStatement();
rs = stmt.executeQuery("select * from "+this.tableName+" where id="+p_id);
while (rs.next()){
i = Integer.parseInt(rs.getString("id"));
this.name = rs.getString("name");
this.address = rs.getString("address");
}
if (i==0) throw new ObjectNotFoundException("没有编号为"+i+"的公司纪录");
}
catch(Exception e){
e.printStackTrace();
}
finally{
try{
if (rs != null ) rs.close();
if (stmt != null ) stmt.close();
if (conn != null ) conn.close();
}
catch(Exception e){
e.printStackTrace();
}
}
return new Integer(i);
}
/**
* @ejbgen:remote-home-method
*/
public Collection ejbFindCompanysByName(String p_name){
Collection c = new ArrayList();
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try{
conn = dataSource.getConnection();
stmt = conn.createStatement();
rs = stmt.executeQuery("select * from "+this.tableName+" where name like %" + p_name + "%");
CompanyBean company = null;
while (rs.next()){
company = new CompanyBean();
company.setId(Integer.parseInt(rs.getString("id")));
company.setName(rs.getString("name"));
company.setAddress(rs.getString("address"));
c.add(company);
}
}
catch(Exception e){
e.printStackTrace();
}
finally{
try{
if (rs != null ) rs.close();
if (stmt != null ) stmt.close();
if (conn != null ) conn.close();
}
catch(Exception e){
e.printStackTrace();
}
}
return c;
}
/**
* @ejbgen:remote-method
*/
public void setId(int p_id){
this.id = new Integer(p_id);
}
/**
* @ejbgen:remote-method
*/
public void setName(String p_name) {
this.name = p_name;
}
/**
* @ejbgen:remote-method
*/
public void setAddress(String p_address) {
this.address = p_address;
}
/**
* @ejbgen:remote-method
*/
public int getId() {
return this.id.intValue();
}
/**
* @ejbgen:remote-method
*/
public String getName() {
return this.name;
}
/**
* @ejbgen:remote-method
*/
public String getAddress() {
return this.address;
}
}
现在编译你的EJB工程,然后打开生成xx.jar(你的EJB工程编译后生成的.jar文件),看看这个.jar文件里面的描述配置符,是否有以下内容:
<entity>
<ejb-name>CompanyBean</ejb-name>
<home>org.vivianj.wls.examples.bmp.CompanyHome</home>
<remote>org.vivianj.wls.examples.bmp.Company</remote>
<ejb-class>org.vivianj.wls.examples.bmp.CompanyBean</ejb-class>
<persistence-type>Bean</persistence-type>
<prim-key-class>java.lang.Integer</prim-key-class>
<reentrant>False</reentrant>
<env-entry>
<env-entry-name>tablename</env-entry-name>
<env-entry-type>java.lang.String</env-entry-type>
<env-entry-value>company</env-entry-value>
</env-entry>
<env-entry>
<env-entry-name>poolName</env-entry-name>
<env-entry-type>java.lang.String</env-entry-type>
<env-entry-value>mysqlds</env-entry-value>
</env-entry>
<resource-ref>
<res-ref-name>jdbc/mysqlds</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
<res-sharing-scope>Shareable</res-sharing-scope>
</resource-ref>
</entity>
注: 作者的配置符中增加了环境变量和资源引用,如果你没有,应该看起来像这个样子:
<entity>
<ejb-name>CompanyBean</ejb-name>
<home>org.vivianj.wls.examples.bmp.CompanyHome</home>
<remote>org.vivianj.wls.examples.bmp.Company</remote>
<ejb-class>org.vivianj.wls.examples.bmp.CompanyBean</ejb-class>
<persistence-type>Bean</persistence-type>
<prim-key-class>java.lang.Integer</prim-key-class>
<reentrant>False</reentrant>
</entity>
4. 现在启动你的服务器,你会发觉这个EJB已经和你Workshop中的其他EJB一样被配置到服务器中了。
7更进一步
好了,现在BMP已经集成到了Workshop中,配置已经和CMP的支持基本一致了,开发怎么办?不要急,深入地了解一下Workshop的工作原理,一切是可以解决的:
1. 配置工作做了,如何实现远程方法呢?这是个难题,需要对Workshop有更深入的了解,不过做起来当然不困难,如果你用Workshop开发过Sessuin Bean,你应该知道你的本地方法和远程方法是通过什么来区别的,对,是标签:
- 这是表示一个方法是远程(Remote)访问方法的标签
/**
* @ejbgen:remote-method
*/
- 这是表示一个方法是本地(Locale)访问方法的标签
/**
* @ejbgen:local-method
*/
这个方法同样适用于BMP,你可以用这种标签设定力的业务方法是远程方法还是本地方法
注:作者个人猜测,Workshop中应该是使用了Xdoclet框架来编译、生成EJB项目。
2. 我们的所有准备工作和操作都是针对远程调用的,本地调用呢?Workshop仍然会自动帮你生成本地调用接口,只是需要增加配置内容,请再次将鼠标指向public class CompanyBean implements EntityBean所在的行,右边的Property Editor会出现这样的内容:
选中里面的Locale EJB后面的多选框,输入需要的JNDI Name/Bean Class Name/Home Class Name属性,然后编译,你会发现,这些类(CompanyLocale/CompanyLocalHome)仍然会自动生成。也就意味着,你也可以同时生成需要的远程和本地调用类。
8总结
Workshop8.1的可视化支持非常棒,以至于开发基于Weblogic平台应用的时候爱不释手,然而他不提供BMP的向导,使我开发BMP的时候只能借助记事本和ANT,还得忍受不停的自己重新启动应用,于是一直想找到一种解决办法,无意中的灵感解决了这个问题,所以记录了下来,希望能够帮助大家更好地享受Workshop,也希望更多的人发觉Workshop中的更好的功能,让Workshop发挥它的潜力。
作者信息:
姓名: 肖菁 (dev2dev ID: powerise)
简介: 作者目前是湖南省长沙铁道学院科创计算机系统集成有限公司软件中心软件工程师,IBM developerworks/BEA dev2dev撰稿人,主要研究J2EE编程技术、Web Service技术以及他们在websphere、weblogic、apache平台上的实现,拥有IBM 的 Developing With Websphere Studio证书。欢迎大家访问作者的个人网站: guilaida.go.nease.net