ITPub博客

首页 > Linux操作系统 > Linux操作系统 > 为遗留用户存储库开发联合存储库的定制适配器

为遗留用户存储库开发联合存储库的定制适配器

原创 Linux操作系统 作者:CloudSpace 时间:2009-05-06 16:30:03 0 删除 编辑

引言

WebSphere Application Server (WAS) V6.1 引入了联合用户存储库,它提供了将多个独立的用户存储库映射到一个虚拟存储库的功能,使得在 WebSphere Application Server 中可以更加容易地使用多个存储库。然而,有些遗留系统正使用它们自定义的数据库结构,将用户名、密码、组和一些相关信息存储在关系型数据库中,这些信息无法被 WebSphere Application Server 直接使用。对于这种情况,要使遗留的用户存储库和联合存储库集成在一起,需要为遗留的用户存储库开发一个联合存储库的定制适配器,使 WebSphere Application Server 能管理存储在遗留关系数据库中的用户和组。本文将详细介绍如何开发联合存储库的定制适配器,并以基于关系型数据库的遗留用户存储库为例分析实现细节,最后针对示例给出定制适配器的部署和测试方案。

联合存储库

联合存储库为用户和组管理提供了读写能力,可以通过应用程序编程接口(API)、管理控制台、wsadmin 命令等方式对用户和组进行管理。

联合存储库支持多种类型的存储库,包括基于文件的存储库、轻量级目录访问协议 (LDAP) 存储库、数据库存储库和定制存储库。基于文件的存储库和 LDAP 存储库受管理控制台支持,对于数据库和定制存储库,可以使用 wsadmin 命令行界面或配置应用程序编程接口 (API)。

联合存储库通过适配器操作各个存储库。它直接提供 File、LDAP 和 Database 适配器,分别为联合存储库访问基于文件的存储库、LDAP 存储库和数据库存储库提供适配功能,这些覆盖了大部分用户的需求。联合存储库还提供了扩展功能,用户可以通过实现定制适配器,使联合存储库支持更多的存储库。所有的联合存储库的适配器需要实现 com.ibm.wsspi.wim.Repository 软件编程接口 (SPI)。

示例场景介绍

本文的示例场景假设用户的遗留系统正在使用关系型数据库来维护用户存储库。在用户存储库中,用户、密码、组和一些相关信息在运行时有自定义的对象类型,而在持久化时也有自定义的数据表结构。然而联合存储库自带的数据库适配器必须使用规定的数据库模式来存储数据,对于遗留数据库的存储模式无法直接存取,因此遗留的用户存储库无法直接和联合存储库集成在一起。

本文以此场景为例,介绍联合存储库定制适配器的开发,并针对基于关系型数据库的用户存储库给出一种定制适配器的实现方式。

在本文介绍的场景中,遗留系统通过 User 和 Group 类来管理用户和组。其定义如图 1 所示。其中 User 类表示一个用户, Group 类表示一个组, User 和 Group 之间存在多对多关系。


图 1. 遗留系统中的用户和组的对象模型
遗留系统中的用户和组的对象模型

遗留系统通过关系型数据库来持久化用户和组的信息,包括 3 个数据表:USER、GROUP 和 USER_IN_GROUP。其定义如图 2 所示。其中 USER 表存储一个用户,GROUP 表存储一个组,USER_IN_GROUP 表存储用户和组之间的关联关系,表示用户在组中,分别通过外键关联到 USER 和 GROUP 表中。


图 2. 遗留系统中的用户和组的数据库模型
遗留系统中的用户和组的数据库模型

一般情况下,关系型数据库持久化通过数据访问对象 (DAO) 来实现。遗留系统定义了 UserDao 和 GroupDao 来负责对象的持久化,如图 3 所示。UserDao 包括用户的查找、创建、更新和删除等操作的接口定义,GroupDao 包括用户组的查找、创建、更新和删除等操作,以及增加、删除组成员等操作的接口定义。在遗留系统中,数据访问对象层可以有各种实现方式,例如:JDBC、Hibernate 等等。


