Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.

Bug 167968

Summary: Need a way to calculate the "uses" directive on exports
Product: [Eclipse Project] PDE Reporter: Thomas Watson <tjwatson>
Component: UIAssignee: Brian Bauman <baumanbr>
Status: RESOLVED FIXED QA Contact:
Severity: normal    
Priority: P3 CC: hargrave, jeffmcaffer, john.arthorne, ob1.eclipse, pascal, Peter.Kriens, wassim.melhem
Version: 3.3   
Target Milestone: 3.3 M5   
Hardware: PC   
OS: Windows XP   
Whiteboard:

Description Thomas Watson CLA 2006-12-13 16:49:27 EST
I thought I already opened a bug about this but I cannot find it.  We need a way to calculate the "uses" directive on Export-Package statements for the developer.

Classes can depend on classes in other packages. For example, when they
extend classes from another package, or these other classes appear in
method signatures. It can therefore be said that a package uses other packages.
These inter-package dependencies are modeled with the uses directive
on the Export-Package header.

For example, org.osgi.service.http depends on the package javax.servlet.http
because it is used in the API of the org.osgi.service.http package. The export definition of the org.osgi.service.http should therefore contain the uses directive with the javax.servlet package as its value.  For example,

Export-Package: org.osgi.service.http; uses:="javax.servlet.http"

If a bundle imports a package from an exporter then the export definition of
that package can imply constraints on a number of other packages through
the uses directive. The uses directive lists the packages that the exporter
depends upon and therefore constrains the resolver for imports. These constraints ensure that a set of bundles share the same class loader for the same package.

If this is not done we can get different errors (like ClassCastExcpetion) when the wrong version of a class is used to call some API.  It would be nice if PDE provided some way (maybe with a "calculate uses directive" operation) to calculate what the uses directive should be for all packages exported by a bundle.  

We should be able to calculate this by doing code analysis on the exported packages.  Here is an example of some rules we could start with to calculate the uses directive.

- Only calculate uses directive on public API packages (not x-internal ones)
- Only calculate used packages from public and protected classes.
- Never include a package in java.* these can only come from boot and everone shares them.
- Include the packages to all argument and return types to public/protected methods.
- Include the packages to all public/protected field types

This list is probably not complete but it should be a good start.  CC'ing BJ to see if he has other rules that should be applied to calculate the uses directive.  As you can see the rules are not easy for a mere mortal to follow and given the sheer number of API packages in Eclipse this is going to be very hard to force down on the community unless we have a tool to calculate it for them.

I also CC'ed John because this is very much related to API definition.
Comment 1 Thomas Watson CLA 2007-01-09 14:00:28 EST
I think some of the work Oleg is doing in the PDE incubator for API tools could help here.  The code for "Usage Discovery" may be able to be used to calculate the "uses" directive on Export-Package statements?

Thoughts Oleg?

Otherwise this bug report is pretty quite.  Any plans to address this for 3.3?
Comment 2 Oleg Besedin CLA 2007-01-09 16:15:31 EST
Yes, the reference extractor from PDE-incubator/api-tooling might help.

On a more general note does it mean that you'd like all Export-Package directives to have a "uses" clause? It would be a bit of a pain to maintain it. 
Comment 3 Thomas Watson CLA 2007-01-09 16:28:02 EST
Yes, every API package should define the "uses" directive.  That should be consider part of defining your API.  Yes I agree it is a pain to maintain, but my hope is tooling will relieve us from that pain.
Comment 4 Wassim Melhem CLA 2007-01-09 17:21:31 EST
As for what will actually get into 3.3, Jeff and I had an oral agreement that we will leave all package management work (import/export) to Oleg and we will incorporate what is appropriate for development time into PDE and will leave what is appropriate for build time for Releng.

Note that oral agreements are binding in the province of Ontario.  
Comment 5 John Arthorne CLA 2007-01-09 18:23:14 EST
Tooling and support for "uses" makes sense, but I don't think we can reasonably expect development teams to add and maintain "uses" for every single API package.  It just seems like too much work and prone to mistakes/staleness. In the Eclipse team context, does the problem only arise with packages that are imported using Import-Package (i.e., service packages)?  That would greatly narrow the scope of the required effort, since most bundles use Require-Bundle.
Comment 6 Thomas Watson CLA 2007-01-10 08:50:41 EST
This does not only apply to service packages or Import-Package constraints.  See bug 169593 and bug 155996 for more details.  We can see many issues if multiple versions of the same bundle are installed and resolved at the same time.

If we want to support such scenarios then we must start defining the "uses" directive.
Comment 7 Wassim Melhem CLA 2007-01-23 17:49:36 EST
Assigning to Bauman.

Brian, we envision this functionality to have two UI hooks:
1. a button in the Export-Package section of the plug-in manifest editor
2. an option in the Exported Packages section of the Organize Manifests wizard that would be checked by default.

