0

I am rather new to spring boot and have implemented a way of placing a datasource in JNDI context by following the advice given in How to create JNDI context in Spring Boot with Embedded Tomcat Container

I got it to work by adding these beans to the application, which enable naming and place the datasource in JNDI-context like this:

@Autowired
Environment env;

public static void main(final String[] args) {
 SpringApplication.run(MyApplication.class, args);
}


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

  @Override
  public TomcatEmbeddedServletContainer getTomcatEmbeddedServletContainer(final Tomcat tomcat) {
    tomcat.enableNaming();
    return super.getTomcatEmbeddedServletContainer(tomcat);
  }

  @Override
  public void postProcessContext(final Context context) {
    final String dataSourceURL = env.getProperty("datasource.url");
    // more properties

    final ContextResource resource = new ContextResource();
    resource.setType(DataSource.class.getName());
    resource.setProperty("url", dataSourceURL);
    // more properties

    resource.setName("jdbc/myDB");
    resource.setAuth("Container");
    resource.setType("javax.sql.DataSource");
    resource.setScope("Sharable");

    resource.setProperty("factory", "org.apache.commons.dbcp.BasicDataSourceFactory");

    context.getNamingResources().addResource(resource);
  }
};
}

@Bean(destroyMethod = "")
public DataSource jndiDataSource() throws IllegalArgumentException, NamingException {
  final JndiObjectFactoryBean bean = new JndiObjectFactoryBean();
  bean.setJndiName("java:comp/env/jdbc/myDB");
  bean.setProxyInterface(DataSource.class);
  bean.setLookupOnStartup(false);
  bean.afterPropertiesSet();
  return (DataSource)bean.getObject();
}

So far so good, it worked. But now the specification of the project has changed. In addition of delivering a fat JAR that starts up an embedded Tomcat (as initially planned), I need to be able to deliver a WAR that has no references to the embedded Tomcat. So i created extra projects for packaging and handled the optional inclusion of embedded Tomcat via Maven dependencies. Problem is, I had to move the code that is shown above out of my main class and into a seperate package which i include via Maven dependency. And now it no longer does the trick.

I admit that I am not too familiar with how the Spring-magic with @Autowired and @Bean works, so I am kind off stumbling around here.

What do i have to do to make the creation of JNDI context work outside of my main class?

BFR
  • 105
  • 1
  • 1
  • 9
  • Don't.. Just don't... Let the user decide. Just create a WAR file (which is as executable as the jar) and if people want to use JNDI bound datasource specify the `spring.dataosurce.jndi-name` property else configure the database using the other `spring.datasoure` properties. Don't try to shoehorn all that into embedded tomcat with JNDI as that makes things way too complex. – M. Deinum Feb 06 '19 at 11:21
  • Wouldn't I still have to enable naming to do that? Seems to me it would fall back to the same problem. – BFR Feb 06 '19 at 14:12
  • No you don't need that. – M. Deinum Feb 06 '19 at 14:31
  • I´m still not sure i understand. You suggest to not use JNDI at all or make it optional? The problem is that i´m reusing an old, established persistence-layer which requires the datasource to be placed in JNDI, so i can't avoid it. Would you mind elaborating on your suggestion? – BFR Feb 06 '19 at 14:41
  • Judging from your configuration it requires a `DataSource` where it comes from shouldn't matter. Spring boot supports either. – M. Deinum Feb 06 '19 at 14:42
  • Could you point me towards more details of how to implement this? – BFR Feb 06 '19 at 15:12
  • You don't really need to implement anything. You need to change the packaging to war, make the embedded container provided and remove your setup for JNDI and the datasource. Then just configure the `spring.datasource.` properties of your need (locally the full datasource, when deployed the `jndi-name` spring boot will take care of everything else). – M. Deinum Feb 06 '19 at 18:34
  • Form the record: I tried this and it did not work, due to the nature of the underlying persistence layer. But I figured it out myself (thankfully). – BFR Feb 08 '19 at 07:28
  • @M.Deinum I'd really like to know how to do this, too. My pre-Spring Boot code uses `JndiObjectFactoryBean` to provide a `dataSource()` in my `AppConfig` configurator. Since adding Spring Boot, I can't seem to get it to create a data source and wire the beans. – Rick May 19 '20 at 23:16

1 Answers1

0

The solution turned out to be quite simple and i could find it by learning more about spring beans. I created another class in which the beans were created, annotated it with @Configuration and added it to the @ComponentScan specification of the main class. Looks like this:

@ComponentScan(basePackages = {"myBasePackage",
                           "externalPackageContainingConfiguration"})

externalPackageContainingConfiguration is only found when it´s artifact is added via Maven Dependency. A little hacky, but does the trick.

BFR
  • 105
  • 1
  • 1
  • 9