Thomas Watson created FELIX-5450:
------------------------------------

             Summary: Fragments with multiple hosts can cause 
java.lang.ArrayIndexOutOfBoundsException
                 Key: FELIX-5450
                 URL: https://issues.apache.org/jira/browse/FELIX-5450
             Project: Felix
          Issue Type: Bug
          Components: Resolver
    Affects Versions: resolver-1.10.0
            Reporter: Thomas Watson
            Assignee: Thomas Watson


The fix in FELIX-5389 for ShadowList is not complete.  There are still cases 
where the underlying ArrayList from the CandidateSelector is reused in the 
ShadowList when it is not intended.  This leads to exceptions like the 
following:

java.lang.ArrayIndexOutOfBoundsException: -1
        at java.util.ArrayList.elementData(ArrayList.java:418)
        at java.util.ArrayList.set(ArrayList.java:446)
        at org.apache.felix.resolver.util.ShadowList.replace(ShadowList.java:81)
        at org.apache.felix.resolver.Candidates.prepare(Candidates.java:915)
        at 
org.apache.felix.resolver.ResolverImpl.getInitialCandidates(ResolverImpl.java:502)
        at 
org.apache.felix.resolver.ResolverImpl.doResolve(ResolverImpl.java:387)
        at org.apache.felix.resolver.ResolverImpl.resolve(ResolverImpl.java:375)
        at org.apache.felix.resolver.ResolverImpl.resolve(ResolverImpl.java:368)

This is happening when there are multiple hosts for a single fragment and the 
fragment has a requirement that is getting resolved to a candidate from another 
host resource that also has at least one fragment.

The issue comes up when replacing the capability from the host with a wrapped 
capability for the fragment requirement which is a payload requirement for more 
than one host.  It should do this for each WrappedRequirement that is wrapping 
the payload requirement from the fragment to each host.  The first 
WrappedRequirement has its candidates modified, but that changes the shared 
ArrayList of the candidates for each of the other WrappedRequirements for the 
other hosts.  The fix for this is to ensure the ArrayList from a 
CandidateSelector is never shared with a ShadowList.

But once I fixed this I ran into another strange issue that ended up causing 
Uses constraint errors like this:

org.osgi.service.resolver.ResolutionException: Uses constraint violation. 
Unable to resolve resource host [osgi.identity; host] because it is exposed to 
package 'exporter' from resources exporter [osgi.identity; exporter] and 
exporter [osgi.identity; exporter] via two dependency chains.

Chain 1:
  host [osgi.identity; host]
    import: (osgi.wiring.package=exporter)
     |
    export: osgi.wiring.package: exporter
  exporter [osgi.identity; exporter]

Chain 2:
  host [osgi.identity; host]
    import: (osgi.wiring.package=exporter)
     |
    export: osgi.wiring.package: exporter
  exporter [osgi.identity; exporter]

This only happens if a fragment has more than one host and the fragment and 
host have a requirement for a the same package.  Additionally the capability 
that satisfies the payload requirement must come from a host that also has at 
least one fragment.  The issue here is how we are finding CandidateSelectors of 
depending requirements when we need to replace a capability with a wrapped 
capability.  There is a loop in the Candidates.prepare method which is says 
"Copy candidates for fragment requirements to the host.".  This loop basically 
copies the candidates from the original requirement from the fragment to a 
CandidateSelector for the WrappedRequirement for the host.  But it also removes 
the original requirement from the dependents for the capability.  If there are 
multiple hosts this becomes problematic because this dependency set is used to 
find CandidateSelectors that need to be modified when wrapping a host.  But 
since we remove the original requirement from the fragment that means any other 
hosts the fragment is attached to will not be discovered and therefore will not 
have the original capability properly replaced with the WrappedCapability.  
That makes the consistency check fail and give this bogus message that make it 
look like there are 2 identical chains leading to the identical capability.  
But the two capabilities are different because one is wrapped and one is not.

The fix is to separate out the inner loop that "Copy candidates for fragment 
requirements to the host." to a outer loop that is done before the main loop 
over the hostResources.  This way we properly setup all the CandidateSelector 
for the payload WrappedRequirements before actually modifying the 
CandidateSelector capabilities with the WrappedCapabilities.

Super long story short:  Fragments are just horribly complex. 



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)

Reply via email to