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.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> …
下面的例子举例说明了在展开描述符中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.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说明得到详细介绍。