入门

本教程是关于什么的?

本教程概述了Java™2企业版(J2EE)连接器体系结构(JCA)。 本教程首先对JCA进行了高级介绍,包括其在J2EE体系结构中的位置,它如何工作以集成企业级系统以及体系结构的基本元素。 在以下各节中,您将通过分步说明和示例来更详细地探讨每个元素。 本课程以示例应用程序结尾,将帮助您了解与JCA兼容且已启用的系统的所有部分如何协同工作。

我应该学习本教程吗?

为了从本教程中获得最大收益,您应该熟悉Java编程和面向对象的编程概念。 您还应该对J2EE和J2EE应用程序有一个高层次的了解。

工具,代码示例和安装要求

本教程提供了示例代码( helloworldra.zip ),并将在您逐步进行解释。 要执行和测试示例代码,您将需要一个支持J2EE连接器体系结构的J2EE应用服务器环境。 源代码以标准J2EE包装提供; 有关部署的详细信息,请参见J2EE应用程序服务器环境。

整合复杂度

在开发基于Web的应用程序时,您可能发现您需要将这些应用程序与至少一个企业信息系统(EIS)中可用的资源和数据集成,例如企业资源计划(ERP)系统,供应链管理(SCM)系统或事务处理监视器(TPM)。 这种集成是电子商务战略的本质:我们利用和改造现有基础架构,将其与Web和其他开放技术相结合,以支持新的业务流程,例如企业对企业(B2B)交易。

在J2EE连接器体系结构出现之前,集成J2EE应用程序和EIS既复杂又成问题,因为尚无用于此类集成的标准。 每个EIS供应商都针对该问题提供了自己的解决方案。 EIS供应商通常不支持所有J2EE应用服务器。 所有这些使编写与企业信息系统集成的真正可移植的应用程序变得困难。 集成每个应用程序服务器-EIS组合需要进行定制工作。

下图说明了J2EE应用程序和EIS集成的复杂性。

JCA简化了集成

J2EE连接器体系结构(JCA)解决了将J2EE应用程序服务器连接到EIS的问题。 通过遵循JCA标准,EIS供应商确保其EIS可以轻松地与任何基于Java的应用程序服务器集成。 同样,应用程序服务器供应商只需确保为其产品启用JCA连接,而无需为市场上的每个EIS定制其产品。 任何启用JCA的应用程序服务器都可以与任何符合JCA的EIS集成。

下图显示了JCA如何简化将多个应用程序服务器连接到单个EIS或将单个应用程序服务器连接到多个EIS的过程。

JCA的要素

JCA由三个主要元素组成:

  • 系统合约
  • 客户端API
  • 资源适配器模块

这些元素中的每一个在JCA中都扮演着特定的角色。 我们将分别对每个元素进行高层次的研究,然后在下一部分继续进行更复杂的讨论。

系统合约

系统协定定义了应用程序服务器和EIS之间的连接。 系统合同的EIS端由资源适配器实现 - 资源适配器是EIS专用的系统级软件驱动程序。 应用程序服务器和资源适配器通过系统合同协作,以提供对EIS的安全,可靠,可扩展的访问。

定义了三种类型的系统合同:

  • 连接管理协定启用了到EIS的物理连接,并为应用程序服务器提供了池化那些连接的机制。
  • 事务管理合同支持在事务上下文中访问EIS。 事务可以由应用程序服务器管理,提供包含EIS以外的其他资源的事务,也可以位于EIS资源管理器内部,在这种情况下,不需要事务管理器。
  • 安全合同支持对EIS的安全访问。

JCA未指定如何在每一端(应用程序服务器和资源适配器)上实现系统协定; 它们可以按照每个供应商认为合适的方式实施。

客户端API

JCA的第二个元素是客户端API 。 该API可以特定于资源适配器,也可以是JCA定义的标准公共客户端接口 (CCI)。 供应商可以使用CCI提供集成工具和框架,从而使开发人员可以更轻松地访问企业系统。 建议(但不强制)资源适配器使用CCI。

资源适配器模块

资源适配器模块包含为应用程序提供EIS连接所必需的所有元素。 具体来说,资源适配器模块包括以下组件:

  • 实现资源适配器的Java类和接口
  • 资源适配器所需的所有实用程序Java类
  • 任何EIS特定于平台的本机库
  • 部署描述符

应用程序服务器利用资源适配器随附的部署描述符将其配置为特定的操作环境。

资源适配器模块包装

使用Java存档(JAR)文件格式,所有资源适配器模块的文件都打包到资源适配器存档(RAR)文件中。 所有Java类和接口都打包在JAR文件中,然后由RAR文件包含。 本机文件也打包在RAR文件中。 部署描述符名为ra.xml,位于RAR文件的META-INF文件夹中。

JCA的基础架构

JCA概述

对JCA有了基本的了解之后,您就可以开始更多地考虑架构下工作的元素了。 在本部分中,您将学习可以一起创建和管理连接,完成复杂事务并维护JCA兼容和启用系统的安全性的类,接口和库。

获取并关闭连接

应用程序组件通过由资源适配器实现者提供的ConnectionFactory和Connection接口访问资源适配器。 这些接口可以是CCI接口( javax.resource.cci.ConnectionFactory和javax.resource.cci.Connection ),也可以特定于资源适配器。 资源适配器还提供了实现这些接口的类。

连接工厂是通过Java命名和目录接口(JNDI)获得的,因此应用程序无需了解基础实现类。 一旦检索到连接工厂,就可以通过getConnection()方法从连接工厂获得连接。 连接工厂必须至少提供一个getConnection()方法,尽管可以提供更多方法。 重要的是要注意, Connection是到EIS的基础物理连接的应用程序级句柄,由ManagedConnection表示,我们将在后面讨论。

应用程序组件完成连接后,将在连接上调用close()方法。 需要资源适配器才能在连接上提供一种方法来关闭连接。 此方法必须将close委托给创建连接句柄的ManagedConnection 。 关闭连接句柄不应关闭与EIS的物理连接。

连接管理

连接工厂中的getConnection()方法实际上不会创建连接; 它在其关联的ConnectionManager上调用allocateConnection()方法。 ConnectionManager接口由应用程序服务器实现。 实例化连接工厂时,它以实现特定的方式与连接工厂关联。 对ConnectionManager的调用允许应用程序服务器“挂接”资源适配器功能,以提供池,事务和安全服务。 可以将ConnectionRequestInfo对象传递给allocateConnection()以传递特定于连接请求的信息。

反过来, ConnectionManager调用ManagedConnection以获得连接句柄。 连接句柄通过ConnectionManager传递回连接工厂,再传递到应用程序组件。

连接池

为了支持连接池,资源适配器提供了一个实现ManagedConnectionFactory接口的类。 ManagedConnectionFactory类充当连接工厂实例和ManagedConnection实例的工厂。

当应用程序服务器需要创建连接工厂时,它将调用createConnectionFactory()方法,并传入ConnectionManager的实例。 如前所述,这是当应用程序组件在连接工厂上调用getConnection()时调用的实例。

应用程序服务器使用两个ManagedConnectionFactory方法之一来创建或请求托管连接。 当服务器需要ManagedConnection的新实例时,它将调用createManagedConnection()方法。 当服务器要重用现有的 ManagedConnection ,它将调用matchManagedConnections()方法。 为了找到正确的匹配,服务器会传递一组ManagedConnection ,它们可能满足所请求连接的条件,以及有关所需连接类型的信息。 在内部, matchManagedConnection()方法将此信息与候选集进行比较,以确定是否可以进行匹配。 如果是这样,则返回匹配的ManagedConnection ; 如果不是,则返回null 。

其他连接池方法

应用程序服务器使用许多其他ManagedConnection方法来简化连接池,如下所示:

  • cleanup()方法清除由给定ManagedConnection维护的所有特定于客户端的状态,并使与该连接关联的所有连接句柄无效。
  • 当服务器不再需要池中的ManagedConnection时,将调用destroy()方法。 调用destroy()启动与EIS的物理连接的关闭。
  • addConnectionEventListener()方法允许应用程序服务器向ManagedConnection注册一个ConnectionEventListener ,以便可以向应用程序服务器通知关闭,错误和事务发生。 ManagedConnection接口还提供了removeConnectionEventListener()方法。

该图显示了连接池的过程:

交易管理

JCA中提供两种类型的事务管理。 第一种类型涉及事务管理器,它协调单个事务中多个资源管理器的活动。 第二种类型涉及只有一个资源管理器的事务 ,称为本地事务 。 资源适配器还可以通过其部署描述符指示它不支持事务。

Java事务API(JTA) XAResource接口支持参与同一事务的多个资源管理器。 该接口允许事务管理器管理支持该接口的多个资源之间的事务。 ManagedConnection接口包含方法getXAResource() ,该方法返回XAResource对象。 应用程序服务器的事务管理器使用此对象来管理事务。 有关XAResource更多信息,请参见JTA规范。

支持本地交易

为了支持本地事务, ManagedConnection接口提供了getLocalTransaction()方法,该方法返回LocalTransaction对象。 LocalTransaction接口具有启动,提交和回滚基础EIS事务的方法。 另外,当应用程序组件开始,提交或回滚事务时, ManagedConnection必须通知其注册的ConnectionEventListener 。 localTransactionStarted() , ConnectionEventListener接口提供了localTransactionStarted() , localTransactionCommitted()和localTransactionRolledback()方法。 此图显示了此过程:

尽管getXAResource()和getLocalTransaction()方法以及ConnectionEventListener通知是资源适配器支持事务所必需的,但事务管理却很复杂,需要资源适配器和应用程序服务器之间进行大量协作。 需要对JTA,Java事务服务(JTS)和JCA的事务管理合同有详细的了解,才能有效地为EIS提供事务支持。 请参阅相关主题了解有关这些主题进一步阅读。

安全

JCA的安全性合同使用Java身份验证和授权服务(JAAS) Subject类提供安全性信息。 创建新的ManagedConnection , createManagedConnection()方法传递给Subject实例。 该连接在尝试登录EIS时使用Subject 。 一个Subject包含了信息Principal的,或者名称, Subject ,大约由委托人持有安全证书信息。

JCA定义了两种凭证。 GenericCredential是Java包装程序,表示特定的安全机制,例如Kerberos凭据。 PasswordCredential包含用户名和密码信息。 应用程序服务器必须提供这两个接口的实现。

资源适配器的部署描述符列出了支持的安全性类型,所使用的身份验证机制,所支持的凭据的接口以及是否支持重新身份验证。 ManagedConnection的getConnection()方法将“ Subject作为参数来支持重新认证。 下图显示了安全管理过程。

因为资源适配器上只有两种方法与安全性有关,所以安全性管理似乎有些简单。 但是,像事务管理一样,复杂性在于应用程序服务器和资源适配器之间的协作。 为了确保有效的安全性,需要对JAAS和JCA安全合同有全面的了解。 请参阅相关主题有关JAAS的更多信息。

ManagedConnectionMetaData接口

尽管在JCA的三个系统合同中没有特别提及,但ManagedConnectionMetaData接口是JCA的重要组件。 它提供了检索有关ManagedConnection和连接的EIS信息的方法。 这些信息包括:

  • EIS的产品名称
  • EIS的产品版本
  • EIS可以支持的最大连接数
  • 连接的用户名

通用客户端界面

总览

CCI是供应用程序组件使用的标准客户端API。 它旨在为EIS访问提供基础级别的API,EAI和工具供应商将在其上构建更高级别的功能。 CCI分为五个部分,我们将在以下各节中讨论每个部分。 CCI的五个部分是:

  • 与连接有关的接口
  • 互动相关界面
  • 数据表示相关的接口
  • 与元数据相关的接口
  • 例外和警告

不需要资源适配器即可为CCI提供支持。 实际上,资源适配器可以定义自己的客户端API,与CCI不同。

与连接有关的接口

CCI使用其ConnectionFactory接口来获取EIS的连接句柄。 ConnectionFactory提供了两种getConnection()方法:一种没有参数,另一种将ConnectionSpec实例作为参数。 当必须随连接请求一起提供特定于连接请求的信息时,使用第二个getConnection() 。

ConnectionFactory还提供方法以返回有关资源适配器的元数据信息( getResourceAdapterMetaData() )并返回记录工厂( getRecordFactory() )。

ConnectionSpec是一个空接口,可以扩展以添加所需的任何属性。 JCA定义了两个标准属性UserName和Password ,但是可能支持其他属性(或不支持任何属性)。 资源适配器应的属性映射ConnectionSpec那些的ConnectionRequestInfo打电话时allocateConnection()上ConnectionManager 。

连接方式

Connection接口是用于访问EIS的应用程序级连接句柄。 它提供以下方法来管理应用程序和EIS之间的连接:

  • close()方法允许应用程序按照连接管理协定的要求关闭连接句柄。
  • getLocalTransaction()方法允许应用程序组件使用本地事务。
  • createInteraction()方法返回一个Interaction对象,该对象用于访问EIS函数。
  • getResultSetInfo()方法返回有关EIS支持的结果集功能的信息。
  • getMetaData()函数返回有关连接的元数据。

互动相关界面

Interaction实例允许应用程序组件执行EIS功能。 它有两种execute()方法:一种采用InteractionSpec和一个输入Record并返回输出Record ,另一种则采用InteractionSpec ,一个输入Record和一个输出Record 。 此方法执行InteractionSpec定义的适当的EIS函数,并更新输出Record 。

Interaction必须与创建它的Connection保持关联,并且getConnection()必须返回该Connection 。

Interaction的close()方法应释放为Interaction维护的所有资源,但不应关闭Connection 。

标准互动属性和值

InteractionSpec接口为指定的EIS函数提供属性。 它定义了以下标准属性:

  • FunctionName是一个字符串,代表EIS函数的名称。
  • InteractionVerb是一个整数,它指定与EIS的交互方式。 InteractionVerb允许值为:
  • SYNC_SEND :输入记录被发送到EIS,没有返回结果。
  • SYNC_SEND_RECEIVE :将输入记录发送到EIS,并返回结果。
  • SYNC_RECEIVE :从EIS同步检索结果。
  • ExecutionTimeout是等待EIS执行功能的毫秒数。

数据表示相关的接口

Record接口提供用于输入或输出到EIS的数据的Java表示。 Record具有两个标准属性: RecordName和RecordShortDescription 。 表示EIS记录数据的其他属性必须由实施者定义。

还提供了三个扩展Record附加接口。 MappedRecord接口提供对键值映射集合中记录元素的访问。 IndexedRecord接口提供对记录元素的有序集合访问。 ResultSet接口基于JDBC ResultSet并提供用于访问EIS数据的类似功能。

RecordFactory接口提供了创建MappedRecord和IndexedRecord实例的方法。 RecordFactory可能支持一种,两种或两种记录类型。 如果两者都不是,则ConnectionFactory的getRecordFactory()方法应引发异常。

与元数据相关的接口

ConnectionMetaData接口提供有关EIS名称,EIS版本和用户名的信息,类似于ManagedConnectionMetaData接口。

ResourceAdapterMetaData接口提供有关适配器名称,版本,供应商,描述以及资源适配器支持的JCA版本的信息。 它还提供了确定资源适配器的以下功能的方法:是否使用InteractionSpec 支持哪些execute()方法变体; 应用程序组件是否可以划分本地事务。

例外和警告

ResourceException是系统协定和CCI的异常层次结构的根。 它提供了一个描述错误的字符串,一个错误代码以及对另一个异常的引用,这可能是导致ResourceException的较低级问题。

ResourceWarning提供有关EIS由于Interaction而返回的警告的信息。 ResourceWarning构成一个链; 在Interaction上对getWarnings()的调用将检索第一个警告,然后通过该警告访问链的其余部分。

样本资源适配器

节概述

在本节中,我们将研究JCA资源适配器的简单实现。 您可以在helloworldra.rar文件中找到示例资源适配器。 Java类位于此RAR文件中的helloworldra.jar文件中。 helloworldra.jar也提供了所有类的源代码。

您可能会从其名称中猜到,该资源适配器实现了无处不在的“ Hello World”功能。 这样,它实际上并没有连接到企业系统,并且它的功能仅限于返回一个备受喜爱的消息的String 。 尽管资源适配器未实现交易或安全性合同,但确实实现了CCI。 它使用Interaction , InteractionSpec , RecordFactory和IndexedRecord 。

您将找到示例资源适配器中最重要和最有趣的部分,这些资源在以下讨论中进行了提取和解释。 除了类和接口之外,我们还将讨论部署描述符的源代码。 通过这个简单的实现,您将对需要编写的类以及它们之间的关系有一些了解。 除了研究以下两部分之外,您还应该花一些时间查看完整的源代码,您可以在参考资料中找到完整的源代码。

HelloWorldConnectionFactoryImpl类

HelloWorldConnectionFactoryImpl类实现CCI ConnectionFactory接口,并提供应用程序组件用来创建与EIS的连接的连接工厂。 以下是创建HelloWorldConnectionFactoryImpl实例的代码,以及返回连接,记录工厂和元数据的客户端方法。

创建连接工厂实例 HelloWorldConnectionFactoryImpl类的构造函数要求传入ConnectionManager和ManagedConnectionFactory以便在getConnection()方法中使用,如下所示:

...
public HelloWorldConnectionFactoryImpl(
   ManagedConnectionFactory mcf,
   ConnectionManager cm) {

   super();
   this.mcf = mcf;
   this.cm = cm;
}
...

建立连接 HelloWorldConnectionFactoryImpl类都不支持ConnectionRequestInfo和ConnectionSpec ,因此这两个getConnection()方法都做相同的事情:它们调用ConnectionManager的allocateConnection()方法,传入ManagedConnectionFactory并为ConnectionRequestInfo传递null ,如下所示:

