不少系统中都有动态数据表的存在,比如按日或者按月在数据库中生成一个表,以日表为例,其表名的形式为TableName_XXXX_XX_XX,如TableName_2006_03_10等,表明其表内数据存放的是2006年3月10日所产生的数据,在这些日表中,表结构完全相同,只是在表名上有所区别。
而在ALDSP从关系数据库中导入元数据(import Meta Data)时,无论是直接从表导入,还是从SQL语句导入,都必须提供其表名,否则无法生成Data Services;但是在不少客户的应用中,经常是要根据选择的时间范围来动态的查询一个表或者多个表。根据客户提出的这些要求,经过研究发现,在ALDSP中要比较方便的解决这个问题,主要可以通过两个途径解决,其一是在数据库端生成一个函数(function)或者存储过程(store procedure),设定表名作为参数,然后由ALDSP导入生成Data Services,其二是直接利用ALDSP可以从函数导入元数据的功能,先生成一个以表名为参数的函数,然后导入ALDSP生成Data Services.
以下主要介绍第二种方法的实现。
在ALDSP中,可以从多种异构数据源中取得数据,包括数据库,flatfile,xml文件,Web Services,Java函数等。从Java函数中生成Data Services有几点要注意的地方,详见http://edocs.bea.com/aldsp/docs20/datasrvc/datasources.html#1136189.其中包括函数的定义必须为static,还有就是返回值有些限制,主要可以返回两种类型,其一为Java原始类型(primitive types)或者原始类型的数组,其二为复杂类型(complex types)或者复杂类型的数组。在一般的Java程序中,返回复杂类型数据一般会用到JavaBean或者JavaBean的数组或者直接用一个容器返回,但是对ALDSP而言,无论是容器或者JavaBean的数据,ALDSP均不能从中获取到所需的元数据(Meta Data)信息,要满足ALDSP元数据获取的要求,我们可以通过一个Java-to-XML或者JavaBena的技术来对其返回值进行封装。
针对以上这些情况,我们通过一个模拟的例子来实现这个解决方案,首先在数据库中生成两张表表名为table1和table2,结构如下:
字段名
类型
ID
字符串型
NAME
字符串型
根据表的类型,设计XMLBean的XML Schema来适应我们的需要。
以下为图形化视图(由XMLSPY生成):
XML文件源代码如下:
<?xml version="1.0"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://temp.openuri.org/TestDynamicTable2/AllUser.xsd" targetNamespace="http://temp.openuri.org/TestDynamicTable2/AllUser.xsd" elementFormDefault="qualified" attributeFormDefault="unqualified"> <xs:element name="AllUser"> <xs:complexType> <xs:sequence> <xs:element name="User" minOccurs="0" maxOccurs="unbounded"> <xs:complexType> <xs:sequence> <xs:element name="ID" type="xs:string"/> <xs:element name="Name" type="xs:string"/> </xs:sequence> </xs:complexType> </xs:element> </xs:sequence> </xs:complexType> </xs:element> </xs:schema>然在在Workshop里新建一个应用程序,再新建一个Schema Project,再新建一个XML Schema如下所示:
保存AllUser.xsd后会自动编译成生XMLBean的包:
这样,我们就可以在定义的Java类中返回XMLBean类型的数据了。
接下来在当前应用程序中新建一个Java工程,加一个Java类,生成一个类如下:
import java.sql.Connection;import java.sql.Driver;import java.sql.ResultSet;import java.sql.Statement;import java.util.Hashtable;import javax.naming.Context;import javax.naming.InitialContext;import javax.sql.DataSource;import org.openuri.temp.testDynamicTable2.allUser.AllUserDocument;
public class DynamicTable { //函数的函数为表名public static AllUserDocument getUser(String tablename)
{ AllUserDocument doc;AllUserDocument.AllUser alluser;AllUserDocument.AllUser.User user;//先生成一个XMLBean的实例doc = AllUserDocument.Factory.newInstance();//像这个实例中加入一个节点alluser = doc.addNewAllUser();try { Hashtable env = new Hashtable();Context ctx = null;ctx = new InitialContext();DataSource ds = (DataSource)ctx.lookup("cgDataSource");Connection conn = ds.getConnection();Statement stmt = conn.createStatement();ResultSet rs = stmt.executeQuery("select id,name from "+tablename);//通过JDBC取得数据集ResultSet while(rs.next())
{ //然后将数据集中的数据加入到XMLBean中user = alluser.addNewUser();user.setID(rs.getString("id"));user.setName(rs.getString("name"));} System.out.println(doc.toString());} catch(Exception ex)
{ ex.printStackTrace();} //将结果集包装为XMLBean后返回return doc;}以上代码的主要原理是:通过JNDI取得数据源,然后使用根据传入的表名拼装出一个SQL查询语句,然后由取得结果集后生成XMLBean返回。
经过编译后就可以导入生成一个Data Services了:
最后测试结果如下:
后记:
ALDSP的功能很强大,现在也有越来越多的关键应用在通过ALDSP来实现,特别是异构数据源的访问,多数据库的集成等业务,而在ALDSP中通过导入Java函数做为数据源,则更是进一步的模糊了数据源这个传统概念的边界。总的来说,通过Java函数,ALSDP可以很灵活的处理各种数据结构,比如将数据库与LDAP Server的数据放在在一起访问,通过Java函数,ALDSP可以与任何一种能由Java处理的数据进行集成,从而得到统一数据访问的目的。ALDSP的这些功能对于SOA下各种异构数据的统一处理尤为重要。