Jeff may have some working code that can be used as starting point.
The ideal solution, from a PDE/UI standpoint, would have to use JDT/Core APIs when calculating the uses directive.
Comment 8 Brian Bauman CLA 2007-01-26 15:38:54 EST
Should we include the package of a super class or interface of a class?  Ie. A public class in a public package is extending an internal class, should the internal class's package be included in the 'uses' directive?
Comment 9 BJ Hargrave CLA 2007-01-26 15:54:19 EST
CCing Peter Kriens who have some experience on this.
Comment 10 Peter Kriens CLA 2007-01-27 08:22:01 EST
I have been calculating the uses directive for about 2 years now in btool and now also in bnd (http://www.aqute.biz/Code/Bnd). 

I fully agree that the developer should NEVER add the uses themselves, too error prone. Same is true for Import-Package btw. We get a bad rap for being complicated because we expose these to the developer unnecessary (all information is in the class files, so why on earth should we repeat it??).

Comment 11 Brian Bauman CLA 2007-02-02 15:14:00 EST
PDE should be able to calculate the uses directive for plug-ins for 3.3M5.  As per comment #7, it can be done from the Organize Manifest Wizard or a button on the Export Package Section of the Manifest Editor.  Also included some formatting for the directive so Manifest don't become completely unreadable.
Comment 12 Wassim Melhem CLA 2007-02-03 01:41:32 EST
I just tested the function.  Nice job, particularly on the formatting.
Comment 13 Oleg Besedin CLA 2007-03-12 11:36:25 EDT
Let me start by saying that, in my opinion, the solution offered in this bug is highly counterproductive and not ready for use. 

It won't solve the problem but rather introduce another hard-to-remember step for all Eclipse developers. Anybody really thinks this change will make an average Eclipse developer happy? If not, why we are doing it?

While the OSGi wiring problem is real, the solution, to me, is done in a wrong dimension. To me, the real problem is that OSGi needs some data that is rather expensive to calculate on every startup. So, what if we cache it - either during initial Eclipse run or during the bundle build process.

Moreover, after attempting to use it I was left with the impression that either I am missing something or there are bugs in its implementation.

Details:

- Including "uses" directive in a day-to-day software development ties manifest.mf files to PDE tools. It will be impractical (or impossible) to maintain manifest.mf tools outside of PDE as calculating "uses" directives by hands will be very time consuming and error-prone.

- Usability: in the current implementation "uses" directives are guaranteed to either not to be used by consumers or to become stale and outdated. The action of calculating uses should be automatic, not a separate button. Of course, this is rather hard to implement without impacting performance - but that's one other reason why I believe that this solution goes in a wrong direction.

- Results: It seems that there are some issues (or bugs?) in the "uses" directives generated. Here are some examples:

a) What packages are included in the "uses" directive? Do we include "x-friends"?
ExtensionTracker from o.e.equinox.registry has "import org.eclipse.core.internal.runtime.RuntimeLog;" but no "uses" is generated for the "org.eclipse.core.internal.runtime".

b) Used packages used not shown
RegistryStrategy from o.e.equinox.registry imports org.eclipse.osgi.util.NLS but it's not in the "uses" clause
BaseExtensionHandle from the same bundle has "import org.eclipse.core.runtime.*;" but no uses are generated

c) Java packages
I noticed that there is uses directive generated for the "javax.xml.parsers". While I can understand the pragmatic reason for this, it begs a question which Java packages are included in the "uses" directive and which aren't.

To summarize:
- The current solution ties manifest.mf files to PDE tools
- Due to the manual nature of the solution proposed, "uses" directives are guaranteed to go out of synch 
- There are some issues with results it currently generates

I do believe that we need to consider solving the OSGi wiring problem in some other way, perhaps by calculating information it needs on the first startup or during the build process.
Comment 14 Thomas Watson CLA 2007-03-12 12:07:09 EDT
Oleg, just because a java class imports a package does not mean its API "uses" that package.  See comment 0 for more information on what it means for API to use another package.  The OSGi R4 specification also gives more details.

I think you have a point about usability but can we not work around that by flagging the manifest as stale?  But I will let Wassim deal with the workflows.  Other options are to generate the uses directives in the build process.  We could look into generating the uses clauses at bundle install time in the runtime but this would not really comply with the OSGi specification.

BTW, I am not in favor of pushing this on anyone at this point in 3.3.  I think it is much to late to recommend developers update all their manifests to include uses clauses at this point.  There are too many questions left at this point.
Comment 15 Oleg Besedin CLA 2007-03-12 12:24:55 EDT
I am not sure if it is fine to limit "uses" directive to the classes present in the signatures of APIs. 

Consider the following scenario:

Bundle A has an API method that declared as:
   java.lang.Object #getFoo().
It returns java.lang.Object, but has a Javadoc saying that it really returns Class1 or Class2 (in this case, Class1 and Class2 are coming from a bundle VeryBasicBundle).

Plugin developer makes a Bundle B uses an API from the Bundle A and does:
   if (#getFoo() instanceof Class1) { 
   ...
   }

In this case to me it looks like even as Class1 is not present in the API, OSGi still needs to both BundleA and BundleB to wire to the same VeryBasicBundle.

