Trying to get maven pmd plugin updated to PMD 5.6.0. We get couple of strange IOExceptions when running the unit tests.
Observations:
Current state of the work: https://github.com/adangel/maven-plugins/tree/pmd-upgrade / https://github.com/adangel/maven-plugins/commit/7f3a8372755b7d18065a3090a899b611280b418c
Be aware - I'll rebase this branch, when pushing it to apache.
Exceptions:
Running org.apache.maven.plugin.pmd.PmdReportTest
java.io.IOException: Stream closed
at java.util.zip.InflaterInputStream.ensureOpen(InflaterInputStream.java:67)
at java.util.zip.InflaterInputStream.read(InflaterInputStream.java:121)
at java.io.FilterInputStream.read(FilterInputStream.java:83)
at net.sourceforge.pmd.util.ResourceLoader$1.read(ResourceLoader.java:109)
at java.io.InputStream.read(InputStream.java:170)
at java.util.zip.CheckedInputStream.read(CheckedInputStream.java:82)
at java.io.FilterInputStream.read(FilterInputStream.java:107)
at org.apache.commons.io.IOUtils.copyLarge(IOUtils.java:2146)
at org.apache.commons.io.IOUtils.copy(IOUtils.java:2102)
at org.apache.commons.io.IOUtils.copyLarge(IOUtils.java:2123)
at org.apache.commons.io.IOUtils.copy(IOUtils.java:2078)
at org.apache.commons.io.IOUtils.toByteArray(IOUtils.java:721)
at net.sourceforge.pmd.RuleSetFactoryCompatibility.filterRuleSetFile(RuleSetFactoryCompatibility.java:94)
at net.sourceforge.pmd.RuleSetFactory.parseRuleSetNode(RuleSetFactory.java:283)
at net.sourceforge.pmd.RuleSetFactory.createRuleSet(RuleSetFactory.java:211)
at net.sourceforge.pmd.RuleSetFactory.createRule(RuleSetFactory.java:258)
at net.sourceforge.pmd.RuleSetFactory.parseRuleReferenceNode(RuleSetFactory.java:588)
at net.sourceforge.pmd.RuleSetFactory.parseRuleNode(RuleSetFactory.java:358)
at net.sourceforge.pmd.RuleSetFactory.parseRuleSetNode(RuleSetFactory.java:306)
at net.sourceforge.pmd.RuleSetFactory.createRuleSet(RuleSetFactory.java:211)
at net.sourceforge.pmd.RuleSetFactory.createRuleSet(RuleSetFactory.java:206)
at net.sourceforge.pmd.RuleSetFactory.createRuleSets(RuleSetFactory.java:167)
at net.sourceforge.pmd.RuleSetFactory.createRuleSets(RuleSetFactory.java:151)
at net.sourceforge.pmd.processor.PmdRunnable.call(PmdRunnable.java:68)
at net.sourceforge.pmd.processor.PmdRunnable.call(PmdRunnable.java:27)
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)
java.io.IOException: Stream closed
at java.util.zip.InflaterInputStream.ensureOpen(InflaterInputStream.java:67)
at java.util.zip.InflaterInputStream.read(InflaterInputStream.java:121)
at java.io.FilterInputStream.read(FilterInputStream.java:83)
at net.sourceforge.pmd.util.ResourceLoader$1.read(ResourceLoader.java:109)
at java.io.InputStream.read(InputStream.java:170)
at java.util.zip.CheckedInputStream.read(CheckedInputStream.java:82)
at java.io.FilterInputStream.read(FilterInputStream.java:107)
at org.apache.commons.io.IOUtils.copyLarge(IOUtils.java:2146)
at org.apache.commons.io.IOUtils.copy(IOUtils.java:2102)
at org.apache.commons.io.IOUtils.copyLarge(IOUtils.java:2123)
at org.apache.commons.io.IOUtils.copy(IOUtils.java:2078)
at org.apache.commons.io.IOUtils.toByteArray(IOUtils.java:721)
at net.sourceforge.pmd.RuleSetFactoryCompatibility.filterRuleSetFile(RuleSetFactoryCompatibility.java:94)
at net.sourceforge.pmd.RuleSetFactory.parseRuleSetNode(RuleSetFactory.java:283)
at net.sourceforge.pmd.RuleSetFactory.createRuleSet(RuleSetFactory.java:211)
at net.sourceforge.pmd.RuleSetFactory.createRule(RuleSetFactory.java:258)
at net.sourceforge.pmd.RuleSetFactory.parseRuleReferenceNode(RuleSetFactory.java:588)
at net.sourceforge.pmd.RuleSetFactory.parseRuleNode(RuleSetFactory.java:358)
at net.sourceforge.pmd.RuleSetFactory.parseRuleSetNode(RuleSetFactory.java:306)
at net.sourceforge.pmd.RuleSetFactory.createRuleSet(RuleSetFactory.java:211)
at net.sourceforge.pmd.RuleSetFactory.createRuleSet(RuleSetFactory.java:206)
at net.sourceforge.pmd.RuleSetFactory.createRuleSets(RuleSetFactory.java:167)
at net.sourceforge.pmd.RuleSetFactory.createRuleSets(RuleSetFactory.java:151)
at net.sourceforge.pmd.processor.PmdRunnable.call(PmdRunnable.java:68)
at net.sourceforge.pmd.processor.PmdRunnable.call(PmdRunnable.java:27)
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)
[ERROR] PMD processing errors:
[ERROR] /home/andreas/projects/programming/apache.org/maven-plugins/maven-pmd-plugin/src/test/resources/unit/processing-error/src/BrokenFile.java: Error while parsing /home/andreas/projects/programming/apache.org/maven-plugins/maven-pmd-plugin/src/test/resources/unit/processing-error/src/BrokenFile.java
Tests run: 15, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 3.162 sec <<< FAILURE! - in org.apache.maven.plugin.pmd.PmdReportTest
testFileURL(org.apache.maven.plugin.pmd.PmdReportTest) Time elapsed: 1.013 sec <<< ERROR!
java.lang.RuntimeException: org.apache.maven.reporting.MavenReportException: Failure executing PMD: Couldn't find the class Stream closed
at org.apache.maven.plugin.pmd.PmdReport.canGenerateReport(PmdReport.java:277)
at org.apache.maven.reporting.AbstractMavenReport.execute(AbstractMavenReport.java:119)
at org.apache.maven.plugin.pmd.PmdReportTest.testFileURL(PmdReportTest.java:165)
Caused by: org.apache.maven.reporting.MavenReportException: Failure executing PMD: Couldn't find the class Stream closed
at org.apache.maven.plugin.pmd.PmdReport.processFilesWithPMD(PmdReport.java:469)
at org.apache.maven.plugin.pmd.PmdReport.executePmd(PmdReport.java:386)
at org.apache.maven.plugin.pmd.PmdReport.executePmdWithClassloader(PmdReport.java:290)
at org.apache.maven.plugin.pmd.PmdReport.canGenerateReport(PmdReport.java:264)
... 24 more
Caused by: java.lang.RuntimeException: Couldn't find the class Stream closed
at net.sourceforge.pmd.RuleSetFactory.classNotFoundProblem(RuleSetFactory.java:332)
at net.sourceforge.pmd.RuleSetFactory.parseRuleSetNode(RuleSetFactory.java:324)
at net.sourceforge.pmd.RuleSetFactory.createRuleSet(RuleSetFactory.java:211)
at net.sourceforge.pmd.RuleSetFactory.createRule(RuleSetFactory.java:258)
at net.sourceforge.pmd.RuleSetFactory.parseRuleReferenceNode(RuleSetFactory.java:588)
at net.sourceforge.pmd.RuleSetFactory.parseRuleNode(RuleSetFactory.java:358)
at net.sourceforge.pmd.RuleSetFactory.parseRuleSetNode(RuleSetFactory.java:306)
at net.sourceforge.pmd.RuleSetFactory.createRuleSet(RuleSetFactory.java:211)
at net.sourceforge.pmd.RuleSetFactory.createRuleSet(RuleSetFactory.java:206)
at net.sourceforge.pmd.RuleSetFactory.createRuleSets(RuleSetFactory.java:167)
at net.sourceforge.pmd.RuleSetFactory.createRuleSets(RuleSetFactory.java:151)
at net.sourceforge.pmd.processor.PmdRunnable.call(PmdRunnable.java:68)
at net.sourceforge.pmd.processor.PmdRunnable.call(PmdRunnable.java:27)
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)
Results :
Tests in error:
org.apache.maven.plugin.pmd.PmdReportTest#testFileURL RuntimeException org.apa...
Tests run: 34, Failures: 0, Errors: 1, Skipped: 0
I've also seen another test failing before, PmdReportTest#testCustomConfiguration
I wonder if line 116 of ResourceLoader.java in https://github.com/pmd/pmd/pull/349 is the culprit? The first closed resource using a Jar would close the entire Jar, affecting all other open streams?
Thorny problem that the ClassLoader used to handle? I think I'd need to research the original motivation and changes made in this area a couple commits back.
Yes, I tried that. And without closing the jar file, no errors. I don't understand however, why 5.5.6 seems to run. But - these are concurrency errors - they don't consistently come up with 5.6.0 either.
Right now, I'm looking into the solution synchronizing the method parseRuleSetNode. It seems to be working. My assumption here would be, that the JarURLConnection would reuse open file handles, if possible. If now two threads load the ruleset from the jar file, they would share the file handle. One thread finishes earlier and closes the file before the other thread had a chance to read from the stream. When this is synchronized, the JarURLConnection seems to open the file again - at least, I don't see a problem anymore.....
I've pushed my proposed fix...
@ryan-gustafson @jsotuyod What do you think?
The closing of the jar file is the problem that was being fixed in the PR I referenced. Removing it basically puts it back to 5.5.6 behavior.
This change doesn't fix the issue in ResourceLoader, which essentially can only reliably have one InputStream outstanding at a time. This may avoid a particular usage, but the API is inherently unstable/fragile at the moment.
We may need to understand the scopes of sharing for items loaded via ResourceLoader and address the sharing (or not?) directly. Again I've not researched the original problem with the ResourceLoader yet, and I won't be able to today.
Nevermind the PR was is in 5.5.6 it seems. Not sure why the difference between 5.5.6 and 5.6.0, may need to run more to trigger it.
I hope, the "synchronized fix" is good enough for 5.6.1. But you're right - it's very fragile and would fix only the one use case loading rulesets. A proper fix for 5.7 would be probably located in ResourceLoader...
Idea! Wouldn't this be fixed if we added connection.setUseCaches(false); before this: https://github.com/pmd/pmd/blob/master/pmd-core/src/main/java/net/sourceforge/pmd/util/ResourceLoader.java#L102
It's important to do it before getInputStream. I believe this will prevent any reuse that leads to these race conditions.
I've dived into the JDK code, and it looks like it should work consistently fine with my suggestion. Even having to close the jar manually doesn't seem necessary if the cache is disabled.
We should be able to revert to the old (simpler) implementation (https://github.com/pmd/pmd/blob/86d73ca26807f701ad0a8e84a7e461d46f642145/pmd-core/src/main/java/net/sourceforge/pmd/util/ResourceLoader.java#L95), and just add connection.setUseCaches(false); before returning the input stream; and all issues (both this, and the file handler leaks on windows) should be gone.
I cannot seem to find anything interesting in URLConnection and JarURLConnection and I've not decompiled the subclass in the sun package. My original researched was based on behavior in URLClassLoader. Can you point me in the right direction?
Also, we don't own these Resource, the classloader does, so we also need to make sure the behavior is correct if someone else called setUseCaches(true) on the Resource before we did. Assuming that is even possible...
@ryan-gustafson both URLConnection and JarURLConnection are abstract and don't make use of getUseCache() directly, but the concrete implementations do, in particular during the call to connect() (the value can only be modified before connecting or an exception is thrown). For instance, this is the Oracle JRE's implementation: http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8u40-b25/sun/net/www/protocol/jar/JarURLConnection.java#119
The docs on setUseCaches (which is not implementation dependant) is explicit though:
Sets the value of the useCaches field of this URLConnection to the specified value.
Some protocols do caching of documents. Occasionally, it is important to be able to "tunnel through" and ignore the caches (e.g., the "reload" button in a browser). If the UseCaches flag on a connection is true, the connection is allowed to use whatever caches it can. If false, caches are to be ignored. The default value comes from DefaultUseCaches, which defaults to true.
No reuse of the resource can be made if set to false. On Linux this may even mean an error if the file, although already open from another location, is deleted. That's exactly the behaviour we want.
Similarly, on the close() os the stream, we find:
public void close () throws IOException {
try {
super.close();
} finally {
if (!getUseCaches()) {
jarFile.close();
}
}
}
As for your concern on the ownership of the resource. The flag can be freely modified up to the point connect() is called, as seen here: http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8u40-b25/java/net/URLConnection.java#987
So even if the classloader had set it to true before returning the Resource, the fact we override it before getting the inputstream (connecting) is good enough to ensure it's not reusing resources.
@jsotuyod Awesome analysis, thanks very much! My concerns are thoroughly addressed. Great job finding this API on the connection classes, it should do the trick, and it is simple to boot.
@adangel Are we certain this isn't an issue in 5.5.6? The code is the same as in 5.6.0. Timing/concurrency problems can be difficult to manifest.
I suggest trying out Juan's change, and adding into 5.5.7 and 5.6.1.
Finally, what can be done to catch these kinds of things before release? Anything we can do on Travis? If https://github.com/pmd/pmd/issues/360 was addressed, could that suffice as a stability gatekeep?
I've tested the solution with setUseCaches(false) and this seems to be working 馃憤
@ryan-gustafson we are not certain, this problem is not in 5.5.6... It just didn't popup, when I used 5.5.6 in the maven plugin. So, yes, this fix is probably for 5.5.7 and 5.6.1 then.
It could be detected through integration tests. The chances that such a concurrency issue pops up is bigger with bigger projects - although the unit test in maven-pmd-plugin only had 5 source files to analyze... What definitely makes sense is, having one integration project, that runs maven-pmd-plugin with the current SNAPSHOT of PMD. This would highlight if we change any API (accidently or deliberately) - and in this case, we would have seen the issue earlier (before the release....).
Using pmd 5.8.1 and still seeing this issue. Were things expected to be fixed by now?
[exec] :platform:kernel:jobscheduler:pmdTest
[exec] java.io.IOException: Stream closed
[exec] at java.util.zip.InflaterInputStream.ensureOpen(InflaterInputStream.java:67)
[exec] at java.util.zip.InflaterInputStream.read(InflaterInputStream.java:142)
[exec] at java.io.FilterInputStream.read(FilterInputStream.java:133)
[exec] at java.io.FilterInputStream.read(FilterInputStream.java:107)
[exec] at org.apache.commons.io.IOUtils.copyLarge(IOUtils.java:1792)
[exec] at org.apache.commons.io.IOUtils.copyLarge(IOUtils.java:1769)
[exec] at org.apache.commons.io.IOUtils.copy(IOUtils.java:1744)
[exec] at org.apache.commons.io.IOUtils.toByteArray(IOUtils.java:462)
@cdancy yes, this has been fixed for quite some time now.
Please, provide us the following:
@jsotuyod Using Gradle 3.5 with PMD 5.8.1. Gradle config for PMD is as follows:
pmd {
toolVersion = '5.8.1'
ruleSetConfig = resources.text.fromFile(rootProject.file("gradle/config/pmd/pmd.xml"))
consoleOutput = true
ignoreFailures = false
ruleSets = [] // set to empty list otherwise we pick up defaults
}
Pmd Rules file:
<?xml version="1.0"?>
<ruleset name="PMD-Rules">
<description>
The rulesets we want to use in pmd. For a detailed description of pmd rulesets: http://pmd.sourceforge.net/rules/index.html
</description>
<rule ref="rulesets/java/imports.xml/DuplicateImports"> <priority>1</priority></rule>
<rule ref="rulesets/java/imports.xml/DontImportJavaLang"> <priority>1</priority></rule>
<rule ref="rulesets/java/imports.xml/UnusedImports"> <priority>1</priority></rule>
<rule ref="rulesets/java/imports.xml/ImportFromSamePackage"> <priority>1</priority></rule>
<rule ref="rulesets/java/unusedcode.xml/UnusedLocalVariable"> <priority>1</priority></rule>
<!-- rule ref="rulesets/java/unusedcode.xml/UnusedPrivateField"> <priority>1</priority></rule -->
<!-- rule ref="rulesets/java/unusedcode.xml/UnusedPrivateMethod"> <priority>1</priority></rule -->
<!-- rule ref="rulesets/java/unusedcode.xml/UnusedFormalParameter"> <priority>1</priority></rule -->
<exclude-pattern>.*/build/.*</exclude-pattern>
</ruleset>
Full stacktrace is as follows:
[exec] :platform:kernel:jobscheduler:pmdTest
[exec] java.io.IOException: Stream closed
[exec] at java.util.zip.InflaterInputStream.ensureOpen(InflaterInputStream.java:67)
[exec] at java.util.zip.InflaterInputStream.read(InflaterInputStream.java:142)
[exec] at java.io.FilterInputStream.read(FilterInputStream.java:133)
[exec] at java.io.FilterInputStream.read(FilterInputStream.java:107)
[exec] at org.apache.commons.io.IOUtils.copyLarge(IOUtils.java:1792)
[exec] at org.apache.commons.io.IOUtils.copyLarge(IOUtils.java:1769)
[exec] at org.apache.commons.io.IOUtils.copy(IOUtils.java:1744)
[exec] at org.apache.commons.io.IOUtils.toByteArray(IOUtils.java:462)
[exec] at net.sourceforge.pmd.RuleSetFactoryCompatibility.filterRuleSetFile(RuleSetFactoryCompatibility.java:84)
[exec] at net.sourceforge.pmd.RuleSetFactory.parseRuleSetNode(RuleSetFactory.java:249)
[exec] at net.sourceforge.pmd.RuleSetFactory.createRuleSet(RuleSetFactory.java:202)
[exec] at net.sourceforge.pmd.RuleSetFactory.createRule(RuleSetFactory.java:226)
[exec] at net.sourceforge.pmd.RuleSetFactory.parseRuleReferenceNode(RuleSetFactory.java:538)
[exec] at net.sourceforge.pmd.RuleSetFactory.parseRuleNode(RuleSetFactory.java:321)
[exec] at net.sourceforge.pmd.RuleSetFactory.parseRuleSetNode(RuleSetFactory.java:272)
[exec] at net.sourceforge.pmd.RuleSetFactory.createRuleSet(RuleSetFactory.java:202)
[exec] at net.sourceforge.pmd.RuleSetFactory.createRuleSet(RuleSetFactory.java:197)
[exec] at net.sourceforge.pmd.RuleSetFactory.createRuleSets(RuleSetFactory.java:161)
[exec] at net.sourceforge.pmd.RuleSetFactory.createRuleSets(RuleSetFactory.java:145)
[exec] at net.sourceforge.pmd.ant.internal.PMDTaskImpl.doTask(PMDTaskImpl.java:119)
[exec] at net.sourceforge.pmd.ant.internal.PMDTaskImpl.execute(PMDTaskImpl.java:269)
[exec] at net.sourceforge.pmd.ant.PMDTask.execute(PMDTask.java:47)
[exec] at org.apache.tools.ant.UnknownElement.execute(UnknownElement.java:293)
[exec] at sun.reflect.GeneratedMethodAccessor863.invoke(Unknown Source)
[exec] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
[exec] at java.lang.reflect.Method.invoke(Method.java:606)
[exec] at org.apache.tools.ant.dispatch.DispatchUtils.execute(DispatchUtils.java:106)
[exec] at groovy.util.AntBuilder.performTask(AntBuilder.java:327)
[exec] at groovy.util.AntBuilder.nodeCompleted(AntBuilder.java:272)
[exec] at org.gradle.api.internal.project.ant.BasicAntBuilder.nodeCompleted(BasicAntBuilder.java:78)
[exec] at sun.reflect.GeneratedMethodAccessor777.invoke(Unknown Source)
[exec] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
[exec] at java.lang.reflect.Method.invoke(Method.java:606)
[exec] at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93)
[exec] at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325)
[exec] at org.gradle.internal.metaobject.BeanDynamicObject$MetaClassAdapter.invokeMethod(BeanDynamicObject.java:464)
[exec] at org.gradle.internal.metaobject.BeanDynamicObject.invokeMethod(BeanDynamicObject.java:176)
[exec] at org.gradle.internal.metaobject.AbstractDynamicObject.invokeMethod(AbstractDynamicObject.java:163)
[exec] at org.gradle.api.internal.project.antbuilder.AntBuilderDelegate.nodeCompleted(AntBuilderDelegate.java:118)
[exec] at groovy.util.BuilderSupport.doInvokeMethod(BuilderSupport.java:154)
[exec] at groovy.util.BuilderSupport.invokeMethod(BuilderSupport.java:67)
[exec] at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.call(PogoMetaClassSite.java:48)
[exec] at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:133)
[exec] at org.gradle.api.plugins.quality.internal.PmdInvoker$_invoke_closure2.doCall(PmdInvoker.groovy:62)
[exec] at sun.reflect.GeneratedMethodAccessor847.invoke(Unknown Source)
[exec] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
[exec] at java.lang.reflect.Method.invoke(Method.java:606)
[exec] at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93)
[exec] at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325)
[exec] at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:294)
[exec] at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1027)
[exec] at groovy.lang.Closure.call(Closure.java:414)
[exec] at groovy.lang.Closure.call(Closure.java:430)
[exec] at org.gradle.api.internal.ClosureBackedAction.execute(ClosureBackedAction.java:71)
[exec] at org.gradle.api.internal.ClosureBackedAction.execute(ClosureBackedAction.java:53)
[exec] at org.gradle.api.internal.project.antbuilder.DefaultIsolatedAntBuilder$2.execute(DefaultIsolatedAntBuilder.java:151)
[exec] at org.gradle.api.internal.project.antbuilder.DefaultIsolatedAntBuilder$2.execute(DefaultIsolatedAntBuilder.java:133)
[exec] at org.gradle.api.internal.project.antbuilder.ClassPathToClassLoaderCache.withCachedClassLoader(ClassPathToClassLoaderCache.java:134)
[exec] at org.gradle.api.internal.project.antbuilder.DefaultIsolatedAntBuilder.execute(DefaultIsolatedAntBuilder.java:127)
[exec] at org.gradle.api.internal.project.IsolatedAntBuilder$execute$2.call(Unknown Source)
[exec] at org.gradle.api.plugins.quality.internal.PmdInvoker.invoke(PmdInvoker.groovy:60)
[exec] at org.gradle.api.plugins.quality.Pmd.run(Pmd.java:98)
[exec] at sun.reflect.GeneratedMethodAccessor834.invoke(Unknown Source)
[exec] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
[exec] at java.lang.reflect.Method.invoke(Method.java:606)
[exec] at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:73)
[exec] at org.gradle.api.internal.project.taskfactory.DefaultTaskClassInfoStore$StandardTaskAction.doExecute(DefaultTaskClassInfoStore.java:141)
[exec] at org.gradle.api.internal.project.taskfactory.DefaultTaskClassInfoStore$StandardTaskAction.execute(DefaultTaskClassInfoStore.java:134)
[exec] at org.gradle.api.internal.project.taskfactory.DefaultTaskClassInfoStore$StandardTaskAction.execute(DefaultTaskClassInfoStore.java:123)
[exec] at org.gradle.api.internal.AbstractTask$TaskActionWrapper.execute(AbstractTask.java:692)
[exec] at org.gradle.api.internal.AbstractTask$TaskActionWrapper.execute(AbstractTask.java:675)
[exec] at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter$1.execute(ExecuteActionsTaskExecuter.java:115)
[exec] at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter$1.execute(ExecuteActionsTaskExecuter.java:109)
[exec] at org.gradle.internal.Transformers$4.transform(Transformers.java:169)
[exec] at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:106)
[exec] at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:56)
[exec] at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeAction(ExecuteActionsTaskExecuter.java:109)
[exec] at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:90)
[exec] at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:68)
[exec] at org.gradle.api.internal.tasks.execution.SkipUpToDateTaskExecuter.execute(SkipUpToDateTaskExecuter.java:62)
[exec] at org.gradle.api.internal.tasks.execution.ValidatingTaskExecuter.execute(ValidatingTaskExecuter.java:58)
[exec] at org.gradle.api.internal.tasks.execution.SkipEmptySourceFilesTaskExecuter.execute(SkipEmptySourceFilesTaskExecuter.java:88)
[exec] at org.gradle.api.internal.tasks.execution.ResolveTaskArtifactStateTaskExecuter.execute(ResolveTaskArtifactStateTaskExecuter.java:46)
[exec] at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:51)
[exec] at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:54)
[exec] at org.gradle.api.internal.tasks.execution.ExecuteAtMostOnceTaskExecuter.execute(ExecuteAtMostOnceTaskExecuter.java:43)
[exec] at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:34)
[exec] at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker$1.execute(DefaultTaskGraphExecuter.java:236)
[exec] at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker$1.execute(DefaultTaskGraphExecuter.java:228)
[exec] at org.gradle.internal.Transformers$4.transform(Transformers.java:169)
[exec] at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:106)
[exec] at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:61)
[exec] at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker.execute(DefaultTaskGraphExecuter.java:228)
[exec] at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker.execute(DefaultTaskGraphExecuter.java:215)
[exec] at org.gradle.execution.taskgraph.AbstractTaskPlanExecutor$TaskExecutorWorker.processTask(AbstractTaskPlanExecutor.java:77)
[exec] at org.gradle.execution.taskgraph.AbstractTaskPlanExecutor$TaskExecutorWorker.run(AbstractTaskPlanExecutor.java:58)
[exec] at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:63)
[exec] at org.gradle.internal.concurrent.StoppableExecutorImpl$1.run(StoppableExecutorImpl.java:46)
[exec] at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
[exec] at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
[exec] at java.lang.Thread.run(Thread.java:745)
[exec] :platform:kernel:messagebus:compileIntegTestJava
[exec] :platform:kernel:jobscheduler:pmdTest FAILED
[exec] Note: C:\usr\app\AutomatedInstaller\work\proje
@cdancy awesome. Just to be sure now I would like you to check 2 more things
<pmd tag)./gradlew --stop and reproduce the issue again?The thing is, the Gradle daemon has an issue where, once a version of PMD is loaded, it will keep on being used even after changing toolVersion (same applies to other tools other than PMD, this is down to the dependencies being kept in the classloader).
@jsotuyod well would you look at that:
<pmd version="5.5.1" timestamp="2017-08-11T09:43:48.841">
So that's an interesting bug of sorts ;) Can't easily do #2 as it doesn't pop every run however unfortunate. Any thoughts or suggestions? Maybe override the PMD gradle configruration assuming it can be done in this case?
@cdancy that's it then! Your run used PMD 5.5.1 due to the Gradle daemon bug, not 5.8.1. 5.5.1 was before this fix.
After restarting the daemon, as long as the PMD version is not changed, you should be using the newly set PMD version. If it does happen with 5.8.1 feel free to let us know with an updated stacktrace; but it shouldn't.
@jsotuyod these pops actually occur on a fresh dockerized instance with nothing having been previously run on them. So there is no caching of any sort going on. Furthermore I'm not using the daemon on my desktop, and can confirm there are no daemon processes running, and still it's using the older version. This is not your guys fault of course just wondering if you have a "better" solution. Maybe I'll try forcing the PMD configuration.
@cdancy I fear I know of no other reason for having a different version run than the one you configured... but please, let us know if you manage to find the reason / fix it, so we may help others in the future.
Will do. Stay tuned...
@jsotuyod , or for folks coming along to this thread, I tried every "gradle trick" to get this to work with gradle-3.5 and still it would use the older version. Bumping to gradle 4.x allowed me to do what I wanted and all the expected "gradle tricks" to use a different config/version worked as expected.
So the solution, so far as I can tell, is to use the latest and greatest gradle.
Most helpful comment
@ryan-gustafson both
URLConnectionandJarURLConnectionare abstract and don't make use ofgetUseCache()directly, but the concrete implementations do, in particular during the call toconnect()(the value can only be modified before connecting or an exception is thrown). For instance, this is the Oracle JRE's implementation: http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8u40-b25/sun/net/www/protocol/jar/JarURLConnection.java#119The docs on
setUseCaches(which is not implementation dependant) is explicit though:No reuse of the resource can be made if set to false. On Linux this may even mean an error if the file, although already open from another location, is deleted. That's exactly the behaviour we want.
Similarly, on the
close()os the stream, we find:http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8u40-b25/sun/net/www/protocol/jar/JarURLConnection.java#JarURLConnection.JarURLInputStream
As for your concern on the ownership of the resource. The flag can be freely modified up to the point
connect()is called, as seen here: http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8u40-b25/java/net/URLConnection.java#987So even if the classloader had set it to true before returning the
Resource, the fact we override it before getting the inputstream (connecting) is good enough to ensure it's not reusing resources.