Maneira fácil de iniciar um servidor JNDI autônomo (e registrar alguns resources)

Para fins de teste, estou procurando uma maneira simples de iniciar um servidor JNDI autônomo e vincular meu javax.sql.DataSource a "java:/comp/env/jdbc/mydatasource" programaticamente.

O servidor deve ligar-se a alguma URL, por exemplo: “java.naming.provider.url = jnp: // localhost: 1099” (não precisa ser JNP), para que eu possa procurar minha fonte de dados de outro processo . Eu não me importo com qual implementação do servidor JNDI eu terei que usar (mas eu não quero iniciar um servidor JavaEE completo).

Isso deve ser fácil, mas para minha surpresa, não consegui encontrar nenhum tutorial (de trabalho).

O JDK contém um provedor JNDI para o registro RMI . Isso significa que você pode usar o registro do RMI como um servidor JNDI. Então, apenas inicie o rmiregistry , defina java.naming.factory.initial como com.sun.jndi.rmi.registry.RegistryContextFactory , e você está ausente.

O registro RMI tem um namespace simples, então você não será capaz de se ligar a java: / comp / env / jdbc / mydatasource, mas poderá se ligar a algo para aceitar java: / comp / env / jdbc / mydatasource, mas irá tratá-lo como um nome de componente único (obrigado, @ EJP).

Eu escrevi um pequeno aplicativo para demonstrar como fazer isso: https://bitbucket.org/twic/jndiserver/src

Eu ainda não tenho idéia de como o servidor JNP deve funcionar.

Eu trabalhei no código do John e agora está funcionando bem.

