javamavenclientweblogicrmi

Porting Weblogic T3 RMI client to Java 17


I am moving my old SpringBoot 2 / Java 8 application to the newer SpringBoot 3 / Java 17.

My issue is related to the Weblogic T3 client. Until now I used the wlthint3client artifact coming from a Weblogic 12.2.1.3 installation (compiled by Java 8) which runs with no issues.

Using the same artifact inside the new architecture, based on SpringBoot 3 / Java 17 the new InitialContext(environment) instruction stucks forever!!!

Could anybody tell me if there exist a newer release of the Weblogic Client, or a workaround for that issue?

Here is a fragment of the code which uses the client:

public static MyRemoteEJB lookup(
    String clusterAddress,
    String userName,
    String password
)
    throws NamingException
{
    Properties environment = new Properties();

    environment.put(Context.INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory");
    environment.put(Context.PROVIDER_URL,            clusterAddress);

    if (null != userName) {
        environment.put(Context.SECURITY_PRINCIPAL, userName);
    }

    if (null != password) {
        environment.put(Context.SECURITY_CREDENTIALS, password);
    }

    environment.put("weblogic.jndi.allowExternalAppLookup", "true");
    environment.put("weblogic.jndi.relaxVersionLookup",     "true");

    InitialContext context      = new InitialContext(environment);
    String         resourceName = String.format(
        "remote-app#%s",
        MyRemoteEJB.class.getName()
    );

    return (MyRemoteEJB)context.lookup(resourceName);
}

Thank you so much!


Solution

  • With a lot of effort, I finally solved the issue!

    I am going to describe which the solution is, and how I achieved it.

    The first step was to ask to the Oracle support, provided by my company, the Jakarta version of the Weblogic T3 Thin Client shipped with Weblogic 14.1.1.0.

    I decompiled and debugged it by the IntelliJ built-in java decompiler to get enough information to activate and redirect the T3 client debug logs to my console (look at the below source code).

    Here the relevant source code:

    logging.properties

    handlers=java.util.logging.ConsoleHandler
    .level=FINE
    
    java.util.logging.ConsoleHandler.level=FINE
    java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter
    

    Main.java

    package org.example;
    
    import javax.naming.Context;
    import javax.naming.InitialContext;
    import javax.naming.NamingException;
    import java.util.Properties;
    import java.util.logging.Logger;
    
    public class Main {
        private static final Logger logger = Logger.getLogger(Main.class.getName());
    
        private static void loggerSetup() {
            String pwd = System.getenv("PWD");
    
            System.setProperty(
                "java.util.logging.config.file",
                (pwd + "/src/main/resources/logging.properties")
            );
    
            System.setProperty("com.bea.core.debug.DebugLegacy.stdout", "true");
            System.setProperty("weblogic.diagnostics.debug.DebugLogger.DISABLED", "false");
    
            System.setProperty("weblogic.debug.DebugAbbrevs", "true");
            System.setProperty("weblogic.debug.DebugAllowList", "true");
            //System.setProperty("weblogic.debug.DebugClassLoadingContextualTrace", "true");
            //System.setProperty("weblogic.debug.DebugClassLoadingVerbose", "true");
            System.setProperty("weblogic.debug.DebugCluster", "true");
            System.setProperty("weblogic.debug.DebugClusterVerbose", "true");
            System.setProperty("weblogic.debug.DebugConnection", "true");
            System.setProperty("weblogic.debug.DebugDGCEnrollment", "true");
            System.setProperty("weblogic.debug.DebugFailOver", "true");
            System.setProperty("weblogic.debug.DebugGenericMethodDescriptor", "true");
            System.setProperty("weblogic.debug.DebugJNDI", "true");
            System.setProperty("weblogic.debug.DebugJVMID", "true");
            System.setProperty("weblogic.debug.DebugLegacy", "true");
            System.setProperty("weblogic.debug.DebugLoadBalancing", "true");
            System.setProperty("weblogic.debug.DebugMessaging", "true");
            System.setProperty("weblogic.debug.DebugRMIRequestPerf", "true");
            System.setProperty("weblogic.debug.DebugRouting", "true");
            System.setProperty("weblogic.debug.DebugStubGeneration", "true");
            System.setProperty("weblogic.debug.ServerHelp", "true");
        }
    
        private static Object lookup(
            String clusterAddress,
            String userName,
            String password
        )
            throws NamingException
        {
            Properties environment = new Properties();
    
            environment.put(Context.INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory");
            environment.put(Context.PROVIDER_URL,            clusterAddress);
    
            if (null != userName) {
                environment.put(Context.SECURITY_PRINCIPAL, userName);
            }
    
            if (null != password) {
                environment.put(Context.SECURITY_CREDENTIALS, password);
            }
    
            environment.put("weblogic.jndi.allowExternalAppLookup", "true");
            environment.put("weblogic.jndi.relaxVersionLookup",     "true");
    
            InitialContext context      = new InitialContext(environment);
            String         resourceName = String.format(
                "remote-app#%s",
                MyRemoteEJB.class.getName()
            );
    
    
            return context.lookup(resourceName);
        }
    
        public static void main(String[] args) {
            loggerSetup();
    
            logger.info("Connecting...");
    
            try {
    
                Object myRemoterEJB = lookup("t3://127.0.0.1:7002", null, null);
    
                if (null != sogeiAdapterEJB) {
                    logger.info("Remove EJB got!");
                }
    
            } catch(NamingException e) {
                String message = e.getMessage();
    
                if (message.contains("MyRemoteEJB")) {
                    logger.info("Remote EJB got, but not marshaled.");
                } else {
                    logger.severe(message);
                }
            }
        }
    
    }
    

    Running it I got several exceptions, but only one really related to my problem:

    java.lang.reflect.InaccessibleObjectException: Unable to make private static java.lang.ClassLoader java.io.ObjectInputStream.latestUserDefinedLoader() accessible: module java.base does not "opens java.io" to unnamed module @50675690
    

    The above one was the root cause of:

    Try to create JVM connection 1 time, encounter : java.io.IOException: Timed out while attempting to establish connection to :t3://127.0.0.1:7002
    

    The solution was provided by this post, so I added the JVM arguments:

    --add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.util=ALL-UNNAMED --add-opens java.base/java.io=ALL-UNNAMED
    

    All the connections issues are gone!!!