1
votes

I know there are a lot of questions about JNDI Resources in tomcat embedded, but I tried all the solutions I found without success.

I have an application that expose Rest API for my clients. Inside this app, we have a async solution using JMS and Amazon SQS. The App uses third-part libs, that uses JNDI to get sql.Datasource, because of that, I need use JNDI Datasource.

The problem is, when the App does a call to this libs in the same thread of Rest Controller, the JNDI Lookup works, and the datasource is getted.

When my @JmsListener calls this libs, I get a NamingNotFoungException.

I've used context.list("java") in 2 points of my code and confirmed that, inside JmsListener, there is no JNDI Context.

My tomcat factory class: Configuration public class CustomTomcatEmbeddedServletContainerFactory {

@Value("${spring.log.datasource.jndiName}")
private String logJndiName;

@Value("${spring.log.datasource.password}")
private String logPassword;

@Value("${spring.log.datasource.url}")
private String logUrl;

@Value("${spring.log.datasource.username}")
private String logUsername;

@Bean
public TomcatEmbeddedServletContainerFactory tomcatFactory() {
    return new TomcatEmbeddedServletContainerFactory() {

        @Override
        protected TomcatEmbeddedServletContainer getTomcatEmbeddedServletContainer(Tomcat tomcat) {
            tomcat.enableNaming();

            return super.getTomcatEmbeddedServletContainer(tomcat);
        }

        @Override
        protected void postProcessContext(Context context) {
            // LogDS
            context.getNamingResources()
                .addResource(
                    getContextResource(logJndiName, logUrl, logUsername, logPassword)
                );
            ContextResourceLink contextResourceLink = new 
                    ContextResourceLink();
                             contextResourceLink.setGlobal(logJndiName);
                             contextResourceLink.setName(logJndiName);
                             contextResourceLink.setType("javax.sql.DataSource");
                             context.getNamingResources().addResourceLink(contextResourceLink);

        }

        private ContextResource getContextResource(
                final String name
                , final String url
                , final String username
                , final String password
            ) {
            ContextResource resource = new ContextResource();
            resource.setName(name);
            resource.setType(DataSource.class.getName());
            resource.setProperty("factory", "com.zaxxer.hikari.HikariJNDIFactory");
            resource.setProperty("jdbcUrl", url);
            resource.setProperty("dataSource.user", username);
            resource.setProperty("dataSource.password", AESCrypto.decrypt(password));
            resource.setScope("Sharable");
            return resource;
            }
        };
    }
}

Any idea of this problem?

-------Update---------

When I use the code below, the context in JMSListener solve but my RestController doesn't answer anymore, a 404 http status happen.

 protected TomcatEmbeddedServletContainer getTomcatEmbeddedServletContainer(Tomcat tomcat) {
            tomcat.enableNaming();
            TomcatEmbeddedServletContainer container = super.getTomcatEmbeddedServletContainer(tomcat);
            for (Container child : container.getTomcat().getHost().findChildren()) {
                if (child instanceof Context) {
                    ClassLoader contextClassLoader = ((Context) child).getLoader().getClassLoader();
                    Thread.currentThread().setContextClassLoader(contextClassLoader);
                    break;
                }
            }
            return container;
        }

-------Update2--------- My problem is fixed. Instead of returning "container", like I said above, I was returning super.getTomcatEmbeddedServletContainer(tomcat); The manual GlobalContext in my first update works well!

1

1 Answers

0
votes

My problem is fixed. Instead of returning "container", like I said above, I was returning super.getTomcatEmbeddedServletContainer(tomcat); The manual GlobalContext in my first update works well!