Bug 45767 - Should fragments be on a downstream plugin's classpath?
Summary: Should fragments be on a downstream plugin's classpath?
Status: RESOLVED FIXED
Alias: None
Product: PDE
Classification: Eclipse Project
Component: UI (show other bugs)
Version: 3.0   Edit
Hardware: PC Windows XP
: P3 normal (vote)
Target Milestone: 3.0 M5   Edit
Assignee: Wassim Melhem CLA
QA Contact:
URL:
Whiteboard:
Keywords:
: 45686 45732 (view as bug list)
Depends on:
Blocks: 75182
  Show dependency tree
 
Reported: 2003-10-29 16:54 EST by Michael Valenta CLA
Modified: 2006-11-09 17:21 EST (History)
9 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Michael Valenta CLA 2003-10-29 16:54:59 EST
I have changed all the team plugins to use the PDE classpath container. At 
some point since I set it up, all my .project files have change to include a 
fragement that I have loaded but is not a dependency of the project (the core 
resources spysupport fragment). This automatic changing has happened a few 
times. The first time, I wasn't sure if it wasn't because of something I did 
so I just replaced the .project files with what was in the repository. 
However, I just noticed that they are all changed again. This should not 
happen.
Comment 1 Michael Valenta CLA 2003-10-29 16:58:27 EST
I just remembered that I may have performed an Update classpath on a plugin 
since the last time I reverted the .projects (I'm not sure of the timing). 
However, even if I did, the .project file for other projects should not be 
effected. I would even argue the the .project file should not be effected at 
all when the classpath is updated.
Comment 2 Wassim Melhem CLA 2003-10-29 17:02:40 EST
The .project modification is done by JDT Core.  
cc'ing Philippe to shed some light on why that is necessary.
Comment 3 Philipe Mulet CLA 2003-10-29 17:13:04 EST
In order to induce the proper build order, we have to record project references 
(in the platform way) for each Java project prerequisite on the classpath.

This is why we update the project description so as to ensure references are 
adding according to the classpath. This is not a happy story, but this is the 
only existing solution (since day 1).
Comment 4 Michael Valenta CLA 2003-10-30 09:08:53 EST
Is there no way I can prevent the fragment from getting on the classpath? It 
is not required for the plugin but is being put there by the PDE classpath 
container. I don't really understand the relationship between plugins, 
fragments and classpaths but it does seem a bit odd that adding a fragment to 
my workspace would cause projects that didn't require the fragment before to 
all of a sudden require it. 
Comment 5 Philipe Mulet CLA 2003-10-30 09:42:33 EST
If the PDE container states a fragment, then we will add it as a project 
reference.
Comment 6 Wassim Melhem CLA 2003-10-30 09:59:28 EST
Fragments have to be on the classpath, if PDE plans on maintaining its claim 
that it provides a development environment that is as close as possible to the 
runtime environment.  This is not negotiable.

This is a big issue that goes beyond fragments, and has nothing to do with 
fragments.  

As you delete projects from your workspace or add projects to your workspace, 
the classpath of the other projects is recomputed dynamically by PDE to 
reflect the new environment (and hence the luxury of classpath containers).
The .classpath file does not change.  However, since the newly recomputed 
classpath depends on a different set of projects (since some have been 
deleted/added from the workspace by the user), JDT Core goes in there and 
modifies the .project file.

So whatever the consistency that we gained by maintaining an 
unchanged .classpath file is undermined by the instability of the .project 
file.
Comment 7 Dejan Glozic CLA 2003-10-30 10:35:20 EST
I will add DJ to the discussion because ultimately this is a platform core 
issue. 

DJ, can you shed more light to the relationship between project references and 
builders? It seems to us that the dependencies between the projects (i.e. if a 
project A references project B and B changes, A must be built as well) are 
somewhat leaking too low in the component stack.
Comment 8 Philipe Mulet CLA 2003-10-30 11:44:06 EST
Note: by putting fragments on a plugin classpath, you allow plugin code to 
directly target fragment code.

The .project modifications are mandatory as per platform build management 
design. I would love to get rid of the project reference setting, and let 
others do it for us. The 'simple' problem is to get the build order right. This 
is achieved by a topological sort of project references (remember that platform 
knows nothing about Java, so it doesn't care about a classpath).

What would be better than static project references in the project description 
would be dynamic project references answered by each builder/project nature.
This change would have to come from the platform side. Until something like 
that occurs, there is nothing JDTCore can do without breaking the build 
management.
Comment 9 Dejan Glozic CLA 2003-10-30 12:04:46 EST
OK, lets hear the platform core guys - it would be really good if we could get 
this problem fixed because we think that dynamic classpaths (that's how we re-
branded our use of classpath containers :-) are 'the' way of selfhosting for 
Eclipse 3.0. We would like to make it the default but we need to fix these 
issues if possible.

Comment 10 Wassim Melhem CLA 2003-10-31 15:09:25 EST
Assigning to John A. to see what he can do.
Comment 11 John Wiegand CLA 2003-11-12 10:47:23 EST
My opinion: I don't believe the fragments should be auto-included in a plugin's 
classpath.  A plugin should define its API.  If it explicitly includes 
something from a fragment (like swt), then the fragment's contents can be 
included.  In other conditions, the fragments should not be on the classpath of 
a plugin.
Comment 12 DJ Houghton CLA 2003-11-12 10:52:51 EST
What about the following common case:

plug-in: org.eclipse.core.tests.resources
fragment: org.eclipse.core.resources.testsupport (fragement for resources plug-in)

The fragment provides public classes/methods for package visibility code so we
can test it.

The tests project needs to have the fragment on its classpath to compile.

We also have this case in our spies/tools plug-in.
Comment 13 Wassim Melhem CLA 2003-11-12 10:55:03 EST
Taking DJ's case into account, that is why PDE adds a fragment project 
directly to a plug-in's classpath only if the fragment project contain a 
source folder.
Comment 14 Philipe Mulet CLA 2003-11-12 12:05:16 EST
Right, but this doesn't mean core.resources classpath should include its own 
fragments for free. If you read original reporter's problem, he was concerned 
that switching to PDE container was adding gratuitous project prereqs. If my 
test plugin was targeting the fragment, then in the past it would have 
explicitly referred to it on its classpath to be able to compile against it.

Using the PDE container shouldn't change the set of project references. For 
instance, you don't want to allow core.resource developpers to code against 
their metrics fragment...

Comment 15 Wassim Melhem CLA 2003-11-12 12:41:56 EST
The spy fragment was never on the org.eclipse.core.resources project's 
classpath.  It was on the org.eclipse.core.tools project's classpath.
org.eclipse.core.tools explicitly imports org.eclipse.core.resources and that 
is why it got the spy fragment as part of the deal because the spy fragment is 
a fragment for core.resources.
Comment 16 Wassim Melhem CLA 2003-11-12 12:46:50 EST
To further clarify things:
A fragment project contains a project reference to its parent plug-in.
The parent plug-in never has project references to its fragments.
However, clients of the parent plug-in should be able to have visibility to 
all the code of the parent plug-in and all that plug-in's fragments.
Comment 17 Philipe Mulet CLA 2003-11-13 06:00:47 EST
I see, sorry for the confusion. Still I find suspicious that fragments are 
automatically attached to dependents. I had the feel that a fragment was only 
an implementation detail of a particular plugin. Thinking of swt, the win32 or 
linux implementation pieces. I start to wonder if the spy fragment shouldn't 
rather be a separate plugin, normally prereq'd by the test project...
Comment 18 Wassim Melhem CLA 2003-11-13 06:22:24 EST
Actually, we also had a problem with swt fragments on gtk.  This fragment 
needed to be explicitly on the classpath of clients of the swt plug-in; 
otherwise the JDT compiler would complain that indirectly referenced class 
files are missing from the classpath of the client plug-in.  For a trip down 
memory lane, see bug 34128.
Comment 19 Philipe Mulet CLA 2003-11-13 07:26:02 EST
This one is special, as it does not have any API on its own, but rather 
reexport its entire fragment. Do we think of fragments as addendum to a plugin 
or simply an implementation detail ? I understand however that this is tricky 
for you to make the clear distinction in between these 2 cases. Ideally, you'd 
like to always reexport fragments so that swt would be happy by default. 

Comment 20 Dejan Glozic CLA 2003-11-13 08:07:49 EST
We wouild be happy to simplify our classpath computation regarding fragments if 
all the use cases listed in this defect are handled in a different way. SWT 
case may be a hard problem, though. If we ask all the teams that reference 
classes in their fragments from their plug-ins to simply convert these 
fragments to dependent plug-ins, then we will end up with SWT to handle.

Perhaps a solution would be to treate SWT as special (have an explicit 
knowledge of org.eclipse.swt in our code). This is a little goofy but at least 
we would not impose a strange rule on every fragment because of one internal 
use case.
Comment 21 Philipe Mulet CLA 2003-11-13 11:23:33 EST
You could funace the rule like below: 

When the plugin.xml references a library JAR which happen to live in a 
fragment, then you could offer to export the fragment to dependents (swt 
case) ? If not, then you'd do nothing by default. The test project would have 
to explicitly reference the spy fragment (as it probably did in the past 
anyway).

But I presume this shouldn't even be necessary. Bug 34128 was not further 
investigated. Do we really need the special rule for swt ? Could have been 
nothing but a bug ? Suggest bug 34128 is further analyzed.
Comment 22 Wassim Melhem CLA 2003-11-13 12:48:19 EST
Re comment #19, it is true that swt is a special case, i.e. the swt library is 
declared in the plugin.xml, yet it's packaged in the fragment.
Note however that PDE is able to model that at development time on win32 for 
instance without having to add the fragment to clients of swt.

The reason why the gtk fragment needs to be added on that platform is because 
the swt.gtk fragment contains an extra library swt-pi.jar.  And whenever a 
plug-in references the type Composite in their code, the JDT compiler starts 
wanting to resolve types declared in the swt-pi.jar and complains when they're 
not found.  Adding the swt.gtk to the classpath of the client, whether or not 
it's rightly justified, solves that problem.

So my "conjecture" is that the JDT compiler is too eager to resolve all types 
referenced by Composite, including ones from the swt.gtk fragment, to put them 
on the classpath of the client plug-in, and complains when it does not find 
the type coming from the fragment.
We should investigate whether this is a bug in the JDT compiler or if other 
compilers exhibit the same behavior.
Comment 23 Wassim Melhem CLA 2003-11-13 20:05:54 EST
Bug 34128 has now been resolved and clients of swt no longer need the swt.gtk 
fragment on their classpath to compile.
I'm sensing that the direction we want to go is to impose a limitation that if 
a plugin A imports plug-in B, and plug-in B has a fragment: then plug-in A 
cannot directly reference classes in plug-in B's fragment.

Note however that this new limitation will break DJ's scenario (comment #12) 
and similar testing setups for the Help team (and other people who, I'm sure, 
will become pretty vocal if we go in this direction).  Their argument would be 
of course, that plug-in B's fragment is available to plug-in A at runtime, so 
why is it not available at development time.

Incidentally, none of this fragment-related conversation has anything to do 
with the subject of this bug report which is the fact that the .project file 
is being overwritten.
Comment 24 Wassim Melhem CLA 2003-11-13 20:17:43 EST
While we're at it, let's add Jeff to the discussion to see his take on how 
this might affect fragments in the Equinox world.
Comment 25 Jeff McAffer CLA 2003-11-13 23:39:11 EST
In comment #23 it is proposed "that if a plugin A imports plug-in B, and plug-
in B has a fragment: then plug-in A cannot directly reference classes in plug-
in B's fragment."  Did I miss how one gets SWT code on their classpath (it is 
all in the fragment)?  Or ui.win32 (activeX api is in the fragment)?

To me the simplest story to explain is the one that has the dev-time classpaths 
model the runtime classpath as closely as possible.  This reduces the incidence 
of "but I could see that at compile time!" and "why cant the compiler see it, 
its there a runtime?"  The problem at hand is the collateral damage to 
the .project file not so much the value of the classpaths.

While fragments are largely used to express implementation detail, there is 
nothing in any of the design or doc to discourage people from putting API in 
there.  As we have seen Eclipse does it with SWT and ui.win32.  In the absence 
of being able to spec a dependency on a fragment, it makes sense to put the 
fragment code on the classpath (how else will it ever get there?).

In Equinox we used to treat fragments as first class entities and plugins were 
allowed to express dependencies on them.  So JDT could say it requires ui and 
ui.win32 (just examples).  Under this model it is clearer that the classpath 
should not include the fragments for free.  If you really do depend on ui.win32 
you can state it in the plugin.xml.

This has the significant drawback of encouraging/promoting platform-
specificness up. This is especially true in the SWT case where all of the API 
is in the fragment so to get anything you would have to make a platform-
specific dependency. 

Side note: SWT is an anomoly and I really don't remember why the plugin.xml 
contains the library decl but the jar is in the fragment or why the API is not 
in the plugin.  Perhaps this can be changed?  

Also note that Equinox has since moved from independent fragments to merged 
fragments (the classic Eclipse model) to maintain backward compatibility and 
allows package visibility between fragments and their host plugin.

Comment 26 Wassim Melhem CLA 2003-11-14 00:10:57 EST
To make it clearer how the statement from comment #23 covers the swt case, it 
should be rephrased as:
"if a plugin A imports plug-in B, and plug-in B has a fragment that declares a 
library in its fragment.xml, then plug-in A cannot directly reference classes 
in a library declared by plug-in B's fragment".
swt.jar is declared in the swt plugin.xml, so it will still be visible to 
clients of swt, although it is physically located in the fragment.  swt-
pi.jar, for example, which is declared in the swt.gtk fragment will not.

I, for one, am in total agreement with remarks made in comment #25.
"While fragments are largely used to express implementation detail, there is 
nothing in any of the design or doc to discourage people from putting API in 
there."  This statement says it all.

If we now introduce a new limitation to not allow client plug-ins to directly 
reference code declared by fragments, it will break at least one existing and 
perfect valid scenario for many people, e.g. DJ's setup.  And that's one 
scenario too many.

The bottom line is if a library is on the runtime classpath, it ought to be on 
the development classpath.
Comment 27 Philipe Mulet CLA 2003-11-14 05:05:23 EST
I still disagree, and would rather force people requiring APIs located in 
fragments to declare these dependencies explicitly.

To summarize, I don't want JDT Core to see any spy functionalities when coding. 
At runtime, I don't care since I will not invoke them since I did not code 
against these. All coding tools are expecting the classpath to determine what 
is expected to be accessible. Compile-time is different from runtime.

Following your argument of making the dev classpath be the same as the runtime 
one, you could add all other projects even indirectly referenced from a 
plugin.xml, as this is exactly what will occur at runtime... isn't it ? I 
certainly wouldn't want that.
Comment 28 Dejan Glozic CLA 2003-11-14 07:38:37 EST
If I may shed some light on SWT 'special case', it has been a particular 
architecture choice that led to this. Erich Gamma can talk for hours about one 
of the dearest patterns in his book (the factory) and multi-platform widget 
toolkits are one of the classic use cases. In this pattern, all the widgets 
would be first defined as interfaces (IButton, IText etc.). There would be also 
a factory interface (IWidgetFactory) with methods like IButton createButton() 
etc. To create a button, one would need to call 'WidgetToolkit.getFactory
().createButton()'. Depending on the os/ws/arch, the correct factory instance 
will be created, dolling out concrete os/ws/atch implementations of widgets. 

In this architecture, SWT plug-in would contain interface declarations, while 
fragments would contain conrete implementations. Nobody would need to have SWT 
fragments on the classpath because no plug-in would access internal 
implementations of interfaces directly.

SWT team argued that this approach leads to duplication (each widget has an 
interface and N implementations) and lots of code that would affect 
performance. Instead, they are using Java's late binding to achieve the same 
goal. When your code says 'Button button = new Button(...)', the actual Button 
class is resolved to a different 'real' class depending on your classpath. 
There is no 'common' declaration of a button - there is a "Button' class for 
each platform that happens to have the same API, so your code always compiles. 
With this approach, there is no common code to put in SWT plug-in, so SWT 
fragment must be put on your classpath.

Erich and myself spent one afternoon ages ago trying to solve the SWT classpath 
problem and gave up in frustration - there is no way around the fact that SWT 
case is 'special' and Eclipse developers should be discouraged from copying it.
Needless to say, there is no way SWT will now be redesigned to use the 
toolkit+factories architecture :-).
Comment 29 John Arthorne CLA 2003-11-14 09:57:04 EST
I'm sorry to interrupt this interesting discussion, but I have entered a new bug
report (bug 46668) for the problem of changes to the .project file.  Note that
this problem in the abstract is completely unrelated to fragments.  I am
renaming this bug report to better reflect the majority of its discussion.
Comment 30 John Arthorne CLA 2003-11-14 10:46:10 EST
To me the most important argument against adding fragments to the classpath is
this: since a plugin cannot explicitly require a fragment, your plugin cannot
safely assume that it will be there at runtime. Thus automatically making it
available at compile time is inviting trouble at runtime. As Jeff argues, this
also encourages creeping fragment (and platform) dependence that will come back
to bite people when they discover that they can't rely on the fragment always
being there.

