Criação de resources no jboss

6 respostas
bbarbosa

Olá, estou criando uma enterprise application (ear) com um módulo de EJB e outro Web.
No EJB tenho meu backend do sistema (conexão com o banco de dados, validação de dados para não ter lixo no banco, etc…).
No Web tenho as páginas html e implemento JSF 1.2.

Minha questão é a seguinte, assim como uso um data source do jboss para gerenciar o pool de conexões com o banco de dados, queria criar um pool de conexões ao EJB para usar no modulo web, para não ter que chamar toda hora o initialcontext para conectar. Alguém pode me orientar como faço isso?

Desculpem se a questão parecer ridicula ainda sou novato, assim como vocês já foram um dia.
Obrigado

6 Respostas

KrinosX

Bom dia,

olha… esse é um problema comum… ficar chamando o InitialContext… tão comum que no J2EE Blueprints tem até um padrão de projeto para te ajudar com isso…

De uma olhada no link:
http://java.sun.com/blueprints/corej2eepatterns/Patterns/ServiceLocator.html

Se tiver dúvidas de como implementar… .poste ai!!

Abraços!

bbarbosa

Obrigado pela dica, consegui fazer um gerenciador de pools conforme o padrão no link que você me mandou.
Agora meu problema é iniciar esse gerenciador na inicialização do context do jsf.

KrinosX

Hummm para iniciar o pool…
Assim… o “Service Locator” é um singleton… então nao precisa “iniciar” ele… é so chamar ele direto no seus Beans do JSF…

Agora como voce implementou? seguiu qual abordagem do padrão Service Locator?

bbarbosa

O que eu disse que estava com problema de iniciar, é porque essa única instância do poolmanager eu queria carregar e deixar no contexto do servlet, e não precisar solicitar a cada request do modulo web.

O que eu fiz pra acertar isso (embora ainda não consegui testar), é no módulo web criar uma classe que implementa ServletContextListener e no método contextInitialized eu recupero a instância do poolmanager e coloco no contexto do servlet, depois para recuperar o poolmanager nas páginas, recupero o contexto do servlet a partir do contexto do jsf.

Classe que implementa o listener do servlet

public class SetupServlet implements ServletContextListener{
    public void contextInitialized(ServletContextEvent sc){
        EJBConnectionPool pool = EJBConnectionPool.getInstance();
        ServletContext context = sc.getServletContext();

       context.setAttribute("ejbPool", pool);
    }
}

Páginas que recuperam a conexão com o ejb.

ServletContext servletContext = (ServletContext) FacesContext.getCurrentInstance().getExternalContext().getContext();

As configurações de conexão (host, user, pass, maxConn) eu seto num arquivo “.properties”.
Assim estou fechando esse problema, caso funcione certinho eu posto os códigos.

KrinosX

Solução elegante. Olhando os códigos me parece que vai funcionar corretamente.

A única duvida é se não daria para fazer isso direto por XML… tipo da mesma maneira que setamos os “init-param” no web.xml.

Mas poste ae se funcionar!
Abraço!

bbarbosa

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);
		}
Criado 12 de agosto de 2008
Ultima resposta 17 de ago. de 2008
Respostas 6
Participantes 2