JavaBeans:创建客户端应用
来源:优易学  2011-11-29 16:11:19   【优易学:中国教育考试门户网】   资料下载   IT书店

  Cabin实体和 TravelAgent EJB已经部署完毕,我们打算从远程客户端对其进行访问。本节中,我们会创建一个远程客户端,连向EJB服务器,为TravelAgent EJB定位EJB远程接口,并与TravelAgent EJB进行交互,以创建Cabin实体并将其从数据库中取出。下列代码展示了一个Java应用程序,该程序新建了一个Cabin实体,设置其name、 deckLevel、shipId和bedCount成员属性,然后再用主键对其进行定位。

  package com.titan.clients;

  import com.titan.travelagent.TravelAgentRemote;

  import com.titan.domain.Cabin;

  import javax.naming.InitialContext;

  import javax.naming.Context;

  import javax.naming.NamingException;

  import java.util.Properties;

  import javax.rmi.PortableRemoteObject;

  public class Client {

  public static void main(String [] args) {

  try {

  Context jndiContext = getInitialContext( );

  Object ref = jndiContext.lookup( "TravelAgentBean/remote");

  TravelAgentRemote dao = (TravelAgentRemote)

  PortableRemoteObject.narrow(ref,TravelAgentRemote.class);

  Cabin cabin_1 = new Cabin( );

  cabin_1.setId(1);

  cabin_1.setName( "Master Suite");

  cabin_1.setDeckLevel(1);

  cabin_1.setShipId(1);

  cabin_1.setBedCount(3);

  dao.createCabin(cabin_1);

  Cabin cabin_2 = dao.findCabin(1);

  System.out.println(cabin_2.getName( ));

  System.out.println(cabin_2.getDeckLevel( ));

  System.out.println(cabin_2.getShipId( ));

  System.out.println(cabin_2.getBedCount( ));

  } catch (javax.naming.NamingException ne){ne.printStackTrace( );}

  }

  public static Context getInitialContext( )

  throws javax.naming.NamingException {

  Properties p = new Properties( );

  // ... 指定厂商专有的JNDI属性

  return new javax.naming.InitialContext(p);

  }

  }

  为了访问enterprise bean,客户端首先使用JNDI获得一个连向bean所在容器的目录。JNDI是一组独立于实现的API,用于目录和命名系统。每家EJB厂商都必须提供一个与JNDI兼容的目录服务。这意味着他们必须给出一个JNDI service provider(JNDI服务提供程序),即一段类似JDBC驱动的软件代码。不同的service provider与不同的目录服务相连接,就如同JDBC一样,不同的驱动程序与不同的关系数据库相连接。getInitialContext()方法使用JNDI来获得一个指向EJB服务器的网络连接。

  用于获取JNDI上下文的代码和你使用哪一家EJB厂商的产品有关。如何获取与你所用的产品相配的JNDI上下文,请参考厂商文档。例如,在WebSphere中用于获取JNDI上下文的代码可能类似如下。

  public static Context getInitialContext( )

  throws javax.naming.NamingException {

  java.util.Properties properties = new java.util.Properties( );

  properties.put(javax.naming.Context.PROVIDER_URL, "iiop:///");

  properties.put(javax.naming.Context.INITIAL_CONTEXT_FACTORY,

  "com.ibm.ejs.ns.jndi.CNInitialContextFactory");

  return new InitialContext(properties);

  }

  而针对JBoss编写的同一方法会有所不同。

  public static Context getInitialContext( )

  throws javax.naming.NamingException {

  Properties p = new Properties( );

  p.put(Context.INITIAL_CONTEXT_FACTORY,

  "org.jnp.interfaces.NamingContextFactory");

  p.put(Context.URL_PKG_PREFIXES,

  " org.jboss.naming:org.jnp.interfaces");

  p.put(Context.PROVIDER_URL, "jnp://localhost:1099");

  return new javax.naming.InitialContext(p);

  }

  一旦建立起JNDI连接,并且通过getInitialContext()方法获得了上下文,我们就可以利用上下文来查找TravelAgent EJB的远程接口了。

  Object ref = jndiContext.lookup("TravelAgentBean/remote");

  在本书中,我们将始终为远程客户端应用程序使用形如“TravelAgentBean/remote”这样的查找名称。你所用的实际查找名称或许有所不同,这依赖于厂商的要求。你需要把查找名称绑定到EJB服务器的命名服务上,而有些厂商可能会要求一个特殊的目录路径,或者提供一个默认的绑定。

  如果使用标准的Java EE组件(Servlet、JSP、EJB或Java EE应用客户端),无论你使用哪家EJB厂商的产品,在创建JNDI InitialContext时都不需要显式的设置属性。这是因为JNDI属性可以在部署期间配置并被自动应用。一个Java EE组件会以如下方式获得其InitialContext。

  public static Context getInitialContext( )

  throws javax.naming.NamingException {

  return new javax.naming.InitialContext( );

  }

  相比于为简单Java客户端手工配置JNDI属性,这种方式更为简单,也更易于移植。所有的Java EE组件都使用相同的JNDI命名系统,enterprise bean以此来查找任何服务。特别要指明的是,这些组件要求指向EJB的引用要与“java:comp/env/ejb/”名字空间绑定。例如,对于像 servlet这样一个不同的Java EE组件而言,为了查找TravelAgent EJB,下面是我们所要做的全部工作。

  Object ref = jndiContext.lookup("java:comp/env/ejb/TravelAgentRemote");

  在部署期间,你要使用厂商的部署工具将JNDI名称映射到TravelAgent EJB的远程接口。在后续章节里,我们会看到使用特殊的注解可以将指向EJB的引用直接注入到bean class中。我们已经看到过这种方式的一个例子,即:将EntityManager服务注入到Travel- AgentBean类里。在本书中,Java客户端应用程序需要使用显式的参数来进行JNDI查找。作为替代方案,你也可以使用一种特殊的Java EE组件,叫做Java EE应用客户端(Java EE Application Client),但是这类组件超出了本书的讨论范围。有关Java EE应用客户端组件的更多信息可以参考Java EE 5的规范。

  客户端应用程序使用PortableRemoteObject.narrow()方法将Object ref窄化(narrow)成一个TravelAgentRemote引用。

  Object ref = jndiContext.lookup("TravelAgentRemote");

  CabinHomeRemote home = (TravelAgentRemote)

  PortableRemoteObject.narrow(ref,TravelAgentRemote.class);

  PortableRemoteObject.narrow()方法在EJB 1.1中被首次引入,并继续沿用于EJB 3.0的远程客户端。这需要支持基于IIOP之上的RMI。由于CORBA要支持许多不同的语言,而转型并非CORBA的固有功能(一些语言没有转型概念)。因此,为了获得一个指向TravelAgentRemote的远程引用,我们必须显示地对从lookup()返回的对象进行窄化。

  用于查找TravelAgent EJB远程接口的名称,可以是特定于厂商的默认值,特定于厂商的注解,或部署描述文件。或者,如果EJB产品中带有部署向导,还可以由部署人员使用向导来设置。JNDI的名称完全取决于部署bean的人;可以与在XML部署描述文件中设定的bean名字相同,也可以截然不同。

责任编辑:小草

文章搜索:
 相关文章
热点资讯
热门课程培训