This Bugzilla instance is deprecated, and most Eclipse projects now use GitHub or Eclipse GitLab. Please see the deprecation plan for details.
Bug 338240 - Unsatisfied constraint for ACTIVE bundle
Summary: Unsatisfied constraint for ACTIVE bundle
Status: RESOLVED FIXED
Alias: None
Product: Equinox
Classification: Eclipse Project
Component: Framework (show other bugs)
Version: 3.7   Edit
Hardware: PC Windows Vista
: P3 normal (vote)
Target Milestone: 3.7 M6   Edit
Assignee: Thomas Watson CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2011-02-25 11:26 EST by Lazar Kirchev CLA
Modified: 2011-03-07 08:38 EST (History)
3 users (show)

See Also:


Attachments
Sample bundles reproducing the problem (1.33 KB, application/zip)
2011-02-25 11:26 EST, Lazar Kirchev CLA
no flags Details
Single bundle which reproduces the problem (395 bytes, application/java-archive)
2011-02-25 11:44 EST, Nobody - feel free to take it CLA
no flags Details
patch + test (4.14 KB, text/plain)
2011-03-02 09:52 EST, Thomas Watson CLA
no flags Details
patch for state helper + test (3.44 KB, patch)
2011-03-03 15:20 EST, Thomas Watson CLA
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Lazar Kirchev CLA 2011-02-25 11:26:33 EST
Created attachment 189825 [details]
Sample bundles reproducing the problem

I have two bundles, test.bundle.api_1.0.0.BUILD-1 and test.bundle.impl_1.0.0.BUILD-2. The second is a fragment to the first. The first imports package test.bundle.impl with version 1.0.0.BUILD-1. The fragment exports the same package with no version (then it should be 0.0.0 by default). No bundle exports the package with version 1.0.0.BUILD-1. Both bundles resolve, but the diag command for the first bundle returns missing imported package test.bundle.impl_[1.0.0.BUILD-1, 1.0.0.BUILD-1].

The steps for reproducing are as follows:

1. Install the two bundles from the attached archive and refresh
2. Call diag command for the api bundle.
Comment 1 Nobody - feel free to take it CLA 2011-02-25 11:34:13 EST
See http://dev.eclipse.org/mhonarc/lists/virgo-dev/msg00747.html for a real-world instance of this problem. The issue is that we have an ACTIVE bundle and yet diag reports an unsatisfied constraint for the import that was dropped in favour of an export of the same package.

Perhaps diag should print some text saying that the import was dropped because the constraint could not be satisified (or whatever the reason actually was).
Comment 2 Nobody - feel free to take it CLA 2011-02-25 11:43:51 EST
I can reproduce this problem without using a fragment. I will attach a test bundle with the following manifest:

Manifest-Version: 1.0
Export-Package: test
Created-By: 1.6.0_22 (Apple Inc.)
Bundle-ManifestVersion: 2
Import-Package: test;version=1
Bundle-SymbolicName: test

Here's the bundle's appearance to the Equinox console:

bundle 58
test_0.0.0 [58]
  Id=58, Status=ACTIVE      Data Root=/Users/glynnormington/downloads/virgo-kernel-3.0.0.M01/work/osgi/configuration/org.eclipse.osgi/bundles/58/data
  No registered services.
  No services in use.
  Exported packages
    test; version="0.0.0"[exported]
  No imported packages
  No fragment bundles
  Named class space
    test; bundle-version="0.0.0"[provided]
  No required bundles

osgi> diag 58
org.eclipse.virgo.region.user@file:/Users/glynnormington/downloads/virgo-kernel-3.0.0.M01/work/org.eclipse.virgo.kernel.deployer_3.0.0.M01/staging/global/bundle/test/0.0.0/test.jar/ [58]
  Direct constraints which are unresolved:
    Missing imported package test_1.0.0.
Comment 3 Nobody - feel free to take it CLA 2011-02-25 11:44:41 EST
Created attachment 189827 [details]
Single bundle which reproduces the problem
Comment 4 Thomas Watson CLA 2011-02-25 12:25:25 EST
The diag command is using org.eclipse.osgi.service.resolver.StateHelper.getUnsatisfiedConstraints(BundleDescription) to determine unresolved constraints.  It seems odd to me that this is returning unresolved constraints for a bundle that is resolved.  Currently this method returns unresolved optional constraints for resolved bundles also.  Perhaps if the bundle is resolved it should only return unresolved optional constraints and forget about non-optional constraints.  Non-optional constraints must have been dropped choosing the export instead.
Comment 5 Lazar Kirchev CLA 2011-03-01 10:59:49 EST
(In reply to comment #4)
> The diag command is using
> org.eclipse.osgi.service.resolver.StateHelper.getUnsatisfiedConstraints(BundleDescription)
> to determine unresolved constraints.  It seems odd to me that this is returning
> unresolved constraints for a bundle that is resolved.  Currently this method
> returns unresolved optional constraints for resolved bundles also.  Perhaps if
> the bundle is resolved it should only return unresolved optional constraints
> and forget about non-optional constraints.  Non-optional constraints must have
> been dropped choosing the export instead.

But why the import is resolved to the export? The import states version 1.0.0 for package test, while the export of test is with version 0.0.0. The import should be discarded, but only if it is resolved to an export - at least according to the spec. 

Actually, this is why org.eclipse.osgi.service.resolver.StateHelper.getUnsatisfiedConstraints(BundleDescription) returns the import as unsatisfied - for each import of the bundle it checks if there is an export, which satisfies it. In this case actually the export does not satisfy the import - the version check fails. The check is actually in ImportPackageSpecificationImpl.isSatisfiedBy(BaseSescription).
Comment 6 Thomas Watson CLA 2011-03-01 11:21:11 EST
(In reply to comment #5)
> 
> But why the import is resolved to the export? 

The import is not resolved to the export.  Instead, the framework has a decision to make.  Should the bundle be considered as an importer of the package or an exporter of the package.  At runtime a bundle cannot be both an exporter and an importer of a package at the same time, the framework must decide if the bundle is going to play the role of exporter or importer.  In this case the framework decided that the bundle will be an exporter of the package and decided to drop the import role.

> The import states version 1.0.0
> for package test, while the export of test is with version 0.0.0. The import
> should be discarded, but only if it is resolved to an export - at least
> according to the spec. 

Can you point me to the section of the specification (including what version of the specification) this is stated?  I have not found anything that makes this clear in the specification.


> 
> Actually, this is why
> org.eclipse.osgi.service.resolver.StateHelper.getUnsatisfiedConstraints(BundleDescription)
> returns the import as unsatisfied - for each import of the bundle it checks if
> there is an export, which satisfies it. In this case actually the export does
> not satisfy the import - the version check fails. The check is actually in
> ImportPackageSpecificationImpl.isSatisfiedBy(BaseSescription).

Right, but the important piece of information missing is that the framework completely discarded the import so it will never be resolved to a provider.
Comment 7 Lazar Kirchev CLA 2011-03-02 02:26:02 EST
> Can you point me to the section of the specification (including what version of
> the specification) this is stated?  I have not found anything that makes this
> clear in the specification.

Section 3.8, Resolving Process (version 4.3, page 51) states that:

"If a module has both import and export definitions for the same package, then the Framework needs
to decide which to choose.
It must first try to resolve the overlapping import definition. The following outcomes are possible:
• External – If this resolves to an export statement in another bundle, then the overlapping export definition in this bundle is discarded.
• Internal – If it is resolved to an export statement in this module, then the overlapping import definition in this module is discarded.
• Unresolved – There is no matching export definition. This is however a developer error because it means the overlapping export definition of the bundle is not compatible with the overlapping import definition."

I thought that if the outcome of the import of the resolving is unresolved, then the bundle should stay unresolved. Probably my interpretation is wrong?

> Right, but the important piece of information missing is that the framework
> completely discarded the import so it will never be resolved to a provider.

But if the import was completely discarded, why it is included in the return result of the call to BundleDescription.getImportPackages()?  StateHelperImpl.getUnsatisfiedConstraints() checks if there are exports to resolve the imports, returned by this call. Since the import is present in the returned result and there is no export to resolve it, finally it is considered as unsatisfied constraint.
Comment 8 Thomas Watson CLA 2011-03-02 09:09:20 EST
(In reply to comment #7)
> > Can you point me to the section of the specification (including what version of
> > the specification) this is stated?  I have not found anything that makes this
> > clear in the specification.
> 
> Section 3.8, Resolving Process (version 4.3, page 51) states that:
> 

Well, look at that.  You are correct, it looks like we should not allow the bundle to resolve.  This is quite surprising to me.  I know equinox used to behave this way, but after several discussions with Richard Hall.  He and I decided it was valid to drop the import in this case.  Felix < 3.0 actually does the same thing here.  But that does not seem correct now that I look at section 3.8 in more detail.

> I thought that if the outcome of the import of the resolving is unresolved,
> then the bundle should stay unresolved. Probably my interpretation is wrong?
> 

I would say your interpretation is correct.  I don't see much room for the framework to behave otherwise.  Only if the import is optional should the resolve succeed IMO.

Looks like I will have to find a way to fix this.  The behavior changed in equinox when I implemented

> > Right, but the important piece of information missing is that the framework
> > completely discarded the import so it will never be resolved to a provider.
> 
> But if the import was completely discarded, why it is included in the return
> result of the call to BundleDescription.getImportPackages()? 
> StateHelperImpl.getUnsatisfiedConstraints() checks if there are exports to
> resolve the imports, returned by this call. Since the import is present in the
> returned result and there is no export to resolve it, finally it is considered
> as unsatisfied constraint.

BundleDescription.getImportPackages() is really only returning the declared imports, it knows nothing about dropping of imports and it should not know that either.
Comment 9 Thomas Watson CLA 2011-03-02 09:52:52 EST
Created attachment 190150 [details]
patch + test

(In reply to comment #8)
> Looks like I will have to find a way to fix this.  The behavior changed in
> equinox when I implemented
> 

Really wish I could edit comments in bugzilla ...

I meant to put the bug # that changed to this behavior (bug217724).  We even have a non-overlapping testcase in equinox to test this.  This patch changes the test case to match the spec.

I have had more discussions with Richard Hall on this.  While Felix > 3.0 behaves as the spec states in this regard that is not how Felix < 3.0 behaved.  There is some debate on if the spec should be loosened in this regard.  Also see OSGi bug https://www.osgi.org/members/bugzilla/show_bug.cgi?id=582 for CPEG discussion/decision that seems to contradict what the spec has written.

At any rate, here is a potential patch should CPEG decide that this is the correct behavior.
Comment 10 Lazar Kirchev CLA 2011-03-02 10:42:14 EST
(In reply to comment #9)

Thanks for the patch, Tom! 

As for the StateHelperImpl.getUnsatisfiedConstraints() - it seems that it did not take into account that an import was discarded and tried to resolve it. Is this the correct behavior? Can the resolving logic in StateHelperImpl check if an import is discarded and not try to resolve it at all?
Comment 11 Thomas Watson CLA 2011-03-03 14:57:03 EST
(In reply to comment #10)
> (In reply to comment #9)
> 
> Thanks for the patch, Tom! 

At the CPEG call we decided that the specification text is too strict and that the current behavior in Equinox should be allowed.  We will publish an errata for this to the R4.2 and the just released R4.3 specification.  So this patch will not be released.

> 
> As for the StateHelperImpl.getUnsatisfiedConstraints() - it seems that it did
> not take into account that an import was discarded and tried to resolve it. Is
> this the correct behavior? Can the resolving logic in StateHelperImpl check if
> an import is discarded and not try to resolve it at all?

Yes, this is what I am eluding to in comment 4.  For bundles that are resolved Perhaps it should only return unresolved OPTIONAL constraints and forget about non-optional constraints.  Non-optional constraints for a resolved bundle must have must have been dropped choosing the export instead.
Comment 12 Thomas Watson CLA 2011-03-03 15:20:47 EST
Created attachment 190305 [details]
patch for state helper + test

Here is a patch to StateHelper to ignore discarded imports from resolved bundles.
Comment 13 Thomas Watson CLA 2011-03-03 15:35:28 EST
Patch released.
Comment 14 Lazar Kirchev CLA 2011-03-07 05:06:58 EST
Regarding the substitution of imports and exports, it seems to me that the case with fragments could cause problems. If I have a bundle which imports a specific version, and my bundle really needs this version to work, I expect that if another bundle does not export this version, my bundle will not resolve. 
But if someone creates a fragment to my bundle - I assume that I know nothing about this fragment - and the fragment exports a lower version of the package that my bundle imports with a specific version, then even if no other bundle exports this package with the needed version, my bundle will resolve because of the fragment's export. But this will not be correct, because my bundle is not designed to work with the lower version. Is this not a problem?
Comment 15 Thomas Watson CLA 2011-03-07 08:38:15 EST
(In reply to comment #14)
> Regarding the substitution of imports and exports, it seems to me that the case
> with fragments could cause problems. If I have a bundle which imports a
> specific version, and my bundle really needs this version to work, I expect
> that if another bundle does not export this version, my bundle will not
> resolve. 
> But if someone creates a fragment to my bundle - I assume that I know nothing
> about this fragment - and the fragment exports a lower version of the package
> that my bundle imports with a specific version, then even if no other bundle
> exports this package with the needed version, my bundle will resolve because of
> the fragment's export. But this will not be correct, because my bundle is not
> designed to work with the lower version. Is this not a problem?

This would be a poorly designed fragment and would be considered a developer error.  The framework does not catch all developer errors.  We can discuss further with CPEG on https://www.osgi.org/members/bugzilla/show_bug.cgi?id=582 if you would like.