The approach used by the core spy plug-in and help tests is a hack: these
plugins will break at runtime if the fragment they rely on is missing. In
controlled scenarios like testing and "spy" tools this may be acceptable, but it
is not a scenario to be designing general plugin tools against.  The ui.win32
fragment is also not a good example.  The UI plugins don't compile against this
fragment (since it's unsafe to assume it will be there at runtime).  This leaves
only SWT, which I think we all agree is an anomalous case.

I suggest the following:

- PDE never adds fragments to the classpath of downstream plugins
- The "atypical" cases that do want to compile against a fragment (spy and
tests) can add the fragment pre-requisite to the classpath manually as a
separate entry (as they have always done in the past).  By requiring these
special cases to add the dependency manually, we are reinforcing that this is
not normal behaviour that will necessarily reflect the runtime situation, and
they are responsible for their own breakage if that fragment is missing.
Comment 31 John Wiegand CLA 2003-11-14 10:48:14 EST
Concur with John A's proposal.

fragments were not intended to provide API for a plugin.  I don't have a 
problem that they can be used this way, but we don't want to optimize the 
tooling for this case. It is valuable occasionally (DJ's case is an example), 
but we do not want to encourage this style.

The "normal" situation is that plug-in developers should write plug-ins that 
depend on other plug-ins.  
Comment 32 Jim des Rivieres CLA 2003-11-14 11:07:55 EST
I third John A proposal :-)

I also want to add two more facts about SWT that I learned from SWT and UI 
teams:
(a) The SWT project in the repository is a single project - there are no 
projects corresponding to the OS-specific fragments. When you load this 
project from CVS, you need to follow manual instructions prepared by the SWT 
team to get the SWT project itself to compile. This instructions involves 
replacing the Java .classpath file.
(b) If you import SWT the plug-in and fragments as source, they do not 
compile. This has never been an issue. People who want to see but not touch 
SWT source simply import its plug-in and fragments as binary. And people who 
want to see and possibly modify SWT source load the real SWT swource project 
from the CVS repository.
Comment 33 Wassim Melhem CLA 2003-11-14 12:26:20 EST
>Following your argument of making the dev classpath be the same as the 
>runtime one, you could add all other projects even indirectly referenced from 
>a plugin.xml, as this is exactly what will occur at runtime... isn't it ? I 
>certainly wouldn't want that.
I am not sure what you are referring to here, but I hope you are not talking 
about reexported imports.  They are indeed added to a plug-in's classspath.  
How else would it compile?
PDE also adds core.boot and core.runtime to all plug-in's classpath, as these 
two plug-ins are implicitly available at runtime to all plug-ins (in a non-
Equinox world, that is).  Plug-ins do not have to declare core.boot and 
core.runtime as dependency in order to gain visibility to their libraries.

Comment 34 Dejan Glozic CLA 2003-11-14 13:02:02 EST
Wassim, you mentioned that Help component has a fragment case that we needed 
to support. What category does it fall in?
Comment 35 Wassim Melhem CLA 2003-11-14 13:14:20 EST
I believe it fell under the test project category from comment #12.
I remember Konrad checking out his test project from CVS, using PDE to update 
its classpath and being shocked that the project did not compile because one 
of his plug-in's fragments was in source form and not picked up by PDE.
Note that if plug-ins and fragments are in binary form, then fragments are not 
added to a client's classpath because their libraries can be directly accessed 
through a project reference to the parent plug-in.
Comment 36 Wassim Melhem CLA 2003-11-19 00:28:16 EST
Fixed.
In summary,
The classpath of a plug-in project will contain:
   1. the libraries declared in its plugin.xml
   2. all its direct dependencies and reexported imports of its direct 
dependencies.

The classpath of a fragment project will contain:
   1. the libraries declared in its fragment.xml
   2. the libraries declared in its parent plug-in's plugin.xml
   3. The fragment's direct dependencies and reexported imports of these 
direct dependencies.
   4. Its parent plug-in's direct dependencies and reexported imports of these 
dependencies.

Plug-ins that will be added for free to all classpaths (both fragments and 
plug-ins) are core.boot and core.runtime.
These free dependencies are not added to the core.boot and swt plug-ins.
They are not added to any plug-in if Eclipse is in OSGi mode.
Comment 37 DJ Houghton CLA 2003-11-20 12:15:08 EST
*** Bug 45686 has been marked as a duplicate of this bug. ***
Comment 38 Wassim Melhem CLA 2003-11-27 10:25:02 EST
*** Bug 45732 has been marked as a duplicate of this bug. ***