Nesta versão estou usando libs do JBoss5.1.0.GA, veja lista de jar abaixo:

  • jboss-5.1.0.GA \ client \ jbossall-client.jar
  • jboss-5.1.0.GA \ server \ minimum \ lib \ jnpserver.jar
  • jboss-5.1.0.GA \ server \ minimal \ lib \ log4j.jar
  • jboss-remote-naming-1.0.1.Final.jar (baixado de http://search.maven.com )

Este é o novo código:

 import java.net.InetAddress; import java.util.Hashtable; import java.util.concurrent.Callable; import javax.naming.Context; import javax.naming.InitialContext; import org.jnp.server.Main; import org.jnp.server.NamingBeanImpl; public class StandaloneJNDIServer implements Callable { public Object call() throws Exception { setup(); return null; } @SuppressWarnings("unchecked") private void setup() throws Exception { //configure the initial factory //**in John´s code we did not have this** System.setProperty(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory"); //start the naming info bean final NamingBeanImpl _naming = new NamingBeanImpl(); _naming.start(); //start the jnp serve final Main _server = new Main(); _server.setNamingInfo(_naming); _server.setPort(5400); _server.setBindAddress(InetAddress.getLocalHost().getHostName()); _server.start(); //configure the environment for initial context final Hashtable _properties = new Hashtable(); _properties.put(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory"); _properties.put(Context.PROVIDER_URL, "jnp://10.10.10.200:5400"); //bind a name final Context _context = new InitialContext(_properties); _context.bind("jdbc", "myJDBC"); } public static void main(String...args){ try{ new StandaloneJNDIServer().call(); }catch(Exception _e){ _e.printStackTrace(); } } } 

Para ter um bom registro, use estas propriedades log4j:

 log4j.rootLogger=TRACE, A1 log4j.appender.A1=org.apache.log4j.ConsoleAppender log4j.appender.A1.layout=org.apache.log4j.PatternLayout log4j.appender.A1.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n 

Para consumir o servidor JNDI Independente, use esta class de cliente:

 import java.util.Hashtable; import javax.naming.Context; import javax.naming.InitialContext; /** * * @author fabiojm - Fábio José de Moraes * */ public class Lookup { public Lookup(){ } @SuppressWarnings("unchecked") public static void main(String[] args) { final Hashtable _properties = new Hashtable(); _properties.put("java.naming.factory.initial", "org.jnp.interfaces.NamingContextFactory"); _properties.put("java.naming.provider.url", "jnp://10.10.10.200:5400"); try{ final Context _context = new InitialContext(_properties); System.out.println(_context); System.out.println(_context.lookup("java:comp")); System.out.println(_context.lookup("java:jdbc")); }catch(Exception _e){ _e.printStackTrace(); } } } 

Aqui está um trecho de código adaptado das amostras remotas do JBoss. O código que está nas amostras (versão 2.5.4.SP2) não funciona mais. Embora a correção seja simples, levei mais horas do que quero pensar para descobrir. Suspiro. De qualquer forma, talvez alguém possa se beneficiar.

 package org.jboss.remoting.samples.detection.jndi.custom; import java.net.InetAddress; import java.util.concurrent.Callable; import org.jnp.server.Main; import org.jnp.server.NamingBeanImpl; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class StandaloneJNDIServer implements Callable { private static Logger logger = LoggerFactory.getLogger( StandaloneJNDIServer.class ); // Default locator values - command line args can override transport and port private static String transport = "socket"; private static String host = "localhost"; private static int port = 5400; private int detectorPort = 5400; public StandaloneJNDIServer() {} @Override public Object call() throws Exception { StandaloneJNDIServer.println("Starting JNDI server... to stop this server, kill it manually via Control-C"); //StandaloneJNDIServer server = new StandaloneJNDIServer(); try { this.setupJNDIServer(); // wait forever, let the user kill us at any point (at which point, the client will detect we went down) while(true) { Thread.sleep(1000); } } catch(Exception e) { e.printStackTrace(); } StandaloneJNDIServer.println("Stopping JBoss/Remoting server"); return null; } private void setupJNDIServer() throws Exception { // start JNDI server String detectorHost = InetAddress.getLocalHost().getHostName(); Main JNDIServer = new Main(); // Next two lines add a naming implemention into // the server object that handles requests. Without this you get a nice NPE. NamingBeanImpl namingInfo = new NamingBeanImpl(); namingInfo.start(); JNDIServer.setNamingInfo( namingInfo ); JNDIServer.setPort( detectorPort ); JNDIServer.setBindAddress(detectorHost); JNDIServer.start(); System.out.println("Started JNDI server on " + detectorHost + ":" + detectorPort ); } /** * Outputs a message to stdout. * * @param msg the message to output */ public static void println(String msg) { System.out.println(new java.util.Date() + ": [SERVER]: " + msg); } } 

Eu sei que estou atrasado para a festa, mas acabei hackeando isso juntos assim

 InitialContext ctx = new InitialContext(); // check if we have a JNDI binding for "jdbc". If we do not, we are // running locally (ie through JUnit, etc) boolean isJndiBound = true; try { ctx.lookup("jdbc"); } catch(NameNotFoundException ex) { isJndiBound = false; } if(!isJndiBound) { // Create the "jdbc" sub-context (ie the directory) ctx.createSubcontext("jdbc"); //parse the jetty-web.xml file Map dataSourceProperties = JettyWebParser.parse(); //add the data sources to the sub-context for(String key : dataSourceProperties.keySet()) { DataSource ds = dataSourceProperties.get(key); ctx.bind(key, ds); } } 

Você já pensou em usar o Mocks? Se bem me lembro, você usa Interfaces para interagir com o JNDI. Eu sei que eu zombei deles pelo menos uma vez antes.

Como alternativa, você provavelmente poderia usar o Tomcat. Não é um completo J2EE impl, ele inicia rápido e é bastante fácil de configurar resources JNDI. A configuração do DataSource está bem documentada. É sub-ótimo, mas deve funcionar.

Você insinua que encontrou tutoriais que não funcionam; isso pode significar que você já viu estes:

  • J2EE ou J2SE? JNDI trabalha com ambos
  • Servidor JNDI independente usando jnpserver.jar

Eu fui rápido, mas não consegui fazer isso funcionar. Um pouco mais de perseverança pode fazer isso, no entanto.

Para locais, um processo jar purpouses standalone eu usaria o pacote de teste de primavera:

  SimpleNamingContextBuilder builder = new SimpleNamingContextBuilder(); SQLServerConnectionPoolDataSource myDS = new SQLServerConnectionPoolDataSource(); //setup... builder.bind("java:comp/env/jdbc/myDS", myDS); builder.activate(); 

log de boot:

 22:33:41.607 [main] INFO org.springframework.mock.jndi.SimpleNamingContextBuilder - Static JNDI binding: [java:comp/env/jdbc/myDS] = [SQLServerConnectionPoolDataSource:1] 22:33:41.615 [main] INFO org.springframework.mock.jndi.SimpleNamingContextBuilder - Activating simple JNDI environment 

Eu tenho procurado por uma solução inicial simples similar recentemente. O “provedor de serviços de sistema de arquivos da Sun Microsystems” funcionou bem para mim. Veja https://docs.oracle.com/javase/jndi/tutorial/basics/prepare/initial.html .

O problema com o registro RMI é que você precisa de um visualizador – aqui você só precisa olhar para o conteúdo do arquivo.

Você pode precisar de fscontext-4.2.jar – eu obtive de http://www.java2s.com/Code/Jar/f/Downloadfscontext42jar.htm

Intereting Posts