1

When running test-app in grails 3.0, or run-app, grails runs its own version of the embedded Tomcat server. I was able to conclude this from the following link: https://roshandawrani.wordpress.com/2011/03/13/grails-tip-configuring-embedded-tomcat-instance-used-in-developmenttest-env/

However, the context.xml and server.xml files are precompiled with the pulled down libraries. When creating a grails app from scratch, I cannot find either of there two files. Same is true for config.groovy, as it is located within an external library.

I am trying to inject JNDI resources, into the container, so that I can invoke them. Something like this:

<Resource name="myDatasourceName" auth="Container" type="javax.sql.DataSource"
    maxActive="100" maxIdle="30" maxWait="10000"
    username="root" password="password" driverClassName="com.mysql.jdbc.Driver"
    url="jdbc:mysql://localhost:3306/my_db_name"/>

In the first link, the authors provide a way to do it in a scripts/_Events.groovy directory, but I do not have this either.

UPDATE 1: Non-working code

import grails.boot.GrailsApp
import grails.boot.config.GrailsAutoConfiguration
import org.apache.catalina.Context
import org.apache.catalina.startup.Tomcat
import org.apache.tomcat.util.descriptor.web.ContextResource
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainer
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory
import org.springframework.context.annotation.Bean

@SpringBootApplication
class Application extends GrailsAutoConfiguration {
    static void main(String[] args) {
        GrailsApp.run(Application, args)
    }

    @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) {
                context.getNamingResources().addResource(preconfigureDbResource("oneSource", "127.0.0.1"))
                context.getNamingResources().addResource(preconfigureDbResource("nextSource", "127.0.0.1"))
            }
        }

    }

    private ContextResource preconfigureDbResource(String name, String ip) {
        ContextResource resource = new ContextResource()
        resource.setType("javax.sql.DataSource")
        resource.setName("jdbc/" + name)
        resource.setProperty("url", "jdbc:oracle:thin:@" + ip + ":1521:ucop")
        resource.setProperty("driverClassName", "oracle.jdbc.driver.OracleDriver")
        resource.setProperty("username", "coolio")
        resource.setProperty("password", "password")
        resource.setProperty("auth", "Container")
        resource.setProperty("maxTotal", "100")
        resource.setProperty("maxIdle", "30")
        resource.setProperty("maxWaitMillis", "10000")
        return resource;
    }


}

I am calling this source like this in my service file:

public DataSource getOneSource() {
    Context context = (Context) new InitialContext().lookup("java:/comp/env")
        oneSource= (DataSource) context.lookup("jdbc/oneSource")
    return oneSource
}    

But I am getting an error stating:

javax.naming.NameNotFoundException: Name [comp/env] is not bound in this Context. Unable to find [comp].

Has anyone done this before? I would not be surprised if there is an extra thread that is overwriting the context.

angryip
  • 2,140
  • 5
  • 33
  • 67

2 Answers2

0

In Grails 3, you do it like this: SampleTomcatJndiApplication

Typically, in Grails web applications, this is in /grails-app/init/Application.groovy

(In my case, I commented out the jndiDataSource() part and just used postProcessContext().)

Source: Graeme Rocher

HypeMK
  • 331
  • 3
  • 9
  • whats the purpose of the jndiDataSource() block? Can you share the code you have that works? I cannot seem to make this work on 3. – angryip Feb 18 '16 at 17:16
  • How about posting your code? (And any error messages.) – HypeMK Feb 18 '16 at 19:06
  • How about if you do this: `resource.setName("java:comp/env/jdbc/" + name)` – HypeMK Feb 18 '16 at 20:41
  • same issue :/ javax.naming.NameNotFoundException: Name [comp/env] is not bound in this Context. Unable to find [comp]. – angryip Feb 19 '16 at 12:31
  • That's strange. Can you try running it in the debugger, and see if it stops at `tomcat.enableNaming();` and in `postProcessContext()`? – HypeMK Feb 19 '16 at 18:49
  • it doesnt stop anywhere, it actually executes. I even added print statements to the individual methods, and the context resources are being added. It is almost as if some other context is overwriting the context in postProcessContext – angryip Feb 19 '16 at 19:27
  • I just noticed something in your code. How about if you do this: `Object obj = new InitialContext().lookup("java:/comp/env/jdbc/oneSource")` Or alternatively, what if you revert to `resource.setName("jdbc/" + name)` and then do `Object obj = new InitialContext().lookup("jdbc/oneSource")` – HypeMK Feb 19 '16 at 20:39
  • if I do Object obj = new InitialContext().lookup("jdbc/oneSource") the error remains the same. If i do new InitialContext().lookup("java:/comp/env/jdbc/oneSource") The error doesnt complain about java:, just comp. Name [comp/env/jdbc/rawDataSource] is not bound in this Context. Unable to find [comp]. – angryip Feb 22 '16 at 13:46
0

The solution to this issue is addressed in two steps. First, I had to use the child approach to setting the right context, found in this question. Setting the right context in embedded Tomcat

As imagined, The only change I then had to make was to the getTomcatEmbeddedServletContainer method. I have edited the original to look like this:

@Override
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;
}

Next, I had to edit the gradle build file, to include the dbcp BasicDataSource Dependency. My gradle build file now contains:

dependencies {
    // Embedded tomcat dependencies
    compile "org.apache.tomcat:tomcat-dbcp:9.0.0.M1"
}
Community
  • 1
  • 1
angryip
  • 2,140
  • 5
  • 33
  • 67