图 3. 遗留系统中的用户和组的数据访问对象
遗留系统中的用户和组的数据访问对象

开发联合存储库的定制适配器,就是充分利用数据访问对象提供的方法来实现适配器中定义的方法,从而达到适配的目的。而至于数据访问对象中定义的方法的具体实现方式对定制适配器没有影响。

扩展联合存储库

所有的适配器需要实现 com.ibm.wsspi.wim.Repository 接口。在 Repository 接口中,定义了以下 9 个抽象方法,如表 1 所示。


表 1. Repository 接口定义的抽象方法

方法 描述
create 在给定对象下创建实体
createSchema 动态创建新实体和属性的类型结构
delete 删除给定对象下的实体
get 获取给定对象的信息
getSchema 获取实体和属性的类型结构信息
initialize 初始化适配器
login 认证给定对象下的账户信息
search 查找给定对象下满足搜索条件的对象,并返回指定的属性
update 更新给定对象下的实体

这 9 个方法使用 commonj.sdo.DataObject 类型作为参数,Data Object 是 Service Data Objects (SDO) 的基础组件,用于表达结构化的数据,为结构化数据提供统一的表达形式。

Repository 接口有一个默认的实现 com.ibm.wsspi.wim.RepositoryImpl 类。类派生关系如图 4 所示。其中,FileAdapter、LdapAdapter 和 DBAdapter 分别用于适配文件存储库、LDAP 存储库和数据库存储库。AbstractAdapterImpl 抽象类是一个辅助的资料库实现,实现了 Repository SPI。LegacyDBAdapter 类是本文为遗留存储库开发的定制适配器。


图 4. Repository 接口及其子类的派生关系
Repository 接口及其子类的派生关系 

利用 AbstractAdapterImpl 抽象类

AbstractAdapterImpl 是 WebSphere Application Server 示例定制适配器代码的一部分,可以从参考资料中下载。AbstractAdapterImpl 抽象类采用了模板方法 (Template Method) 设计模式,实现了不包含任何和特定资料库相关的代码。而对于和特定资料库相关的代码,AbstractAdapterImpl 抽象类以抽象方法的形式留给了子类来实现。

准备开发环境

开发定制适配器可以使用任何 Java 集成开发环境,这里使用 Eclipse,如下图 5 所示。


图 5. Eclipse 中的定制适配器项目
Eclipse 中的定制适配器项目

具体步骤如下:

  1. 新建 Java 项目:LegacyDBAdapter。
  2. 添加 WebSphere Application Server 运行时类库:com.ibm.ws.runtime_6.1.0.jar。这个 jar 文件可以在 {app_server_root}/plugins 目录下找到。
  3. 添加 Service Data Objects 的实现类库,这里使用的是 Eclipse Modeling Framework (EMF) 实现。这个类库可以在 {app_server_root}/plugins 目录下找到,包括以下 5 个 jar 文件 ( 对于不同版本的 WebSphere Application Server,文件名可能略有不同 ):
    • org.eclipse.emf.commonj.sdo_2.1.0.v200609210005.jar
    • org.eclipse.emf.common_2.2.1.v200609210005.jar
    • org.eclipse.emf.ecore.sdo_2.2.0.v200609210005.jar
    • org.eclipse.emf.ecore.xmi_2.2.1.v200609210005.jar
    • org.eclipse.emf.ecore_2.2.1.v200609210005.jar
  4. 添加访问遗留系统所需要的类库,这些类库可能以各种形式存在。这里直接导入了遗留系统的访问代码,包括数据模型和数据访问对象:
    • User
    • UserDao
    • UserDaoImpl
    • Group
    • GroupDao
    • GroupDaoImpl
  5. 导入 AbstractAdapterImpl 类,这个类可以简化定制开发适配器的开发。
  6. 新建 LegacyDBAdapter 类,该类从 AbstractAdapterImpl 派生,Eclipse 会自动添加抽象方法的默认实现代码。本文接下来几节将详细介绍如何实现这些抽象方法。

    实现定制适配器的初始化功能

    在 WebSphere Application Server 启动时会对定制适配器进行初始化,我们可以在这个过程中从配置文件中读取对遗留系统访问的相关信息。实现初始化功能包括以下方法:

    public void initialize(DataObject reposConfig) throws WIMException

    此方法对定制适配器进行初始化。AbstractAdapterImpl 抽象类中的 initialize 方法实现了基本的初始化操作,包括从配置文件中读取自定义属性等。如果定制适配器需要一些特定的初始化,可以重写 initialize 方法。对于本文的例子,需要读取数据库访问的一些属性,并对数据访问对象进行初始化。


    清单 1. 重写 initialize 方法
    				
    public void initialize(DataObject reposConfig) throws WIMException
    {
     // 调用父类初始化方法
     super.initialize(reposConfig);
     // 获取数据库连接属性
     ……
     // 初始化数据访问对象
     ……
    }
    

    注:本文只列出重要的实现方法,具体的实现请下载本文提供的代码示例。

    public boolean isValidCustomProperty(String key, String value)

    此方法用于对自定义的属性进行验证。对于本文的例子,我们只验证了属性名是否为 driver、url、user 和 password,这些属性用于连接遗留数据库。

    实现用户和组的转换

    定制适配器使用 DataObject 来保存用户和组的信息,而遗留系统使用自定义的用户和组的对象 User 和 Group,我们需要在两种表达方式之间建立一种映射关系。我们定义了一些私有方法用于用户和组的转换,这些方法将会在后面介绍的方法中大量地被使用到。

    private DataObject convertToDataObject(User user)

    private DataObject convertToDataObject(Group group)

    private User convertToUser(DataObject entity)

    private Group convertToGroup(DataObject entity)

    前两个方法用于将遗留系统中的用户和组转换成 DataObject,后两个方法用于将 DataObject 转换为遗留系统中的用户和组。

    这里以 convertToDataObject (User) 为例说明转换过程。首先建立一个用户 DataObject,将用户的一些基本属性 ( 如 principalName、uid 等 ) 存入其中,再在其下面建立一个标识符 DataObject,将用户的一些标识信息 ( 如 uniqueId、uniqueName 等 ) 存入其中,最后将用户 DataObject 返回。


    清单 2. convertToDataObject 方法实现代码

    				
    private DataObject convertToDataObject(User user) throws WIMException
    {
        if (user != null)
        {
            DataObject rootDO = SDOHelper.createRootDataObject();
            // 创建用户 Data Object
            DataObject userDO = rootDO.createDataObject(
    DO_ENTITIES, WIM_NS_URI, DO_PERSON_ACCOUNT);
            userDO.setString(PROP_PRINCIPAL_NAME, user.getUid());
            userDO.setBytes(PROP_PASSWORD, user.getPassword().getBytes());
            userDO.setString("uid", user.getUid());
            ……
            // 创建用户的标识符 Data Object
            DataObject identifierDO = userDO.createDataObject(DO_IDENTIFIER);
            identifierDO.set(PROP_EXTERNAL_ID, user.getUniqueId());
           ……
            // 返回用户 Data Object
            return userDO;
        }
        return null;
    }
    

    以用户 testuser 为例,相应的 DataObject 如清单 3 所示 ( 打印成 XML 的形式便于查看 )。


    清单 3. 用户 testuser 的 DataObject 示例

    				
    
        
            
                
                testuser
                KioqKg==
                testuser
                aa
                bb
                testuser@ibm.com
            
        
    
    

    实现用户和组的读取功能

    用户和组的读取功能从遗留数据库中读取用户和组的信息,并转换成 DataObject。实现用户和组的读取功能包括以下方法:

    public DataObject getEntity(DataObject entity, DataObject propertyCtrl, DataObject returnRoot)

    此方法用于获取实体的信息。首先从传入的 entity 中获取实体的唯一名字,然后通过唯一名字查找到实体的详细信息,最后将得到的数据存入 returnRoot 中返回。此方法在通过唯一名字查找到实体的详细信息时,用到了一个私有方法 getEntityByUniqueName,其定义如下:

    private DataObject getEntityByUniqueName(String uniqueName)

    此方法根据传入的 uniqueName 的前缀进行判断,如果前缀是 uid,说明实体是用户,调用 UserDao 中的 getUserByUniqueName 方法从数据库中读取用户的信息;如果前缀是 cn,说明实体是组,调用 GroupDao 中的 getGroupByUniqueName 方法从数据库中读取组的信息。由于使用数据访问对象获取的用户和组对象是由遗留系统提供的,所以需要通过方法 convertToDataObject 将对象中对应的字段进行映射,转换成 DataObject。


    清单 4. getEntityByUniqueName 方法实现代码

    				
    private DataObject getEntityByUniqueName(String uniqueName) throws WIMException
    {
        DataObject entity = null;
        if (uniqueName != null)
        {
            if (uniqueName.startsWith("uid"))
            {
                // entity 对象是一个用户
                User user = userDao.getUserByUniqueName(uniqueName);
                entity = convertToDataObject(user);
            }
            else if (uniqueName.startsWith("cn"))
            {
                // entity 对象是一个组
                Group group = groupDao.getGroupByUniqueName(uniqueName);
                entity = convertToDataObject(group);
            }
        }
        if (entity == null)
        {
            throw new EntityNotFoundException(......);
        }
        return entity;
    }
    

    在以后介绍的方法中,经常需要通过实体的 uniqueName 前缀来区分实体是用户或组;而对于通过数据访问对象获取的用户和组对象,也需要用 convertToDataObject 做转换。

    public String getUniqueName(DataObject entity) throws EntityNotFoundException

    此方法用于获取实体的唯一名字。如果传入的 entity 是标识符类型,直接读取其 PROP_UNIQUE_NAME 属性;如果 entity 是实体类型,则通过 DO_IDENTIFIER 属性可以解析出标识符,再递归调用 getUniqueName 就可以得到实体的唯一名字。


    清单 5. getUniqueName 方法实现代码

    				
    public String getUniqueName(DataObject entity) throws EntityNotFoundException
    {
        String uniqueName = null;
        if (entity != null)
        {
            // 检查 entity 是否为标识符对象
            if (DO_IDENTIFIER_TYPE.equals(entity.getType().getName()))
            {
            // 如果是,则直接通过 PROP_UNIQUE_NAME 属性读取 uniqueName
                uniqueName = entity.getString(PROP_UNIQUE_NAME);
                ......
            }
            else
            {
                // 如果不是,则通过 DO_IDENTIFIER 属性读取其标识符,再递归调用 getUniqueName 方法
                DataObject identifier = entity.getDataObject(DO_IDENTIFIER);
                uniqueName = getUniqueName(identifier);
            }
        }
        return uniqueName;
    }
    

    对于上节中的用户 DataObject 的例子,调用 getUniqueName 可获得其 uniqueName 为 uid=testuser,o=legacyDBRepository,反过来,通过 uniqueName 调用 getEntityByUniqueName,可以得到完整的 DataObject 信息。

    实现搜索功能

    搜索功能返回所有符合搜索条件的实体。实现搜索功能包括以下方法:

    public DataObject searchEntities(DataObject searchControl)

    此方法用于在存储库中搜索实体。首先从传入的 searchControl 中解析出搜索的条件:需要搜索的实体类型,和实体属性需要符合的条件。通过对搜索的条件表达式进行解析,将搜索条件以名值对的形式存入一个 Properties 对象中。然后调用 search 私有方法进行搜索, search 方法定义如下:

    private List search(List entityTypes, Properties properties)

    此私有方法根据不同的实体类型 entityTypes,搜索符合 properties 条件的对象列表。


    清单 6. searchEntities 方法实现代码

    				
    public DataObject searchEntities(DataObject searchControl) throws WIMException
    {
        try
        {
            // 解析搜索表达式
            String searchExpr = 
    searchControl.getString(SchemaConstants.PROP_SEARCH_EXPRESSION);
            WIMXPathInterpreter parser =
     new WIMXPathInterpreter(new StringReader(searchExpr));
            XPathNode node = parser.parse(null);
            // 获取匹配的实体类型
            List entityTypes = parser.getEntityTypes();
            // 将搜索条件以名值对的形式存入一个 Properties 对象中
            Properties properties = new Properties();
            if (node != null)
            ......
            // 调用 search 方法
            List searchResult = search(entityTypes, properties);
            // 建立包含搜索结果的 Data Object,并返回
            ......
        }
        catch (Exception e) { ...... }
    }
    


    清单 7. search方法实现代码
    				
    private List search(List entityTypes, Properties properties) throws Exception
    {
        List searchResult = new Vector();
        // 遍历每一个实体类型
        for (Iterator typeIterator = entityTypes.iterator(); typeIterator.hasNext();)
        {
            String entityType = (String) typeIterator.next();
            if (SchemaHelper.isLoginAccountType(entityType))
            {
                // 搜索用户
                List userList = userDao.findUsersByProperties(properties);
                // 将每一个搜索结果转换为Data Object
                ......
            }
            else if (SchemaHelper.isGroupType(entityType))
            {
                // 搜索组
                List groupList = groupDao.findGroupsByProperties(properties);
                // 将每一个搜索结果转换为 Data Object
                ......
            }
        }
        return searchResult;
    }
    

    以下给出一个搜索的示例。假设要搜索 E-mail 为 testuser@ibm.com 的用户。在集成解决方案控制台中提交搜索用户请求,如图 6 所示。


    图 6. 提交搜索用户请求
    提交搜索用户请求

    WebSphere Application Server 会调用 searchEntities 方法,传入的 searchControl 中保存的搜索条件表达式为:

    //entities[@xsi:type='PersonAccount' and mail='testuser@ibm.com']

    然后从中解析出一个搜索条件:名字为 mail,值为 testuser@ibm.com,保存在 properties 对象中,传入 search 方法。再调用 UserDao.findUsersByProperties,将搜索条件转换为 SQL 语句:

    SELECT * FROM USER WHERE 1=1 AND MAIL LIKE ‘testuser@ibm.com’

    最后将查询的结果转换为 DataObject 返回,如之前的清单 3 所示。

    在集成解决方案控制台中显示的结果如图 7 所示。


    图 7. 搜索用户结果
    搜索用户结果 

    实现登录功能

    实现登录功能包括以下方法:
    public DataObject login(DataObject account, DataObject loginCtrl)

    此方法用于对用户进行认证。首先从传入的 account 对象中解析出用于认证的 principalName 和 password,将 principalName 作为搜索条件,调用 search 方法找到相应的账户信息,并且此账户信息必须是唯一的。然后将传入的密码和账户信息中的密码进行比对,比对成功后,将唯一匹配的帐户 DataObject 返回,登录成功。


    清单 8. login 方法实现代码

    				
    public DataObject login(DataObject account, DataObject loginCtrl) throws WIMException
    {
        ......
        String accountEntityType = account.getType().getName();
        // 搜索匹配的用户信息
        List entityTypes = new Vector();
        ……
        // 调用 search 方法
        List accountList = search(entityTypes, properties);
        if (accountList.size() == 1)
        {
            // 找到唯一的匹配用户
            accountDO = (DataObject) accountList.get(0);
        }
        else if (accountList.size() > 1)
        {
            throw new PasswordCheckFailedException(......);
        }
        // 进行密码比对
        ......
    }
    

    实现用户和组的管理功能

    用户和组的管理功能包括创建、更新和删除用户和组等操作。实现用户和组的管理功能包括以下方法:

    public DataObject createEntity(String entityType, DataObject entity)

    此方法用于创建实体。首先需要对传入的 entity 做一些处理,包括:去除一些和其它实体的关联信息,为新实体生成唯一的 ID,对实体中的密码信息进行 Hash 处理等。然后通过数据访问对象 UserDao.createUser ( 用户 ) 或 GroupDao.createGroup ( 组 ) 向数据库中添加实体信息,并将新生成的实体返回。

    public boolean entityAlreadyExists(DataObject entity)

    public boolean entityAlreadyExists(String uniqueId, String uniqueName)

    public boolean entityMustExist(String uniqueId, String uniqueName)

    public boolean memberMustExist(String uniqueId, String uniqueName)

    public boolean groupMustExist(String uniqueId, String uniqueName)

    这几个方法都用于判断实体是否已经存在。根据 uniqueName 调用数据访问对象 UserDao.getUserByUniqueName ( 用户 ) 或 GroupDao.getGroupByUniqueName ( 组 ) 从数据库中查找实体,如果找到,说明实体已经存在。

    public void rename(String entityType, DataObject updatedEntity, String uniqueName, String newUniqueName)

    此方法用于更改实体的 uniqueName。首先验证新的 uniqueName 在存储库中不存在,然后更新 updatedEntity 中的 uniqueName 和 externalName,最后通过数据访问对象 UserDao.updateUserUniqueName ( 用户 ) 或 GroupDao.updateGroupUniqueName ( 组 ) 更新实体的 uniqueName。

    public void updateEntity(DataObject updatedEntity, String uniqueName, List modItems)

    此方法用于更新实体的属性。需要更新的属性保存在一个 ModificationItem 对象的列表中。首先通过 uniqueName 获取需要更改的 entity。然后对于列表中的每一个 ModificationItem 对象,如果更改操作是替换或删除,则从 entity 中去除要更改的属性;如果更改操作是替换或添加,则向 entity 中添加新的属性和值。最后根据 entity 的 uniqueName 将 entity 转换成用户或组对象,通过数据访问对象 UserDao.updateUser( 用户 ) 或 GroupDao.updateGroup( 组 ) 更新到数据库中。


    清单 9. updateEntity 方法实现代码

    				
    public void updateEntity(DataObject updatedEntity, String uniqueName, List modItems)
    {
        ......
        // 遍历每一个 ModificationItem
        for (int i = 0; i < modItems.size(); i++)
        {
            ModificationItem modItem = (ModificationItem) modItems.get(i);
            int modOp = modItem.getModificationOp();
            Attribute attr = modItem.getAttribute();
            String propName = attr.getID();
            // 如果是替换或删除操作,则先删除原先设定的值
            if ((modOp == DirContext.REPLACE_ATTRIBUTE) 
                || (modOp == DirContext.REMOVE_ATTRIBUTE))
            {
                entity.unset(propName);
            }
            // 如果是替换或添加操作,则设置新的值
            ......
            }
        }
        // 将实体更新信息保存到数据库
        ......
    }
    

    public DataObject deleteEntities(DataObject root)

    此方法用于删除实体。从每一个待删除的实体中解析出 uniqueName,通过数据访问对象 UserDao.deleteUser ( 用户 ) 或 GroupDao.deleteGroup ( 组 ) 从数据库中删除。

    以下给出一个 rename 和 updateEntity 的示例。假设我们要将用户 testuser 的用户标识更改为 testuser2,以及姓氏更改为 xxxx。在集成解决方案控制台中提交更改用户请求,如图 8 所示。


    图 8. 提交更改用户请求
    提交更改用户请求

    WebSphere Application Server 首先会调用 rename 方法,将用户 testuser 的 uniqueName 改为 testuser2,如清单 10 所示。


    清单 10. 调用 rename 后原 testuser 的 DataObject

    				
    
        
            
                
                ......
            
        
    


    清单 11. 调用 updateEntities 后原 testuser 的 DataObject
    				
    
        
            
                xxxx
            
       
    
    
    

    在集成解决方案控制台中显示的结果如图 9 所示。


    图 9. 更改用户结果
    更改用户结果

    实现组和成员的管理功能

    组和成员的管理功能包括获取组中的成员列表,获取成员所在组的列表,以及更新组中的成员。实现组和成员的管理功能包括以下方法:

    public void getGroupMembers(DataObject rootEntity, DataObject grpMemberCtrl)

    此方法用于获取组中的成员列表。首先从传入的 rootEntity 中解析出组的 uniqueName。然后调用数据访问对象 UserDao.findUsersByGroupUniqueName 从数据库中读取其成员的信息,再将每一个成员信息转换成 DataObject,存入组的 DataObject 的成员列表 (DO_MEMBERS) 部分中。


    清单 12. getGroupMembers 方法实现代码

    				
    public void getGroupMembers(DataObject rootEntity, DataObject grpMemberCtrl)
    {
        // 得到组的 uniqueName
        ……
        // 通过组的 uniqueName 获取组成员列表
        List userList = userDao.findUsersByGroupUniqueName(groupUniqueName);
        // 将每一个成员转换成 Data Object,并加入组的 DO_MEMBERS 列表中
        for (Iterator iterator = userList.iterator(); iterator.hasNext();)
        {
            User user = (User) iterator.next();
            DataObject userEntity = convertToDataObject(user);
            groupEntity.getList(DO_MEMBERS).add(userEntity);
        }
    }
    

    以组 testgroup 和其成员 testuser 为例,相应的 DataObject 如清单 13 所示。


    清单 13. 组 testgroup 和其成员 testuser 的 DataObject 示例

    				
    
        
            
                
                testgroup
                
                   
                    ......
                
                This is a test group.
            
        
    
    

    public void getGroupMembership(DataObject rootEntity, DataObject grpMembershipCtrl)

    此方法用于获取用户所在组的列表。首先从传入的 rootEntity 中解析出用户的 uniqueName,然后调用数据访问对象 GroupDao.findGroupsByUserUniqueName 从数据库中读取包含该用户的组的信息,再将每一个组员信息转换成 DataObject,存入用户的 DataObject 的组列表 (DO_GROUPS) 部分中。

    public void updateGroupMembers(DataObject entity, String groupUniqueName, List memberUniqueNames, int grpMbrMod)

    此方法用于更新组中的成员。如果是添加或替换,通过调用 addMemberToGroup 方法,从而调用了数据访问对象 GroupDao.addMemberToGroup 将 memberUniqueNames 中的每个用户加入组中;如果是删除,则将调用私有方法 removeMemberFromGroup ,从而调用数据访问对象 GroupDao. removeMemberFromGroup 从组中移除用户。

    定制适配器的部署

    部署定制适配器可以使用 wsadmin 命令,具体步骤如下:

    1. 将 LegacyDBAdapter.jar 和遗留数据库访问相关的 jar 文件复制到 {app_server_root}/lib 目录下。

    2. 在 wimconfig.xml 文件 ( 位于 {app_server_root}/profiles/{profile_name}/config/cells/cell_name/wim/config) 中,添加新的 config:repositories 元素,将此元素放在 config:realmConfiguration 元素之前。

    3. 启动 wsadmin 工具:wsadmin –conntype none

    4. 禁用页面调度功能。

    $AdminTask updateIdMgrRepository {-id LegacyDBRepository -supportPaging false}

    5. 设置 driver、url、user 和 password 定制属性,用于和遗留存储库连接。

    $AdminTask setIdMgrCustomProperty {-id LegacyDBRepository -name driver -value "com.ibm.db2.jcc.DB2Driver"}

    $AdminTask setIdMgrCustomProperty {-id LegacyDBRepository -name url -value "jdbc:db2://localhost:50000/LegacyDB"}

    $AdminTask setIdMgrCustomProperty {-id LegacyDBRepository -name user -value "administrator"}

    $AdminTask setIdMgrCustomProperty {-id LegacyDBRepository -name password -value "passw0rd"}

    6. 配置 o=legacyDBRepository 基本条目。

    $AdminTask addIdMgrRepositoryBaseEntry {-id LegacyDBRepository -name o=legacyDBRepository}

    7. 将 o=legacyDBRepository 基本条目和 defaultWIMFileBasedRealm 域关联。

    $AdminTask addIdMgrRealmBaseEntry {-name defaultWIMFileBasedRealm -baseEntry o=legacyDBRepository}

    8. 保存更改,在 wimconfig.xml 中新添加的内容如下:

    
    
      
      
      
      
    

    9. 重新启动 WebSphere Application Server。

    定制适配器的测试

    要验证定制适配器是否正确配置和工作,可以通过在 WebSphere Application Server 的集成解决方案控制台中进行一些简单操作。以下列举一些测试示例。

    1. 将缺省父代基本条目设为 o=legacyDBRepository
    在集成解决方案控制台中,进入“安全性 > 安全管理、应用程序和基础结构”,确认“可用的域定义”选择的是“联合存储库”,单击“配置”按钮。在联合存储库配置页面中,单击“受支持的实体类型”,将“缺省父代基本条目”设置为 o=legacyDBRepository,如图 10 所示。保存更改,并重新启动 WebSphere Application Server。


    图 10. 设置缺省父代基本条目
    设置缺省父代基本条目

    2. 添加用户和组
    在集成解决方案控制台中,进入“用户和组 > 管理用户”。单击“创建”按钮,创建用户 testuser,如图 11 所示。通过数据库工具可以查看到已经在 USER 表中添加了 testuser 记录,如图 12 所示。


    图 11. 添加用户
    图 11. 添加用户

    图 12. 新添加的用户记录
    图 12. 新添加的用户记录

    用类似的方法可以创建组 testgroup,如图 13 所示。通过数据库工具可以查看到已经在 GROUP 表中添加了 testgroup 记录,如图 14 所示。


    图 13. 添加组
    图 13. 添加组

    图 14. 新添加的组记录
    图 14. 新添加的组记录

    在新建的 testgroup 组中,“成员”标签页下,单击“添加用户”,将 testuser 加入该组中,如图 15 所示。通过数据库工具可以查看到已经在 USER_IN_GROUP 表中添加了相应的关联记录,如图 16 所示。


    图 15. 添加组成员
    图 15. 添加组成员

    图 16. 新添加的用户和组的关联记录
    新添加的用户和组的关联记录

    3. 用户登录
    在集成解决方案控制台中,进入“用户和组 > 管理用户角色”,给 testuser 赋予“管理员”角色,如图 17 所示。


    图 17. 给用户添加管理员角色
    图 17. 给用户添加管理员角色

    用 testuser 重新登录集成解决方案控制台,此时 testuser 应该可以正常地登录集成解决方案控制台。

    技巧和提示

    1. 可以打开 WebSphere Application Server 的详细日志来帮助调试定制适配器。具体方法如下:在集成解决方案控制台中,进入 Troubleshooting -> Logs and Trace,选择相应的 profile 名字,单击 Diagnostic Trace,再单击 Change Log Detail Levels,在文本框中添加 com.ibm.ws.wim.*=all。保存更改后,重新启动 WebSphere Application Server。
    2. 在用户登录时,WebSphere Application Server 会搜索联合存储库配置的各个存储库以查找该用户出现的所有位置,任何一个存储库的访问失败,都会导致用户登录失败。如果找到了该用户的多个实例,也会导致用户登录失败。
    3. 如果由于定制适配器的配置或实现上的问题,导致 WebSphere Application Server 管理用户无法登录集成解决方案控制台,可以暂时先将 WebSphere Application Server 的全局安全禁用。具体方法如下:
      启动 wasadmin 工具:
      wsadmin –conntype none
      输入以下命令将 WebSphere Application Server 的全局安全禁用:
      securityoff
      重新启动 WebSphere Application Server。
    4. 联合存储库的定制适配器不能依赖于任何 WebSphere Application Server 组件。如果定制适配器的实现需要使用数据源来连接数据库,那么在 WebSphere Application Server 启动期间,需要使用 JDBC 进行连接。在稍后数据源可用的情况下,改为使用数据源来连接至数据库。
    5. 在 WIMTraceHelper 辅助类中,提供了 printDataGraph 静态方法,可以将 DataObject 转换为 XML 形式的字符串,在调试定制适配器时非常实用。其声明如下:
      public static String printDataGraph(commonj.sdo.DataObject root)

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/14789789/viewspace-594335/,如需转载,请注明出处,否则将追究法律责任。

下一篇: 添加自定义角色
请登录后发表评论 登录
全部评论

注册时间:2008-07-08

  • 博文量
    355
  • 访问量
    863807