简体   繁体   中英

How to do a remote JNDI lookup from Spring Boot Client to GlassFish Server?

I am starting with a working Spring Boot application, using the latest version of Spring Boot and embedded Tomcat. It contains a HomeController with an index method mapped to a corresponding .jsp in the webapp directory.

@RequestMapping(value={"/", "/home", "/home/index"})
public ModelAndView index() {
    ModelAndView mv = new ModelAndView("/home/index");
    return mv;
}

My goal is to do a remote JNDIlookup to a glassfish server to access an EJB Singleton Service. I have previously verified using a simple desktop client that Remote JNDI lookups to my Glassfish server are working perfectly.

I followed this tutorial for WildFly, repurposing it for Glassfish: https://www.baeldung.com/spring-ejb

Seemed simple enough. Instead of WildFly's client module, I would import Glassfish's, and instead of WildFly's InitialContext properties, I would use Glassfish's.

So I updated my pom.xml with this (I also added a dependency containing remote interfaces):

 <dependency>
      <groupId>org.glassfish.main.appclient</groupId>
      <artifactId>gf-client</artifactId>
      <version>5.1.0</version>
 </dependency>

Updated McvConfig.java like this (my base port for GlassFish is 8000, and it adds 37 for the JNDI port):

 @Bean
 public Context ejbInitialContext() {
      InitialContext initialContext = null;
      try {
           Properties jndiProps = new Properties();
           jndiProps.put(Context.INITIAL_CONTEXT_FACTORY,
            "com.sun.enterprise.naming.impl.SerialInitContextFactory");
           jndiProps.put(Context.STATE_FACTORIES,
            "com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl");
           jndiProps.put(Context.URL_PKG_PREFIXES, "com.sun.enterprise.naming");
           jndiProps.put("org.omg.CORBA.ORBInitialHost", "localhost");
           // optional.  Defaults to 3700.  Only needed if target orb port is not 3700.
           jndiProps.put("org.omg.CORBA.ORBInitialPort", "8037");
           initialContext = new InitialContext(jndiProps);
      } catch (NamingException e) {
      } 
      return initialContext;
 }

And Updated HomeController like this:

@Autowired
Context ejbInitialContext;

@RequestMapping(value={"/", "/home", "/home/index"})
public ModelAndView index() {
    ModelAndView mv = new ModelAndView("/home/index");
    ServiceRemote service = (ServiceRemote) ejbInitialContext.lookup("java:global/core/Service");
    mv.addObject("Hello", service.hello());
    return mv;
}

I ran the GlassFish server, and then tried to run my Spring Boot app. The Sprint Boot logs did not show up, and after a while, I got this instead (Full Log Here: https://pastebin.com/E11xLmFN ):

 org.omg.CORBA.COMM_FAILURE: FINE: 00410001: Connection failure: socketType: IIOP_CLEAR_TEXT; hostname: localhost; port: 3700  vmcid: OMG  minor code: 1  completed: No
 ...
 Caused by: java.lang.RuntimeException: java.net.ConnectException: Connection refused: connect
 ...
 Caused by: java.net.ConnectException: Connection refused: connect

I tried accessing localhost and it just said:

This site can’t be reached

I messed around with it for a while, and concluded a few things:

  1. Adding the new dependency was all it took to break Spring MVC and take down my web service.
  2. Spring is trying to integrate with GlashFish, because the stack trace includes this:

    at org.springframework.jndi.JndiTemplate.lambda$lookup$0(JndiTemplate.java:157) at org.springframework.jndi.JndiTemplate.execute(JndiTemplate.java:92) at org.springframework.jndi.JndiTemplate.lookup(JndiTemplate.java:157) at org.springframework.jndi.JndiTemplate.lookup(JndiTemplate.java:179)

  3. Spring is completely ignoring my Bean and using the default GlassFish InitialContext, because the port number in the logs is still 3700, the default for GlassFish, but I specified 8048.

Spring is somehow detecting the client module and periodically attempting to connect to Glassfish. The problem is that I have absolutely no idea how to tell Spring to use my custom InitialContext properties.

I looked all over the web for a solution. Most of the similar questions were not asked very well, and received no answers, and others were specifically about the DataSource, which is too specific for me, as I am trying to put the entire Service layer on a Jakarta EE server.

Nevermind. I just figured out what to do. If you look in the stack trace, it is starting at the beginning of the Spring Boot app: SpringApplication.run(App.class, args);

Spring Boot is literally initializing the GlassFish AppClient inside it's own initialization. That much was clear when I wrote this question.

It turns out the only way to do this is to put the same properties from the InitialContext inside the System Properties like this:

@SuppressWarnings("unused")
private static ApplicationContext applicationContext;
public static void main( String[] args ) throws NamingException
{
    Properties props = System.getProperties();   
    jndiProps.put(Context.INITIAL_CONTEXT_FACTORY,
        "com.sun.enterprise.naming.impl.SerialInitContextFactory");
    jndiProps.put(Context.STATE_FACTORIES,
        "com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl");
    jndiProps.put(Context.URL_PKG_PREFIXES, "com.sun.enterprise.naming");
    jndiProps.put("org.omg.CORBA.ORBInitialHost", "localhost");
       // optional.  Defaults to 3700.  Only needed if target orb port is not 3700.
    jndiProps.put("org.omg.CORBA.ORBInitialPort", "8037");
    System.setProperties(props);
    applicationContext = SpringApplication.run(App.class, args);
}

You must take the initial System properties first and add to it, before overwriting the System properties with the new set of properties, or you will break the whole thing.

It must also be done before running the SpringApplication, because that is where the initialization is happening.

The very last thing I had to do was move the aforementioned GlassFish AppClient underneath all of the Spring dependencies in the pom.xml. Having it near the top was creating a NoClassDefFoundError for a Connector class that I think was in the Tomcat server itself.

<dependency>
  <groupId>org.glassfish.main.appclient</groupId>
  <artifactId>gf-client</artifactId>
  <version>5.1.0</version>
</dependency>

After that I opened my webpage and the test text created inside the EJB Singleton living on my GlassFish server was passed through my Spring Boot client and into my browser. Proving the system works as expected.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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