Segue a solução que coloquei no meu projeto
Criei um classe que recebe os parametros de initialcontext que eu uso (Context.PROVIDER_URL, Context.SECURITY_PRINCIPAL, Context.SECURITY_CREDENTIALS) e controla o pool de conexões com o EJB.
package brbshow.ejb;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Properties;
import java.util.Vector;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
public class EJBConnectionManager {
private static EJBConnectionManager instance;
private static int clients;
private Hashtable<String, EJBConnectionPool> pools = new Hashtable<String, EJBConnectionPool>();
public static synchronized EJBConnectionManager getInstance(InputStream input){
if (instance == null){
instance = new EJBConnectionManager(input);
}
clients++;
return instance;
}
public EJBConnectionManager(InputStream input){
createPools(input);
}
public Context getConnection(String name){
EJBConnectionPool pool = (EJBConnectionPool) pools.get(name);
return pool.getConnection();
}
public void freeConnection(String name, Context context){
EJBConnectionPool pool = (EJBConnectionPool) pools.get(name);
if (pool != null){
pool.freeConnection(context);
}
}
public synchronized void release(){
if (--clients != 0){
return;
}
Enumeration<EJBConnectionPool> all = pools.elements();
while(all.hasMoreElements()){
EJBConnectionPool pool = (EJBConnectionPool) all.nextElement();
pool.release();
}
}
public void createPools(InputStream input){
Properties props = new Properties();
try {
props.load(input);
} catch (IOException e) {
e.printStackTrace();
}
Enumeration<?> p = props.propertyNames();
while(p.hasMoreElements()){
String name = (String) p.nextElement();
if (name.endsWith(".url")){
String poolName = (String) name.substring(0, name.lastIndexOf("."));
String host = props.getProperty(poolName + ".url");
String user = props.getProperty(poolName + ".user");
String pass = props.getProperty(poolName + ".password");
String conn = props.getProperty(poolName + ".maxConn", "0");
int max = Integer.valueOf(conn).intValue();
EJBConnectionPool pool = new EJBConnectionPool(host, user, pass, max);
pools.put(poolName, pool);
}
}
}
class EJBConnectionPool{
private int checkedOut;
private Vector<Context> freeConnections = new Vector<Context>();
private int maxConn;
private String user;
private String password;
private String url;
public EJBConnectionPool(String url, String user, String password, int maxConn){
this.url = url;
this.user = user;
this.password = password;
this.maxConn = maxConn;
}
public synchronized Context getConnection(){
Context context = null;
if (freeConnections.size() > 0){
context = (Context) freeConnections.firstElement();
freeConnections.removeElementAt(0);
try{
if (context == null){
context = getConnection();
}
}catch(Exception e){
e.printStackTrace();
}
}else if (maxConn == 0 || checkedOut < maxConn){
context = newConnection();
}
if (context != null){
checkedOut++;
}
return context;
}
public Context newConnection(){
Hashtable<String, String> prop = new Hashtable<String, String>();
Context context = null;
try {
prop.put(Context.PROVIDER_URL, url);
prop.put(Context.SECURITY_PRINCIPAL, user);
prop.put(Context.SECURITY_CREDENTIALS, password);
context = new InitialContext(prop);
} catch (NamingException e) {
e.printStackTrace();
}
return context;
}
public synchronized void freeConnection(Context context){
freeConnections.addElement(context);
checkedOut--;
notifyAll();
}
public synchronized void release(){
for (Context context : freeConnections){
try {
context.close();
} catch (NamingException e) {
e.printStackTrace();
}
}
freeConnections.removeAllElements();
}
}
}
Essa classe eu coloquei num jar e adicionei como uma biblioteca no meu projeto web.
Para no projeto web eu poder instanciar o pool, eu seto um listener no web.xml
<listener>
<listener-class>listeners.SetupContext</listener-class>
</listener>
Nesse listener eu implemento a interface ServletContextListener que ao inicializar um servlet (dar start no seu application server), ele já roda e recupera a instância do pool e se não me engano, ele tem um escopo de application, então a cada requisição ou sessão do usuário não chega e criar e destruir a instancia do pool.
package listeners;
import java.io.InputStream;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import brbshow.ejb.EJBConnectionManager;
public class SetupContext implements ServletContextListener{
private EJBConnectionManager ejbManager;
public void contextDestroyed(ServletContextEvent context) {
ejbManager.release();
}
public void contextInitialized(ServletContextEvent context) {
InputStream ejbInput = getClass().getResourceAsStream("/ejb.properties");
ejbManager = EJBConnectionManager.getInstance(ejbInput);
context.getServletContext().setAttribute("ejbManager", ejbManager);
}
}
Segue um exemplo do arquivo ejb.properties que usei para setar os parametros do initialcontext
admin.url=localhost
admin.user=admin
admin.password=admin
admin.maxConn=20
E por fim, na classe que o jsf precisa se conectar ao ejb eu recupero o pool do contexto do servlet e chamo o que for preciso.
EJBConnectionManager ejbManager = null;
Context context = null;
try {
ServletContext sc = (ServletContext) FacesContext.getCurrentInstance().getExternalContext().getContext();
ejbManager = (EJBConnectionManager) sc.getAttribute("ejbManager");
context = ejbManager.getConnection("admin");
} catch (NamingException e) {
e.printStackTrace();
}finally{
ejbManager.freeConnection("admin", context);
}