blob: 13e70ba4a80185de21105fd26b7d820ba922e3ea [file] [log] [blame]
<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<meta http-equiv="Content-Language" content="en-us">
<meta name="GENERATOR" content="Microsoft FrontPage 4.0">
<meta name="ProgId" content="FrontPage.Editor.Document">
<title>Class Path Container Enhancement</title>
</head>
<body>
<h1>Class Path Container Enhancement</h1>
<span style="FONT-SIZE: 10pt">Last Modified April 23, 2002</span>
<h2>
Background</h2>
JDT supports to switch the JDK that is used for building. It is currently
implemented as follows:
<ul>
<li>
org.eclipse.jdt.launching maintains the following JDK/VM information in
its plugin metadata:</li>
<ul>
<li>
a set of <i>VM install types</i>: a description of a VM install. It knows
how to find the location of the binary JAR and the source JARs.</li>
<li>
<i>VM installs: </i>the location/home of a VM install on the file system.
A VM install has an internal ID that is not visible to the user.</li>
<li>
one of the VM installs is marked as the <i>default VM install</i>.</li>
</ul>
<li>
org.eclipse.jdt.launching defines a JRE_LIB, JRE_SRC, JRE_SRCROOT variables
that binds to the default VM install:</li>
<ul>
<li>
JRE_LIB: the binary JAR (e.g. rt.jar)</li>
<li>
JRE_SRC: the source JAR/zip (e.g. src.jar)</li>
<li>
JRE_SRCROOT: the prefix in the source JAR (e.g. "src")</li>
</ul>
<li>
The Java project creation wizard adds a JRE_LIB classpath variable on a
project's build class path.</li>
<li>
org.eclipse.jdt.debug.ui contributes a preference page to define new VM
installs and to set the default VM install. When the default VM install
changes, then the bindings of the JRE_* variables are changed accordingly.</li>
<li>
org.eclipse.jdt.ui contributes a class path variable preference page. It
"knows" that the JRE_* variables are reserved and doesn't allow the user
to edit them.</li>
<li>
The packages view shows the resolved JRE_LIB contents as a referenced library.</li>
</ul>
Characteristics of the current implementation:
<ul>
<li>
Class path stability: changing the default JRE/VM install doesn't affect
the build class path since the JRE_LIB variable is not affected by this
change. In other words, when a user changes the JRE for building then the
.classpath file is not affected.</li>
<li>
JDK switching at the workspace level for all projects is straightforward
by the user, only the default VM install needs to be changed and all projects
in the workspace switch to use this VM install.</li>
<li>
Since class path variables can only bind to a single JAR, the JRE_LIB variable
can only bind to a single JAR (for the standard SUN JRE this is rt.jar).</li>
<li>
There is some magic involved with regard to the handling of JRE_* variables
that is not obvious to the user:</li>
<ul>
<li>
on the build class path the user sees JRE_LIB but when defining a launch
configuration then the user sees VM Installs. The user has to know that
JRE_LIB is indirectly bound to the VM install via the JRE installed preference
settings.</li>
<li>
The user also has to understand that the reserved variables cannot be edited
like the other class path variables, etc.</li>
</ul>
<li>
Build class path ordering - users can control the order of the build class
path in a simple way. For example, to do JCL development, to do so users
can put their source folders in front of the JRE_LIB class path entry.</li>
<li>
Java Core is not affected by the JDK switching support and is independent
of launching concerns.</li>
</ul>
<h2>
Motivation for enhancing the current implementation</h2>
<h3>
New Requirements</h3>
There are new requirements with regard to the handling of the JRE/JDK on
the build class path that need to be addressed by 2.0:
<ul>
<li>
Multiple JARs per JDK</li>
<br>The JRE_LIB class path variable can only bind to a single JAR file
typically the rt.jar. However, there are JDK installs that have split the
rt.jar into multiple JARs. For example, the JDK on the MacOS X has split
the rt.jar into: classes.jar and ui.jar (contains AWT and Swing).
<br>&nbsp;
<li>
Workspaces with a different JDK per project</li>
<br>WSDD needs support for having a workspace where different projects
build against different JDKs. The JRE_LIB variable is global and there
is no infrastructure and UI support to have different JDKs for different
projects. WSDD defined their own build description mechanism that bypasses
the JRE_LIB support. This results in a problematic user experience when&nbsp;
switching from WSAD or vanilla Eclipse Java development to WSDD.</ul>
<h3>
Existing characteristics to be preserved in the new implementation</h3>
<ul>
<li>
Class path stability, it has to be possible to switch a JDK locally in
a workspace without affecting the .classpath file.</li>
<li>
Easy JDK switching at the workspace level, i.e., a single setting can be
changed to change the build class path of all projects.</li>
<li>
Java Core is independent of the VM install infrastructure</li>
</ul>
<h2>
Proposal</h2>
The proposal affects core, launching, java debug UI, and the Java UI components.
<h3>
JavaCore</h3>
JavaCore provides a new type of classpath entry "CPE_CONTAINER",
which is just a named reference to a set of other classpath entries.
A container entry refers to a container path, which can be resolved by
a <code>ClasspathContainerInitializer</code> through an extension point,
or explicitly assigned using a setter method.
The actual binding from the CPE_Container entry to
the target classpath entries is implemented in term of an extension point
to keep Java Core independent of VM install concerns:
<p><tt>&nbsp;&nbsp; &lt;!ELEMENT classpathContainerInitializer
EMPTY></tt>
<br><tt>&nbsp;&nbsp; &lt;!ATTLIST classpathContainerInitializer</tt>
<br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; id&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
CDATA #REQUIRED</tt>
<br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; class&nbsp;&nbsp;
CDATA #REQUIRED</tt>
<br><tt>&nbsp;&nbsp; ></tt></p>
<ul>
<li><b>id</b> - the container unique name for which this resolver will be activated.</li>
<li><b>class</b> - the class that implements this container initializer.
The class must implement a public subclass of <code>org.eclipse.jdt.core.ClasspathContainerInitializer</code>
with a public 0-argument constructor.</li>
</ul>
<tt>&nbsp;&nbsp; abstract class ClasspathContainerResolver
{</tt>
<br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
void initialize(IPath containerPath, IJavaProject project) throws CoreException;</tt>
<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }
<p>The initialize call passes in a project, this enables
to resolve a classpath container in the context of a particular project.
The initialize method should only be called once to resolve the class path
entry (in case of failure, the container will not be considered as having been
resolved).
</p>
<p>It is possible to register an initializer per container ID. The full container path
being passed along to the initializer. Its first segment is
the container ID for which an initializer should be registered. The remaining segments
can be used to provide additional hints for the container expansion.
In case multiple resolvers are registered on the same container ID, the first
registered one will be used).
</p>
<p>JavaCore provides a method to perform explicit modifications of a container:
<pre>
JavaCore#setClasspathContainer(
IPath containerPath,
IJavaProject[] affectedProjects,
IClasspathContainer[] respectiveContainers,
IProgressMonitor monitor)
</pre>
In particular, this method is to be used in the context of a classpath initializer so as to perform
the actual initialization. Note that it allows to modify the value of a container for a set of projects
at once. In reaction to invoking this method, the JavaModel will be refreshed and corresponding Java element
changes will be notified.
</p>
<p> A classpath container implements <code>org.eclipse.jdt.core.IClasspathContainer</code> and can be queried
through a JavaCore API: <code>JavaCore#getClasspathContainer(IPath containerPath, IJavaProject project) </code>.
There is no assumption that the returned container must answer the exact same containerPath
when requested <code>IClasspathContainer#getPath</code>.
Indeed, the containerPath is just an indication for resolving it to an actual container object.</p>
<p>
Classpath container values are persisted locally to the workspace, but
are not preserved from a session to another. It is thus highly recommended to register a
<code>ClasspathContainerInitializer</code> for each referenced container
(through the extension point "org.eclipse.jdt.core.ClasspathContainerInitializer").
<pre>
public interface IClasspathContainer {
/**
* Kind for a container mapping to an application library
*/
int K_APPLICATION = 1;
/**
* Kind for a container mapping to a system library
*/
int K_SYSTEM = 2;
/**
* Kind for a container mapping to a default system library, implicitly contributed by the runtime
*/
int K_DEFAULT_SYSTEM = 3;
/**
* Answers the set of classpath entries this container is mapping to.
* The set of entries associated with a classpath container may contain any of the following:
* - library entries (<code>CPE_LIBRARY</code>)
* - project entries (<code>CPE_PROJECT</code>)
* A classpath container can neither reference further classpath containers or classpath variables.
*/
IClasspathEntry[] getClasspathEntries();
/**
* Answers a readable description of this container
*/
String getDescription();
/**
* Answers the kind of this container. Can be either:
* - K_APPLICATION if this container maps to an application library
* - K_SYSTEM if this container maps to a system library
* Typically, system containers should be placed first on a build path.
*/
int getKind();
/**
* Answers the container path identifying this container.
* A container path is formed by a first ID segment followed with extra segments.
* which can provide additional hint for resolving.
* This container ID is used in conjunction with the hints for resolving to this container.
* The container ID is also used to identify a ClasspathContainerInitializer
* registered on the extension point "org.eclipse.jdt.core.classpathContainerInitializer", which can
* be invoked if needing to resolve the container before it is explicitely set.
*/
IPath getPath();
}
</pre>
</p>
<p><font color="#FF0000"><b>Issue</b>: The Mac OS X JDK install is
an interesting case. There the rt.jar is split into two binary JARs (classes.jar,
ui.jar), but there is still a single src.jar. This cases needs to be handled by </font><font color="#FF0000">the
source lookup. For example, when src.jar is attached to classes.jar then when
looking up java.awt.Frame out of ui.jar, the source attachment of classes.jar
needs to searched as well.</font></p>
<h2>
Example</h2>
The class path of a project will look as follows:
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;classpath&gt;
<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;classpathentry kind=&quot;src&quot; path=&quot;/src&quot;/&gt;
<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;classpathentry kind="container" path="JDK/1.3"/>
<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;classpathentry kind="output" path="bin"/>
<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;/classpath&gt;</p>
<p>In the case where the user didn't override the
VM install at the project level. Then the Java launching contributed container
resolver (registered for container prefixes: "JDK") would resolve "JDK/1.3" using the default
VM install, using "1.3" as an hint, and may expand it into the following:</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;classpathentry kind="lib" path=&quot;d:/jdk/1.3.1/jre/lib/rt.jar&quot;
rootpath=&quot;d:/jdk1.3.1/lib/src.jar&quot; sourcepath=&quot;/src&quot;/&gt;
</p>
</body>
</html>