You are browsing the archive for oc4j.

WebService系列:创建PL/SQL复合式数据类型Web Services

二月 13, 2009 in Oracle 融合中间件

 

 

本文描述基于PLSQL中记录和记录表复合式数据类型的功能函数来创建Web Services。

 

一、创建Web Service

 

1,准备数据

我就利用前面文章中用来验证的用户信息表 sec_users 作为操作的实例

1
2
3
4
5
INSERT INTO sec_users VALUES(1,'aronehome','aronehome');
INSERT INTO sec_users VALUES(2,'aronezhang','aronezhang');
INSERT INTO sec_users VALUES(3,'amyyu','amyyu');
 
COMMIT;

 

2,PL/SQL函数功能声明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
CREATE OR REPLACE PACKAGE aronehome_demo_ws2 IS
 
  TYPE user_type IS RECORD (
    userid    NUMBER,
    username  VARCHAR2(30),
    password  varchar2(30)
  );
  TYPE user_tbl IS TABLE OF user_type INDEX BY BINARY_INTEGER ;
 
  FUNCTION get_user_list RETURN user_tbl;
  PROCEDURE update_user_info(p_user_list user_tbl) ;
 
END aronehome_demo_ws2;
/
 
CREATE OR REPLACE PACKAGE BODY aronehome_demo_ws2 IS
 
  FUNCTION get_user_list RETURN user_tbl IS
    l_user_list user_tbl;
  BEGIN
    l_user_list.delete ;
 
    FOR cur IN (SELECT userid , username, password FROM sec_users) LOOP
      l_user_list(l_user_list.COUNT + 1) := cur;
    END LOOP;
 
    RETURN l_user_list;
  END get_user_list;
 
  PROCEDURE update_user_info(p_user_list user_tbl) IS
  BEGIN
    FOR i IN 1 .. p_user_list.count -1 LOOP
       UPDATE sec_users
          SET password = p_user_list(i).password
        WHERE userid = p_user_list(i).userid;
    END LOOP;
  END update_user_info;
 
END aronehome_demo_ws2;
/

 

上面两个函数过程的声明:

  1. get_user_list 函数用来得到用户信息列表,返回一个Table数据类型作为结果
  2. update_user_info过程用来成批更新用户的密码,传入一个Table数据类型作为参数

 

3,创建WebService

 

创建的详细步骤请参考前面相关的文章,由于后续文章需要从Microsoft VBA调用发布的WebServices,因此在创建WebServices的时候需要特别注意两个地方

  1. 创建PL/SQL J2EE 1.4 Web Service的第一个步骤中需要选择SOAP1.1 Binding标准
  2. 第二个步骤中需要选择SOAP Message Format为:RPC/Encoded
  3. 其它步骤没有特殊的地方

 

最后发布Web Service,对应的endpoint为:http://ORACLE:8888/aronehome/UserListInfoSoapHttpPort,WSDL文件包含在附件下载中

 

二、SQL到XML类型映射(Call-Ins)

 

从WebServices调用数据库资源的时候(Call-Ins),一个SQL操作如PL/SQL的存储过程、函数或者SQL语句都被映射为Web服务操作,

SQL操作的参数会从SQL的类型映射为XML类型,下表列出复合式SQL数据类型与XML类型间的映射

SQL 类型 XML 类型
Primitive PL/SQL indexby table Array
PL/SQL indexby table complexType
PL/SQL record complexType
SQL table complexType

注:此表不包括基本SQL类型与XML类型间的映射

 

下面我们来看看一段wsdl内容的片断代码

1
 

 

上面ArrayOfAronehomeDemoWs2UserTypeUser复合式类型就是由AronehomeDemoWs2UserTypeUser类型的元素组成,

而AronehomeDemoWs2UserTypeUser则是由AronehomeDemoWs2UserTypeBase基础类型扩展而来的类型,AronehomeDemoWs2UserTypeBase基础类型由:

userid:decimal
username:string
password:string

三个元素组成,这样的结构和PL/SQL table的结构是一样的。在JDeveloper的结构窗口中可以看到类型对应的Java实现类

26.ws_java_class

 

相关的JDeveloper Wordspace文件:Download Oracle EBS二次开发系列视频教程之开发基于Table的Form(4) Version 1 

 

