轻松启动独立JNDI服务器(并注册一些资源)

时间:2011-05-02 20:00:30

标签: java datasource jndi

出于测试目的,我正在寻找一种简单的方法来启动独立的 JNDI服务器,并以编程方式将我的javax.sql.DataSource绑定到"java:/comp/env/jdbc/mydatasource"

服务器应该将自己绑定到某个URL,例如:“java.naming.provider.url = jnp:// localhost:1099”(不一定是JNP),这样我就可以查找我的数据源从另一个过程。我不关心我必须使用哪个JNDI服务器实现(但我不想启动一个完整的JavaEE服务器)。

这应该很容易,但令我惊讶的是,我找不到任何(工作)教程。

8 个答案:

答案 0 :(得分:8)

JDK包含JNDI provider for the RMI registry。这意味着您可以将RMI注册表用作JNDI服务器。所以,只需启动rmiregistry,将java.naming.factory.initial设置为com.sun.jndi.rmi.registry.RegistryContextFactory即可离开。

RMI注册表有一个扁平的命名空间,所以你将无法绑定到java:/ comp / env / jdbc / mydatasource,但是你可以绑定到某些东西所以它将接受java:/ comp / env / jdbc / mydatasource,但会将其视为单组件名称(感谢@EJP)。

我写了一个小应用程序来演示如何执行此操作:https://bitbucket.org/twic/jndiserver/src

我仍然不知道JNP服务器应该如何工作。

答案 1 :(得分:4)

我参与了约翰的代码,现在工作得很好。

在这个版本中,我使用的是JBoss5.1.0.GA的库,请参阅下面的jar列表:

  • jboss-5.1.0.GA \客户\ jbossall-client.jar中
  • jboss-5.1.0.GA \服务器\最小\ lib中\ jnpserver.jar
  • jboss-5.1.0.GA \服务器\最小\ lib中\ log4j.jar
  • jboss-remote-naming-1.0.1.Final.jar(从http://search.maven.com下载)

这是新代码:

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<Object> {

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();
    }

}
}

要获得良好的日志记录,请使用此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

要使用独立JNDI服务器,请使用此客户端类:

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();
    }
}

}

答案 2 :(得分:3)

这是一个改编自JBoss远程处理示例的代码片段。代码是 在样本(版本2.5.4.SP2)中不再有效。虽然修复 这很简单,我花了很多时间才想到想出来。 叹。无论如何,也许有人可以受益。

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<Object> { 

    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);
    } 
}

答案 3 :(得分:2)

我知道我迟到了,但我最终还是像这样一起黑客攻击

InitialContext ctx = new InitialContext();

// check if we have a JNDI binding for "jdbc". If we do not, we are
// running locally (i.e. through JUnit, etc)
boolean isJndiBound = true;
try {
    ctx.lookup("jdbc");
} catch(NameNotFoundException ex) {
    isJndiBound = false;
}

if(!isJndiBound) {
    // Create the "jdbc" sub-context (i.e. the directory)
    ctx.createSubcontext("jdbc");

    //parse the jetty-web.xml file
    Map<String, DataSource> 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);
    }
}

答案 4 :(得分:0)

你考虑过使用Mocks吗?如果我没记错的话,你可以使用Interfaces与JNDI进行交互。我知道我以前至少曾经嘲笑过他们一次。

作为后备,你可能会使用Tomcat。它不是一个完整的J2EE impl,它启动速度很快,并且很容易配置JNDI资源。 DataSource设置已有详细记录。它是次优的,但应该有效。

答案 5 :(得分:0)

你暗示你发现了非工作教程;这可能意味着你已经看过这些:

我快速去了,但无法让这个工作。但是,坚持不懈可能会做到这一点。

答案 6 :(得分:0)

对于本地,一个进程独立的jar purpouses我会使用spring-test包:

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

启动日志:

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

答案 7 :(得分:0)

最近我一直在寻找类似的简单入门解决方案。 “ Sun Microsystems的文件系统服务提供商”对我来说很好。参见https://docs.oracle.com/javase/jndi/tutorial/basics/prepare/initial.html

RMI注册表的问题是您需要查看器-在这里您只需要查看文件内容即可。

您可能需要fscontext-4.2.jar-我是从http://www.java2s.com/Code/Jar/f/Downloadfscontext42jar.htm获得的