Is this correct?
Comment 16 BJ Hargrave CLA 2007-03-12 13:23:28 EDT
(In reply to comment #15)
These are semantics not expressed in the API signature and no amount of runtime or tooling can help with that. This is clearly a pathological case where the developer must hand code the uses clause.
Comment 17 Oleg Besedin CLA 2007-03-12 13:40:52 EDT
BJ, what is "pathological" with that example? I intentionally simplified it so that it was easy to read. However, even in the simplified form it is not uncommon. Think adaptors. Think listeners.

Your answer highlights another point. OK, let's say I have some "pathological" code that needed "usage" directives to be adjusted. Now what?

Next time me (or somebody else) runs an automated tools it overwrites my hand-coded "uses" directives?
Comment 18 BJ Hargrave CLA 2007-03-12 14:43:43 EDT
(In reply to comment #17)
The pathological part is that the API says it returns Object but the javadoc says it returns some other type. If the user of the API is then expected to cast the value to some other type, this is not captured in the API signature and automated tooling cannot handle this. You would then need some other tooling help like an annotation or doclet tag which described the actual return types vs. the one specified in the API signature. Then the tools could take this additional metadata  into account to calculate the proper uses clause.
(If the user is not expected to cast the object to some other type, then that type does not need to be in a uses clause since the code does not directly reference that class.)

Yes, the tooling need to handle the use hand coding the uses clauses which means it is not always possible to completely calculate the uses clauses (without an annotation or doclet tag as I described above). I don't think this is any different from automatically calculating the import-package statement. If the code does a Class.forName on some class, the programmer may need to manually add a package to the import-package statement.
Comment 19 Oleg Besedin CLA 2007-03-12 15:32:34 EDT
A trivial case where downcasting is necessary: a method that returns a Collection. (Rememeber that runtime is supposed to run on Java 1.4.2 so no new nice Java5 features.)

In this case if you need an element of a Collection, you have to downcast. Let's say you getting a List from BundleA and elements of the list are of type Class1 which is in some other BundleBasic.

The automated tool can catch this is you create "uses" for all classes it is using, not just for what's in the API signatures.

My point here is that there are some really simple scenarios which looks like they need "uses" directives even if the used classes are not present in the API signatures.
Comment 20 Jeff McAffer CLA 2007-03-12 16:52:32 EDT
This is why developers need to craft the uses clauses and it cannot be left to some automatic generation tool all the time.  We can do markup etc to help in the automation and checking.  In the end though there will be cases where developers have to provide input.
Comment 21 Oleg Besedin CLA 2007-03-12 17:14:51 EDT
Hmmm... How would developer know when "uses" statement has to be adjusted?

Even if I only modify "implementation details" due to the ["pathological" :-)] patterns shown in the comment 15 and comment 19, I need to check if my modifications ever trickle into APIs. 

And it will be quite non-trivial to figure that out - that's for a person who understands the reasons behind the "uses" clause. (Note to myself: money-making opportunity. Consulting company "Solving your "uses" problem in 7 days or your money back" :-).)
Comment 22 Thomas Watson CLA 2007-03-12 17:50:26 EDT
Oleg, your points are valid.  But to me this whole topic about "pathological" API is exposing a real deficiency in how Eclipse (and to a greater extend Java) defines API in a pre 1.5 JRE.

Someone has to write the javadoc to make it clear to clients what the pathological case is because it is not clear from return types or the param types.  Is the "uses" clause harder to maintain than the language you have to remember to maintain in your javadoc?  Any time you change your pathological (I just do not have a better term ;-) cases then you have to remember to update your javadoc.  It seems like we have been playing pretty loose in our API definitions WRT the pathological case.  If we want tooling to automatically generate uses clauses for these cases then we need an annotation or doclet tag like BJ suggests in comment 18.  But unfortunately developers still must remember to update the annotation or doclet tag anytime they make a change to the API.
Comment 23 Oleg Besedin CLA 2007-03-13 09:51:36 EDT
One thing I'd like to point out is that downcasting is used often. Every time results returned by another bundle are downcasted, you'll have a problem with "uses". (As long as you limit calculation of "uses" to APIs.)

Moreover, typically, the person doing downcasting will be a different person from the person who generated "uses" statement. Now consider if 3 bundles are involved. Bundle1 provides some classes used by the Bundle2. Bundle2 provides some classes to be used by Bundle3. 

The person writing Bundle2 might not even know what are the actual object types provided by the Bundle1 so he *can't* provide a correct "uses" statement.

Bottom line is that unless you are going to outlaw downcasting in Eclipse world, "uses" statements should be calculated based on all the contents of the bundle, not just APIs.

(And I have a funny feeling that similar problem will be in up-casting but that is a bit too complicated to figure out at this early morning hour :-).)
Comment 24 Thomas Watson CLA 2007-03-13 10:29:08 EDT
Oleg, please provide actual bundles that demostrate you usecase.  I think code speaks louder than words in this case.  I'm having a hard time following the scenario.
Comment 25 Wassim Melhem CLA 2007-03-20 01:52:23 EDT
I am re-closing the bug report because it tracks the completion of this feature.

Oleg, if you would like enhancements to the existing function or you find bugs in the current implementation, please open a separate bug report and cc the usual suspects.  Thanks.