[
https://issues.apache.org/jira/browse/IVY-1347?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13443634#comment-13443634
]
Mitch Gitman commented on IVY-1347:
-----------------------------------
The attached patch addresses two separate sets of bugs:
* One set that was introduced with some changes that were made to my series of
patches for issues IVY-1359, IVY-1363, IVY-1364.
* Another bug that went unaddressed by a solution to IVY-1347 that was a
rationale for the preceding changes.
KEEPING TRACK OF PARENT-SPECIFIC MODULE-INHERITANCE-REPOSITORY RESOLVER
When Maarten Coene merged from trunk into the 2.3.x branch some otherwise
worthwhile refinements to the work I'd done to have XmlModuleDescriptorParser
correctly locate source parent modules on the filesystem, he removed the
following line:
IvyContext.getContext().getSettings().addResolver(parentModuleResolver);
This line was necessary for the resolve-parent-from-source-location mechanism
to work in a normal and predictable way. Without it, I would see error output
like the following on a regular basis:
[ivy:resolve] :: problems summary ::
[ivy:resolve] :::: ERRORS
[ivy:resolve] unknown resolver
module-inheritance-repository-com.foo#bootstrap-parent;1.0
[ivy:resolve] unknown resolver
module-inheritance-repository-com.foo#bootstrap-parent;1.0
[ivy:resolve] unknown resolver
module-inheritance-repository-com.foo#bootstrap-parent;1.0
At the risk of sounding like a broken record, as I'd noted before with a
previous modification of this feature, it violates any reasonable contract to
be reporting errors for non-error behaviors that happen in the normal course of
things. Simple principle: crying wolf about nonexistent errors is itself an
error.
Worse, right after the error gets reported, something insidious happens.
Because the caller, DefaultRepositoryCacheManager, can't find the correct
resolver, it goes and either finds or creates another one:
DependencyResolver resolver =
settings.getResolver(resolverName);
if (resolver == null) {
Message.debug("/tresolver not found: " + resolverName
+ " => trying to use the one configured for " +
mrid);
resolver =
settings.getResolver(depMD.getResolvedModuleRevisionId());
This second resolver, a ChainResolver, is different from the original
FileSystemResolver that was created. So the FileSystemResolver we go to the
trouble to create in the method checkParentModuleOnFilesystem is never actually
used to located the parent module.
Therefore, I have restored the line that adds the parent-specific
FileSystemResolver to IvySettings.
Now, Maarten told me the reason he removed that line was that, with it still
there, he would still have the StackOverflowError associated with IVY-1347:
https://issues.apache.org/jira/browse/IVY-1347
I was not able to reproduce this failure, even though I'm using Windows as
Maarten is.
CHCEKING FOR MISLEADING PARENT SOURCE LOCATION
However, I noticed something suspicious about the particular test project that
was attached to the bug. See:
ivy-2.3.x/test/repositories/IVY-1347
This test case contains two source modules, childtwo and childone. The ivy.xml
for childtwo indicates that its parent is foo#parent. Since no location is
specified, the default location, the ivy.xml one directory above, is used:
<info organisation="foo" module="childtwo" revision="1.0"
status="integration">
<extends organisation="foo" module="parent" revision="1.0"/>
</info>
The problem is, the ivy.xml at that location is the one for the childone
module, not parent. As a result, Ivy is getting tricked into treating childOne
as the parent of childTwo when it's not.
When you get into
XmlModuleDescriptorParser.resolveParentFromModuleInheritanceRepository, the
resolver named module-inheritance-repository-foo#parent;1.0 has for its only
ivyPattern ivy-2.3.x/test/repositories/IVY-1347/childone/ivy.xml.
Then, within the resolveParentFromModuleInheritanceRepository call, you get to
the following line in Repository.findResourceUsingPattern:
String resourceName = IvyPatternHelper.substitute(pattern,
mrid, artifact);
At this point, the values are:
pattern = ivy-2.3.x/test/repositories/IVY-1347/childone/ivy.xml
mrid = foo#parent;1.0
artifact = foo#parent;1.0!ivy.xml(ivy)
resourceName = ivy-2.3.x/test/repositories/IVY-1347/childone/ivy.xml
You see the unkosher mixing of parent and childone. And
findResourceUsingPattern indeed returns a ResolvedResource of:
ivy-2.3.x/test/repositories/IVY-1347/childone/ivy.xml (1.0)
Then in BasicResolver.getDependency, the ResolvedModuleResource rmr becomes
foo#parent;1.0.
My sense is the only reason this test isn't blowing up is that there's nothing
in the parent to merge. I also believe that Maarten's experiencing the
StackOverflowError had something to do with Ivy trying to resolve this invalid
combination.
Now, with the attached patch, Ivy ignores the false positive, and no purported
source-located parent resolver gets added to the Ivy settings. Instead, the
parent has to be found in the regular repository.
To accomplish this, I've added a method isExpectedParentInLocation to
XmlModuleDescriptorParser. If that method returns false,
resolveParentFromModuleInheritanceRepository is not called.
The isExpectedParentInLocation implementation relies on a new class,
MinimalParentParser, that I've added as a static class in
XmlModuleDescriptorParser. This parser parses just enough of the parent ivy.xml
to find the organisation/module/revision combination. From here, the Parser in
XmlModuleDescriptorParser checks if the ModuleRevisionId in the parent ivy.xml
matches the ModuleRevisionId in the extends element of the child ivy.xml. This
includes obtaining a VersionMatcher and calling accept on it, so that a desired
revision like "latest.integration" in the extends will match something like
"1.0" in the parent:
VersionMatcher versionMatcher =
settings.getVersionMatcher();
if (versionMatcher.accept(expectedParentMrid,
actualParentMrid)) {
return true;
}
This solution required adding a getVersionMatcher() method to the
ParserSettings interface.
NOTE: I've created this patch only for the 2.3.x branch, but not for trunk.
> StackOverflowError when using <extends> with no location specified
> ------------------------------------------------------------------
>
> Key: IVY-1347
> URL: https://issues.apache.org/jira/browse/IVY-1347
> Project: Ivy
> Issue Type: Bug
> Components: Core
> Affects Versions: 2.3.0-RC1
> Reporter: Matt Hurne
> Assignee: Maarten Coene
> Priority: Critical
> Labels: testcase
> Fix For: 2.3.0
>
> Attachments: IVY-1347-1363.patch, IVY-1347.zip
>
>
> When using {{<extends>}} without specifying a {{location}}, we end up with a
> {{StackOverflowError}}. For example:
> {noformat}
> ...
> <info organisation="foo" module="bar" revision="1.0" status="integration">
> <extends organisation="foo" module="parent" revision="1.0.0" />
> </info>
> ...
> {noformat}
> {noformat}
> [ivy:buildlist] :: Apache Ivy 2.3.0-rc1 - 20120416000235 ::
> http://ant.apache.org/ivy/ ::
> [ivy:buildlist] :: loading settings :: file = D:\foo\ivysettings.xml
> BUILD FAILED
> java.lang.StackOverflowError
> at java.net.URL.set(URL.java:683)
> at java.net.URLStreamHandler.setURL(URLStreamHandler.java:521)
> at java.net.URLStreamHandler.setURL(URLStreamHandler.java:571)
> at sun.net.www.protocol.jar.Handler.parseURL(Handler.java:76)
> at java.net.URL.<init>(URL.java:596)
> at java.net.URL.<init>(URL.java:464)
> at
> sun.misc.URLClassPath$JarLoader.checkResource(URLClassPath.java:674)
> at sun.misc.URLClassPath$JarLoader.getResource(URLClassPath.java:759)
> at sun.misc.URLClassPath$JarLoader.findResource(URLClassPath.java:735)
> at sun.misc.URLClassPath.findResource(URLClassPath.java:146)
> at java.net.URLClassLoader$2.run(URLClassLoader.java:385)
> at java.security.AccessController.doPrivileged(Native Method)
> at java.net.URLClassLoader.findResource(URLClassLoader.java:382)
> at java.lang.ClassLoader.getResource(ClassLoader.java:1003)
> at java.lang.ClassLoader.getResourceAsStream(ClassLoader.java:1193)
> at javax.xml.parsers.SecuritySupport$4.run(SecuritySupport.java:96)
> at java.security.AccessController.doPrivileged(Native Method)
> at
> javax.xml.parsers.SecuritySupport.getResourceAsStream(SecuritySupport.java:89)
> at
> javax.xml.parsers.FactoryFinder.findJarServiceProvider(FactoryFinder.java:250)
> at javax.xml.parsers.FactoryFinder.find(FactoryFinder.java:223)
> at
> javax.xml.parsers.SAXParserFactory.newInstance(SAXParserFactory.java:128)
> at org.apache.ivy.util.XMLHelper.newSAXParser(XMLHelper.java:57)
> at org.apache.ivy.util.XMLHelper.parse(XMLHelper.java:120)
> at org.apache.ivy.util.XMLHelper.parse(XMLHelper.java:96)
> at org.apache.ivy.util.XMLHelper.parse(XMLHelper.java:86)
> at
> org.apache.ivy.plugins.parser.xml.XmlModuleDescriptorParser$Parser.parse(XmlModuleDescriptorParser.java:276)
> at
> org.apache.ivy.plugins.parser.xml.XmlModuleDescriptorParser.parseDescriptor(XmlModuleDescriptorParser.java:116)
> at
> org.apache.ivy.plugins.resolver.RepositoryResolver.findResourceUsingPattern(RepositoryResolver.java:109)
> at
> org.apache.ivy.plugins.resolver.AbstractPatternsBasedResolver.findResourceUsingPatterns(AbstractPatternsBasedResolver.java:96)
> at
> org.apache.ivy.plugins.resolver.AbstractPatternsBasedResolver.findIvyFileRef(AbstractPatternsBasedResolver.java:66)
> at
> org.apache.ivy.plugins.resolver.BasicResolver.getDependency(BasicResolver.java:228)
> at
> org.apache.ivy.plugins.parser.xml.XmlModuleDescriptorParser$Parser.resolveParentFromModuleInheritanceRepository(XmlModuleDescriptorParser.java:684)
> at
> org.apache.ivy.plugins.parser.xml.XmlModuleDescriptorParser$Parser.extendsStarted(XmlModuleDescriptorParser.java:438)
> at
> org.apache.ivy.plugins.parser.xml.XmlModuleDescriptorParser$Parser.startElement(XmlModuleDescriptorParser.java:327)
> at org.apache.xerces.parsers.AbstractSAXParser.startElement(Unknown
> Source)
> at
> org.apache.xerces.parsers.AbstractXMLDocumentParser.emptyElement(Unknown
> Source)
> at
> org.apache.xerces.impl.XMLNSDocumentScannerImpl.scanStartElement(Unknown
> Source)
> at
> org.apache.xerces.impl.XMLDocumentFragmentScannerImpl$FragmentContentDispatcher.dispatch(Unknown
> Source)
> at
> org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown
> Source)
> at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
> at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
> at org.apache.xerces.parsers.XMLParser.parse(Unknown Source)
> at org.apache.xerces.parsers.AbstractSAXParser.parse(Unknown Source)
> at org.apache.xerces.jaxp.SAXParserImpl$JAXPSAXParser.parse(Unknown
> Source)
> at org.apache.xerces.jaxp.SAXParserImpl.parse(Unknown Source)
> at org.apache.ivy.util.XMLHelper.parse(XMLHelper.java:133)
> at org.apache.ivy.util.XMLHelper.parse(XMLHelper.java:96)
> at org.apache.ivy.util.XMLHelper.parse(XMLHelper.java:86)
> at
> org.apache.ivy.plugins.parser.xml.XmlModuleDescriptorParser$Parser.parse(XmlModuleDescriptorParser.java:276)
> at
> org.apache.ivy.plugins.parser.xml.XmlModuleDescriptorParser.parseDescriptor(XmlModuleDescriptorParser.java:116)
> at
> org.apache.ivy.plugins.resolver.RepositoryResolver.findResourceUsingPattern(RepositoryResolver.java:109)
> at
> org.apache.ivy.plugins.resolver.AbstractPatternsBasedResolver.findResourceUsingPatterns(AbstractPatternsBasedResolver.java:96)
> at
> org.apache.ivy.plugins.resolver.AbstractPatternsBasedResolver.findIvyFileRef(AbstractPatternsBasedResolver.java:66)
> at
> org.apache.ivy.plugins.resolver.BasicResolver.getDependency(BasicResolver.java:228)
> at
> org.apache.ivy.plugins.parser.xml.XmlModuleDescriptorParser$Parser.resolveParentFromModuleInheritanceRepository(XmlModuleDescriptorParser.java:684)
> at
> org.apache.ivy.plugins.parser.xml.XmlModuleDescriptorParser$Parser.extendsStarted(XmlModuleDescriptorParser.java:438)
> at
> org.apache.ivy.plugins.parser.xml.XmlModuleDescriptorParser$Parser.startElement(XmlModuleDescriptorParser.java:327)
> at org.apache.xerces.parsers.AbstractSAXParser.startElement(Unknown
> Source)
> at
> org.apache.xerces.parsers.AbstractXMLDocumentParser.emptyElement(Unknown
> Source)
> at
> org.apache.xerces.impl.XMLNSDocumentScannerImpl.scanStartElement(Unknown
> Source)
> at
> org.apache.xerces.impl.XMLDocumentFragmentScannerImpl$FragmentContentDispatcher.dispatch(Unknown
> Source)
> at
> org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown
> Source)
> at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
> at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
> at org.apache.xerces.parsers.XMLParser.parse(Unknown Source)
> at org.apache.xerces.parsers.AbstractSAXParser.parse(Unknown Source)
> at org.apache.xerces.jaxp.SAXParserImpl$JAXPSAXParser.parse(Unknown
> Source)
> at org.apache.xerces.jaxp.SAXParserImpl.parse(Unknown Source)
> at org.apache.ivy.util.XMLHelper.parse(XMLHelper.java:133)
> at org.apache.ivy.util.XMLHelper.parse(XMLHelper.java:96)
> at org.apache.ivy.util.XMLHelper.parse(XMLHelper.java:86)
> at
> org.apache.ivy.plugins.parser.xml.XmlModuleDescriptorParser$Parser.parse(XmlModuleDescriptorParser.java:276)
> at
> org.apache.ivy.plugins.parser.xml.XmlModuleDescriptorParser.parseDescriptor(XmlModuleDescriptorParser.java:116)
> at
> org.apache.ivy.plugins.resolver.RepositoryResolver.findResourceUsingPattern(RepositoryResolver.java:109)
> at
> org.apache.ivy.plugins.resolver.AbstractPatternsBasedResolver.findResourceUsingPatterns(AbstractPatternsBasedResolver.java:96)
> at
> org.apache.ivy.plugins.resolver.AbstractPatternsBasedResolver.findIvyFileRef(AbstractPatternsBasedResolver.java:66)
> at
> org.apache.ivy.plugins.resolver.BasicResolver.getDependency(BasicResolver.java:228)
> at
> org.apache.ivy.plugins.parser.xml.XmlModuleDescriptorParser$Parser.resolveParentFromModuleInheritanceRepository(XmlModuleDescriptorParser.java:684)
> ...
> {noformat}
--
This message is automatically generated by JIRA.
If you think it was sent incorrectly, please contact your JIRA administrators
For more information on JIRA, see: http://www.atlassian.com/software/jira