package dataaccess;import java.sql.*; import javax.sql.DataSource; import java.util.Hashtable; import javax.naming.*; import javax.ejb.*; import javax.rmi.PortableRemoteObject; import session.counter.CounterHome; import session.title.TitleDAOHome; import session.editor.EditorDAOHome;/* * The ServiceLocator pattern is abstracts away the JNDI * logic necessary for retrieving a JDBC Connection or EJBHome * interface */ public class ServiceLocator{ private static ServiceLocator serviceLocatorRef = null; private static Hashtable ejbHomeCache = null; private static Hashtable dataSourceCache = null; /*Enumerating the different services available from the Service Locator*/ public static final int COUNTER = 0; public static final int TITLEDAO = 1; public static final int EDITORDAO = 2; public static final int SUBSCRIPTIONDB = 3; /*The JNDI Names used to lookup a service*/ private static final String COUNTER_JNDINAME="counter/Counter"; private static final String TITLEDAO_JNDINAME="title/TitleDAO"; private static final String EDITORDAO_JNDINAME="editor/EditorDAO"; private static final String SUBSCRIPTIONDB_JNDINAME="jdbc/subscriptionDS"; /*References to each of the different EJB Home Interfaces*/ private static final Class COUNTERCLASSREF = CounterHome.class; private static final Class TITLECLASSREF = TitleDAOHome.class; private static final Class EDITORCLASSREF = EditorDAOHome.class; static { serviceLocatorRef = new ServiceLocator(); } /*Private Constructor for the ServiceLocator*/ private ServiceLocator(){ ejbHomeCache = new Hashtable(); dataSourceCache = new Hashtable(); } /* * The ServiceLocator is implemented as a Singleton. The getInstance() * method will return the static reference to the ServiceLocator stored * inside of the ServiceLocator Class. */ public static ServiceLocator getInstance(){ return serviceLocatorRef; } /* * The getServiceName will retrieve the JNDI name for a requested * service. The service is indicated by the ServiceId passed into * the method. */ static private String getServiceName(int pServiceId) throws ServiceLocatorException{ String serviceName = null; switch (pServiceId){ case COUNTER: serviceName = COUNTER_JNDINAME; break; case TITLEDAO: serviceName = TITLEDAO_JNDINAME; break; case EDITORDAO: serviceName = EDITORDAO_JNDINAME; break; case SUBSCRIPTIONDB: serviceName = SUBSCRIPTIONDB_JNDINAME; break; default: throw new ServiceLocatorException( "Unable to locate the service requested in " + "ServiceLocator.getServiceName() method. "); } return serviceName; } /* * Returns the EJBHome Class reference for a requested service. * If the method can not make a match, it will throw a ServiceLocatorException * . */ static private Class getEJBHomeRef(int pServiceId) throws ServiceLocatorException{ Class homeRef = null; switch (pServiceId){ case COUNTER: homeRef = COUNTERCLASSREF; break; case TITLEDAO: homeRef = TITLECLASSREF; break; case EDITORDAO: homeRef = EDITORCLASSREF; break; default: throw new ServiceLocatorException( "Unable to locate the service requested in " + "ServiceLocator.getEJBHomeRef() method. "); } return homeRef; } /* * The getEJBHome method will return an EJBHome interface for a requested * service. If it can not find the requested EJB, it will throw a * servicelocator exception. * * The getEJBHome interface caches a requested EJBHome so that the first * time an EJB is requested, a home interface will be retrieved but then * be placed into a cache. * */ public EJBHome getEJBHome(int pServiceId) throws ServiceLocatorException{
/*Trying to find the JNDI Name for the requested service*/ String serviceName = getServiceName(pServiceId); EJBHome ejbHome = null; try{ /*Checking to see if I can find the EJBHome interface in cache*/ if (ejbHomeCache.containsKey(serviceName)){ ejbHome = (EJBHome) ejbHomeCache.get(serviceName); return ejbHome; } else{ /* * If I could not find the EJBHome interface in the cache, look it * up and then cache it. * */ Context ctx = new InitialContext(); Object jndiRef = ctx.lookup(serviceName); Object portableObj = PortableRemoteObject.narrow(jndiRef, getEJBHomeRef(pServiceId)); ejbHome = (EJBHome) portableObj; ejbHomeCache.put(serviceName, ejbHome); return ejbHome; } } catch(NamingException e){ throw new ServiceLocatorException("Naming exception error in ServiceLocator.getEJBHome()" ,e); } catch(Exception e){ throw new ServiceLocatorException("General exception in ServiceLocator.getEJBHome",e); }
} /* * The getDBConn() method will create a JDBC connection for the * requested database. It too uses a cachin algorithm to minimize * the number of JNDI hits that it must perform. */ public Connection getDBConn(int pServiceId) throws ServiceLocatorException{ /*Getting the JNDI Service Name*/ String serviceName = getServiceName(pServiceId); Connection conn = null; try{ /*Checking to see if the requested DataSource is in the Cache*/ if (dataSourceCache.containsKey(serviceName)){ DataSource ds = (DataSource) dataSourceCache.get(serviceName); conn = ((DataSource)ds).getConnection();
return conn; } else{ /* * The DataSource was not in the cache. Retrieve it from JNDI * and put it in the cache. */ Context ctx = new InitialContext(); DataSource newDataSource = (DataSource) ctx.lookup(serviceName); dataSourceCache.put(serviceName, newDataSource); conn = newDataSource.getConnection(); return conn; } } catch(SQLException e){ throw new ServiceLocatorException("A SQL error has occurred in " + "ServiceLocator.getDBConn()", e); } catch(NamingException e){ throw new ServiceLocatorException("A JNDI Naming exception has occurred "+ " in ServiceLocator.getDBConn()" , e); } catch(Exception e){ throw new ServiceLocatorException("An exception has occurred "+ " in ServiceLocator.getDBConn()" ,e); } } }
当用户终止与Session beans互操作的时候.会话终止了
所以用户不操作又想长时间保存是不现实的
然后被抛弃
钝化/激活只是容器管理其状态的方法 回收条件:
超时 (无论是激活的或钝化的)
被调用 remove()
可是session bean超时呢,我只能接受到一个RemoteException,我怎么知道它是由超时引起的呢RMI和无状态session bean呢,我从JNDI上得到一个引用,过了很长时间才用,会不会出错?
比如我把JNDI上找到的Home接口的引用缓存起来,避免每次都要查找JNDI,Home接口的引用会不会超时?
在本地为需要的jndi引用做一个cache,需要时从cache 里面取,如果cache中坏了或没有就再创建,用完了放回cache中
import javax.sql.DataSource;
import java.util.Hashtable;
import javax.naming.*;
import javax.ejb.*;
import javax.rmi.PortableRemoteObject;
import session.counter.CounterHome;
import session.title.TitleDAOHome;
import session.editor.EditorDAOHome;/*
* The ServiceLocator pattern is abstracts away the JNDI
* logic necessary for retrieving a JDBC Connection or EJBHome
* interface
*/
public class ServiceLocator{
private static ServiceLocator serviceLocatorRef = null;
private static Hashtable ejbHomeCache = null;
private static Hashtable dataSourceCache = null; /*Enumerating the different services available from the Service Locator*/
public static final int COUNTER = 0;
public static final int TITLEDAO = 1;
public static final int EDITORDAO = 2;
public static final int SUBSCRIPTIONDB = 3; /*The JNDI Names used to lookup a service*/
private static final String COUNTER_JNDINAME="counter/Counter";
private static final String TITLEDAO_JNDINAME="title/TitleDAO";
private static final String EDITORDAO_JNDINAME="editor/EditorDAO";
private static final String SUBSCRIPTIONDB_JNDINAME="jdbc/subscriptionDS"; /*References to each of the different EJB Home Interfaces*/
private static final Class COUNTERCLASSREF = CounterHome.class;
private static final Class TITLECLASSREF = TitleDAOHome.class;
private static final Class EDITORCLASSREF = EditorDAOHome.class; static {
serviceLocatorRef = new ServiceLocator();
} /*Private Constructor for the ServiceLocator*/
private ServiceLocator(){
ejbHomeCache = new Hashtable();
dataSourceCache = new Hashtable();
} /*
* The ServiceLocator is implemented as a Singleton. The getInstance()
* method will return the static reference to the ServiceLocator stored
* inside of the ServiceLocator Class.
*/
public static ServiceLocator getInstance(){
return serviceLocatorRef;
} /*
* The getServiceName will retrieve the JNDI name for a requested
* service. The service is indicated by the ServiceId passed into
* the method.
*/
static private String getServiceName(int pServiceId)
throws ServiceLocatorException{
String serviceName = null;
switch (pServiceId){
case COUNTER: serviceName = COUNTER_JNDINAME;
break;
case TITLEDAO: serviceName = TITLEDAO_JNDINAME;
break;
case EDITORDAO: serviceName = EDITORDAO_JNDINAME;
break;
case SUBSCRIPTIONDB: serviceName = SUBSCRIPTIONDB_JNDINAME;
break;
default: throw new ServiceLocatorException(
"Unable to locate the service requested in " +
"ServiceLocator.getServiceName() method. ");
}
return serviceName;
} /*
* Returns the EJBHome Class reference for a requested service.
* If the method can not make a match, it will throw a ServiceLocatorException
* .
*/
static private Class getEJBHomeRef(int pServiceId)
throws ServiceLocatorException{
Class homeRef = null;
switch (pServiceId){
case COUNTER: homeRef = COUNTERCLASSREF;
break;
case TITLEDAO: homeRef = TITLECLASSREF;
break;
case EDITORDAO: homeRef = EDITORCLASSREF;
break;
default: throw new ServiceLocatorException(
"Unable to locate the service requested in " +
"ServiceLocator.getEJBHomeRef() method. ");
}
return homeRef;
} /*
* The getEJBHome method will return an EJBHome interface for a requested
* service. If it can not find the requested EJB, it will throw a
* servicelocator exception.
*
* The getEJBHome interface caches a requested EJBHome so that the first
* time an EJB is requested, a home interface will be retrieved but then
* be placed into a cache.
*
*/
public EJBHome getEJBHome(int pServiceId)
throws ServiceLocatorException{
/*Trying to find the JNDI Name for the requested service*/
String serviceName = getServiceName(pServiceId);
EJBHome ejbHome = null; try{
/*Checking to see if I can find the EJBHome interface in cache*/
if (ejbHomeCache.containsKey(serviceName)){
ejbHome = (EJBHome) ejbHomeCache.get(serviceName);
return ejbHome;
}
else{
/*
* If I could not find the EJBHome interface in the cache, look it
* up and then cache it.
* */
Context ctx = new InitialContext();
Object jndiRef = ctx.lookup(serviceName); Object portableObj =
PortableRemoteObject.narrow(jndiRef, getEJBHomeRef(pServiceId)); ejbHome = (EJBHome) portableObj; ejbHomeCache.put(serviceName, ejbHome);
return ejbHome;
}
}
catch(NamingException e){
throw new ServiceLocatorException("Naming exception error in ServiceLocator.getEJBHome()" ,e);
}
catch(Exception e){
throw new ServiceLocatorException("General exception in ServiceLocator.getEJBHome",e);
}
} /*
* The getDBConn() method will create a JDBC connection for the
* requested database. It too uses a cachin algorithm to minimize
* the number of JNDI hits that it must perform.
*/
public Connection getDBConn(int pServiceId)
throws ServiceLocatorException{
/*Getting the JNDI Service Name*/
String serviceName = getServiceName(pServiceId);
Connection conn = null;
try{
/*Checking to see if the requested DataSource is in the Cache*/
if (dataSourceCache.containsKey(serviceName)){
DataSource ds = (DataSource) dataSourceCache.get(serviceName);
conn = ((DataSource)ds).getConnection();
return conn;
}
else{
/*
* The DataSource was not in the cache. Retrieve it from JNDI
* and put it in the cache.
*/
Context ctx = new InitialContext();
DataSource newDataSource = (DataSource) ctx.lookup(serviceName);
dataSourceCache.put(serviceName, newDataSource);
conn = newDataSource.getConnection();
return conn;
}
}
catch(SQLException e){
throw new ServiceLocatorException("A SQL error has occurred in " +
"ServiceLocator.getDBConn()", e);
}
catch(NamingException e){
throw new ServiceLocatorException("A JNDI Naming exception has occurred "+
" in ServiceLocator.getDBConn()" , e);
}
catch(Exception e){
throw new ServiceLocatorException("An exception has occurred "+
" in ServiceLocator.getDBConn()" ,e);
}
}
}
然而我们要做出健壮的程序就必须考虑到各种问题引用肯定是会失效的,比如远程服务器重启了
不知道的是如果服务器没有重启动的化,我一直保留引用是否可以,服务器怎么知道客户端是否还在引用某个对象?如果引用失效,在引用上调用方法会有RemoteException,但是引起RemoteException的原因很多,我怎么知道是引用失效引起的呢,这时怎么从错误中恢复?
我怎么知道它无法用,我只受到一个远程异常而已,这也可能是因为数据库异常或是短暂的IO异常引起的
我怎么知道应该去新建一个引用呢
我的意思是:
》只要从cache里面得到的引用无法用
我怎么知道它无法用,我只是在引用上调用方法的时候受到一个远程异常而已,这也可能是因为数据库异常或是短暂的IO异常引起的,也可能是引用超时。按你的说法,引用超时应该新建,不过运行时我的程序怎么知道是引用超时而不是SQL错误并且去新建一个引用呢