下一篇文章将描述如何生成Microsoft VBA的Web Service客户端代理程序

 

WebService系列:OC4J安全性提供程序

二月 10, 2009 in Oracle 融合中间件

 

 

上面的章节中我们添加了WS安全认证之后执行Web Service报出:wsse:FailedAuthentication的错误,这是由于验证失败的缘故。

为了验证Web Services的安全信息,需要在OC4J服务器端对Web Services所属的Web应用设置安全验证方式,OC4J提供了四种安全验证的方式:

  1. 基于文件的安全提供程序
  2. Oracle Identity Management安全提供程序
  3. 用于第三方LDAP服务器的Oracle安全提供程序
  4. 定制的安全提供程序

 

本文基于本人实际使用过的1,4两种安全提供程序方式的描述

 

一、基于文件的安全提供验证

 

本节采用OC4J默认的“基于文件的安全提供程序”来进行Web Services安全验证,设置步骤如下:

  1. 登录OC4J EM管理页面
  2. 选择“应用程序”标签页中的应用“aronehome”
  3. 选择“应用程序:aronehome”下的标签页“管理”页中的“安全提供程序”任务,选择“转到任务”链接图标
  4. 进入安全提供程序设置界面,选择“领域”标签
  5. 选择角色的数字链接进入角色定义和查询界面
  6. 选择用户的数字链接进入用户定义和查询界面

 

15.ws_web_app_home

 

16.security_provider

 

17.file_based_security_provider

 

18.file_based_security_provider_user

 

19.file_based_security_provider_add_user

 

根据验证的需要创建不同的用户信息,如本示例创建用户:aronehome/aronehome

只要是在这里创建的用户信息都可以用来验证本应用下的安全Web Services,在调用启用了安全验证的Web Service时,

如果调用程序没有提供用来验证的用户信息或者是提供了上面未定义的被认为错误的验证信息,则不会调用Web Services。

 

设置好用户信息之后,再次运行Web Service进行测试!

 

二、定制的安全提供程序

 

基于文件的安全性认证对于在实际的应用中很难满足灵活的用户管理,因此本文描述如何使用定制类型的安全提供程序来通过编写PLSQL程序从数据库表sec_users中验证用户。

下面使用OTN提供的DatabaseLoginModule来, 相关的Jar从OTN下载:http://www.oracle.com/technology/products/jdev/howtos/10g/jaassec/jaasdatabaseloginmodule.zip

1,配置JAR环境

  1. 拷贝DBLoginModule.jar文件包到$ORACLE_HOME/j2ee/home/lib目录下
  2. 修改文件$ORACLE_HOME/j2ee/home/config/application.xml,添加内容:
    <library path=”../../home/lib/DBLoginModule.jar”/>
  3. 重启OC4J

 

2,创建用户信息表

1
2
3
4
5
6
7
8
CREATE TABLE sec_users(
  userid     NUMBER,
  username   VARCHAR2(30),
  PASSWORD   VARCHAR2(30)
);
 
INSERT INTO sec_users VALUES(1,'aronehome','aronehome');
COMMIT;

 

3,编写用户验证的PLSQL过程

下面是一个例子,实际的验证请根据数据库表进行必要的修改:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
CREATE OR REPLACE PACKAGE aronehome_jaas_utils IS
  TYPE principal_ref IS REF CURSOR;
  FUNCTION get_user_authentication(p_username IN VARCHAR2,
                                   p_password IN VARCHAR2,
                                   p_realm    VARCHAR2) RETURN principal_ref;
END aronehome_jaas_utils;
/
CREATE OR REPLACE PACKAGE BODY aronehome_jaas_utils IS
  FUNCTION get_user_authentication(p_username IN VARCHAR2,
                                   p_password IN VARCHAR2,
                                   p_realm    VARCHAR2) RETURN principal_ref AS
    var_username VARCHAR2(100);
    var_userid   NUMBER(10);
    var_password VARCHAR2(100);
    role_cursor  principal_ref;
    failed_authentication EXCEPTION;
  BEGIN
    SELECT userid, username, password
      INTO var_userid, var_username, var_password
      FROM sec_users
     WHERE username = p_username;
 
    IF (var_password = p_password) THEN
      BEGIN
          -- Manager,Administrator,User
          OPEN role_cursor FOR
            SELECT 'User' FROM dual ;
      END;
      -- if password doesn't match, raise Excpetion for LM to
      -- abort the authentication process
    ELSE
      RAISE failed_authentication;
    END IF;
    RETURN role_cursor;
  END get_user_authentication;  
END aronehome_jaas_utils;
/

 

4,设置数据库存贮信息来验证

 

  1. 登录OC4J EM管理界面
  2. 选择需要设置的Web应用,如:aronehome
  3. 切换到应用对应的管理页面,选择“安全提供程序
  4. 选择“更改安全提供程序”按钮来更改设置,设置如下的属性:
    安全提供程序类型:定制安全提供程序
    JAAS 登录模块类: oracle.sample.dbloginmodule.DBProcLM.DBProcLoginModule
  5. 设置登录模块的属性如下:
    Name:jdbcDriver ;Value:oracle.jdbc.driver.OracleDriver
    Name:plsql_procedure ;Value:ARONEHOME_JAAS_UTILS.GET_USER_AUTHENTICATION
    Name:db_schema;Value:aronehome
    Name:db_schema_pw;Value:aronehome
    Name:jdbcUrl;Value:jdbc:oracle:thin:@localhost:1521:xe
    Name:debug;Value:false
    Name:log_level;Value:ALL

 

20.custom_security_provider

 

设置好上面的配置之后,需要从新启动aronehome应用,再次运行Web Service进行测试!

 

注:DatabaseLoginModule的使用请查看OTN的相关文章,Declarative J2EE authentication and authorization with JAAS,上面只是其中一种用法。

 

 

最终的JDeveloper10 Workspace项目文件:Download R12 Form个性化白皮书 Version 1

 

 

WebService系列:为WebService添加安全性

二月 10, 2009 in Oracle 融合中间件

 

 

为了保证发布到外网的Web Services不被非法使用,在调用Web Services之前需要进行必要的安全验证。

如前面文章中发布的GreetingWords的Web Service,希望只有授权的用户才具备调用它的权限,

虽然它的wsdl描述文件可以被任何人查看,但是如果不具备相应权限的人则无法通过调用它返回有用的信息。

 

一、设置Web Service安全性认证

 

为了实现这样的功能,按照向导在JDeveloper创建完Web Services后,添加验证信息,步骤如下:

  1. 选择端口,并保证使用“Text Password”验证选项
  2. 左边选择安全下的验证菜单,设置如下图的选项
  3. 从新发布Web Service

 

12.secure_web_service

 

选中 Security 项,并选择GreetingWordsSoapHttpPort,按照下图设置选项

13.secure_web_service_security

 

选择 Security–>Authentication 项,右边选择GreetingWordsSoapHttpPort,按照下图进行选项的设置

14.secure_web_service_authentication

 

 

二、测试Web Service

 

上面添加了Web Service的安全性认证发布之后,在浏览器中输入wsdl的端口地址,如:

http://aronezhang:8888/aronehome/GreetingWordsSoapHttpPort

浏览器显示Web Service的测试页面,输入参数,点击Invoke按钮调用Web Services

21.test_secure_ws

 

Web Services执行返回错误,错误代码为:wsse:InvalidSecurity,错误消息为:Missing <wsse:Security> in SOAP Header

这个错误是由于已发布的Web Services添加了安全验证,而调用的时候没有把相关的验证信息发送给它,导致SOAP Header没有包括安全验证需要的信息。

 

我们可以通过测试页面的功能查看到这个时候发送给服务器的消息是:

1
2
3
4
 
 
 
            aronehome

从发送的消息可以看到,没有任何安全验证的信息。

重新测试Web Service,在测试页面中选择WS-Security部分的Include In Header选项,然后输入上面OC4J的中定义的用户信息,并输入调用参数,如下图:

22.test_secure_ws_security

1
2
3
4
5
6
7
8
9
10
11
12
 
 
 
 
	      aronehome
	      aronehome
 
 
 
 
 
            aronehome

上面的提交消息中,SOAP Header部分包括了安全验证的信息,提交之后还是报如下的错误信息:

1
2
3
4
5
6
 
 
 
 
   wsse:FailedAuthentication
   The security token could not be authenticated or authorized

 

虽然我们提供了WS安全认证的用户信息,但是执行还是没有成功,这是由于提供的用户认证信息不正确,

后面的文章中将描述如何来通过OC4J提供安全性认证信息。

 

 

WebService系列:PL/SQL调用Web Service(Web Service Callout)

二月 8, 2009 in Oracle 融合中间件

 

 

Web Service Callout的意思是在数据库中使用SQL查询、PL/SQL存储过程或Java存储过程来调用Web Service。

 

在Oracle Database 9.2或更高的版本中执行Web Service Callout需要完成以下的工作:

  1. 准备数据库(启用数据库Web Service功能),主要是装载基于Java的Web Service客户端运行环境到数据库中
  2. 装载Web Service的客户端代理到数据库中。生成基于Java的Web Service客户端代理、对应的Java和PL/SQL包装器,装载所有生成的对象到数据库
  3. 使用代理、包装器或DII(dynamic Invocation) APIs来调用Web Service

 

本文介绍基于Oracle Database 10.2.0,并将Web Service发布到独立的OC4J环境中。

基于Oracle Database 9.2的实现,可以参考OTN 技术文章Web Service Callout User Guide

为了实现PL/SQL调用Web Service,需要使用以下工具,从OTN下载

  1. 10.1.3.1 Webservice Callout for 10g (R1 + R2) (ZIP, ~13MB)
  2. JPublisher
  3. OC4J

 

 

一、数据库设置

 

准备数据库的主要工作是装载Web Service客户端运行环境到数据库中。装载客户端运行环境需要JVM而外的内存空间来解析和存贮jar文件。

查看系统的设置,保证shared_pool_sizejava_pool_size的设置分别大于等于96M和80M:

shared_pool_size=96M

java_pool_size=80M

 

1,装载Oracle SOAP客户端到Oracle 10g数据库

下载OC4J,解压oc4j_extended.zip文件,并将它的根目录设为环境变量ORACLE_HOME。可以将SOAP的客户端装载到SYS模式下或者一个特定的用户模式。

使用下列的命令来装载将它装载到aronehome模式下:

1
2
3
4
5
6
7
8
loadjava -u aronehome/aronehome -r -f -v -genmissing -grant public $ORACLE_HOME/webservices/lib/soap.jar ; 
loadjava -u aronehome/aronehome -r -f -v -genmissing -grant public $ORACLE_HOME/lib/dms.jar ;
loadjava -u aronehome/aronehome -r -f -v -genmissing -grant public $ORACLE_HOME/jlib/javax-ssl-1_1.jar ;
loadjava -u aronehome/aronehome -r -f -v -genmissing -grant public $ORACLE_HOME/j2ee/home/lib/servlet.jar ; 
loadjava -u aronehome/aronehome -r -f -v -genmissing -grant public $ORACLE_HOME/j2ee/home/lib/mail.jar ; 
loadjava -u aronehome/aronehome -r -f -v -genmissing -grant public $ORACLE_HOME/j2ee/home/lib/activation.jar ; 
loadjava -u aronehome/aronehome -r -f -v -genmissing -grant public $ORACLE_HOME/j2ee/home/lib/http_client.jar ; 
loadjava -u aronehome/aronehome -r -f -v -genmissing -grant public $ORACLE_HOME/j2ee/home/lib/ejb.jar ;

 

-grant public选项是将装载的Java类授权给public,使其它的模式也可以看到,如果希望是某个特定的模式使用,可以去掉它。

 

2,装载Oracle JAX-RPC客户端到Oracle 10g R2数据库

下载10.1.3.1 Webservice Callout for 10g 工具集,解压后可以看到dbwsclientws.jar和dbwsclientdb102.jar文件

使用下列的命令来装载将Oracle JAX-RPC装载到aronehome模式下:

loadjava -u aronehome/aronehome -r -v -f -genmissing -grant public dbwsclientws.jar dbwsclientdb102.jar

-grant public选项是将装载的Java类授权给public,使其它的模式也可以看到,如果希望是某个特定的模式使用,可以去掉它。

 

 

二、生成Web Service代理

 

这部分使用JPublisher来生成Web Service客户端代理

1,下载安装JPublisher。添加下列jar文件到CLASSPATH环境变量

${ORACLE_HOME}/sqlj/lib/dbwsa.jar
${ORACLE_HOME}/sqlj/lib/translator.jar
${ORACLE_HOME}/sqlj/lib/runtime12.jar
${ORACLE_HOME}/jdbc/lib/ojdbc14.jar

 

2,设置JAVA_HOME指向JDK1.4,并将JAVA_HOME/bin添加到PATH环境变量中

3,运行JPublisher来生成Web Service客户端代理和PL/SQL包装器

首先取得已发布的Web Service的描述文件(WSDL),通过Web Service的端口连接在浏览器中打开Web Service的相关信息,如下图

11.ws_endpoint

 

通过Service Description连接可以查看到WSDL文件内容,将其保存文wsdl为后缀的文件,如GreetingWordsSoapHttpPort.wsdl
运行下面的命令:

jpub -u aronehome/aronehome -sysuser sys/sys -proxywsdl=GreetingWordsSoapHttpPort.wsdl -endpoint=http://aronezhang:8888/aronehome/GreetingWordsSoapHttpPort

命令将创建Web Service客户端代理和它的Java和PL/SQL包装器,同时装载代理和包装器到数据库。命令会输入如下的信息:

1
2
3
4
5
6
7
8
9
GreetingWordsSoapHttpPortClientJPub.java 
plsql_wrapper.sql 
plsql_dropper.sql 
plsql_grant.sql 
plsql_revoke.sql 
Executing plsql_dropper.sql 
Executing plsql_wrapper.sql 
Executing plsql_grant.sql 
Loading plsql_proxy.jar

 

三、运行PL/SQL包装器来调用Web Service

 

在SQLPLUS或者PL/SQL Developer中运行Web Service的PL/SQL包装器的方法来输出欢迎语

1
2
3
4
5
SQL &gt; conn aronehome/aronehome
SQL &gt; select jpub_plsql_wrapper.GreetingWords('aronehome') as GreetingWords from dual;
 GreetingWords
--------------------------------------------------------------------------------
Hello aronehome, 2009-02-08

 

四、使用DII API调用Web Service

 

除了上面所描述的生成和装载客户端代理来在PL/SQL中调用Web Service外,也可以使用SYS.UTL_DBWS 包中的Web Service客户端DII APIs或者PL/SQL DII APIs来调用Web Service

前面章节中下载的JPublisher包中包括了SQL脚本utl_dbws_decl.sql 和utl_dbws_body.sql,以SYS用户运行这两个脚本。这样就可以使用SYS.UTL_DBWS来调用Web Service

下面是一段示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
DECLARE
  service_          sys.utl_dbws.service;
  call_             sys.utl_dbws.CALL;
  service_qname     sys.utl_dbws.qname;
  port_qname        sys.utl_dbws.qname;
  operation_qname   sys.utl_dbws.qname;
  string_type_qname sys.utl_dbws.qname;
  retx              anydata;
  retx_string       VARCHAR2(100);
  retx_len          NUMBER;
  params            sys.utl_dbws.anydata_list;
BEGIN
  service_qname   := sys.utl_dbws.to_qname(NULL, 'GreetingWords');
  service_        := sys.utl_dbws.create_service(service_qname);
  port_qname      := sys.utl_dbws.to_qname(NULL, 'SoapHttpPort');
  operation_qname := sys.utl_dbws.to_qname('http://com/aronehome/GreetingWords.wsdl/types/',
                                           'GreetingWordsElement');
  call_           := sys.utl_dbws.create_call(service_,
                                              port_qname,
                                              operation_qname);
  sys.utl_dbws.set_target_endpoint_address(call_,
                                           'http://AroneZhang:8888/aronehome/GreetingWordsSoapHttpPort');
  string_type_qname := sys.utl_dbws.to_qname('http://www.w3.org/2001/XMLSchema',
                                             'string');
  sys.utl_dbws.add_parameter(call_,
                             'String_1',
                             string_type_qname,
                             'ParameterMode.IN');
  sys.utl_dbws.set_return_type(call_, string_type_qname);
  params(0) := anydata.convertvarchar('Arone.Zhang');
  retx := sys.utl_dbws.invoke(call_, params);
  retx_string := retx.accessvarchar2;
  dbms_output.put_line('PL/SQL DII client return ' || retx_string);
END;