轉載自:http://www.java-cn.com/technology/technology_detail.jsp?id=785
為Beans增加功能
EJB 上下文:通往容器的門戶
存在如下資訊:
1、關于bean的home對象和EJB對象的資訊
2、bean的目前事務資訊。
3、 對于客戶授權的安全資訊。Bean可以通過查詢環境決定客戶執行操作所需要的安全層次。
4、 bean的環境屬性。
容器将所有這些資訊儲存在一個稱為EJB context object的對象裡。EJB上下文作為容器的實體部分,可以被bean通路。這些通路可以讓bean得到目前的狀态和改變目前的狀态。
上下文可以在bean的生命期中被更改。
EJB1.0 javax.ejb.EJBContext接口:
public interface javax.ejb.EJBContext
{
public javax.ejb.EJBHome getEJBHome();
public java.util.Properties getEnvironment();
public java.security.Identity getCallerIdentity();
public boolean isCallerInRole(java.security.Identity);
public javax.jts.UserTransaction getUserTransaction();
public void setRollbackOnly();
public boolean getRollbackOnly();
}
會話bean的上下文
上下文根據bean的不同分為:會話上下文和實體上下文。它們分别被用于會話bean和實體bean
javax.ejb.EJBContext
public interface javax.ejb.SessionContext
extends javax.ejb.EJBContext
{
public javax.ejb.EJBObject getEJBObject();
}
注意:SessionContext接口繼承了EJBContext接口,在EJBContext中定義的方法提供了對會話bean的存取路徑。
對于會話bean,調用setSessionContext,這個方法在javax.ejb.SessionBean接口中被定義。對于實體bean,調用setEntityContext。
SessionContext.getEJBObject()
在EJB中,beans可以作為其他bean的用戶端。如果一個bean需要調用另外的bean,getEJBObject()方法則是必需的。在java中,對象可以使用this關鍵字儲存自身的參考。在EJB中,bean不能使用this關鍵字給其他bean傳遞對象,這是因為所有的客戶調用bean上的方法都是間接調用bean的EJB對象。Bean可以使用this關鍵字将自己傳給EJB對象。
了解EJB的安全性
首先,用戶端必須是可被鑒别的。
其次,用戶端必須是已經授權的。
第一步:鑒别
不同的EJB容器擁有不同的鑒别用戶端的方法。例如:BEA的WebLogic中,當不同用戶端代碼使用JNDL定位Home對象時,提供不同的使用者名和密碼。
Properties props = System.getProperties();
props.put(Context.SECURITY_PRINCIPAL, "EmployeeA");
props.put(Context.SECURITY_CREDENTIALS, "myPassword1");
Context ctx = new InitialContext(props);
// Use the initial context to lookup home objects...
EJB沒有制定如何鑒别的規範,是以這樣就影響了可移植性。要了解這方面,檢視各類容器的文檔。
當運作這段代碼時,應用伺服器将驗證你的使用者名和密碼,這是應用伺服器規範。許多應用伺服器允許在屬性檔案裡設定使用者名和密碼。這個檔案将在運作時由應用伺服器讀。
進階點的伺服器支援已經存在的驗證系統的整合。例如将使用者名和密碼清單存儲在LDAP伺服器中。
第二步:授權
隻有經過授權的用戶端才可以調用bean中的方法。EJB中有兩種驗證授權的方法:declaratively和programmatically。即:由容器執行所有的授權檢驗、在程式中進行授權檢查。
Declarative授權檢查時,要在配置描述符中聲明bean的授權需要。例如使用BEA的WebLogic伺服器的配置描述符的例子:
(accessControlEntries
submitPurchaseOrder [employees]
approvePurchaseOrder [managers]
DEFAULT [administrators]
); end accessControlEntries
容器将在運作時自動的執行安全檢查。抛會出java.lang.SecurityException異常。
Programmatic授權檢查,必須查詢EJB上下文得到目前用戶端的授權資訊。由兩種方法調用CallerInRole(Identity role)和getCallerIdentity()。
isCallerInRole()
import java.security.Identity;
...
public class MyBean implements SessionBean {
private SessionContext ctx;
...
public void foo() {
Identity id = new MyIdentity("administrators");
if (ctx.isCallerInRole(id)) {
System.out.println("An admin called me");
return;
}
System.out.println("A non-admin called me");
}
}
import java.security.Identity;
public class MyIdentity extends Identity {
public MyIdentity(String id) {
super(id);
}
}
getCallerIdentity()
import java.security.Identity;
...
public class MyBean implements SessionBean {
private SessionContext ctx;
...
public void bar() {
Identity id = ctx.getCallerIdentity();
String name = id.getName();
System.out.println("The caller´s name is " + name);
}
}
了解EJB對象的操作
許多EJB應用程式需要用戶端有與bean斷開的能力,還要有與bean重建連接配接的能力。EJB提供了EJB object handles。EJB對象操作對于EJB對象是一個長生命期的代理。可以用它來重建與EJB對象的連接配接,并保證會話狀态不被丢失。下面是EJB對象操作的代碼
// First, get the EJB object handle from the EJB object.
javax.ejb.Handle myHandle = myEJBObject.getHandle();
// Next, serialize myHandle, and then save it in
// permanent storage.
ObjectOutputStream stream = ...;
stream.writeObject(myHandle);
// time passes...
// When we want to use the EJB object again,
// deserialize the EJB object handle
ObjectInputStream stream = ...;
Handle myHandle = (Handle) stream.readObject();
// Convert the EJB object handle back into an EJB object
MyRemoteInterface myEJBObject =
(MyRemoteInterface) myHandle.getEJBObject();
// Resume calling methods again
myEJBObject.callMethod();
例子:The Puzzle Game “Fazuul”(參考原文)