Easy way to start a standalone JNDI server (and re

2019-02-02 00:53发布

For testing purposes, I'm looking for a simple way to start a standalone JNDI server, and bind my javax.sql.DataSource to "java:/comp/env/jdbc/mydatasource" programmatically.

The server should bind itself to some URL, for example: "java.naming.provider.url=jnp://localhost:1099" (doesn't have to be JNP), so that I can look up my datasource from another process. I don't care about which JNDI server implementation I'll have to use (but I don't want to start a full-blown JavaEE server).

This should be so easy, but to my surprise, I couldn't find any (working) tutorial.

8条回答
可以哭但决不认输i
2楼-- · 2019-02-02 01:16

Have you considered using Mocks? If I recall correctly you use Interfaces to interact with JNDI. I know I've mocked them out at least once before.

As a fallback, you could probably use Tomcat. It's not a full blown J2EE impl, it starts fast, and is fairly easy to configure JNDI resources for. DataSource setup is well documented. It's sub-optimal, but should work.

查看更多
劫难
3楼-- · 2019-02-02 01:20

Here's a code snippet adapted from JBoss remoting samples. The code that is in the samples (version 2.5.4.SP2 ) no longer works. While the fix is simple it took me more hours than I want to think about to figure it out. Sigh. Anyway, maybe someone can benefit.

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);
    } 
}
查看更多
叛逆
4楼-- · 2019-02-02 01:23

I have been looking for a similar simple starter solution recently. The "file system service provider from Sun Microsystems" has worked for me well. See https://docs.oracle.com/javase/jndi/tutorial/basics/prepare/initial.html.

The problem with the RMI registry is that you need a viewer - here you just need to look at file contents.

You may need fscontext-4.2.jar - I obtained it from http://www.java2s.com/Code/Jar/f/Downloadfscontext42jar.htm

查看更多
Juvenile、少年°
5楼-- · 2019-02-02 01:26

You imply you've found non-working tutorials; that may mean you've already seen these:

I had a quick go, but couldn't get this working. A little more perseverance might do it, though.

查看更多
神经病院院长
6楼-- · 2019-02-02 01:27

For local, one process standalone jar purpouses I would use spring-test package:

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

startup log:

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楼-- · 2019-02-02 01:35

The JDK contains a JNDI provider for the RMI registry. That means you can use the RMI registry as a JNDI server. So, just start rmiregistry, set java.naming.factory.initial to com.sun.jndi.rmi.registry.RegistryContextFactory, and you're away.

The RMI registry has a flat namespace, so you won't be able to bind to java:/comp/env/jdbc/mydatasource, but you will be able to bind to something so it will accept java:/comp/env/jdbc/mydatasource, but will treat it as a single-component name (thanks, @EJP).

I've written a small application to demonstrate how to do this: https://bitbucket.org/twic/jndiserver/src

I still have no idea how the JNP server is supposed to work.

查看更多
登录 后发表回答