[Resolvido] Configurar datasource - Tomcat + OpenEJB: javax.naming.NameNotFoundException

Boa tarde,

Estou com uma aplicação antiga, Java 1.4 com EJB 2.1, Struts 1 e iBatis 2. Por questões de problemas com licenciamento, estamos efetuando testes para migrar de servidor de aplicação, para um open source.

Inicialmente, efetuei a migração para o JBoss 5, e tivemos sucesso.

Porém, por determinações superiores, tenho que migrar a aplicação para o Tomcat + OpenEJB. Já utilizei o Tomcat antes (nunca com OpenEJB), porém somente para aplicações mais triviais (usando Spring, JSF, por exemplo). E, agora, para migrar esta aplicação, estou deparando com uma série de adversidades.

A aplicação está empacotada em um EAR (são vários módulos WAR - mais de 100, e diversos EJBs empacotados em JARs) e, dentro da mesma, há um módulo ROOT.war que deve ser carregado por padrão (quando o usuário acessar localhost:8080, por exemplo). Eu já fiz a configuração do contexto deixando o path vazio, o que espero que funcione, porém, antes de conseguir testar já me deparei com outro problema: configurar o datasource!

Encontrei vários tutoriais no Google, porém, não estou tendo sucesso. Eu tentei três abordagens diferentes:

1. Colocar a definição do <Resource> no TOMCAT_HOME\conf\server.xml, como no exemplo abaixo (a única alteração que fiz no arquivo):
	<Host>
		...
		<Context path="" docBase="nome-projeto" debug="0" reloadable="true">
			
			<Resource name="NomeDS" auth="Container" 
				type="javax.sql.DataSource" 
				maxActive="100" maxIdle="30" maxWait="10000" 
				username="user" password="pass" 
				driverClassName="oracle.jdbc.driver.OracleDriver" 
				url="string.conexao.oracle" />
				
		</Context> 
		
    </Host>
2. Colocar a mesma definição do Resource no arquivo TOMCAT_HOME\conf\context.xml:
	<Context>

		<!-- Default set of monitored resources -->
		<WatchedResource>WEB-INF/web.xml</WatchedResource>
		
		<!-- Uncomment this to disable session persistence across Tomcat restarts -->
		<!--
		<Manager pathname="" />
		-->

		<!-- Uncomment this to enable Comet connection tacking (provides events
			 on session expiration as well as webapp lifecycle) -->
		<!--
		<Valve className="org.apache.catalina.valves.CometConnectionManagerValve" />
		-->
		
			<Resource name="NomeDS" auth="Container" 
				type="javax.sql.DataSource" 
				maxActive="100" maxIdle="30" maxWait="10000" 
				username="user" password="pass" 
				driverClassName="oracle.jdbc.driver.OracleDriver" 
				url="string.conexao.oracle" />

	</Context>
3. Criar um arquivo context.xml dentro do META-INF do meu EAR, com o mesmo conteúdo da solução 2, e editar todos os meus arquivos web.xml (inicialmente estou testando apenas com um módulo web, claro) para colocar a referência ao resource, da seguinte forma:
	<?xml version="1.0" encoding="UTF-8"?>
	<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
		xmlns="http://java.sun.com/xml/ns/javaee" 
		xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" 
		xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
		http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" 
		id="WebApp_ID" version="2.5">

	 <resource-ref>
		 <description>DB Connection</description>
		 <res-ref-name>jdbc/NomeDS</res-ref-name>
		 <res-type>javax.sql.DataSource</res-type>
		 <res-auth>Container</res-auth>
	  </resource-ref>
	  
	  <!-- Definição servlets -->
	  ...
	  </web-app>

No código, há um ServiceLocator invocado sempre que é necessária uma chamada/referência ao Datasource. Para carregar o datasource, é utilizado o código:

	Context context = new InitialContext();
	DataSource ds = (DataSource) context.lookup("java:comp/env/jdbc/NomeDS");

Em todas as abordagens, ao iniciar o Tomcat (estou inicializando por linha de comando), recebo o erro abaixo:

	javax.naming.NameNotFoundException: Name comp is not bound in this Context

Todos os tutoriais que encontrei até agora recomendam sempre uma das abordagens que testei, e que não consigo fazer funcionar. Após consultar aqui no fórum, vi que o pessoal estava chamando o contexto da seguinte forma:

	Context context = new InitialContext();
	Context envContext  = (Context)context.lookup("java:/comp/env");  
	DataSource ds = (DataSource)envContext.lookup("jdbc/NomeDS");

Apesar de inicialmente não ter entendido a diferença téorica entre as opções, alterei o ServiceLocator para ficar como acima, e também não tive sucesso. Permanece o mesmo erro na inicialização do Tomcat. Apaguei tudo, instalei o Tomcat de novo (para garantir que não há nenhum teste de configuração esquecido que esteja atrapalhando), removi o arquivo context.xml do META-INF do EAR e repeti o processo conforme descrito num outro tópico aqui no GUJ

http://www.guj.com.br/java/199168-datasource-da-aplicacao-java-no-tomcat

E continuo com o mesmo erro: Name comp is not bound in this Context. Tentei também o tutorial deste link, sempre com o mesmo erro.
http://numberformat.wordpress.com/tag/tomcat-6-mysql-datasource/

Eu entenderia este erro se tivesse esquecido de colocar “java:” nos fontes, mas, já utilizei a busca do Eclipse em todos os fontes do projeto (incluindo nos fontes empacotados em JARs nossos), e em nenhum lugar deixei de escrever “java:/comp/env” (pois é, tem código repetido na aplicação ¬¬’ Já tem um chamado aberto para corrigir isso, mas, até lá a gente se vira como dá). Alguém tem idéia do que possa ser?

Obrigada.

Obs: fiquei em dúvida sobre onde postar, visto que minha aplicação envolve EJBs, mas, postei nesta seção por ser um problema aparentemente relacionado à configuração do Tomcat. Caso não seja o apropriado, peço desculpas.

Fiz um novo teste. Baseado no que li da documentação do OpenEJB, a configuração do datasource deve ser feita no mesmo, e não no Tomcat: http://openejb.apache.org/3.0/configuring-datasources.html

Deste modo, apaguei minha instalação do Tomcat + OpenEJB, e instalei de novo do zero, para garantir que não esqueceria nenhuma configuração prévia - e nenhum lixo em sessão/histórico (estou utilizando a versão bundle, tomee-6.0.29.314.zip).

Alterei o arquivo TOMCAT_HOME\CONF\openejb.xml, declarando meu datasource:

<Resource id="NomeDS" type="DataSource">
  JdbcDriver oracle.jdbc.driver.OracleDriver
  JdbcUrl jdbc:oracle:oci:string_conexao
  UserName user
  Password pass
  JtaManaged true
</Resource>

Desta vez, não modifiquei nenhuma configuração do Tomcat (nem mesmo para colocar o projeto como default, deixei isso para uma segunda etapa).

Dentro do ejb-jar.xml que contem o Bean responsável pela parte de segurança, e que aparece no stacktrace da exceção, acrescentei a referência para o resource:

<?xml version="1.0" encoding="UTF-8"?>

<ejb-jar 
	id="ejb-jar_ID" metadata-complete="false" version="3.0" 
	xmlns="http://java.sun.com/xml/ns/javaee"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_0.xsd">
	
    <enterprise-beans>
        <session>
            <ejb-name>NomeClasseBean</ejb-name>
            ...
		<resource-ref>
		   <res-ref-name>NomeDS</res-ref-name>
		   <res-type>javax.sql.DataSource</res-type>
		</resource-ref>
	   ...	
        </session>
    </enterprise-beans>
</ejb-jar>

E, no ServiceLocator, para abrir o datasource, utilizo o código:

Properties p = new Properties();
p.put(Context.INITIAL_CONTEXT_FACTORY,"org.apache.openejb.client.LocalInitialContextFactory"); 
context = new InitialContext(p);
...
DataSource ds = (DataSource) context.lookup("java:openejb/Resource/NomeDS");

Porém, o problema persiste. Abaixo segue o log com a exceção. Deixei também a parte da inicialização, alguma informação pode ser relevante:

02/03/2011 15:07:14 org.apache.catalina.core.AprLifecycleListener init
INFO: The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: C:\Arquivos de programas\Java\jdk1.6.0_13\bin;.;C:\WINDOWS\Sun\Java\bin;C:\WINDOWS\system32;C:\WINDOWS;D:\oracle\ora92\bin;C:\Arquivos de programas\TortoiseSVN\bin;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\system32\WindowsPowerShell\v1.0;C:\WINDOWS\system32;D:\Ambiente\Android;C:\apache-ant-1.6.2\bin;C:\Arquivos de programas\Java\jdk1.6.0_13;C:\Arquivos de programas\Java\jdk1.6.0_13\bin;02/03/2011 15:07:14 org.apache.tomcat.util.digester.SetPropertiesRule begin
WARNING: [SetPropertiesRule]{Server/Service/Engine/Host/Context} Setting property 'debug' to '0' did not find a matching property.
Apache OpenEJB 3.1.4    build: 20101112-03:32
http://openejb.apache.org/
log4j:WARN No appenders could be found for logger (org.apache.openejb.resource.activemq.ActiveMQResourceAdapter).
log4j:WARN Please initialize the log4j system properly.
02/03/2011 15:07:17 org.apache.coyote.http11.Http11Protocol init
INFO: Initializing Coyote HTTP/1.1 on http-8080
02/03/2011 15:07:17 org.apache.catalina.startup.Catalina load
INFO: Initialization processed in 2952 ms
02/03/2011 15:07:17 org.apache.catalina.core.StandardService start
INFO: Starting service Catalina
02/03/2011 15:07:17 org.apache.catalina.core.StandardEngine start
INFO: Starting Servlet Engine: Apache Tomcat/6.0.29
context path =
02/03/2011 15:07:17 org.apache.catalina.startup.HostConfig deployDescriptor
INFO: Deploying configuration descriptor ejb-examples.xml
context path = /ejb-examples
FOO moduleName = D:\Ambiente\apache-tomcat-6.0.29\webapps\ejb-examples\WEB-INF\classes
02/03/2011 15:07:18 org.apache.cxf.service.factory.ReflectionServiceFactoryBeanbuildServiceFromClass
INFO: Creating Service {http://examples.org/wsdl}HelloEjbService from class org.superbiz.servlet.HelloEjb
02/03/2011 15:07:18 org.apache.cxf.endpoint.ServerImpl initDestination
INFO: Setting the server's publish address to be http://nopath:80
02/03/2011 15:07:18 org.apache.catalina.startup.ContextConfig validateSecurityRoles
INFO: WARNING: Security role name user used in an <auth-constraint> without being defined in a <security-role>
02/03/2011 15:07:18 org.apache.catalina.startup.ContextConfig validateSecurityRoles
INFO: WARNING: Security role name fake used in a <run-as> without being defined in a <security-role>
02/03/2011 15:07:18 org.apache.cxf.service.factory.ReflectionServiceFactoryBeanbuildServiceFromClass
INFO: Creating Service {http://examples.org/wsdl}HelloPojoService from class org.superbiz.servlet.HelloPojo
02/03/2011 15:07:18 org.apache.cxf.endpoint.ServerImpl initDestination
INFO: Setting the server's publish address to be http://nopath:80
02/03/2011 15:07:18 org.apache.catalina.startup.HostConfig deployDescriptor
INFO: Deploying configuration descriptor host-manager.xml
context path = /host-manager
02/03/2011 15:07:18 org.apache.catalina.startup.HostConfig deployDescriptor
INFO: Deploying configuration descriptor manager.xml
context path = /manager
02/03/2011 15:07:18 org.apache.catalina.startup.HostConfig deployDescriptor
INFO: Deploying configuration descriptor openejb.xml
context path = /openejb
OpenEJB init-params:
02/03/2011 15:07:19 org.apache.catalina.startup.HostConfig deployDirectory
INFO: Deploying web application directory docs
context path = /docs
02/03/2011 15:07:19 org.apache.catalina.startup.HostConfig deployDirectory
INFO: Deploying web application directory examples
context path = /examples
02/03/2011 15:07:19 org.apache.catalina.startup.HostConfig deployDirectory
INFO: Deploying web application directory nome_projeto-ejb
context path = /nome_projeto-ejb
02/03/2011 15:07:19 org.apache.coyote.http11.Http11Protocol start
INFO: Starting Coyote HTTP/1.1 on http-8080
02/03/2011 15:07:19 org.apache.jk.common.ChannelSocket init
INFO: JK: ajp13 listening on /0.0.0.0:8009
02/03/2011 15:07:19 org.apache.jk.server.JkMain start
INFO: Jk running ID=0 time=0/16  config=null
02/03/2011 15:07:19 org.apache.catalina.startup.Catalina start
INFO: Server startup in 2522 ms
Constante nao encontrada #DATA_SISTEMA_DATA_SISTEMA#
Erro ao localizar o DS!
javax.naming.NameNotFoundException: Name openejb is not bound in this Context
        at org.apache.naming.NamingContext.lookup(NamingContext.java:770)
        at org.apache.naming.NamingContext.lookup(NamingContext.java:153)
        at org.apache.naming.SelectorContext.lookup(SelectorContext.java:152)
        at javax.naming.InitialContext.lookup(InitialContext.java:392)
        at pacotes.util.ServiceLocator.getDefaultDataSource(ServiceLocator.java:127)
        at pacotes.util.DAOFac.getDefaultConnection(DAOFac.java:36)
        at pacotes.nome_projeto.util.constante.Constante.getConnection(Constante.java:190)
        at pacotes.nome_projeto.util.constante.Constante.<init>(Constante.java:25)
        at pacotes.nome_projeto.pacote.ejbs.NomeClasseBean.<clinit>(NomeClasseBean.java:56)
        at java.lang.Class.forName0(Native Method)
        at java.lang.Class.forName(Class.java:247)
        at org.apache.openejb.assembler.classic.EnterpriseBeanBuilder.load(EnterpriseBeanBuilder.java:397)
        at org.apache.openejb.assembler.classic.EnterpriseBeanBuilder.loadClass(EnterpriseBeanBuilder.java:377)
        at org.apache.openejb.assembler.classic.EnterpriseBeanBuilder.build(EnterpriseBeanBuilder.java:79)
        at org.apache.openejb.assembler.classic.EjbJarBuilder.build(EjbJarBuilder.java:52)
        at org.apache.openejb.assembler.classic.Assembler.createApplication(Assembler.java:527)
        at org.apache.openejb.assembler.classic.Assembler.createApplication(Assembler.java:450)
        at org.apache.openejb.assembler.classic.Assembler.createApplication(Assembler.java:446)
        at org.apache.openejb.tomcat.catalina.TomcatWebAppBuilder.checkHost(TomcatWebAppBuilder.java:500)
        at org.apache.openejb.tomcat.catalina.GlobalListenerSupport.lifecycleEvent(GlobalListenerSupport.java:74)
        at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:119)
        at org.apache.catalina.core.ContainerBase.backgroundProcess(ContainerBase.java:1337)
        at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1601)
        at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1610)
        at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.run(ContainerBase.java:1590)
        at java.lang.Thread.run(Thread.java:619)

Obrigada.

Bom dia pessoal!

Enfim, consegui resolver o problema! 8)

O David Blevins, da mailing list do OpenEJB, me sugeriu utilizar o namespace com “openejb:” ao invés de “java:”, ficando da seguinte forma:

DataSource ds = (DataSource) context.lookup("openejb:Resource/NomeDS");

E funcionou!

Isso é um “workaround” (gambiarra, em bom português, rssss) do pessoal do OpenEJB. Eis o link com a reposta, e a explicação do mesmo:
http://openejb.979440.n4.nabble.com/EJB-2-1-OpenEJB-Tomcat-Datasource-Name-openejb-is-not-bound-in-this-Context-td3331555.html

[]'s