...
public Connection getConnection() throws ResourceException {

   return (Connection) cm.allocateConnection(mcf, null);
}

public Connection getConnection(ConnectionSpec connectionSpec) 
  throws ResourceException {

   return getConnection();
}
...

记录工厂和元数据方法 getRecordFactory()和getMetaData()方法仅返回相应接口的实现类,如下所示:

...
public RecordFactory getRecordFactory() throws ResourceException {

   return new HelloWorldRecordFactoryImpl();
}

public ResourceAdapterMetaData getMetaData() throws ResourceException {

   return new HelloWorldResourceAdapterMetaDataImpl();
}
...
HelloWorldConnectionImpl类

HelloWorldConnectionImpl类实现CCI Connection接口,并为应用程序组件提供访问EIS的连接句柄。 以下是创建,无效和关闭连接的方法,向客户端提供Interaction和元数据的方法,以及用于发出信号通知该类不支持本地事务和结果集的代码。

建立连接 HelloWorldConnectionImpl类的构造函数要求传入ManagedConnection以便在close()方法中使用。 在实例化期间设置一个标志,以指示这是有效连接,即未关闭。 在其他方法中,如果合适,将检查此标志以确定是否可以执行请求的操作。

...
public HelloWorldConnectionImpl(ManagedConnection mc) {

   super();
   this.mc = mc;
   valid = true;
	}
...

使连接无效 invalidate()方法将ManagedConnection引用设置为null并设置指示连接不再有效的标志。

...
void invalidate() {

   mc = null;
   valid = false;
}
...

断开连接 close()方法根据需要将其调用委托给ManagedConnection 。

...
public void close() throws ResourceException {

   if (valid) {
      ((HelloWorldManagedConnectionImpl) mc).close();
   }
}
...

交互和元数据方法 createInteraction()和getMetaData()方法仅返回相应接口的实现类。

...
public Interaction createInteraction() throws ResourceException {

   if (valid) {
      return new HelloWorldInteractionImpl(this);
   } else {
      throw new ResourceException(CLOSED_ERROR);
   }
}

public ConnectionMetaData getMetaData() throws ResourceException {

   if (valid) {
      return new HelloWorldConnectionMetaDataImpl();
   } else {
      throw new ResourceException(CLOSED_ERROR);
   }
}
...

引发NotSupportedException 因为此资源适配器既不支持本地事务也不支持结果集,所以getLocalTransaction()和getResultSetInfo()抛出NotSupportedException 。

...
public LocalTransaction getLocalTransaction() throws ResourceException {

   throw new NotSupportedException(TRANSACTIONS_NOT_SUPPORTED);
}

public ResultSetInfo getResultSetInfo() throws ResourceException {

   throw new NotSupportedException(RESULT_SETS_NOT_SUPPORTED);
}
...
HelloWorldManagedConnectionFactoryImpl类

HelloWorldManagedConnectionFactoryImpl类实现ManagedConnectionFactory接口。 在下面的代码中,您将看到如何创建连接工厂,如何创建托管连接以及类如何响应匹配托管连接的请求。

创建连接工厂和托管连接 createConnectionFactory()和createManagedConnection()方法仅返回相应接口的实现类。 因为此资源适配器未实现安全协定,所以在创建ManagedConnnection时, createManagedConnection()方法不使用Subject或ConnectionRequestInfo参数。

...
public Object createConnectionFactory(ConnectionManager cm)
   throws ResourceException {

   return new HelloWorldConnectionFactoryImpl(this, cm);
}

public ManagedConnection createManagedConnection(
   Subject subject,
   ConnectionRequestInfo cxRequestInfo)
   throws ResourceException {

   return new HelloWorldManagedConnectionImpl();
}
...

匹配托管连接 此资源适配器实现的简单性使每个ManagedConnection彼此之间无法区分。 因此, matchManagedConnections()方法仅返回输入Set的第一个ManagedConnection ,如下所示:

...
public ManagedConnection matchManagedConnections(
   Set connectionSet,
   Subject subject,
   ConnectionRequestInfo cxRequestInfo)
   throws ResourceException {

   ManagedConnection match = null;
   Iterator iterator = connectionSet.iterator();
   if (iterator.hasNext()) {
      match = (ManagedConnection) iterator.next();
   }

   return match;
}
...
HelloWorldManagedConnectionImpl类

