Search code examples
springjettyjndi

Jetty JNDI configuration vs Spring lookup


I have got a problem with JNDI configuration on Jetty server. I cannot by any means configure it in a way that afterwards Spring (3.0.5) can retrieve JNDI variables.

I have some credentials which I do not want to store in properties so that it will not exist in git repo. My web application is running on Jetty (most recent version 9.2.3), thus I came up with idea to store this credentials in Jetty web application context. Jetty provides such solution with jetty-env.xml. So I have created jetty-env.xml file in my WEB-INF/ like following:

<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.mortbay.org/configure.dtd">

<Configure id="webappCtx" class="org.eclipse.jetty.webapp.WebAppContext">

  <New id="username"  class="org.eclipse.jetty.plus.jndi.Resource">
    <Arg><Ref refid="webappCtx"/></Arg> <!-- scope -->
    <Arg>server/username</Arg> <!-- name -->
    <Arg type="java.lang.String">myUsername</Arg> <!-- value -->

  </New>

  <New id="password"  class="org.eclipse.jetty.plus.jndi.Resource">
    <Arg><Ref refid="webappCtx"/></Arg> <!-- scope -->
    <Arg>server/password</Arg> <!-- name -->
    <Arg type="java.lang.String">qwerty</Arg> <!-- value -->
  </New>

</Configure>

After that I have defined binding in the web.xml as follows:

<?xml version="1.0" encoding="UTF-8"?>
<web-app id="MyWebApp" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

<display-name>My Web App</display-name>

<!-- INITIALIZE SPRING -->
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:/spring-context.xml</param-value>
</context-param>
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<!-- JETTY-ENV JNDI -->
<resource-ref>
    <res-ref-name>server/username</res-ref-name>
    <res-type>java.lang.String</res-type>
</resource-ref>
<resource-ref>
    <res-ref-name>server/password</res-ref-name>
    <res-type>java.lang.String</res-type>
</resource-ref>

</web-app>

And configured my Spring context in this way:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:context="http://www.springframework.org/schema/context"
   xmlns:aop="http://www.springframework.org/schema/aop"
   xmlns:amq="http://activemq.apache.org/schema/core"
   xmlns:tx="http://www.springframework.org/schema/tx"
   xmlns:ehcache="http://www.springmodules.org/schema/ehcache"
   xmlns:jee="http://www.springframework.org/schema/jee"
   xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
        http://activemq.apache.org/schema/core http://activemq.apache.org/schema/core/activemq-core-5.2.0.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
        http://www.springmodules.org/schema/ehcache http://www.springmodules.org/schema/cache/springmodules-ehcache.xsd
        http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd">

    <jee:jndi-lookup id="serverUsername" jndi-name="server/username" expected-type="java.lang.String" resource-ref="true" />
    <jee:jndi-lookup id="serverPassword" jndi-name="server/password" expected-type="java.lang.String" resource-ref="true"/>

    <bean name="abstractServerConnectionFactory" class="my.package.ServerConnectionFactory" abstract="true">
        <constructor-arg value="${server.host}"/>
        <constructor-arg value="${server.port}"/>
        <constructor-arg ref="serverUsername"/>
        <constructor-arg ref="serverPassword"/>
    </bean>
</beans>

After that I am starting Jetty with --add-to-startd=jndi enabled and I am always getting javax.naming.NameNotFoundException when creating serverUsername and serverPassword. I have tried many modfication, but non have seem to work. I have tried:

  • Changing org.eclipse.jetty.plus.jndi.Resource to org.eclipse.jetty.plus.jndi.EnvEntry and then refering to it via resource-env-ref in web.xml
  • Setting resource scope to JVM instead of webapp so changing <Arg><Ref refid="webappCtx"/></Arg> to <Arg></Arg> as mentioned here
  • Adding automatic binding without using web.xml as mentioned here
<Call name="bindToENC">
    <Arg>server/username</Arg>  <!-- binds server/username to java:comp/env/server/username for this webapp -->
</Call>

And many other, but it just does not work. Please give me a working example how I can get it to work. Thank you!


Solution

  • Ok so I have managed to get this working. The problem was the configuration. I am using Jetty 9 so according to the official documentation (https://eclipse.dev/jetty/documentation/jetty-9/index.html#jndi-quick-setup) the only thing that needs to be done prior to using JNDI in Jetty is adding jndi module to start.d by doing --add-to-startd=jndi. And well, that's not exactly true, because this will enable JNDI, BUT WILL NOT INCLUDE jetty-env.xml contents (Jetty do not even touch it). I've been reading about the container lifecycle and noticed that in order to use JNDI one need to include following classes in the web application context configuration classes set:

    • org.eclipse.jetty.plus.webapp.EnvConfiguration
    • org.eclipse.jetty.plus.webapp.PlusConfiguration

    This is done by default in $JETTY_HOME/etc/jetty-plus.xml, which is config file for plus module. So in order to add this classes into the Jetty container lifecycle, and by this include and parse jetty-env.xml, one need to enable plus module in addition to jndi module (jndi does not depend upon plus)! Thus I have changed my start.d config by invoking --add-to-startd=jndi,plus (no space between modules) and everything started working like a charm.