Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to configure hotswap-agent.properties with weblogic? #164

Open
zenglian opened this issue Jan 4, 2017 · 11 comments
Open

How to configure hotswap-agent.properties with weblogic? #164

zenglian opened this issue Jan 4, 2017 · 11 comments

Comments

@zenglian
Copy link

zenglian commented Jan 4, 2017

I'm using maven + weblogic 12c.

What I did:

(1) installed dcevmlight for jdk1.8.0-112 v8 as altjvm.

(2) add below line in setDomainEnv.cmd, version is 1.0.1-SNAPSHOT

set JAVA_OPTIONS=%JAVA_OPTIONS% -XXaltjvm=dcevm -javaagent:G:\programs\java\hotswap-agent.jar

(3) put hotswap-agent.properties in src/main/resources, where g:/a/b/c/d/target/classes is the target path of mvn compile.

extraClasspath=G:/a/b/c/d/target/classes
autoHotswap=true
autoHotswap.port=8453

(4) run "mvn clean install" to package the classes under g:/a/b/c/d/class into lib1.jar and deploy it to weblogic server. hotswap-agent.properties is in the root of jar file.

(5) edit a java file and run "mvn -o compile".

I'm expecting the modified class is reloaded by weblogic server, but nothing happens. What's wrong with the above steps?

From weblogic console, I see a lot of messages like "HOTSWAP AGENT: 20:46:01.274 INFO (org.hotswap.agent.watch.nio.TreeWatcherNIO) - Registering directory target C:\oracle\fmwhome12\user_projects\domains\base_domain\servers\AdminServer\tmp_WL_user\MyApp\kd1vs via watched: C:\oracle\fmwhome12\user_projects\domains\base_domain\servers\AdminServer\tmp_WL_user\MyApp", but I could not find the string "g:/a/b/c/d/target/classes" I defined in hotswap-agent.properties.

Thanks.

@rs-renato
Copy link

I also would like to know..

@jp295m
Copy link

jp295m commented Sep 30, 2018

I think HotSwapAgent does not support Weblogic. Can someone confirm?

@skybber
Copy link
Contributor

skybber commented Jan 1, 2019

You are right, it does not support.

@Kladdkaka
Copy link

Hi! I would like to try to get hotswapagent working with weblogic, have there been any progress or anything that is helpful to start off with?

@skybber
Copy link
Contributor

skybber commented Jun 17, 2019

Unfortunately nobody is working on it now.

@ramuece09
Copy link

Hi! Do we have any updates on this? Is the current version HotswapAgent works with web logic? Please confirm

@skybber
Copy link
Contributor

skybber commented Aug 2, 2020

Probably it does not work.

@Kladdkaka
Copy link

For @ramuece09 and anyone who might be interested, a while ago I tried to write a plugin to enable weblogic support, if I recall correctly I kind of got it to work, although it was quite buggy and I have completely forgot how I configured weblogic, and I think some weird JVM crash also happened, although that could have been that weblogics built-in fastswap was enabled or something.

package org.hotswap.agent.plugin.weblogic

import org.hotswap.agent.annotation.Init
import org.hotswap.agent.annotation.OnClassLoadEvent
import org.hotswap.agent.javassist.*
import org.hotswap.agent.logging.AgentLogger
import org.hotswap.agent.util.classloader.HotswapAgentClassLoaderExt
import org.hotswap.agent.util.classloader.WatchResourcesClassLoader

/**
 * ModuleClassLoaderTransformer
 */
class ModuleClassLoaderTransformer {
    @Init
    var moduleClassLoader: ClassLoader? = null

    companion object {
        protected var LOGGER = AgentLogger.getLogger(ModuleClassLoaderTransformer::class.java)

        @OnClassLoadEvent(classNameRegexp = "weblogic.utils.classloaders.ChangeAwareClassLoader")
        @Throws(NotFoundException::class, CannotCompileException::class)
        @JvmStatic
        fun transformChangeAwareClassLoader(classPool: ClassPool, ctClass: CtClass) {
            LOGGER.error("transformChangeAwareClassLoader: ${ctClass.simpleName}")

            val src = """$currentClassName.logMessage("ChangeAwareClassLoaderConstructor -> " + $1.toString());"""

            ctClass.getDeclaredConstructor(arrayOf(
                    classPool["weblogic.utils.classloaders.ClassFinder"],
                    CtClass.booleanType,
                    classPool["java.lang.ClassLoader"]
            )).insertBefore(src)
        }

        @OnClassLoadEvent(classNameRegexp = "weblogic.utils.classloaders.MultiClassFinder")
        @Throws(NotFoundException::class, CannotCompileException::class)
        @JvmStatic
        fun transformMultiClassFinder(classPool: ClassPool, ctClass: CtClass) {
            LOGGER.error("MultiClassFinder: ${ctClass.simpleName}")

            val srcAddFinder = """$currentClassName.logMessage("MultiClassFinder#addFinder -> " + $1.toString());"""

            ctClass.getDeclaredMethod("addFinder", arrayOf(classPool["weblogic.utils.classloaders.ClassFinder"])).insertBefore(
                    srcAddFinder
            )
            val srcAddFinderFirst = """$currentClassName.logMessage("MultiClassFinder#addFinderFirst -> " + $1.toString());"""

            ctClass.getDeclaredMethod("addFinderFirst", arrayOf(classPool["weblogic.utils.classloaders.ClassFinder"])).insertBefore(
                    srcAddFinderFirst
            )
        }

        @OnClassLoadEvent(classNameRegexp = "weblogic.utils.classloaders.CompositeWebAppFinder")
        @Throws(NotFoundException::class, CannotCompileException::class)
        @JvmStatic
        fun transformCompositeWebAppFinder(classPool: ClassPool, ctClass: CtClass) {
            LOGGER.error("MultiClassFinder: ${ctClass.simpleName}")
            val src = """$currentClassName.logMessage("CompositeWebAppFinder#addLibraryFinder -> " + $1.toString());"""
            ctClass.getDeclaredMethod("addLibraryFinder", arrayOf(classPool["weblogic.utils.classloaders.ClassFinder"])).insertBefore(
                    src
            )
        }

        @OnClassLoadEvent(classNameRegexp = "weblogic.utils.classloaders.GenericClassLoader")
        @Throws(NotFoundException::class, CannotCompileException::class)
        @JvmStatic
        fun transformGenericClassLoader(classPool: ClassPool, ctClass: CtClass) {
            LOGGER.error("transformGenericClassLoader: ${ctClass.simpleName}")

            val ctHaClassLoader = classPool[HotswapAgentClassLoaderExt::class.java.name]
            ctClass.addInterface(ctHaClassLoader)

            val setExtraClassPath = "$\$ha\$setExtraClassPath"

            val srcSetExtraClassPath = """
            public void $setExtraClassPath(java.net.URL[] extraClassPath) {
                $currentClassName.logMessage("okokok -> " + extraClassPath[0].toString());
                try {
                    weblogic.utils.classloaders.MultiClassFinder multiClassFinder = new weblogic.utils.classloaders.MultiClassFinder();
                    for (int i = 0; i < extraClassPath.length; i++) {
                        try {
                            java.net.URL url = extraClassPath[i];
                            java.io.File root = new java.io.File(url.getPath());
                            weblogic.utils.classloaders.IndexedDirectoryClassFinder indexedDirectoryClassFinder = new weblogic.utils.classloaders.IndexedDirectoryClassFinder(root);
                            multiClassFinder.addFinder(indexedDirectoryClassFinder);
                        } catch (java.lang.Exception e) {
                            $currentClassName.logException(e);
                        }
                    }
                    this.addClassFinderFirst(multiClassFinder);
                    $currentClassName.logMessage("classpathzlol -> " + this.getClassPath());
                } catch (java.lang.Exception e) {
                    $currentClassName.logException(e);
                }
            }
            """.trimIndent()

            ctClass.addMethod(CtNewMethod.make(
                    srcSetExtraClassPath,
                    ctClass
            ))

            val setWatchResourceLoader = "$\$ha\$setWatchResourceLoader"

            val srcSetWatchResourceLoader = """
            public void $setWatchResourceLoader(${WatchResourcesClassLoader::class.java.name} watchResourceLoader) {
                $currentClassName.logMessage("WatchResourcesClassLoader -> " + watchResourceLoader.toString());
            }
            """.trimIndent()

            ctClass.addMethod(CtNewMethod.make(
                    srcSetWatchResourceLoader,
                    ctClass
            ))
        }

        @JvmStatic
        fun logMessage(str: String) {
            LOGGER.error("logMessage: $str")
        }

        @JvmStatic
        fun logException(ex: Exception?) {
            LOGGER.error("logException", ex)
        }
    }
}

private val currentClassName: String
    get() {
        return ModuleClassLoaderTransformer::class.java.name
    }

Although I must say that I am quite new to the Java world still, I think I had only worked with Java for 1.5 year or something when I wrote that, so there is probably some stupid mistake that I did :)

@skybber
Copy link
Contributor

skybber commented Sep 30, 2020

It looks OK for me, could you please turn it to Java code and make plugin?

@skybber skybber closed this as completed Sep 30, 2020
@skybber skybber reopened this Sep 30, 2020
@ramuece09
Copy link

@Kladdkaka It's really sounds good. I'm a Java freak.. Let me pitch this when I get some time. Thanks for the update. Share if you have any specific error message

@tporeba
Copy link
Contributor

tporeba commented Jan 29, 2022

@skybber @ramuece09 I translated the plugin draft by @Kladdkaka into Java and it does work. For now I just tested some basic paths of reloading existing class or adding a new one with WLS12 - and it is OK, it works even for EJB classes.

See:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants