blob: 5ac9b2355791870294caecce98028727093f94b3 [file] [log] [blame]
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Design of a Tool for Checking API Usage in Eclipse-based
Components</title>
<link
rel="stylesheet"
type="text/css"
href="sources/formate.css">
</head>
<body>
<p class="ueberschrift">Design of a Tool for Checking API Usage in
Eclipse-based Components</p>
<p>Jim des Rivieres<br>
Last updated Jan 14, 2005</p>
<p>This document contains the design for a tool for checking API usage
in Eclipse-based components and products.</p>
<p class="ueberschrift">Components</p>
<p>For the purposes of this tool, a component is a set of plug-ins and
plug-in fragments. Components must be disjoint, in that the plug-ins and
fragments within one component must be distinct from those in other
components. In other words, components partition the set of plug-ins and
plug-in fragments into disjoint subsets. We also allow a form of library
component containing&nbsp; no plug-ins or fragments; library components
are used to describe class libraries such as J2SE that are not located
inside any plug-in.</p>
<p>The code for a component is the sum total of the code in the
component's plug-ins and fragments (as described by the plug-in
manifest). The code is in the form of Java types (predominantly classes
and interfaces; J2SE 5.0 adds enumerations and annotation types). The
types that are intended to be used by other components are called the
component's API, and referred to as API types. A component can provide
any number of API types, including none. Typically, only a subset of a
component's types are part of its API. The rest are referred to as
internal types. Non-public types are always considered internal.</p>
<p>It's common to use Java packages to separate one component from
another, and to separate API from internal within a component. Each
component generally declares its code in packages different from those
used by any other component. An API package is one that contains at
least one API type. An internal package is one that contains no API
types. The default assumption is that all public top-level types in an
API package are API types.</p>
<p>An API type declared in one component can be used by other components
is various ways:</p>
<ul>
<li>Declare a field, variable, parameter, or return type where the
type is an API type.</li>
<li>Cast the value on an expression to an API type.</li>
<li>Declare a class that implements an API interface.</li>
<li>Declare an interface that extends an API interface.</li>
<li>Declare a class that extends (subclasses) an API class.</li>
<li>Creates an instance of an API class.</li>
</ul>
<p>It is common for an API type to be intended to be used only in
certain ways. In some cases, Java modifiers can be used to rule out
unintended uses (e.g., prevent subclassing by declaring the class
&quot;final&quot;). But in many cases, the intended uses are spelled out
in the type's specification (doc comment). The most common restrictions
are:</p>
<ul>
<li>Clients may not instantiate this API class.</li>
<li>Clients may not subclass this API class.</li>
<li>Clients may not implement this API interface. It follows that the
client may not extend the interface either.</li>
</ul>
<p>Types have members (fields, methods, types). For the present, we make
the simplifying assumption that all public and protected members of an
API type are intended to be used by other components.</p>
<p class="ueberschrift">Component description files</p>
<p>Each component will be described via a component description file.
The file format is XML-based; the DTD follows:</p>
<pre>&lt;!ELEMENT component (plugin* package* component-depends)&gt;
&lt;!ATTLIST component
name CDATA #REQUIRED
&gt;</pre>
The &lt;component&gt; element provides information about a component.
Attributes:
<ul>
<li><b>name</b> - the component name; &quot;Eclipse Platform Generic
Workbench&quot;; note that this name is used to refer to the component
and distinguish it from other components (but otherwise has no
official status in Eclipse ontology)</li>
</ul>
<p>Child elements or the &lt;component&gt; element describe the set of
plug-ins and fragments making up the component, provide information
about the Java packages and types in the component's code, and include a
list of other components on which this component may depend.</p>
<p>Each &lt;plugin&gt; element must identify a distinct plug-in or
fragment. The list of plug-ins must be complete; that is, a component
contains a plug-in (or fragment) if and only if a &lt;plugin&gt; element
occurs as a child of the &lt;component&gt; element.</p>
<pre>&lt;!ELEMENT plugin EMPTY&gt;
&lt;!ATTLIST plugin
id CDATA #REQUIRED
fragment (&quot;true&quot; | &quot;false&quot;) &quot;false&quot;
&gt;</pre>
The &lt;plugin&gt; element identifies a plug-in or plug-in fragment that
is part of the component. Attributes:
<ul>
<li><b>id</b> - the plug-in id or plug-in fragment id; e.g.,
&quot;org.eclipse.core.resources&quot;; note that in the case of a
fragment, this is the id of fragment itself</li>
<li><b>fragment</b> - whether this is a plug-in fragment as opposed to
a plug-in (default: plug-in)</li>
</ul>
<p>Each &lt;plugin&gt; element must identify a distinct plug-in or
fragment. The list of plug-ins must be complete; that is, a component
contains a plug-in (or fragment) if and only if a &lt;plugin&gt; element
occurs as a child of the &lt;component&gt; element.</p>
<pre>&lt;!ELEMENT package (type*)&gt;
&lt;!ATTLIST package
name CDATA #REQUIRED
exclusive (&quot;true&quot; | &quot;false&quot;) &quot;true&quot;
api (&quot;true&quot; | &quot;false&quot;) &quot;true&quot;
&gt;</pre>
The &lt;package&gt; element provides information about a package as used
by the component. Attributes:
<ul>
<li><b>name</b> - Java package name; e.g., &quot;javax.swing&quot;,
&quot;org.eclipse.ui&quot;</li>
<li><b>api</b> - whether top-level types in this package are API types
by default (default: true). It's good practice for all public classes
API top-level types in a package to be considered API. Specify
&quot;false&quot; in order to explicitly list API types found in the
package.</li>
<li><b>exclusive</b> - whether this package is reserved for exclusive
use by this component (default: true); specify &quot;false&quot; in
(rare) cases where a multiple components declared types in the same
package. Package sharing is only by mutual consent; all components
involved must explicitly declare the package as
exclusive=&quot;false&quot; (even if it has no API types).</li>
</ul>
<p>Each &lt;package&gt; element must identify a distinct package
relative to that component. If the unusual case where a package is
shared with other components, the &lt;package&gt; element is understood
to apply only to the types the component actually declares, and has no
bearing on the types declared in the same package in any other
component. The list of packages may be incomplete; if the component
contains code in a package not mentioned in the list, the package is
considered to be internal (equivalent to being explicitly described as
&lt;package name=&quot;...&quot; api=&quot;false&quot; /&gt;). The
children of the &lt;package&gt; element provide information about
specific types in the package.</p>
<pre>&lt;!ELEMENT type EMPTY&gt;
&lt;!ATTLIST type
name CDATA #REQUIRED
reference (&quot;true&quot; | &quot;false&quot;) &quot;true&quot;
implement (&quot;true&quot; | &quot;false&quot;) &quot;true&quot;
subclass (&quot;true&quot; | &quot;false&quot;) &quot;true&quot;
instantiate (&quot;true&quot; | &quot;false&quot;) &quot;true&quot;
&gt;</pre>
The &lt;type&gt; element provides information about a top-level type in
a package. Attributes:
<ul>
<li><b>name</b> - simple name of a top-level Java class, interface,
enumeration, or annotation type; e.g., &quot;String&quot;,
&quot;IResource&quot;</li>
<li><b>reference</b> - whether other components are expected to
reference this type by name (default: true); specify &quot;false&quot;
to indicate that the type is internal</li>
<li><b>implement</b> - whether other components are expected to
declare a class that implements this interface (default: true);
specify &quot;false&quot; for an interface that other components are
not supposed to implement directly; this attribute is ignored for
classes, enumerations, and annotation types, none of which can be
meaningfully implemented</li>
<li><b>subclass</b> - whether other components are expected to declare
a class that directly subclasses this class (default: true); specify
&quot;false&quot; for a class that other components are not supposed
to subclass directly; this attribute is ignored for interfaces,
enumerations, and annotation types, none of which can be meaningfully
subclassed</li>
<li><b>instantiate</b> - whether other components are expected to
create instances of this class or annotation type (default: true);
specify &quot;false&quot; for a type that other components are not
supposed to instantiate directly; this attribute is ignored for
interfaces and enumerations, neither of which can be meaningfully
instantiated; this attribute is moot for classes that are declared
final (or ones with no generally accessible constructors), since the
Java compiler and JRE will block outside attempts to instantiate</li>
</ul>
<p>(Note: We could extend the schema in the future to allow &lt;type&gt;
elements to provide analogous information about their members. We could
also extend the &lt;component&gt; element to allow aspects other than
code API to be described.)</p>
<pre>&lt;!ELEMENT component-depends (component-ref*)&gt;
&lt;!ATTLIST component-depends
unrestricted (&quot;true&quot; | &quot;false&quot;) &quot;false&quot;
&gt;
&lt;!ELEMENT component-ref EMPTY&gt;
&lt;!ATTLIST component-ref
name CDATA #REQUIRED
&gt;</pre>
The &lt;component-depends&gt; element identifies other components on
which this component is allowed to depend. Attributes:
<ul>
<li><b>unrestricted</b> - whether this component is allowed to depend
on arbitrary other components, or just the ones explicitly named by
the &lt;component-ref&gt; children</li>
</ul>
If a component specifies &lt;component-depends
unrestricted=&quot;true&quot;&gt;, then it is allowed to depend on any
component (and the children, if any, are ignored). Otherwise, the
&lt;component-ref&gt; elements give the names of the component on which
this component may depend. The &lt;component-ref&gt; element identifies
a component by name. Attributes:
<ul>
<li><b>name</b> - the name of the referenced component; e.g.,
&quot;Eclipse Platform Generic Workbench&quot;</li>
</ul>
<p class="ueberschrift">Example</p>
<p>A component description of one of the Eclipse Platform components:</p>
<pre>
&lt;component name="Eclipse Platform Core Resources"&gt;
&lt;plugin id="org.eclipse.core.resources" /&gt;
&lt;plugin id="org.eclipse.core.resources.win32" fragment="true" /&gt;
&lt;plugin id="org.eclipse.core.resources.linux" fragment="true" /&gt;
&lt;plugin id="org.eclipse.core.resources.hpux" fragment="true" /&gt;
&lt;plugin id="org.eclipse.core.resources.macosx" fragment="true" /&gt;
&lt;plugin id="org.eclipse.core.resources.qnx" fragment="true" /&gt;
&lt;package name="org.eclipse.core.resources"&gt;
&lt;type name="ICommand" implement="false" /&gt;
&lt;type name="IContainer" implement="false" /&gt;
&lt;type name="IFile" implement="false" /&gt;
&lt;type name="IFileState" implement="false" /&gt;
&lt;type name="IFolder" implement="false" /&gt;
&lt;type name="IMarker" implement="false" /&gt;
&lt;type name="IMarkerDelta" implement="false" /&gt;
&lt;type name="IPathVariableChangeEvent" implement="false" /&gt;
&lt;type name="IPathVariableManager" implement="false" /&gt;
&lt;type name="IProject" implement="false" /&gt;
&lt;type name="IProjectDescription" implement="false" /&gt;
&lt;type name="IProjectNatureDescriptor" implement="false" /&gt;
&lt;type name="IResource" implement="false" /&gt;
&lt;type name="IResourceChangeEvent" implement="false" /&gt;
&lt;type name="IResourceDelta" implement="false" /&gt;
&lt;type name="IResourceProxy" implement="false" /&gt;
&lt;type name="IResourceRuleFactory" implement="false" /&gt;
&lt;type name="IResourceStatus" implement="false" /&gt;
&lt;type name="ISaveContext" implement="false" /&gt;
&lt;type name="ISavedState" implement="false" /&gt;
&lt;type name="ISynchronizer" implement="false" /&gt;
&lt;type name="IWorkspace" implement="false" /&gt;
&lt;type name="IWorkspaceDescription" implement="false" /&gt;
&lt;type name="IWorkspaceRoot" implement="false" /&gt;
&lt;type name="ResourcesPlugin" subclass="false" instantiate="false" /&gt;
&lt;/package>
&lt;package name="org.eclipse.core.resources.mapping"&gt;
&lt;/package>
&lt;package name="org.eclipse.core.resources.refresh"&gt;
&lt;type name="IRefreshResult" implement="false" /&gt;
&lt;/package>
&lt;package name="org.eclipse.core.resources.team"&gt;
&lt;type name="IResourceTree" implement="false" /&gt;
&lt;/package>
&lt;component-depends>
&lt;component-ref name="Eclipse Platform Core Resources" /&gt;
&lt;component-ref name="J2SE" /&gt;
&lt;/component-depends>
&lt;/component>
</pre>
<p class="ueberschrift">How component descriptions are used</p>
<ul>
<li><b>Component package/type map</b> - Given the code for a component
and its component description, you can generate a fleshed-out list of
the API types declared by the component. (It's considerably harder to
properly describe the set of API members, since this involves building
the supertype chain and performing inheritance. Since the supertype
chain need not be confined to a single component, you also need the
code for required plug-ins, etc.)</li>
<li><b>Inter-component reference map</b> - Given the code for a
component, its component description, and the component descriptions
for all other components to which the given component may contain
references, you can generate the list of external references from the
component to types in some other component (possibly unknown, possibly
ambiguous). In particular, you can do this without needing to consult
the code for the other components (or even needing the code to be
available).</li>
<li><b>Fragile usage map</b> - You can go further and classify
inter-component usage as fragile. This requires the code for a
component, its component description, and the component descriptions
for all other components to which the given component may contain
references. In the limited case of shared packages between components,
the code for these components may be needed to disambiguate external
references to types in the shared package. A fragile external
reference is any of:
<ul>
<li>A reference to an internal type in another (possibly unknown)
component.</li>
<li>A declaration of a subclass of a class C in another component
where C is described as subclass=&quot;false&quot;.</li>
<li>A declaration of a class implementing an interface I in another
component where I is described as implement=&quot;false&quot;.</li>
<li>An invocation of a constructor of a class C in another component
where C is described as instantiate=&quot;false&quot;.</li>
<li>A declaration of a type in a package P that another component
describes as exclusive=&quot;true&quot;.</li>
</ul>
</li>
</ul>
<p class="ueberschrift">Change history</p>
<ul>
<li>Dec. 23, 2004 - Initial version</li>
<li>Jan. 14, 2005
<ul>
<li>Added &lt;component-depends&gt; element to allow each component
to explicitly specify which other component it may depend on.</li>
<li>Added clarification to &quot;api&quot; attribute of
&lt;package&gt; element re: this is in line with good practice of
making all top-types public types in an API package being considered
API.</li>
</ul>
</li>
</ul>
</body>
</html>