改进的Oracle Jpublisher可以将数据库实体映射到Java和Web服务。
编写客户端和中间层的Java与J2EE应用程序来表示数据库实体,如用户定义的SQL对象类型和集合类型时,如果你需要手工完成所有编码,这将是非常具有挑战性和易于出错的工作。另一种办法则是你可以使用Oracle JPublisher工具来完成,该工具自动根据你输入的命令行(或根据在Oracle JDeveloper集成开发环境下的鼠标点击)自动产生相应的Java类。
本文中,我将概要介绍JPublisher并描述它是如何简化将数据库实体映射到Java的过程,包括你无法从Java Database Connectivity (JDBC)直接使用的类型。然后我将展示如何通过一或两个JPublisher命令将数据库的操作和商务逻辑映射到你的Java客户端、J2EE组件和Web服务客户端。最后,我将描述JPublisher如何简化从数据库内部调用外部Web服务的过程。
Jpublisher概述
Oracle JPublisher是一个用于在Java和SQL之间转换和交换结构化对象数据的工具,它还可以访问其他的数据库资源,如PL/SQL包和Java存储过程。它生成Java类来表示数据库实体,如SQL对象和操作、PL/SQL包和过程以及服务器端Java类。你可以通过JDBC在你的Java客户端、servlet、JavaServer Pages (JSP)、Enterprise JavaBeans (EJB)和Web服务中使用这些生成的类。
JPublisher 可以生成表示以下数据库实体的类:
用户定义的SQL对象类型。对于每个对象类型,JPublisher为表示该对象的类生成一个type.java文件。它提供访问程序方法,用以获取和设置该对象类型的每个属性。还有,如果你的对象类型包含了作为存储过程而实现的方法,则JPublisher将生成封装器方法在对象实例上调用这些方法。
对象引用类型(REF 类型)。 对于一个SQL对象引用类型,JPublisher生成一个typeRef.java文件来建立该Java对象类型的引用模型。它包括通过一个对象引用来访问实际的对象值的方法。
用户定义的SQL集合类型。对于每个集合类型,JPublisher为表示该集合的类生成一个type.java文件。对于嵌套的数据表,生成的类具有作为整个数组来获取和设置嵌套的数据表的一些方法,以及用于获取和设置该数据表中各个元素的一些方法。
用户定义的OPAQUE类型。每当JPublisher遇到一个没有提供其相应类型的SQL OPAQUE类型时,它都会生成一个type.java文件来发布一个Java封装器类。OPAQUE的有效负荷以字节数组(byte array)来表示,可以从生成的封装器的子类中进行处理。
PL/SQL BOOLEAN PL/SQL BOOLEAN被映射到Java Boolean类型。这要求有SYS.SQLJUTL包,该包是由数据库(JPublisher生成的代码要在其中运行)中的sqljutil.sql脚本来安装的。这个脚本默认安装在Oracle Database 10g中。
PL/SQL RECORD和TABLE类型。对于RECORD和TABLE类型,JPublisher生成相应的SQL对象(对于RECORD类型)或SQL VARRAY类型(对于TABLE类型),以及用于在PL/SQL和SQL类型之间进行映射的转换函数。
PL/SQL INDEXED-BY数据表。如果你使用Oracle Database 10g 的JDBC Oracle Call Interface (OCI)驱动程序并且需要发布已有索引的标量数据表,那么你可以直接在Java和这些类型(以Java数组表示)之间进行映射。
运行JPublisher实用工具
要在数据库中你想转换为Java类的用户定义的数据类型和PL/SQL包上运行JPublisher,你必须建立一个数据库连接,以便能对你映射的SQL类型和PL/SQL包进行访问。为此,可以使用-user和-url选项,如下例所示:
% jpub -user=scott/tiger -url=jdbc:oracle:oci:@ ...
% jpub -user=scott/tiger -url=jdbc:oracle:thin:@host:port/
servicename ...
第一个例子使用了Oracle JDBC OCI驱动程序,第二个使用了Oracle JDBC Thin驱动程序。下面的例子建立在Order Entry (OE)模式的基础上,该模式是Oracle Database 10g中一些示例模式的一种。假设OE模式的口令是OE,使用以下命令来发布SQL对象类型CATEGORY_TYP,其中CategoryTyp是相应Java类的名字:
% jpub -user=OE/OE -url=jdbc:oracle:oci:@
-sql=CATEGORY_TYP:CategoryTyp
-sql选项指定将要发布的类型和类包。
Oracle JPublisher生成并编译相应的Java类。
映射数据库操作
在这一部分,我将对PL/SQL包到Java的手工映射与JPublisher方法进行比较和对照。我的例子中使用了一个PL/SQL特有的类型,该类型无法从Java (本例中是PL/SQL RECORD)直接访问,而JPublisher则提供了附加支持。
create or replace package action
as type emprec
is record (name varchar2(10),
age number);
procedure foo (hired timestamp,
emp in out emprec);
end;
/
假设你想将ACTION包映射到一个Java类的Action。JDBC支持从TIMESTAMP到java.sql.TimeStamp的映射,然而,你并不想使用JDBC支持的映射,而是想从TIMESTAMP映射到Date。相应的Java foo方法将有如下定义:
public void foo(java.util.Date hired, EmpRecSql[] emp_inout)
手工方法。下面的一些步骤概括了你可以如何为这个ACTION包示例手工设置PL/SQL到Java的映射:
为PL/SQL RECORD类型EMPREC创建一个SQL对象类型,例如EMPREC_SQL。
为你创建的SQL类型创建一个Java类型。例如,为SQL类型EMPREC_SQL创建Java类型EmpRecSql。
在Java中,将每个参数转换为一个对应的Java类型。例如,将SQL TIMESTAMP转换为Java Date。
通过JDBC将每个IN或IN OUT参数传递给一个PL/SQL块。例如,将EmpRecSql和TimeStamp传递给foo。
在PL/SQL块中,将每个IN和IN OUT参数转换为PL/SQL存储过程的正确类型。例如,将EMPREC_SQL转换为EMPREC。
调用PL/SQL存储过程。
在PL/SQL中,将每个OUT参数、IN OUT参数或函数结果从JDBC不支持的类型转换为JDBC支持的相应类型。例如,将EMPREC转换为EMPREC_SQL。
从PL/SQL块返回每个OUT参数、IN OUT参数或函数结果。
在Java中,将每个OUT参数、IN OUT参数或函数结果从JDBC支持的类型转换为它不支持的类型。例如,从TimeStamp转换为Date。
Oracle JPublisher方法。以下的JPublisher命令直接发布ACTION包:
%
jpub -u scott/tiger -s action:Action
-style=webservices9
-outarguments=array
-plsqlfile=actionWrap.sql
请注意,-style=webservices9选项指定从TimeStamp到Date的映射。-outarguments= array表示OUT参数通过只有一个元素的数组来传递。
JPublisher产生你必须在使用JPublisher生成的代码之前要执行的PL/SQL封装器脚本。这个脚本包含了对应PL/SQL EMPREC类型的SQL类型EMPREC_SQL的定义,以及EMPREC和EMPREC_SQL之间的转换函数。同时,该脚本还包含了一个针对PL/SQL存储过程foo的封装器。
以下命令将执行生成的脚本:
% sqlplus scott/tiger @actionWrap.sql
这就算完成了。两相比较,JPublisher只需两个命令就可以完成ACTION包的PL/SQL到Java映射,而手工方法中却需要很多个命令。
以下是对JPublisher为ACTION PL/SQL包到Java映射生成的每个文件的简单描述:
Action.java, 为ACTION包生成的Java基类
ActionBase.java,从ActionBase扩展来的Java用户子类
ActionUser.java, 从ActionBase扩展来的Java类,包含Java类型映射,如从TimeStamp到Date
ActionEmprec.java, 为EMPREC_SQL生成的Java接口
ActionEmprecBase.java,为EMPREC_SQL生成的Java基类
ActionEmprecUser.java, 提供ActionEmprecBase的Java用户子类
ActionEmprecUserRef.java, EMPREC_SQL的REF类型的Java类型
actionWrap.sql,定义了EMPREC的SQL类型的SQL和PL/SQL脚本以及EMPREC和SQL类型之间的转换函数
数据库作为Web服务提供者
Oracle Database 10g提供了一个新的JPublisher特性,用以支持数据库Web服务。Oracle Database 10g与Oracle Application Server 10g的结合允许你将PL/SQL包和存储过程、SQL查询、SQL数据操作语言(DML)语句、以及服务器端Java类发布为Web服务。JPublisher生成的类可以通过Oracle Application Server Web Services Assembler工具作为Web服务而公布。
发布SQL查询或DML语句。JPublisher可以将具体的SELECT、UPDATE、INSERT或DELETE语句发布为一个Java类的方法。这个类也可以作为Web服务而发布。
样式文件。在发布服务器端Java类时,JPublisher使用说明Java到Java类型映射的样式文件来确保生成的类可用于Web服务。
生成Java接口。JPublisher可以生成Java接口和类。这就避免了手工生成Java接口来表示用以生成Web服务描述语言(WSDL)内容的API。
所支持的SQL类型。以下的SQL类型可以在数据库Web服务签名中发布:各种简单SQL类型,包括DATE,SQL对象类型,SQL VARRAY类型,SYS.XMLTYPE和REF CURSOR。
数据库作为Web服务消费者
当数据库作为Web服务消费者时,Web服务客户端代码采用SQL、PL/SQL或Java编写并在数据库中运行,用以调用外部Web服务。对于在数据库中运行以访问其他Web服务的代码,你必须能够调用这些服务。你可以使用手工方法进行简单对象访问协议(SOAP)的编程,或者通过JPublisher。以下步骤将帮助你通过JPublisher来构建你的第一个数据库Web服务消费者。
第一步:确认数据库的安装。在Oracle Database 10g中,在数据库安装时应该装入了[Oracle_Home]/sqlj/lib的sqljutl.jar库和utl_dbws_jserver.jar库、以及SYS.UTL_DBWS包。
第二步:生成并装入客户端代理以及Java和PL/SQL封装器。JPublisher将生成Web服务客户端代理代码的任务完全自动化,将其编译、放入Java归档(JAR)文件并装入到数据库中。 使用以下格式来生成代理代码:
% jpub
-proxywsdl=URL_of_Web_Service_WSDL
-user=username/password
另外,如果它与WSDL本身所提供的不相同,则你可以指定
-endpoint=external_Web_Services_URL
如果与通过JDBC OCI驱动程序访问的默认数据库实例不相同,则你还可以指定-url=JDBC_database_URL。以下例子使用了多个选项:
% jar xvf dist/javacallout.jar
META-INF/HelloServiceEJB.wsdl
% jpub -proxywsdl=META-INF/
HelloServiceEJB.wsdl
-dir=genproxy
-package=javacallout
-user=scott/scott
-endpoint=http://localhost:8888/
javacallout/javacallout
-proxywsdl选项指定了WSDL文件,JPublisher将为它生成静态Java代理类、Java和PL/SQL封装器,以及PL/SQL脚本。
-dir选项为生成的代码和脚本指定了根目录。
-package选项为生成的Java代码指定了包的名字。
代码生成后,JPublisher自动将以下文件装入数据库中:
genproxy/javacallout。这个目录下的Java类由JPublisher调用的Web服务WSDL编译工具生成。
genproxy/HelloServiceEJBJPub.java。HelloServiceEJBJPub.java类将方法sayHello()定义为一个静态的Java方法。
genproxy/plsql_wrapper.sql。这是Web服务客户端(HelloServiceEJBJPub.java)的PL/SQL封装器。
genproxy/plsql_dropper.sql。它用来删除plsql_wrapper.sql定义的PL/SQL类型和包。
genproxy/plsql_grant.sql。它(运行在SYS下)用来为Java客户端代理分配必要的权限以调用Web服务。
genproxy/plsql_revoke.sql。它用来取消plsql_grant.sql所分配的权限。
genproxy/jpub_proxyload.log。这是用于装入生成的Java文件和安装plsql_wrapper.sql脚本的日志文件。
为了禁止JPublisher将生成的代码装入到数据库中,你可以指定选项-proxyopts =noload。使用静态客户端代理的优点是你可以简化在你的Java代码中引用端口类型实例方法,而无需担心如何编排(marshal)或反编排(unmarshal)来自SOAP消息的个别参数。 下一步
第三步:分配权限。脚本plsql_grant.sql用于SYS给SCOTT分配执行装入的客户端代理时所必需的权限:
SQL conn / as sysdba
SQL @genproxy/plsql_grant.sql
第四步:调用外部Web服务。要从数据库调用外部Web服务,声明和运行run_plsql_proxy.sql脚本,或运行以下的PL/SQL块:
SQL set serveroutput on
SQL declare x varchar2(100);
begin
x:=JPUB_PLSQL_WRAPPER.sayHello(
'Hello from database');
dbms_output.put_line(x);
end;
/
第五步:清除。使用SQL*PLUS删除PL/SQL封装器并取消分配的权限。
SQL conn scott/tiger
SQL @genproxy/plsql_dropper.sql
SQL conn / as sysdba
SQL @genproxy/plsql_revoke.sql
使用dropjava工具从数据库中删除装入的Java类:
dropjava -u scott/tiger
genproxy/wsdlGenerated.jar
结论
JPublisher使Java开发人员免于复杂的学习、以及掌握手工创建Java数据库访问程序的很多逻辑细节和麻烦。此外,Jpublisher还简化了将数据库操作作为Web服务发布的过程和从数据库内部使用外部Web服务的过程。