繁体   English   中英

嵌入式 Jetty 服务器的 JNDI 查找失败

[英]JNDI Lookup Failing For Embedded Jetty Server

我在我想针对嵌入式码头服务器运行的项目之一中进行了集成测试。 我跟着这里的例子: https : //www.eclipse.org/jetty/documentation/jetty-9/index.html#jndi-embedded但是当我去实际运行我的测试时,它失败并出现错误:

javax.naming.NameNotFoundException: env is not bound; remaining name 'env/jdbc/NavDS'
    at org.eclipse.jetty.jndi.NamingContext.getContext(NamingContext.java:241)
    at org.eclipse.jetty.jndi.NamingContext.lookup(NamingContext.java:491)
    at org.eclipse.jetty.jndi.NamingContext.lookup(NamingContext.java:491)
    at org.eclipse.jetty.jndi.NamingContext.lookup(NamingContext.java:505)
    at org.eclipse.jetty.jndi.java.javaRootURLContext.lookup(javaRootURLContext.java:101)
    at javax.naming.InitialContext.lookup(InitialContext.java:417)
    at com.tura.eyerep.test.TestWebServices.setUpBeforeClass(TestWebServices.java:63)

我确定我在某个地方犯了一个简单的错误,但我似乎无法发现它。 任何人都可以就我在这里做错了什么提出建议吗?

在我的测试中,我正在设置服务器:

@BeforeClass
public static void setUpBeforeClass() throws Exception {
            
    server = new Server(8080);
    ClassList classList = ClassList.setServerDefault(server);
    classList.addAfter("org.eclipse.jetty.webapp.FragmentConfiguration", "org.eclipse.jetty.plus.webapp.EnvConfiguration", "org.eclipse.jetty.plus.webapp.PlusConfiguration");
    
    WebAppContext context = new WebAppContext();
    context.setExtractWAR(false);
    context.setDescriptor("src/main/webapp/WEB-INF/web.xml");
    context.setResourceBase("src/main/webapp");
    context.setConfigurationDiscovered(false);  
    
    BasicDataSource ds = null;      
    ds = new BasicDataSource();
    ds.setUrl("jdbc:h2:mem:myDB;create=true;MODE=MSSQLServer;DATABASE_TO_UPPER=FALSE;");
    org.eclipse.jetty.plus.jndi.Resource mydatasource = new org.eclipse.jetty.plus.jndi.Resource(context, "jdbc/NavDS",ds);
    
    server.setHandler(context);
    server.start();
}

@Test
public void testLookup()
{
    InitialContext ctx = new InitialContext();
    DataSource myds = (DataSource) ctx.lookup("java:comp/env/jdbc/NavDS");
    assertNotNull( myds);
}

在我的 web.xml 我有一个资源引用条目:

  <resource-ref>
    <description>Nav Datasource</description>
    <res-ref-name>jdbc/NavDS</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
  </resource-ref>

让我们先清理你的测试用例。

// meaningless when you have a WAR that is a directory.
context.setExtractWAR(false); // remove this line

// This prevents Servlet 3 behaviors when using Servlet 2.x descriptors
context.setConfigurationDiscovered(false); // Remove this

你得到的错误...

javax.naming.NameNotFoundException: env is not bound; 
  remaining name 'env/jdbc/NavDS'

这可能意味着服务器仍在某处运行,可能忘记停止/清理以前的服务器实例。 (查看下面的示例 junit5 测试用例,了解它如何处理非固定端口、如何引用非固定端口以及它如何停止服务器的生命周期)。

接下来,请注意您的范围。

new org.eclipse.jetty.plus.jndi.Resource(context, "jdbc/NavDS",ds);

这会将资源条目绑定到作用域context上的jdbc/NavDS

这意味着如果您在WebAppContext范围之外查找资源,就像您使用testLookup()方法所做的testLookup() ,它将存在于initialContext.lookup("jdbc/NavDS") ,而没有其他地方, java:comp/env前缀/树甚至不存在于该testLookup()方法范围。

在您的 web 应用程序内部,例如在过滤器或 Servlet 中,特定于上下文的资源被绑定并在jdbc:comp/env/jdbc/NavDS

您有 3 个典型的范围。

命令 范围 EnvEntryResource第一个参数
1 网络应用程序 new EnvEntry(webappContext, ...)new Resource(webappContext, ...)
2 服务器 new EnvEntry(server, ...)new Resource(server, ...)
3 虚拟机 new EnvEntry(null, ...)new Resource(null, ...)

如果该值在 WebApp 范围内不存在,则检查服务器范围,然后检查 JVM 范围。

您的服务器可以具有名称val/foo的值,而特定的 webapp 可以具有相同名称val/foo不同值,这仅取决于范围的定义方式。

接下来,在 Servlet 规范中有绑定,您已经指定了<resource-ref>并且这与服务器端的声明相结合,绑定到context意味着您可以从您的 servlet 中访问java:comp/env/jdbc/NavDS那个特定的 webapp。

以不同的方式看待这一点,在代码中......

package jetty.jndi;

import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.net.HttpURLConnection;
import java.nio.charset.StandardCharsets;
import java.nio.file.Paths;
import java.util.List;
import javax.naming.InitialContext;
import javax.naming.NameNotFoundException;
import javax.naming.NamingException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.eclipse.jetty.plus.webapp.EnvConfiguration;
import org.eclipse.jetty.plus.webapp.PlusConfiguration;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.component.LifeCycle;
import org.eclipse.jetty.util.resource.PathResource;
import org.eclipse.jetty.webapp.Configuration;
import org.eclipse.jetty.webapp.FragmentConfiguration;
import org.eclipse.jetty.webapp.WebAppContext;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;

public class WebAppWithJNDITest
{
    private static Server server;
    private static WebAppContext context;

    public static class JndiDumpServlet extends HttpServlet
    {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
        {
            resp.setCharacterEncoding("utf-8");
            resp.setContentType("text/plain");
            PrintStream out = new PrintStream(resp.getOutputStream(), false, StandardCharsets.UTF_8);
            try
            {
                dumpJndi(out);
            }
            catch (NamingException e)
            {
                throw new ServletException(e);
            }
        }
    }

    @BeforeAll
    public static void startServer() throws Exception
    {
        server = new Server(0); // let os/jvm pick a port
        Configuration.ClassList classList = Configuration.ClassList.setServerDefault(server);
        classList.addAfter(FragmentConfiguration.class.getName(),
            EnvConfiguration.class.getName(),
            PlusConfiguration.class.getName());

        context = new WebAppContext();
        context.setContextPath("/");
        // This directory only has WEB-INF/web.xml
        context.setBaseResource(new PathResource(Paths.get("src/main/webroots/jndi-root")));
        context.addServlet(JndiDumpServlet.class, "/jndi-dump");


        new org.eclipse.jetty.plus.jndi.Resource(null, "val/foo", Integer.valueOf(707));
        new org.eclipse.jetty.plus.jndi.Resource(server, "val/foo", Integer.valueOf(808));
        new org.eclipse.jetty.plus.jndi.Resource(context, "val/foo", Integer.valueOf(909));

        new org.eclipse.jetty.plus.jndi.EnvEntry(null, "entry/foo", Integer.valueOf(440), false);
        new org.eclipse.jetty.plus.jndi.EnvEntry(server, "entry/foo", Integer.valueOf(550), false);
        new org.eclipse.jetty.plus.jndi.EnvEntry(context, "entry/foo", Integer.valueOf(660), false);

        server.setHandler(context);
        server.start();
    }

    @AfterAll
    public static void stopServer()
    {
        LifeCycle.stop(server);
    }

    public static void dumpJndi(PrintStream out) throws NamingException
    {
        InitialContext ctx = new InitialContext();

        List<String> paths = List.of("val/foo", "entry/foo");
        List<String> prefixes = List.of("java:comp/env/", "");

        for (String prefix : prefixes)
        {
            for (String path : paths)
            {
                try
                {
                    Integer val = (Integer)ctx.lookup(prefix + path);
                    out.printf("lookup(\"%s%s\") = %s%n", prefix, path, val);
                }
                catch (NameNotFoundException e)
                {
                    out.printf("lookup(\"%s%s\") = NameNotFound: %s%n", prefix, path, e.getMessage());
                }
            }
        }
    }

    @Test
    public void testLookup() throws NamingException, IOException
    {
        System.out.println("-- Dump from WebApp Scope");
        HttpURLConnection http = (HttpURLConnection)server.getURI().resolve("/jndi-dump").toURL().openConnection();
        try (InputStream in = http.getInputStream())
        {
            String body = IO.toString(in, StandardCharsets.UTF_8);
            System.out.println(body);
        }

        System.out.println("-- Dump from Test scope");
        dumpJndi(System.out);
    }
}

src/main/webroot/jndi-root/WEB-INF/web.xml

<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
         http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
  version="3.1">

  <resource-ref>
    <description>My Foo Resource</description>
    <res-ref-name>val/foo</res-ref-name>
    <res-type>java.lang.Integer</res-type>
    <res-auth>Container</res-auth>
  </resource-ref>
</web-app>

输出看起来像...

2021-10-26 17:05:16.834:INFO:oejs.Server:main: jetty-9.4.44.v20210927; built: 2021-06-30T11:07:22.254Z; git: 526006ecfa3af7f1a27ef3a288e2bef7ea9dd7e8; jvm 11.0.12+7
2021-10-26 17:05:17.012:INFO:oejsh.ContextHandler:main: Started o.e.j.w.WebAppContext@19932c16{/,file:///home/joakim/code/jetty/junk/src/main/webroots/jndi-root/,AVAILABLE}
2021-10-26 17:05:17.033:INFO:oejs.AbstractConnector:main: Started ServerConnector@212b5695{HTTP/1.1, (http/1.1)}{0.0.0.0:45387}
2021-10-26 17:05:17.034:INFO:oejs.Server:main: Started @816ms
-- Dump from WebApp Scope
lookup("java:comp/env/val/foo") = 909
lookup("java:comp/env/entry/foo") = 660
lookup("val/foo") = 707
lookup("entry/foo") = 440

-- Dump from Test scope
lookup("java:comp/env/val/foo") = NameNotFound: env is not bound
lookup("java:comp/env/entry/foo") = NameNotFound: env is not bound
lookup("val/foo") = 707
lookup("entry/foo") = 440
2021-10-26 17:05:17.209:INFO:oejs.AbstractConnector:main: Stopped ServerConnector@212b5695{HTTP/1.1, (http/1.1)}{0.0.0.0:0}
2021-10-26 17:05:17.210:INFO:oejs.session:main: node0 Stopped scavenging
2021-10-26 17:05:17.214:INFO:oejsh.ContextHandler:main: Stopped o.e.j.w.WebAppContext@19932c16{/,file:///home/joakim/code/jetty/junk/src/main/webroots/jndi-root/,STOPPED}

希望范围差异在上面很明显。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM