Uploaded image for project: 'camunda BPM'
  1. camunda BPM
  2. CAM-3432

Groovy Scripting Engine holds random webapp class loader when cached

    • Icon: Bug Report Bug Report
    • Resolution: Fixed
    • Icon: L3 - Default L3 - Default
    • 7.4.0, 7.3.3, 7.2.7, 7.4.0-alpha2
    • None
    • engine
    • None

      Scenario:
      Shared process engine on Tomcat. Groovy-all is in the global lib folder.
      A process application is deployed with a Groovy script. The process is started and the Groovy script evaluated. Up to now, no Groovy engine has been created which is now done. The engine is cached in the process engine configuration. After undeployment of the web application that contains the mentioned process application, all other Groovy script evaluations fail with a NullPointerException.

      Reason:
      1. Our code calls the JSR223 method ScriptEngineManager#getEngineByName
      2. This makes an SPI lookup for ScriptEngineFactories that serve scripts for the desired language
      3. The GroovyScriptEngineFactory is found and the method GroovyScriptEngineFactory#getScriptEngine() is invoked to build a new engine
      4. GroovyScriptEngineFactory#getScriptEngine() calls new GroovyScriptEngineImpl() and the constructor uses the context class loader as the parent class loader of a newly created GroovyClassLoader
      5. If the first script invocation is within the context of a process application, the context class loader is the web application's classloader
      6. After undeployment of the web application, its classloader is in an undefined state (i.e. some resources are cleared).
      7. However, it is still referenced from the GroovyScriptEngine and trying to resolve a resource from this class loader fails with a NullPointerException. This happens on any following Groovy script execution.

      Solution ideas:

      • Script engines need to be cached at a Process Application Level (keep the note below in mind)
      • it seems impossible to pass a proper classloader to GroovyScriptEngineFactory because it is called via a JSR223-SPI method which interface we have no control over
      • Since GroovyScriptEngineFactory creates a new GroovyScriptEngine with every lookup, one solution could be to remove the script engine caching. The JSR223 docs state anyway, that a ScriptEngineFactory itself can cache engines if it likes. Perhaps these implementations know better than we do whether the engines can be cached.
      • Another option could be to initialize scripting engines when the process engine is created. However this requires that we know in advance which engines are used.

      Notes:

      • This has also an impact on the script compilation option since an instance of GroovyCompiledScript keeps a reference to the ScriptEngine it was created with. When the process definition is not removed from the deployment cache when the web application is removed (isDeleteUponUndeploy = false), this results in another memory leak

      related discussion: https://groups.google.com/forum/#!msg/camunda-bpm-users/SVyoYoWPcK0/X7wIFu3nWhgJ

        This is the controller panel for Smart Panels app

            [CAM-3432] Groovy Scripting Engine holds random webapp class loader when cached

            Thorben Lindhauer created issue -
            Thorben Lindhauer made changes -
            Description Original: Scenario:
            Shared process engine on Tomcat. Groovy-all is in the global lib folder.
            A process application is deployed with a Groovy script. The process is started and the Groovy script evaluated. Up to now, no Groovy engine has been created which is now done. The engine is cached in the process engine configuration. After undeployment of the web application that contains the mentioned process application, all other Groovy script evaluations fail with a NullPointerException.

            Reason:
            1. Our code calls the JSR223 method ScriptEngineManager#getEngineByName
            2. This makes an SPI lookup for ScriptEngineFactories that serve scripts for the desired language
            3. The GroovyScriptEngineFactory is found and the method GroovyScriptEngineFactory#getScriptEngine() is invoked to build a new engine
            4. GroovyScriptEngineFactory#getScriptEngine() calls new GroovyScriptEngineImpl() and the constructor uses the context class loader as the parent class loader of a newly created GroovyClassLoader
            5. If the first script invocation is within the context of a process application, the context class loader is the web application's classloader
            6. After undeployment of the web application, its classloader is in an undefined state (i.e. some resources are cleared).
            7. However, it is still referenced from the GroovyScriptEngine and trying to resolve a resource from this class loader fails with a NullPointerException. This happens on any following Groovy script execution.

            Solution ideas:
            - it seems impossible to pass a proper classloader to GroovyScriptEngineFactory because it is called via a JSR223-SPI method which interface we have no control over
            - Since GroovyScriptEngineFactory creates a new GroovyScriptEngine with every lookup, one solution could be to remove the script engine caching. The JSR223 docs state anyway, that a ScriptEngineFactory itself can cache engines if it likes. Perhaps these implementations know better than we do whether the engines can be cached.
            New: Scenario:
            Shared process engine on Tomcat. Groovy-all is in the global lib folder.
            A process application is deployed with a Groovy script. The process is started and the Groovy script evaluated. Up to now, no Groovy engine has been created which is now done. The engine is cached in the process engine configuration. After undeployment of the web application that contains the mentioned process application, all other Groovy script evaluations fail with a NullPointerException.

            Reason:
            1. Our code calls the JSR223 method ScriptEngineManager#getEngineByName
            2. This makes an SPI lookup for ScriptEngineFactories that serve scripts for the desired language
            3. The GroovyScriptEngineFactory is found and the method GroovyScriptEngineFactory#getScriptEngine() is invoked to build a new engine
            4. GroovyScriptEngineFactory#getScriptEngine() calls new GroovyScriptEngineImpl() and the constructor uses the context class loader as the parent class loader of a newly created GroovyClassLoader
            5. If the first script invocation is within the context of a process application, the context class loader is the web application's classloader
            6. After undeployment of the web application, its classloader is in an undefined state (i.e. some resources are cleared).
            7. However, it is still referenced from the GroovyScriptEngine and trying to resolve a resource from this class loader fails with a NullPointerException. This happens on any following Groovy script execution.

            Solution ideas:
            - it seems impossible to pass a proper classloader to GroovyScriptEngineFactory because it is called via a JSR223-SPI method which interface we have no control over
            - Since GroovyScriptEngineFactory creates a new GroovyScriptEngine with every lookup, one solution could be to remove the script engine caching. The JSR223 docs state anyway, that a ScriptEngineFactory itself can cache engines if it likes. Perhaps these implementations know better than we do whether the engines can be cached.
            - Another option could be to initialize scripting engines when the process engine is created. However this requires that we know in advance which engines are used.
            Thorben Lindhauer made changes -
            Description Original: Scenario:
            Shared process engine on Tomcat. Groovy-all is in the global lib folder.
            A process application is deployed with a Groovy script. The process is started and the Groovy script evaluated. Up to now, no Groovy engine has been created which is now done. The engine is cached in the process engine configuration. After undeployment of the web application that contains the mentioned process application, all other Groovy script evaluations fail with a NullPointerException.

            Reason:
            1. Our code calls the JSR223 method ScriptEngineManager#getEngineByName
            2. This makes an SPI lookup for ScriptEngineFactories that serve scripts for the desired language
            3. The GroovyScriptEngineFactory is found and the method GroovyScriptEngineFactory#getScriptEngine() is invoked to build a new engine
            4. GroovyScriptEngineFactory#getScriptEngine() calls new GroovyScriptEngineImpl() and the constructor uses the context class loader as the parent class loader of a newly created GroovyClassLoader
            5. If the first script invocation is within the context of a process application, the context class loader is the web application's classloader
            6. After undeployment of the web application, its classloader is in an undefined state (i.e. some resources are cleared).
            7. However, it is still referenced from the GroovyScriptEngine and trying to resolve a resource from this class loader fails with a NullPointerException. This happens on any following Groovy script execution.

            Solution ideas:
            - it seems impossible to pass a proper classloader to GroovyScriptEngineFactory because it is called via a JSR223-SPI method which interface we have no control over
            - Since GroovyScriptEngineFactory creates a new GroovyScriptEngine with every lookup, one solution could be to remove the script engine caching. The JSR223 docs state anyway, that a ScriptEngineFactory itself can cache engines if it likes. Perhaps these implementations know better than we do whether the engines can be cached.
            - Another option could be to initialize scripting engines when the process engine is created. However this requires that we know in advance which engines are used.
            New: Scenario:
            Shared process engine on Tomcat. Groovy-all is in the global lib folder.
            A process application is deployed with a Groovy script. The process is started and the Groovy script evaluated. Up to now, no Groovy engine has been created which is now done. The engine is cached in the process engine configuration. After undeployment of the web application that contains the mentioned process application, all other Groovy script evaluations fail with a NullPointerException.

            Reason:
            1. Our code calls the JSR223 method ScriptEngineManager#getEngineByName
            2. This makes an SPI lookup for ScriptEngineFactories that serve scripts for the desired language
            3. The GroovyScriptEngineFactory is found and the method GroovyScriptEngineFactory#getScriptEngine() is invoked to build a new engine
            4. GroovyScriptEngineFactory#getScriptEngine() calls new GroovyScriptEngineImpl() and the constructor uses the context class loader as the parent class loader of a newly created GroovyClassLoader
            5. If the first script invocation is within the context of a process application, the context class loader is the web application's classloader
            6. After undeployment of the web application, its classloader is in an undefined state (i.e. some resources are cleared).
            7. However, it is still referenced from the GroovyScriptEngine and trying to resolve a resource from this class loader fails with a NullPointerException. This happens on any following Groovy script execution.

            Solution ideas:
            - it seems impossible to pass a proper classloader to GroovyScriptEngineFactory because it is called via a JSR223-SPI method which interface we have no control over
            - Since GroovyScriptEngineFactory creates a new GroovyScriptEngine with every lookup, one solution could be to remove the script engine caching. The JSR223 docs state anyway, that a ScriptEngineFactory itself can cache engines if it likes. Perhaps these implementations know better than we do whether the engines can be cached.
            - Another option could be to initialize scripting engines when the process engine is created. However this requires that we know in advance which engines are used.

            related discussion: https://groups.google.com/forum/#!msg/camunda-bpm-users/SVyoYoWPcK0/X7wIFu3nWhgJ
            Daniel Meyer made changes -
            Fix Version/s New: 7.2.4 [ 13507 ]
            Thorben Lindhauer made changes -
            Description Original: Scenario:
            Shared process engine on Tomcat. Groovy-all is in the global lib folder.
            A process application is deployed with a Groovy script. The process is started and the Groovy script evaluated. Up to now, no Groovy engine has been created which is now done. The engine is cached in the process engine configuration. After undeployment of the web application that contains the mentioned process application, all other Groovy script evaluations fail with a NullPointerException.

            Reason:
            1. Our code calls the JSR223 method ScriptEngineManager#getEngineByName
            2. This makes an SPI lookup for ScriptEngineFactories that serve scripts for the desired language
            3. The GroovyScriptEngineFactory is found and the method GroovyScriptEngineFactory#getScriptEngine() is invoked to build a new engine
            4. GroovyScriptEngineFactory#getScriptEngine() calls new GroovyScriptEngineImpl() and the constructor uses the context class loader as the parent class loader of a newly created GroovyClassLoader
            5. If the first script invocation is within the context of a process application, the context class loader is the web application's classloader
            6. After undeployment of the web application, its classloader is in an undefined state (i.e. some resources are cleared).
            7. However, it is still referenced from the GroovyScriptEngine and trying to resolve a resource from this class loader fails with a NullPointerException. This happens on any following Groovy script execution.

            Solution ideas:
            - it seems impossible to pass a proper classloader to GroovyScriptEngineFactory because it is called via a JSR223-SPI method which interface we have no control over
            - Since GroovyScriptEngineFactory creates a new GroovyScriptEngine with every lookup, one solution could be to remove the script engine caching. The JSR223 docs state anyway, that a ScriptEngineFactory itself can cache engines if it likes. Perhaps these implementations know better than we do whether the engines can be cached.
            - Another option could be to initialize scripting engines when the process engine is created. However this requires that we know in advance which engines are used.

            related discussion: https://groups.google.com/forum/#!msg/camunda-bpm-users/SVyoYoWPcK0/X7wIFu3nWhgJ
            New: Scenario:
            Shared process engine on Tomcat. Groovy-all is in the global lib folder.
            A process application is deployed with a Groovy script. The process is started and the Groovy script evaluated. Up to now, no Groovy engine has been created which is now done. The engine is cached in the process engine configuration. After undeployment of the web application that contains the mentioned process application, all other Groovy script evaluations fail with a NullPointerException.

            Reason:
            1. Our code calls the JSR223 method ScriptEngineManager#getEngineByName
            2. This makes an SPI lookup for ScriptEngineFactories that serve scripts for the desired language
            3. The GroovyScriptEngineFactory is found and the method GroovyScriptEngineFactory#getScriptEngine() is invoked to build a new engine
            4. GroovyScriptEngineFactory#getScriptEngine() calls new GroovyScriptEngineImpl() and the constructor uses the context class loader as the parent class loader of a newly created GroovyClassLoader
            5. If the first script invocation is within the context of a process application, the context class loader is the web application's classloader
            6. After undeployment of the web application, its classloader is in an undefined state (i.e. some resources are cleared).
            7. However, it is still referenced from the GroovyScriptEngine and trying to resolve a resource from this class loader fails with a NullPointerException. This happens on any following Groovy script execution.

            Solution ideas:
            - it seems impossible to pass a proper classloader to GroovyScriptEngineFactory because it is called via a JSR223-SPI method which interface we have no control over
            - Since GroovyScriptEngineFactory creates a new GroovyScriptEngine with every lookup, one solution could be to remove the script engine caching. The JSR223 docs state anyway, that a ScriptEngineFactory itself can cache engines if it likes. Perhaps these implementations know better than we do whether the engines can be cached.
            - Another option could be to initialize scripting engines when the process engine is created. However this requires that we know in advance which engines are used.

            Notes:
            - This has also an impact on the script compilation option since an instance of GroovyCompiledScript keeps a reference to the ScriptEngine it was created with. When the process definition is not removed from the deployment cache when the web application is removed (isDeleteUponUndeploy = false), this results in another memory leak

            related discussion: https://groups.google.com/forum/#!msg/camunda-bpm-users/SVyoYoWPcK0/X7wIFu3nWhgJ

            There seems to be a similar class loading issue with spin in scripts (e.g. javascript) on tomcat. See fixed project from this post [1] and debug in the childElements method of DomXmlElement on tomcat. It will throw a class not found exception for the class SpinListImpl and DomXmlElementIterable. If the caching of the script engines in the engine was disabled the class loading worked fine.

            [1] https://groups.google.com/d/msg/camunda-bpm-users/dEIG6qbMEUk/ysS_3iyfyzYJ

            Sebastian Menski added a comment - There seems to be a similar class loading issue with spin in scripts (e.g. javascript) on tomcat. See fixed project from this post [1] and debug in the childElements method of DomXmlElement on tomcat. It will throw a class not found exception for the class SpinListImpl and DomXmlElementIterable. If the caching of the script engines in the engine was disabled the class loading worked fine. [1] https://groups.google.com/d/msg/camunda-bpm-users/dEIG6qbMEUk/ysS_3iyfyzYJ
            Robert Gimbel made changes -
            Fix Version/s New: 7.2.5 [ 13590 ]
            Fix Version/s Original: 7.2.4 [ 13507 ]
            Daniel Meyer made changes -
            Assignee New: Ronny [ ronny.braeunlich ]
            Daniel Meyer made changes -
            Description Original: Scenario:
            Shared process engine on Tomcat. Groovy-all is in the global lib folder.
            A process application is deployed with a Groovy script. The process is started and the Groovy script evaluated. Up to now, no Groovy engine has been created which is now done. The engine is cached in the process engine configuration. After undeployment of the web application that contains the mentioned process application, all other Groovy script evaluations fail with a NullPointerException.

            Reason:
            1. Our code calls the JSR223 method ScriptEngineManager#getEngineByName
            2. This makes an SPI lookup for ScriptEngineFactories that serve scripts for the desired language
            3. The GroovyScriptEngineFactory is found and the method GroovyScriptEngineFactory#getScriptEngine() is invoked to build a new engine
            4. GroovyScriptEngineFactory#getScriptEngine() calls new GroovyScriptEngineImpl() and the constructor uses the context class loader as the parent class loader of a newly created GroovyClassLoader
            5. If the first script invocation is within the context of a process application, the context class loader is the web application's classloader
            6. After undeployment of the web application, its classloader is in an undefined state (i.e. some resources are cleared).
            7. However, it is still referenced from the GroovyScriptEngine and trying to resolve a resource from this class loader fails with a NullPointerException. This happens on any following Groovy script execution.

            Solution ideas:
            - it seems impossible to pass a proper classloader to GroovyScriptEngineFactory because it is called via a JSR223-SPI method which interface we have no control over
            - Since GroovyScriptEngineFactory creates a new GroovyScriptEngine with every lookup, one solution could be to remove the script engine caching. The JSR223 docs state anyway, that a ScriptEngineFactory itself can cache engines if it likes. Perhaps these implementations know better than we do whether the engines can be cached.
            - Another option could be to initialize scripting engines when the process engine is created. However this requires that we know in advance which engines are used.

            Notes:
            - This has also an impact on the script compilation option since an instance of GroovyCompiledScript keeps a reference to the ScriptEngine it was created with. When the process definition is not removed from the deployment cache when the web application is removed (isDeleteUponUndeploy = false), this results in another memory leak

            related discussion: https://groups.google.com/forum/#!msg/camunda-bpm-users/SVyoYoWPcK0/X7wIFu3nWhgJ
            New: Scenario:
            Shared process engine on Tomcat. Groovy-all is in the global lib folder.
            A process application is deployed with a Groovy script. The process is started and the Groovy script evaluated. Up to now, no Groovy engine has been created which is now done. The engine is cached in the process engine configuration. After undeployment of the web application that contains the mentioned process application, all other Groovy script evaluations fail with a NullPointerException.

            Reason:
            1. Our code calls the JSR223 method ScriptEngineManager#getEngineByName
            2. This makes an SPI lookup for ScriptEngineFactories that serve scripts for the desired language
            3. The GroovyScriptEngineFactory is found and the method GroovyScriptEngineFactory#getScriptEngine() is invoked to build a new engine
            4. GroovyScriptEngineFactory#getScriptEngine() calls new GroovyScriptEngineImpl() and the constructor uses the context class loader as the parent class loader of a newly created GroovyClassLoader
            5. If the first script invocation is within the context of a process application, the context class loader is the web application's classloader
            6. After undeployment of the web application, its classloader is in an undefined state (i.e. some resources are cleared).
            7. However, it is still referenced from the GroovyScriptEngine and trying to resolve a resource from this class loader fails with a NullPointerException. This happens on any following Groovy script execution.

            Solution ideas:
            - Script engines need to be cached at a Process Application Level
            - it seems impossible to pass a proper classloader to GroovyScriptEngineFactory because it is called via a JSR223-SPI method which interface we have no control over
            - Since GroovyScriptEngineFactory creates a new GroovyScriptEngine with every lookup, one solution could be to remove the script engine caching. The JSR223 docs state anyway, that a ScriptEngineFactory itself can cache engines if it likes. Perhaps these implementations know better than we do whether the engines can be cached.
            - Another option could be to initialize scripting engines when the process engine is created. However this requires that we know in advance which engines are used.

            Notes:
            - This has also an impact on the script compilation option since an instance of GroovyCompiledScript keeps a reference to the ScriptEngine it was created with. When the process definition is not removed from the deployment cache when the web application is removed (isDeleteUponUndeploy = false), this results in another memory leak

            related discussion: https://groups.google.com/forum/#!msg/camunda-bpm-users/SVyoYoWPcK0/X7wIFu3nWhgJ
            Thorben Lindhauer made changes -
            Description Original: Scenario:
            Shared process engine on Tomcat. Groovy-all is in the global lib folder.
            A process application is deployed with a Groovy script. The process is started and the Groovy script evaluated. Up to now, no Groovy engine has been created which is now done. The engine is cached in the process engine configuration. After undeployment of the web application that contains the mentioned process application, all other Groovy script evaluations fail with a NullPointerException.

            Reason:
            1. Our code calls the JSR223 method ScriptEngineManager#getEngineByName
            2. This makes an SPI lookup for ScriptEngineFactories that serve scripts for the desired language
            3. The GroovyScriptEngineFactory is found and the method GroovyScriptEngineFactory#getScriptEngine() is invoked to build a new engine
            4. GroovyScriptEngineFactory#getScriptEngine() calls new GroovyScriptEngineImpl() and the constructor uses the context class loader as the parent class loader of a newly created GroovyClassLoader
            5. If the first script invocation is within the context of a process application, the context class loader is the web application's classloader
            6. After undeployment of the web application, its classloader is in an undefined state (i.e. some resources are cleared).
            7. However, it is still referenced from the GroovyScriptEngine and trying to resolve a resource from this class loader fails with a NullPointerException. This happens on any following Groovy script execution.

            Solution ideas:
            - Script engines need to be cached at a Process Application Level
            - it seems impossible to pass a proper classloader to GroovyScriptEngineFactory because it is called via a JSR223-SPI method which interface we have no control over
            - Since GroovyScriptEngineFactory creates a new GroovyScriptEngine with every lookup, one solution could be to remove the script engine caching. The JSR223 docs state anyway, that a ScriptEngineFactory itself can cache engines if it likes. Perhaps these implementations know better than we do whether the engines can be cached.
            - Another option could be to initialize scripting engines when the process engine is created. However this requires that we know in advance which engines are used.

            Notes:
            - This has also an impact on the script compilation option since an instance of GroovyCompiledScript keeps a reference to the ScriptEngine it was created with. When the process definition is not removed from the deployment cache when the web application is removed (isDeleteUponUndeploy = false), this results in another memory leak

            related discussion: https://groups.google.com/forum/#!msg/camunda-bpm-users/SVyoYoWPcK0/X7wIFu3nWhgJ
            New: Scenario:
            Shared process engine on Tomcat. Groovy-all is in the global lib folder.
            A process application is deployed with a Groovy script. The process is started and the Groovy script evaluated. Up to now, no Groovy engine has been created which is now done. The engine is cached in the process engine configuration. After undeployment of the web application that contains the mentioned process application, all other Groovy script evaluations fail with a NullPointerException.

            Reason:
            1. Our code calls the JSR223 method ScriptEngineManager#getEngineByName
            2. This makes an SPI lookup for ScriptEngineFactories that serve scripts for the desired language
            3. The GroovyScriptEngineFactory is found and the method GroovyScriptEngineFactory#getScriptEngine() is invoked to build a new engine
            4. GroovyScriptEngineFactory#getScriptEngine() calls new GroovyScriptEngineImpl() and the constructor uses the context class loader as the parent class loader of a newly created GroovyClassLoader
            5. If the first script invocation is within the context of a process application, the context class loader is the web application's classloader
            6. After undeployment of the web application, its classloader is in an undefined state (i.e. some resources are cleared).
            7. However, it is still referenced from the GroovyScriptEngine and trying to resolve a resource from this class loader fails with a NullPointerException. This happens on any following Groovy script execution.

            Solution ideas:
            - Script engines need to be cached at a Process Application Level (keep the note below in mind)
            - it seems impossible to pass a proper classloader to GroovyScriptEngineFactory because it is called via a JSR223-SPI method which interface we have no control over
            - Since GroovyScriptEngineFactory creates a new GroovyScriptEngine with every lookup, one solution could be to remove the script engine caching. The JSR223 docs state anyway, that a ScriptEngineFactory itself can cache engines if it likes. Perhaps these implementations know better than we do whether the engines can be cached.
            - Another option could be to initialize scripting engines when the process engine is created. However this requires that we know in advance which engines are used.

            Notes:
            - This has also an impact on the script compilation option since an instance of GroovyCompiledScript keeps a reference to the ScriptEngine it was created with. When the process definition is not removed from the deployment cache when the web application is removed (isDeleteUponUndeploy = false), this results in another memory leak

            related discussion: https://groups.google.com/forum/#!msg/camunda-bpm-users/SVyoYoWPcK0/X7wIFu3nWhgJ

              thorben.lindhauer Thorben Lindhauer
              thorben.lindhauer Thorben Lindhauer
              Votes:
              0 Vote for this issue
              Watchers:
              4 Start watching this issue

                Created:
                Updated:
                Resolved: