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)