blob: 4183a2057d343be8f596f3210d82c58041781f46 [file] [log] [blame]
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
<meta name="GENERATOR" content="Microsoft FrontPage 4.0">
<meta name="ProgId" content="FrontPage.Editor.Document">
<title>Design of a Tool for Checking API Usage in Eclipse-based Components</title>
</head>
<body>
<h1>Design of a Tool for Checking API Usage in Eclipse-based Components</h1>
<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>
<h2>Components</h2>
<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>
<h2>Component description files</h2>
<p>Each component will be described via a component description file. The file
format is XML-based; the DTD follows (complete <a href="http://dev.eclipse.org/viewcvs/index.cgi/working/apitools/component.xsd?cvsroot=WebTools_Project">XML
scheme</a>):</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>
<h3>Example</h3>
<p>A component description of one of the Eclipse Platform components:</p>
<pre>&lt;component name=&quot;Eclipse Platform Core Resources&quot;&gt;
&lt;plugin id=&quot;org.eclipse.core.resources&quot; /&gt;
&lt;plugin id=&quot;org.eclipse.core.resources.win32&quot; fragment=&quot;true&quot; /&gt;
&lt;plugin id=&quot;org.eclipse.core.resources.linux&quot; fragment=&quot;true&quot; /&gt;
&lt;plugin id=&quot;org.eclipse.core.resources.hpux&quot; fragment=&quot;true&quot; /&gt;
&lt;plugin id=&quot;org.eclipse.core.resources.macosx&quot; fragment=&quot;true&quot; /&gt;
&lt;plugin id=&quot;org.eclipse.core.resources.qnx&quot; fragment=&quot;true&quot; /&gt;
&lt;package name=&quot;org.eclipse.core.resources&quot;&gt;
&nbsp;&nbsp; &lt;type name=&quot;ICommand&quot; implement=&quot;false&quot; /&gt;
&nbsp;&nbsp; &lt;type name=&quot;IContainer&quot; implement=&quot;false&quot; /&gt;
&nbsp;&nbsp; &lt;type name=&quot;IFile&quot; implement=&quot;false&quot; /&gt;
&nbsp;&nbsp; &lt;type name=&quot;IFileState&quot; implement=&quot;false&quot; /&gt;
&nbsp;&nbsp; &lt;type name=&quot;IFolder&quot; implement=&quot;false&quot; /&gt;
&nbsp;&nbsp; &lt;type name=&quot;IMarker&quot; implement=&quot;false&quot; /&gt;
&nbsp;&nbsp; &lt;type name=&quot;IMarkerDelta&quot; implement=&quot;false&quot; /&gt;
&nbsp;&nbsp; &lt;type name=&quot;IPathVariableChangeEvent&quot; implement=&quot;false&quot; /&gt;
&nbsp;&nbsp; &lt;type name=&quot;IPathVariableManager&quot; implement=&quot;false&quot; /&gt;
&nbsp;&nbsp; &lt;type name=&quot;IProject&quot; implement=&quot;false&quot; /&gt;
&nbsp;&nbsp; &lt;type name=&quot;IProjectDescription&quot; implement=&quot;false&quot; /&gt;
&nbsp;&nbsp; &lt;type name=&quot;IProjectNatureDescriptor&quot; implement=&quot;false&quot; /&gt;
&nbsp;&nbsp; &lt;type name=&quot;IResource&quot; implement=&quot;false&quot; /&gt;
&nbsp;&nbsp; &lt;type name=&quot;IResourceChangeEvent&quot; implement=&quot;false&quot; /&gt;
&nbsp;&nbsp; &lt;type name=&quot;IResourceDelta&quot; implement=&quot;false&quot; /&gt;
&nbsp;&nbsp; &lt;type name=&quot;IResourceProxy&quot; implement=&quot;false&quot; /&gt;
&nbsp;&nbsp; &lt;type name=&quot;IResourceRuleFactory&quot; implement=&quot;false&quot; /&gt;
&nbsp;&nbsp; &lt;type name=&quot;IResourceStatus&quot; implement=&quot;false&quot; /&gt;
&nbsp;&nbsp; &lt;type name=&quot;ISaveContext&quot; implement=&quot;false&quot; /&gt;
&nbsp;&nbsp; &lt;type name=&quot;ISavedState&quot; implement=&quot;false&quot; /&gt;
&nbsp;&nbsp; &lt;type name=&quot;ISynchronizer&quot; implement=&quot;false&quot; /&gt;
&nbsp;&nbsp; &lt;type name=&quot;IWorkspace&quot; implement=&quot;false&quot; /&gt;
&nbsp;&nbsp; &lt;type name=&quot;IWorkspaceDescription&quot; implement=&quot;false&quot; /&gt;
&nbsp;&nbsp; &lt;type name=&quot;IWorkspaceRoot&quot; implement=&quot;false&quot; /&gt;
&nbsp;&nbsp; &lt;type name=&quot;ResourcesPlugin&quot; subclass=&quot;false&quot; instantiate=&quot;false&quot; /&gt;
&lt;/package&gt;
&lt;package name=&quot;org.eclipse.core.resources.mapping&quot;&gt;
&lt;/package&gt;
&lt;package name=&quot;org.eclipse.core.resources.refresh&quot;&gt;
&nbsp;&nbsp; &lt;type name=&quot;IRefreshResult&quot; implement=&quot;false&quot; /&gt;
&lt;/package&gt;
&lt;package name=&quot;org.eclipse.core.resources.team&quot;&gt;
&nbsp;&nbsp; &lt;type name=&quot;IResourceTree&quot; implement=&quot;false&quot; /&gt;
&lt;/package&gt;
&lt;component-depends&gt;
&lt;component-ref name=&quot;Eclipse Platform Core Resources&quot; /&gt;
&lt;component-ref name=&quot;J2SE&quot; /&gt;
&lt;/component-depends&gt;
&lt;/component&gt;</pre>
<h2>How component descriptions are used</h2>
<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>
<h2>Change history</h2>
<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>