第五章 命名规则
这一章讲述JAVA2平台(企业版)的命名系统需求。这些要求是基于JNDI说明书的规则的。
注--此章节的大部分都摘自EJB1.1说明书,第14章,"企业组件环境".
5.1 概述
应用程序的编译者和展开者不需要访问程序原代码就能够定制一个应用程序的业务逻辑。
另外,ISVs开发的典型的应用程序是,在很大的程度上,独立于应用程序要运行的操作环境。大多数应用程序必须访问资源和外部信息。关键的问题就是在不知道目标操作环境中,外部信息是如何命名和组织的情况下,怎么来定位外部信息。
为满足上述的情况,这个说明书定义了J2EE平台的命名要求。
这一章的结构是:
5.2小节定义了一些规定和访问应用构件命名环境的接口.这一
小节举例说明了应用构件的命名环境是如何规定通用的应用程序业务逻辑的。
5.3小节定义了能得到一个EJB组件的内部接口的一些接口函
数。EJB标准在应用构件环境中是一个很特殊的入口。
5.4小节定义了能得到一个resource factory的一些接口函数。
Resource factory标准在应用构件环境中是个很特殊的入口。
只有J2EE应用程序客户端、企业组件和网络构件是需要访问一个JNDI命名环境的。只有这些应用构件类型的容器必须提供命名环境描述符。
这里的展开描述符入口描述是和每个应用部件的DTDs描述同一形式的。可以查看相应的说明得到相关的细节。
5.2JNDI命名关系
应用构件的命名环境是以下的一个在编译和展开的时候允许规定构件业务逻辑的机制。这个环境允许不需要访问或修改原代码就可以规定应用构件。
容器实现了应用构件的环境,并且把它作为一个JNDI命名关系给应用构件使用。它是如下被运用的:
1.应用构件的业务方法运用JNDI接口访问环境。应用构件的提供者必须在展开描述符中声明所有运行时需要的的环境入口。
2.容器给JNDI命名关系提供一个存储应用构件环境的实现方法。它也提供允许展开者创建和管理每个构件环境的工具。
3.展开者运用容器提供的工具初始化在展开描述符中声明的环境入口。他能设置和修改入口的值。
4.容器使命名关系能在应用构件事例在运行时运用。这些事例用JNDI接口来得到环境入口的值。
每个应用构件定义它自己的一套环境入口。同一容器的中的所有应用构件事例可分享相同的环境入口。事例在运行是不允许修改环境。
注--术语警告:应用构件的"环境"不能于JNDI文档中定义的"环境属性"相混淆。"环境属性"是用来初始化和配置JNDI命名关系自己的。应用构件直接运用JNDI命名关系可以访问应用构件环境。
下面的小节描述了每个J2EE角色的职责。
5.2.1应用构件提供者的职责
这一节描述了应用构件提供者在构件环境中的观点,并定义了他或着她的职责,共分2小节,第一节描述了访问环境入口的API函数,第二节描述了声明环境入口的语法。
5.2.1.1访问应用构件的环境
一个应用构件事例通过JNDI接口定位环境命名关系。一个事例用没有参数的构造函数创建了一个Javax.naming.InitialContext对象,通过java:comp/env下面的InitialContext查找命名环境。应用构件的环境入口是直接存储在环境命名关系中的,或者是在任何一个它的直接或间接的子关系中。
环境入口的值的类型是构件提供者在展开描述符中声明的JAVA类型。
下面的代码举例说明了一个应用构件如何访问它的环境入口的。
...
// Obtain the application component's environment naming context.
Context initCtx = new InitialContext();
Context myEnv = (Context)initCtx.lookup("java:comp/env");
// Obtain the maximum number of tax exemptions
// configured by the Deployer.
Integer max = (Integer)myEnv.lookup("maxExemptions");
// Obtain the minimum number of tax exemptions
// configured by the Deployer.
Integer min = (Integer)myEnv.lookup("minExemptions");
// Use the environment entries to customize business logic.
if (numberOfExeptions > max.intValue() ||
numberOfExemptions < min.intValue())
throw new InvalidNumberOfExemptionsException();
// Get some more environment entries. These environment
// entries are stored in subcontexts.
String val1 = (String)myEnv.lookup("foo/name1");
Boolean val2 = (Boolean)myEnv.lookup("foo/bar/name2");
// The application component can also lookup using full pathnames.
Integer val3 = (Integer)
initCtx.lookup("java:comp/env/name3");
Integer val4 = (Integer)
initCtx.lookup("java:comp/env/foo/name4");
...
}
5.2.1.2声明环境入口
应用构件提供者必须声明所有原代码中访问到的环境入口。这些入口是通过展开描述符中的env-entry元素来声明的。每个env-entry元素描述单独一个环境入口。它包含一个可选的描述:与java:comp/env关系关联的环境入口名称、环境入口值的JAVA类型(例如,JNDIlookup方法中返回的对象的类型)和一个可选的环境入口的值。
环境入口的值可以是以下JAVA类型之一:String、Byte、 Short、 Integer、 Long、 Boolean、 Double、 and Float。
如果应用构件提供者为一个环境入口提供了一个值,那么这个值以后就能被应用程序的编译者和展开者修改。这个值必须是一个对一个带单个字符串参数的构造函数有效的字符串。
下面的例子是被前一节例子的构件引用的环境入口的声明过程。
...
<env-entry>
<description>
The maximum number of tax exemptions
allowed to be set.
</description>
<env-entry-name>maxExemptions</env-entry-name>
<env-entry-type>java.lang.Integer</env-entry-type>
<env-entry-value>15</env-entry-value>
</env-entry>
<env-entry>
<description>
The minimum number of tax exemptions
allowed to be set.
</description>
<env-entry-name>minExemptions</env-entry-name>
<env-entry-type>java.lang.Integer</env-entry-type>
<env-entry-value>1</env-entry-value>
</env-entry>
<env-entry>
<env-entry-name>foo/name1</env-entry-name>
<env-entry-type>java.lang.String</env-entry-type>
<env-entry-value>value1</env-entry-value>
</env-entry>
<env-entry>
<env-entry-name>foo/bar/name2</env-entry-name>
<env-entry-type>java.lang.Boolean</env-entry-type>
<env-entry-value>true</env-entry-value>
</env-entry>
<env-entry>
<description>Some description.</description>
<env-entry-name>name3</env-entry-name>
<env-entry-type>java.lang.Integer</env-entry-type>
</env-entry>
<env-entry>
<env-entry-name>foo/name4</env-entry-name>
<env-entry-type>java.lang.Integer</env-entry-type>
<env-entry-value>10</env-entry-value>
</env-entry>
...
5.2.2应用构件编译者的职责
编译者可以修改组件提供者已设置的环境入口的值,而且可以设置那些没有规定任何初始值的环境入口。
5.2.3展开者的职责
展开者必须确保所有环境入口的值已经被构件声明为一个有效的值。
展开者可以修改那些构件提供者或是编译者先前已经修改过的环境入口的值,而且必须设置那些一直没有被初始化过的环境入口。
5.2.4J2EE产品提供者的职责
J2EE产品提供者的职责如下:
提供一个展开工具,允许展开者设置和修改应用构件环境入口的值。
实现java:comp/env环境命名关系,提供给应用构件在运行时使用。这个命名关系必须包含所有的构件提供者声明过的环境入口,以及在展开描述符中提供或是展开者设置过的值。如果需要的话,环境命名关系必须允许展开者创建子关系。
容器必须确保应用构件事例对环境变量只有只读权。所有
javax.naming.Context接口中的方法,如果修改环境命名关系或是其子关系的就必须抛出javax.naming.OperationNotSupportedException异常。
5.3EJB标准
这一节描述程序和展开描述符接口,它们允许应用构件提供者参考运用"逻辑"名字(EJB标准)的企业组件的内部。EJB标准在命名环境中是特殊的入口。展开者把目标环境中的内部企业组件和EJB标准绑定在一起。
展开描述符也允许编译者把同一个J2EE应用程序中的EJB标准和一个ejb-jar文件中的组件链接在一起。这个链接就代表着展开描述符把规定的目标企业组件和EJB标准绑定在一起。
5.3.1应用构件提供者的职责
这一节描述了对于EJB标准,应用构件提供者的观点和责任。它共分两节,第一节描述了访问EJB标准的API函数,第二节描述了声明EJB标准的语法。
5.3.1.1EJB标准的程序接口
应用构件提供者必须通过以下方法用EJB标准来定位企业组件内部接口。
按照参考指定一个环境中的入口。(查看5.3.1.2小节了解如何在展开描述符中声明EJB标准)这里推荐,但不是必须,所有的企业组件的参考组织在环境的ejb子关系中.用JNDI查找组件的内部接口。
下面的例子说明了一个应用构件如何用EJB标准来定位企业组件的内部接口。
Public void changePhoneNumber(…) {
…
// Obtain the default initial JNDI context.
Context initCtx = new InitialContext();
// Look up the home interface of the EmployeeRecord
// enterprise bean in the environment.
Object result = initCtx.lookup(
"java:comp/env/ejb/EmplRecord");
// Convert the result to the proper type.
EmployeeRecordHome emplRecordHome = (EmployeeRecordHome)
javax.rmi.PortableRemoteObject.narrow(result,
EmployeeRecordHome.class);
…
}
在这个例子中,应用构件提供者把ejb/EmplRecord当作EJB标准赋值给环境入口,来参照企业组件内部。
5.3.1.2声明EJB标准
虽然EJB标准是一个应用构件的环境入口,但构件提供者不能用env-entry元素来声明它,而必须用展开描述符中的ejb-ref元素。它允许构件的jar文件的用户(例如应用程序的编译和展开者)发现所有构件使用的EJB标准。
每个ejb-ref元素描述作为参考的企业组件的接口要求。它包含了一个可选的description元素,和强制的ejb-ref-name、ejb-ref-type、 home和remote元素。
Ejb-ref-name元素规定EJB标准名字;它的值在构件原代码中用到的环境入口名字。Ejb-ref-type元素规定了组件的期望类型;它的值必须是Entity或是Session。Home和remote元素规定了被参考的组件内部和远程接口的JAVA类型。
下面的例子举例说明了在展开描述符中如何声明EJB标准。
…
<ejb-ref>
<description>
This is a reference to the entity bean that
encapsulates access to employee records.
</description>
<ejb-ref-name>ejb/EmplRecord</ejb-ref-name>
<ejb-ref-type>Entity</ejb-ref-type>
<home>com.wombat.empl.EmployeeRecordHome</home>
<remote>com.wombat.empl.EmployeeRecord</remote>
</ejb-ref>
<ejb-ref>
<ejb-ref-name>ejb/Payroll</ejb-ref-name>
<ejb-ref-type>Entity</ejb-ref-type>
<home>com.aardvark.payroll.PayrollHome</home>
<remote>com.aardvark.payroll.Payroll</remote>
</ejb-ref>
<ejb-ref>
<ejb-ref-name>ejb/PensionPlan</ejb-ref-name>
<ejb-ref-type>Session</ejb-ref-type>
<home>com.wombat.empl.PensionPlanHome</home>
<remote>com.wombat.empl.PensionPlan</remote>
</ejb-ref>
…
5.3.2应用构件编译者的职责
应用构件编译者能用展开描述符的ejb-link元素来链接EJB标准到目标企业组件。展开工具会发现这个链接。
编译者按以下方法规定一个到企业组件的链接:
l应用程序编译者用ejb-ref元素中可选的ejb-link元素。它的值是
目标企业组件的名字。(在目标组件的ejb-name元素中定义)目标组件在同一个J2EE应用的ejb-jar文件中作为参考构件。
编译者必须保证目标企业组件和声明的EJB标准是兼容的。这就意味着它的类型必须是在ejb-ref-type中规定的类型,而且它的内部和远程接口也必须是于EJB标准中声明过的类型相兼容。
下面的例子举例说明了在展开描述符中ejb-link元素的用处。组件的名字必须是EmployeeRecord。它可以象构件实现这个接口一样打包在一个相同的模块中,或者打包到同一个J2EE应用中的另一个模块。
...
<ejb-ref>
<description>
This is a reference to the entity bean that
encapsulates access to employee records. It
has been linked to the entity bean named
EmployeeRecord in this application.
</description>
<ejb-ref-name>ejb/EmplRecord</ejb-ref-name>
<ejb-ref-type>Entity</ejb-ref-type>
<home>com.wombat.empl.EmployeeRecordHome</home>
<remote>com.wombat.empl.EmployeeRecord</remote>
<ejb-link>EmployeeRecord</ejb-link>
</ejb-ref>
...
5.3.3应用构件展开者的职责
展开者的职责如下:
展开者必须确保所有声明的EJB标准已经和操作环境中存在的组件部绑定在一起。展开者可以用,比如,JNDI LinkRef机制来创建一个链接到真实的组件内部JNDI名字的标记。
展开者必须确保目标企业组件是和EJB标准声明的类型相兼容。这就意味着它的类型必须是在ejb-ref-type中规定的类型,它的内部和远程接口必须和EJB标准中声明的兼容。
如果EJB标准声明中包括ejb-link元素,展开者必须把组件参考当作链接对象绑定到组件内部。
5.3.4J2EE产品提供者的职责
J2EE产品提供者必须提供展开工具,允许展开者执行在前面的小节中描述的任务。这些工具必须能够处理由展开描述符中的ejb-ref元素提供的信息。
这些工具至少能够完成以下功能:
通过绑定一个EJB标准到规定的目标企业组件内部接口上,保存应用程序ejb-link元素中的编译信息。
通知展开者所有未定的EJB标准,允许他或她通过绑定到兼容的目标组件上来决定一个标准。
5.4资源因子标准
一个资源是封装在一个资源管理器中的对象。一个资源因子是一个用来创建资源的对象。举个例子来说,一个实现java.sql.Connection接口的对象是一个提供反问一个数据库管理系统的资源,一个实现javax.sql.DataSource接口的对象是一个资源因子。
这一小节描述了允许应用构件代码参考资源因子的程序和展开描述符,也叫资源因子标准。它也是应用构件环境中的一个特殊的入口。展开者把资源因子标准绑定到真实存在在目标操作环境中的资源因子上。
通过命名环境访问的资源因子只有在构件事例中被查询的时候才是有效的。
查看个体构件说明书可以得到附加的限制。
5.4.1应用构件提供者的职责
这一节描述了对于定位资源因子标准,应用构件提供者的观点和责任。它共分两节,第一节描述了访问资源因子标准的API函数,第二节描述了声明资源因子标准的语法。
5.4.1.1资源因子标准的程序接口
构件提供者必须按以下方法使用资源因子标准来得到资源。
在应用构件命名环境中为资源因子标准定一个入口。(查看5.4.1.2小节得到如何在展开描述符中声明资源因子标准的方法)。
这里推荐,但不是必须,所有的资源因子标准组织到构件环境的子关系中,每个资源管理类型用一个不同的子关系。比如,所有的JDBC数据源标准须声明在java:comp/env/jdbc子关系中,所有的JMS连接因子在java:comp/env/jms子关系中声明,所有的JavaMail连接因子在java:comp/env/mail子关系中声明,所有的URL连接因子在java:comp/env/url子关系中声明。
用JNDI接口在应用构件环境中查找资源因子对象。
在资源因子方法上调用适当的方法来得到资源。这个因子方法是对因子的类型专用的。它能通过多个资源对象通过多次呼叫资源因子。
构件提供者要关联主要的资源访问有两个选择:
l.允许展开者建立主体映射或是资源通信开始的信息。这样,构件代码调用资源因子方法就没有安全参数。
2.在代码中标记资源,这样构件调用资源因子方法就可以把这个标记信息作为方法的参数。
构件提供者用res-auth展开描述符元素来证明哪种方法被使用了。
我们希望第一种规则(例如,让展开者建立资源标记信息)被大部分构件使用。
下面的代码举例说明了得到一个资源。
public void changePhoneNumber(...) {
...
// obtain the initial JNDI context
Context initCtx = new InitialContext();
// perform JNDI lookup to obtain resource factory
javax.sql.DataSource ds = (javax.sql.DataSource)
initCtx.lookup("java:comp/env/jdbc/EmployeeAppDB");
// Invoke factory to obtain a resource. The security
// principal for the resource is not given, and therefore
// it will be configured by the Deployer.
java.sql.Connection con = ds.getConnection();
...
5.4.1.2资源因子标准的声明
虽然资源因子标准是一个应用构件环境的入口,但构件提供者不能用env-entry元素来声明它。
而必须用resource-ref元素来声明所有的资源因子标准。这就允许了应用构件的jar文件的用户可以发现构件使用到的资源因子标准。
每个resource-ref元素描述了一个单独的资源因子标准。resource-ref元素包含了description元素;和强制res-ref-name、 res-type和res-auth元素。res-ref-name元素包含了构件代码用到的环境入口名字。res-type元素包含了构件代码期望得到的资源因子的JAVA类型。res-auth元素规定了构件代码是否在程序中使用了资源标记的方法,或者是用了主要映射信息。构件提供者通过设置res-auth元素的值为Bean或者Container。
...
<resource-ref>
<description>
A data source for the database in which
the EmployeeService enterprise bean will
record a log of all transactions.
</description>
<res-ref-name>jdbc/EmployeeAppDB</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
5.4.1.3标准资源因子类型
应用构件提供者必须用javax.sql.DataSource资源因子类型来得到JDBC连接。
构件提供者必须用javax.jms.QueueConnectionFactory或者
javax.jms.TopicConnectionFactory来得到JMS连接。
构件提供者必须用javax.mail.Session资源因子类型来得到JavaMail连接。
构件提供者必须用java.net.URL资源因子类型来得到URL连接。
推荐构件提供者在java:comp/env/jdbc子关系中命名JDBC数据源。所有的JMS连接因子在java:comp/env/jms子关系中命名,所有的JavaMail连接因子在java:comp/env/mail子关系中命名,所有的URL连接因子在java:comp/env/url子关系中命名。
注:下一个说明版本会增加"connector"机制,它允许一个应用构件用这一节中描述的API函数来得到资源对象访问后断系统。
5.4.2应用构件展开者职责
展开者用展开工具把实际操作环境中的资源因子绑定到资源因子标准上。
展开者必须完成以下的任务来声明每个资源因子标准。
l. 绑定资源因子标准到一个存在于操作环境的资源因子上。展开者可以用比如JNDI LinkRef的机制来创建一个连接标记到一个真实资源因子的JNDI名字。它的类型必须和在res-type元素中声明的类型兼容。
2. 为资源管理者需要的打开管理资源提供任何附加的配置信息。这个配置机制是资源管理者说明的,超出了这个说明的范围。
3. 如果res-auth元素的值是Container,展开者就有职责配置资源的标记信息。这是容器和资源管理者的任务,超出了这个说明的范围。
举个例子来说,如果主体必须从安全域中映射,主体方面用在构件层中的安全域中,主体方面是资源管理者,展开者或者系统管理员必须定义映射。映射是有容器和资源管理员做的事,超出了这个说明的范围。
5.4.3J2EE产品提供者的职责
J2EE产品提供者的职责如下:
l 提供展开工具允许展开者执行描述前面小节所说的任务。
l 提供实现资源因子类的方法。
l 如果构件提供者把资源因子设置为Bean,那么这个容器必须允许应用构件来显示使用资源管理者的API的标记。
l 容器必须提供工具允许展开者设置资源标记信息配置那些res-auth设置为Container的标准。最起码这些展开者能为每个资源标准规定用户/密码信息,容器必须能在获得资源执行资源因子的时候根据用户/密码识别用户。
虽然没有要求,但我们希望容器能支持一些单个标记的信息。允许展开者设置那些主体能被传播的资源(直接或通过主体映射),如果应用程序需要。
这个说明没有要求,但大多数J2EE产品回提供以下特征:
l. 一个允许系统管理员增加、删除、修改一个J2EE服务器的资源管理器的工具。
l. 一个应用构件资源池的机制,或者是通过容器管理资源的使用。这个池必须对应用构件是透明的。
5.4.4系统管理员的职责
系统管理员的典型职责如下:
在J2EE服务环境中增加、删除、修改资源管理器。
有些时候这些任务能有展开者来完成。
5.5用户事务标准
许多J2EE应用构件类型允许用JTA UserTransaction接口来开始,委托和终止事务。在这样的应用构件中,通过查找JNDI名字java:comp/UserTransaction,能发现一个适当的对象来执行UserTransaction接口。这个容器只需要为那些能妥当运用的构件提供java:comp/UserTransaction方法。任何这种UserTransaction
对象只有在一个执行查找的构件事例中才有效。查看个人构件定义获得很多的信息。
下面的例子说明了一个应用构件调入和使用一个UserTransaction对象。
public void updateData(...) {
...
// Obtain the default initial JNDI context.
Context initCtx = new InitialContext();
// Look up the UserTransaction object.
UserTransaction tx = (UserTransaction)initCtx.lookup(
"java:comp/UserTransaction");
// Start a transaction.
tx.begin();
...
// Perform transactional operations on data.
...
// Commit the transaction.
tx.commit();
...
}
5.5.1应用构件提供者的职责
应用构件提供者有责任运用定义的名字来查找UserTransaction对象。只有一些应用构件类型是可以访问一个UserTransaction对象的。看表6-1和EJB1.1说明得到详细介绍。
5.5.2展开者的职责
展开者没有规定与此相关的职责。
5.5.3J2EE产品提供者的职责
J2EE产品提供者对于UserTransaction对象的职责是必须的。
5.5.4系统管理员的职责
系统管理员没有规定与此有关的职责。
|