内容


使用 Java API 定制 WebSphere Service Registry and Repository

简介

本文将展示如何编写、编译和执行一些 Java™ 代码,这些代码使用 IBM® WebSphere® Service Registry and Repository(后面简称为 WSRR)提供的 API 与产品进行交互。本文在正文部分提供了一些重要调用的代码片段,并在文件 wsrr_examples.zip 中提供了完整的源代码,您可以 在本文末尾处下载该文件

本文假设您熟悉 WebSphere Application Server、Java 编程、WSDL 和 XSD 语法、以及 WebSphere Service Registry and Repository V7。本文提供的示例主要针对想深入了解如何使用 WSRR API 实现代码的技术用户。给出的 引用和路径适用于 WSRR V7.5 和 Websphere Application Server V7.0,文中的示例适用于 Microsoft™ Windows™。这些 Java 代码应该用于 WebSphere Service Registry and Repository V6.3 和 V7.0 等版本。要使用 WebSphere Application Server V6.1,则需要修改环境类路径配置。

重复数据场景

在 WSRR 中,可通过名称、命名空间和版本的组合来标识 WSDL 和 XSD。默认情况下,有可能将具有相同名称、命名空间和版本(或者没有版本)的重复 WSDL 或 XSD 加载到 WSRR 中。加载后,所有文档及其相关内部对象都将存储到唯一的 bsruri 键下,以便内部处理能够区分它们,但它们包含相同的数据。因此,用户很难确定应该使用这两个重复条目中的哪一个。您可以在任何对象的 WSRR 用户界面详细信息中看见 bsruri 键,以及 API 查询的结果。

本文中的示例 1(EJB 客户端示例)移除已经加载到存储库中的重复 WSDL。但这个示例应该谨慎应用,因为它会删除用户数据。WSDL 文件拥有相同的名称、命名空间和版本,但拥有不同的 bsruris 和创建时间,示例 1 利用这些区别来决定删除哪个文件。

本文中的示例 2(WSRR Java 验证器插件示例)可阻止将重复的 WSDL 加载到 WSRR 中。

WebSphere Service Registry and Repository API

可以通过几个接口(包括 REST)访问 WSRR 中的内容。有关这些不同接口的详细信息,请参阅本文末尾处的 参考资料

对于 Java 程序员,有两个客户端选项可供选择,即 EJB API 和 Web 服务 API。有关这两个 API 的详细信息,请参阅本文末尾处的 参考资料

该示例将 EJB 客户端作为从命令行调用的纯 Java 类文件来执行。您可以在其他 Java 和 J2EE 应用程序中使用 Java 代码,就像对所有 WebSphere Application Server 客户端一样。

要点:WebSphere Service Registry and Repository 接口可提供对您的数据的完全访问,包括创建、删除和更新。因此,在对生产系统执行这些操作之前,应该彻底测试这些示例和所有 API 客户端。

设置环境

配置类路径以便编译

为了访问 EJB 和 WSR 客户端 API,需要将 JAR 文件添加到您的类路径中,在安装好 WSRR 之后,可以在 Websphere Application Server 中找到这些 JAR 文件。要详细了解安全客户端和瘦客户端上下文中的 WebSphere Application Server 环境配置,请参见本文末尾的 参考资料。您需要使用这些设置来编译这两个示例,并使用这些设置获得执行示例 1 的 EJB 客户端的运行时环境。

Microsoft Windows 上的 WebSphere Application Server V7 样例配置

在您的环境配置中,提供了 WebSphere Application Server 主接口的位置、WSRR 和 Java 目录的位置以及客户端 API 需要的 WSRR JAR 文件的位置。两个示例都对 ServiceRegistrySession EJB 执行了一个查询,因此还需提供 WebSphere Application Server EJB 客户端 JAR 文件的位置。

Windows 上的 WebSphere Application Server 样例环境设置
set WAS_HOME=c:\ibm\appserver 
set WSRR_HOME=%WAS_HOME%\wsrr 
set JAVA_HOME=%WAS_HOME%\java\bin 

set CP1=.;%WSRR_HOME%\ServiceRegistryClient.jar;%WSRR_HOME%\sdo-int.jar; 
set CP2=%WAS_HOME%\runtimes\com.ibm.ws.ejb.thinclient_7.0.0.jar; 

set CLASSPATH=%CLASSPATH%;%CP1%;%CP2%;

有关如何构建和加载插件 JAR 文件的详细信息,请参见下面的 生成 JAR 文件 部分。

示例 1. 使用 EJB 客户端删除重复的 WSDL 文件

创建 EJB 客户端并设置连接到 WSRR 会话 bean 的连接

如果使用的 WSRR 版本不同,那么用来识别主接口的 JNDI 名称也会有所不同。本文中的示例假定您正在使用 V7.5,因此创建一个 EJB 客户端的基本调用类似于:

Object ejbHome = 
   initialContext.lookup("ejb/com/ibm/serviceregistry/7_5/ServiceRegistrySessionHome");

如果您使用的是以前的 WSRR 版本,那么应该相应地更新接口 JNDI 名。有关详细信息,请参见本文末尾的 参考资料

当您在安全的环境中创建 EJB 客户端时,如果您在托管 WebSphere Service Registry and Repository 的 Websphere Application Server 中启用了应用程序安全性,则需要进行额外的调用来验证您的用户 ID 和密码。

设置 EJB 的安全和逻辑上下文
WSCallbackHandlerImpl callBackHandler = new WSCallbackHandlerImpl(userid, password);

Context initialContext = new InitialContext();
LoginContext loginContext = new LoginContext("WSLogin", callBackHandler);
loginContext.login();

Subject subject = loginContext.getSubject(); 
ContextManagerFactory.getInstance().setInvocationSubject(subject); 

Object ejbHome = initialContext.lookup 
("ejb/com/ibm/serviceregistry/7_5/ServiceRegistrySessionHome");

ServiceRegistrySessionHome srHome = (ServiceRegistrySessionHome) 
PortableRemoteObject.narrow(ejbHome, ServiceRegistrySessionHome.class);

ServiceRegistrySession session = srHome.create();

要点:尽管总是推荐在启用了安全性的生产环境中运行代码,但本文中的 EJB 客户端应用程序可以在禁用安全性的开发环境中运行。示例源代码提供了两种不同的方法,即 getServiceRegistrySession 和 getServiceRegistrySessionNoSecurity,以便您能够基于您的安全配置了解一些不同的方法。

使用 WSRR EJB 客户端 API

创建 ServiceRegistrySession 对象后,您就可以使用来自 WSRR 会话 bean 的 API 调用。有关详细信息,请参见本文末尾的 参考资料

为了删除重复 WSDL,示例使用了两个函数:executeQuery(查询 Registry 中的 WSDL)和 delete(根据 bsruri)。查询语法要求包含用来查询您想要返回的文档属性的文档(或对象)类型(本例使用的文档属性包括 bsrURI、lastModified、名称、命名空间和版本)。

为您感兴趣的参数创建属性查询并配置属性
// create a property query object
PropertyQuery typeSearch = (PropertyQuery)DataFactory.INSTANCE.create 
   (TypeConstants.SR_URI, TypeConstants.TYPE_PROPERTYQUERY); 
// set the type of documents to look for
String expression1 = "/WSRR/WSDLDocument";
typeSearch.setQueryExpression(expression1);
// set the properties to retrieve
BSRSDOHelper.INSTANCE.addProperty(typeSearch, "p1", "name");
BSRSDOHelper.INSTANCE.addProperty(typeSearch, "p2", "namespace");
BSRSDOHelper.INSTANCE.addProperty(typeSearch, "p3", "version");
BSRSDOHelper.INSTANCE.addProperty(typeSearch, "p4", "bsrURI");
BSRSDOHelper.INSTANCE.addProperty(typeSearch, "p5", "lastModified");

// execute the query
List WSDLList = serviceRegistry.executeQuery(typeSearch);
处理查询结果
// process the contents of the list in a loop
PropertyQueryResult queryResult = (PropertyQueryResult)WSDLList.get(i);

// retrieve the properties for each result 
String name = BSRSDOHelper 
   .INSTANCE.getPropertyQueryResultValue(queryResult,"name");
String namespace = BSRSDOHelper
   .INSTANCE.getPropertyQueryResultValue (queryResult,"namespace");
String version = BSRSDOHelper
   .INSTANCE.getPropertyQueryResultValue (queryResult,"version");
String date = BSRSDOHelper
   .INSTANCE.getPropertyQueryResultValue(queryResult,"lastModified");
String bsrURI =	BSRSDOHelper
   .INSTANCE.getPropertyQueryResultValue(queryResult,"bsrURI");

您可以在应用程序逻辑中使用查询结果。样例源代码提供了一个示例,您可以 在本文末尾处下载 源代码。

删除一个 WSDL 文件
serviceRegistry.delete(bsrURI);

安全环境中的独立(瘦)客户端

要在安全环境中执行瘦应用程序服务器客户端,则需要向该客户端提供对 3 个属性文件的运行时访问。您可以在环境配置中进行这些设置。如果希望这些文件在您的所有环境中都位于相同的位置,您也可以在客户端的源中配置它们的位置:

配置 Websphere Application Server 安全属性文件的位置
System.setProperty("com.ibm.SSL.ConfigURL","file:///" + <wasHome> + 
"/profiles/" + <profileName> + "/properties/ssl.client.props"); 
System.setProperty("java.security.auth.login.config","file:///" + <wasHome> + 
"/profiles/" + <profileName> + "/properties/wsjaas_client.conf"); 
System.setProperty("com.ibm.CORBA.ConfigURL","file:///" + <wasHome> + 
"/profiles/" + <profileName> + "/properties/sas.client.props");

默认文件位置都位于同一个目录中:<was_home>/profiles/<profile_name>/properties

  • ssl.client.props
  • sas.client.props
  • wsjaas_client.conf

本文提供的样例代码已经在 Java 源代码中配置了该位置。

生成 .class 文件

使用命令行 Java 工具 javac 编译 Java 代码。本例使用的包名称为 com.mycorp.ejbclient。源必须位于某个匹配的目录结构中,比如 c:\<wsrr_apps_dir>\com\mycorp\ejbclient。 要编译源 Java 文件,请按照 配置类路径以便编译 中的描述配置类路径。然后执行:

c:\<wsrr_apps_dir>javac 
com/mycorp/ejbclient/WSDLDuplicateRemover.java

测试 .class 文件

要运行 .class 文件,请配置您用来编译代码的类路径,如 配置类路径以便进行编译 中所述。然后执行:

c:\<wsrr_apps_dir>java 
com/mycorp/ejbclient/WSDLDuplicateRemover [websphere_appserver_dir] 
[profile] [userid] [password] [hostname] [port]

如果发现重复的 WSDL,示例客户端会进行如下报告:

The WSDL basic.wsdl from http://ibm.com/sr/test/wsdl/basic.wsdl is duplicated in the 
registry. The older version, b10222b1-33c0-40a1.b449.03280a034918, has been deleted.

如果没有发现重复的 WSDL,示例客户端会返回,并且不会进行任何更改:

WSDLDuplicateRemover has finished processing

您可以扩展这个示例,删除其他类型的 WSRR 文档,比如 XSD。如果某个文档有依赖项,则不能删除它。要查明是否有潜在依赖项,可以使用 UI 或 Governance Bean 进行影响分析。

故障诊断

CORBA Connection 拒绝

示例 ConnectException
at com.mycorp.ejbclient.WSDLDuplicateRemover.main
(WSDLDuplicateRemover.java:90)

Caused by: org.omg.CORBA.TRANSIENT: java.net.ConnectException: 
Connection refused: connect:host=9.x.y.z,port=2809  vmcid: IBM  minor code: E02  
completed: No 
at com.ibm.CORBA.transport.TransportConnectionBase.connect
(TransportConnectionBase.java:425)
...

客户端不能定位 host 9.x.y.z,port 2809 上的一个应用程序服务器。检查端口和 IP 地址是否正确,应用程序服务器是否正在运行。

CORBA NO_PERMISSION 和 SECJ0053E

示例 SECJ0053E
Remote exception in WSDLDuplicateRemover java.rmi.AccessException: CORBA 
NO_PERMISSION 0x0 No; nested exception is:
org.omg.CORBA.NO_PERMISSION:
>> SERVER (id=4773e3aa, host=localhost) TRACE START:
>>    org.omg.CORBA.NO_PERMISSION: java.rmi.AccessException:  ; nested 
exception is:
com.ibm.websphere.csi.CSIAccessException: SECJ0053E: Authorization fail
d for ??? while invoking (Home)ServiceRegistry#ServiceRegistryAPIEJB.jar#Service
RegistrySession60 create::2 null  vmcid: 0x0  minor code: 0  completed: No

这个错误通常由基本连接失败引起,例如试图对安全应用程序服务器进行不安全的连接。如果您正在使用本文提供的文件中的代码,则应确保使用的是 getServiceRegistrySession 方法,而不是 getServiceRegistrySessionNoSecurity 方法,而且您已经为您的环境设置传递了正确的参数。

CORBA NO_PERMISSION 和身份验证失败

示例身份验证失败
Login exception in WSDLDuplicateRemover com.ibm.websphere.security.auth.
WSLoginFailedException: Authentication Failed.
Note: The propagation of native registry error information is disabled by 
default. You may enable it by setting the property 
"com.ibm.websphere.security.registr y.propagateExceptionsToClient=true" 
using the server's administration console at Security -> Global Security -> 
Custom Properties.

身份验证失败错误通常由一个错误的用户 ID 或密码导致。

SecurityException:不能定位一个逻辑配置

示例 IOException
java.lang.SecurityException: Unable to locate a login configuration at 
com.ibm.security.auth.login.ConfigFile.init(ConfigFile.java:124) at 
java.lang.J9VMInternals.newInstanceImpl(Native Method) at 
java.lang.Class.newInstance(Class.java:1328) at 
javax.security.auth.login.Configuration$3.run(Configuration.java:267) …
Caused by: java.io.IOException: Unable to locate a login configuration

这个安全故障的常见原因是无法定位 3 个属性文件(ssl.client.props、sas.client.props 和 wsjaas_client.conf)或无法查看它们的内容。如果找不到文件,您应该会看到一条 Path not found 消息。如果文件存在,则应检查文件内容是否正确。

示例 2. 使用 WSRR 验证器插件阻止加载重复的 WSDL

WSRR 插件

示例 1 中的 EJB 客户端可以由用户根据需要执行。WSRR 还允许您创建用户代码,并将其作为插件嵌入到 WSRR 配置文件中,以便在处理过程中对 WSRR 中加载或修改的每个对象执行它。要详细了解如何创建和配置插件,请参阅本文末尾处的 参考资料

当您编写一个插件应用程序时,需要提供实现代码,每当(直接通过 API 或间接通过 UI)调用接口方法时,WSRR 都会执行该实现代码。可以为验证器实现的接口方法有 create、update 和 delete。

创建验证器插件

可以通过创建一个实现接口 com.ibm.serviceregistry.ServiceRegistryValidator 的 Java 类来编写一个 WSRR 验证器插件:

验证器声明
package com.mycorp.plugins.example;

import java.util.List;

import com.ibm.serviceregistry.ServiceRegistryStatus;
import com.ibm.serviceregistry.ServiceRegistryValidator;
import com.ibm.serviceregistry.delegate.DelegateFactory;
import com.ibm.serviceregistry.delegate.RepositoryDelegate;
import com.ibm.serviceregistry.sdo.OriginalObject;
import com.ibm.serviceregistry.sdo.PropertyQuery;
import com.ibm.serviceregistry.sdo.PropertyQueryResult;
import com.ibm.serviceregistry.sdo.WSDLDocument;
import com.ibm.serviceregistry.sdo.helper.BSRSDOHelper;
import com.ibm.serviceregistry.sdo.helper.DataFactory;
import com.ibm.serviceregistry.sdo.helper.TypeConstants;

public class NoDuplicatesValidator implements ServiceRegistryValidator {
使用 Repository Delegate
private RepositoryDelegate getRepositoryDelegate() throws Exception {
   return DelegateFactory.createRepositoryDelegate();
}

您不需要编写任何特定安全代码(即使在安全环境中),因为这个插件将在 WSRR 应用程序内部运行,从 WSRR 继承安全凭据。

您需要实现的 create 方法会传递给将要创建新对象的内容,您可以在验证器逻辑中使用其中的 SDO 信息:

实现 Validator API 的 create 方法
public ServiceRegistryStatus create(OriginalObject newObject) {

   final String methodName = "create";

   final String newName = newObject.getName();
   final String newNamespace = newObject.getNamespace();
   final String newVersion = newObject.getVersion();

   ServiceRegistryStatus srStatus = new ServiceRegistryStatus();

   if (newObject instanceof WSDLDocument) {
      logMsg(methodName, "Processing WSDL Document with name: " + newName
         + ", namespace:" + newNamespace + " and version: " + newVersion);
查询存储库中已有的 WSDL 文档
try {
   // create the query
   final PropertyQuery query = (PropertyQuery) DataFactory.INSTANCE.create(
   TypeConstants.SR_URI, TypeConstants.TYPE_PROPERTYQUERY);
   final String myExpression = "/WSRR/WSDLDocument[@name='" + newName +
   "' and @namespace='" + newNamespace + "' and @version='" + newVersion + "']";

   query.setQueryExpression(myExpression);
   BSRSDOHelper.INSTANCE.addProperty(query, "p1", "name");

   // retrieve an instance of the registry and execute the query
   final RepositoryDelegate repositoryDelegate = getRepositoryDelegate();
   List<PropertyQueryResult> wsdlList = repositoryDelegate.executeQuery(query);
执行 WSDL 列表检查以发现重复的 WSDL
 // if we have one or more results, then the document already exists in the registry
         if (wsdlList.size() >= 1) {
            final String errorMsg = newName + " is a duplicate of an existing document."
               + " WSDL must be unique.";

            srStatus.addDiagnostic(ServiceRegistryStatus.ERROR, errorMsg);
         }
      } catch (Exception e) {
         logMsg(methodName, e.getCause().toString());
         srStatus.addException(e);
      }
   }
return srStatus;

生成 JAR 文件

使用命令行 Java 工具 javacjar 编译 Java 代码并生成一个 JAR 文件,将其作为一个配置项目加载到 WSRR 中,这样做比较简单。本例使用的包名称为 com.mycorp.plugins.example。源需要位于某个匹配的目录结构中,比如 c:\<wsrr_apps_dir>\com\mycorp\plugins\example

确保 CLASSPATH 已按照上面的 配置类路径以便进行编译 中的描述进行配置。从父目录(例如 c:\<wsrr_apps_dir>)执行以下命令:

javac -Xlint:unchecked com/mycorp/plugins/example/NoDuplicatesValidator.java

这将生成一条警告信息,这是意料之中的,因为 executeQuery 方法返回一个原始列表,该列表可以包含任何对象类型。我们相信这个命令只会返回一列 PropertyQueryResults,因此您完全可以忽略这条来自编译器的警告。还可以检查返回列表中的每个元素的类型,并将其设置为 PropertyQueryResult

Java 编译警告
com/mycorp/plugins/example/NoDuplicatesValidator.java:43: warning:
[unchecked] unchecked conversion
found   : java.util.List
required: java.util.List<com.ibm.serviceregistry.sdo.PropertyQueryResult>
   List<PropertyQueryResult> wsdlList = registrySession.executeQuery(query);
                                                              ^
1 warning

完成代码编译后,将创建要加载到 WSRR 中的 JAR 文件。从 c:\<wsrr_apps_dir> 目录执行以下命令:

jar -cvf NoDuplicatesValidator.jar com/mycorp/plugins/example/NoDuplicatesValidator.class

将 JAR 文件加载到 WSRR 中

在 WSRR UI 中,切换到 Configuration 透视图:

  1. 选择 Active Profile => Plug-in JARs => Load JAR plug-in
  2. 加载插件 JAR 后需要启用它:选择 Active Profile => Validators => Validation properties plug-in (ValidationProperties)
  3. 将验证器的完全限定名称附加到属性文件中的 validators= 条目之后,然后保存更改。如果使用了本文中的示例,则该名称应该为 com.mycorp.plugins.example.NoDuplicatesValidator。现在已经启用了验证器。

测试插件

启用验证器插件后,如果您加载的 WSDL 与现有的 WSDL 的名称、命名空间和版本(或者没有版本)相同,则会看到一个错误:

图 1. 来自 WSRR 验证器的 GSR0044E
来自 WSRR 验证器的 GSR0044E
来自 WSRR 验证器的 GSR0044E

相关信息

尽管 API 包含了一个用于 WARNING 的参数,但 UI 只能处理 ERROR 或 SUCCESS 结果(WARNING 被视为 SUCCESS),因此,从实用角度看,不应该使用 WARNING 选项。

您可以编写通知、修改程序、治理插件或验证器插件,但使用的 API 是类似的。有关插件的详细信息,请参阅下面的 参考资料

结束语

WebSphere Service Registry and Repository Java API 使您能够创建独立的 EJB 客户端和插件运行时代码,它们可以管理和增强您的用户数据,充当可重用、可自动化的资产。


下载资源


相关主题

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=WebSphere
ArticleID=774202
ArticleTitle=使用 Java API 定制 WebSphere Service Registry and Repository
publish-date=11142011