Uploaded image for project: 'CXF'
  1. CXF
  2. CXF-7083

Maven Plugins: System properties handling in ClassLoaderSwitcher breaks thread safety

    XMLWordPrintableJSON

Details

    • Bug
    • Status: Closed
    • Major
    • Resolution: Fixed
    • 2.7.18
    • 3.0.13, 3.1.11, 3.2.0
    • Tooling
    • None
    • Unknown

    Description

      We got a rather large Maven project with a couble of modules that execute cxf-codegen-plugin. Our builds runs in parallel mode via -Tx and according to the JavaDoc the plugin should be fine with that:

      /**
       * @goal wsdl2java
       * @phase generate-sources
       * @description CXF WSDL To Java Tool
       * @requiresDependencyResolution test
       * @threadSafe
       */
      public class WSDL2JavaMojo extends AbstractCodegenMoho {
      ...
      

      But from time to time (maybe 5% of our builds) we see following exception causing the respective build to fail:

      [ERROR] Failed to execute goal org.apache.cxf:cxf-codegen-plugin:2.7.18:wsdl2java (exampleExec) on project example-module: Execution exampleService of goal org.apache.cxf:cxf-codegen-plugin:2.7.18:wsdl2java failed. ConcurrentModificationException -> [Help 1]
      org.apache.maven.lifecycle.LifecycleExecutionException: Failed to execute goal org.apache.cxf:cxf-codegen-plugin:2.7.18:wsdl2java (exampleExec) on project example-module: Execution exampleService of goal org.apache.cxf:cxf-codegen-plugin:2.7.18:wsdl2java failed.
      	at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:212)
      	at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:153)
      	at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:145)
      	at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:116)
      	at org.apache.maven.lifecycle.internal.builder.multithreaded.MultiThreadedBuilder$1.call(MultiThreadedBuilder.java:185)
      	at org.apache.maven.lifecycle.internal.builder.multithreaded.MultiThreadedBuilder$1.call(MultiThreadedBuilder.java:181)
      	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
      	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
      	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
      	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
      	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
      	at java.lang.Thread.run(Thread.java:745)
      Caused by: org.apache.maven.plugin.PluginExecutionException: Execution exampleService of goal org.apache.cxf:cxf-codegen-plugin:2.7.18:wsdl2java failed.
      	at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:145)
      	at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:207)
      	... 11 more
      Caused by: java.util.ConcurrentModificationException
      	at java.util.Hashtable$Enumerator.next(Hashtable.java:1378)
      	at java.util.HashMap.putMapEntries(HashMap.java:511)
      	at java.util.HashMap.<init>(HashMap.java:489)
      	at org.apache.cxf.maven_plugin.ClassLoaderSwitcher.restoreClassLoader(ClassLoaderSwitcher.java:129)
      	at org.apache.cxf.maven_plugin.AbstractCodegenMoho.execute(AbstractCodegenMoho.java:326)
      	at org.apache.cxf.maven_plugin.wsdl2java.WSDL2JavaMojo.execute(WSDL2JavaMojo.java:524)
      	at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:134)
      	... 12 more
      [ERROR] 
      [ERROR] Re-run Maven using the -X switch to enable full debug logging.
      [ERROR] 
      [ERROR] For more information about the errors and possible solutions, please read the following articles:
      [ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/PluginExecutionException
      

      There seems to be a write access from another thread while ClassLoaderSwitcher tries to copy the system properties:

              if (origProps != null) {
                  Map<Object, Object> newProps = new HashMap<Object, Object>(System.getProperties());
                  for (Object o : newProps.keySet()) {
                      if (!origProps.containsKey(o)) {
                          System.clearProperty(o.toString());
                      }
                  }
                  System.getProperties().putAll(origProps);
      }
      

      Possible solutions:

      • synchronize on System.getProperties() in the entire block (lines 129-135)
      • create a clone
        (Properties) System.getProperties().clone()
        

        and instead of .putAll() use .setProperties(...)

      I haven't checked ClassLoaderSwitcher .switchClassLoader() but I guess something similar needs to be done there.

      Attachments

        Activity

          People

            dkulp Daniel Kulp
            famod Falko Modler
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved: