[ 
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

Reply via email to