HelloWorldManagedConnectionImpl类实现ManagedConnection接口。 在下面的代码中,您将看到getConnection() , close() , cleanup()和destroy()方法如何共同创建,关闭和清理连接,以及发出信号的方法资源适配器不支持事务。

建立连接 getConnection()方法首先使现有的连接句柄无效(如果存在),然后创建一个新的连接句柄,并将其存储在实例变量中。 然后,它返回对该实例变量的引用。 这将保持连接句柄和ManagedConnection之间的一对一关系。 资源适配器可能具有与ManagedConnection关联的多个连接句柄,但并非必须这样做。

...
public Object getConnection(
   Subject subject,
   ConnectionRequestInfo cxRequestInfo)
   throws ResourceException {

   if (connection != null) {
      connection.invalidate();
   }
   connection = new HelloWorldConnectionImpl(this);
   return connection;
}
...

断开连接 close()方法通知其ConnectionEventListener发生了关闭,然后使连接句柄无效。

...
public void close() {

   Enumeration list = listeners.elements();
   ConnectionEvent event =
      new ConnectionEvent(this, ConnectionEvent.CONNECTION_CLOSED);
   while (list.hasMoreElements()) {
      ((ConnectionEventListener) list.nextElement()).connectionClosed(event);
   }
   connection.invalidate();
}
...

清理并破坏连接 cleanup()和destroy()方法都使连接句柄无效。 destroy()方法还将ManagedConnection的实例变量设置为null ,以准备从应用程序服务器的连接池中删除。

...
public void cleanup() throws ResourceException {

   connection.invalidate();
}

public void destroy() throws ResourceException {

   connection.invalidate();
   connection = null;
   listeners = null;
}
...

引发NotSupportedException 因为此资源适配器不支持事务,所以getXAResource()和getLocalTransaction()方法都抛出NotSupportedException 。

...
public XAResource getXAResource() throws ResourceException {

   throw new NotSupportedException(TRANSACTIONS_NOT_SUPPORTED_ERROR);
}

public LocalTransaction getLocalTransaction() throws ResourceException {

   throw new NotSupportedException(TRANSACTIONS_NOT_SUPPORTED_ERROR);
}
...
HelloWorldInteractionImpl类

HelloWorldInteractionImpl类实现CCI Interaction接口。 在本节中,您将看到该类中一些更重要的元素如何协同工作以创建,执行和关闭Interaction 。

建立Interaction 因为JCA要求Interaction保持与用于创建它的连接句柄的关联,所以构造函数要求传入Connection 。在实例化期间设置一个标志,以指示这是有效的Interaction ,即未关闭。 在其他方法中,如果合适,将检查此标志以确定是否可以执行请求的操作。

...
public HelloWorldInteractionImpl(Connection connection) {

   super();
   this.connection = connection;
   valid = true;
}
...

执行Interaction HelloWorldInteractionImpl类仅支持具有InteractionSpec ,输入记录和输出记录的execute()变体(另一个execute()抛出NotSupportedException )。 该方法确保:

  • Interaction有效
  • 正确的InteractionSpec实现实例已传入
  • 提供了正确的输入记录类型
  • 提供了正确的输出记录类型

execute()方法 如果所有条件都正确,则“ Hello World!” 消息放置在输出记录中。 如果条件不正确,则将引发异常。

...
public boolean execute(InteractionSpec ispec, Record input, Record output)
   throws ResourceException {

   if (valid) {
      if (((HelloWorldInteractionSpecImpl) ispec)
         .getFunctionName()
         .equals(HelloWorldInteractionSpec.SAY_HELLO_FUNCTION)) {
         if (input.getRecordName().equals(HelloWorldIndexedRecord.INPUT)) {
            if 
            (output.getRecordName().equals(HelloWorldIndexedRecord.OUTPUT)) {
               ((HelloWorldIndexedRecord) output).clear();
               ((HelloWorldIndexedRecord) output).add(
                   OUTPUT_RECORD_FIELD_01);
            } else {
               throw new ResourceException(INVALID_OUTPUT_ERROR);
            }
         } else {
            throw new ResourceException(INVALID_INPUT_ERROR);
         }

      } else {
         throw new ResourceException(INVALID_FUNCTION_ERROR);
      }
   } else {
      throw new ResourceException(CLOSED_ERROR);
   }
   return true;
}
...

结束Interaction close()方法清除连接句柄并将Interaction标记为无效。

...
public void close() throws ResourceException {

   connection = null;
   valid = false;
}
...
HelloWorldInteractionSpec类

为了使用此资源适配器从应用程序组件中隐藏尽可能多的实现细节, HelloWorldInteractionSpec接口扩展了InteractionSpec 。 InteractionSpec接口使我们能够提供应用程序组件必须具有的所有信息。 在下一节中,我们将查看此接口的实现类。

...
public interface HelloWorldInteractionSpec extends InteractionSpec {

   public static final String SAY_HELLO_FUNCTION = "sayHello";

   public String getFunctionName();
   public void setFunctionName(String functionName);
}
HelloWorldInteractionSpecImpl类

HelloWorldInteractionSpecImpl类实现了HelloWorldInteractionSpec接口。 它具有一个属性FunctionName ,具有用于访问该属性的获取器和设置器。 JCA规范指出,必须对InteractionSpec实现中的属性进行绑定或约束。 此实现提供了绑定的属性。

...
public String getFunctionName() {

   return functionName;
}

public void setFunctionName(String functionName) {

   String oldFunctionName = functionName;
   this.functionName = functionName;
   firePropertyChange("FunctionName", oldFunctionName, functionName);
}
...
HelloWorldIndexedRecord类

像HelloWorldInteractionSpec一样, HelloWorldIndexedRecord接口用于从应用程序组件隐藏实现细节。

...
public interface HelloWorldIndexedRecord extends IndexedRecord {

   public static final String INPUT = "input";
   public static final String OUTPUT = "output";
   public static final int MESSAGE_FIELD = 0;
}
HelloWorldIndexedRecordImpl类

HelloWorldIndexedRecordImpl类实现了HelloWorldIndexedRecord接口。 它具有两个属性, Name和ShortDescription ,具有用于访问属性的getter和setter。 因为此类还必须实现List接口,所以它将ArrayList维护为实例变量,并通过在ArrayList上调用相应的方法来实现所有List方法。

...
public class HelloWorldIndexedRecordImpl implements HelloWorldIndexedRecord {

   private ArrayList list = new ArrayList();
   private String name;
   private String description;
...
HelloWorldRecordFactoryImpl类

HelloWorldRecordFactoryImpl类实现RecordFactory接口。 它不支持创建MappedRecord 。

createIndexedRecord()方法确保所请求的记录名称有效,然后创建记录并返回它。 如果记录名称无效,则引发异常。

...
public IndexedRecord createIndexedRecord(String recordName)
   throws ResourceException {

   HelloWorldIndexedRecordImpl record = null;

   if ((recordName.equals(HelloWorldIndexedRecord.INPUT))
      || (recordName.equals(HelloWorldIndexedRecord.OUTPUT))) {
      record = new HelloWorldIndexedRecordImpl();
      record.setRecordName(recordName);
   }
   if (record == null) {
      throw new ResourceException(INVALID_RECORD_NAME);
   } else {
      return record;
   }
}
...

部署描述符

部署描述符提供以下JCA组件的标准名称:

  • ManagedConnectionFactory实现类
  • ConnectionFactory接口
  • ConnectionFactory实现类
  • Connection界面
  • Connection实现类

它还表明既不支持事务也不支持重新认证。 如果支持交易和安全合同,则部署描述符将包含其他元素。

< !DOCTYPE connector PUBLIC '-//Sun Microsystems, Inc.//
  DTD Connector 1.0//EN' 'http://java.sun.com/dtd/connector_1_0.dtd'>

<connector>
   <display-name>Hello World Sample</display-name>
   <vendor-name>Willy Farrell</vendor-name>
   <spec-version>1.0</spec-version>
   <eis-type>Hello World</eis-type>
   <version>1.0</version>
   <resourceadapter>
      <managedconnectionfactory-class>
      com.ibm.ssya.helloworldra.HelloWorldManagedConnectionFactoryImpl
      </managedconnectionfactory-class>
      <connectionfactory-interface>
      javax.resource.cci.ConnectionFactory
      </connectionfactory-interface>
      <connectionfactory-impl-class>
      com.ibm.ssya.helloworldra.HelloWorldConnectionFactoryImpl
      </connectionfactory-impl-class>
      <connection-interface>
      javax.resource.cci.Connection
      </connection-interface>
      <connection-impl-class>
      com.ibm.ssya.helloworldra.HelloWorldConnectionImpl
      </connection-impl-class>
      <transaction-support>
      NoTransaction
      </transaction-support>
      <reauthentication-support>
      false
      </reauthentication-support>
   </resourceadapter>
</connector>

样品申请

J2EE Web应用程序

You should now have a fairly comprehensive understanding of how JCA's components work together to create and manage complex interactions with an enterprise system. All that's left to do is play with the code itself. You will find a sample application that uses the sample resource adapter in the file helloworldra.ear . It is a J2EE Web application with an input HTML form (with only a Submit button), a servlet controller, a JavaBeans component that invokes the resource adapter, and a JavaServer Pages (JSP) component to display the results of the invocation.

We'll close this tutorial with a look at the bean that invokes the resource adapter, as well as another class (provided separately from the .ear file) that helps deploy an InteractionSpec instance into JNDI.

HelloWorldBean class

This HelloWorldBean class, through its execute() method, invokes the resource adapter, using the CCI interface. First, the ConnectionFactory is retrieved from JNDI and is used to create a RecordFactory . The RecordFactory is used to create an input record and an output record.

Next, an InteractionSpec is retrieved from JNDI. Then a Connection is created from the ConnectionFactory and an Interaction is created from the Connection . The Interaction is used to execute the function, and the results are stored in the bean's Message property.

You will observe that the two JNDI lookups are different. The lookup of the ConnectionFactory is done using the java:comp/env context, while the lookup of the InteractionSpec is not. This is because the environment that was used to develop and test the resource adapter and sample application did not have a deployment tool to bind an InteractionSpec into JNDI; it only provided for binding the ConnectionFactory , which could then be accessed using a resource reference in the Web application.

...
public void execute() throws NamingException, ResourceException {

   InitialContext context = new InitialContext();
   ConnectionFactory cxFactory =
      (ConnectionFactory) context.lookup("java:comp/env/HelloWorld");
   RecordFactory recordFactory = cxFactory.getRecordFactory();
   IndexedRecord input =
      recordFactory.createIndexedRecord(HelloWorldIndexedRecord.INPUT);
   IndexedRecord output =
      recordFactory.createIndexedRecord(HelloWorldIndexedRecord.OUTPUT);
   InteractionSpec ispec =
      (InteractionSpec) context.lookup("jca/HelloWorldISpec");
   Connection connection = cxFactory.getConnection();
   Interaction interaction = connection.createInteraction();
   interaction.execute(ispec, input, output);
   message = (String) output.get(HelloWorldIndexedRecord.MESSAGE_FIELD);
   interaction.close();
   connection.close();
}
...

DeployISpec class

The DeployISpec class, which is provided in the helloworldradeploy.jar file, is used to deploy the InteractionSpec object into JNDI if your deployment environment does not provide a tool to accomplish that. It has a simple main() method that creates the InteractionSpec and binds it into JNDI. This class should be run after the resource adapter is deployed and the connection factory has been bound into JNDI.

...
public static void main(String[] args) throws NamingException {

 Properties properties = new Properties();
 properties.put(Context.INITIAL_CONTEXT_FACTORY, INITIAL_CONTEXT_FACTORY);
 InitialContext context = new InitialContext(properties);
 HelloWorldInteractionSpecImpl ispec = new HelloWorldInteractionSpecImpl();
 ispec.setFunctionName(HelloWorldInteractionSpec.SAY_HELLO_FUNCTION);
 context.bind("jca/HelloWorldISpec", ispec);
}
...

Running the code

After deploying the resource adapter into your application server environment, create a connection factory with the JNDI name of jca/HelloWorld . Then run the DeployISpec class to bind the InteractionSpec into JNDI under the name jca/HelloWorldISpec .

After deploying the Web application, you should pull up a browser and load the URL http://SERVER_NAME/hello . Once the page has loaded, click the Submit button and the results page with the "Hello World!" message should appear.

The sample resource adapter and sample application were successfully deployed and tested on IBM WebSphere Application Server Advanced Edition Version 4.03.

Wrapping up

摘要

In this tutorial, you have been introduced to the J2EE Connector Architecture. We started with a high-level view of JCA and its primary elements: system contracts, the client API, and the resource adapter module. From there, we moved on to a more detailed discussion, encompassing the interfaces, classes, and methods that work beneath JCA to create and manage connections to an EIS. As part of this discussion, we looked at the source code for an actual JCA implementation. Each of the most relevant components of the implementation was pulled out, and its various functions explained in detail. We closed with an actual resource adapter implementation, which you are free to continue exploring on your own.

This tutorial has provided you a hands-on, step-by-step introduction to the J2EE Connector Architecture, the most relevant components beneath that architecture, and the functionality of each of those components. You should now have a fairly good foundation for building your own JCA resource adapter and connecting to an EIS.


翻译自: https://www.ibm.com/developerworks/java/tutorials/j-jca/j-jca.html